架构风格与模式58 条

DRY、KISS 与 YAGNI

三条通用设计原则:DRY 指知识的唯一来源(不是禁止任何重复代码),KISS 指优先选择简单方案,YAGNI 指不实现当前不需要的能力。

三条原则是什么

DRY 指知识的唯一来源,同一业务规则或常量只在一处表达;KISS 指优先选择简单方案,把复杂度用在真正需要的地方;YAGNI 指不实现当下不需要的能力,等真实需求出现再扩展。三条原则共同约束过度设计,常被误读为“禁止任何重复代码”“一切从简”与“拒绝所有扩展点”,实际它们针对的是同一件事:控制变化成本。

原则与误用

原则含义常见误用
DRY同一知识只表达一次为消除表面重复强行抽象出错误概念
KISS简单方案优先把简单问题包装成通用框架
YAGNI只做当下需要的能力拒绝必要的扩展点设计
共同目标控制变化影响面与维护成本拿原则当挡箭牌拒绝合理抽象

判断方法

  • 两处代码长得像但变化原因不同,不应该合并(重复的偶然,不是重复的知识)
  • 同一业务规则在多处出现且必须同时修改,属于真正的重复,应抽取
  • 新增能力需要引入第三个抽象层,先确认是否已有两个真实实现
  • 通用方案需要枚举未来所有场景,说明当前就应该先写具体实现
  • 扩展点只在已知日期或路线图上出现时才预留,避免为想象留接口
  • 重构时先补测试,再消除重复,避免合并过程中引入行为变化

基本信息

适用范围代码、配置、文档、测试数据与业务流程
评判标准改动一处业务规则需要修改几个地方,数量越少越好
常见反例复制粘贴后分别改造,规则逐渐分化且无人察觉
常见过度为三行相似代码建一套配置驱动的通用引擎
配合使用与 SOLID 一起约束职责划分与抽象程度
DRY 的对象是知识而不是代码字符:两段代码形式相同但服务于不同业务规则,合并后一旦其中一方的规则变化,反而被迫增加分支。
以 YAGNI 为由完全不留扩展点,遇到真实变化时只能大规模修改,成本高于提前预留一个简单接口。

易错点

  • 为消除表面重复强行抽象,得到一组概念混乱的通用类,理解成本高于原来的重复
  • 复制粘贴后分别改造,同一规则在多个副本里演化出不同行为
  • 以 KISS 为由拒绝任何分层与抽象,业务规则与框架代码混杂在一起
  • 以 YAGNI 为由把所有扩展点砍掉,需求变化时改动面覆盖整个模块
  • 把三原则当评审里的口号,不落到具体的重复点与抽象收益上

数据来源与参考

  • Andrew Hunt & David Thomas《The Pragmatic Programmer》
  • Ron Jeffries《You're NOT gonna need it!》(XP)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌