糟糕系统设计的代码重构

时间:2010-09-01 13:11:46

标签: java refactoring legacy-code

我是一名初级软件工程师,他接受了接管旧系统的任务。根据我的初步评估,该系统存在一些问题。

  1. 意大利面条代码
  2. 重复代码
  3. 10k及以上的课程
  4. 使用log4j误用和过度记录
  5. 糟糕的数据库表设计
  6. 缺少源代码管理 - >我为此设置了Subversion
  7. 缺少文件 - >除了阅读代码
  8. 之外,我不知道业务规则

    我应该如何去提高系统质量并解决这些问题?我可以考虑使用静态代码分析软件来解决任何不良编码实践。

    然而,它无法检测到任何不良设计问题或问题。我应该如何逐步解决这些问题?

14 个答案:

答案 0 :(得分:16)

获取并阅读Working Effectively With Legacy Code。它完全符合这种情况。

正如其他人也建议的那样,对于重构,你需要一套可靠的单元测试。但是,遗留代码通常很难进行单元测试,因为它尚未编写为可单元测试的。因此,您需要首先重构以允许单元测试,这将允许您开始重构......一个糟糕的捕获。

本书将帮助您。它提供了许多关于如何使用最小和最安全的代码更改来设计设计糟糕的代码单元的实用建议。自动重构也可以帮助你,但书中描述的技巧只能手工完成。然后,一旦第一组单元测试到位,您就可以开始逐步重构,以获得更好,更易维护的代码。

更新:有关如何接管旧代码的提示,您可能会发现此earlier answer of mine非常有用。

正如@Alex所指出的,单元测试对于理解和记录代码的实际行为也非常有用。当有关系统的文档不存在或过时时,这尤其有用。

答案 1 :(得分:14)

首先,不要修复未破坏的东西。只要你要接管的系统工作,就单独保留功能。

然而,在可维护性方面,系统显然被打破了,所以这就是你要解决的问题。如上所述,首先编写一些测试,然后在cvs中备份源代码,然后首先清理小块,然后是较大的块,依此类推。在您充分了解系统的工作原理之前,请不要攻击更大的架构问题。只要您不自己深入研究代码,工具就无法帮助您,但是当您这样做时,它们确实提供了很多帮助。

记住,没有什么是“完美的”。不要过度工程。遵守KISSYAGNI原则。

EDIT:添加了与YAGNI文章的直接链接

答案 2 :(得分:14)

首先关注稳定性。在应用程序周围存在某种稳定的环境之前,您无法增强或重构。

一些想法:

  1. 修订控制。你已经开始设置颠覆了。现在确保您的数据库模式,存储过程,脚本,第三方组件等也在版本控制之下。有一个版本标签系统,请确保标记版本,并在将来准确访问旧版本。
  2. 构建和发布。有办法在机器其他上构建稳定版本,而不是开发机器。您可能希望使用ant / nant,make,msbuild,甚至是批处理文件或shell脚本。如果它们不存在,您可能也需要部署脚本/安装程序。
  3. 正在接受测试。在您有办法知道您的更改是否已破坏之前,请勿更改应用程序。为此你需要测试。您应该希望能够为一些更简单的独立类编写xunit单元测试,但是尝试构建一些系统/集成测试来整体应用该应用程序。没有高代码覆盖率(您不必开始)集成测试是您最好的选择。养成尽可能经常运行测试的习惯。抓住一切机会扩展它们。
  4. 进行小型,专注的更改。尝试识别应用程序中的系统/子系统,并改善它们之间的界限。这可以减少您可能进行的更改的连锁效应。注意通过重新格式化或强加最新的时尚设计模式来“漂亮”代码的诱惑。转向这样的系统需要时间
  5. <强>文档即可。它是必要的,但不要太担心它。在我的经验中很少使用系统文档。好的测试通常比良好的文档更好。专注于记录应用程序与其运行的系统上下文(输入,输出,文件结构,数据库模式等)之间的接口。
  6. 管理期望。如果它形状不好那么它可能会抵制你做出改变的努力,而且时间尺度可能比平常更难以估计。确保管理层和利益相关者理解这一点。
  7. 不惜一切代价,要注意重写整件事的诱惑。在这种情况下,它几乎不是正确的事情。如果它有效,请集中精力保持其正常工作。

    作为初级开发人员,不要害怕寻求帮助。正如其他人所说,有效地使用遗留代码是一本很好的书,正如Martin Fowler的 Refactoring 一样。

    祝你好运!

答案 3 :(得分:8)

你的问题#7到目前为止 是最重要的。只要您不知道系统应该如何表现,所有技术考虑因素都是次要的。每个人都建议进行单元测试 - 但是如果你无法区分有用和无用的行为,你如何编写有用的测试呢?

因此,在开始触摸代码之前,您必须从用户的角度理解系统:与用户交谈,使用系统观察它们,在用例级别编写文档。

是的,我认真地建议你花几天时间,更可能是几周,而不需要改变一行代码。因为现在,你所做的任何改变都可能在你没有意识到的情况下破坏它。

了解应用后,您至少会知道哪些功能对测试很重要(手动或自动)。

答案 4 :(得分:6)

首先编写一些单元测试,并确保它们通过。然后,每做一次重构更改,只需继续确保测试不断通过。然后,您可以确信您对外界的应用程序行为没有改变。

这还有一个额外的好处,即测试将始终存在,因此对于任何未来的更改,测试仍应通过,以防止新更改中的任何回归。

答案 5 :(得分:3)

首先,确保您安装了源代码管理系统,并且所有源代码都已经过版本化并且可以构建。

接下来,您可以尝试为系统的核心部分编写单元测试。从那里,当你有一个或多或少坚实的回归测试体,你可以实际进行重构。

当我遇到凌乱的代码库时,我通常会首先重命名命名不佳的类型和方法,以更好地反映其初始意图。接下来,您可以尝试将大型方法拆分为较小的方法。

答案 6 :(得分:2)

请记住,这个遗留系统及其所有意大利面条代码目前都可以使用。不要因为看起来不那么美观而改变事物。专注于稳定性,新功能和在将旧代码从左右中心翻录之前熟悉。

答案 7 :(得分:1)

首先,我要说 Working Effectively with Legacy Code 可能是一本非常好的书,可以在一分钟之内通过三个答案来判断。

  
      
  1. 糟糕的数据库表设计
  2.   

这一个,你可能会被困住。如果您尝试更改现有数据库设计,则可能需要重新设计整个系统为现有数据编写迁移工具。别管了。

答案 8 :(得分:1)

我对这个问题的标准答案是:Refactor the Low-hanging Fruit。在这种情况下,我倾向于参加10K课程中的一个,并寻找Sprout Class的机会,但这只是我自己的倾向;您可能更愿意首先更改其他内容(设置源代码管理是优秀的第一步!)测试您可以做的事情;重构无法测试的东西,一步一步,让它变得更好。

请记住,随着你的进步,你做得更好;如果你只专注于有多糟糕的事情,你很可能会气馁。

答案 9 :(得分:1)

正如其他人所指出的那样,不要改变那些只是为了让它更漂亮的东西。您将引入错误的风险很大。

我的理念是:由于我必须进行更改以满足新要求或修复报告的错误,因此我尝试将我需要的代码更改为更清洁。无论如何,我将不得不测试更改的代码,所以现在是以较小的额外费用进行一些清理的好时机。

基本的设计变更是最难的,必须保存,以便你必须做出足够大的改变,无论如何都要测试所有改变的代码。

更改糟糕的数据库设计是最难的,因为许多程序可能会使用设计不佳的表。对数据库的任何更改都需要更改每个读取或写入它的程序。实现此目的的最佳方法通常是尝试减少访问数据库任何给定部分的位置数。举个简单的例子:假设有20个地方可以读取客户记录并计算客户账户余额。将其替换为一个读取数据库并返回总数的函数,以及对该函数的二十次调用。现在你可以改变客户记录的模式,只有一段代码可以改为20而不是20.原理很简单,但实际上访问给定记录的每个函数都不太可能做同样的事情。即使最初的程序员笨拙地写了相同的代码20次(不是不可能 - 我已经看到了很多),真实的情况可能不是他写了20次函数,期间,但他写了函数A 20次,功能B 12次,功能C 4次等

答案 10 :(得分:0)

关于这一主题的好书是有效地使用遗产代码作者Michael Feathers(2004)。它经历了一个小的改变过程,同时努力进行更大的清理。

  1. 写单元测试&amp;查找并删除重复的代码。
  2. 写单元测试&amp;将长方法分解为一系列简短方法。
  3. 写单元测试&amp;查找并删除重复方法。
  4. 写单元测试&amp;拆分班级,以便遵循single responsibility principle

答案 11 :(得分:0)

Working Effectively With Legacy Code可能会有所帮助。

答案 12 :(得分:0)

设计问题很难掌握。首先要了解应用程序的设计。我发现使用UML或流程图对图表有用,任何可以传达设计和为应用程序工作的工作。

从那里我进入更多细节,并问自己“我会以这种方式做到这一点”的问题,还有其他选择。很容易看到代码债务,即我们从做出错误选择中获得的债务,总是很糟糕,但有时还会涉及其他因素,如预算,时间,资源的可用性等等。他们你必须提出问题,如果它值得重构一个工作但设计糟糕的应用程序。

如果有许多即将推出的新功能,更改,错误修复等,我会说重构很好,但如果应用程序很少更改并且稳定,那么可能将其保留为更好的方法。

另一个需要注意的方面是,如果代码被另一个应用程序用作服务或模块,那么重构可能首先意味着在服务器作为接口的代码周围创建一个存根,一旦明确定义并具有单元测试证明它有效。您可以选择任何技术来填写详细信息。

答案 13 :(得分:0)

首先尝试创建一些可以触发代码中某些操作的单元测试。

承诺SVN和TAG中的每一个(如果出现问题,你将有一个逃生舱)。

使用inCode Eclipse插件http://www.intooitus.com/inCode.html并查找它提出的重构内容。检查提议的重构是否适合您的问题。试着理解它们。

使用之前创建的单位重新测试。

现在您可以使用FindBugs和/或PMD来检查其他细微问题。

如果一切都是oka,您可能需要再次办理登机手续。

我还尝试阅读源代码,以便检测可以应用模式的一些情况。

相关问题