7月8日,突闻安倍晋三遭遇枪击,枪手仅距离其两到三米!我当时心想,原来日本政治家这么亲民,一点也不设防。后来才知道,根本不是不设访,而是每年花费了超过2亿日元的安保费用,并且据《AREA》一年前的报道,说虽然安倍晋三已不再是首相,但是其安保体系不仅没有减弱,反而更加“兴师动众”起来。然而,就这?后来看了他被刺的完整视频,更加被安保的业余水平惊呆了!

这让我想起自己的故事,我去年换了份工作,进入了一个刚成立的数字化新团队,不到半年,仅在云设施上的花费就超过了六千万。由于是新成立的团队,自有软件开发人员严重不足,因此还花费了大量的成本聘请了顶级的咨询公司来协助开发,这些咨询师的成本高达5000人天。这都不是重点,重点是上线后,BUG 频出,导致了技术团队在业务部门的口碑不佳,抬不起头。然而就是在这样的时刻,技术团队却开始了如火如荼的“重构”(重写)大业。当时我的感觉,就如同最近看到的安倍晋三明明花费了重金聘请了安保团队却仍然轻易地丢了性命一样。

重写不是重构!

说是“重构”,然而其实就是报怨前人写的代码已经无法维护,要全部重写!这…… 岂不是说前面上亿的花费全打了水漂?更糟糕地是,重写时采用的方法和当初的咨询师没什么两样,代码质量也没有更高,而且业务需求不仅有新的,老的也已经发生了变化,在这样的情况下,怎么保证低水平重复,结局一定比之前好呢?所以,这根本不是什么重构,而是重蹈覆辙,也就是花两倍不菲的经费,犯同样的错误而已。所以说,有钱真好!

既然重写不等于重构,那么究竟什么是重构呢?其实 Martin Fowler 专门写了一本书,就叫《重构》,它开门见山地指出:

所谓重构(refactoring)是这样一个过程:在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。重构是一种经千锤百炼形成的有条不紊的程序整理方法,可以最大限度地减小整理过程中引入错误的概率。本质上说,重构就是在代码写好之后改进它的设计。



屎山并不可怕

《重构》在定义“重构”时,还说

哪怕手上有一个糟糕的设计,甚至是一堆混乱的代码,我们也可以借由重构将它加工成设计良好的代码。

这就是说,不存在什么已有代码无法维护,需要推倒重来的情况。从这里推论出去,我甚至觉得,屎山不仅不可怕,甚至可以很香。只要坚持正确的重构,越老的项目其质量应该是越高的。

没有测试安全网的“重构”就是耍流氓

测试是重构的第一步

构筑测试体系是重构的第一步,也是最重要的一步,所以作者用了整整一章来详细讨论它。

连 Martin Fowler 这样的大师,也承认自己是人而不是神,因此,他要进行代码重构之前,会确保即将要修改的代码拥有一组可靠的测试。如果已有代码已经有测试了,这非常好,如果没有,就先添加测试而不是修改实现代码。正确的重构是,在重构完成后,先前确保的可靠测试不用改,全部通过。这些可靠且通过的测试,就验证了前面所说的“不改变代码外在行为的前提”。因为重构不改变代码外在行为,所以它只是软件开发过程中的一个部分,作者借用 Kent Beck 的“两顶帽子”比喻,非常建议在开发软件时,将自己的时间分配给两种截然不同的行为:添加新功能和重构。添加新功能时,不应该修改既有代码,只管添加新功能。但同样重要的是,重构时就不能再添加新功能,而是只管调整代码的结构。

重构不应大刀阔斧:同样的需求不应该收两份钱

更不应该打着重构的旗号,推掉业务的需求,进行大规模重写之事。真正的重构,绝大多数可以在几分钟到几小时完成。作者还专门举了一个极端的例子,哪怕是需要几个星期才能完成的库替换,他也不愿让一支团队专门做重构,而是采用 Branch By Abstraction 的策略,来保证每次小改动后,系统仍然照常工作。重构应该是小步快跑的,长期进行的持续改进,而不是运动式的大工程。更不应该跟业务团队说,我们这段时间因为要重构已有代码,所以需求需要缓一缓之类,作者甚至说,作为程序员,都不应该向自己的经理提重构的事情,作为专业人士,我们的工作是尽可能快速创造出高效软件,至于怎么完成,那是我们自己的事。我们认为重构是快速实现需求的方式,于是我们就进行重构。这一点看似有点矛盾,其实作者的意思是,同样的需求不应该向两客户收两份钱,这才是专业人士呀。否则,像我经历过的很多团队一样,第一次上线的需求收了一笔钱,然后以专门的重构期实际上又收了第二笔钱,由于根本不是重构而带来新问题,导致需要更多的“重构”,很可能需要客户再付第三份钱甚至更多。

注释是坏味道!

和大多数程序员们总是调侃前人代码是屎山一样,他们抱怨的另一点就是代码中没有注释。然而,《重构》这本书却恰恰持相反的观点,注释往往是一个明显的代码坏味道,是需要去除的。这符合我的观察,多数注释不仅无用,而且有些注释给阅读者明显的误导。甚至有注释上写的和实现代码所表达的完全矛盾的现象存在!
所以每当你有写注释的冲动时,应该先尝试使用各种重构手法,把代码坏味道去除。毕竟,代码本来就是写给人看的,只是恰好能在计算机上运行而已。当然,如果所有的重构手法都用了,仍然觉得需要注释的话,那还是可以写的。但是注释本身不是可以运行的软件,请别变成文档工程师哦。

除了注释,《重构》还列举了各种其他的代码坏味道以及相应的解决方法,这就是一系列的重构手法。

终点:测试驱动开发

本书除了详细论述各种代码坏味道和相应的重构手法外,专门花了一整章描写如何构筑测试体系。除了这一章,对于测试的强调其实充斥在全书的各个角落。尽管全书没有特别强调测试驱动开发这个词,但我想借此机会再次强调一下,在测试驱动开发中,重构正是其中的一个环节,没有测试驱动的重构不是真的重构。和测试驱动开发一样,《重构》也是浮现式设计的支持者。而这也正是重构的本意:通过调整代码改进原有的设计。软件之所以是“软”件,就是指它是可以改变的。在测试驱动开发中,应用好重构手法,是不会产生出无法更改的屎山代码的。