DRY 针对的是什么
DRY(Don't Repeat Yourself)针对的是知识重复:同一条业务规则在多个地方各写一遍,改动时必须同步修改多处,漏掉一处就是缺陷。它并不要求把长得像的代码都合并——外观相似但语义不同、会各自独立演化的两段代码,硬合并反而制造出错误的耦合。
基本信息
| 本质 | 规则与知识的单一表述 |
|---|---|
| 常见误用 | 把巧合相似当成重复,强行抽取 |
| 判断方法 | 两段代码是否因同一需求同时改动 |
| 例外 | 语义不同但暂时同源的规则,可以先保留两份 |
典型使用场景
- 同一校验规则散落多端:前端、后端、批处理各写一遍,应抽成单一来源
- 同一常量重复硬编码:改一处忘一处,提取为常量或配置
- 文档与代码描述同一份规则:实现改了文档不跟着改,同样是重复
- 两段巧合相似的代码:变化原因不同,保持独立更安全
- 多个模块各自实现同一协议:抽成共享库并明确维护责任
判断是不是真重复
- 它们会因为同一个需求变化而同时修改吗
- 合并之后是否引入了与业务无关的耦合
- 合并后的抽象会不会比两份实现更难理解
- 如果规则今后分化,拆开的成本有多大
相似但语义不同
相似但语义不同
// 用户校验与管理员校验:规则现在相同,将来可能分化
// 直接抽成同一个函数:一方改规则就会误伤另一方
// 可先保留两份,等变化节奏一致时再合并
boolean isValidUser(String name) { return name.length() >= 3; }
boolean isValidAdmin(String name) { return name.length() >= 3; }重复类型与处理方向
| 重复类型 | 处理方向 |
|---|---|
| 同一规则多处实现 | 抽成单一来源,供各方调用 |
| 巧合相似的两段代码 | 保持独立,等变化节奏一致再合并 |
| 常量与配置硬编码 | 提取为常量或配置项 |
| 文档与代码不一致 | 以代码为准更新文档,或让文档自动生成 |
DRY 的检验器是变化:改一个需求时被迫改多处,那才是真正的重复。
抽取的代价要一起算:多一层间接、多一个共享模块的维护责任,都属于合并的成本。