【发布时间】:2010-09-17 08:28:00
【问题描述】:
我想知道其他开发人员是如何开始重构的。你的第一步是什么?如果您重构不属于您的代码,这个过程(重构)有何不同?你在重构的时候写测试吗?
【问题讨论】:
我想知道其他开发人员是如何开始重构的。你的第一步是什么?如果您重构不属于您的代码,这个过程(重构)有何不同?你在重构的时候写测试吗?
【问题讨论】:
我接受废话,让它不那么糟糕。 :-)
说真的。我不重构以创建新功能。重构发生在新事物之前。如果没有测试,我会编写测试以确保我的重构不会破坏任何东西。如果有测试,我会使用这些。如果测试不充分,我可能会编写更多测试,但我会考虑将此与重构分开并先进行。
对我来说,第一步是注意到我可以抽象一些东西并使其更通用(并且在现在需要该功能的其他地方有用),或者我注意到某些东西不好但可能会更好(主观)。我不会无缘无故地重构一般性。 YAGNI principle 适用。
我们有共享所有权的概念,因此代码始终是我的——我可能没有编写它,但在重构时我不考虑这一点。如果目的不明确,我可能会在决定需要重构之前先了解事物——尽管这几乎总是重构本身的理由。
【讨论】:
第一步:识别code smell.
第二步:考虑替代实现以及权衡是什么以及我接受哪个“更好”。
第三步:实施更好的解决方案。
无论代码是不是我的,这并没有什么不同,因为有时我可能会回顾几个月或几年前编写的代码,它看起来就像是其他人的代码。如果我正在制作新方法或者对代码没有足够的测试,我可能会编写测试,IMO。
【讨论】:
阅读Martin Fowler的书“Refactoring”
顺便说一句 - 这是 Martin Fowler 自己的 Amazon 执行链接,如果您想知道的话:)
【讨论】:
你的第一步是什么?
第一步是运行单元测试以确保它们都通过。实际上,如果在修改代码之前 已经破坏了测试,那么您可能会浪费大量时间来查找哪些更改破坏了测试。
如果你重构不属于你的代码,这个过程会有什么不同?
在重构不是我写的代码(或我很久以前写的代码)时,我肯定会采取更小的步骤。我还可以在继续之前验证测试覆盖率,以避免依赖始终通过的单元测试......但不会测试我正在处理的区域。
你在重构的时候写测试吗?
我通常不会,但我可能会在以下情况下添加新的测试(列表并不详尽):
它还取决于正在执行的重构。提取函数时,如果可以以与以前不同的方式调用它,我可能会创建一个新测试。
以下是一些一般性建议:
第一件事是维护在处理代码时注意到的code smells 的列表。这可以让人们从记住代码中看到的内容的负担中解放出来。还有,
当单元测试没有完全通过时,黄金法则永远不会重构。
在代码稳定时进行重构,在添加您知道会受到未来重构影响的内容之前,在集成之前以及最重要的是在说您完成之前。
在没有单元测试的情况下,您必须将要重构的代码部分置于测试之下。如果单元测试太难改造,通常是这样,那么您可以创建characterization tests,按照Michael Feathers in Working Effectively with Legacy Code 的建议。简而言之,它们是端到端的测试,可以让您确定代码的当前行为(并不假定它一直都能完美运行)。
不要害怕做小步骤。不要同时做两件事。如果你注意到需要重构的东西,记下它,不要马上修复它,即使它看起来很容易。
当测试通过时,请经常签到。这样您就可以在不丢失之前完成的内容的情况下恢复糟糕的重构。
请记住,重构不会为您的客户增加价值(这可以讨论),但客户不会付钱给您进行重构。一条经验法则是在对代码进行更改或添加新功能之前进行重构。
【讨论】:
* DRY = 不要重复自己
【讨论】:
比起重构自己的代码,我更不愿意重构别人写的代码。
如果它是由我的一位前辈编写的,我通常只在函数内重构。例如。我可能会用 switch 替换 if 语句。任何比这大得多的东西通常都超出范围,也不在预算之内。
对于我自己的代码,我通常会在编写代码时进行重构,只要某些东西看起来很难看或开始有异味。现在解决它要容易得多,而不是等待它在以后引起问题。
【讨论】:
很大程度上取决于我的目标。如前所述,您需要单元测试以确保您的重构没有破坏任何东西,如果有,您必须花时间修复它。在许多情况下,我会测试现有的解决方案,如果它有效,则将其包装而不是重构它,因为这样可以最大限度地减少中断的可能性。
如果我必须重构,例如我最近不得不将一堆基于 ASCII 的 C++ 移植到 UNICODE,我倾向于确保我有良好的回归测试,可以在最终用户和单元级别工作。同样,我尝试使用工具而不是手动重构,因为这样不太容易出错,而且你得到的错误是系统性的,而不是随机的。
【讨论】:
当您重构自己编写的代码时,我同意其他发帖者的观点。
如果不是您编写的代码,尤其是如果代码很多,我会先使用 fxCop、Visual Studio 的代码分析、DevPartner 等工具——我相信还有其他好的工具。他们会给你关于从哪里开始以及最常见的编码问题是什么的想法。我还会做压力测试,看看瓶颈在哪里,因此你在改进代码方面所做的努力可以获得最大的回报。
我喜欢重构我的代码,但也有可能过度。如果您并没有真正提高应用程序的性能,或者没有认真提高代码可读性,那么您可能应该停止。重构时总是有可能引入新的错误,尤其是在没有单元测试的情况下。
【讨论】:
我删除了重复,它统一了代码中固有的思维模式。重构需要实现这两件事。如果您有两次执行相同操作的代码,请将其重构到一个公共位置,统一抽象。如果你在三个地方有相同的文字,把它放在一个常数中,统一目的。如果您有相同的参数组,请确保它们始终以相同的顺序使用,或者更好的是,将它们放在一个共同的结构中,统一信息组。
【讨论】:
没有单元测试的重构是危险的。始终进行单元测试。如果您在没有经过良好测试的情况下更改某些内容,则代码的某些部分可能是安全的,但其他地方的某些内容可能不会有相同的行为。借助单元测试,您可以保护任何更改。
重构其他代码也可以,但极端情况并非如此。其他人不像你那样编程是正常的。改变东西不是“善意的”,因为你会以另一种方式做到这一点。如果确实有必要,只需重构即可。
【讨论】:
从获取单元测试开始,然后使用自动重构工具。如果重构不能自动化,那么它就不是真正的代码机械转换,因此也不是重构。单元测试是为了确保您确实只是在执行从一个代码库到等效代码库的机械转换。
【讨论】:
我在编写新代码时使用单元测试进行重构。如果方法太长,或者变量命名错误,或者我发现重复等,我也会重构我的或其他人的旧代码。
【讨论】:
对我来说,首先要确保代码符合我们办公室的所有最佳实践。 例如,对我们的 Perl 脚本使用严格、警告和污染。
如果存在效率或速度问题,请关注它们。 比如找到更好的算法,或者找到更好的方法来完成四重嵌套的 for 循环正在做的事情。
最后看看是否有办法让代码更具可读性。这通常通过将 5 个执行类似操作的小脚本转换为 1 个模块(类)来实现。
【讨论】: