你怎么重构?

时间:2008-10-15 16:31:17

标签: unit-testing refactoring

我想知道其他开发者如何开始重构。你的第一步是什么?如果你重构不属于你的代码,这个过程(重构)会有什么不同?你在重构时编写测试吗?

14 个答案:

答案 0 :(得分:25)

  1. 不重构任何尚未进行单元测试的非平凡
  2. 编写单元测试,然后重构
  3. 重构小块并经常重新运行测试
  4. 当代码为DRY * clean
  5. 时停止重构

    * DRY =不要重复自己

答案 1 :(得分:8)

  

你的第一步是什么?

第一步是运行单元测试以确保它们全部通过。实际上,如果在修改代码之前已经破坏,您可以浪费大量时间来查找哪些更改破坏了测试。

  

如果您重构不属于您的代码,此过程有何不同?

在重构我没写过的代码(或者我很久以前编写过的代码)时,我肯定会做更小的步骤。我还可以在继续之前验证测试覆盖率,以避免依赖于总是通过的单元测试......但是没有测试我正在研究的区域。

  

你在重构时编写测试吗?

我通常不这样做,但我可能会在以下情况下添加新测试(列表并非详尽无遗):

  • 一个新测试的想法闪现在我的脑海中(“如果......会发生什么?” - 写 一个测试知道)
  • 在测试范围内发现漏洞

它还取决于正在执行的重构。在提取函数时,我可以创建一个新的测试,如果它可以像以前那样以不同的方式调用。


以下是一些一般性建议:

首先要在处理代码时保持注意到的code smells列表。这样可以让人们摆脱记住代码中所见内容的负担。另外,

当单元测试没有完全通过时,黄金法则永远不会重构。

在代码稳定之前重新构建,在添加您知道的内容之前将受到未来重构的影响,然后再进行集成,最重要的是之后再说完

如果没有单元测试,则必须将要重构的代码部分放在测试中。如果单元测试太难以改造(通常是这种情况),那么您可以按照characterization tests的建议创建Michael Feathers in Working Effectively with Legacy Code。简而言之,它们是端到端测试,允许您确定代码的当前行为(不会假设它始终完美运行)。

不要害怕做婴儿步骤。不要同时做两件事。如果你注意到需要重构的东西,请记下来,不要立即修复它,即使看起来很容易。

在测试通过时经常检查。这样你就可以在不丢失以前所做的事情的情况下恢复糟糕的重构。

请记住,重构不会为您的客户增加价值(这可以讨论),但客户不会向您支付重构费用。一个经验法则是重构之前进行更改或向代码添加新功能。

答案 2 :(得分:4)

我采取废话,使其不那么糟糕。 : - )

严重。我不重构创建新功能。重构发生在新东西之前。如果没有测试我会编写测试以确保我没有因为重构而破坏任何东西。如果有测试,我会使用它们。如果测试不充分,我可能会编写更多的测试,但我会将其与重构分开考虑并首先进行。

对我而言,第一步是注意我可以抽象一些东西并使其更通用(并且在其他需要现在功能的地方也很有用),或者我注意到某些东西是坏的并且可能更好(主观)。我没有理由不重构一般性。 YAGNI principle适用。

我们有共享所有权的概念,所以代码总是我的 - 我可能没有写过它,但我在重构时没有考虑到。如果目的不明确,我可能会在我决定需要重构之前寻求理解事物 - 虽然这几乎总是重构其中的理由。

答案 3 :(得分:4)

阅读Martin Fowler的书“Refactoring

BTW - 这是Martin Fowler自己的亚马逊执行官链接,如果你想知道:)

答案 4 :(得分:3)

非常依赖我的目标。如前所述,您需要进行单元测试以确保您的重构没有破坏任何东西,如果有,您必须花时间修复它。在许多情况下,我测试现有的解决方案,如果它有效,请将其包装而不是重构,因为这样可以最大限度地减少中断的可能性。

如果我必须重构,例如我最近不得不将一堆基于ASCII的C ++移植到UNICODE,我倾向于确保我在最终用户和单元级别都有良好的回归测试。同样,我尝试使用工具而不是手动重构,因为这不容易出错,而且你得到的错误是系统的而不是随机的。

答案 5 :(得分:2)

对我来说,首先要确保代码符合我们办公室的所有最佳实践。 例如,对我们的Perl脚本使用严格,警告和污点。

如果有效率或速度问题集中在他们身上。 比如找到一个更好的算法,或找到一个更好的方法去做四重嵌套for循环的事情。

最后看看是否有办法让代码更具可读性。这通常是通过将5个执行类似操作的小脚本转换为1个模块(类)来实现的。

答案 6 :(得分:2)

我在编写新代码时重构,使用单元测试。如果方法太长,或者变量命名很差,或者我发现重复等,我也会重构旧代码,无论是我的还是别人的代码。

答案 7 :(得分:2)

从获取单元测试开始,然后使用自动重构工具。如果重构不能自动化,那么它不是真正的代码的机械转换,因此不是重构。单元测试是为了确保您真正只是执行从一个代码库到等效代码库的机械转换。

答案 8 :(得分:2)

没有单元测试的重构是危险的。总是有单元测试。如果你在没有经过良好测试的情况下改变某些东西,那么代码的某些部分可能是安全的,但其他地方可能没有相同的行为。通过单元测试,您可以保护任何更改。

重构其他代码也很好,但极端情况并非如此。其他人不像你那样编程是很正常的。改变东西不是“善意”,因为你会以其他方式做到这一点。如果真的有必要重新构建。

答案 9 :(得分:2)

我删除了复制,它统一了代码中固有的思维模式。重构需要实现这两件事。如果你有两次执行相同操作的代码,请将它重构到一个公共位置,统一抽象。如果你在三个地方有相同的文字,把它放在一个常数,统一目的。如果你有相同的参数组,确保它们总是以相同的顺序使用,或者更好的是,将它们放在一个共同的结构中,统一信息组。

答案 10 :(得分:2)

我更不愿意重构别人编写的代码,而不是重构我自己的代码。

如果它是由我的一位前任写的,我通常只在一个函数内重构。例如。我可以用switch替换if语句。任何比这大得多的东西通常都超出了范围而且不在预算之内。

对于我自己的代码,我通常会在我写作时进行重构,只要看起来很难看或者闻起来有些东西。现在更容易修复它,而不是等待它在未来发生问题。

答案 11 :(得分:1)

当你重构你编写的代码时,我同意其他海报。

如果它是你没写的代码,特别是如果它有很多,我会先使用像fxCop,Visual Studio的代码分析,DevPartner这样的工具 - 我敢肯定还有其他好的代码。他们会为您提供有关从哪里开始以及最常见的编码问题的想法。我也会进行压力测试,看看瓶颈在哪里,因此是你改进代码的最大回报。

我喜欢重构我的代码,但有可能过度使用它。如果您没有真正提高应用程序的性能,或者认真提高代码可读性,那么您应该停下来。在重构时总是有可能引入新的错误,特别是如果你在没有单元测试的情况下工作。

答案 12 :(得分:0)

第一步:确定code smell.

第二步:考虑替代实施以及权衡利弊,我接受哪种方式“更好”。

第三步:实施更好的解决方案。

如果代码是我的,这没有区别,因为有时候我可能会回到几个月或几年前编写的代码,它看起来像是其他人的代码。如果我正在制作新方法或者代码没有足够的测试,我可以编写测试,IMO。

答案 13 :(得分:0)

一般方法

我可以从鸟瞰图中窥视软件(组件)开始。依赖性分析和图形工具在这里是一个很好的帮助(参见后面的部分)。我在包级别或类级别依赖项中寻找一个圆圈,也可以寻找具有太多依赖关系的类。这些都是重构的好选择。

交易工具

依赖性分析工具: