【问题标题】:When should you not refactor?什么时候不应该重构?
【发布时间】:2009-08-08 03:01:15
【问题描述】:

我们都知道重构是好的,我和下一个人一样喜欢它,但你有真实的案例重构更好吗?

诸如时间关键的东西或同步之类的东西?技术或人为原因同样受欢迎。真实案例场景和经验加分。

编辑:从目前的答案来看,不重构的唯一原因似乎是钱。我的问题主要是这样的:假设你想执行“提取方法”,但如果你添加额外的函数调用,你会使代码稍微慢一些,并阻碍非常严格的同步。只是为了让您了解我的意思。

我有时听到的另一个原因是“习惯于当前代码布局的其他人会因你的更改而烦恼”。当然,我怀疑这是一个很好的理由。

【问题讨论】:

  • (仅举您的示例 :))非常严格的同步或定时可能会因速度的轻微变化而失去平衡,这太不可靠了,不能被视为工作代码。除非你的工作非常接近硬件,否则可能......
  • 是的,完全同意,但我想举一个例子来说明我的意思。
  • 应该是社区维基
  • 重构在一般情况下是否意味着“更改代码”?许多答案表明重构可能会破坏代码,但它不能按照重构的定义!如果它破坏了代码,它只是重写。重构是一个非常短的更改序列,它不能改变代码库其余部分的操作。如果它导致错误,那你就错了!

标签: refactoring


【解决方案1】:

我非常喜欢通过重构来保持代码的整洁和可维护性。但您通常希望避免重构可以正常工作且不需要更改的生产模块。但是,当您确实需要在模块上工作以修复错误或引入新功能时,一些重构通常是值得的并且不会花费太多,因为您已经致力于进行全套测试并通过发布过程。 (单元测试非常有用,但只是完整测试套件的一部分,正如其他海报所指出的那样。)

更重要的重构可能会使其他人更难找到解决新代码的方法,然后他们可能会对重构做出不利的反应。为了尽量减少这种情况,请使用结对编程之类的方法让其他团队成员参与到这个过程中。

更新(8/10):不重构的另一个原因是当您没有以适当的谦逊和尊重来接近现有代码库时。有了这些品质,你就会变得保守,只做真正有影响的重构。如果您过于自大地处理代码,您可能最终只是进行更改而不是重构。新方法名称真的更清晰,还是旧方法名称在您的应用程序域中具有非常特定的含义?当现有风格符合项目准则时,您真的需要将源文件机械地重新格式化为您的个人风格吗?结对编程也有帮助。

【讨论】:

    【解决方案2】:

    为了强化另一个答案(并触及您提到的问题):不要重构代码的一部分,直到它被所有相关类型的测试很好地覆盖。这并不意味着“不要重构它”——重点是“添加必要的测试”(正确地进行单元测试可能需要一些重构,特别是在引入工厂 DP 和/或依赖注入 DP现在已经牢固地绑定到具体依赖项的代码)。

    请注意,这确实涵盖了您第二段的问题:如果代码的一部分是时间关键的,它应该被“负载测试”很好地涵盖(就像更常见的类型,正确性测试,应该涵盖两个特定的单元[尽管在性能方面——正确性检查是其他测试的业务!-)] 和端到端操作——如果人们谈论的是正确性而不是性能,则相当于单元测试和集成测试。

    带有细微同步问题的多任务代码可能是一场噩梦,因为没有测试可以真正让您完全相信它——没有其他重构(可能以任何方式影响任何现在似乎正在工作的脆弱同步)应该在打算使同步更加健壮和健全之前被考虑(通过保证线程安全队列的消息传递是迄今为止我在这方面最喜欢的设计模式;-)。

    【讨论】:

    • 关于使同步更加健壮的优点。我在一个项目中也遇到过这种情况:首先该项目使用锁定和共享可变状态,但这会产生脆弱的测试和一些并发错误,所以现在我将重构其架构以基于消息传递。
    • @Esko,太好了!顺便说一句,如果我有机会(和一个好的实现;-)我想尝试的一种同步技术是 STM,cfr。 en.wikipedia.org/wiki/Software_transactional_memory -- 似乎它会提供稳健性和速度 -- 但到目前为止我还没有实际使用它的经验。
    【解决方案3】:

    嗯 - 我不同意上述观点(第一个回应)。给定没有测试的代码,您可以对其进行重构以使其更具可测试性。

    当您无法及时测试生成的代码以交付它以使其对接收者仍然有价值时,您不会重构代码。

    当您的重构不会提高代码质量时,您不会重构代码。质量不是主观的,尽管有时设计可能是。

    当没有商业理由进行更改时,您不会重构代码。

    可能还有更多,但希望你能明白...

    【讨论】:

    • 没有测试的重构不是重构,因为你无法检查你没有破坏任何东西。
    【解决方案4】:

    正如 Martin Fowler 所写,如果临近截止日期,您不应该重构。项目中的那个时间更适合清除错误而不是改进设计(重构)。在deadline结束后直接做这次省略的重构。

    【讨论】:

    • 你们难道不经常觉得自己是一个内心的声音,告诉你做相反的事情,比如“哦,明天我需要交付这个。让我们让它更漂亮并重构。”
    • 我经常听到这个声音。但在截止日期前不久,这是致命的。标记发布版本后直接做笔记和重构。并且真的应该在发布之前留出一些时间 - 编写更多测试用例。
    【解决方案5】:

    重构本身并不好。相反,它的目的是提高代码质量,以便可以更便宜地维护它并且减少添加缺陷的风险。对于积极开发的代码,重构的好处是值得付出代价的。对于不打算做任何进一步工作的冻结代码,重构没有任何好处。

    即使对于实时代码,重构也有其自身的风险,单元测试可以将风险降到最低。它在开发周期中也有自己的位置,它位于前面,破坏性较小。重构的最佳时间和地点是在您开始对一些原本脆弱的代码进行重大更改之前。

    【讨论】:

    • 阅读代码的频率远高于编写代码的频率。您可能需要了解“冻结代码”才能在其他地方进行更改,如果该代码难以理解,是否不值得仅仅因为不需要更改而重构?
    【解决方案6】:

    当它不具有成本效益时。在我工作的地方有一个人喜欢重构。让代码完美让他很开心。他可以查看当前的项目树并在其上运行,移动函数和类并将其收紧,以使它们看起来很棒,具有更好的流程,并且在未来更具可扩展性。

    不幸的是,这不值钱。如果他花一周时间将一些类重构为更多可能在未来更容易使用的功能单元,那么这相当于公司损失了一周的薪水,而没有明显的底线改善。 p>

    代码永远不会绝对完美。你学会了忍受它,并把你的手放在可以做得更好,但也许不值得花时间的事情上。

    【讨论】:

    • 我不同意。无情的重构绝对是让项目工作的最佳方式,如果你正在使用敏捷而不是无情地重构所有东西,那么你做错了,应该尽快转换方法。 100% 无情的重构是控制代码库增长的唯一方法。如果你想更好地利用这个人的时间,让他承担更艰巨的任务,或者让他从事重构更有利的设计。
    • 是的,除非您拥有这家公司,并且您发现错误被引入到代码中,因为有人“让它变得更好”而工作得很好。有一行,重构你看到的每一行代码都是愚蠢的。 关心代码质量,客户关心获得及时运行的软件。两者之间存在平衡。
    • 我想我可能是错的,但在我看来,很多人严重低估了重复代码的成本。花一天时间修改一些函数确实不是很昂贵,尤其是如果它最终被评论并且更有用的话。我从来没有见过不会再被触及的代码,最大的成本总是重新理解代码,在这个过程中,重构和添加 cmets 几乎是免费的。在您不了解所有后果的情况下编辑代码的成本可能很高。
    • @Ed 如果客户关心获得及时运行的软件,那么他们也会关心代码质量,无论他们是否知道。没有后者,你就不能拥有前者,至少不会长久。
    • 重构并不能保证代码质量。事实上,它经常引入新的错误。 使用单元测试的项目比那些使用单元测试的项目多得多,因此重构通常是一个耗时的过程,没有单元测试保证支持。
    【解决方案7】:

    如果代码看起来很难在不中断的情况下重构,那是最重要的重构代码!

    如果没有任何测试,请在重构时编写一些。

    老实说,一种情况是管理层/客户/SomeoneImportant 禁止您触摸某些代码,当这种情况发生时,我认为项目已损坏。

    【讨论】:

      【解决方案8】:

      这是我的经验:

      不要重构:

      • 当您没有附带要重构的代码的测试套件时。您可能想先开发测试套件。
      • 当您的经理并不真正关心 当前 代码库的可维护性和可扩展性时,他们反而更关心他们是否能够按时交付产品,尤其是对于具有时间紧迫。

      【讨论】:

      • 不管经理怎么说,代码似乎永远不会消失。因此,如果您的代码不会消失,那么改进它不是更好吗?
      • “一切都在变化,没有什么是静止的”——赫拉克利特 :-)
      • 如果你想快速发布,你最好有一个好的代码库。大多数时间修复错误是开发的 80% 以上,重构所花费的时间少于修复大量错误和为每个错误管理大量小任务等。
      【解决方案9】:

      如果您坚持所做的一切都应该为客户/业务增加价值的原则,那么您不应该重构的时间如下:

      • 有效且没有新开发计划的代码。
      • 足够好的代码/工作和重构只是代表镀金。
      • 重构的成本高于使用现有代码。
      • 重构的成本高于从头重写代码

      其他一些回答说你不应该重构没有单元测试的代码。如果代码需要重构,你应该重构它,但是你必须先编写测试。如果代码以难以测试的方式编写,则应该重写(在完美的世界中)。

      【讨论】:

      • 有趣的是最后一点——重构的成本比使用现有代码要高。通常只有非常有经验的工程师才能计算出重构的价值。我看到的越多,分解的代码就越有价值,而未分解的代码 (IMO) 实际上有一个相当高的负值——这意味着你最好把它扔掉并从头开始编写,而不是尝试与它交互一次或两次.
      【解决方案10】:

      当您有其他东西要构建时。当我应该做其他事情时,我总是感觉想重构现有系统。

      【讨论】:

        【解决方案11】:

        在修复或添加代码与重构之间始终需要取得平衡。然而,到目前为止,这种平衡是有利于重构的,我认为我从未在一个重构过多的团队中工作过。很有可能,如果您认为自己在重构方面犯了太多错误,那么您就对了。

        当然,最大的决定因素是截止日期有多近。如果最后期限迫在眉睫,要求是第一位的。

        【讨论】:

          【解决方案12】:

          重构代码的需要不是主要基于人们剪切和粘贴代码的倾向,而不是考虑解决方案并提前进行分解吗?换句话说,每当您觉得需要剪切和粘贴某些代码时,只需将该代码块变成一个函数并记录下来。

          我不得不维护太多的代码,人们发现剪切和粘贴整个函数更容易,只进行一两个微不足道的更改,这些更改很容易被参数化。但是像许多其他人的经验一样,尝试重构其中的一些代码会花费大量时间并且风险很大。

          我有 4 个项目,其中仅根据需要复制和修改了 10K 行的函数集合。这是一个可怕的维护噩梦。特别是当代码有很多问题时,例如硬连线的字节顺序假设,大量的全局变量等等。我一想到它就觉得喉咙里有胆汁。

          【讨论】:

            【解决方案13】:

            如果您没有时间在发布前测试重构的代码,请不要重构。重构可能会引入错误。如果您有经过良好测试且相对没有错误的代码,为什么要冒险呢?等到下一个开发周期。

            【讨论】:

              【解决方案14】:

              如果您坚持维护旧的易碎代码库,除了保持其运行之外没有未来,直到管理层可以咬紧牙关并进行重写,那么重构是一种双输的情况。首先,开发人员失败了,因为重构糟糕的易碎代码是一场噩梦,其次,业务失败了,因为开发人员试图重构软件以意想不到的方式中断。

              【讨论】:

              • 但是重构允许开发人员学习系统,这是重写发生时的收获。因此,除非您维护的是一次性遗留代码,否则它仍然可能是有益的。
              • 而且,一次一个模块,一点一点地重写旧的、易碎的代码通常是个好主意,而不是把它扔掉并从头开始。
              • 完全不同意!维护和重构“一个旧的 flakey 代码库”是您真正学习如何编程的地方(应用程序如何工作,位如何而不是应该组合在一起等),更不用说客户是否可以推迟数百万美元重写 5 或 10 年,因为一切都让他们满意,然后你就在做你的工作。重构和渐进式再设计可以使旧的边缘系统对您的客户更有价值,而这(不是在完全重写时使用新玩具)是目标。
              • @kloucks:有一座古老的木桥横跨一条湍急的河流,它的支撑梁底部已经开始腐烂。日常使用这座桥对于人们上下班是必不可少的。选择是尝试修复正在使用的旧桥,尝试砍掉腐烂的部分,这是一项危险和冒险的操作,或者建造一座新的钢桥。一座新桥的成本是拆除腐烂梁的成本的 5 倍。无论选择哪种方法,使用这座桥的人都必须缴税。你会怎么做?
              • @sipwiz 我会支撑木桥以免它倒下(无论如何你都必须这样做!)。一旦它安全并且您熟悉它,修补它应该比重新开始更容易。这是一个已知的数量,我见过很多用大写字母 F 重写的 FAIL,而原来的“Bad”代码只是不停地跳动。
              【解决方案15】:

              当您一开始并不真正知道代码在做什么时。是的,我看到人们忽略了这条规则。

              【讨论】:

              • 再一次,重构是了解一段(不清楚的)代码究竟做了什么的好方法。 只要您小心翼翼地分小步进行,并在此过程中添加缺失的单元测试。
              【解决方案16】:

              这只是成本效益的权衡。估计重构的成本,估计收益,确定您是否真的有时间在给定其他任务的情况下进行重构,确定重构是否是最佳的时间收益权衡。可能还有其他更值得做的任务。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2020-07-16
                • 2012-03-31
                • 2010-10-10
                • 2010-12-30
                • 2013-10-31
                相关资源
                最近更新 更多