How to Rewrite a Legacy System: The Ship of Theseus

如何重写陈旧系统:就像忒修斯之船

前言

近期面对许多陈旧代码维护的问题,碰巧我翻找到这个博客:Understand Legacy Code🔗,记录一下「重写」陈旧系统可能会遇到的困境与解套方案。以我自己手上的项目为例,在进行项目升级评估时发现事情比原先想象还要复杂!

  • 框架版本升级:说好的向后兼容呢?版本一换代码风格与架构全都要改,旧版本的套件框架将被永远抛弃。
  • 不存在的文件:因为太匆忙了没有时间记录文件,「学习」累积成为每个团队成员必经的痛,上手项目之前都要消化大量的学习债务。
  • 根深蒂固的反模式:错误的开发模式已经深植到成为整个项目的文化,现有的反模式也容易造成破窗效应🔗的发生。

总之到达一个无法回头的地步,或许只剩下重写这个高风险的选项,因为……

  • 程式间耦合性过高牵一发动全身…
  • 无测试或难以被测试…
  • 重写都比重构还要低成本…
  • 项目再也承受不起变化…

于是你踏上了项目重写的道路。

重写项目的陷阱

  1. 你跟管理层讨论了停止推出新功能的策略,用这段时间重写现有的应用程序。
  2. 你估计重写将需要 6 个月的时间来覆盖现有应用程序的功能。
  3. 几个月后,发现了严重的错误,绝对需要在旧代码中进行修复。因此,你修补了旧代码和新代码。
  4. 几个月后,一个全新的功能被销售给客户,但由于新版尚未准备好,只能先在旧代码中实现,并且也要在新版本中添加此功能。
  5. 经过 5 个月,你意识到项目将延迟。旧应用程序做了比预期多得多的事情。你开始更加努力。
  6. 经过 7 个月,你开始测试新版本。QA 提出了很多应该修复的问题。
  7. 经过 9 个月,业务无法忍受「不开发功能」的状况了。领导层对这种情况感到不满,你感到很疲惫。你开始对令人痛苦的旧代码进行更改,同时努力跟上重写进度。
  8. 最终,你们在生产环境中拥有了两个系统。长期目标是淘汰旧系统,但新系统还没准备好。每个功能都需要实现两次。

故事中重写造成两套完全独立的系统,可以想象重写在这个例子当中带来多大多沉重与负担。

忒修斯之船模式

如果船舶部件随着腐烂而逐步更换,那么船舶完全更换后还是原来的船吗?先不讨论哲学,这种做法的观点在于渐进的替换重写片段,代表更快的反馈、更少的工作(至少更少的心理负担)以及避免失去功能!

  • 让新代码作为旧代码的代理,用户使用新系统只是导向到旧系统中。
  • 逐步实践旧代码的行为到新代码当中
  • 渐进的淡出旧代码,取代上新代码

总结

我们对重写的概念通常是「打掉全部重做」,但这么做过于理想化,并且在有些规模需要重写的项目上,这样的做法可能会让项目陷入无底深渊。退一步思考,并重新审视重写的最终目的,忒修斯之船模式是简单但极容易被忽略的选项。

延伸阅读