为什么我们要重构?

9
我想了解我们进行重构并证明它的原因。我读到很多人对重构的想法感到不满。重构被描述为:
  1. 由于缺乏足够的前期设计。

  2. 无纪律的黑客行为。

  3. 一种危险的活动,不必要地冒着破坏工作代码的风险。

  4. 资源浪费。

导致我们重构代码的原因是什么?

我在这里也找到了一个类似的问题how-often-should-you-refactor,但它没有提供重构的原因。


为什么重构如此重要? - balexandre
8
应该设为社区 wiki。 - SilentGhost
5
当我们谈论重构时,我们指的是对现有代码进行一系列的修改,以使其更易于理解和维护,同时保持原始功能不变。每个程序员都会遇到需要进行重构的代码,因为随着项目的发展和需求的变化,代码也会变得越来越复杂和难以理解。重构可以提高代码的可读性、可维护性和可扩展性,从而使代码更加健康和稳定。通过重构,我们可以发现并修复隐藏在代码中的缺陷,并减少错误的出现率。此外,重构也可以减轻代码负担,使其更容易进行测试和部署。总之,重构是一个必不可少的工具,可以帮助开发者更好地理解和管理他们的代码,并确保代码的质量和可靠性。 - SilentGhost
27个回答

36

为什么我们需要进行重构?

因为没有实际的替代方法可以取代编写代码。没有多少前期规划或经验能够替代实际的代码编写。这就是整个“瀑布式”一代人(称为瀑布模型)走过的艰辛历程。

一旦您开始编写代码并处于其中,您会考虑它在更低级别上的工作方式,您会注意到高级设计视图中忽略的事情(如性能、可用性或正确性问题)。

重构是完善的过程。

问问自己:为什么画家要在同一位置多次使用刷子?


13
我还要补充一点,客户的需求或他们对需求的理解会随着时间的推移而不断变化。你出色的前期设计可能无法持久... - morechilli
@morechilli,我能引用你的话吗:“你精彩的前期设计可能不会持续下去…”? :)。我喜欢你说话的方式。 - Pop Catalin
3
我可以为您进行翻译。morechilli的法则是否可以这样表述?“你华丽的前期设计并不会持久......” - Binary Worrier
当然,你让我微笑了 :) - morechilli
1
问问自己:为什么画家要在同一位置多次使用刷子?...那是从经济角度考虑的。 - Chuck Conway

14

7
为了保持可维护的代码库?
代码被阅读的次数比写入的次数多,因此需要有一个可读性强、易于理解和可维护的代码库。当您看到一些编写或设计不良的内容时,可以进行重构以改善代码的设计。
您也经常打扫房子,对吗?虽然这可能被认为是浪费时间,但为了保持干净整洁的房子,这是必要的,这样您就有一个舒适的生活环境。

7
我想简要讨论你提出的三个观点。
1. "不足的前期设计结果"
常识告诉我们,为解决特定问题应该尽可能地追求最简单、最清晰的设计。虽然有些代码可能是在没有充分理解需求和问题领域的情况下编写的,但更常见的情况是“糟糕的代码”在编写时并不“糟糕”;相反,它已经不再足够。
需求会发生变化,设计必须支持额外的功能和能力。预先考虑一些未来的变化是合理的,但是当没有明确和现实的需要时,McConnell等人正确地警告高层次、过度灵活的设计。
3. "危险的活动,不必要地冒着破坏工作代码的风险"

如果不正确地执行,那么是的。在您试图对工作系统进行任何重大修改之前,应该采取适当的措施来确保您不会造成任何损害 - 几乎可以说是一种“开发 Hippocratic oath”。

通常,这将通过文档和测试的混合来完成,而且往往代码胜出,因为它是实际行为的最新描述。在实践中,这意味着具有单元测试套件的良好覆盖范围,以便如果重构确实引入了意外问题,这些问题将被识别并解决。

显然,当您试图进行重构时,您将破坏某些测试,尤其是因为您正在尝试修复某些破损的代码合同。但是,只要您有机制来发现意外错误,就完全可以毫无顾虑地进行重构。

4. “浪费资源”

有人提到了 技术债务 的概念,简单来说,就是随着时间的推移,这些系统变得越来越复杂,其中一部分必须通过重构和其他技术手段来减少,以便在未来的开发中合理地促进。换句话说,有时候你必须咬咬牙,继续进行你一直拖延的改变,因为否则,当你在那个区域添加新东西时,你会让一个糟糕的情况变得更加糟糕。

显然,有时候还需要付清这些债务;你不会试图偿还贷款,直到你有现金可以做到这一点,而且在开发的关键阶段周围乱改代码也是得不偿失的。然而,通过决定解决代码库中的一些问题,您可以节省未来的开发时间,从而节省金钱,甚至可能在将来避免因无法理解而放弃或完全重写某个组件的成本。


不错的回答。在第一点下,我想补充说,通常我们在拥有类似物之前并不知道自己确切需要什么。这不仅是因为最初计划得到完全符合我们要求的东西是不切实际的,而且通常是不可能的。 - David Thornley

6

如果你的代码存在以下问题,就需要进行重构:

  • 效率低下
  • 存在缺陷
  • 难以扩展
  • 难以维护

这些问题都源于原始代码的质量不够好,因此需要改进。如果你有合理的单元测试,重构过程应该是安全的。


4
这并不意味着原始代码不够好。原始代码可能非常出色,但由于其他特性或需求变更的影响而进行的后续修改可能使事情变得混乱。如果“新”的代码需要重构,那就是你遇到了“烂开发者”的标志,如果人们在修复错误/更改功能时没有进行架构整理(根据我的经验,这种情况很少发生),那么旧代码几乎总是需要重构。 - Quibblesome

3

因为事后诸葛亮总比先见之明容易。

软件是人类创造的最复杂的东西之一,因此在事前考虑到所有问题并不容易。对于大型项目来说,即使团队(至少由人类组成的团队;)在实际开始开发之前考虑到所有问题可能也是不可能的。

另一个原因是软件不是构建出来的,而是在不断地生长。这意味着软件可以并且必须适应不断变化的需求和环境。


2
正如Martin Fowler所说,关于软件需求的变化,唯一让人惊讶的是有人会对此感到惊讶。
需求将会改变,新功能将会被要求。这是一件好事。增强努力大多数情况下都会成功,即使失败了,也只是小规模的失败,因此还有预算可以做更多的工作。大量的前期设计项目经常失败(据一项统计数据显示失败率为66%),因此应该避免这种情况。避免这种情况的方法是为第一个版本设计足够的内容,并在添加增强功能时进行重构,使其看起来像系统一开始就打算这样做一样。能够做到这一点的项目寿命是无限的(当您发布数据格式或API时存在问题-一旦上线,您不能总是保持完美)。
针对四个观点,我会说,一个避免重构的过程需要:
  1. 一个静态的世界,没有任何变化,以便前期设计可以完美地击中非移动目标。
  2. 将导致丑陋的黑客攻击,以解决未被重构的设计缺陷。
  3. 会导致危险的代码复制,因为害怕改变现有代码。
  4. 将浪费资源,过度工程化问题,并构建大型设计工件,以预期最终没有建造的需求,导致大量代码和复杂性拖慢项目,而不提供任何价值。
然而,有一个警告。如果您没有适当的支持,在简单情况下进行自动化工具,以及在更复杂情况下进行彻底的单元测试,那么它会带来麻烦,会引入新的错误,并且您会开发出(非常合理的)对此更加恐惧的心理。重构是一个很好的工具,但需要安全设备。

你有支持BDUF项目失败率的声明的参考资料吗?我正在为我的公司准备重构的理由清单,这将非常有用。 - Dennis Kassel
@GinoBambino,我推荐Bob Lewis的网站http://issurvivor.com/。他有很多篇文章都能够阐述这个观点。 - Yishai

1
另一个需要重构的场景是TDD。 TDD的教科书方法是仅编写您需要通过测试的代码,然后在之后将其重构为更好的东西。

1

......因为编程就像园艺一样。随着时间的推移,您的代码库不断增长,您的领域也在变化。过去看起来很好的想法现在常常看起来像是一个糟糕的设计,而现在看起来很好的设计未来可能并不是最优的。

代码永远不应被视为永久性的产物,也不应被视为太神圣而不可触及。通过测试获得信心,重构是促进变革的机制。


1
  1. 对需求的理解不足:

    如果开发人员没有清晰地理解需求,那么最终的设计和代码就无法满足客户的要求。随着需求变得更加明确,重构变得必不可少。

  2. 支持新需求。

    如果一个组件过于老旧,在大多数情况下它将无法处理激进的新需求。这时进行重构变得至关重要。

  3. 现有代码中存在许多错误。

    如果你花费了很长时间在办公室修复某个组件中的一些恶心的错误,那么尽早进行重构就成为了自然选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接