外观
重写还是继续改:祖传系统三问决策框架与成本测算
每个工程师职业生涯里都会遇到这样一个时刻:面对一个跑了七八年、注释比代码还少、原作者早已离职的系统,你在第 N 次因为一个诡异 bug 加班到深夜后,愤怒地敲下一行字:"这玩意儿没法维护了,必须重写。"
但冷静下来,真正资深的工程师会问一个更难的问题:重写,真的比继续改更便宜吗?
问题背景:为什么"重写冲动"如此普遍
祖传系统(legacy system)的痛苦是真实的:技术栈过时导致招人困难、隐性耦合让一个小改动牵动全身、缺少测试使得每次发布都像拆弹。这些痛点会持续放大工程师的挫败感,而"重写"提供了一种心理上的彻底解脱——仿佛推倒重来就能一次性摆脱所有债务。
然而行业数据反复证明:大多数重写项目都以超期、超支甚至失败告终。经典案例是 Netscape 与某大型 ERP 替换项目,重写期间旧系统仍需持续维护和加功能,团队被迫两线作战;新系统在功能追平旧系统之前无法上线,而业务不会等你。结果往往是旧系统没换掉,团队还多背了一个半成品。
根本原因在于,重写的成本被系统性低估,而旧系统的"保留价值"被情绪性忽视。
方案对比:三条路线的本质差异
面对遗留系统,通常有三条可选路线,它们并非互斥,但起点逻辑完全不同。
- 继续修补:投入最小、见效最快,但每次改动都在偿还越来越高的"债务利息",适合已经进入维护期、需求极少的系统。
- 渐进式重构:以绞杀者模式(Strangler Fig Pattern)为代表,在旧系统外套一层新实现,逐模块替换,随时可上线、可回退,是绝大多数场景的最优解。
- 推倒重写:理论上最干净,实际是一场豪赌。只有当旧架构在根本层面无法承载业务(如单机架构无法水平扩展、核心模型与业务彻底背离),且组织能承受需求冻结时才值得考虑。
三问框架:在动手前逼自己回答
不要凭情绪决策,用下面三个问题给系统做一次"体检"。每个问题都要落到可观察的证据,而不是"我觉得很烂"。
第一问:这套系统现在还创造价值吗
区分"代码烂"和"系统没价值"。一个代码丑陋但每天稳定处理数万笔交易的结算系统,价值极高;一个技术时髦但业务已下线的边缘服务,再新也是负资产。
具体看三个指标:它支撑的业务收入或关键流程是什么、停用它会影响谁、未来 12~24 个月是否还有明确演进需求。如果系统已稳定且不再变化,最优策略往往是封装隔离、维持运行,而不是花钱重写一个功能相同的新系统。
第二问:痛苦的根因是架构还是知识
很多"必须重写"的判断,混淆了两类截然不同的问题。
- 架构性问题:耦合呈网状、核心数据模型错误、技术栈已停止维护且无法招人。这类问题修补无法解决,需要重构或重写。
- 知识性问题:没人懂业务规则、缺少文档、没有测试、部署靠口口相传。这类问题靠重写解决不了——因为你连"要重写成什么样"都不知道,重写只会把隐性知识再次埋进新代码。
判断方法很简单:如果给团队三个月专门补测试、补文档、做可观测性,痛点能否消除大半?若能,先做知识工程,别急着换架构。
第三问:重写的隐性成本算清楚了吗
这是最容易被跳过的一问。重写成本绝不只是"写新代码的人天"。
迁移成本测算:把直觉变成数字
建议用一张简单的测算表,把成本显性化。可以直接用下面的思路在团队内估算(数字为示例人天):
text
# 重写/迁移总成本估算(单位:人天)
1. 功能追平成本
- 梳理旧系统全部行为(含边角规则) :15
- 新系统实现并对齐既有功能 :60
2. 数据迁移成本
- 脏数据清洗、字段映射、双写校验 :12
- 历史数据回填与一致性核对 :8
3. 并行运行成本(关键且常被遗漏)
- 重写期间旧系统仍要修 bug、加需求 :30
- 新旧双跑、流量灰度、对账 :10
4. 风险与回退储备
- 按上述总和的 20%~30% 预留 :27
--------------------------------------------
合计 :162 人天测算时有两个关键动作。第一,把"并行运行成本"单列,这是重写项目超支的头号来源——旧系统在新系统上线前不可能冻结,团队实际在同时维护两套。第二,用继续修补的成本做对照:估算未来 12 个月在旧系统上修 bug、加功能的预期投入。如果重写 162 人天,而继续维护一年只要 40 人天且系统无根本性架构障碍,那么除非有明确的扩展性或战略收益,重写在财务上就不成立。
一个实用的决策信号:优先选择能分批交付价值的方案。渐进重构每两周都能上线一部分改善,而重写往往要半年后才能见到第一个可用成果,后者的不确定性和组织信任成本都高得多。
推荐路径:用绞杀者模式渐进迁移
当三问的答案指向"需要改变架构"时,优先采用渐进式迁移:在旧系统前引入流量路由,先把一个边界清晰的模块用新服务实现,通过代理把对应请求切到新服务,验证稳定后再切下一个;数据层采用双写或事件同步保证一致,旧模块被逐个"绞杀"直至整体下线。整个过程系统始终可用、随时可回退,避免了 Big Bang 式切换的豪赌。
避坑总结
坑一:把"没人懂"误判成"架构烂"。 常见现象是团队一接手就喊重写,真正开工才发现连旧系统的计费规则都没人说得清,新系统上线后频频算错账。修正方法:重写前先做一轮行为梳理,用 Characterization Test(特征测试)把现有输入输出固化下来,让旧系统成为新实现的"标准答案"。
坑二:重写期间承诺"功能完全冻结"。 业务方当面答应,转身就提紧急需求,团队被迫新旧两边都改,最终双线崩溃。修正方法:不要假设能冻结,而是把并行开发成本显式算进计划,并采用绞杀者模式缩短每批切换周期,让"两线作战"的窗口尽量短。
坑三:低估数据迁移,只盯代码重写。 新代码按期完成,却卡在历史脏数据、重复主键、字段语义不一致上,上线一拖再拖。修正方法:在项目第一周就做数据画像,提前清洗、制定映射规则,并设计双写与对账机制,用"新旧数据逐条比对"作为切换的硬门槛。
坑四:用最时髦的技术栈作为重写理由。 "旧框架不够现代"本身不构成商业理由,新栈还会带来招人、踩坑、生态成熟度等新风险。修正方法:技术选型必须绑定具体痛点——只有当新栈能实证解决扩展性、性能或可维护性问题时,切换才值得,否则保留 boring technology 反而是更理性的选择。
重写从来不是一个技术纯洁性问题,而是一道投资回报题。先用三问框架确认系统的价值、痛苦的根因和真实成本,再让数字而不是情绪替你做决定——能渐进就别豪赌,该保留就果断封装。
免责声明
本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。