dont-repeat-yourself
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDRY (Don't Repeat Yourself)
DRY (Don't Repeat Yourself)
Overview
概述
Every piece of knowledge must have a single, unambiguous representation in the system.
If you find yourself writing the same logic twice, extract it. Duplication is a bug waiting to happen.
每一项知识在系统中都必须有唯一、明确的表示。
如果你发现自己在编写两次相同的逻辑,就把它抽离出来。代码重复是随时可能爆发的bug隐患。
When to Use
适用场景
- Writing code similar to existing code
- Copy-pasting and modifying
- Making the same change in multiple files
- Validation logic repeated across forms
- Same calculations in different places
- 编写和已有代码相似的代码
- 复制粘贴后再修改
- 需要在多个文件中做相同的变更
- 多个表单之间重复的校验逻辑
- 不同位置执行相同的计算逻辑
The Iron Rule
铁则
NEVER duplicate logic. Extract and reuse.No exceptions:
- Not for "it's faster to copy"
- Not for "they're slightly different"
- Not for "I'll refactor later"
- Not for "it's just a few lines"
NEVER duplicate logic. Extract and reuse.没有例外:
- 哪怕「复制更快」也不行
- 哪怕「它们只有细微差别」也不行
- 哪怕「我之后再重构」也不行
- 哪怕「只有几行代码」也不行
Detection: The Copy-Paste Smell
识别方式:复制粘贴坏味道
If you're about to copy code and modify it, STOP:
typescript
// ❌ VIOLATION: Duplicated validation
function validateRegistrationEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function validateProfileEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); // Same logic!
}
// ✅ CORRECT: Single source of truth
function validateEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
// Reuse everywhere
const isValidRegistration = validateEmail(regEmail);
const isValidProfile = validateEmail(profileEmail);如果你正准备复制代码再修改,立刻停下来:
typescript
// ❌ 违规:重复的校验逻辑
function validateRegistrationEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function validateProfileEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); // 逻辑完全一致!
}
// ✅ 正确:单一可信源
function validateEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
// 所有场景复用
const isValidRegistration = validateEmail(regEmail);
const isValidProfile = validateEmail(profileEmail);Detection: The "Change in Multiple Places" Test
识别方式:「多位置变更」测试
If fixing a bug requires changing multiple locations, you have duplication:
typescript
// ❌ Bug in tax calculation requires changes in 3 files
// cart.ts: const tax = price * 0.08;
// checkout.ts: const tax = price * 0.08;
// invoice.ts: const tax = price * 0.08;
// ✅ Single source of truth
// tax.ts: export const calculateTax = (price: number) => price * TAX_RATE;如果修复一个bug需要修改多个位置,说明你存在代码重复:
typescript
// ❌ 税费计算的bug需要修改3个文件
// cart.ts: const tax = price * 0.08;
// checkout.ts: const tax = price * 0.08;
// invoice.ts: const tax = price * 0.08;
// ✅ 正确:单一可信源
// tax.ts: export const calculateTax = (price: number) => price * TAX_RATE;The Correct Pattern: Extract and Parameterize
正确模式:抽离+参数化
When code is "almost the same", extract the common part and parameterize the differences:
typescript
// ❌ VIOLATION: Similar functions with minor differences
function formatUserName(user: User): string {
return `${user.firstName} ${user.lastName}`;
}
function formatAdminName(admin: Admin): string {
return `${admin.firstName} ${admin.lastName} (Admin)`;
}
// ✅ CORRECT: Parameterized
function formatName(person: { firstName: string; lastName: string }, suffix?: string): string {
const name = `${person.firstName} ${person.lastName}`;
return suffix ? `${name} (${suffix})` : name;
}当代码「几乎一致」时,抽离公共部分,把差异点参数化:
typescript
// ❌ 违规:只有细微差别的相似函数
function formatUserName(user: User): string {
return `${user.firstName} ${user.lastName}`;
}
function formatAdminName(admin: Admin): string {
return `${admin.firstName} ${admin.lastName} (Admin)`;
}
// ✅ 正确:参数化处理
function formatName(person: { firstName: string; lastName: string }, suffix?: string): string {
const name = `${person.firstName} ${person.lastName}`;
return suffix ? `${name} (${suffix})` : name;
}Pressure Resistance Protocol
压力应对准则
1. "It's Faster to Copy"
1. 「复制更快」
Pressure: "I'll just copy this and modify it"
Response: Copying creates two places to maintain. Bugs will diverge.
Action: Extract shared logic first, then use it in both places.
压力来源:「我直接复制过来改改就行」
回应: 复制会产生两个需要维护的位置,两个地方的bug会逐渐分化。
行动: 先抽离公共逻辑,再在两个地方调用。
2. "They're Slightly Different"
2. 「它们只有细微差别」
Pressure: "The functions are almost the same but not quite"
Response: "Almost the same" = extract common part, parameterize differences.
Action: Identify what's shared, extract it, make differences parameters.
压力来源:「这些函数几乎一样但又不完全一样」
回应:「几乎一样」= 抽离公共部分,把差异点参数化。
行动: 识别共享逻辑,抽离出来,把差异作为参数处理。
3. "It's Just a Few Lines"
3. 「只有几行代码而已」
Pressure: "It's only 3 lines, not worth extracting"
Response: 3 lines duplicated 5 times = 15 lines to maintain. Bugs multiply.
Action: Extract even small duplications. Name them well.
压力来源:「只有3行代码,不值得抽离」
回应: 3行代码重复5次 = 15行需要维护的代码,bug会成倍增长。
行动: 哪怕是很小的重复也要抽离,给它起个合适的名字。
4. "I'll Refactor Later"
4. 「我之后再重构」
Pressure: "Ship now, DRY it up later"
Response: You won't. Duplication spreads. DRY now takes 2 minutes.
Action: Extract before committing the duplication.
压力来源:「先上线,之后再做DRY优化」
回应: 你不会做的,重复会越来越多,现在做DRY只需要2分钟。
行动: 在提交重复代码之前先抽离。
Red Flags - STOP and Reconsider
危险信号 - 停下来重新思考
If you notice ANY of these, you're about to violate DRY:
- Ctrl+C / Ctrl+V in your workflow
- "This is similar to that other function"
- Same regex/validation in multiple places
- Identical error handling patterns repeated
- Same data transformation logic duplicated
- Constants defined in multiple files
All of these mean: Extract to a shared location.
如果你发现以下任何一种情况,说明你即将违反DRY原则:
- 工作流中用到了Ctrl+C / Ctrl+V
- 「这段代码和另一个函数很像」
- 多个位置用到了相同的正则/校验逻辑
- 重复出现相同的错误处理模式
- 重复出现相同的数据转换逻辑
- 多个文件中定义了相同的常量
以上所有情况都意味着:你需要把逻辑抽离到公共位置。
Types of Duplication
重复的类型
| Type | Example | Solution |
|---|---|---|
| Code | Same function body twice | Extract function |
| Logic | Same algorithm, different names | Extract and parameterize |
| Data | Same constant in multiple files | Centralize constants |
| Structure | Same class shape repeated | Extract interface/base |
| Knowledge | Business rule in multiple places | Single source of truth |
| 类型 | 示例 | 解决方案 |
|---|---|---|
| 代码 | 相同的函数体出现两次 | 抽离为公共函数 |
| 逻辑 | 相同的算法,不同的命名 | 抽离后参数化 |
| 数据 | 多个文件中存在相同的常量 | 集中管理常量 |
| 结构 | 重复出现相同的类结构 | 抽离interface/基类 |
| 知识 | 多个位置存在相同的业务规则 | 维护单一可信源 |
Quick Reference
快速参考
| Symptom | Action |
|---|---|
| Copy-pasting code | Extract shared function |
| Same validation twice | Create validator module |
| Same constant in files | Create constants file |
| Similar functions | Extract + parameterize |
| Bug fix needs multiple changes | Consolidate to one place |
| 现象 | 行动 |
|---|---|
| 复制粘贴代码 | 抽离公共函数 |
| 相同的校验逻辑出现两次 | 创建校验器模块 |
| 多个文件存在相同常量 | 创建常量管理文件 |
| 功能相似的函数 | 抽离+参数化 |
| 修复bug需要修改多个位置 | 把逻辑整合到一处 |
Common Rationalizations (All Invalid)
常见的不合理借口
| Excuse | Reality |
|---|---|
| "It's faster to copy" | It's slower to maintain duplicates. |
| "They're slightly different" | Extract common, parameterize differences. |
| "Just a few lines" | Few lines × many places = many bugs. |
| "I'll refactor later" | You won't. Extract now. |
| "Different contexts" | Same logic = same code, regardless of context. |
| "More readable as copies" | Named, extracted functions are more readable. |
| 借口 | 现实 |
|---|---|
| 「复制更快」 | 维护重复代码的成本更高 |
| 「它们只有细微差别」 | 抽离公共逻辑,参数化差异点 |
| 「只有几行代码而已」 | 少量代码 × 多处重复 = 大量bug |
| 「我之后再重构」 | 你不会的,现在就抽离 |
| 「上下文不同」 | 相同的逻辑就该用相同的代码,和上下文无关 |
| 「复制的代码可读性更高」 | 命名清晰、抽离出来的函数可读性更高 |
The Bottom Line
核心准则
One piece of knowledge. One place in code.
When writing similar code: stop, find the existing code, extract if needed, reuse. Duplication is the root of maintenance nightmares.
一项知识,代码中只存在一处。
编写相似代码时:停下来,找到已有代码,必要时抽离,再复用。代码重复是维护噩梦的根源。