19

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

4

14 回答 14

24
  1. 不要重构任何没有单元测试的重要内容
  2. 编写单元测试,然后重构
  3. 重构小块并经常重新运行测试
  4. 当代码是 DRY * clean时停止重构

* DRY = 不要重复自己

于 2008-10-15T16:34:21.813 回答
8

你的第一步是什么?

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

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

在重构我没有编写的代码(或我很久以前编写的代码)时,我肯定会采取更小的步骤。我还可以在继续之前验证测试覆盖率,以避免依赖始终通过的单元测试......但不会测试我正在处理的区域。

你在重构时写测试吗?

我通常不会,但我可能会在以下情况下添加新测试(列表不详尽):

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

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


以下是一些一般性建议:

首先是维护在处理代码时注意到的代码异味列表。这可以让人们从记住代码中看到的内容的负担中解放出来。还,

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

在代码稳定时进行重构,在添加一些你知道会受到未来重构影响的东西之前,在集成之前,最重要的是在说你完成之前

在没有单元测试的情况下,您必须将要重构的代码部分置于测试之下。如果单元测试太难改造,通常是这样,那么您可以创建特征测试,正如Michael Feathers 在有效地使用旧代码中所推荐的那样。简而言之,它们是端到端的测试,允许您确定代码的当前行为(并不假定它一直都在完美地工作)。

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

当测试通过时,经常检查。这样您就可以在不丢失之前完成的内容的情况下恢复糟糕的重构。

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

于 2008-10-17T11:48:07.723 回答
4

我接受废话,让它不那么糟糕。:-)

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

对我来说,第一步是注意到我可以抽象一些东西并使其更通用(并且在现在需要该功能的其他地方有用),或者我注意到某些东西很糟糕并且可能会更好(主观的)。我不会无缘无故地重构一般性。 YAGNI 原则适用。

我们有共享所有权的概念,因此代码始终是我的——我可能没有编写它,但我在重构时不考虑这一点。如果目的不明确,我可能会在决定需要重构之前寻求理解事物——尽管这几乎总是重构本身的理由。

于 2008-10-15T16:39:08.010 回答
4

阅读Martin Fowler的《重构》一书

顺便说一句 - 这是 Martin Fowler 自己的亚马逊 exec 链接,如果你想知道的话:)

于 2008-10-15T16:42:29.470 回答
3

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

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

于 2008-10-15T16:48:17.197 回答
2

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

如果存在效率或速度问题,请关注它们。比如找到一个更好的算法,或者找到一个更好的方法来完成四重嵌套的 for 循环正在做的事情。

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

于 2008-10-15T16:35:02.093 回答
2

我在编写新代码时使用单元测试进行重构。如果方法太长,或者变量命名错误,或者我发现重复等,我还将重构旧代码,无论是我的还是其他人的。

于 2008-10-15T16:35:42.170 回答
2

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

于 2008-10-15T16:37:45.720 回答
2

没有单元测试的重构是危险的。始终进行单元测试。如果您在没有经过良好测试的情况下更改某些内容,则代码的某些部分可能是安全的,但其他地方的某些内容可能不会有相同的行为。使用单元测试,您可以保护任何更改。

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

于 2008-10-15T16:39:45.467 回答
2

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

于 2008-10-15T16:40:07.027 回答
2

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

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

对于我自己的代码,我通常会在编写时进行重构,只要某些东西看起来很难看或开始有异味。现在修复它要容易得多,而不是等待它在路上引起问题。

于 2008-10-16T20:05:17.020 回答
1

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

如果代码不是你写的,特别是如果有很多,我会先使用 fxCop、Visual Studio 的代码分析、DevPartner 等工具——我相信还有其他好的工具。他们会给你关于从哪里开始以及最常见的编码问题是什么的想法。我还会进行压力测试以查看瓶颈在哪里,因此您在改进代码方面所做的努力可以获得最大的回报。

我喜欢重构我的代码,但也有可能做得过火。如果您并没有真正提高应用程序的性能,或者没有认真提高代码的可读性,那么您可能应该停止。重构时总是有可能引入新的错误,尤其是在没有单元测试的情况下。

于 2008-10-15T16:43:57.067 回答
0

第一步:识别代码异味。

第二步:考虑替代实现以及权衡是什么以及我接受哪个“更好”。

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

无论代码是不是我的,这都没有什么不同,因为有时我可能会回顾几个月或几年前编写的代码,它看起来就像是其他人的代码。如果我正在制作新方法或者对代码没有足够的测试,我可能会编写测试,IMO。

于 2009-01-23T17:18:13.937 回答
0

一般的做法

我可以从鸟瞰的软件(组件)开始。依赖性分析和绘图工具在这里提供了很大的帮助(请参阅后面的部分)。我在包级别或类级别的依赖项中寻找一个圆圈,或者在具有太多依赖项的类中寻找一个圆圈。这些都是重构的好候选。

贸易工具

依赖分析工具:

于 2011-06-15T12:18:52.527 回答