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 | 开始实现前写清输入、输出、错误和不变量 | 契约测试、边界测试、集成测试 |
把这些原则写进项目规则时,可采用以下形式:
- 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、破坏事务语义或制造不必要的复杂度。单纯把需求翻译成语法,已经不足以构成长期优势。
工作重心逐渐集中在四个位置:
定义问题:识别真实需求、非目标和不能被破坏的业务规则。
设计边界:让模块、数据和权限沿清楚的责任关系组织。
建立反馈:用测试、日志、运行页面和用户结果缩短判断距离。
审查证据:区分可证明的行为、合理推断和暂时未知的部分。
这些工作不能靠更长的 Prompt 自动消失。Prompt 只能承载已经形成的工程判断。开发者没有想清楚边界时,模型得到的只是更长的模糊描述。
把格言改写成可验证规则
《程序员修炼之道》由许多相对独立的短主题组成,适合结合正在发生的工作逐项重读。摘录格言不会自动改变工程行为。
可以从一个两周实验开始:
选择当前代码库中重复出现的一类 AI 任务;
找出最常见的失败方式,例如改动过大、边界猜测或测试不足;
选择一条对应原则,改写成具体项目规则;
在后续任务中记录它是否改变了
diff、返工次数和验收结果;只有规则确实有效,才把它保留在长期指令中。
长期指令只保留经过真实任务验证的规则。没有改变 diff、返工次数或验收结果的原则,不必继续留在 Prompt 中。