代码整洁之道Skill clean-code

代码整洁之道是基于Robert C. Martin的经典书籍,旨在提高软件开发中的代码质量。它涵盖命名、函数设计、错误处理、测试等最佳实践,帮助程序员编写易于理解、修改和扩展的代码。关键词:Clean Code, 代码质量, 软件开发, Robert C. Martin, 整洁代码, 代码重构, 单元测试, 架构设计。

架构设计 0 次安装 0 次浏览 更新于 3/9/2026

名称: 洁净代码 描述: 在编写、审查或重构代码时使用。适用于命名变量或函数、构建类、处理错误、编写测试,或当代码感觉复杂或难以理解时。基于Robert C. Martin的《代码整洁之道》。

代码整洁之道

概述

整洁的代码读起来像优美的散文。每个名称都揭示意图。每个函数都讲述一个故事。每个类都有一个单一目的。目标不仅仅是让代码工作——而是让其他人能快速理解、安全修改和自信扩展的代码。

“整洁的代码看起来总是像是由关心的人编写的。” — Michael Feathers

“当每个例行程序都如你所预期时,你就知道你在处理整洁的代码。” — Ward Cunningham

童子军规则: 离开时让代码比你发现时更整洁。每次提交都应该提高质量,哪怕只是略微。小的改进会累积。

章节参考

本技能提供概览和快速参考。有关详细指导和示例,请参阅章节文件:

  • chapters/names.md - 有意义的名称(揭示意图、可搜索、可发音)
  • chapters/functions.md - 函数(小、做一件事、参数少)
  • chapters/comments.md - 注释(为何避免、什么是可接受的)
  • chapters/objects-and-data.md - 对象和数据结构(德米特法则、DTOs)
  • chapters/error-handling.md - 错误处理(异常、空值处理、特例模式)
  • chapters/tests.md - 单元测试(TDD、F.I.R.S.T.、整洁测试)
  • chapters/classes.md - 类(SRP、内聚性、OCP、DIP)
  • smells-and-heuristics.md - 完整的代码异味参考(66个异味及解释)

快速参考:名称

名称应揭示意图并可搜索。

规则
揭示意图 d elapsedTimeInDays
避免误导 accountList(不是List) accounts
区分清晰 a1, a2 source, destination
可发音 genymdhms generationTimestamp
可搜索 7 MAX_CLASSES_PER_STUDENT
类 = 名词 Process Customer, Account
方法 = 动词 data postPayment(), save()

避免: 在类名中使用ManagerProcessorDataInfo——它们暗示职责不清晰。

关键见解: 如果需要注释来解释变量是什么,不如重命名它。

快速参考:函数

大小和范围

  • 理想: 4-10行,很少超过20行
  • 缩进级别: 永远不超过一或两个
  • 做一件事 — 如果可以用非重复的名称提取另一个函数,那它做得太多

参数

数量 指导
0 最佳
1
2 可接受
3+ 避免—封装到对象中

标志参数(布尔值)很丑陋。 它们宣称函数做两件事。拆分它:

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

# 好
def render_for_suite(): ...
def render_for_single_test(): ...

关键规则

  • 命令查询分离: 做某事或回答某事,不要同时做
  • 无副作用: 如果checkPassword()也初始化会话,那它撒谎了
  • 偏好异常而非错误码: 分离快乐路径和错误处理
  • 提取try/catch块: 错误处理是一件事

快速参考:注释

注释,充其量是必要的恶。注释的正确使用是弥补我们在代码中表达失败的缺陷。

删除这些注释

  • 冗余的 — 重申代码所说的
  • 日记/变更日志 — 使用git
  • 注释掉的代码 — 一种可憎之物,git记得
  • 噪音// 默认构造函数, // 递增 i
  • 闭合大括号} // 结束 if 意味着嵌套太多

可接受的注释

  • 法律声明
  • 意图解释(为什么,而不是什么)
  • 后果警告(// 需要30分钟
  • TODO(但要清理它们)
  • 澄清外部库行为

规则: 当你感到想注释时,首先尝试重构代码,使注释变得不必要。

快速参考:错误处理

错误处理很重要,但如果它模糊了逻辑,那就是错误的。

规则 细节
使用异常而非返回码 分离算法和错误处理
提供上下文 包括失败的操作和失败类型
包装第三方API 最小化依赖,启用模拟
使用特例模式 返回处理特例的对象(空列表、默认值)
不要返回null 增加工作,引发NullPointerException
不要传递null 比返回null更糟—默认禁止
# 差 - 到处都是空值检查
if employees is not None:
    for e in employees:
        total += e.pay

# 好 - 返回空集合而非null
for e in get_employees():  # 如果没有,返回[]
    total += e.pay

快速参考:类

单一职责原则(SRP)

一个类应该有一个,且仅有一个,改变的理由。

测试:

  • 你能推导出简洁的名称吗?(避免ManagerProcessorSuper
  • 你能在25个词内描述它,不使用“如果”、“和”、“或”、“但是”吗?

内聚性

方法应使用类的实例变量。当方法围绕某些变量聚集而不围绕其他变量时,应拆分类。

开闭原则(OCP)

类应对扩展开放,对修改关闭。通过子类化添加新行为,而不是修改现有代码。

依赖倒置原则(DIP)

依赖抽象,而非具体细节。注入依赖以提高可测试性。

# 差 - 没有网络就无法测试
class Portfolio:
    def __init__(self):
        self.exchange = TokyoStockExchange()

# 好 - 可注入,可测试
class Portfolio:
    def __init__(self, exchange: StockExchange):
        self.exchange = exchange

快速参考:测试

TDD三定律

  1. 除非有失败的测试,否则不写生产代码
  2. 不写超过足以失败的测试
  3. 不写超过足以通过的生产代码

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

  • 快速 — 运行迅速,以便经常运行
  • 独立 — 不相互依赖
  • 可重复 — 在任何环境中结果相同
  • 自我验证 — 布尔输出(通过/失败)
  • 及时 — 在生产代码之前编写

整洁测试

  • 可读性 至关重要
  • 使用 构建-操作-检查 模式
  • 创建领域特定的测试语言
  • 每个测试一个概念(不一定是一个断言)

警告: 测试代码和生产代码同样重要。如果让测试腐烂,代码也会腐烂。

对象 vs 数据结构

概念 隐藏 暴露 易于添加…
对象 数据 函数 新类型
数据结构 数据 新函数

万物皆对象的想法是个神话。 有时你只需要简单的数据结构和操作它们的程序。

德米特法则

一个方法应只调用:

  • 类自身的方法
  • 它创建的对象的方法
  • 作为参数传递的对象的方法
  • 实例变量持有的对象的方法

不要 调用允许函数返回的对象的方法(火车残骸):

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

# 好 - 告诉对象做工作
bos = ctxt.create_scratch_file_stream(class_file_name)

最关键的气味

来自第17章的全面列表,这些是最重要的:

G5: 重复

软件中所有罪恶的根源。 每次重复都是一个错过的抽象机会:

  • 相同代码 → 提取到函数
  • 重复的switch/if-else → 多态性
  • 相似算法 → 模板方法或策略模式

G30: 函数应做一件事

如果你能从中提取另一个函数,原函数做得太多。

N1: 选择描述性名称

名称是代码可读性的90%。花时间明智选择。

F1: 参数太多

零最好,然后一、二、三。更多需要理由。

F3: 标志参数

布尔参数意味着函数做两件事。拆分它。

G9: 死代码

未执行的代码。删除它—版本控制记得。

G11: 不一致性

如果你用一种方式做某事,所有类似事情都用相同方式做。

C5: 注释掉的代码

一种可憎之物。立即删除。

技艺

“编写整洁的代码需要纪律性地运用无数小技巧,通过艰苦获得的‘整洁感’来应用。代码感是关键。”

整洁的代码不是机械遵循规则写出的。它来自驱动纪律的价值观—关心技艺,尊重代码读者,并以专业工作为傲。

你如何编写整洁代码? 初稿很笨拙—长函数、嵌套循环、随意名称、重复。你提炼:拆分函数、更改名称、消除重复、缩减方法。没有人一开始就写出整洁代码。

让软件工作和让代码整洁是不同的活动。我们大多数人头脑空间有限,所以先专注于让代码工作。问题是太多人认为程序一旦工作就完成了。 我们未能切换到组织和整洁。我们继续下一个问题,而不是回去将臃肿的类拆分成解耦单元。

不要这样。回去。清理它。留下比发现时更好的状态。