您可以对遗留代码库做哪些对提高质量影响最大的事情?
-
02-07-2019 - |
题
当您在遗留代码库中工作时,随着时间的推移,什么会对提高代码库的质量产生最大的影响?
- 删除未使用的代码
- 删除重复的代码
- 添加单元测试以提高覆盖率较低的测试覆盖率
- 跨文件创建一致的格式
- 更新第三方软件
- 减少静态分析工具(即 Findbugs)生成的警告
该代码库是由许多具有不同专业水平的开发人员多年来编写的,其中许多领域未经测试,有些领域在没有花费大量时间编写测试的情况下无法测试。
解决方案
- 阅读迈克尔·费瑟的书 “有效地使用旧代码”
这是一本很好的书。
如果您不喜欢这个答案,那么我能给的最好建议是:
- 首先,停止编写新的遗留代码[1]
[1]:遗留代码 = 没有单元测试的代码,因此是未知的
在没有适当的自动化测试套件的情况下更改遗留代码是危险且不负责任的。如果没有良好的单元测试覆盖率,您不可能知道这些更改会产生什么影响。Feathers 建议采用“束缚”方法,在该方法中,您可以隔离需要更改的代码区域,编写一些基本测试来验证基本假设,在单元测试的支持下进行小的更改,然后从那里开始工作。
笔记:我并不是说您需要停止所有事情并花费数周时间为所有事情编写测试。恰恰相反,只需围绕您需要测试的区域进行测试并从那里进行解决即可。
吉米·博加德和雷·休斯顿针对与此非常相似的主题做了一个有趣的屏幕拍摄:http://www.lostechies.com/blogs/jimmy_bogard/archive/2008/05/06/pablotv-elimination-static-dependency-screencast.aspx
其他提示
我使用的是由大约 50 名程序员编写和修改的遗留 1M LOC 应用程序。
* Remove unused code
几乎没用...忽略它即可。您不会从中获得很大的投资回报 (ROI)。
* Remove duplicated code
事实上,当我修复某些东西时,我总是寻找重复的东西。如果我发现一些,我会放置一个通用函数或注释所有出现重复的代码(有时,放置通用函数的努力并不值得)。主要的想法是,我讨厌多次做同样的动作。另一个原因是因为总是有人(可能是我)忘记检查其他事件......
* Add unit tests to improve test coverage where coverage is low
自动化单元测试很棒......但如果你有大量的积压,任务本身就很难推进,除非你有稳定性问题。继续你正在做的部分,并希望在几年内你能获得不错的覆盖范围。
* Create consistent formatting across files
IMO 格式上的差异是遗产的一部分。它可以提示您代码是由谁或何时编写的。这可以为您提供一些关于如何在该部分代码中表现的线索。重新格式化的工作并不有趣,而且不会为您的客户带来任何价值。
* Update 3rd party software
仅当有新的非常好的功能或新操作系统不支持您所拥有的版本时才执行此操作。
* Reduce warnings generated by static analysis tools
这是值得的。有时警告可以隐藏潜在的错误。
我想说“删除重复的代码”几乎意味着你必须提取代码并对其进行抽象,以便它可以在多个地方使用 - 从理论上讲,这使得错误更容易修复,因为你只需要修复一段代码,而不是许多代码段,修复其中的错误。
我可以联系到这个问题,因为我目前在我的腿上有一个“那些”旧学校代码库。它并不是真正的遗产,但它肯定没有追随这些年来的趋势。
我会告诉你我想解决的问题,因为它们每天都困扰着我:
- 记录输入和输出变量
- 重构变量名称,使它们实际上意味着其他含义,一些匈牙利符号前缀后跟三个字母的首字母缩略词,具有一些晦涩的含义。CammelCase 是正确的选择。
- 我非常害怕更改任何代码,因为它会影响数百个使用该软件的客户,甚至有人会注意到最隐秘的副作用。任何可重复的回归测试都将是一件幸事,因为现在为零。
剩下的确实是花生。这些是遗留代码库的主要问题,它们确实消耗了大量的时间。
我想说这很大程度上取决于您想如何处理遗留代码......
如果它将无限期地保持在维护模式并且工作正常,那么什么都不做是最好的选择。“如果它没有坏,就不要修理它。”
如果它不能正常工作,删除未使用的代码并重构重复的代码将使调试变得更加容易。但是,我只会对错误代码进行这些更改。
如果您计划使用 2.0 版本,请添加单元测试并清理您将提出的代码
好的文档。作为必须维护和扩展遗留代码的人,这是头号问题。更改您不理解的代码即使不是非常危险,也是很困难的。即使您足够幸运获得了文档化的代码,您如何确定文档是正确的?它涵盖了原作者的所有隐性知识吗?它涉及所有“技巧”和边缘情况吗?
好的文档可以让原作者以外的人理解、修复和扩展甚至是糟糕的代码。我会在一周中的任何一天采用我可以理解的被黑客攻击但记录良好的代码,而不是完美但难以理解的代码。
我对必须使用的遗留代码所做的最重要的一件事就是围绕它构建一个真正的 API。这是一个 1970 年代风格的 COBOL API,我围绕它构建了一个 .NET 对象模型,因此所有不安全代码都位于一个位置,API 的本机数据类型和 .NET 数据类型之间的所有转换都位于一个位置,主要方法返回并接受数据集,等等。
正确地做到这一点非常困难,而且据我所知,其中仍然存在一些缺陷。由于所有的编组工作都在进行,它的效率也不是很高。但另一方面,我可以构建一个 DataGridView,将数据往返到一个已有 15 年历史的应用程序,该应用程序在大约半小时内将其数据保存在 Btrieve (!) 中,并且它可以工作。当客户向我提出项目时,我的估算会以天或周为单位,而不是以月或年为单位。
与乔什·西格尔所说的类似,我想说的是不要评论它。我曾经开发过几个非常大的遗留系统,但这些系统都被扔在了我的腿上,我发现最大的问题是跟踪我已经学到的关于特定代码部分的知识。一旦我开始边走边记笔记,包括“待办事项”笔记,我就不再重新思考我已经弄清楚的事情了。然后我可以专注于这些代码段如何流动和交互。
我想说的是,在大多数情况下,不要管它。如果没有损坏,就不要修理它。如果它被破坏了,那么继续修复和改进被破坏的代码部分及其周围的代码。您可以利用错误或严重缺失的功能带来的痛苦来证明改进该部分的努力和费用是合理的。
我不会建议任何不以实际业务或最终用户需求为指导的大规模重写、重构、重新格式化或放入单元测试。
如果你确实有机会修复某些问题,那么就把它做对(第一次做对的机会可能已经过去了,但既然你再次接触到那个部分,也可能在以后的时间里做对),这包括所有你提到的项目。
总而言之,您应该做的不是单一的或只有几件事。你应该把这一切都做完,但要小部分地、以机会主义的方式做。
虽然迟到了,但在经常使用或引用函数/方法的情况下,以下可能值得做:
- 局部变量在遗留代码中通常命名不当(通常是由于修改方法时它们的范围扩大,并且没有更新以反映这一点)。根据它们的实际目的重命名它们可以帮助澄清遗留代码。
- 即使只是稍微不同地布置方法也能产生奇迹 - 例如,将
if
在一条线上。 - 那里可能已经有陈旧/令人困惑的代码注释。如果不需要,请将其删除;如果绝对必要,则修改它们。 (当然,我并不是主张删除有用的评论,只是主张删除那些有障碍的评论。)
这些可能不会产生您正在寻找的巨大的标题影响,但它们的风险较低,特别是在代码无法进行单元测试的情况下。