遗留代码处理建议

38

我需要关于如何处理遗留代码的建议。

有一段时间,我被分配任务给一个报表应用程序添加一些报告。这个应用程序是在2005年写的,使用Struts 1框架,但代码非常混乱。没有使用Action forms,基本上所有的代码都在一个巨大的Action中,里面有很多的if-else语句。此外,我们这里没有人对其进行功能知识的了解,只是因为它在合同中被提到才拿到了这个任务。

我对此感到非常不满意,不确定该如何继续。这个应用程序很隐蔽:很少有人使用(但所有人都非常重要),所以他们不在意我读代码时是否会流血。然而,我觉得存在技术债务需要偿还。我该怎么办?继续按照if-else的方式继续下去,还是尝试用正确的方法来完成这个需求,忽略项目的其他部分?冒着无法在截止日期前完成的风险开始一个庞大的重构工作?


9
这是一本名为《遗留代码改善手册》的书,作者是迈克尔·费瑟斯。如果你需要购买这本书,可以前往 http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052 。 - Dave Swersky
@Dave 是的,我的公司已经购买了它,但是其中一个大公司也拥有它。很遗憾 :( - Tom
@Carl:这在我的愿望清单上 :-)。 - Tom
2
@Dave @Carl,我从大牛那里拿了这本书 :) - Tom
我因此失去了一份工作。不要重构代码!没有人会欣赏它。 - Ali Saberi
4个回答

46

传统代码是一个大问题,我相信人们不会同意!

我认为开始进行大规模的重构可能是一个错误。

大规模的重构意味着要做很多工作,使其功能完全与现在一样。如果你选择独自承担这个责任,你所做的事情就不会有太多的可见性。如果它起作用了,没有人会知道你花了多少时间来实现它。如果它不起作用,而你最终获得了整洁的代码,但添加了一些错误(谁写的代码没有添加一些错误),那么你将会得到“为什么改变了这个”的问题。

我目前正在完成一个基于10年旧代码库的项目。我们一路上已经做了不少重构的工作。但对于每次重构,我们都可以证明“这个具体的变化将使我们正在做的实际任务更容易”。而不是“为未来的工作更清晰”。我们发现,在处理遇到的每一个问题时,我们都修复了很多问题,而没有(太多)破坏它。

在很多情况下,在进行重构之前,您需要进行自动化测试,这样您就可以比较确信地把它正确地组合起来!

大多数重构都是为了“使维护和未来开发更容易”。你的项目似乎没有太多未来的发展。这限制了重构对公司的优势。


你说得很对,这个项目大部分时间都处于冻结状态。 - Tom
"在大量重构之前,我会说您需要自动化测试,这样您可以相当确信已经正确地将其重新组合在一起!" 如果您的代码库需要进行重大更改才能支持单元测试怎么办? - NeverEndingQueue
我的意见?你需要证明重构没有破坏任何东西。你会怎么做呢?手动测试可能比自动化测试更好,如果自动化测试需要太长时间的话。我发现在使用VMware集成时,自动化测试成本太高了。 - Jon

10

规则#1:如果它没坏,就不要修。

规则#2:如果不确定,重新阅读规则#1。

不幸的是,遗留代码很难被描述为“没有问题”。因此,我们必须调整现有代码来纠正新发现的错误、修改以前可接受的行为或添加新功能。

我的经验告诉我,任何重构都必须采用“无限小”的增量。如果你必须违反规则#2,我建议你从最内层嵌套循环或IF结构开始搜索,并向外扩展,直到找到一个清晰、逻辑的分离点,并创建一个只包含该循环或结构的实质内容的新函数/方法/子程序。这不会使任何东西更有效率,但应该让您对底层逻辑和结构有更清晰的视角。一旦你有了几个新的、较小的函数/方法/子例程,你可以将它们重构和合并成更可管理的东西。

规则#3:忽略我的上一段话,重新阅读前两条规则。


1
修复遗留代码占据了我大部分的专业工作时间,因此我不得不表示不同意。我试着牢记营地原则,让它比你发现时更好,但要在合理范围内。没有人会因为你推倒厕所而感谢你。 - Chris Huang-Leaver

4

我同意其他评论。如果你不必要做这个,那就不要做了。如果代码库已经死亡或者接近死亡,那么它的价值往往远远不如它的成本。

另一方面,如果你觉得自己无法理解代码,那么重构可能是不可避免的。既然这是一个Web应用程序,你能否使用Selenium创建一个可靠的功能测试套件呢?如果可以的话,这是处理此类代码最快、最有回报的测试方法,并且可以捕获大部分错误。

其次,从提取方法重构开始,创建大型复杂方法的组合方法。每当你想到“这应该有一个注释来解释它的作用”时,你都应该提取出一个方法,并用一个替换注释的名称来命名它。

一旦完成了这些步骤,如果你仍然无法添加所需的功能,你可以进行更高级的重构,甚至添加一些单元测试。但我通常发现,通过创建自我说明的代码,我可以在遗留代码中添加所需的内容/修复错误。


这让我失去了一份工作! - Ali Saberi

3
简而言之,在对传统代码进行任何修改之前,最好先从自动化单元测试开始。这将使开发人员了解关键事项:此代码段具有的依赖项、输入数据、输出结果、边界条件等等。
完成后,您很可能会更好地了解此代码的功能和工作原理。
在此之后,清理一下代码,为本地变量命名更准确,将某些功能(如果有)移入具有清晰人性化名称的函数中。
简单的清理可以使代码更易读,并同时通过单元测试帮助开发人员避免回归问题。
重构——逐步进行小规模的更改,当您有时间和对要求和功能的了解时,定期进行单元测试。
但不要从重构开始。

我很少遇到需要进行这种重构以便在任何合理的级别上进行测试的遗留代码... - Joe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接