clean-code

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Clean Code

代码整洁之道

Overview

概述

Clean code reads like well-written prose. Every name reveals intent. Every function tells a story. Every class has a single purpose. The goal isn't just working code—it's code that others can understand quickly, modify safely, and extend confidently.
"Clean code always looks like it was written by someone who cares." — Michael Feathers
"You know you are working on clean code when each routine turns out to be pretty much what you expected." — Ward Cunningham
The Boy Scout Rule: Leave the code cleaner than you found it. Every commit should improve quality, even if just slightly. Small improvements compound.
整洁的代码读起来就像文笔流畅的散文。每个命名都清晰传达意图,每个函数都讲着完整的故事,每个类都有单一职责。我们的目标不只是让代码能运行,更是要让他人能快速理解、安全修改、自信扩展。
“整洁的代码总是看起来出自用心之人之手。”——Michael Feathers
“当你发现每个程序单元都和你预期的差不多时,你就是在和整洁代码打交道。”——Ward Cunningham
童子军规则: 让代码比你接手时更整洁。每次提交都要提升代码质量,哪怕只是微小的改进。小进步会不断积累。

Chapter References

章节参考

This skill provides an overview with quick references. For detailed guidance with examples, see the chapter files:
  • chapters/names.md
    - Meaningful Names (intention-revealing, searchable, pronounceable)
  • chapters/functions.md
    - Functions (small, do one thing, few arguments)
  • chapters/comments.md
    - Comments (why to avoid, what's acceptable)
  • chapters/objects-and-data.md
    - Objects and Data Structures (Law of Demeter, DTOs)
  • chapters/error-handling.md
    - Error Handling (exceptions, null handling, Special Case Pattern)
  • chapters/tests.md
    - Unit Tests (TDD, F.I.R.S.T., clean tests)
  • chapters/classes.md
    - Classes (SRP, cohesion, OCP, DIP)
  • smells-and-heuristics.md
    - Complete code smells reference (66 smells with explanations)
本内容提供了快速参考概览。如需带示例的详细指导,请查看章节文件:
  • chapters/names.md
    - 有意义的命名(传达意图、便于搜索、可读可发音)
  • chapters/functions.md
    - 函数设计(短小、单一职责、参数精简)
  • chapters/comments.md
    - 注释规范(应避免的类型、可接受的场景)
  • chapters/objects-and-data.md
    - 对象与数据结构(迪米特法则、DTO)
  • chapters/error-handling.md
    - 错误处理(异常、空值处理、特殊用例模式)
  • chapters/tests.md
    - 单元测试(TDD、F.I.R.S.T.原则、整洁测试)
  • chapters/classes.md
    - 类设计(SRP、内聚性、OCP、DIP)
  • smells-and-heuristics.md
    - 完整代码坏味道参考(66种坏味道及解释)

Quick Reference: Names

快速参考:命名

Names should reveal intent and be searchable.
RuleBadGood
Reveal intent
d
elapsedTimeInDays
Avoid disinformation
accountList
(not a List)
accounts
Make distinctions
a1, a2
source, destination
Pronounceable
genymdhms
generationTimestamp
Searchable
7
MAX_CLASSES_PER_STUDENT
Classes = nouns
Process
Customer
,
Account
Methods = verbs
data
postPayment()
,
save()
Avoid:
Manager
,
Processor
,
Data
,
Info
in class names—they hint at unclear responsibilities.
Key insight: If you need a comment to explain what a variable is, rename it instead.
命名应清晰传达意图且便于搜索。
规则反面示例正面示例
传达意图
d
elapsedTimeInDays
避免误导
accountList
(实际不是List)
accounts
明确区分
a1, a2
source, destination
可读可发音
genymdhms
generationTimestamp
便于搜索
7
MAX_CLASSES_PER_STUDENT
类名用名词
Process
Customer
,
Account
方法名用动词
data
postPayment()
,
save()
应避免: 类名中使用
Manager
Processor
Data
Info
——这些词暗示职责不清晰。
核心见解: 如果你需要用注释解释变量含义,不如直接重命名它。

Quick Reference: Functions

快速参考:函数

Size and Scope

大小与范围

  • Ideal: 4-10 lines, rarely over 20
  • Indent level: Never more than one or two
  • Do one thing — if you can extract another function with a non-restating name, it's doing too much
  • 理想长度: 4-10行,极少超过20行
  • 缩进层级: 不超过1-2层
  • 单一职责 —— 如果你能提取出另一个名称不重复的函数,说明原函数职责过多

Arguments

参数数量

CountGuidance
0Best
1Good
2Acceptable
3+Avoid—wrap in object
Flag arguments (booleans) are ugly. They proclaim the function does two things. Split it:
python
undefined
数量指导原则
0最佳
1良好
2可接受
3+应避免——封装为对象
标记参数(布尔值)很糟糕,它表明函数在做两件事。应拆分函数:
python
undefined

Bad

反面示例

def render(is_suite: bool): ...
def render(is_suite: bool): ...

Good

正面示例

def render_for_suite(): ... def render_for_single_test(): ...
undefined
def render_for_suite(): ... def render_for_single_test(): ...
undefined

Key Rules

核心规则

  • Command Query Separation: Do something OR answer something, not both
  • No side effects: If
    checkPassword()
    also initializes a session, it lies
  • Prefer exceptions to error codes: Separates happy path from error handling
  • Extract try/catch blocks: Error handling is one thing
  • 命令查询分离: 要么执行操作,要么返回结果,不可两者兼具
  • 无副作用: 如果
    checkPassword()
    同时初始化会话,这是一种“欺骗”
  • 优先使用异常而非错误码: 将主逻辑与错误处理分离
  • 提取try/catch块: 错误处理是单一职责

Quick Reference: Comments

快速参考:注释

Comments are, at best, a necessary evil. The proper use of comments is to compensate for our failure to express ourselves in code.
注释充其量是必要的恶。注释的恰当用途是弥补我们无法用代码清晰表达的不足。

Delete These Comments

应删除的注释

  • Redundant — restating what code says
  • Journal/changelog — use git
  • Commented-out code — an abomination, git remembers
  • Noise
    // default constructor
    ,
    // increment i
  • Closing brace
    } // end if
    means too much nesting
  • 冗余注释 —— 重复代码已表达的内容
  • 日志/变更记录 —— 用git记录
  • 被注释掉的代码 —— 这是糟粕,git会保留历史版本
  • 无意义注释 ——
    // 默认构造函数
    // 递增i
  • 闭合括号注释 ——
    } // end if
    意味着嵌套层级过深

Acceptable Comments

可接受的注释

  • Legal notices
  • Explanation of intent (why, not what)
  • Warning of consequences (
    // takes 30 minutes
    )
  • TODO (but clean them up)
  • Clarifying external library behavior
The Rule: When you feel the urge to comment, first try to refactor the code so the comment would be unnecessary.
  • 法律声明
  • 意图解释(说明原因而非内容)
  • 后果警告(如
    // 执行需30分钟
  • TODO注释(但需及时清理)
  • 第三方库行为说明
规则: 当你想要写注释时,先尝试重构代码,让注释变得多余。

Quick Reference: Error Handling

快速参考:错误处理

Error handling is important, but if it obscures logic, it's wrong.
RuleDetails
Use exceptions over return codesSeparates algorithm from error handling
Provide contextInclude operation that failed and type of failure
Wrap third-party APIsMinimizes dependencies, enables mocking
Use Special Case PatternReturn object that handles special case (empty list, default values)
Don't return nullCreates work, invites NullPointerException
Don't pass nullWorse than returning null—forbid it by default
python
undefined
错误处理很重要,但如果它掩盖了核心逻辑,那就是错误的实现方式。
规则细节说明
优先使用异常而非返回码将算法与错误处理分离
提供上下文信息包含失败的操作及失败类型
封装第三方API减少依赖,便于Mock测试
使用特殊用例模式返回处理特殊场景的对象(如空列表、默认值)
不要返回null增加额外工作,易引发NullPointerException
不要传递null比返回null更糟——默认禁止传递null
python
undefined

Bad - null checks everywhere

反面示例——到处做空值检查

if employees is not None: for e in employees: total += e.pay
if employees is not None: for e in employees: total += e.pay

Good - return empty collection instead of null

正面示例——返回空集合而非null

for e in get_employees(): # Returns [] if none total += e.pay
undefined
for e in get_employees(): # 无数据时返回[] total += e.pay
undefined

Quick Reference: Classes

快速参考:类

Single Responsibility Principle (SRP)

单一职责原则(SRP)

A class should have one, and only one, reason to change.
Tests:
  • Can you derive a concise name? (Avoid
    Manager
    ,
    Processor
    ,
    Super
    )
  • Can you describe it in 25 words without "if," "and," "or," "but"?
一个类应该有且仅有一个发生变化的原因。
检验方法:
  • 能否为类起一个简洁明确的名称?(避免
    Manager
    Processor
    Super
    这类模糊名称)
  • 能否用25个单词以内描述类的职责,且不使用“if”、“and”、“or”、“but”?

Cohesion

内聚性

Methods should use the class's instance variables. When methods cluster around certain variables but not others, the class should be split.
类的方法应使用类的实例变量。当方法仅围绕部分变量而非全部变量时,应拆分该类。

Open-Closed Principle (OCP)

开闭原则(OCP)

Classes should be open for extension but closed for modification. Add new behavior via subclassing, not modifying existing code.
类应对扩展开放,对修改关闭。通过子类添加新行为,而非修改现有代码。

Dependency Inversion Principle (DIP)

依赖倒置原则(DIP)

Depend on abstractions, not concrete details. Inject dependencies for testability.
python
undefined
依赖抽象而非具体实现。通过依赖注入提升可测试性。
python
undefined

Bad - can't test without network

反面示例——无法脱离网络环境测试

class Portfolio: def init(self): self.exchange = TokyoStockExchange()
class Portfolio: def init(self): self.exchange = TokyoStockExchange()

Good - injectable, testable

正面示例——可注入依赖,便于测试

class Portfolio: def init(self, exchange: StockExchange): self.exchange = exchange
undefined
class Portfolio: def init(self, exchange: StockExchange): self.exchange = exchange
undefined

Quick Reference: Tests

快速参考:测试

The Three Laws of TDD

TDD三定律

  1. Don't write production code until you have a failing test
  2. Don't write more test than sufficient to fail
  3. Don't write more production code than sufficient to pass
  1. 除非有一个失败的测试,否则不编写生产代码
  2. 不编写超出当前失败所需的测试代码
  3. 不编写超出通过当前测试所需的生产代码

F.I.R.S.T. Principles

F.I.R.S.T.原则

  • Fast — Run quickly so you run them often
  • Independent — Don't depend on each other
  • Repeatable — Same result in any environment
  • Self-Validating — Boolean output (pass/fail)
  • Timely — Written just before production code
  • Fast(快速) —— 运行速度快,便于频繁执行
  • Independent(独立) —— 测试用例之间互不依赖
  • Repeatable(可重复) —— 在任何环境下都能得到相同结果
  • Self-Validating(自验证) —— 输出布尔结果(通过/失败)
  • Timely(及时) —— 编写生产代码前先写测试

Clean Tests

整洁测试

  • Readability is paramount
  • Use BUILD-OPERATE-CHECK pattern
  • Create domain-specific testing language
  • One concept per test (not necessarily one assert)
Warning: Test code is just as important as production code. If you let tests rot, your code will rot too.
  • 可读性 是首要原则
  • 使用 BUILD-OPERATE-CHECK(构建-操作-验证) 模式
  • 构建领域特定测试语言
  • 每个测试对应一个概念(不一定是一个断言)
警告: 测试代码和生产代码同等重要。如果测试代码腐化,生产代码也会跟着腐化。

Objects vs Data Structures

对象 vs 数据结构

ConceptHidesExposesEasy to add...
ObjectsDataFunctionsNew types
Data StructuresNothingDataNew functions
The idea that everything is an object is a myth. Sometimes you want simple data structures with procedures operating on them.
概念隐藏暴露易于添加...
对象数据函数新类型
数据结构数据新函数
“万物皆对象”是误区。 有时你只需要简单的数据结构,以及操作它们的过程。

Law of Demeter

迪米特法则

A method should only call methods of:
  • The class itself
  • Objects it creates
  • Objects passed as arguments
  • Objects held in instance variables
Don't call methods on objects returned by allowed functions (train wrecks):
python
undefined
方法只能调用以下对象的方法:
  • 类自身
  • 方法创建的对象
  • 方法参数传入的对象
  • 类实例变量持有的对象
不要 调用允许调用的函数返回的对象的方法(链式调用的“火车失事”):
python
undefined

Bad

反面示例

output_dir = ctxt.get_options().get_scratch_dir().get_absolute_path()
output_dir = ctxt.get_options().get_scratch_dir().get_absolute_path()

Good - tell the object to do the work

正面示例——告诉对象去完成工作

bos = ctxt.create_scratch_file_stream(class_file_name)
undefined
bos = ctxt.create_scratch_file_stream(class_file_name)
undefined

The Most Critical Smells

最关键的代码坏味道

From Chapter 17's comprehensive list, these are the most important:
来自第17章的完整列表中,以下是最重要的几项:

G5: Duplication

G5: 重复代码

The root of all evil in software. Every duplication is a missed abstraction opportunity:
  • Identical code → extract to function
  • Repeated switch/if-else → polymorphism
  • Similar algorithms → Template Method or Strategy pattern
这是软件领域万恶之源。 每一处重复都是错失的抽象机会:
  • 完全相同的代码 → 提取为函数
  • 重复的switch/if-else → 用多态替代
  • 相似的算法 → 使用模板方法或策略模式

G30: Functions Should Do One Thing

G30: 函数应单一职责

If you can extract another function from it, the original was doing more than one thing.
如果你能从函数中提取出另一个函数,说明原函数职责过多。

N1: Choose Descriptive Names

N1: 选择有意义的命名

Names are 90% of what makes code readable. Take time to choose wisely.
命名决定了代码可读性的90%。花时间选一个好名字。

F1: Too Many Arguments

F1: 参数过多

Zero is best, then one, two, three. More requires justification.
零参数最佳,其次是1个、2个、3个。更多参数需要合理的理由。

F3: Flag Arguments

F3: 标记参数

Boolean parameters mean the function does two things. Split it.
布尔参数意味着函数在做两件事。应拆分函数。

G9: Dead Code

G9: 死代码

Code that isn't executed. Delete it—version control remembers.
未被执行的代码。删除它——版本控制系统会保留历史。

G11: Inconsistency

G11: 不一致性

If you do something one way, do all similar things the same way.
如果一件事用某种方式处理,所有类似的事都应采用相同方式。

C5: Commented-Out Code

C5: 被注释掉的代码

An abomination. Delete it immediately.
这是糟粕。立即删除它。

The Craft

匠艺精神

"Writing clean code requires the disciplined use of a myriad little techniques applied through a painstakingly acquired sense of 'cleanliness.' The code-sense is the key."
Clean code isn't written by following rules mechanically. It comes from values that drive disciplines—caring about craft, respecting readers of your code, and taking pride in professional work.
How do you write clean code? First drafts are clumsy—long functions, nested loops, arbitrary names, duplication. You refine: break out functions, change names, eliminate duplication, shrink methods. Nobody writes clean code from the start.
Getting software to work and making it clean are different activities. Most of us have limited room in our heads, so we focus on getting code to work first. The problem is that too many of us think we are done once the program works. We fail to switch to organization and cleanliness. We move on to the next problem rather than going back and breaking overstuffed classes into decoupled units.
Don't. Go back. Clean it up. Leave it better than you found it.
“编写整洁代码需要自觉运用无数小技巧,而这些技巧来自于辛苦培养出的‘整洁感’。这种代码直觉是关键。”
整洁代码不是机械遵循规则就能写出来的。它源于驱动行为的价值观——重视匠艺、尊重代码的阅读者、为专业工作感到自豪。
如何编写整洁代码? 初稿往往笨拙——函数冗长、循环嵌套、命名随意、代码重复。你需要不断打磨:拆分函数、修改命名、消除重复、精简方法。没人能一开始就写出整洁的代码。
让软件运行起来和让软件整洁是两件不同的事。我们大多数人的思维容量有限,所以先专注于让代码运行。问题在于,太多人认为程序能运行就完工了。 我们没有切换到代码组织和整洁化的工作,而是去处理下一个问题,而非回头把臃肿的类拆分为解耦的单元。
别这么做。回头去整理。把代码清理干净。让它比你接手时更整洁。