原则
YAGNI:"You Aren't Gonna Need It"(你不会需要它)。
含义:不要为"将来可能需要"的功能写代码,只实现当前需要的。
为什么重要
一、预测未来的需求是很难的
研究表明,人们(包括领域专家)在预测未来需求上表现很差。
结果:为"将来"写的抽象和扩展点,往往:
- 从未被使用;
- 或者被使用时,当初的设计假设已经错了。
二、代码是有成本的
每一行代码都要:
- 被阅读和理解;
- 被测试;
- 被维护(依赖升级、重构、修改);
- 可能引入 bug。
没用到的代码不是"免费的可选项",而是持续的成本。
三、过早的抽象会束缚你
一个为"可能的多种情况"设计的抽象,当你真正遇到第二种情况时,往往会发现:
- 实际情况与预期不同;
- 抽象的接口不对;
- 修改这个抽象的代价比当初直接写更高。
这就是"错误的抽象比重复更糟糕"。
一个常见场景
// 需求:支持 MySQL
// "将来可能要支持 Oracle、PostgreSQL……"
public interface DatabaseAdapter { ... }
public class MySQLAdapter implements DatabaseAdapter { ... }
// 但永远只有 MySQLAdapter 这一个实现YAGNI 的做法:先直接用 MySQL 的客户端写。
如果将来真的需要支持第二种数据库,那时你有两个具体的实现,才能看出哪些是需要抽象的共同点——这时抽象才是正确的。
这就是"三次法则"(前文提到过):第一次直接做,第二次注意重复,第三次才抽象。
例外情况
YAGNI 不是"不做任何设计"。
一、架构级的决策应该有一定前瞻性
比如:
- 数据模型和存储选型;
- 服务边界的划分;
- 对外暴露的 API 契约。
这些后期变更成本极高的决策,值得多想一步。
但"多想一步"不等于"实现所有可能性"——你可以选择架构,让它容易在未来扩展,而不必现在就把扩展实现出来。
二、明确的、有依据的未来需求
如果需求方明确说"下个季度要支持 X",且这是可信的,那么现在就考虑 X 是合理的。
判断标准:这是"我猜可能会",还是"我们确定会"?
三、安全与合规要求
某些安全设计不能等到"需要时再加"——因为事后补的成本和风险都太高。
与其它原则的关系
KISS(Keep It Simple, Stupid):保持简单。
DRY(Don't Repeat Yourself):不要重复。
注意 DRY 与 YAGNI 的张力:
- DRY 说:消除重复;
- YAGNI 说:不要为将来写代码。
协调:对已经存在的重复,DRY 适用;对想象中的未来需求,YAGNI 适用。
少量重复的成本,往往低于过早抽象的成本。
一个实用的自问
在加一段"为了将来"的代码前,问自己:
- 这个需求在当前是真实存在的吗?
- 如果不加,将来加的成本有多高?(如果很低,那就现在别加)
- 我对未来的预测有多大的把握?
- 这段代码现在有人用吗?
如果"将来加的成本"很低(通常如此),那就遵循 YAGNI。
一句话
"为今天设计,为明天做好准备(但不要今天就建造明天)。"
让代码保持易于修改,比让它预先包含所有可能性更有价值。
说明:本文为软件设计原则的知识整理。