How to Rewrite a Legacy System: The Ship of Theseus
如何重写陈旧系统:就像忒修斯之船
前言
近期面对许多陈旧代码维护的问题,碰巧我翻找到这个博客:Understand Legacy Code,记录一下「重写」陈旧系统可能会遇到的困境与解套方案。以我自己手上的项目为例,在进行项目升级评估时发现事情比原先想象还要复杂!
- 框架版本升级:说好的向后兼容呢?版本一换代码风格与架构全都要改,旧版本的套件框架将被永远抛弃。
- 不存在的文件:因为太匆忙了没有时间记录文件,「学习」累积成为每个团队成员必经的痛,上手项目之前都要消化大量的学习债务。
- 根深蒂固的反模式:错误的开发模式已经深植到成为整个项目的文化,现有的反模式也容易造成破窗效应的发生。
总之到达一个无法回头的地步,或许只剩下重写这个高风险的选项,因为……
- 程式间耦合性过高牵一发动全身…
- 无测试或难以被测试…
- 重写都比重构还要低成本…
- 项目再也承受不起变化…
于是你踏上了项目重写的道路。
重写项目的陷阱
- 你跟管理层讨论了停止推出新功能的策略,用这段时间重写现有的应用程序。
- 你估计重写将需要 6 个月的时间来覆盖现有应用程序的功能。
- 几个月后,发现了严重的错误,绝对需要在旧代码中进行修复。因此,你修补了旧代码和新代码。
- 几个月后,一个全新的功能被销售给客户,但由于新版尚未准备好,只能先在旧代码中实现,并且也要在新版本中添加此功能。
- 经过 5 个月,你意识到项目将延迟。旧应用程序做了比预期多得多的事情。你开始更加努力。
- 经过 7 个月,你开始测试新版本。QA 提出了很多应该修复的问题。
- 经过 9 个月,业务无法忍受「不开发功能」的状况了。领导层对这种情况感到不满,你感到很疲惫。你开始对令人痛苦的旧代码进行更改,同时努力跟上重写进度。
- 最终,你们在生产环境中拥有了两个系统。长期目标是淘汰旧系统,但新系统还没准备好。每个功能都需要实现两次。
故事中重写造成两套完全独立的系统,可以想象重写在这个例子当中带来多大多沉重与负担。
忒修斯之船模式
如果船舶部件随着腐烂而逐步更换,那么船舶完全更换后还是原来的船吗?先不讨论哲学,这种做法的观点在于渐进的替换重写片段,代表更快的反馈、更少的工作(至少更少的心理负担)以及避免失去功能!
- 让新代码作为旧代码的代理,用户使用新系统只是导向到旧系统中。
- 逐步实践旧代码的行为到新代码当中
- 渐进的淡出旧代码,取代上新代码
总结
我们对重写的概念通常是「打掉全部重做」,但这么做过于理想化,并且在有些规模需要重写的项目上,这样的做法可能会让项目陷入无底深渊。退一步思考,并重新审视重写的最终目的,忒修斯之船模式是简单但极容易被忽略的选项。
延伸阅读
- The Ship of Theseus to NOT rewrite a legacy system from scratch - Understand Legacy Code
- 面對 Legacy Code ,該重構還是重寫? - 網站製作學習誌