clean-code

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Clean 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

操作步骤

  1. Read the code in its full context (not just the snippet)
  2. Identify the code's responsibility and purpose
  3. Measure cyclomatic complexity
  4. Map coupling and dependencies
  5. Note any existing tests
  1. 通读完整上下文内的所有代码(不只是代码片段)
  2. 明确代码的职责和用途
  3. 计算圈复杂度
  4. 梳理耦合关系和依赖项
  5. 记录所有已有的测试用例

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

臃肿类

SmellDetectionRefactoring
Long Method> 30 linesExtract Method
Large Class> 300 lines or > 5 responsibilitiesExtract Class
Long Parameter List> 3 parametersIntroduce Parameter Object
Data ClumpsSame params appear togetherExtract Class
Primitive ObsessionPrimitives instead of small objectsReplace with Value Object
异味类型检测方式重构方案
过长方法超过30行抽取方法
过大类超过300行或承担超过5项职责抽取类
过长参数列表超过3个参数引入参数对象
数据泥团相同参数总是成对出现抽取类
基本类型偏执用基本类型替代小型对象替换为值对象

Object-Orientation Abusers

面向对象滥用类

SmellDetectionRefactoring
Switch StatementsSwitch on typeReplace with Polymorphism
Parallel InheritanceEvery subclass requires parallel subclassMerge hierarchies
Refused BequestSubclass ignores inherited methodsReplace Inheritance with Delegation
异味类型检测方式重构方案
Switch语句基于类型做Switch判断替换为多态
并行继承每个子类都需要对应创建并行的子类合并继承层次
拒绝遗赠子类忽略继承来的方法用委托替代继承

Change Preventers

变更阻碍类

SmellDetectionRefactoring
Divergent ChangeOne class changed for multiple reasonsExtract Class (SRP)
Shotgun SurgeryOne change touches many classesMove Method, Inline Class
异味类型检测方式重构方案
发散式变化一个类会因多个不同原因被修改抽取类(符合单一职责原则)
霰弹式修改一处改动需要修改多个类移动方法、内联类

Dispensables

冗余类

SmellDetectionRefactoring
Dead CodeUnreachable or unusedRemove
Speculative GeneralityUnused abstractions "just in case"Collapse Hierarchy, Remove
Comments explaining bad codeComments compensating for unclear codeRename, 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

操作步骤

  1. Apply ONE refactoring at a time
  2. Run tests after each change
  3. If any test fails, revert immediately
  4. Continue until code is clean
  5. Review naming, structure, and documentation
  1. 每次只执行一项重构操作
  2. 每次改动后都运行测试用例
  3. 如果有任何测试失败,立即回滚改动
  4. 持续迭代直到代码符合整洁标准
  5. 评审命名、结构和文档

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

规则

ElementConventionExample
VariablesNouns describing what they hold
userCount
, not
n
BooleansPrefixed with is/has/can/should
isActive
,
hasPermission
FunctionsVerbs describing what they do
calculateTotal
,
fetchUsers
ConstantsUPPER_SNAKE_CASE
MAX_RETRY_COUNT
ClassesPascalCase nouns
UserRepository
,
PaymentService
InterfacesDescribe capability
Serializable
,
Cacheable
元素类型规范示例
变量用描述存储内容的名词
userCount
,而非
n
布尔值以is/has/can/should为前缀
isActive
hasPermission
函数用描述功能的动词
calculateTotal
fetchUsers
常量全大写蛇形命名
MAX_RETRY_COUNT
大驼峰命名的名词
UserRepository
PaymentService
接口描述具备的能力
Serializable
Cacheable

Name Length Guidelines

名称长度指南

ScopeLengthExample
Loop counters1-2 chars
i
,
j
(tiny loops only)
Lambda params1-3 chars when context clear
users.filter(u => u.active)
Local variablesShort but descriptive
total
,
result
Function namesMedium, descriptive
calculateMonthlyRevenue
Class namesAs long as needed
AuthenticationTokenValidator

作用域长度示例
循环计数器1-2个字符仅在极短循环中使用
i
j
Lambda参数上下文清晰时可用1-3个字符
users.filter(u => u.active)
局部变量简短但具备描述性
total
result
函数名中等长度、描述清晰
calculateMonthlyRevenue
类名按需定义长度
AuthenticationTokenValidator

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

决策表

ApproachUse WhenExample
Result typeFunctional style, expected failures
Result<T, E>
return type
Specific exceptionsOOP style, exceptional cases
throw new ValidationError(...)
Error codesC-style APIs, cross-languageReturn code + message
Option/MaybeValue may or may not exist
Option<User>
方案适用场景示例
Result类型函数式风格、预期内的失败场景返回
Result<T, E>
类型
特定异常OOP风格、非预期的异常场景
throw new ValidationError(...)
错误码C风格API、跨语言场景返回错误码+消息
Option/Maybe值可能存在也可能不存在的场景
Option<User>

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

复杂度指标

RangeRisk LevelAction
1-5LowNo action needed
6-10ModerateConsider refactoring
11-20HighShould refactor
21+CriticalMust refactor
数值范围风险等级操作建议
1-5无需处理
6-10中等考虑重构
11-20应该重构
21+严重必须重构

Reducing Complexity

降低复杂度的方法

  1. Extract complex conditions into named booleans
  2. Replace nested conditionals with guard clauses
  3. Use polymorphism instead of type checking
  4. Decompose into smaller functions
  5. Use lookup tables instead of switch/if chains

  1. 将复杂条件抽取为有名称的布尔变量
  2. 用卫语句替换嵌套条件
  3. 用多态替代类型检查
  4. 拆分为更小的函数
  5. 用查找表替代switch/if判断链

DRY Application Decision Table

DRY原则应用决策表

SituationApply DRY?Rationale
Exact duplication of logicYesSame logic should live in one place
Three or more occurrencesYesRule of Three confirms the pattern
Two occurrences onlyWaitMay be coincidental similarity
Similar structure, different purposeNoDifferent reasons to change
Abstracting adds more complexityNoClarity over DRY

场景是否应用DRY?理由
逻辑完全重复相同逻辑应该只在一处维护
出现3次及以上三次规则可以确认是可复用的模式
仅出现2次暂不应用可能只是巧合相似
结构相似但用途不同变更的理由不同
抽象会增加更多复杂度可读性优先于DRY原则

Comment Philosophy

注释原则

Good Comments

好的注释

TypeExample
Why (reasoning)
// Use binary search because list is pre-sorted and >10K items
LegalCopyright, license headers
TODO with ticket
// TODO(PROJ-123): Add rate limiting
Warning
// WARNING: This is not thread-safe
Public API docsJSDoc/TSDoc for public interfaces
类型示例
说明原因(设计思路)
// Use binary search because list is pre-sorted and >10K items
法律声明版权、许可证头
带工单编号的TODO
// TODO(PROJ-123): Add rate limiting
警告提示
// WARNING: This is not thread-safe
公共API文档公共接口的JSDoc/TSDoc说明

Bad Comments (remove and fix code instead)

坏的注释(删除并优化代码替代)

TypeExample
Restating code
// increment counter
before
counter++
Commented-out codeUse version control instead
Journal commentsUse git log instead
Closing brace comments
} // end if

类型示例
复述代码逻辑
counter++
前写
// increment counter
注释掉的代码用版本控制替代留存
日志式注释用git log替代
闭合大括号注释
} // end if

Anti-Patterns / Common Mistakes

反模式/常见错误

Anti-PatternWhy It Is WrongCorrect Approach
Premature abstractionDRYing code that differs in intentWait for Rule of Three
God classesKnow everything, do everythingSplit by responsibility (SRP)
Feature envyMethod uses another class's data more than its ownMove method to the data owner
Stringly typed dataStrings where enums/types belongDefine proper types
Magic numbersUnclear meaning, error-proneNamed constants
Boolean trapFunction with boolean params that change behaviorUse named options or separate functions
Over-engineeringAbstractions for problems that do not existYAGNI — You Ain't Gonna Need It

反模式问题所在正确方案
过早抽象对意图不同的代码强行做DRY复用等待满足三次规则再抽象
上帝类知晓所有信息、承担所有功能按职责拆分(符合单一职责原则)
特性嫉妒方法使用其他类的数据比自身类更多将方法移动到数据所属的类
字符串类型滥用应该用枚举/类型的场景用字符串定义合适的类型
魔术数字含义不明确、易出错定义为有名称的常量
布尔陷阱函数的布尔参数会改变行为使用命名配置项或拆分独立函数
过度工程为不存在的问题做抽象YAGNI原则 —— 你其实不需要它

Integration Points

集成点

SkillRelationship
code-review
Review identifies code smells for clean-code to resolve
test-driven-development
TDD ensures behavior preservation during refactoring
senior-frontend
Frontend components follow clean code principles
senior-backend
Backend services follow SOLID and clean architecture
performance-optimization
Clean code enables easier performance optimization
systematic-debugging
Clean code is easier to debug

技能关联关系
code-review
代码评审识别出的代码异味可以通过整洁代码技能解决
test-driven-development
TDD可以保证重构过程中业务行为不被改变
senior-frontend
前端组件遵循整洁代码原则
senior-backend
后端服务遵循SOLID和整洁架构原则
performance-optimization
整洁代码更容易做性能优化
systematic-debugging
整洁代码更容易调试

Immutability Preferences

不可变性偏好

  • Default to
    const
    (JavaScript/TypeScript)
  • Use
    readonly
    properties and
    ReadonlyArray
  • Prefer spread/destructuring over mutation
  • Use immutable update patterns for state
  • Only mutate when performance profiling demands it

  • JavaScript/TypeScript中默认使用
    const
  • 使用
    readonly
    属性和
    ReadonlyArray
  • 优先使用展开/解构而非直接修改
  • 状态更新使用不可变更新模式
  • 仅在性能 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原则。结合实际判断,优先优化团队可读性,而非理论上的纯粹性。