来源:Martin Fowler、Kent Beck、Ron Jeffries、Superpowers 项目实践
为什么把它们放在一起?
YAGNI 和 TDD 表面上是两个独立原则,但它们来自同一个母体——极限编程(Extreme Programming, XP),共享同一个哲学内核,并且在实践中互为前提。
YAGNI — “You Aren’t Gonna Need It”
不要为你预想的未来需求写代码。直到真正需要的那一刻才写。
起源:1990 年代末,Kent Beck 和 Chet Hendrickson 在 C3 项目上。Chet 不停提出「系统将来会需要 X」,Kent 每次都回答「你用不着它的(You aren’t gonna need it)」。
Martin Fowler 把提前构建「推测性功能」的成本分为四种:
| 成本 | 说明 |
|---|---|
| 构建成本 | 花时间做了一个最终没用的东西 |
| 延迟成本 | 这段时间本可以做现在就能产生价值的东西 |
| 携带成本 | 多余代码增加复杂度,让后续每个功能都更难做 |
| 修复成本 | 就算猜对了需求,6 个月后的最优解已经不同了 |
一个惊人的数据:微软研究发现,即使经过仔细前期分析,只有 ⅓ 的功能最终改善了它们想改善的指标。提前做的功能有 ⅔ 的概率是浪费。
常见误解
YAGNI ≠ 不做设计。 它只适用于「为未来需求提前写的功能代码」,不适用于:
- 重构(让代码更易修改)
- 自测试代码(TDD)
- 持续交付基础设施
这些让代码保持可修改性的工作,正是 YAGNI 得以成立的前提。
YAGNI 的悖论:它既被进化式设计所启用,也启用了进化式设计。
TDD — Test-Driven Development
先写测试,看到测试失败,再写最少的代码让测试通过,然后重构。
三个步骤,无限循环:
- RED — 写一个失败的测试(描述想要的行为)
- GREEN — 写最少的代码让测试通过
- REFACTOR — 清理代码,保持测试通过
为什么先写测试?
接口优先思维:先写测试逼你先想「我要怎么用这个功能」——先设计接口再想实现。很多程序员的问题是先想实现再想接口,导致 API 难用。TDD 自然地把你拉到用户视角。
自测试代码:规则是「只有在让测试通过时才能写生产代码」,最终代码库天然有完整的测试覆盖——不是「写完代码补测试」,而是「测试驱动代码的产生」。
Superpowers 的激进立场
先写了代码?删掉。不要当参考。不要看它。删就是删。
原因:后写的测试受实现偏见影响,你只会测试「做了什么」而不是「该做什么」。沉没成本谬误——「已经写了 X 小时」不是保留它的理由。
TDD 最常见的失败模式
忽略第三步(Refactor)。只做 Red-Green 不做 Refactor,最终得到有测试的混乱代码——比没有测试好一点,但远不够好。
互为前提
这两个原则不是并列的,是互为前提的:
[[YAGNI]] 说:别提前做,以后再做。
[[TDD]] 说:好,但要让代码随时可改。
[[TDD]] 说:只写最少的代码让测试通过。
[[YAGNI]] 说:对,多一行都是浪费。
没有 TDD 的 YAGNI = 灾难。没有测试保护,「以后再改」变成「以后改了就炸」。
没有 YAGNI 的 TDD = 浪费。为推测性功能写测试,花双倍力气做不需要的东西。
共同的哲学根基
对人类预测能力的不信任
两者都基于同一个前提:人类非常不擅长预测未来。
「做最少的事」= 最快的速度
直觉上「多做准备」应该更快,但实践反复证明:做最少必要的事是最快的路径。
- 少写代码 = 少维护、少调试
- 每步有测试 = 出错立刻知道、立刻修
- 不提前做 = 不需要后来拆掉重做
勇气来自安全网
Kent Beck 说 XP 的核心价值之一是勇气——敢于大幅修改代码、敢于删掉不需要的、敢于说「以后再做」。这种勇气不是来自自信,而是来自安全网:测试套件在,改坏了会立刻知道。
在 AI 时代的新意义
相关:YAGNI · TDD · Spec-First Development · Superpowers 分析