经验与方法论 · 共识经验 · 收录于 2026-09-01

技术债越欠越多,接手"屎山"代码到底该不该重写?

症状

我交过一笔最贵的"学费",是一次全量重写。

当时我接手一个跑了六年的老系统,业务逻辑缠成一团,改一个字段要顺藤摸瓜找出七八处关联。我看了三天,越看越气:"这种代码留着干嘛?重写!"我拉上两个同事,用当时最流行的新框架,从零开始搭。三个月后,新系统能跑了——然后我们傻眼了:老系统六年的边界情况、暗坑、兼容逻辑,全藏在那些"烂代码"里,新系统一个都没带过来。上线第一个月,业务方报了一百多个"以前能用现在不能用了"。

最后我们又花了大半年,把老系统的逻辑一点一点补回去。

那一次重写,成本是新写的三倍,还差点把业务线干没。

这不是我一个人的故事。我后来见过太多团队掉进同一个坑:接手老系统,越看越不顺眼,全员高呼"重写",立项、排期、干三个月,然后被现实打脸。也有反过来的——一个朋友的公司把老系统当"祖传宝贝"供着,什么都不敢动,结果每次需求都要绕路,半年后系统终于被业务抛弃,重写成本翻了十倍。

如果你也在经历这些——手头的代码越改越乱,天天在"屎山"上贴瓷砖;或者你刚接手一个老项目,满脑子都是"重写吧"——这篇文章是写给同类人的。它不是重构教程,是那些在真实项目里还过技术债、也踩过重写大坑的人,用事故换来的共识:技术债不是靠一次重写还清的,是靠一次次小步偿还的。

原因

先搞清楚"技术债"到底是什么。这个词是 Ward Cunningham(wiki 之父)1992 年发明的:借债本身不是问题,问题是不还利息。

把非理想的代码、设计、架构决策看作"本金",把维护、理解、扩展、修复它们多花的时间看作"利息"——这跟金融债务一模一样:借的时候很爽(快),利息每天都在涨(越来越难改),而且你永远不知道哪一天会暴雷(改一行崩全局)。

技术债是怎么欠下的?不是开发者偷懒。我复盘过自己和身边团队踩过的坑,债的来源几乎都是"当时看起来合理的决定":

  1. 赶工:"这版先这么写,上线后重构"——上线后没人记得,记得了也没人敢动;
  2. 需求变了:当初按 A 场景设计,业务变成了 B 场景,代码在原架构上打补丁,越打越厚;
  3. 换人:写代码的人离职了,注释和代码各说各话,后来的人只能猜;
  4. 测试敷衍:没有自动化测试,改代码如履薄冰,于是干脆不改,债越滚越大;
  5. 技术过时:依赖库停留在多年前的版本,想升级发现没人知道为什么当初这么选。

这里有个特别扎心的机制:技术债的利息是复利,而且收利息的时机你控制不了。 前六个月你可能毫无感觉,甚至觉得"代码还行";等系统长到一定规模,每一次改动都开始牵一发动全身,你每天 50% 的时间在修 bug 而不是做功能——这时候债已经大到"不敢还"了:重构的 ROI 在老板眼里是零,因为"没坏就别修",可系统一旦崩了,老板又觉得是你们没维护好。

我观察到的真相是:还债的最大障碍从来不是技术,是"一次还清"的执念。 全量重写是最贵、最危险、成功率最低的还债方式;真正有效的方式,是绞杀者模式——像绞杀榕一样,在新系统旁边一点点长出来,把老系统慢慢包住、替换掉。下面每一条经验,都是这个共识在不同场景下的展开。

解法

下面每条经验都按「现象 → 做法 → 为什么」展开。它们不是一家之言,而是多篇独立实践里反复出现的共识。

经验 0(L1 一句话结论):别重写,绞杀它——小步还债,每步可回滚

技术债只能分批还,不能一次还清。凡是"推倒重来"的还债方案,成功率都低得可怜;凡是"新老并存、逐步替换"的方案,虽然慢,但稳。赶时间只看这一条:接手"屎山"先别骂,先给系统装上测试保护网,然后用绞杀者模式一小块一小块地替换。下面的经验 1~5 是为什么。

经验 1:识别先行——把"感觉烂"变成"清单"

现象:几乎所有团队都知道自己有技术债,但问"债在哪",没人说得清。我见过最典型的状态:"这个系统很烂"是共识,"烂在哪、先还哪"是空白。结果就是:想还债的人无从下手,不想还债的人有理由拖延。

做法:先把债显性化。三件套:①画一张系统热力图(SonarQube 等技术债扫描工具,按模块标出复杂度、重复代码、坏味道);②建一张技术债清单,每条写清"在哪、为什么是债、不还的后果";③用四象限排序——高影响高紧急的优先,低影响低紧急的排队。核心逻辑只有一条:把"感觉"变成数字和清单,债才谈得上"还"。

为什么:技术债最可怕的地方是隐形。它不报错、不告警,只是让你的每次改动都越来越慢。清单和热力图把隐形的东西显性化,还债才有优先级、有进度、有交代——老板能看到 ROI,团队能看到盼头。

经验 2:别全量重写——绞杀者模式是唯一被反复验证的路线

现象:这是翻车率最高的一步,我自己就翻过(开头那个三个月重写就是)。重写的诱惑太大了:新框架、新架构、干净的代码,谁不想要?但现实是:老系统六年的边界情况、兼容逻辑、暗坑,全部藏在"烂代码"里,重写时你根本不知道它们存在,直到上线后业务方一个个找上门。行业里著名的重写翻车案例(Netscape 重写、Healthcare.gov 初期)都是同一个剧本。

做法:用绞杀者模式(Strangler Fig Pattern,Martin Fowler 提出):新功能用新架构写,老功能一个模块一个模块地迁移到新系统,每迁移一块就下线一块老模块,直到老系统被完全"绞杀"。关键原则:新老系统通过防腐层(Adapter)对接,老系统一天没死,就一天是事实源。 迁移顺序按"业务价值 × 风险"排:先迁独立、低风险、高频的模块,建立信心后再碰核心。

为什么:绞杀者模式把"一次大爆炸"拆成"无数次小爆炸",每次爆炸范围可控、可回滚、可验证。业务不中断,老板不恐慌,团队有正反馈。全量重写的本质是"用未来三年的风险赌现在三个月的爽",而绞杀者模式是"用每个迭代的小步,换不翻车的确定性"。

经验 3:测试保护网——没测试,别碰核心逻辑

现象:重构最大的恐惧是"改坏了怎么办"。没有测试的系统,改一行代码要靠"感觉"和"运气";改完上线,出了问题连是哪次改动引入的都查不出来。我见过太多团队死在"先重构后补测试"的顺序上——重构到一半发现行为变了,又不知道是不是自己改坏的,只能回滚,来回几次,士气就没了。

做法:先补测试,再重构。 不用追求全覆盖,先把"关键路径"包住:核心业务逻辑、资金/权限/数据一致性相关的高危代码,用测试固定住当前行为(哪怕当前行为是错的,也要先固定,因为那是线上行为)。实测有效的参考线:核心代码覆盖率 80%+ 再动,至少把高危代码的关键路径包住。重构时每步跑测试,红→绿→重构循环。

为什么:测试保护网是"敢动"的前提。有了它,重构从"赌博"变成"验证"——改坏了测试会告诉你,而不是上线后用户告诉你。这也是绞杀者模式能跑起来的地基:没有测试,你连"这块迁过去行为没变"都无法证明。

经验 4:小步重构——单次改动小到可以随时回滚

现象:重构翻车的第二个常见原因是"步子太大"。我见过同事一次重构改了 2000 行,改完编译都过不去,回滚又舍不得,最后熬夜修到上线前夜。经验规律:重构的难度和改动量不是线性关系,是指数关系——每多一个逻辑分支,理解成本就组合式上涨。

做法:单次重构控制在可回滚的粒度(行业共识:一次不超过 50 行,最多不碰超过 500 行的 MR/PR)。每次重构前先提交一个干净的基线,改完立刻跑测试 + 让同事 review;CI 全绿再提交下一步。别信"这次改动就是这么多,没法拆"——拆不动说明设计抽象不够,先做架构调整再动手。

为什么:小步重构把"改坏了"的成本从"通宵回滚"降到"撤销一个 commit"。而且小步重构有个隐藏收益:每一步都有同事 review,知识在团队里流动——重构一次,全组都更懂这块代码了,这是大重构永远给不了的。

经验 5:把还债排进迭代——债是还的,不是等的

现象:技术债清单建了,优先级排了,然后呢?最常见的结局是清单吃灰——因为"还债"没有排进迭代,永远被新需求挤掉。"等有空了再还"的意思是永远不还。

做法:把还债变成迭代的固定项:每个迭代划出固定比例的时间(参考实践:20% 左右)专门还债,还债任务和功能任务一样有验收标准、有 review、有记录。把"还债"从"额外工作"变成"常规工作"。老板视角的话术:还债不是烧钱,是给系统买保险——今天不还,利息每天在涨。

为什么:技术债是持续产生的(每个赶工的需求都在产生新债),所以还债也必须持续。固定比例的机制化安排,让还债不依赖某个人"有良心"、不依赖某个版本"恰好有空"。它是唯一能跑赢"利息复利"的方式。

怎么开始用(落地清单,L1 执行层)

  1. 先扫描,后动手:SonarQube(或同类工具)出一张技术债热力图,建清单,四象限排序;
  2. 给关键路径补测试:核心业务 + 高危代码先包住,覆盖率 80% 再动核心;
  3. 选一个独立小模块试点绞杀者模式:新架构写新功能,老模块一块块迁,防腐层隔离;
  4. 小步提交:单次重构 ≤50 行,每步 CI 全绿 + review,随时可回滚;
  5. 把还债排进迭代:每迭代固定 20% 时间,还债任务有验收、有记录、有 review。

怎么迁移到你的场景(L3 深入层)

  • 个人项目:没有老板和团队,你的债主是你自己——定期用扫描工具看看自己的代码,至少把"每次改动都要靠猜"的模块补上测试;重构前 git commit 一个干净基线,改坏了随时回退。
  • 小团队(5-15 人):技术债清单建起来,每次迭代划固定比例时间还债;别搞"重构周"——集中式还债既影响业务又容易烂尾,细水长流才是正解。
  • 大型系统 / 核心业务:只走绞杀者模式,防腐层隔离,迁移顺序按业务价值×风险排;任何一次 Big Bang 重写提案,先问三个问题:老系统的边界情况你盘点全了吗?测试保护网建好了吗?业务能接受几个月的不稳定吗?答不上来就别立项。
  • AI 时代:AI 是重构的好帮手(识别代码异味、批量替换、生成测试),但"重写"的诱惑在 AI 时代更大了——AI 生成新系统的速度会让你误以为重写成本很低。清醒一点:AI 帮你写的也是新代码,老系统的业务逻辑它同样看不见。让 AI 做绞杀者模式里的"手术刀",别让它做"推土机"。
  • 如果你正在犹豫"要不要重写":先做经验 1 和 3——把债列出来,把测试补上。做完这两步,你大概率会发现:真正需要"重写"的部分,远没有你想象的那么多;而剩下的债,绞杀者模式足够还清。

收尾:我栽过最大的跟头,是相信「重构完就清爽了」——结果重写两个月,老系统的边界情况在第四周开始报复我,最后灰溜溜回滚。后来我才想明白:技术债不是「脏东西要一次性清掉」,它是「你欠未来的利息,得按月还」。别等大扫除——先把债列出来、把测试补上,剩下的交给绞杀者模式慢慢磨。你不需要一次还清,你只需要今天开始还。

不绑定工具

本条目为共识型经验,不挂接具体工具;相关工具类问题请到对应工具的问题页。

来源与证据

收录 共识经验 · 不承诺实测
本条目为共识型经验:不承诺本地实测,案例已脱敏提炼进正文,外部来源不逐一列出。

← 经验与方法论 问题域 | 问题货架 | 遇到其它问题?去 问题空间 提交求助卡