clean-code
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseClean Code
整洁代码
Overview
概述
Apply clean code principles to produce readable, maintainable, and testable software. This skill covers SOLID principles, DRY application, code smell identification, refactoring patterns, naming conventions, error handling, and complexity management. Based on the works of Robert C. Martin, Martin Fowler, and Kent Beck.
Announce at start: "I'm using the clean-code skill to improve code quality."
应用整洁代码原则来构建可读性强、可维护、可测试的软件。本技能涵盖SOLID原则、DRY原则落地、代码异味识别、重构模式、命名规范、错误处理和复杂度管理,内容参考Robert C. Martin、Martin Fowler和Kent Beck的相关著作。
启动时声明: "我正在使用整洁代码技能来提升代码质量。"
Phase 1: Analyze Current Code
阶段1:分析现有代码
Goal: Read and understand the code in full context before changing anything.
目标: 在做任何改动前,完整通读并理解上下文内的全部代码。
Actions
操作步骤
- Read the code in its full context (not just the snippet)
- Identify the code's responsibility and purpose
- Measure cyclomatic complexity
- Map coupling and dependencies
- Note any existing tests
- 通读完整上下文内的所有代码(不只是代码片段)
- 明确代码的职责和用途
- 计算圈复杂度
- 梳理耦合关系和依赖项
- 记录所有已有的测试用例
STOP — Do NOT proceed to Phase 2 until:
停止条件 —— 满足以下要求前不要进入阶段2:
- Code is read in full context
- Purpose and responsibility are understood
- Complexity hotspots are identified
- Existing test coverage is known
- 已通读完整上下文的代码
- 已理解代码的用途和职责
- 已识别出复杂度热点
- 已明确现有测试覆盖范围
Phase 2: Identify Code Smells
阶段2:识别代码异味
Goal: Catalog all code smells using the reference tables below.
目标: 参考下方的参考表格整理所有代码异味。
Bloaters
臃肿类
| Smell | Detection | Refactoring |
|---|---|---|
| Long Method | > 30 lines | Extract Method |
| Large Class | > 300 lines or > 5 responsibilities | Extract Class |
| Long Parameter List | > 3 parameters | Introduce Parameter Object |
| Data Clumps | Same params appear together | Extract Class |
| Primitive Obsession | Primitives instead of small objects | Replace with Value Object |
| 异味类型 | 检测方式 | 重构方案 |
|---|---|---|
| 过长方法 | 超过30行 | 抽取方法 |
| 过大类 | 超过300行或承担超过5项职责 | 抽取类 |
| 过长参数列表 | 超过3个参数 | 引入参数对象 |
| 数据泥团 | 相同参数总是成对出现 | 抽取类 |
| 基本类型偏执 | 用基本类型替代小型对象 | 替换为值对象 |
Object-Orientation Abusers
面向对象滥用类
| Smell | Detection | Refactoring |
|---|---|---|
| Switch Statements | Switch on type | Replace with Polymorphism |
| Parallel Inheritance | Every subclass requires parallel subclass | Merge hierarchies |
| Refused Bequest | Subclass ignores inherited methods | Replace Inheritance with Delegation |
| 异味类型 | 检测方式 | 重构方案 |
|---|---|---|
| Switch语句 | 基于类型做Switch判断 | 替换为多态 |
| 并行继承 | 每个子类都需要对应创建并行的子类 | 合并继承层次 |
| 拒绝遗赠 | 子类忽略继承来的方法 | 用委托替代继承 |
Change Preventers
变更阻碍类
| Smell | Detection | Refactoring |
|---|---|---|
| Divergent Change | One class changed for multiple reasons | Extract Class (SRP) |
| Shotgun Surgery | One change touches many classes | Move Method, Inline Class |
| 异味类型 | 检测方式 | 重构方案 |
|---|---|---|
| 发散式变化 | 一个类会因多个不同原因被修改 | 抽取类(符合单一职责原则) |
| 霰弹式修改 | 一处改动需要修改多个类 | 移动方法、内联类 |
Dispensables
冗余类
| Smell | Detection | Refactoring |
|---|---|---|
| Dead Code | Unreachable or unused | Remove |
| Speculative Generality | Unused abstractions "just in case" | Collapse Hierarchy, Remove |
| Comments explaining bad code | Comments compensating for unclear code | Rename, Extract Method |
| 异味类型 | 检测方式 | 重构方案 |
|---|---|---|
| 死代码 | 不可达或从未被使用 | 移除 |
| 投机性泛化 | 为了"以防万一"添加的未使用抽象 | 折叠继承层次、移除 |
| 解释坏代码的注释 | 为了弥补代码不清晰而补充的注释 | 重命名、抽取方法 |
STOP — Do NOT proceed to Phase 3 until:
停止条件 —— 满足以下要求前不要进入阶段3:
- All code smells are cataloged
- Each smell has a priority (high/medium/low)
- Refactoring approach is identified for each
- 所有代码异味都已整理归档
- 每个异味都已标注优先级(高/中/低)
- 每个异味都已确定对应的重构方案
Phase 3: Apply Refactoring
阶段3:执行重构
Goal: Apply refactoring patterns one at a time, verifying tests after each.
目标: 逐一应用重构模式,每次改动后都验证测试用例。
Actions
操作步骤
- Apply ONE refactoring at a time
- Run tests after each change
- If any test fails, revert immediately
- Continue until code is clean
- Review naming, structure, and documentation
- 每次只执行一项重构操作
- 每次改动后都运行测试用例
- 如果有任何测试失败,立即回滚改动
- 持续迭代直到代码符合整洁标准
- 评审命名、结构和文档
STOP — Refactoring complete when:
停止条件 —— 满足以下要求时重构完成:
- All high-priority smells are resolved
- All tests pass after each change
- No behavior was changed during refactoring
- Code is readable to a new team member
- 所有高优先级异味都已解决
- 每次改动后所有测试都能通过
- 重构过程中没有修改任何原有业务行为
- 新团队成员也能轻松读懂代码
SOLID Principles
SOLID原则
S — Single Responsibility Principle
S — 单一职责原则
A class/module should have one, and only one, reason to change.
Smell: A class that changes for multiple unrelated reasons.
Fix: Extract responsibilities into separate classes.
一个类/模块应该有且只有一个变更的理由。
对应异味: 一个类会因多个不相关的原因被修改。
修复方案: 将不同职责拆分到独立的类中。
O — Open/Closed Principle
O — 开闭原则
Open for extension, closed for modification.
Smell: Switch statements that grow with new types.
Fix: Polymorphism, strategy pattern, or plugin architecture.
对扩展开放,对修改关闭。
对应异味: 随着新类型增加不断扩展的Switch语句。
修复方案: 多态、策略模式或插件架构。
L — Liskov Substitution Principle
L — 里氏替换原则
Subtypes must be substitutable for their base types.
Smell: Subclass overrides method to throw "not supported."
Fix: Restructure hierarchy; prefer composition over inheritance.
子类必须可以替换其基类使用。
对应异味: 子类重写方法后抛出"不支持"异常。
修复方案: 重构继承层次,优先使用组合而非继承。
I — Interface Segregation Principle
I — 接口隔离原则
No client should depend on methods it does not use.
Smell: Interfaces with many methods; implementors leave some as no-ops.
Fix: Split into smaller, focused interfaces.
任何客户端都不应该依赖它不需要的方法。
对应异味: 包含大量方法的接口,实现者需要将部分方法置为空实现。
修复方案: 拆分为更小、更聚焦的接口。
D — Dependency Inversion Principle
D — 依赖倒置原则
Depend on abstractions, not concretions.
Smell: High-level modules importing low-level modules directly.
Fix: Inject dependencies via interfaces/abstract classes.
依赖抽象,而非具体实现。
对应异味: 高层模块直接导入低层模块。
修复方案: 通过接口/抽象类注入依赖。
Naming Conventions
命名规范
Rules
规则
| Element | Convention | Example |
|---|---|---|
| Variables | Nouns describing what they hold | |
| Booleans | Prefixed with is/has/can/should | |
| Functions | Verbs describing what they do | |
| Constants | UPPER_SNAKE_CASE | |
| Classes | PascalCase nouns | |
| Interfaces | Describe capability | |
| 元素类型 | 规范 | 示例 |
|---|---|---|
| 变量 | 用描述存储内容的名词 | |
| 布尔值 | 以is/has/can/should为前缀 | |
| 函数 | 用描述功能的动词 | |
| 常量 | 全大写蛇形命名 | |
| 类 | 大驼峰命名的名词 | |
| 接口 | 描述具备的能力 | |
Name Length Guidelines
名称长度指南
| Scope | Length | Example |
|---|---|---|
| Loop counters | 1-2 chars | |
| Lambda params | 1-3 chars when context clear | |
| Local variables | Short but descriptive | |
| Function names | Medium, descriptive | |
| Class names | As long as needed | |
| 作用域 | 长度 | 示例 |
|---|---|---|
| 循环计数器 | 1-2个字符 | 仅在极短循环中使用 |
| Lambda参数 | 上下文清晰时可用1-3个字符 | |
| 局部变量 | 简短但具备描述性 | |
| 函数名 | 中等长度、描述清晰 | |
| 类名 | 按需定义长度 | |
Function Guidelines
函数指南
Size and Structure
大小和结构
- Functions should do one thing
- Ideal: 5-15 lines (excluding boilerplate)
- Maximum: 30 lines (beyond this, extract)
- Maximum parameters: 3 (beyond this, use options object)
- 函数应该只做一件事
- 理想长度:5-15行(不包含样板代码)
- 最大长度:30行(超过则需要抽取拆分)
- 最大参数数量:3个(超过则使用配置对象)
Guard Clauses (Early Return)
卫语句(提前返回)
typescript
// Bad: nested conditions
function getDiscount(user) {
if (user) {
if (user.isPremium) {
if (user.orderCount > 10) {
return 0.2;
}
}
}
return 0;
}
// Good: guard clauses
function getDiscount(user) {
if (!user) return 0;
if (!user.isPremium) return 0;
if (user.orderCount <= 10) return 0;
return 0.2;
}typescript
// 反面示例:嵌套条件
function getDiscount(user) {
if (user) {
if (user.isPremium) {
if (user.orderCount > 10) {
return 0.2;
}
}
}
return 0;
}
// 正面示例:卫语句
function getDiscount(user) {
if (!user) return 0;
if (!user.isPremium) return 0;
if (user.orderCount <= 10) return 0;
return 0.2;
}Error Handling Patterns
错误处理模式
Decision Table
决策表
| Approach | Use When | Example |
|---|---|---|
| Result type | Functional style, expected failures | |
| Specific exceptions | OOP style, exceptional cases | |
| Error codes | C-style APIs, cross-language | Return code + message |
| Option/Maybe | Value may or may not exist | |
| 方案 | 适用场景 | 示例 |
|---|---|---|
| Result类型 | 函数式风格、预期内的失败场景 | 返回 |
| 特定异常 | OOP风格、非预期的异常场景 | |
| 错误码 | C风格API、跨语言场景 | 返回错误码+消息 |
| Option/Maybe | 值可能存在也可能不存在的场景 | |
Result Type Pattern
Result类型模式
typescript
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
function parseConfig(raw: string): Result<Config, ParseError> {
try {
const config = JSON.parse(raw);
if (!isValidConfig(config)) {
return { success: false, error: new ParseError('Invalid config structure') };
}
return { success: true, data: config };
} catch {
return { success: false, error: new ParseError('Invalid JSON') };
}
}typescript
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
function parseConfig(raw: string): Result<Config, ParseError> {
try {
const config = JSON.parse(raw);
if (!isValidConfig(config)) {
return { success: false, error: new ParseError('Invalid config structure') };
}
return { success: true, data: config };
} catch {
return { success: false, error: new ParseError('Invalid JSON') };
}
}Error Handling Never List
错误处理禁止列表
- Never catch and swallow errors silently
- Never use exceptions for control flow
- Never return null to indicate an error
- Never log and rethrow without adding context
- 永远不要捕获错误后静默吞掉
- 永远不要用异常做控制流
- 永远不要返回null表示错误
- 永远不要打印日志后直接重抛错误而不补充上下文
Complexity Metrics
复杂度指标
| Range | Risk Level | Action |
|---|---|---|
| 1-5 | Low | No action needed |
| 6-10 | Moderate | Consider refactoring |
| 11-20 | High | Should refactor |
| 21+ | Critical | Must refactor |
| 数值范围 | 风险等级 | 操作建议 |
|---|---|---|
| 1-5 | 低 | 无需处理 |
| 6-10 | 中等 | 考虑重构 |
| 11-20 | 高 | 应该重构 |
| 21+ | 严重 | 必须重构 |
Reducing Complexity
降低复杂度的方法
- Extract complex conditions into named booleans
- Replace nested conditionals with guard clauses
- Use polymorphism instead of type checking
- Decompose into smaller functions
- Use lookup tables instead of switch/if chains
- 将复杂条件抽取为有名称的布尔变量
- 用卫语句替换嵌套条件
- 用多态替代类型检查
- 拆分为更小的函数
- 用查找表替代switch/if判断链
DRY Application Decision Table
DRY原则应用决策表
| Situation | Apply DRY? | Rationale |
|---|---|---|
| Exact duplication of logic | Yes | Same logic should live in one place |
| Three or more occurrences | Yes | Rule of Three confirms the pattern |
| Two occurrences only | Wait | May be coincidental similarity |
| Similar structure, different purpose | No | Different reasons to change |
| Abstracting adds more complexity | No | Clarity over DRY |
| 场景 | 是否应用DRY? | 理由 |
|---|---|---|
| 逻辑完全重复 | 是 | 相同逻辑应该只在一处维护 |
| 出现3次及以上 | 是 | 三次规则可以确认是可复用的模式 |
| 仅出现2次 | 暂不应用 | 可能只是巧合相似 |
| 结构相似但用途不同 | 否 | 变更的理由不同 |
| 抽象会增加更多复杂度 | 否 | 可读性优先于DRY原则 |
Comment Philosophy
注释原则
Good Comments
好的注释
| Type | Example |
|---|---|
| Why (reasoning) | |
| Legal | Copyright, license headers |
| TODO with ticket | |
| Warning | |
| Public API docs | JSDoc/TSDoc for public interfaces |
| 类型 | 示例 |
|---|---|
| 说明原因(设计思路) | |
| 法律声明 | 版权、许可证头 |
| 带工单编号的TODO | |
| 警告提示 | |
| 公共API文档 | 公共接口的JSDoc/TSDoc说明 |
Bad Comments (remove and fix code instead)
坏的注释(删除并优化代码替代)
| Type | Example |
|---|---|
| Restating code | |
| Commented-out code | Use version control instead |
| Journal comments | Use git log instead |
| Closing brace comments | |
| 类型 | 示例 |
|---|---|
| 复述代码逻辑 | |
| 注释掉的代码 | 用版本控制替代留存 |
| 日志式注释 | 用git log替代 |
| 闭合大括号注释 | |
Anti-Patterns / Common Mistakes
反模式/常见错误
| Anti-Pattern | Why It Is Wrong | Correct Approach |
|---|---|---|
| Premature abstraction | DRYing code that differs in intent | Wait for Rule of Three |
| God classes | Know everything, do everything | Split by responsibility (SRP) |
| Feature envy | Method uses another class's data more than its own | Move method to the data owner |
| Stringly typed data | Strings where enums/types belong | Define proper types |
| Magic numbers | Unclear meaning, error-prone | Named constants |
| Boolean trap | Function with boolean params that change behavior | Use named options or separate functions |
| Over-engineering | Abstractions for problems that do not exist | YAGNI — You Ain't Gonna Need It |
| 反模式 | 问题所在 | 正确方案 |
|---|---|---|
| 过早抽象 | 对意图不同的代码强行做DRY复用 | 等待满足三次规则再抽象 |
| 上帝类 | 知晓所有信息、承担所有功能 | 按职责拆分(符合单一职责原则) |
| 特性嫉妒 | 方法使用其他类的数据比自身类更多 | 将方法移动到数据所属的类 |
| 字符串类型滥用 | 应该用枚举/类型的场景用字符串 | 定义合适的类型 |
| 魔术数字 | 含义不明确、易出错 | 定义为有名称的常量 |
| 布尔陷阱 | 函数的布尔参数会改变行为 | 使用命名配置项或拆分独立函数 |
| 过度工程 | 为不存在的问题做抽象 | YAGNI原则 —— 你其实不需要它 |
Integration Points
集成点
| Skill | Relationship |
|---|---|
| Review identifies code smells for clean-code to resolve |
| TDD ensures behavior preservation during refactoring |
| Frontend components follow clean code principles |
| Backend services follow SOLID and clean architecture |
| Clean code enables easier performance optimization |
| Clean code is easier to debug |
| 技能 | 关联关系 |
|---|---|
| 代码评审识别出的代码异味可以通过整洁代码技能解决 |
| TDD可以保证重构过程中业务行为不被改变 |
| 前端组件遵循整洁代码原则 |
| 后端服务遵循SOLID和整洁架构原则 |
| 整洁代码更容易做性能优化 |
| 整洁代码更容易调试 |
Immutability Preferences
不可变性偏好
- Default to (JavaScript/TypeScript)
const - Use properties and
readonlyReadonlyArray - Prefer spread/destructuring over mutation
- Use immutable update patterns for state
- Only mutate when performance profiling demands it
- JavaScript/TypeScript中默认使用
const - 使用属性和
readonlyReadonlyArray - 优先使用展开/解构而非直接修改
- 状态更新使用不可变更新模式
- 仅在性能 profiling 证明需要时才做可变操作
Skill Type
技能类型
FLEXIBLE — Apply principles based on context. Not every function needs to be 5 lines; not every pattern needs to be SOLID. Use judgment and optimize for team readability over theoretical purity.
灵活适配 —— 根据场景应用原则,不是每个函数都必须写5行,不是所有场景都必须完全符合SOLID原则。结合实际判断,优先优化团队可读性,而非理论上的纯粹性。