YAGNI 是 “You Aren’t Gonna Need It” 的缩写,意思是「你(现在)不会需要它」。它是极限编程(XP)提出的一条实践原则,由 Kent Beck、Ron Jeffries 等人总结,核心主张是:只在真正需要某个功能时才去实现它,不要因为「以后可能用得上」就提前把它做出来。

它要解决的问题

开发中有一种很常见的冲动:在写当前功能时,顺手把「将来或许会用到」的扩展点、配置项、抽象层一起加上。这类提前实现往往带来几种代价:

  • 做了用不上的功能:付出了开发和测试成本,最终却从未被使用。
  • 增加复杂度:每一个为「未来」准备的抽象、参数、分支,都会让代码更难读、更难改。
  • 猜错方向:未来的真实需求常常和当初设想的不一样,提前写好的代码反而成了包袱,删也不是、改也不是。
  • 维护负担:哪怕没用上,这些代码也要被阅读、被编译、被测试、跟着一起重构。

Martin Fowler 把这种「为了未必到来的需求而提前增加的灵活性」称为 speculative generality(投机性通用化),并将其列为一种代码坏味道。YAGNI 正是针对它的解药。

一个例子

假设要做一个把数据导出为 CSV 的功能。

违反 YAGNI 的做法:考虑到「以后可能还要导出 JSON、Excel、PDF」,于是先设计一套 Exporter 接口、工厂、注册表、插件机制,再让 CSV 成为其中一个实现。结果当下只用到 CSV,那一整套扩展架构全是空转的成本。

遵循 YAGNI 的做法:现在只需要 CSV,那就先写一个直接、清晰的 CSV 导出函数。等真的要支持第二种格式时,再基于那时已经明确的两个真实场景去抽象接口——这时的抽象建立在事实之上,而不是猜测之上。

与 KISS、DRY 的关系

这几条原则常被一起提及,但侧重点不同:

  • YAGNI:不要做现在不需要的功能(针对「范围」)。
  • KISS(Keep It Simple, Stupid):用尽量简单的方式解决问题(针对「实现」)。
  • DRY(Don’t Repeat Yourself):消除重复的知识(针对「重复」)。

三者方向一致,都指向「不要引入不必要的复杂度」。值得注意的是 YAGNI 和 DRY 偶尔会拉扯:为了「将来复用」而过早抽取公共逻辑,可能正是一种 YAGNI 想避免的投机性抽象。经验法则是先容忍少量重复,等重复出现第三次、模式真正清晰时再抽象。

边界:YAGNI 不是什么

YAGNI 容易被误读为「不要做任何设计」或「怎么糙怎么来」,这是误解。它有明确的适用边界:

  • 它针对的是「功能/特性」,不是「质量」。该有的测试、错误处理、清晰命名、合理结构都不能省——这些是当前就需要的,不是「未来」。
  • 它偏好可逆决策。YAGNI 之所以成立,前提是「以后再加也不难」。对于难以回退的决策(如数据库选型、对外 API 契约、安全模型、数据格式),仍需要提前认真设计,因为它们不满足「需要时再做」的低成本假设。
  • 它不反对抽象,只反对过早抽象。抽象应当由重复的、已经发生的真实需求来驱动,而不是由想象中的需求来驱动。

实践建议

  • 写代码前问一句:这个能力是当前这个需求现在就要的吗?如果不是,先不做。
  • 把「以后可能要做」的想法记进 backlog 或 TODO,而不是写进代码。
  • 优先保证当前实现简单、清晰、可改;保留把改动控制在小范围内的能力,比预先把扩展点全部铺好更有价值。
  • 对不可逆的决策慎用 YAGNI,对可逆的决策大胆用。

YAGNI 的本质是一种关于「时机」的纪律:把实现推迟到信息最充分的那一刻。需求在「需要时」往往比「设想时」清晰得多,那时再动手,既省去了无用功,也避免了基于错误猜测的设计。