clean-code
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseClean Code
Clean Code
Principles for transforming "code that works" into "code that is clean" — code
that can be read, understood, and enhanced by any developer.
"Code is clean if it can be understood easily — by everyone on the team." — Dave Thomas
本指南提供将「能运行的代码」转化为「整洁代码」的原则——这类代码可以被任何开发人员阅读、理解和改进。
「如果团队中的每个人都能轻松理解,那这段代码就是整洁的。」—— Dave Thomas
When to Apply
适用场景
Reference these guidelines when:
- Writing new code and choosing names, function signatures, structure
- Reviewing pull requests for readability and maintainability
- Refactoring legacy code or reducing complexity
- Identifying and fixing code smells
- Improving team code standards
在以下场景中可参考本指南:
- 编写新代码时,确定命名、函数签名与结构
- 评审拉取请求,检查代码的可读性与可维护性
- 重构遗留代码或降低代码复杂度
- 识别并修复代码坏味道
- 完善团队代码规范
Rule Categories
规则分类
| Priority | Category | Impact |
|---|---|---|
| 1 | Naming | HIGH — affects every line of code |
| 2 | Functions | HIGH — core unit of abstraction |
| 3 | Code Smells | HIGH — early detection prevents rot |
| 4 | Formatting | MEDIUM — readability at a glance |
| 5 | Error Handling | MEDIUM — robustness and clarity |
| 6 | Comments | MEDIUM — most are avoidable |
| 7 | Object Calisthenics | ASPIRATIONAL — exercises for better OO design |
| 优先级 | 类别 | 影响程度 |
|---|---|---|
| 1 | 命名 | 高影响 — 影响每一行代码 |
| 2 | 函数 | 高影响 — 抽象的核心单元 |
| 3 | 代码坏味道 | 高影响 — 早期检测可防止代码腐化 |
| 4 | 格式规范 | 中影响 — 一眼可见的可读性 |
| 5 | 错误处理 | 中影响 — 健壮性与清晰度 |
| 6 | 注释 | 中影响 — 大多数注释可避免 |
| 7 | Object Calisthenics | 进阶目标 — 优化面向对象设计的练习 |
1. Naming
1. 命名
Good names are the single most impactful thing you can do for readability.
Priority order:
- Consistency — same concept = same name everywhere
- Intent-revealing — name says what it does, not how
- Specific — avoid vague names like ,
data,info,manager,handlerutils - Searchable — unique enough to grep
- Brief — short but not cryptic
typescript
// Bad
const d = new Date();
const arr = users.filter((u) => u.a);
function process(data: any) {}
// Good
const createdAt = new Date();
const activeUsers = users.filter((user) => user.isActive);
function validatePayment(payment: Payment) {}Conventions:
- Classes/types: nouns (,
Customer). AvoidOrderRepository,Manager,Data.Info - Methods/functions: verbs (,
createOrder,validateEmail)isEligible - Booleans: question form (,
isActive,hasPermission)canWithdraw - Collections: plural nouns (,
users)orderItems
See for full guidelines.
references/NAMING.md好的命名是提升代码可读性最有效的手段。
优先级顺序:
- 一致性 — 同一概念在所有地方使用相同名称
- 传达意图 — 名称说明用途,而非实现方式
- 具体明确 — 避免模糊的名称,如、
data、info、manager、handlerutils - 便于搜索 — 名称足够独特,可通过grep查找
- 简洁精炼 — 简短但不晦涩
typescript
// 不好的写法
const d = new Date();
const arr = users.filter((u) => u.a);
function process(data: any) {}
// 好的写法
const createdAt = new Date();
const activeUsers = users.filter((user) => user.isActive);
function validatePayment(payment: Payment) {}命名约定:
- 类/类型:使用名词(、
Customer)。避免使用OrderRepository、Manager、Data。Info - 方法/函数:使用动词(、
createOrder、validateEmail)isEligible - 布尔值:使用疑问形式(、
isActive、hasPermission)canWithdraw - 集合:使用复数名词(、
users)orderItems
完整指南请参考。
references/NAMING.md2. Functions
2. 函数
typescript
// Bad — does too many things, unclear name
function handle(order: Order, sendEmail: boolean, log: boolean) {
// validate, calculate, save, email, log — all in one
}
// Good — small, single-purpose, descriptive
function validateOrder(order: Order): ValidationResult { ... }
function calculateTotal(items: OrderItem[]): Money { ... }
function saveOrder(order: Order): Promise<void> { ... }Rules:
- Small — strive for under 20 lines
- Do one thing — if you use "and" to describe it, split it
- One level of abstraction — don't mix business logic with low-level details
- Few arguments — 0-2 ideal, 3+ warrants a parameter object
- No side effects — or name them explicitly (, not
saveAndNotify)save - Command/Query separation — a function either does something or returns something, not both
typescript
// 不好的写法 — 职责过多,名称模糊
function handle(order: Order, sendEmail: boolean, log: boolean) {
// 验证、计算、保存、发送邮件、记录日志 — 全部放在一个函数里
}
// 好的写法 — 小巧、单一职责、描述清晰
function validateOrder(order: Order): ValidationResult { ... }
function calculateTotal(items: OrderItem[]): Money { ... }
function saveOrder(order: Order): Promise<void> { ... }规则:
- 小巧 — 尽量控制在20行以内
- 单一职责 — 如果描述时需要用「和」,就拆分函数
- 单一抽象层级 — 不要混合业务逻辑与底层细节
- 参数少 — 0-2个参数为最佳,3个及以上建议使用参数对象
- 无副作用 — 如有副作用需在名称中明确体现(如,而非
saveAndNotify)save - 命令/查询分离 — 函数要么执行操作,要么返回结果,不可两者兼具
3. Code Smells
3. 代码坏味道
Indicators that code may need refactoring. Not bugs, but design friction.
| Smell | Symptom | Quick Fix |
|---|---|---|
| Long Method | > 20 lines, multiple concerns | Extract methods |
| Large Class | Many responsibilities | Extract class (SRP) |
| Long Parameter List | > 3 parameters | Introduce parameter object |
| Primitive Obsession | Strings/numbers for domain concepts | Wrap in value objects |
| Feature Envy | Method uses another class's data more than its own | Move method |
| Data Clumps | Same group of fields appear together | Extract class |
| Switch Statements | Type-checking switch/if-else across codebase | Replace with polymorphism |
| Divergent Change | One class changed for many reasons | Split by responsibility |
| Shotgun Surgery | One change touches many files | Move related code together |
| Speculative Generality | "Just in case" abstractions | Delete (YAGNI) |
| Dead Code | Unreachable or unused code | Delete |
| Message Chains | | Hide delegate (Law of Demeter) |
See for detailed examples and refactoring strategies.
references/CODE_SMELLS.md代码坏味道是代码需要重构的信号,并非bug,但会增加设计阻力。
| 代码坏味道 | 表现特征 | 快速修复方案 |
|---|---|---|
| 过长方法 | 超过20行,包含多个职责 | 提取方法 |
| 过大类 | 承担多个职责 | 提取类(单一职责原则) |
| 过长参数列表 | 参数数量超过3个 | 引入参数对象 |
| 基本类型偏执 | 使用字符串/数字表示领域概念 | 封装为值对象 |
| 特性依恋 | 方法使用其他类的数据远多于自身类的数据 | 移动方法 |
| 数据泥团 | 同一组字段反复一起出现 | 提取类 |
| 分支语句泛滥 | 代码库中大量存在基于类型检查的switch/if-else | 用多态替代 |
| 发散式变化 | 一个类因多种原因被修改 | 按职责拆分类 |
| 霰弹式修改 | 一次修改需要改动多个文件 | 将相关代码整合到一起 |
| 臆想性通用性 | 为「以防万一」添加的抽象 | 删除(你不会需要它原则YAGNI) |
| 死代码 | 无法到达或未被使用的代码 | 删除 |
| 消息链 | | 隐藏委托(迪米特法则) |
详细示例与重构策略请参考。
references/CODE_SMELLS.md4. Formatting
4. 格式规范
The Newspaper Metaphor — code should read top-to-bottom like a newspaper
article. High-level summary at the top, details below.
typescript
class OrderProcessor {
// Public API first — the "headline"
process(order: Order): ProcessResult {
this.validate(order);
const total = this.calculateTotal(order);
return this.save(order, total);
}
// Supporting methods below, in order of appearance
private validate(order: Order) { ... }
private calculateTotal(order: Order): Money { ... }
private save(order: Order, total: Money): ProcessResult { ... }
}Rules:
- Related code stays close together (vertical density)
- Blank lines between concepts (vertical openness)
- Variables declared near their usage
- Caller above callee (stepdown rule)
- Consistent indentation — non-negotiable
报纸隐喻 — 代码应像报纸一样从上到下阅读,顶部是高层摘要,下方是细节。
typescript
class OrderProcessor {
// 先放公共API — 相当于「标题」
process(order: Order): ProcessResult {
this.validate(order);
const total = this.calculateTotal(order);
return this.save(order, total);
}
// 下方是支撑方法,按出现顺序排列
private validate(order: Order) { ... }
private calculateTotal(order: Order): Money { ... }
private save(order: Order, total: Money): ProcessResult { ... }
}规则:
- 相关代码放在一起(垂直密度)
- 不同概念之间用空行分隔(垂直留白)
- 变量声明在使用位置附近
- 调用方在被调用方上方(向下规则)
- 一致的缩进 — 必须严格遵守
5. Error Handling
5. 错误处理
- Exceptions over error codes — keeps happy path clean
- Don't return — use
null,undefinedtypes, or throwResult - Don't pass — leads to defensive checks everywhere
null - Fail fast — validate at boundaries, trust internals
- Specific exceptions — over generic
InsufficientFundsErrorError
typescript
// Bad — null checks cascade through codebase
function getUser(id: string): User | null {
return db.find(id);
}
const user = getUser(id);
if (user === null) { ... } // Every caller must check
// Good — throw at boundary, trust within domain
function getUser(id: string): User {
const user = db.find(id);
if (!user) throw new UserNotFoundError(id);
return user;
}- 优先使用异常而非错误码 — 保持主逻辑清晰
- 不要返回— 使用
null、undefined类型或抛出异常Result - 不要传递— 会导致到处都是防御性检查
null - 快速失败 — 在边界处验证,内部逻辑可信任
- 使用具体异常 — 用替代通用的
InsufficientFundsErrorError
typescript
// 不好的写法 — null检查在代码库中层层蔓延
function getUser(id: string): User | null {
return db.find(id);
}
const user = getUser(id);
if (user === null) { ... } // 每个调用者都必须检查
// 好的写法 — 在边界处抛出异常,领域内部可信任
function getUser(id: string): User {
const user = db.find(id);
if (!user) throw new UserNotFoundError(id);
return user;
}6. Comments
6. 注释
"Don't comment bad code — rewrite it."
Most comments compensate for failure to express intent in code. Prefer
self-documenting code over comments.
Good comments:
- Why something is done (business reason, non-obvious decision)
- Warnings ("this is slow because X", "order matters here")
- TODOs with context (link to issue)
- Legal/license headers
- Public API docs (JSDoc for libraries)
Bad comments:
- Restating what the code does ()
// increment counter - Commented-out code (that's what git is for)
- Journal/changelog comments
- Noise (,
// constructor)// getters - Mandated boilerplate
typescript
// Bad — restates the obvious
// Check if user is active
if (user.isActive) { ... }
// Good — explains a non-obvious business rule
// Users who haven't verified email within 30 days are auto-deactivated
// per compliance requirement GDPR-2024-42
if (user.isAutoDeactivated) { ... }「不要给糟糕的代码加注释——重写它。」
大多数注释是为了弥补代码无法传达意图的缺陷。优先使用自文档化代码,而非注释。
好的注释:
- 原因 — 说明为什么这么做(业务规则、非显而易见的决策)
- 警告 — (如「此处因X原因运行缓慢」、「顺序很重要」)
- 待办事项 — 附带上下文(关联到问题链接)
- 法律/许可证 头部
- 公共API文档 — (库的JSDoc注释)
坏的注释:
- 重复代码的功能(如)
// 递增计数器 - 被注释掉的代码(用git记录历史即可)
- 日志/变更记录注释
- 无意义的注释(如、
// 构造函数)// getter方法 - 强制要求的模板注释
typescript
// 不好的写法 — 重复显而易见的内容
// 检查用户是否活跃
if (user.isActive) { ... }
// 好的写法 — 解释非显而易见的业务规则
// 根据合规要求GDPR-2024-42,30天内未验证邮箱的用户会被自动停用
if (user.isAutoDeactivated) { ... }7. Object Calisthenics
7. Object Calisthenics
Nine exercises from Jeff Bay to improve OO design. Treat these as aspirational
targets — strict during practice, pragmatic in production.
| # | Rule | Goal |
|---|---|---|
| 1 | One level of indentation per method | Extract methods aggressively |
| 2 | Don't use | Early returns, guard clauses, polymorphism |
| 3 | Wrap all primitives with domain meaning | Value objects ( |
| 4 | First-class collections | Wrap arrays in domain-specific classes |
| 5 | One dot per line | Law of Demeter — talk to friends only |
| 6 | Don't abbreviate | If the name is too long, the class does too much |
| 7 | Keep entities small | Classes < 50 lines, methods < 10 lines |
| 8 | Limit instance variables | Strive for 2-3; forces focused classes |
| 9 | No getters/setters | Objects have behavior, not just data |
See for examples of each rule.
references/OBJECT_CALISTHENICS.md这是Jeff Bay提出的9项练习,用于优化面向对象设计。将这些视为进阶目标——练习时严格遵守,生产环境中灵活运用。
| 编号 | 规则 | 目标 |
|---|---|---|
| 1 | 每个方法只允许一层缩进 | 积极提取方法 |
| 2 | 不要使用 | 使用提前返回、守卫子句、多态 |
| 3 | 封装所有具有领域意义的基本类型 | 使用值对象( |
| 4 | 一等集合 | 将数组封装为领域特定类 |
| 5 | 每行最多一个点 | 迪米特法则——只和朋友对话 |
| 6 | 不要缩写 | 如果名称太长,说明类的职责过多 |
| 7 | 保持实体小巧 | 类少于50行,方法少于10行 |
| 8 | 限制实例变量数量 | 尽量控制在2-3个;促使类职责聚焦 |
| 9 | 不要使用getter/setter | 对象应具备行为,而非仅存储数据 |
每个规则的示例请参考。
references/OBJECT_CALISTHENICS.mdImplementation Checklist
实施检查清单
Before submitting code:
- Can a new team member understand this without asking questions?
- Are names intention-revealing and consistent?
- Does each function do exactly one thing?
- Are there any code smells I can fix while I'm here?
- Are comments explaining why, not what?
- Is error handling clean and specific?
- Did I leave the code better than I found it? (Boy Scout Rule)
提交代码前,请确认:
- 新团队成员无需提问就能理解这段代码吗?
- 命名是否能清晰传达意图且保持一致?
- 每个函数是否只负责一件事?
- 我能否顺便修复一些代码坏味道?
- 注释是否在解释「为什么」而非「是什么」?
- 错误处理是否简洁且明确?
- 我是否让代码比我接手时更优秀?(童子军规则)