首页/开发/代码质量与评审速查/DRY:知识重复的边界
设计原则与模式62 条

DRY:知识重复的边界

DRY(Don't Repeat Yourself)针对的是知识重复:同一规则在多处表述,改动需同步;外观相似的代码若语义不同、会独立变化,硬合并反而制造错误耦合。

DRY 针对的是什么

DRY(Don't Repeat Yourself)针对的是知识重复:同一条业务规则在多个地方各写一遍,改动时必须同步修改多处,漏掉一处就是缺陷。它并不要求把长得像的代码都合并——外观相似但语义不同、会各自独立演化的两段代码,硬合并反而制造出错误的耦合。

基本信息

本质规则与知识的单一表述
常见误用把巧合相似当成重复,强行抽取
判断方法两段代码是否因同一需求同时改动
例外语义不同但暂时同源的规则,可以先保留两份

典型使用场景

  • 同一校验规则散落多端:前端、后端、批处理各写一遍,应抽成单一来源
  • 同一常量重复硬编码:改一处忘一处,提取为常量或配置
  • 文档与代码描述同一份规则:实现改了文档不跟着改,同样是重复
  • 两段巧合相似的代码:变化原因不同,保持独立更安全
  • 多个模块各自实现同一协议:抽成共享库并明确维护责任

判断是不是真重复

  • 它们会因为同一个需求变化而同时修改吗
  • 合并之后是否引入了与业务无关的耦合
  • 合并后的抽象会不会比两份实现更难理解
  • 如果规则今后分化,拆开的成本有多大

相似但语义不同

相似但语义不同
// 用户校验与管理员校验:规则现在相同,将来可能分化
// 直接抽成同一个函数:一方改规则就会误伤另一方
// 可先保留两份,等变化节奏一致时再合并
boolean isValidUser(String name) { return name.length() >= 3; }
boolean isValidAdmin(String name) { return name.length() >= 3; }

重复类型与处理方向

重复类型处理方向
同一规则多处实现抽成单一来源,供各方调用
巧合相似的两段代码保持独立,等变化节奏一致再合并
常量与配置硬编码提取为常量或配置项
文档与代码不一致以代码为准更新文档,或让文档自动生成
DRY 的检验器是变化:改一个需求时被迫改多处,那才是真正的重复。
抽取的代价要一起算:多一层间接、多一个共享模块的维护责任,都属于合并的成本。

易错点

  • 按字符串相似度自动合并:语义已经漂移的两段代码被绑死在一起
  • 注释与文档不同步时不处理:文字里的重复同样需要治理
  • 为 DRY 强行抽象:为一段逻辑加配置项与回调,反而更难读懂
  • 把 DRY 硬套到测试上:可读的重复断言往往比抽象过的辅助函数更容易排查失败

数据来源与参考

  • 《The Pragmatic Programmer》· DRY 条目;《重构》重复代码相关讨论
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌