读书笔记 · 约 12,814 字 · 预计推送 2 部分

《Code Complete》选读:防御式编程(Ch.8)与伪代码编程过程(Ch.9)——挑对现代工程仍有效的章节(主题精读) 未开始

目录

题记与说明


一、七维提取

1. 核心问题

一本 2004 年、900 多页的"代码大全",不是每一章都扛得住 20 年。在 2026 年的工程环境(强类型系统、schema 校验库、秒级编译、CI 测试文化、AI 辅助编码)下回看,本笔记回答三个问题:

2. 主要主张

Ch.8 防御式编程——总纲(原书引述,转自来源 1):

Defensive-programming techniques make errors easier to find, easier to fix, and less damaging to production code.

断言 vs 错误处理的二分(本章最核心的一条,原书引述,转自来源 1):

Use error handling code for conditions you expect to occur and assertions for conditions that should never occur.

配套的一组主张:

__Correctness__ means never returning an inaccurate result; returning no result is better than returning an inaccurate result.
__Robustness__ means always trying to do something that will allow the software to keep operating, even if that leads to results that are inaccurate sometimes.

安全关键系统偏正确性,消费级应用偏健壮性——"Any result whatsoever is usually better than the software shutting down."

Exceptions have an attribute in common with inheritance: used judiciously, they can reduce complexity. Used imprudently, they can make code almost impossible to follow.

细则:只抛"真正异常"的条件;不用异常"甩锅"(能在本地处理就本地处理);避免在构造/析构中抛异常;在正确的抽象层级抛。

Defining some parts of the software that works with dirty data and some that work with clean data can be an effective way to relieve the majority of the code of the responsibility for checking for bad data.

脏数据只允许进入边界区域,边界内校验、边界外假设干净——这是本章在现代最容易被直接对应上的一节。

Ch.9 伪代码编程过程——流程主张(转自来源 2、3):

3. 方法

书内的方法:这两章的证据结构是"原则 + 检查表 + 对比示例代码",属于 McConnell 式的实践综合(全书大量引用文献,但这两章本身不提供受控实验数据)。PPP 甚至给出"与 PPP 并列的备选方案"清单,说明作者意图是给流程选项,不是宣称唯一真理。

本笔记的方法:

  1. 先检索(2 轮 WebSearch),锁定读书笔记、著名批判、现代工业实践三条线;
  2. 用 webReader/WebFetch 精读 5 个来源,摘录可归属的原文引述;
  3. 对每条主张做"现代核对":找 2026 年的对应物(schema 校验、error wrapping、fail-fast 文化、Ousterhout 注释先行、AI 辅助编码),逐条判定仍有效 / 需修正 / 已过时;
  4. 对一个可本地复现的具体警告(断言里别放可执行代码)跑最小实验验证——这正是"精读笔记要动手"与"纯摘抄"的区别。

4. 数据与证据

(a)文字证据:见"主要主张"中的引述,均可归属到来源 1/2/3/4/5 的具体页面。其中来源 3(Coding Horror)逐字转引了 McConnell 的伪代码五好处,来源 4(Joe Duffy)经 WebFetch 提取了 8 段与"bug vs 预期失败"二分直接对应的原话。

(b)本地实验(本次实际运行):验证 Ch.8 中"断言里别放可执行代码"的警告在现代语言是否仍真实(该条的原书精确措辞未能从官方页面核对,此处以我的转述标注;实验只验证其内容成立)。

  def audit():
      print("  [side-effect] audit() executed")
      return True

  def main():
      assert audit(), "audit invariant violated"
      print("  main continues")
  $ python -I cc8-check/assert_pitfall.py
  run 1: normal
    [side-effect] audit() executed      <- 副作用发生了
    main continues
  === exit 0 ===

  $ python -IO cc8-check/assert_pitfall.py
  run 1: normal
    main continues                      <- audit() 从未执行,校验被静默跳过
  === exit 0 ===

(c)证据面的诚实声明:这两章没有任何可量化的对照实验数据支撑"PPP 降低缺陷率"或"断言减少 X% 故障"——CC2 未给出,我检索到的来源也未给出。Ch.8 的力量来自分类学的正确性(见下面 Midori 的独立再推导),Ch.9 的力量来自流程合理性 + Ousterhout 的间接印证。这是精读判断,不是测量结论。

5. 结论

Ch.8 是"保值章节"的典范——它的核心二分法被工业界在 12 年后用另一套语言独立推导了一遍。Midori 的错误模型(来源 4,Joe Duffy 逐字引述):

Our overall solution was to offer a two-pronged error model. On one hand, you had fail-fast – we called it abandonment – for programming bugs.
A bug is a kind of error the programmer didn't expect.
Proceeding in the face of a bug is dangerous when you're trying to build a robust system. … Because the developer didn't expect this to happen, all bets are off. All data structures reachable by this code are now suspect.
We used exceptions for recoverable errors.

把 Duffy 的"abandonment vs recoverable errors"和 McConnell 的"assertions vs error handling"并排:同一个二分,一个从语言运行时层面推导,一个从工程实践层面归纳,2004 与 2016 在此重合。这不是巧合——"程序员错误必须 fail fast,预期失败必须可恢复"是错误分类学的稳定结构。

Ch.9 的判定是"内核有效、载体过时":

code > pseudocode. I find it easier to think about code *in code*.
Comments should be a method of last resort, not something you start with.
Comments are a design tool, not documentation afterthought.
If the interface comment is hard to write, the interface is probably too complex.

Baisa 书摘也记下同一主张:"Delayed comments won't happen at all."(事后补的注释根本不会被写)

元方法(挑章节的标准):讲不变结构(错误分类学、正确性 vs 健壮性、抽象层级)的章节保值;讲具体载体(伪代码、晚编译、当时的调试工具)的章节贬值。据此扫 CC2 目录:Ch.8、Ch.5/6(设计/类)、Ch.7(例程质量)大概率保值,讲工具链与环境的章节需按年代打折。

6. 局限

7. 对我的启发

  1. 错误处理二分法直接落进自己的项目模板(对应本系列已有的 Python/TS 模板笔记):边界层用 schema 校验(pydantic / zod)当 barricade,边界内一律假设数据干净;内部不变量用 assert 表达,且保证 assert 里无副作用(本次实验已证明 -O 会静默剥离);区分"预期失败"(返回 Result / 抛业务异常)与"程序 bug"(fail fast,宁可崩溃也不带脏状态继续跑)。Duffy 那句 "All data structures reachable by this code are now suspect" 是 fail fast 最好的说服理由。
  2. 正确性 vs 健壮性取舍表可以当决策工具用:我的数据管道/备份类脚本(如 3-2-1 备份笔记那类)偏正确性——校验失败就停;展示层/UI 类脚本偏健壮性——降级也要出结果。以前这两类取舍是凭感觉,现在有一张明牌。
  3. 写例程采用"注释先行"的 PPP 变体:先写 docstring + 伪代码式注释骨架(含错误处理与测试思路),再填代码。在 AI 辅助编码下这有了新形态:注释/伪代码骨架就是给 AI 的规格说明,PPP 从"人转译成代码"变成"AI 转译成代码",Atwood 2009 年"精确英语描述函数体不现实"的反对理由,恰好被"转译者从人换成模型"瓦解(推断,待自证)。这也和 Ousterhout "comments as design tool" 完全同构。
  4. "能跑不够"那条值得贴在显示器旁:"A working routine isn't enough. If you don't know why it works, study it…"——对 vibe coding 尤其重要:AI 生成代码"能跑"的成本趋近于零,"知道为什么能跑"成了新的稀缺品。
  5. 方法论沉淀:以后精读老书,先做"不变结构 vs 具体载体"二分,再对 3-5 条核心主张找现代对应物,最后挑 1 条能本地动手验证的跑最小实验——本次这个三步法(对应→判定→实验)比通读全书更省也更扎实。

附:逐条核对表(McConnell 原始主张 → 2026 现代对应 → 判定)

McConnell 主张(Ch.8/9)2026 年的对应物判定
断言查"绝不该发生",错误处理查"预期发生"Midori: abandonment vs recoverable errors(Joe Duffy 2016)仍有效,被工业级系统二次确认
高健壮代码:先断言再处理错误fail fast + 结构化错误类型双保险仍有效
断言里别放可执行代码Python -O / C++ NDEBUG 剥除断言体(本地实测成立)仍有效,现代语言同样踩坑
正确性 vs 健壮性取舍安全关键系统 vs 消费应用的 SLO/降级策略仍有效(框架升级了,二分未变)
隔离栏 barricade边界 schema 校验(pydantic/zod/JSON Schema)、防腐层仍有效,形式工具化
异常只抛真异常、在正确抽象层级抛、勿甩锅error wrapping(%w/anyhow::Context/异常层级设计)仍有效
调试辅助:开发激进、生产收敛;留"优雅崩溃"debug build/feature flag、崩溃上报、优雅降级仍有效
防御过头本身制造缺陷同样成立;且防御代码无测试时更糟仍有效
伪代码五好处(评审/迭代/改动/注释/文档)大部分被类型系统、IDE、测试文化接管形式过时
伪代码转注释、每条注释展开 2-10 行与 self-documenting code、"注释是最后手段"冲突(Atwood)有争议
先想清楚再写(低层设计前置、注释承载设计)Ousterhout "Write the Comments First"(2018/2021);AI 时代的 prompt-as-spec(推断)内核仍有效
晚编译防 "Just One More Compile" 综合症秒级编译、实时诊断、热重载基本过时
先查标准库、复用好代码仍是第一生产力仍有效

附:关键引述汇总(均已在正文标明来源)

附:来源链接

  1. https://nikola-breznjak.com/blog/books/programming/code-complete-2-steve-mcconnell-defensive-programming
  2. https://nikola-breznjak.com/blog/books/programming/code-complete-2-steve-mcconnell-pseudocode-programming-process
  3. https://blog.codinghorror.com/pseudocode-or-code/
  4. http://joeduffyblog.com/2016/02/07/the-error-model
  5. https://www.binaryphile.com/2026/01/09/ousterhout-software-design-guide.html ;https://vit.baisa.cz/books/a-philosophy-of-software-design
  6. (未能访问)https://www.oreilly.com/library/view/code-complete-2nd/0735619670/ch08.html —— curl 返回 Access Denied
← 资料库今日播报 →