2026 年 7 月 27 日 · 阅读时长 10 分钟

AI 时代更需要重读《程序员修炼之道》

Matt Pocock 在视频 My #1 book recommendation for strategic programming 中推荐开发者重读 David Thomas 与 Andrew Hunt 合著的《程序员修炼之道》。他强调的是 strategic programming,并提到自己已经把书中的许多原则直接写进 System Prompt。

AI 正在迅速降低代码实现的成本。一个接口、一段数据转换或一组测试,过去需要开发者连续编写数小时,现在可能只要一轮清楚的任务描述和几次修正。

生成代码草稿的成本下降了,理解问题、选择边界和承担结果仍然困难。代码越容易生成,未经验证的假设、重复抽象和隐藏耦合也越容易一起进入代码库。实现速度提高以后,工程判断反而成了更稀缺的部分。

这让一本 1999 年首次出版的编程书重新进入讨论。它关注如何面对不确定需求、控制变化范围并持续获得真实反馈,不依赖某种语言、框架或模型。技术会过期,这些问题不会。

Matt Pocock 推荐的范围

Matt 的视频标题是「My #1 book recommendation for strategic programming」。其中的「#1」仅指 strategic programming。

这段推荐包含以下事实边界:

  • 他把《程序员修炼之道》称为自己读过的排版可能最好的技术书之一;视频没有使用「洞察最深刻」这样的绝对评价;

  • 他表示已经把书中的许多内容放进 System Prompt,并没有声称每条原则都能直接复制;

  • 他点名提到 Tracer Bullets、Don't Outrun Your Headlights 和 Programming by Coincidence,认为这些原则像是为 AI 时代准备的。

John Ousterhout 在《A Philosophy of Software Design》中也区分了「战术性编程」与「战略性编程」。这个区分关注完成任务与控制复杂度之间的关系,与是否亲自写代码无关。

工作方式首要问题常见结果
Tactical Programming尽快完成当前 Ticket局部功能快速落地,暂不处理长期复杂度
Strategic Programming完成需求,同时让系统继续容易理解和修改为清晰边界、可替换设计和验证能力持续投入

战略性编程关注当前决策如何影响后续修改,而非预测五年后的全部需求。设计保持清楚、可验证、可替换,下一次变化到来时才有调整空间。

AI 放大了局部实现与全局设计之间的差距

LLM 能在给定上下文中快速完成局部任务。接口、输入和约束足够清楚时,它可以补齐实现、测试和文档。模型看到的上下文通常只是系统的一部分。

一个局部改动是否正确,还取决于仓库中未进入当前上下文的内容:领域规则、历史兼容、权限边界、事务语义、运行成本、发布流程和团队约定。上下文缺失时,生成结果仍可能顺利编译,甚至通过局部测试,却把复杂度转移到系统的其他位置。

AI 辅助开发需要让模型在清楚的边界内行动,并持续接收能够纠正判断的反馈。生成代码是循环中的一个步骤。

这条反馈循环比一次性生成完整系统更慢一些,却能更早暴露错误方向。AI 提高了循环内的实现速度,开发者负责控制循环的范围和停止条件。

Tracer Bullets:先贯通一条真实路径

Tracer Bullets 常被译为「示踪弹」。它要求用一条很窄、但真实工作的端到端路径验证方向。产物会进入实际系统并继续扩展,而非随手丢弃的演示。

例如,新建一个订单系统时,可以让 AI 先贯通一条路径:提交最小订单、完成校验、写入数据库、返回可查询结果。认证、日志、迁移、测试和部署仍走真实机制,用户、商品、库存、支付、优惠和通知等平行模块暂缓扩展。

Chain-of-Thought 描述模型的推理过程,Tracer Bullets 描述工程交付和环境反馈。二者处理的问题不同:前者发生在模型内部,后者必须通过真实接口、数据库、测试和运行环境验证。

对 AI 的约束可以写成:先完成最小端到端切片;切片通过验收前,不批量生成平行模块;每扩展一步,都重新运行与该路径相关的验证。

Don't Outrun Your Headlights:让反馈速度决定步幅

《程序员修炼之道》20 周年纪念版的公开样章用夜间驾驶解释这条原则:车灯能照亮的距离有限,车速超过观察和制动能力,就来不及应对弯道。软件开发同样只能可靠看清前面有限的几步。

面对模糊需求,模型可能迅速扩展出大量实现。需求只说「以后可能支持多租户」,它就可能提前加入租户表、上下文中间件、权限抽象和迁移脚本。代码量增加了,尚未确认的问题也被固化进架构。

书中要求持续采用小而明确的步骤,并让反馈速度成为前进速度的上限。长期方向需要考虑,但设计只能延伸到证据能够支持的位置。能够在几分钟内通过测试和运行结果验证的改动,可以快速推进;需要依赖数月后需求才能判断的抽象,应当保持可替换,暂不提前完成。

Programming by Coincidence:运行正常不是充分证据

AI 生成的代码可能通过当前测试,但开发者和模型都无法准确解释它为什么正确。

常见表现包括:

  • 为消除异常而加入一个来源不明的参数;

  • 复制现有实现,却没有确认两处业务语义是否相同;

  • 通过增加重试掩盖并发或幂等问题;

  • 保留模型建议的兼容分支,却没有任何真实调用方;

  • 依赖测试数据的偶然顺序得到正确结果。

这类做法符合 Programming by Coincidence。实现碰巧有效,却缺少稳定依据。每个关键行为都应当指向接口契约、领域规则、标准文档、测试用例或运行证据。人工不必重写所有 AI 代码,但要能解释为什么保留它。

代码评审需要明确逻辑依赖的事实、证明该事实的测试,以及依赖变化时最先出现的失败。无法回答时,就不应仅凭「现在能跑」合并代码。

Orthogonality:模块边界也是上下文边界

Orthogonality 要求无关事物之间的变化尽量互不影响。出版社列出的对应原则是:组件应当自包含、彼此独立,并拥有单一且清楚的目的。

在 AI 协作中,模块边界同时决定上下文边界。一个订单规则只依赖订单领域接口,模型就可以在较小上下文中修改它;如果订单逻辑同时读取全局状态、共享数据库字段和多个页面组件,任何局部任务都要加载更大范围,遗漏副作用的概率也会提高。

正交性关注变化是否沿清楚边界传播,不要求把每个函数拆成独立服务。可以从这些问题判断:

  • 修改一种通知渠道,是否必须改订单状态机;

  • 更换存储实现,是否会改变领域对象的公开接口;

  • 为 AI 提供一个模块及其测试后,是否还必须补充大量隐含全局知识;

  • 一个局部测试失败时,能否快速定位到有限的责任范围。

边界越清楚,AI 需要猜测的内容越少,人工审查也越容易集中在发生变化的部分。

Design by Contract:把意图变成可检查条件

Design by Contract 要求在参数类型之外,继续明确操作开始前必须成立什么、完成后保证什么,以及整个过程有哪些不变量。

以资金转账为例,「实现转账接口」仍然留下大量空白。更接近契约的描述会明确:

  • 前置条件:账户存在、币种一致、金额大于零、请求带有幂等键;

  • 后置条件:成功时生成唯一交易记录,并产生等额借贷记账;

  • 不变量:任何失败路径都不能只更新一侧余额;

  • 错误语义:余额不足、重复请求和系统失败必须可区分;

  • 验收证据:单元测试覆盖边界,集成测试验证事务回滚与幂等。

模型此时不必猜测「健壮」是什么意思。输入、输出、边界条件和失败语义已经转化成测试可以检查的内容。Prompt 提供意图,契约定义可观察行为,测试负责判断实现是否满足承诺。

经典原则可以成为项目级 AI 约束

这本书提供工程原则,不提供现成的 System Prompt。使用时还要把原则改写成与仓库和任务相匹配的执行规则。

经典原则项目规则验收证据
Tracer Bullets先实现一条最小端到端路径,再扩展平行能力真实请求、数据写入与读取结果
Don't Outrun Your Headlights只为已知需求设计,未知方向保持可替换diff 范围、删除成本、下一步反馈
Programming by Coincidence不保留无法解释依据的修复或兼容分支失败复现、测试、文档或调用方证据
Orthogonality修改局部能力时避免引入无关模块变化依赖方向、影响文件、回归测试
Design by Contract开始实现前写清输入、输出、错误和不变量契约测试、边界测试、集成测试

把这些原则写进项目规则时,可采用以下形式:

AI implementation rules
- Start with the smallest end-to-end slice that can be verified in the real system.
- Do not add abstractions for hypothetical requirements; keep uncertain code replaceable.
- Do not keep behavior that cannot be explained by a contract, source, test, or observed result.
- Keep unrelated modules independent and report every cross-module change.
- Define inputs, outputs, error semantics, invariants, and acceptance checks before implementation.
- After each small change, read the feedback and adjust before expanding the scope.

规则必须能改变执行行为。「编写高质量代码」无法指导模型在分歧处如何选择;「未验证端到端路径前不批量扩展模块」则给出了清楚的决策条件。

开发者开始承担更多系统约束工作

AI 普及以后,熟悉语言和工具仍然重要。缺少实现能力,开发者很难识别模型是否误用 API、破坏事务语义或制造不必要的复杂度。单纯把需求翻译成语法,已经不足以构成长期优势。

工作重心逐渐集中在四个位置:

  1. 定义问题:识别真实需求、非目标和不能被破坏的业务规则。

  2. 设计边界:让模块、数据和权限沿清楚的责任关系组织。

  3. 建立反馈:用测试、日志、运行页面和用户结果缩短判断距离。

  4. 审查证据:区分可证明的行为、合理推断和暂时未知的部分。

这些工作不能靠更长的 Prompt 自动消失。Prompt 只能承载已经形成的工程判断。开发者没有想清楚边界时,模型得到的只是更长的模糊描述。

把格言改写成可验证规则

《程序员修炼之道》由许多相对独立的短主题组成,适合结合正在发生的工作逐项重读。摘录格言不会自动改变工程行为。

可以从一个两周实验开始:

  1. 选择当前代码库中重复出现的一类 AI 任务;

  2. 找出最常见的失败方式,例如改动过大、边界猜测或测试不足;

  3. 选择一条对应原则,改写成具体项目规则;

  4. 在后续任务中记录它是否改变了 diff、返工次数和验收结果;

  5. 只有规则确实有效,才把它保留在长期指令中。

长期指令只保留经过真实任务验证的规则。没有改变 diff、返工次数或验收结果的原则,不必继续留在 Prompt 中。

相关内容

参考资料

CO

我是 Cooper,一名生活在中国的开发者,多年来一直在家远程工作。

主要使用 Go、PHP 和 Rust,从事移动端、Web、跨境支付与资金系统开发。目前主要采用 Vibe Coding 构建产品,并以真实运行结果完成验证与交付。