第 10 章:从设计上消灭错误
系列:软件设计的哲学 · 第 10/22 章
全书导读:00-overview.md
一句话总结
优先从定义上消除错误类(让非法状态难表示),而非用异常和 if 在运行时到处救火。
核心观点浓缩
- 定义消除:收窄类型、合并操作、设合理默认值,使错误无法构造
- 异常应用于真正罕见、调用方难以预防的情况
- 过多异常分支 = 复杂度上浮,与第 8 章下拉原则相悖
- 设计模式是工具箱,非仪式;若模式让接口更复杂,应拆掉而非套用
- 好 API 让正确用法显眼,错误用法在编译期或第一次调用就失败
关键概念 / 金句
| 策略 | 示例 |
|---|---|
| 定义消除 | 用 ClosedFile / OpenFile 类型,而非 isOpen 标志 |
| 合并操作 | 原子 transfer(from, to, amount) 而非分步扣款 |
| 例外用异常 | 磁盘满、网络中断——调用方无法设计消除 |
本章在全书中的位置
第 10 章把模块设计延伸到契约与错误模型,衔接第 11 章设计过程。也回应「模式崇拜」:GoF 解法应拆解为降低复杂度的具体手法。
个人思考与启发
扫描状态机若用裸 int phase + 各处校验,错误分散。改为 enum class Phase 且仅在合法转移函数内变更,非法转移在 API 层不可表达,调试面大幅缩小。
与《程序员修炼之道》对照
- 契约式设计(前置/后置条件)与定义消除同源:约束写清楚,错误早发现
- 「死程序不说谎」:崩溃优于静默错误;本书更进:别让错误可写进代码
- 断言用于不可能分支;业务可恢复错误用结果类型——分工与本书一致
重点与注意
重点:先问「能否让这类错误不存在?」再问「捕获后怎么办?」
重点:模式引入前做复杂度会计:接口变简单还是变啰嗦?
注意:定义消除过头会类爆炸,用合理默认值平衡。
注意:用户输入错误无法消灭,应下拉到模块内转成安全结果,非抛给 UI 判 20 种码。
导航:第 9 章 拆还是合 · 下一篇:第 11 章 设计两次