整洁的代码不是某种特定的风格或模式,而是一种让代码易于理解和修改的状态。本文梳理《代码整洁之道》中关于简单设计、重构、代码坏味与命名的核心知识点。
一、迭进式设计(Simple Design)
Kent Beck 提出,遵循以下四条规则,设计就能变得简单。四条规则按优先级从高到低排列:
1 | ① 运行所有测试 |
1.1 运行所有测试
这是驱动整个设计演进过程的基石和动力。系统必须是完全可测试的。
追求高测试覆盖率本身就在强迫你改善设计——因为一个巨大、混乱、依赖众多的类是极难测试的。为了让代码易于测试,你会自然而然地写出短小、单一职责、低耦合的类和函数。
有了测试,就能放心地递增式重构代码:
- 添加几行代码后,暂停,琢磨变化了的设计。
- 设计退步了吗?清理它,运行测试,确认没有破坏任何东西。
- 测试消除了”清理代码会破坏功能”的恐惧。
1.2 消除重复
重复是良好设计中潜藏的最大敌人。
重复的三种常见形式:
| 重复类型 | 示例 | 解决方向 |
|---|---|---|
| 代码重复 | 多处出现相同的逻辑片段 | 提取方法或工具类 |
| 结构重复 | 多个类有相似的字段和操作 | 提取父类或接口 |
| 逻辑重复 | 不同实现但本质相同的算法 | 模板方法模式、策略模式 |
1.3 保证表达力
软件项目的主要成本在于长期维护,而不是最初的开发。
表达力的体现:
- 好命名:变量、函数、类的名字应该自解释,读代码像读文章。
- 短小的函数:每个函数只做一件事,函数名就是对这件事的完整描述。
- 规范的代码风格:统一的格式让团队成员能快速阅读彼此的代码。
- 选用合适的设计模式并说明:使用
Command、Strategy这样的模式名称,本身就是一种表达。
1.4 尽可能减少类和方法的数量
这条规则的优先级最低,是在满足前三条的前提下才考虑的。在消除了重复、保证了表达力之后,如果某些类或方法过于琐碎、可以合理合并来简化设计,那么就应该这样做。
二、逐步改进(Successive Refinement)
优秀的软件设计并非一蹴而就,而是源于对代码质量的持续关注和大量小规模、安全的改进。
重构的触发点
当代码功能完整,但新增支持两种类型后,代码到达了一个临界点——任何进一步的修改都会变得困难且容易引入错误。这就是启动重构的信号。
小步重构的五个特征
| 特征 | 说明 |
|---|---|
| 小步严谨 | 每个步骤非常小,可能只是移动一个方法、重命名一个变量 |
| 测试保障 | 每一步重构后立即运行测试,确保微小改动不破坏现有功能 |
| 持续进行 | 重构不是独立活动,而是在添加功能或修复 Bug 时同步进行 |
| 目标驱动 | 最终目标是让代码清晰、可读、易于修改、没有重复 |
| 勇气与耐心 | 有勇气改动”能工作但丑陋”的代码,有耐心接受逐步完善的过程 |
重构时机判断
1 | ✅ 该重构的信号: |
三、味道与启发(Smells and Heuristics)
3.1 一般性问题
暴露时序耦合
当一组函数必须按特定顺序调用时,应通过函数参数类型让时序关系显式可见,防止调用者乱序调用。
1 | // ❌ 三个函数独立,调用者无法知道必须按此顺序执行 |
封装边界条件
边界条件处理代码(如 + 1、- 1)容易散落在各处,应将其集中封装,避免重复和遗漏。
函数内语句应在同一抽象层级
1 | // ✅ renderHtml() 只包含同一层级的子步骤 |
用命名常量替代魔法数字
1 | // ❌ 含义不明 |
名称应该说明副作用
1 | // ❌ get 暗示只读取,但实际上可能创建对象 |
3.2 注释问题
废弃的注释:过时、无关或不正确的注释比没有注释更糟糕,会误导读者,立即删除。
冗余注释:注释应该谈及代码没有提到的信息,而不是重复代码已经表达的内容。
1 | // ❌ 冗余 |
注释掉的代码:直接删除它,版本控制系统会帮你记住历史。
3.3 函数问题
过多的参数
| 参数数量 | 评价 |
|---|---|
| 0 个 | 最佳 |
| 1 个 | 良好 |
| 2 个 | 尚可 |
| 3 个以上 | 应该重构,封装为参数对象 |
1 | // ❌ |
标识参数(Flag Arguments)
布尔类型的参数大声宣告函数做了不止一件事,应该拆分为两个函数。
1 | render(true); // ❌ 含义不清 |
3.4 命名问题
名称与抽象层级相符
1 | void writeDataToSocket() { ... } // ❌ 暴露实现细节 |
尽可能使用标准命名法
| 用途 | 惯用前缀/动词 |
|---|---|
| 工厂方法 | create、of、from、build |
| 类型转换 | to、as、valueOf |
| 布尔判断 | is、has、can、should |
| 查询 | find、get、query、fetch |
| 执行动作 | execute、run、process、handle |
四、核心原则总结
| 维度 | 核心原则 | 记忆关键词 |
|---|---|---|
| 设计 | 简单设计四原则(测试→消除重复→表达力→减少数量) | 测试先行,逐步演进 |
| 重构 | 小步前进,测试保障,持续进行 | 不积跬步,无以至千里 |
| 函数 | 短小、单一职责、少参数、无副作用 | 只做一件事 |
| 注释 | 解释”为什么”而非”是什么”,及时清理废弃注释 | 注释是代码的补充,不是替代 |
| 命名 | 自解释、无歧义、与抽象层级相符 | 好名字胜过好注释 |
“让营地比你来时更干净。”——童子军规则,也是代码整洁的精髓。



