今天早上,有个网友给我发了一条消息:他是一个老产品版本维护开发人员。他应聘到这家公司的时候,这个产品已经卖了4年了。最初的开发者已经都在这4年中不断流失走掉了。他来了,任务就是维护这套软件,而且就他这一个人维护这套代码,有BUG改BUG,有需求就改需求。
虽说这套软件卖了4年,但真不知道是怎么坚持了4年。他接手的时候仍然是BUG百出。代码没有文档,没有注释,连表结构说明都没有。代码莫名其妙,经常横插一句代码,显然是客户报告了某个错误,为了临时解决这个错误而做的针对性处理,但到底是为了修补什么错误,代码也没有说明。所以他也不敢乱动,但还要修改需求,只能硬着头皮来。他也不知道自己修改的代码是否还会引起其他的问题,只能凭空企求千万不要出问题。老板还在到处吹产品很成熟,而他每天都在心惊胆战,害怕这套代码不知道哪天突然崩溃,出了错误自己都收拾不了,那只能自己被K掉。他能想像的出老板发怒的情景:这么稳定的产品你都搞不定。
他希望我能帮助他出出点子。
我想了想,能有机会开发新产品或新项目的程序员是很幸运的,因为没有历史包袱,白纸画画。而现在大部分的软件公司都是拿一套已经有了型的代码到处修改客户化做新项目。真正做一个新项目从头编写这个项目的第一行代码,这样的机会比较少。
对于修改现有代码适应新客户新项目,这种情况非常多,也是大部分没有文档,修改定制没有注释。客户打电话说了一个需求,能技术达到就答应下来修改,修改完就给客户覆盖,根本没有需求管理、版本管理。而这样的代码,还不是一个特定客户一套特定定制化代码,是要给其他客户也更新的。很可能这个客户好使,那个客户使用其他功能的时候就出了错。按下葫芦起了瓢,是很常见的现象。
我问他:现在你改的代码有注释吗?
他回答:没有。自己修改的自己都记得,即使忘了,看看自己写的代码也能回忆起来。所以也没有写。
我问他:那以后他走了,其他人怎么办?
他回答:反正也是一个烂产品,其他人怎么办,他就管不了了,就应该让这套烂代码尽快死亡,省得祸害别人。
我问他:那你找我帮助的目的是什么?
他回答:在我工作的这段期间内,它不要崩溃就可以了。
我无语了。
关于老系统维护这个话题,我和许多开发人员都有过深入的交流探讨。
许多从事开发的网友认为,一个老系统要维护好,必须具备以下关键因素:有责任心、有文档、设计前做好详细的需求分析、要有需求管理、要OO编程、要有专门的测试人员。如果没有这些,干脆推倒重来,如果不让推倒重来,那就赶快跑路,否则就容易当了冤枉替死鬼。
但现实中,往往维护老系统的就一个人。这是很矛盾的事情。一个软件的开发,往往1-2月就完成,而它的销售、实施、升级周期却长达4-8年。但每个老板好像都认为软件已经开发完毕,修修补补都是小功能,所以一个老系统维护人员就OK了。殊不知白纸好画画,而要在别人的画儿再能点睛成龙就难上加难了。
我在管理运营企业的时候,发现遇到的难题也和维护老系统面临的很类似。都是缺这缺那,部门之间利益冲突,人的素质怎么也提不上来,员工和老板互相做猫和老鼠的游戏,不断博弈薪水和付出劳动力的平衡。总有些公司的历史留下的人留下的势力格局留下的客户印象留下的做事方法不能改变,也无法推翻重来,但公司还要发展还要提高,就必须以目标为中心,不断象骆驼一样挺着风沙干渴饥饿领队前进,有各种困难阻碍都要不断清除,无法根除就想办法平衡与缓解,时而让步时而迂回时而强势时而突然决策突然执行,公司就这样不断持续经营下去。
所以,维护老系统,也要象经营企业一样,不断继承包袱,不断细心剖析问题,剥茧抽丝理清思路,不断改进,才能渐渐从恶性循环走向良性循环,才能把一套烂代码扭转成可持续维护的代码。
我给了他写代码的八个建议:
一、重点把控输入数据的校验。你看见很多横插进来的代码,就是由于输入的漏洞进入,最后引起后续数据处理出错,所以以前的程序员他不截源头,他在最后爆发的地方堵漏洞。现在WINDOWS程序都是消息事件触发式的,还说不准这个流程会走到哪里,他堵得了这个口,其他根本想不到的触发,他能堵住吗?所以,把输入数据的校验,在保存按钮第一步代码写好集中的详细的校验。而且,这块代码要写成函数,不要大流水,省得代码复杂性会让程序加速崩溃。
二、以后的需求再往上加,都写成函数。遇到比较大的IF..ELSE判断,就把其中的代码段再分出一个函数。
三、以后再加功能,尽量不要做成联动触发的。也就是说:保存,最好是单表保存。即使是主从结构的单据,如果客户不强烈反对,也做成先保存主表后再让录入明细表。而且录入明细表要单独的窗口,这样功能和代码都简化了。如查询一张单据,也不要上边是主摘要,下面就是明细联动。这样影响性能。更因为速度可能慢,用户会连续点击多次,触发事件就会乱,莫名其妙的错误就都产生了。最好是双击主摘要,弹出独立的窗口显示明细。
四、你以后写代码,把特殊处理业务和正常处理业务的功能代码分离。就好像你走路,老有人给你下绊子,你就感觉不爽。
五、现有的功能,把不常用的功能做一些隐藏处理,放到一个不起眼的位置。使用的人就会越来越少。到时候就适机真正藏掉,不让它触发了。
六、其实很多时候,你觉得程序很烂,索性破罐子破摔,是由于以前程序员的代码排版可能和你不一样。你喜欢两个空格,人家喜欢三个空格,你就觉得不爽。人家喜欢把{放在最后,你喜欢新开一行。你可以使用代码格式化工具重新排一次版。我看到很多关于老代码维护人员,抱怨变量都是M、N、S、Button1之类,但其实你阅读理解代码,这些并不会使你理解有歧义或读不懂,只不过你不爽而已。理解了这个不爽,你就会心平气和一些,修改代码会更加顺利一些,你越和旧有代码生气,你的工作越乱。(看到这里,相信很多程序员都会会心一笑。真正的根源在于此,老系统无法维护只是借口而已,可能希望老板认为自己的工作很辛苦很复杂而加薪)。真正危害大的是全局变量和大流水代码。所以写代码,要严格避免这两个坏因素。
七、修改需求或BUG的时候,要按照模块来集中修改,而不要挑好改的先改了,不好改的就最后改。按照模块来集中修改,你会通盘考虑所有这些需求和BUG,而不是糊窗户式的补窟窿。
八、我曾经和很多做维护的开发人员都做过交流。他们都觉得一个软件没有文档,没有注释,简直就没法维护。但确实是很多软件没有任何设计文档,连帮助说明都没有,代码也没有注释。而这些软件又出自他们自己之手。也就是说他们一边抱怨没有文档没有注释,一边自己也不做文档不写代码注释,不知道在等谁来专门做。我问他们到底需要什么文档才可以将一个软件维护的越来越好,从一套烂代码扭转到一套良好渐进的代码?他们说要要表结构说明、要详细功能设计书。表结构还好说,可以整理出来,详细设计说明书就不容易出了。
我曾经也维护过别人的代码,也是什么文档都没有,连操作使用帮助都没有,更别提详细设计说明书和表结构,代码当然没有什么注释。我并没有去整理表结构说明。幸亏这个人喜欢数据库上倒弄,写了大量的视图和存储过程。视图中有各个表之间的关系连接,也有各个表中重要字段的中文名。这样我就不需要表结构说明了。因为表结构说明不仅需要需要描述每个表中字段的中文含义,也得描述表之间的关系,这和视图能表达的效果是一样的。所以,我现在也建议开发人员写代码,多写视图,多写存储过程。有的老代码,SQL语句都生写在代码中执行,没有视图。对于这样的老系统维护,就是把这些SQL COPY出来,做成视图,这样就好维护了。
对于详细功能设计书,其实对于程序员来说,其目的是想弄清楚业务流程的来龙去脉细节。光直接看代码是很难弄明白意思的,又没有什么其他文档可以参考,所以只能猜测代码的意思。尤其很多维护人员,很多功能细节都是为了处理某些特殊需求和异常业务的,都是以前的程序员写的,但是以前的程序员已经走了,现在的维护人员连软件中具体的这些细节功能都不知道。当新的实施人员或支持人员反馈回疑问,想问问程序员某个细节功能是怎么回事,程序员都发蒙,嗯,还有这个功能?我也不知道呀。
要解决这个问题,我曾经做过的事情就是组织实施人员写功能操作说明帮助。因为实施人员要给客户去培训讲解,没有帮助说明,只能一张嘴叭叭叭的干说,实施人员是最需要功能操作说明帮助的。但是实施人员认为这个帮助是软件的一部份,而且是开发部开发的软件,开发部最了解功能,所以帮助文档应该开发部写。而开发部认为开发部的职责就是编写代码,你自己培训你连个操作说明都没有,你怎么培训,所以帮助文档应该实施部门自己编写。于是帮助文档谁也没有人写。
归根到底,帮助说明是终究要写的,主要是谁写的问题。谁最有动力写呢?实施人员最有动力,因为这和他们的工作息息相关。而程序员明显没有动力理由。而且实施人员熟悉第一线客户的素质,理解客户的具体操作思路和理解思路,写出来的帮助客户都能理解,帮助文件才能真正为客户服务。很多帮助文档的写作都是从来没有见过客户没有实施培训过没有客户支持服务过,连软件测试都没有做过的纯粹文档人员编写的,可想而知帮助文档到底能对客户有多大的帮助性。
在写帮助说明的时候,我要求实施人员把每个按钮都要点到,每个Grid中的每一个字段的数据来源和数据含义都要说明到,每一张报表中的字段的数据来源和数据含义,每一个明细录入中的字段的数据来源、数据录入要求和数据含义。这一写不要紧,发现了很多隐藏的特殊处理功能。很多功能很多人不了解,因为很多细节功能,都是为某个客户定制的,只有负责实施该家客户的实施人员才知道。于是,实施人员之间互相通气,才算补足了不少功能细节的帮助说明。实在有些功能,都不知道是哪家客户提出来需求,也不知道为什么要这样处理,就留下空白,转给开发人员,让开发人员看看代码是怎么处理的。就这样,一份详细的帮助说明在压力艰难中终于出来了。从此,开发人员理解需求快了许多,当然也就明白了那些过去自认为乱七八糟的代码的含义,心情好了很多,修改代码也轻松了许多。原来,一切都是自己跟自己作怪。不盼望软件工程,不抱怨一穷二白,不幻想增加人手,从现实入手解决自己的问题,发现很多解决方法既简单又有效,根本无须动辄就是团队就是UML就是OO。
另外,我还给了他一些关于需求控制的建议。
需求,是很多方面的。有关于功能的(尤其是每家客户特殊的业务需求),有关于异常错误的、有关于性能的、有关于兼容性的、有关于易用性的、有关于特殊权限的、有关于美观性的。
而需求的来源也是很多方面的,有的是客户计算机室直接打电话,有的是客户业务部门直接打电话,有的是实施人员,有的是支持人员,有的是市场人员,有的是销售人员,有的是老板和客户打单或开会突然想到谈到就直接给开发人员打电话。
而需求的优先级也不一样。有的客户态度强硬,你必须尽快满足他,否则他就给你老板打电话。
而正是这来自四面八方的各种层次各种看法的人的各个方面的需求电话,把程序员就烦的要命,还要去开发。而且很多都是一个电话就认为程序员能开发了。但往往程序员开发完后,客户一看不是自己最想要的,于是再修改。
所以,需求多,其实是一个幻觉。
第一、把需求分类,做个EXCEL表格,量化解决。这个需求管理表格会有下列这些项:客户名称、需求提出人、提出日期、需求关闭时间、功能模块名、客户现在版本号、需求描述、需求分类(需求、BUG)。我在最初没有需求管理系统的时候就使用过这种方法。过去没有使用的时候,我的手下老叫忙死了烦死了。我就让他把现在手头的事情都整理一下给我报个邮件。但一整理,肯定不超过10件事。有些事情是等待客户给资料,有些事情是调试跟踪不出来错误,有些事情是需求模棱两可。我给他一分析,他现在正在进行的事情就两件,而且都是他自己能独立做的,根本不需要别人配合参与的。他忙吗?他瞎忙,或者故意说忙。没有工作效果,就是这样。帐不算不清,话不说不明,就这个道理。
有了这个表格,要定期(可能是一周,可能是一月)给老板一份。这表明你的工作量,让他看看你确实一直很辛苦的在工作,而且干了这么多活。而且,这也能看出你工作的仔细负责态度。
有些程序员不做这个表格,也不给老板报告。很多时候是程序员并没有干那么多活,能推则推,能混则混,能拖就拖。怕自己有一天混不下去,所以心理压力很大,每天不干活却总觉得很累。这种累就是自找的。想必一些程序员看到此会想起自己。
第二、需求描述不清晰是反复修改的罪魁祸首。对于BUG,要有错误报错整个的屏幕截图,千万不要就截那个错误消息框那么一小块。对于需求,是报表需求,要给出表格格式,还有每一项数据的来源,有公式关系的要给出明确的计算公式。对于输入单据需求,要给出单据格式,每一个输入项的要求:可选值、默认值、不可为空、唯一性、约束输入,数字要有小数点后精确度、日期要分辨精度是到日期还是时还是到分。
对于这位网友的现状,我还建议他开始版本管理。
CVS、VSS之类就不必了。因为这是一个人的战斗。连版本都没有概念,一上来就是特正规的工具,大半感觉太麻烦,又退回到最初原始状态,还对版本管理产生了不好的印象,觉得繁琐还没什么用。所以我们有一句话:一管就死,一放就乱。其原因就是缺乏一个 中间过渡解决方法。
所以,我建议先把版本意识提上来,按照版本管理的方法走,走顺了就自然接受了正规的版本管理工具。版本管理工具可以分支,也可以合并,可以针对Bug进行补丁发布,而不发布还未完成的新功能,可以发布为某个客户专门定制的版本,也可以回溯历史版本,对比历史差异,源代码安全性也高。
有几个过渡性建议特别实用:
一、有大的修改或没有把握的修改之前,先把代码备份到其他的机器上。备份目录要跟上日期。
二、在大的修改前,先定一个稳定的版本发布出去。很多程序员没有版本这一概念,每天都在持续修改。结果,给客户的,每个都是半成品,有半拉子没有修改完,还自己没有做屏蔽处理。客户不小心用了,产生了错误,再告知千万不能用这个功能,还没有完善。但晚了,错误数据进入了,以后报表平帐就是问题了,又得特殊数据特殊处理了。自己的孽障自己还得解决。
三、即使是琐碎的修改,也要每天或隔天备份一份源代码,别怕代码多,现在的硬盘大的很,而且备份复制一下也就是5分钟的事情。别怕每天备份太烦。我们经常会遇到这个客户让改了,另外客户不让改。一个功能改了又改回去,但过去的源代码没存备份,忘了怎么写了,这时候你就想起代码备份的好处了。尤其现在有不少免费的文件同步或文件自动备份的软件,都能定时做。功能还强大,有些还有些差异备份的功能
四、现在有不少文本对比软件,如WinMerge之类。可以对比两个文件的差异,这个功能和版本管理工具中的源代码差异对比一样的效果。
五、如果每次发布新版本,就把从上一版本发布之日之后的关闭的需求列表都单独摘成一个文件,附带到这次新发布的版本之后。这样即使没有人写更新说明文档,根据追溯也能明白这次版本解决了哪些问题和需求。很多程序员没有需求管理表格,版本发布要求写更新说明文档,这才从脑海记忆中想,想的就有些遗漏,甚至错误。好多程序员有过这些的情景:我记得改了呀。真正一翻代码,一点没动。大叫:我的代码怎么没了,我记得我改了呀。
我这些建议,从需求描述、工作量管理、遗留系统代码重构技巧、备份管理、版本管理、更新说明文档一整套说明了一个人如何维护老系统的工作方法,但希望能分享给大家,给大家以帮助。
有方法,你就不是一个人在战斗。
一切皆有可能。
相信自己。