你如何重构一个大杂乱的代码库?

我有一大堆的代码。 无可否认,我自己写的 – 一年前。 它没有很好的评论,但它也不是很复杂,所以我可以理解它 – 只是不足以知道从哪里开始重构它。

我违反了过去一年里我读过的每一条规则。 有多种职责,有间接访问(我忘记了这个词 – 就像foo.bar.doSomething() ),就像我说的那样,它没有很好的评论。 最重要的是,这是一个游戏的开始,所以graphics与数据,或者我尝试去耦graphics和数据的地方,我公开的数据,以便graphics能够访问数据它需要…

这是一个巨大的混乱! 我从哪说起呢? 你将如何开始这样的事情?

我目前的做法是采取variables并将其切换为私有,然后重构那些破碎的碎片,但这似乎还不够。 请build议其他策略,通过这混乱趟过,把它变成干净的东西,让我可以继续我离开的地方!


两天后更新:我一直在绘制出类似UML的图表,并一路捕捉到了一些“低悬的果实”。 我甚至发现了一些代码是新function的开始,但是当我试图减less一切,我已经能够删除这些位,并使项目更清洁。 在安装我的testing用例之前,我可能会尽可能地重构(当然,只有100%肯定不会影响function的东西),所以我不必重构testing用例,因为我改变function。 (你认为我是对的还是对的,在你看来,我会更容易把它搞砸,并且先写testing?)

请投票给最好的答案,以便我可以公平地标记! 随意添加你自己的答案,以及还有空间给你! 我会再给它一天左右,然后可能标记最高票数的答案被接受。

感谢到目前为止所有人的回应!


2010年6月25日:我发现了一篇博客文章 ,直接回答这个问题,这个人似乎对编程有很好的把握(或者,如果你阅读他的文章,也许不会):)

为此,当我需要重构代码时,我做了四件事情:

  1. 确定代码的目的是什么
  2. 绘制所涉及的类的UML和动作图
  3. 选购正确的devise模式
  4. 确定当前类和方法的更清晰的名称

为自己找一份Martin Fowler的重构副本。 对于如何打破重构问题,有一些很好的build议。 本书中约75%是小菜谱式的重构步骤。 它还提倡自动的unit testing,您可以在每个步骤后运行,以certificate您的代码仍然有效。

至于要开始的地方,我会坐下来画出一个高层次的程序架构。 你不必对UML模型有兴趣,但是一些基本的UML并不是一个坏主意。 您需要了解主要部分如何组合在一起的全景图,以便您可以直观地看到脱钩将发生的位置。 只是一个或两个基本的框图将有助于你现在压倒一切的感觉。

没有某种高层次的规格或devise,你只会冒险再次迷路,结束了另一个难以维系的混乱。

如果你需要从头开始,请记住,你从来没有真正从头开始。 你有一些代码和你第一次获得的知识。 但是有时候,这有助于从一个空白的项目开始,随时随地拉取内容,而不是在混乱的代码库中扑灭火灾。 只要记住不要完全丢弃旧的,用它的好的部分,并把它们拉进去。

在不同场合下最重要的是unit testing:我花了几天的时间为旧代码编写testing,然后我可以自信地重构。 究竟是一个不同的问题,但是通过testing使我能够对代码进行真正的实质性的改变。

我将会介绍每个人对福勒重构的build议,但是在具体的情况下,您可能需要看看迈克尔·羽毛与遗产代码的有效合作 ,这对您的情况来说是非常完美的。

Feathers谈到了Characterization Tests ,它是unit testing,不是断言系统的已知行为,而是探索和定义现有的(不清楚的)行为 – 在你编写自己的遗留代码并自行修复的情况下,可能不是那么重要,但是如果你的devise是sl then不驯的,那么很可能有一部分代码是“神奇”的,他们的行为并不清晰,甚至对你来说也是如此 – 在这种情况下,特征testing将会有所帮助。

本书最重要的部分是关于在代码库中寻找(或创build) 接缝的讨论 – 接缝是自然的“故障线路”,如果你愿意的话,可以进入现有系统开始testing,并将其拉向一个更好的devise。 很难解释,但值得一读。

有一个简短的论文 ,羽毛充实了书中的一些概念,但是真的很值得去追查整个事情。 这是我的最爱之一。

只是一个额外的重构,比你想象的更重要:正确地命名的东西!

这适用于任何variables名称和方法名称。 如果名称不能准确地反映出所使用的内容,则将其重命名为更精确的内容。 这可能需要几次迭代。 如果你找不到一个简短的,完全准确的名字,那么这个项目就太多了,你有一个很好的候选人的代码片段需要拆分。 这些名字也清楚地表明了切割的地方。

另外,logging你的东西。 每当答案为什么? 没有清楚地传达出如何回答? (作为代码),您将需要添加一些文档。 捕获devise决策可能是最重要的任务,因为在代码中很难做到。

你总是可以从“scratch”开始。 这并不意味着从零开始,而是从一开始就尝试重新考虑高层次的事情,因为从上一次工作以来,你似乎学到了很多东西。

从更高的层次开始,在构build新的和改进的结构的脚手架时,将所有可以重用的代码放在一起,如果您愿意通读并做一些小改动,可能会超出您的想象。

当你做出改变的时候,一定要严格遵守你现在知道的所有好的做法,因为以后你会真的感谢你。

正确地重新制作程序以完成之前所做的事情,只是更“干净地”,可能令人惊讶地令人耳目一新。 ;)

正如其他人所提到的, unit testing是你最好的朋友! 它们可以帮助你确保你的重构工作,如果你是从“scratch”开始的话,现在是编写它们的最佳时机。

与许多面临这个问题的人相比,你的位置要好得多,因为你明白代码应该做什么。

将variables从共享范围中移出,这是一个很好的开始,因为您正在分配责任。 最终你希望每个class级expression一个责任。 其他一些你可能会看到的事情:

  • 容易重构的目标是在许多地方和长方法中重复的代码。
  • 如果你正在通过静态初始化单例pipe理应用程序状态,或者更糟糕的是,一切都在讨论的全局状态,考虑将其移动到托pipe初始化系统(即像Spring或Guice这样的dependency injection框架),或者至less确保初始化不与其他代码纠缠在一起。
  • 集中并标准化你访问外部资源的方式,特别是如果你有文件位置或URL等硬编码的东西。

购买具有良好重构支持的IDE。 我认为IntelliJ是最好的,但Eclipse现在也有。

unit testing的想法也是关键。 您将希望拥有一整套大型的整体交易,这些交易将为您提供代码的整体行为。

一旦你有了这些,开始创build类和小包的unit testing。 编写testing以certificate正确的行为,进行更改,然后重新运行testing,以certificate您没有破坏所有内容。

跟踪代码覆盖率。 你会想要达到70%甚至更好。 对于你改变的课程,你会希望那些在你做出改变之前达到70%或更好。

随着时间的推移build立安全网,你将能够重build一些信心。

很慢:D

没有认真的…一步一个脚印。 例如,只有在影响或帮助您编写当前正在执行的错误/function并重复执行的情况下,才能重构某些内容。 在你重构之前,确保你有一些自动化的testing,在每个构build中运行,实际上将testing你正在写/重构。 即使你没有进行unit testing,也不会太晚,无法为正在编写的所有新的和修改的代码添加它们。 随着时间的推移,你的代码基数将会以每天或每周的小幅度增长,而不是更糟糕的 – 所有这些都不会造成巨大的变化。

以我个人的观点和经验来说,为了重构而重组一个(遗留)代码库是不值得的。 在这种情况下,最好从头开始,重新做一次(很less有机会做这样的事情)。 因此,只需重构渐进式即可。

我认为你应该使用Eclipse作为一个IDE,因为它有很多插件和免费的。你现在应该遵循MVC模式,是的必须使用JUnit编写testing用例.Eclipse也有JUnit的插件,它也提供代码重构工具这样会减less你的一些工作。而且总是记得编写一个代码并不重要,主要的事情就是编写干净的代码。所以现在给所有人发评论,这样不仅你自己而且还有其他人读代码,然后在阅读代码的时候他一定觉得他在读散文。

重构低悬的果实。 轻咬一下,就这样,更难的一点就开始变得容易一些了。 当没有任何剩余的位可以重构时,就完成了。

您可能会发现最有用的重构是重命名方法 (甚至更重要的重命名,如字段,variables和参数), 提取方法和提取类 。 对于您执行的每个重构,编写必要的unit testing以使重构安全,并在每次重构之后运行整套unit testing。 这是诱人的 – 而且说实话,相当安全 – 依赖于IDE的自动化重构,没有testing – 但是这是一个很好的实践,并且随着向项目添加function将来的testing将会很好。

你可能想看Martin Fowler的书Refactoring 。 这是一本推广术语和技巧的书(我的思路是:“我一直在做很多这样的事情,我不知道它有一个名字”)。 来自链接的报价:

重构是用于改进现有代码库devise的受控技术。 它的实质是应用一系列小的行为保存转换,每个转换“太小,不值得去做”。 然而,这些转变的累积效应是相当显着的。 通过小步骤完成它们,可以降低引入错误的风险。 您还可以避免在进行重组时使系统崩溃 – 这使您可以在较长的时间内逐渐重构系统。

正如其他人所指出的那样,unit testing可以让你自信地重构。 并开始减less代码重复。 这本书会给你很多其他的见解。

这是一个重构的目录 。

对于Java代码,我最喜欢的第一步是运行FindBugs,然后删除所有的死存储区,未使用的字段,无法访问的catch块,未使用的私有方法和可能的错误。

接下来我运行CPD来查找剪切复制粘贴代码的证据。

通过这样做可以减less5%的代码量并不罕见。 它还可以避免从未使用过的重构代码。

乱码的正确定义是难以维护和修改的代码。
要使用更多的math定义,可以使用代码度量工具检查代码。
这样,你会保持已经足够好的代码,并且发现速度非常快,错误的代码。
我的经验说,这是提高代码质量的非常有效的方法。 (如果您的工具可以显示每个构build或实时的结果)

扔掉它,build立新的。