• 2012-07-18

    实战遗留代码

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/220017682.html

    什么是遗留代码?没有自动化测试的代码就是遗留代码,不管它是十年前写的,还是昨天写的。

    关于遗留代码,《修改代码的艺术》迄今为止依然是在具体手法上讲得最好的一本书。

    不过,这本书上来就直奔代码,还有一些东西是技法之外的。

    搭建基础设施

    做软件,没有自动化,基本上都算刀耕火织。关于基础设施,我曾写过一篇很长的文章,以我实际的一个项目为例,介绍了一些设施的基本样子。

    那篇文章很长,具体到面对遗留代码,有哪些特别之处呢?

    我们的目标是给没有测试的遗留系统增加代码,那么,那么增加代码覆盖率检查是一个不错的选择,各种语言都有自己的测试覆盖率方案。与单纯使用测试覆盖率不同的是,我们需要保证测试覆盖率只能提升,不能降低。所以,这里可能会略有一些开发的工作量。

    此外,遗留代码的质量往往不高,除了测试覆盖率工具,我们还可以引入各种代码检查工具,同时,采用同上面类似的做法,保证各种错误只能减少,不能增加。

    这里的基本想法很简单,不要在废墟上继续破坏。

    补测试

    理想中,我们要为所有代码补上测试,但是,这种想法不现实,很简单,欠账太多。

    一个更为实际的做法是,任务驱动。根据要解决的问题,先把周边代码清理干净,然后再实现新需求。

    动手清理之前,我们要先补写验收测试,这样做主要是为了保证我们不会产生大规模的破坏。对于比较复杂的场景,要补的测试可能会比较多,但请记住,这是欠账,昨日的帐,今天补当然会很痛苦。

    补完验收测试,就该补单元测试了,补单元测试的做法有几种,无论哪种做法,我们都要先理解一下要动到的代码。

    如果面对的函数比较小,理解起来比较容易,我们就可以直接为它补充单元测试。如果函数比较大怎么办呢?一次看懂所有的逻辑几乎就是一项不可能完成的任务,但通常,即便不能理解所有的代码,但至少我们可以理解一个片段。我们能做的就是把这个可以理解的片段提取到一个单独的函数里,然后,测试这个单独的片段。

    在具体操作的层面上,经常出现的问题是,我们理解了这段丑陋的代码,脑子里常会不经意闪过这段代码未来的样子,所以,一动手就直奔目标样子而去,请停下来。先把这段完整的复制到待测函数里,然后给它写测试,测试通过之后再说重构的事。请记住,步子大了,容易扯到蛋。

    这个片段函数做完之后,我们再回到原来的函数里,在原来片段的地方,调用这个新函数。然后,再继续理解,继续分解,继续补测试,继续重构,继续替换原有调用。如此N番,你会发现,那个复杂的大函数也不像原来那样不可理喻了,这时候,如果还需要,对这个函数,我们也可以如法炮制。

    添加新代码

    所有一切准备就绪,才是添加新代码的时机。

    或许,这种做法会让曾经在开发中健步如飞的你有一种举步维艰的感觉,但请记住,曾经的健步如飞是你的错觉,因为当初的你并没有完成你该做的事情,那是欠账。

    出来混,迟早要还的。

    分享到:
    引用地址:

    评论

  • 可能没有做过单元测试的原因吧,总觉的重构代码不能细节到每个函数做测试,通常OOP会关联好多类.好多不同的状态.