---
author: Best Partners TV
date: '2026-09-01'
guest: ''
layout: post.njk
source: https://www.youtube.com/watch?v=PenFT2xcHp4
speaker: Best Partners TV
tags:
  - ai-assisted-coding
  - mutation-testing
  - clean-code
  - test-driven-development
  - software-architecture
title: Bob大叔谈AI时代编程：为什么我不看AI写的代码，而用确定性工具驾驭Agent
summary: 《代码整洁之道》作者Bob大叔与Matt Pocock展开对谈，分享其使用AI Agent写代码的经验。他提出不直接看AI代码，而是依靠CRAP度量、变异测试等确定性自动化工具与多Agent流水线实施约束，并探讨了架构设计、敏捷模式及新人学习路径。
insight: ''
draft: true
series: ''
category: software-development
area: tech-engineering
project: []
people:
  - Robert C. Martin
companies_orgs: []
products_models: []
media_books:
  - Clean Code
status: evergreen
---
### 背景介绍与传奇程序员

**大飞**: 大家好，这里是最佳拍档，我是**大飞**。

“我完全不看Agent写出来的任何代码。”

这句话如果是从一个刚毕业的程序员嘴里说出来的，我们可能会觉得他不太靠谱。但是说这话的人是**罗伯特·马丁**（**Robert C. Martin**），全球开发者更熟悉的称呼是**Bob大叔**。他编程超过五十年，写了《**代码整洁之道**》（**Clean Code**），是软件工程领域被引用次数最多的作者之一。一个把代码质量看得比什么都重的人，现在说他不看AI写的代码。

今天我们就来聊聊这件事儿。Bob大叔最近和知名TypeScript教育家**马特·波科克**（**Matt Pocock**）做了一场直播对谈，聊的就是AI时代的软件基础，以及他这几个月和AI Agent一起写代码的真实经历。整场对谈不光是聊到了AI怎么写代码，更核心的问题是：当代码的生成速度被大幅提升之后，程序员到底应该把时间花在哪里？

先来给大家介绍一下Bob大叔这个人。他1964年就写了第一个程序，当时才十二岁。那台机器是他母亲送他的生日礼物，一种小型的模拟电脑。当时得把白色的小管子套在插桩上来编程。在他看来，那本质上是一个3位的有限状态机，但是对十二岁的他来说已经足够着迷了。后来他父亲给了他几本编程语言的书，包括**Fortran**、**Cobol**、**PL/I**，他全读完了。只是当时没有机器可以运行程序，他只能把程序写在纸上，在脑子里运行一遍。十六岁的时候，他找到了一份可以写代码的临时工作；十八岁找到第一份正式的程序员工作，从那以后一直做到今天。

这场对谈还有一个有意思的开场：Bob大叔是穿着浴袍出来的。这其实是他个人形象的一部分，源于他所谓的“晨间浴袍吐槽”。大约两年前，他早上六点穿着浴袍坐在前廊，开始琢磨SQL注入这件事，越想越觉得不对劲，掏出手机发了一通牢骚，没想到反响不错。后来就陆续做了几次，用这种半开玩笑的方式来表达对技术问题的看法。

### 从给Agent擦屁股到确定性工具

**大飞**: 接下来我们进入正题。去年圣诞节前后，Bob大叔开始认真尝试AI编程工具。最早试的是**ChatGPT**、**Grok**这些，一开始其实没觉得有多惊艳。后来他找了一个Agent让它帮忙写代码，写得不怎么样，但至少确实写出来了。当时他正忙着一个项目，就让Agent参与了工作。不过那个阶段他一直在给Agent擦屁股，因为它经常把事情搞得一团糟。速度确实快，但总会留下隐患。他的感受很矛盾：AI挺有意思，因为确实快；但是也很让人沮丧，因为反而让自己的效率变慢了。

转折发生在他意识到一件事：既然Agent这么快，那它其实可以做一些他自己根本做不到的事情。这里他提到了两个很早就有、但是一直没法落地的想法：

一个叫**CRAP**，是一个缩写，把代码测试覆盖率和每个函数的圈复杂度结合起来，通过一个公式算出一个分数，衡量一个函数到底有多糟糕。2000年代初他就跑过一次，确实找出了一堆糟糕的函数，但只能一个一个地修，还得重新编写测试，成本太高，只能搁置。

另一个叫**变异测试**（**Mutation Testing**），原理是让一个小程序自动修改你的源代码，比如把负号改正号、小于号改大于号，每改一次就跑一遍完整的测试套件。预期测试应该失败，因为代码被故意改坏了；如果测试没失败，就说明出现了一个存活的变异体，需要处理。这个方法他也试过，当时得跑一整晚，虽然是找出不少问题，但同样没法纳入正常流程。

到了今年初，他突然想到：AI速度快，而且根本不在乎工作有多枯燥，那干脆让Agent去跑CRAP，再让它负责重构和清理代码；也让它跑了跑变异测试。以前要跑一整晚的任务，现在三十分钟就能完成了，而且还能把所有测试漏洞补上。他意识到，AI写代码时虽然会留下很多碎屑和浮毛，但是它们自己也许就是清理这些东西最好的工具。

于是他不断尝试，加入更多工具，让多个Agent配合工作。到现在为止，效果相当不错。他现在的原则很明确：让Agent去干活，运行这些工具。他正在努力达到一种状态——**不需要亲自去看代码，也可以信任AI**。当然他还是会通过其他方式来验证代码的质量，比如检查CRAP分数、抽查代码、运行其他测试等等。但是总体思路是：既然Agent处理代码的速度比人类快得多，而人类处理代码很慢，那就让Agent负责写代码，人类来处理更高层面的事情，确保一切正常运转。

### 规则不是建议：确定性检查 vs 提示词

**大飞**: 不过这里有个关键问题绕不开：AI写的烂代码该怎么办？

Bob大叔很早就发现，如果一直让Agent往下做，不去清理它留下的烂摊子，它的速度反而会越来越慢。比如改了一个地方，无意中破坏了另一个地方；为了修复那个地方，又破坏了其他地方，最后不停绕圈子。这些Agent虽然快，也确实聪明，但是和人类一样，也会受到烂代码的影响。代码烂到一定程度，Agent就处理不了了，开始原地打转，然后把烂摊子越搞越大。他甚至遇到过一个Agent直接跟他说：“我处理不了了。”

那怎么解决呢？大多数人可能会选择给Agent增加指令，在配置文件里堆满规则，每看到坏代码就加一条。但是Bob大叔选了另一条路：**确定性的自动化检查机制**。

他解释了为什么不选择引导的方式。最开始他确实这么做过，给Agent写的提示词都是“这是测试驱动开发的方法”、“这是整洁代码的要求”之类的，最后会得到一份长达十页的文档专门告诉它什么是好代码。但是他很快发现，这些模型对待规则的态度特别像《加勒比海盗》里的海盗法典一样——听起来是规则，但是对它们来说更像是一堆建议。

背后其实是有技术原因的。他研究之后发现，这和一个叫**Lost in the Middle**的现象有关。模型的上下文窗口越来越大，放在最前面和最后面的内容更容易被关注，而夹在中间的内容更容易被忽略，甚至像消失了一样。比如你写了一份很长的提示词，开头前三句它记得很清楚，当作高优先级指令；但是到了第五十句、第八十句，那些内容可能就被丢到上下文中间的某个角落了。

但是确定性的工具不会这样，不会因为规则写在第五十行还是第八十行就把规则当建议。所以他认为使用Agent的关键，就是把初始提示词精简到绝对最小值，尽可能多地保留在优先级区域，然后在这之后使用确定性工具，虽然这确实很难做到。

马特补充了一个很好的说法，叫**上下文窗口的聪明区和愚蠢区**，这是**戴克斯·霍瓦斯**（**Dex Horvath**）提出来的概念。随着上下文不断变长，Transformer中的注意力机制会越来越吃力，信息逐渐被稀释。就像一个越来越拥挤的房间，每个Token都在大声说话，最后你很难从一片噪音中分辨出真正重要的信号。

Bob大叔还提到，自动化检查确实存在一个过多的临界点。如果它们让Agent的速度慢到还不如人类，那你就输了；但是只要生产力仍然高于人类，你就依然领先。根据他目前的观察，大概能把生产力优势维持在两到四倍左右。使用确定性工具会明显拖慢Agent，因为你实际是把它放进了一个循环里，不断修改代码，直到工具告诉它OK为止。Agent就在那里不停循环，修改这个、修改那个，增加测试、降低圈复杂度、拆分函数，需要很长时间才能达到预设的合规标准。本质上是在牺牲一部分生产力，来换取更高的代码质量。

### 多Agent协同流水线

**大飞**: 他正在尝试让多个Agent彼此协作、相互交接。比如一个负责写代码，下一个负责审查，再下一个负责测试和强化。虽然有巨大的通信开销，但是整体速度仍然比人类快得多。

说到多Agent协同，这其实是解决上下文失效问题的一个关键思路。Bob大叔解释了两个优势：第一可以并行运行多个Agent；第二当任务聚焦到单一任务时，可以更好地控制上下文窗口，Lost in the Middle的问题会减轻。你甚至可以设置这样一套机制：让Agent出生、完成任务，然后消失；下一个Agent进来时，面对的是干净的上下文窗口。缺点是启动时间更长，一个Agent可能需要十到十五秒才能启动并且理解当前上下文。

他倾向于尽可能把任务拆得足够细、足够聚焦。具体来说他有一套完整的流程：
1. 先运行一个**规格定义器**，把人类编写的文档转换成**Gherkin**语言和QA流程；
2. 然后交给**编码器**，负责编写单元测试、实现故事逻辑，让Gherkin测试跑通；
3. 完成后交给**清理器**做复杂度分析和常规代码审查；
4. 接着交给**强化器**运行变异测试，反复验证测试是否真的有效，确保百分之百的测试覆盖率（这个过程非常耗时）；
5. 最后交给**QA Agent**，把书面QA文档转换成可执行脚本，用脚本直接操作系统，给出确定性的测试结果。

如果能通过这一整套流程，最终得到的程序质量会非常高。他自己的实践很成功：给单个Agent一个任务可能五分钟就完成了，但是结果是否可靠很难说；而采用这套流程可能需要一个小时，但是依然划算，因为让人类完成同样的工作可能需要半天。

### 架构设计与深层模块

**大飞**: 在架构设计方面，Bob大叔也有不少的思考。过去一个多月前，他一直是手动完成模块结构设计的：先让Agent构建东西，然后通过不断提问来审问它们，比如这里的结构是什么？模块和模块怎么关联？等他得到那些令人恐惧的答案后，就亲自设计模块结构，告诉Agent该怎么划分、怎么通信。这个过程非常辛苦，所以他让Agent帮他构建了一个架构查看器，可以在屏幕上弹出类似UML的图表，展示整个系统的模块结构和依赖关系，可以点击查看子模块甚至直接看代码。

他还构建了另一个确定性工具，可以定义哪些模块应该依赖哪些模块、哪些绝对不能互相依赖，形成一份Agent无法违反的规范文件。如果违反了就必须通过反转依赖、提取接口等方式修复。

马特提到了**约翰·欧斯特豪特**（**John Ousterhout**）的**深层模块**（**Deep Modules**）概念，即接口简单但是内部隐藏大量信息的模块，对Agent来说非常理想，因为它们只需要读取接口而不必理解实现。Bob大叔非常认同这一点，指出模型非常关注接口的名称和结构，这意味着它们不必阅读下层代码。当然这既是一种风险，也是一种优势。他还在《代码整洁之道》附录里记录了和欧斯特豪特之间的一场长篇辩论，他自己玩得很开心。

### 传统工程规范的调整与重塑

**大飞**: 接下来聊到了传统编程规范在AI时代是否需要调整。Bob大叔提到了几个具体的调整：

首先是**阈值问题**。Agent能处理的复杂度和人类开发者是不一样的，它们的短期记忆比人类强得多，而且更加精准。所以他把CRAP分值从人类的4以下放宽到了6，甚至在考虑提高到8。在测试覆盖率达到百分之百的情况下，CRAP分值为6意味着这个函数有六条执行路径，而且每一条都经过测试。他还和Agent就这个问题争论过多次，Agent似乎也认为6是个不错的标准。

另一个重要的调整是关于**测试驱动开发**（**TDD**）。他曾经是TDD的坚定拥护者，但那是一种人类的纪律，是根据人类的思维方式演化出来的。他不会也不打算把这种纪律强加给Agent，强迫Agent写一行测试再写一行生产代码没有什么意义。虽然对人类来说这样做收益很大，但是对于Agent来说，他更愿意允许它们采用欧斯特豪特提倡的方式：先写函数再写测试。事实上即使他要求Agent严格按照TDD来做，它们最终也总会回到先写代码、再写测试的模式。所以他的结论是：**把人类的纪律强加给Agent可能是一个错误**。当然，虽然我们不需要强加纪律，但是仍然需要坚持人类的价值观，只是阈值需要根据Agent的特点调整。

### 敏捷开发 vs 前期过度规划

**大飞**: 关于前期规划，Bob大叔有一个很明确的判断：现在最大的诱惑是过度编写规格说明，让开发者不断完善需求和计划，再把这些东西一次性交给Agent。

这是一个源自七十年代的古老诱惑，后来瀑布流开发模式就是这种思路的典型；而敏捷开发的兴起，很大程度上就是对这种做法的反思。过于沉重的前期规划往往会把事情搞得一团糟，因为最终做出来的东西几乎不可能和最初设想的一模一样。面对Agent，人们同样容易掉进这个陷阱。他这周就试过这种方式，结果一次次证明是灾难。Agent根本无法完全按照你制定的计划执行，因为你不可能提前考虑到所有的细节，Agent也没有你那么强的判断能力，很容易朝错误方向一路跑偏，你只能叫停、回滚、重新计划、从头开始。

所以他放弃了这种做法，回到敏捷的方式：先让Agent完成一两个具体任务，看看整体架构有没有问题，如果需要就手动介入做一些调整，再让它继续。他怀疑我们可能永远无法完全摆脱最后这步人工组织的工作。

对于现在流行的**规格驱动开发**（**Spec-Driven Development**），他的直觉是这条路行不通。Agent非常喜欢写计划，会不断修饰，写得越来越华丽完美、细节越来越丰富，但是到了真正执行的阶段，往往还是会崩盘。

他用了一个很妙的比喻：假设改建一栋房子的成本只需要一美元，包括打地基、修屋顶以及之后所有的修改，每次都只需要一美元。你会先花几千美元请建筑师设计一套完美方案，再花一美元一次性把房子盖出来呢？还是直接走到承包商面前说“地基打在这里，做成这个形状；噢，不对，改一下，厨房放这边客厅放那边；等等，还是换个位置吧”？显然后一种更合理。现在软件修改的成本已经大幅下降，接近于零，所以为什么还要花大量精力做昂贵的前期规划呢？规格说明是转瞬即逝的，会消失也会频繁变化，不等同于源代码。

### 对新生代开发者的忠告与软件基础

**大飞**: 最后是对新生代开发者的忠告，也是这场对谈里最值得深思的部分。

马特提到了欧斯特豪特关于战术编程和战略编程的区分：战术编程像地面作战的士官，负责具体战斗；战略编程像将军，从更高层面指挥整场战争。问题是Agent非常擅长战术却非常不擅长战略。那么刚入行的人，既然AI已经吞掉了大量战术性工作，该如何学习战略编程呢？

Bob大叔坦言他没有完美的答案，但是分享了他的想法：

首先，程序员学习编程的方式都应该是写代码，你应该先写上至少一年代码，这样才能真正知道Agent究竟在处理什么。

下一步，当你入职一家大量使用Agent的公司时，作为一个刚完成培训的年轻人，你应该被当作一个Agent来对待。那位手下运行着一堆Agent、自己负责战略决策的首席工程师，应该把你视作一个Agent，给你分配和Agent一样的任务，让你接受和Agent一样的确定性工具约束。你应该在这种状态下待上几个月，虽然产出很低，但是能学到非常多东西。等你通过了这种严酷考验，也许你才会被信任去亲自运行一个Agent。

他还强调，你不能完全丢掉代码。十年前他常告诉人们，如果你从来没有写过汇编语言，就应该花一个周末写写汇编，这样才能知道后台到底发生了什么。如果你整天只写Java，那你就是生活在一个幻觉世界里，那里仍然存在很多你不理解的魔法。这一点在今天依然成立。在这条学习路上，你必须从最基础的东西（比如二进制）开始，一路经过汇编语言、像C这样的基础编程语言、像Python这样的高级语言，然后进入处理Agent级别的工作，学习使用确定性工具，最后才能在监督下真正开始战略性地运行Agent。

他还推荐去读那些老书，比如**汤姆·德马科**（**Tom DeMarco**）、**埃德·约尔顿**（**Ed Yourdon**）的著作，以及《**程序员修炼之道**》（**The Pragmatic Programmer**）。这些书写于七八十年代，很多重要的经验和教训恰恰是在那个时候总结出来的。你需要过滤掉一些过时的内容，但很多核心的东西依然适用。

至于怎么判断Agent在犯错，Bob大叔说，早期他就是看着代码，发现里面的不好代码，但那其实不是最重要的部分；更重要的是他会看着Agent瞎忙，他能看出Agent什么时候在挣扎，因为作为一名程序员，他自己也经历过同样的挣扎。问题在于，一个刚入行的人可能根本识别不出这种挣扎，他是通过艰苦的实践学会这一点的。

最后回到“软件基础”这个核心话题。Bob大叔引用了**戴克斯特拉**（**Dijkstra**）的话：软件是人类迄今为止尝试过的最复杂的东西，比我们做过的任何其他事都要复杂。基础是我们组织复杂性的一种方式，让复杂的东西变得可以理解——不仅是让人类理解，也让模型理解，毕竟模型终究也是模仿人类建立起来的。

那些认为软件基础已经不重要的人，会吃到苦头，而且不会等太久。虽然可能比他想象的更久一点，因为Agent确实很厉害，但是他已经见过它们撞墙了，他知道那堵墙就在那里。每一次抽象层向上提升，从二进制到汇编，从汇编到编译器，从编译器到模型，处在更低层级的人都会抱怨说这会毁了一切、我们都没工作了、编程变得这么简单、五岁小孩都能写代码了……每一次都是同样的故事。但同样的规则依然适用，你今天扔掉的那些规则，一年之后很可能还是会从地上把它们捡起来，掸掉灰尘，重新想起为什么当初需要它们。

Bob大叔的这套实践和思考，本质上不是在说AI不行，也不是在说传统方法是万能的。他在说的是：**当代码的生成速度被大幅提升之后，组织复杂性的能力、判断代码质量的能力、识别Agent何时开始挣扎的能力，这些更高层面的东西非但没有过时，反而变得更加重要了**。那些以为有了AI就可以跳过基础的人，迟早会撞上那堵墙。

如果你对AI编程有什么想法，或者自己在实践中遇到什么困惑，欢迎在评论区聊聊。感谢收看，我们下期再见。