一个具体项目的重构(二)

了解我的朋友都知道,我的爱好很广泛,什么方向都涉猎,同时呢,因为漫天撒网牵扯了时间精力做事情经常半途而废。所以在我的Blog里面也有很多文章是写了一半的。比如这篇“一个具体项目的重构(一)”。我知道这个习惯不好,所以,我会慢慢地把我没有写完的文章都写完的,呵呵。一般我们把写一个半截的文章叫做挖坑,所以现在我开始埋坑了,所以叫做埋坑计划。

这个文章源于我来到公司的第一个项目,也是我在公司职责所在的项目。当然我主要是负责其中一个功能模块的而已。这里不是写工作总结,所以提到的我也许指的是我们,我们也许是我,这样说是因为这个项目是7,8人的劳动成果,不是我一个人的工作,但是这里不是讲每个人的功劳,而是描述我们的软件架构问题。

书接上文,我们总结了一个软件需求:

1. 可以在线升级。
2. 可以支持公司所有的(流行)产品。
3. 可以比较方便的进行扩充。
4. 一个全新的界面设计
5. 完成原有联机软件的所有功能。

在线升级可以说并不是一个复杂的问题,这个模块的具体实现我不是很清楚,基本上服务器上面放置一个最新版本的主程序和插件的列表,当然包括了他们的生成时间的信息,每次检查更新就是对比本地的文件和服务器上面提供的最高版本的日期差异,然后进行更新操作。这个功能工作得很好,我们的产品已经更新过相当多次了,没有任何失效的例子。

既然我们的题目叫做重构,实际上我最关心的话题是怎么提高软件的灵活性,怎么降低系统维护的成本。

首先我们来仔细看看,我们原有软件的维护难问题是怎么出现的。

首先,从软件结构上来看。这个系统由两个可执行文件构成,一个EXE文件是主界面,提供了完成的用户操作界面,包括名片、行程等的编辑功能,包括文件选择,包括选择上传下载等功能的界面;另一个EXE文件实际执行传输任务。他们之间的数据传输方式是通过对一个共享文件进行读写。这样划分的主要原因是,做界面的程序员和做实际传输模块的程序员往往不是一个人,甚至可能不是一个项目组的。主界面程序由我们的Team编写和维护,实际执行传输的程序往往是对应项目组负责传输协议的程序员来写。从难易程度和方向来讲,这么划分也还是有理由的,因为主界面程序员不需要了解任何通信底层接口,而传输程序的程序员主要是对通讯底层熟悉,他对一般的Win界面编程往往不是很熟悉。

在这样划分粒度下,理论上可以做到在底层通讯协议改变的情况下(每个产品都是有不同的通讯协议,这也是公司存在的一个问题,不过已经不在我可以影响的范围之内了。当然这有时候是必然的,比如外包产品,理论上讲外包产品当然会有不同的协议。),只修改一个EXE就可以的效果。但是实际上,这个问题很复杂不同的协议也可以造成完全不同的操作流程。这时候光修改通讯的EXE显然已经不够了。而且这个问题是这么的复杂,所以,在公司一直以来,有两种完全不同的传输模式存在,他们的联机软件是从完全不同的两个软件发展出来的。不仅仅是传输协议的不同了,这两套软件是完全不同的界面,完全不同的操作方式。这里虽然我不想批评我的公司。但是实际上我认为这对品牌战略是非常不利的。但是这是现状。

然后我们看代码维护和复用方式上面的问题。这里涉及到刚才提到的两种程序员的问题,负责联机软件界面的程序员和负责写通讯程序的程序员是不同 Team的,大部分时间他们是没有任何交流的。只有当一个新产品要准备推出的时候,他们才会临时组成团队。他们各自会找到最相近的一个老代码来进行修改(所以这里还是有一些代码复用的)。但是问题在于这里没有任何的版本控制,这造成了很多混乱,一些修改过的Bug,还会被多次重复的被修改,因为没有人来协调不同产品代码中的相同Bug。甚至可能因为采用了不好的开始代码,某个新产品会包括一些老产品都已经解决的Bug。另外,这样的模式必然会造成程序代码的迅速臃肿。为了安全,大家改代码都喜欢用注释老代码的方法。同时也出现了大量的条件编译语句用来弥合不同的机型之间的一些差异。可以想见,当公司有了 10多个产品之后,加上繁体版简体版的问题,代码中的垃圾和一些难以理解的成分就开始具有惊人的行数了。当一个程序员离职的时候,他根本没有能力给接班者讲清楚代码里面的来龙去脉,加上文档的欠缺。任何一个新从事这项工作的程序员读代码的工作就变得非常的沉重。

对程序的扩充是通过加入外挂程序实现的,一般的外挂是类似于一些特殊文件格式的编辑器,或者察看器之类东西。他们往往都很简单,所以不被重视。但是,他们也存在版本问题,也存在某一个版本已经修改了的Bug,在后续产品中又会出现的问题,这和项目组制度有关系。这里想抱怨一下,因为产品采用项目组的形式,而且缺乏一些必要的中间协调结构和标准化的制度,会出现一些很让人苦笑不得的问题。比如某种词典数据的格式定义是与平台无关的,但是先前的实现里面都莫名其妙的在词典数据的文件头上面加上了型号的标记,而且词典查看工具会读取这个标记。这样就必须把完全没有区别的词典数据文件复制成多份,修改他们的文件头然后,放置在不同的网站页面上。这也给用户带来了麻烦,用户下载词典的时候必须选择相应机型的对应词典,否则不能使用。其实解决起来也很简单,我们最后规定在机器上的词典查看工具忽略这个标记,这样就解决了一切问题。然而,这样的小问题确实在公司里面存在了数年,也给用户和工作人员带来了一些麻烦和困扰。(当然这属于题外化了,但是这个题外话,蕴含了我的一个重要的观点,在应该标准化的地方必须标准化,这样可以提高效率,而且避免给用户困扰。)
新的结构

从上面大家可以看到,我认为主要问题在于软件模块划分的粒度太粗了。在新的实现里面,我们把整个软件划分为主EXE,通用UI插件系统,通讯插件系统,外挂系统三个部分。系统之间的模块可以用EXE来分割,也就是用进程间通讯的模型,我们公司早期的系统就是这么做的。这样的好处是简单,但是问题在于采用共享文件作为通讯方式,速度慢,可靠性低。还可以采用的方法有DLL,或者COM。我们采用的是DLL,这是程序员的普遍水平决定的,事实上有些程序员之间连DLL都没有写过。如果采用COM,那么我们整个项目周期可能都不够培训的时间。
主EXE调用通用UI插件系统,通讯插件系统和外挂系统。这里,我将主要介绍通讯插件系统的设计,因为这是我主要负责的部分,也是我比较得意的部分。

请不要吝惜您的评论,每一条评论,都是我在漫漫长夜前行的力量

::...
免责声明:
当前网页内容, 由 大妈 ZoomQuiet 使用工具: ScrapBook :: Firefox Extension 人工从互联网中收集并分享;
内容版权归原作者所有;
本人对内容的有效性/合法性不承担任何强制性责任.
若有不妥, 欢迎评注提醒:

或是邮件反馈可也:
askdama[AT]googlegroups.com


点击注册~> 获得 100$ 体验券: DigitalOcean Referral Badge

订阅 substack 体验古早写作:


关注公众号, 持续获得相关各种嗯哼:
zoomquiet


自怼圈/年度番新

DU22.4
关于 ~ DebugUself with DAMA ;-)
粤ICP备18025058号-1
公安备案号: 44049002000656 ...::