关于 dry
dry 是一项指导编码 Agent 应用 DRY 原则的技能,强调消除重复知识而非相似代码,并兼顾 KISS、YAGNI 等边界。适用于代码实现与审查。
主要功能
- 01区分知识重复与代码相似
- 02集中配置、规则与数据来源
- 03在模式稳定后提取抽象
- 04通过代码生成保持表示同步
- 05提供代码审查检查清单
适用场景
- 01合并重复的业务规则
- 02检查配置与常量是否重复
- 03评估抽象是否过早或过度
- 04减少修改规则时涉及的文件数
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jordancoin/ codingskills --skill dry安装后在 Claude Code 中输入/dry确认已加载。
详细介绍
DRY — 不要重复自己
应用前
如果 .agents/stack-context.md 存在,请先阅读。根据检测到的技术栈,使用符合其惯用风格的模式来应用此原则。对于框架特定的细节,请使用 context7 MCP 或网络搜索,不要猜测。
原则
系统中的每一项知识都应有唯一且权威的表示。当这项知识发生变化时,你只需在一个地方修改。
为什么这在生产环境中很重要
重复的逻辑是一颗定时炸弹。当业务规则发生变化,而你只在一个地方更新、却漏掉另一处副本时,就会出现难以察觉、也更难调试的不一致行为。副本越多,其中一份悄然偏离的可能性就越大。
DRY 不是为了消除看起来相似的代码,而是为了消除重复的知识——也就是在多个地方表达同一条业务规则、同一个决策或同一个事实来源。
规则
- 区分知识重复与代码重复。 两个看起来相同、但代表不同业务概念的函数应该保持独立。编码了同一条业务规则的两个函数则应该合并。
- 数据应有唯一事实来源。 配置、常量、模式定义和验证规则都应各自只存在于一个地方。其他所有内容都应由该来源派生。
- 模式稳定后再提取。 不要在模式第一次出现时就提取——此时你还不知道抽象应采用什么形式。只有在至少两次看到语义相同的重复模式后,才进行提取。
- 集中管理业务规则。 税费计算、权限检查、定价逻辑都必须放在同一个模块中,而不是散布在处理器、前端和脚本里。
- 优先使用代码生成,而不是手动同步。 如果两种表示必须保持同步(例如,API 类型和客户端类型、模式和文档),就从一种生成另一种,而不是手动维护两者。
反模式
- 牵一发而动全身: 修改一条业务规则需要编辑 5 个以上文件,因为这条规则到处都有重复
- 复制-粘贴-修改: 克隆一个函数并稍作调整,而不是为原函数增加参数
- 平行层级结构: 在多个层中维护相互匹配的结构(例如,后端和前端中相同的类型定义,却不是从共享模式生成的)
- 在多个文件中重复使用魔法字符串: 同一个状态码、错误消息或配置键被硬编码在多个位置
- 重复描述代码的文档: 注释或文档重复说明代码已经表达的内容(并不可避免地逐渐与代码脱节)
错误的 DRY 做法
-- Code looks similar but represents different concepts — DO NOT unify
def calculate_shipping_cost(weight, distance):
return weight * 0.5 + distance * 0.1
def calculate_insurance_premium(value, risk_factor):
return value * 0.5 + risk_factor * 0.1
-- These are different business rules that happen to share a formula today.
-- They will diverge. Keep them separate.
正确的 DRY 做法
-- Same validation rule duplicated — UNIFY
// in signup handler
if len(password) < 8 or not has_uppercase(password):
return error("Password too weak")
// in password-reset handler
if len(new_password) < 8 or not has_uppercase(new_password):
return error("Password too weak")
-- Fix: single source of truth
def validate_password(password):
if len(password) < 8:
return error("Password must be at least 8 characters")
if not has_uppercase(password):
return error("Password must contain an uppercase letter")
return ok()
边界
- DRY 关注的是知识,而不是语法。 两段看起来相同的代码可能代表不同的事物。不要仅仅因为它们看起来相同就将其合并。
- 过早追求 DRY 会产生错误的抽象。 糟糕的抽象比重复更糟,因为它更难撤销。提取前先等到你理解了这个模式。
- 与 KISS 的张力: 过于激进的 DRY 重构可能会引入多层间接结构,比原来的重复更难理解。如果共享函数需要 5 个参数和 3 个布尔标志才能处理所有情况,那么重复反而更简单。
- 与 YAGNI 的张力: 不要「因为以后可能会在别处用到」就构建通用工具。只有在存在具体的重复内容时才进行提取。
- 跨边界 DRY 的代价很高。 在服务、仓库或团队之间共享代码会带来耦合。有时,跨边界重复比使用会阻碍独立部署的共享库更健康。
代码审查清单
- 这项更改是否引入了其他地方已有的重复业务逻辑?
- 是否存在应该定义为常量的魔法字符串或数字?
- 如果这条业务规则发生变化,需要更新多少个文件?
- 是否有共享抽象被迫同时满足过多需求?(错误地应用 DRY)
- 是否存在可以通过生成来实现同步的并行表示,却需要手动同步?
相关技能
- yagni:决定是否提取时(等到出现 3 次)
- kiss:当 DRY 抽象比重复代码更难理解时
- convention-over-configuration:用于消除重复的配置模式
评论
支持 Markdown