核心答案: 技术债务是 Ward Cunningham 在 1992 年创造的词,原本指的不是杂乱代码,而是代码与当前理解之间的差距。
Cunningham 强调,债务策略要发挥作用,代码反而必须保持整洁。
开发者向非开发者解释重构时,经常会用到一个词:技术债务。
本文接续上一篇文章代码异味 #5。
意思是:为了快速完成而背上了债务,利息正在增加,所以需要时间偿还。
但这个词的创造者曾多次说明,他的比喻正在被错误使用,尤其是把杂乱代码称为债务。
1992 年,Ward Cunningham
“技术债务”这一表达由 Ward Cunningham 于 1992 年首次使用,出现在 OOPSLA(Object-Oriented Programming, Systems, Languages & Applications,面向对象编程大会)的经验报告中(论文)。
就是那位因发明 Wiki、并作为极限编程早期人物而广为人知的 Cunningham。
当时,他正在开发金融软件。困难在于领域本身。
你不可能在开始前就完全准确地理解金融产品的结构。因此,他选择先根据当时的理解完成并发布,再把使用过程中学到的内容持续反映到代码中。
他说的债务正是在这里产生的:当前代码所包含的理解,与团队实际已经获得的理解之间的差距。
最初编写时正确的结构,在更了解领域之后可能已经不再合适。这就是债务;让代码符合新的理解,就是偿还。
2009 年,他留下了一段短视频,再次解释这个比喻并纠正误解。要点如下(Debt Metaphor)。
承担债务是为了快速学习的策略,不是允许你写糟糕代码的许可。实际上,债务策略要能运作,代码必须整洁。
因为代码一旦杂乱,连把所学内容反映进去这件事本身都会变得不可能。
这就是关键:在原始概念中,即使是编写良好的代码也会产生债务。
因为随着时间推移,我们理解世界的方式发生变化,债务就会自动产生。
相反,如今被称为技术债务的东西,其中很大一部分只是随便写出来的代码。按照 Cunningham 的论点,那与其说是债务,不如说只是混乱。
Fowler 的四象限
不过,如果划定“只有真正的债务才算债务”,在实践中就很难使用。Martin Fowler 于 2009 年整理的四象限很好地弥合了这一差距(Technical Debt Quadrant)。
它使用两条轴:有意还是无意,以及鲁莽还是谨慎。
| 鲁莽 | 谨慎 | |
|---|---|---|
| 有意 | “没有时间设计” | “现在发布,代价之后承担” |
| 无意 | “什么是分层?” | “现在才知道本来应该怎么做” |
四个格子的性质完全不同。
有意·谨慎是管理决策。有截止日期,延迟会错失机会,同时也清楚知道之后要付出成本,因此做出选择。
这是最准确符合债务比喻的格子。
但有一个条件:知道代价是什么。
无意·谨慎就是 Cunningham 所说的原始债务。已经尽力做好,六个月后对领域有了更深理解,才看到了更好的结构。
即使没有做错任何事,它也会发生。由于无法避免,除了建立偿还周期之外没有其他对策。
有意·鲁莽是明知故犯地草草处理。它常被称为债务,但由于没有偿还计划,与其说是债务,不如说更接近损失。
无意·鲁莽是因为不了解而变成这样。这里的解决方案不是安排重构,而是学习。
即使是同样杂乱的代码,也会因所在格子不同而采取不同应对方式。团队谈论债务时经常产生分歧,往往是因为彼此想象的是不同格子。
利息由什么支付
金融债务的利息是金钱,技术债务的利息是未来的变更成本。如果添加同一功能,没有债务时需要一天,有债务时需要三天,那么多出的两天就是利息。
采用这个定义,可以得到一个结论:无人触碰的代码,其债务利息为 0。
一个五年没人修改的模块即使很杂乱,只要今后也不会修改,就没有偿还的理由。相反,每周都会改动的页面中的小额债务会持续产生利息。
许多团队会按“有多糟”给债务列表排序,但真正的标准应该是“多久会改一次”。
上一篇文章中使用的 Git 变更频率查询在这里同样有用。频繁变化的文件与质量较差的文件重叠之处,就是利率最高的地方。
Adam Tornhill 将找出这个交集并确定优先级的方法称为基于行为的代码分析。
这个比喻的局限
“技术债务”这个词很方便,问题也正因此而来。什么都可以装进去。
Bug、过时的库、不喜欢的设计、不是自己写的代码,统统都被称为债务。这样一来,这个词就成了“想修复的东西”的同义词,并失去原本的解释力。
只有通过两个问题,把它称为债务才有实际意义。
- **你为了获得什么而承担了它?**必须能说清是获得了时间,还是获得了学习。如果什么都没得到,那不是债务,而是错误。
- **你要如何偿还?**没有偿还计划的债务,这个比喻就无法成立。
也有人反对这个比喻本身。因为“债务”这个词让人觉得“以后还掉就行”,从而掩盖了实际会以复利增长、最终无法偿还的情况。
有人建议改称污染或卫生问题,理由是它更接近需要持续清理的东西,而不是偿还一次就结束的东西。
不过,“债务”这个词能长期存在是有原因的:它是少数能够用于和开发之外的人沟通的比喻之一。
Cunningham 最初提出这个比喻时,也是为了向上司解释为什么需要返工。它不是精确术语,但作为翻译工具依然有价值。
实践中的管理方法
**列出清单,但不要把它埋在 issue tracker 里。**只收集债务票据的待办列表通常没人查看。
可以改为把信息留在代码附近。在相关文件中简要写下为什么会这样、需要什么,下一个打开该文件的人一定会看到。
**碰到时顺手偿还。**反正要修改该文件时,正是利息产生的时点,也是上下文还在脑中的时点。
这就是童子军规则,也就是“离开时要比来时更干净”作为债务管理方法确实有效的原因。
**决定不偿还也是一种管理。**债务列表中有一半不是偿还对象,而是记录对象。
明确决定不偿还某项,可以避免下次重复同样的讨论。
**有意承担债务时,也要写下条件。**例如“发布后两周内”或“用户超过 1 万人之前”。
没有时间点的债务,也就没有偿还时间。
总结
- 技术债务是 Ward Cunningham 在 1992 年创造的词,原本指的不是杂乱代码,而是代码与当前理解之间的差距。
- Cunningham 强调,债务策略要发挥作用,代码反而必须保持整洁。
- Fowler 的四象限按有意性与谨慎程度分成四个格子。每个格子的应对方式都不同。
- 利息是未来的变更成本。无人触碰的代码债务利息为 0,因此没有偿还的理由。
- 如果无法说明获得了什么、要如何偿还,那就不是债务,只是一个问题。
下一篇将讨论当债务积累到难以承受时的选择:修好后继续使用,还是重新编写。
软件行业一些代价最高的错误答案,也正是在这里产生的。
来源与核验标准
- The WyCash Portfolio Management System — Ward Cunningham · 论文原文 · 核验日期 2026-08-17 · 依据:1992 年技术债务比喻的原始说明
- Debt Metaphor — Ward Cunningham · 作者原文 · 核验日期 2026-08-17 · 依据:Ward Cunningham 于 2009 年对技术债务比喻的解释
- Technical Debt Quadrant — Martin Fowler · 作者原文 · 核验日期 2026-08-17 · 依据:按谨慎、鲁莽与有意性划分的技术债务四象限

![[代码异味 #6] 技术债务:Cunningham 所说的原始含义 封面图](/assets/images/posts/1e489696-56aa-4ba2-b569-5cdc8f77c60e/technical-debt-compound-interest-typeset-v1.jpg)