重构、重新架构、再设计与重写的区别

jopen 10年前

英文原文:Software is too expensive to build cheaply….

  在稍早的文章评论里,Jon Eaves 表达了把重构做为动词过度使用的忧虑。尤其是重构(refactoring)【注1】和重新架构(rearchitecting)之间的界线非常模糊,重构被用作在你回头做第二遍的、任何行为的标签。你明白吗?Jon 是对的。

  被 Martin Fowler 定义的重构,是一个非常具体的术语,以数学上等同的具体术语为基础【注2】。重构是关于小的、“行为保留”的增加的、安全步骤。重构不是在应用程序里回头去“填充空白”的借口。

  让我们给出一些具体的例子来说明什么不是重构,下面的行为都不被视作重构:

  • “优化”(又称作增加)错误处理。
  • 增加日志
  • 勉强塞满另一个功能
  • 提高测试覆盖率(虽然它非常接近重构了)
  • 当老板不在的时候,玩扫雷游戏

  重构是“优化现有代码的设计”。在本文,优化意味着使之更加易于理解和/或更加灵活。下面的行为都被视作重构:

  • 把臃肿的方法拆分成较小的、功能集中的方法。
  • 重新命名变量和参数,使之更有意义。
  • 把功能从一个类移到另一个类(更加适当)。
  • 基于一个类的方法,产生一个接口,然后让这个类实现该新接口。

  注意,我说的这些可以是重构的行为。决定它们是否属于重构的大部分因素在于你是如何去做的。重申:重构行为,是小而安全的步骤,最好是可逆的步骤。如果你不得不考虑它是否可以运行,那么它就不再是重构行为了。

  那么如何区别重构与重新架构或再设计呢?重构是在键盘上完成的,接触真正的代码。而重新架构,最好是在白板上(或最近的酒吧)完成的。重新架构涉及了较大的愿景,考虑下一周/月/年的规划。重构是你用来帮助自己达成目标的技巧之一。

  再设计(Redisigning)是一个术语,覆盖了任何时候你正在重新考虑的设计决定。由于敲代码是设计行为,甚至到了打字阶段,再设计肯定 包含重构。毕竟,如果你不稍微再设计,就不太容易提高设计。然而,在通常情况,“再设计”意味着放弃老的解决方案,提出新的解决方案,或多或少地从头开 始。如果你在白板上做再设计,可能是没问题的,与重新架构的举动类似,你仍然可以通过重构达成目标。如果你在键盘上完成再设计,这就不是重构了。

  重写(Re-writing)类似再设计,不过它只是在键盘上完成。重写通常是受到了头痛的伤害,但是它常常让你丢掉惰性而到达一个更好的地方。类似拍卖和搬到了印度班加罗尔。

  在实战中,会遇到混合的情况。重构应该是一个开发人员使用的日常进程的一部分,当你这样看的时候,界线会变得模糊。比如:

  • 注意,你需要在业务逻辑里为第二种部件增加支持,这是一个设计行为。
  • 从现有部件抽出一个新的接口类,在此过程中重新命名现有部件,这是一个重构的行为。
  • 用新接口代替部件类的所有适合的引用,是一个重构行为。
  • 开发第二个部件,增加到应用程序里,是一个设计行为。

  如果你最初开发了两个部件,后来才注意到公用的情况,该怎么办?好的,这是重构行为,可能要集中在以多态取代条件式的重构上。但是从外部看,这可能看起来非常像重写;必定(相对地)大量代码要消除掉。但是,不管你用什么方式削减,写第二个部件就不是一个重构行为。

  重构更倾向于保持代码简单、灵活,而不是做对事情。做对事情经常涉及到添加新代码,或再设计应用程序的大块功能。使其灵活只是为了使其更加容易。这样说的话,重构最好被看做是一项赋能(enabling)行为。

  如你所知,如果我写这篇文章不是在深夜,或许本文会更加连贯:) 如果你想更多了解重构,去看看 Fowler 的书。