dont-repeat-yourself

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

DRY (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

重复的类型

TypeExampleSolution
CodeSame function body twiceExtract function
LogicSame algorithm, different namesExtract and parameterize
DataSame constant in multiple filesCentralize constants
StructureSame class shape repeatedExtract interface/base
KnowledgeBusiness rule in multiple placesSingle source of truth
类型示例解决方案
代码相同的函数体出现两次抽离为公共函数
逻辑相同的算法,不同的命名抽离后参数化
数据多个文件中存在相同的常量集中管理常量
结构重复出现相同的类结构抽离interface/基类
知识多个位置存在相同的业务规则维护单一可信源

Quick Reference

快速参考

SymptomAction
Copy-pasting codeExtract shared function
Same validation twiceCreate validator module
Same constant in filesCreate constants file
Similar functionsExtract + parameterize
Bug fix needs multiple changesConsolidate to one place
现象行动
复制粘贴代码抽离公共函数
相同的校验逻辑出现两次创建校验器模块
多个文件存在相同常量创建常量管理文件
功能相似的函数抽离+参数化
修复bug需要修改多个位置把逻辑整合到一处

Common Rationalizations (All Invalid)

常见的不合理借口

ExcuseReality
"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.
一项知识,代码中只存在一处。
编写相似代码时:停下来,找到已有代码,必要时抽离,再复用。代码重复是维护噩梦的根源。