我已经完成了bjdp.org将于2月23日在编程道场上驯服Trivia烂代码的Java编程操练题目。整个驯服过程,断断续续地进行了一周。等最后驯服过程告一段落时,我不禁想起《西游记》中那个孙悟空,从大闹天宫的妖猴,到被如来佛祖所驯服,到最后护送唐僧取得真经修成正果,成为斗战胜佛的过程。这两个驯服过程,都可分为三步:观察、保护、重构。让咱们一起回顾一下这两个有意思的过程,
第一步:观察
编程操练题目Trivia是专为驯服烂代码所设计,包含了C++、C#、Java、JavaScript、Objective-C、PHP、Python、Ruby等10多种语言的版本。2月23日的bjdp.org的编程道场上,咱们将选择Java语言的版本进行操练。
就像现实中所有烂代码一样,Trivia题目的源代码充满了刺鼻的代码腐臭:重复代码、过长的函数、过大的类、数据泥团等等。另外,所有代码都没有注释,有人认为这是缺点,不过这一点我到觉得没什么,因为程序员经常在修改了代码后忘记了同步注释,造成注释经常有可能成为指错路的路标。
从维基百科中查到,Trivia原本是一个答题闯关的游戏。比赛时参赛者先投色子来抽取要回答的问题,如果回答正确会获得金币,如果回答错误则要受罚。这就是我在读代码前,对Trivia题目所知道的所有背景知识。
接下来就是观察Trivia的代码行为了。最直接的观察方法就是运行带有main()方法的客户端GameRunner类,然后对照运行输出结果,观察客户端GameRunner的代码是如何调用服务端Game的公共接口的,并重点看看服务端Game类的所有公共方法的代码。
在《西游记》的大闹天宫结尾处,如来佛在降服妖猴前,也对孙悟空进行了一番仔细的观察。他先听取了玉帝使者的陈述,再赶到灵霄殿止住天兵天将,与孙大圣对话,问清原委。然后和悟空打赌,看着孙猴在自己掌心上翻筋斗云,写字做记号,外带撒泡猴尿。等观察泼猴折腾够了,再做下一步打算。
第二步:保护
在结合运行结果读懂了客户端和服务端接口实现的代码后,就可以列出那些被客户端调用的服务端的公共接口的实现代码的所有行为,之后再列出要驯服的这块代码的不会发生变化的所有主要行为,最后再编写上述所有这些行为的特征测试(Characterization Tests),来印证、刻画和保护这些实际的行为。
特征测试来自Michael Feathers的著作Working Effectively with Legacy Code一书的第13章,意思是刻画一块代码的实际行为。有点像军事上的“火力侦察”:即以火力袭击的方法,迫敌或诱敌还击,以暴露其火力配系,从而判明其兵力部署、阵地编成等情况。比如你读了一段代码,觉得它是做两个整数的加法的,你可以先写这样写断言:assertEquals("Failure - ", 0, 23+11);然后运行一下,在该测试运行失败的提示信息中,发现这样的错误:“期望是0,但实际值是34”,那么你就确信这确实是个做加法的行为。然后把断言改为:assertEquals("Failure - ", 34, 23+11); 这就完成了一个特征测试,来印证、刻画和保护了上述加法行为。
在《西游记》第二十三回“三藏不忘本,四圣试禅心”中,黎山老母、南海、普贤、文殊四位菩萨,分别变作阔宅中的一位美妇人和其貌若天仙的三位女儿,对唐僧师徒四人加以诱惑,以试探他们西天取经的决心。这妇人就好比给唐僧写了一个断言:assertEquals("Failure - ", "", 留下成亲做家长()); 给唐僧的三位徒弟写了另一个断言:assertEquals("Failure - ", "", 留下成亲做女婿()); 最后试探的结果大家都清楚:唐僧、悟空、沙僧的实际行为是“西天取经”,而八戒的实际值是“三个姐姐都许配给我吧!要不丈母娘你招了我吧!”在惩戒了八戒的凡心,印证了唐僧的决心之后,如来佛就一直为师徒四人的西天取经提供保护。
第三步:重构
重构看起来与修改代码没什么两样,但其实二者有本质不同。重构必须在测试的保护下才能进行。没有测试保护的修改代码只能叫做“裸奔”而不能叫做重构。
由于有了上面特征测试的保护,重构变得很安全,程序员修改代码的心情也会因为有保障而变得轻松起来。
我按照优先顺序依次做了下面三种方式的重构:1)消除所有重复代码,因为重复代码是万恶之源;2)将一个大型的类按照职责分解为若干较小的类,使得单一行为和与之相关的数据都集中在一个类中,这一点可以通过在前面系统主要行为的描述文字中找出所有名词来作为候选的小类来辅助进行;3)使用SonarQube来对代码进行静态扫描,修复所有严重性在Major及以上的问题。
在如来佛的保护下,在师父的紧箍咒的约束下,在两位师弟及白龙马的帮助下,孙悟空护送着唐僧,历经千辛万苦,不断战胜自己的弱点,进行着自己内心的重构,从最初“猖狂村野,屡反天宫”的泼猴,重构到最后“隐恶扬善,炼魔降怪,全终全始”的唐僧大徒弟,最终在取到了真经的同时,也把自己的内心重构到佛的境界,成为斗战胜佛。
观察、保护和重构,就是驯服Trivia烂代码的三个步骤。如果把齐天大圣孙悟空比作烂代码,那么把这个烂代码驯服为整洁代码的关键,我认为就是有像如来佛那样进行全程保护的测试代码。
请点击这里:https://github.com/wubin28/TriviaJava,来访问我上传到github上的驯服Trivia烂代码的源代码和重构步骤。