事实证明,跟遗留代码打交道未必需要花费数天时间去研究晦涩难懂的注释。要想找到并修复漏洞,开发者可采用简单的测试工具来对问题抽丝剥茧。
跟遗留代码打交道会是比较困难的,尤其是如果代码是由某位不知道名字的程序员用一种不熟悉的语言编写的话。但跟据Mob Programming 的R Jason Kerney 和Llewellyn Falco的说法,遗留应用中的bug是可以相对迅速地发现和修补好的,这个过程只需要若干相当直截了当的技巧。
“我通常是没有机会去理解(遗留)代码的,所以我必须想出办法在不理解的情况下继续工作,”Falco说。
在奥兰多举行的Agile2014的一场研讨会上,Falco和Kerney展示了他们在不需要过多的研究遗留代码的情况下寻找和修补漏洞的能力。该研讨会的主题是遗留代码处置,两位程序员把有效地跟遗留代码打交道比作切芒果。芒果肉就是重要代码。其余的则是皮或者核。他们给自己的技术起了个通俗的叫法:“去皮切块”。
去皮切块法的原理是缩小焦点直至待检查的代码是与特定漏洞直接相关的。Falco解释了如何从外部开始层层剥离直至重要的代码。Kerney展示了如何在存疑的代码中切块。这样的话,很容易就可以看到哪里出了问题,知道如何去修复。
用例
他们使用了一个假设的金融应用来进行演示,该应用会在给现有记录追加信息时时产生多项新记录。大致是如果“Joe”有3笔独立的贷款,遗留代码就会为他生成3条独立的记录,每一笔贷款一条。应用应该已经给Joe原来的那条记录追加了贷款。
讨论的遗留应用假设是由捷克的外包软件团队编写的,现在这支团队已经不复存在,因此没人可以对代码做出解释。在这种设想的情况下,是没有办法可以轻松访问数据库本身的,因此也没办法通过库去了解。
难以破译的遗留代码样例
唯一知道的变量是代码执行时预期应该做什么事情,以及代码的实际执行情况。Falco和Kerney说,仅利用这一点信息,他们就可以确定遗留代码的问题出在哪里并修复问题。
代码分离
剥除代码技术要求把硬代码和重要代码分离。基本计划是把一个复杂的方法分成两部分。第一部分包含的是硬代码,第二部分包含的是我们希望理解的代码。然后把重要代码析取出来作为第二个方法,与其他代码区隔对待。
一般而言,这会需要对“代码的推拿”进行一些简单的重构,让执行顺序变得更加可行。Kerney和Falco强调,这一重构仍然是非常简单的,足以在无需理解待测遗留应用的遗留代码库的情况下就能完成。
逐块分割
往往会有部分代码不好打交道,没办法像上面那样进行分离。这些就是Falco-Kerney芒果方法论中的坑。这里就要采取切割术了,即把有问题的组件模拟出来。
Kerney使用了一种叫做EasyMock的工具来把数据库模拟出来,然后把它从不相干的东西中抽象出来。他指出这与测试驱动开发的模拟过程非常类似。区别只是前者不去检查新代码是否通过测试,而是测试现有代码中那一部分没有通过测试。
打补丁
通过首先剥除问题范围以外的代码,然后将问题范围内不相干的代码切除,Falco 和Kerney最后得到的几行代码可能就是问题所在。由于只需要聚焦于几行代码,两人就可以更好的确定什么地方出了问题。
在本例中,最后的结果表明,有两行代码写错了次序。通常情况下这两行代码的次序是没有影响的。这里出了问题是因为Java语言及其运作方式的错综复杂。
Falco和Kerney对简化后的代码运行测试时,显然是第一行代码被调用得太快了。找到正确的顺序、修订漏洞并反败为胜并没有花费太多的时间—这一切都不需要理解代码。
一点告诫
重要的是要注意到这些技术并不能保证新的依赖性错误不会发生,如果外部代码引用了被修改的代码的话。然而,正如Kerney所指出那样:“理解代码并不能确保在其身上不会出现任何连绵不绝的依赖性。”
至于在旧的遗留应用上寻找和修补漏洞,有人会提出说找出遗留代码的工作方式纯属浪费时间。不花时间学写代码的话可能会丧失掉一些(也许是可观的)学习的机会。然而,如果这种学习如果真的值得开发者花时间的话,他或她可以在漏洞解决之后再去学习代码。
看看工具
Falco和Kerney利用了面向Java的软件工具进行演示。他们使用的基础工具是Eclipse IDE、JUnit测试工具、覆盖测试用的是EclEmma,模拟对象则使用EasyMock来生成。究竟用什么工具要视具体的项目而言。
后续步骤
Llewellyn Falco针对.Net开发者解释这些过程的系列视频可以在YouTube上面找到。
你可能不想将遗留应用迁移到云上,但在云端进行开发和测试仍然有一些好处。
当你把遗留代码的所有漏洞都补上时别忘了跟踪新项目的缺陷。