Martin Fowler:软件工程的确定性终结了
“我认为这是我职业生涯中最重要的变革。”
说这话的人不是追风口的新秀。Martin Fowler,敏捷宣言联署人,《重构》作者,Thoughtworks 首席科学家,在软件工程领域站了三十年。他说”最重要”,不是修辞,是判断。
但真正刺穿认知的不是这句定性的话,而是紧跟着的半句:
“这次变革最大的特点,不是抽象层又提高了,而是我们从确定性的世界进入了非确定性的世界。”
这句话改变了整个讨论的坐标系。之前大家争论的是”AI 能不能写代码”,Fowler 把问题拉到了更底层——不是能力问题,是范式问题。同一套确定性思维,在非确定性世界里会系统性地失效。
这篇文章拆解 Fowler 对 AI 研发范式的完整思考:从根本性转变,到具体方法论,到工程师角色的重塑。
一、根本性转变:确定性终结
1.1 不是抽象层升级,是范式断裂
很多人把 LLM 等同于”从汇编到高级语言”的又一次抽象提升。Fowler 承认这个类比的方向——用 prompt 和 AI 对话,确实像从 PDP-11 机器指令跳到 Fortran 那样剧烈。但他随即指出一个被忽略的关键差异:
从汇编到高级语言,确定性没变。你写一个 Fortran 函数,编译一百次,出现的永远是同一组 bug。
LLM 打破了这个前提。同样的 prompt,今天生成的代码和明天可能完全不同。
Fowler 的同事 Birgitta Böckeler 把这总结得更精确:
“我们不只是沿着抽象层级往上走,我们同时向侧面滑入了非确定性。”
向上 + 向侧——这是一个 L 型的范式跳跃,不是线性的升级。
1.2 造桥的人早就知道这件事
Fowler 用他妻子——一位结构工程师——的工作来类比。土木工程从第一天起就在和非确定性打交道:木材的强度有波动,混凝土的配比有偏差,风载荷有随机性。所以结构工程师的核心概念叫容差——不按理论最优值设计,而是预留安全边际,为最坏情况做准备。
软件工程从来没有这个概念。数字电路的信号要么是 0 要么是 1,没有”大概”。Fowler 回忆入行时被教导:数字电子的独特之处就是没有容差。
现在有了。
LLM 的输出是概率性的。它可能声称”所有测试通过”但实际运行失败——Fowler 说,如果一个初级工程师表现出这种行为,HR 早就介入了。但在 LLM 的世界里,这是常态,不是异常。
1.3 非确定性的三个工程后果
后果一:测试套件的价值被侵蚀。 LLM 的非确定性输出导致测试时而通过时而失败。一旦工程师习惯性忽略间歇性故障,整个自动化测试体系就崩了——真正的 bug 也会被当作随机噪音。
后果二:质量问题的非判断性放大。 LLM 不加区别地放大。如果基础代码质量差,AI 生成的代码会放大这些问题。缺乏警惕,质量会逐渐下滑,直到代码库连 AI 自己都无法基于它构建。
后果三:调试归因困难。 在确定性世界里,错误是清晰可归因的。但当故障源于 LLM 的概率性推断,诊断和根因分析的难度大幅增加。
二、Vibe Coding vs Agentic Engineering:一条关键分界线
Fowler 引用 Simon Willison 的区分,划了一条硬线:
Vibe Coding——不看代码、不关心代码,让 AI 生成就完事。
Agentic Engineering——用 AI 生成代码,但建立系统化的验证和反馈机制。
2.1 Vibe Coding 不是完全没用
Fowler 承认 Vibe Coding 在特定场景有价值:一次性探索、快速原型、临时工具。这些场景的共同特点是——代码用完即弃,不需要维护。
但一旦项目超过几百行,Vibe Coding 就开始系统性地崩塌。AI 修一个 bug 的同时引入两个新 bug,代码变成黑盒,开发者无法理解也无法演进。
2.2 核心风险:切断学习循环
Fowler 反复强调一个概念——学习循环(Learning Loop)。
编程的本质是”想法 → 代码 → 反馈 → 修正”的循环。每一轮循环,开发者对系统的理解加深一分。这个理解不是文档能替代的——它是你面对需求变更时,知道改哪里、怎么改、改了会影响什么的直觉。
Vibe Coding 切断了这个循环。你不读代码,就不理解代码;不理解代码,就无法修改;无法修改,唯一的路就是推倒重来。
Fowler 举了一个真实案例:一位同事用 AI 生成了 SVG 图表,后来只需微调标签位置,打开源码一看——AI 生成的逻辑复杂得离谱,手写只需十几行的代码变成了无法维护的黑盒。
2.3 低代码平台的前车之鉴
Fowler 指出,这并非新问题。低代码平台也提供过”快速出活”的承诺,也在初期带来了生产力爆发。但它们同样切断了学习循环——开发者不理解平台内部的运作机制,无法持续演进系统,最终被技术债压垮。
“LLM 是有用的,因为它们降低了实验的门槛。但我们必须警惕,不要用它们来走捷径,绕过学习循环——那是软件开发实践的核心。”
三、Harness Engineering:驾驭 AI 的工程方法论
如果说前两节是诊断,这一节是处方。
3.1 Agent = Model + Harness
2026 年初,Mitchell Hashimoto(Terraform 创造者)提炼出一个公式:
Agent = Model + Harness
模型是推理引擎,Harness 是除此之外的一切——系统提示词、代码检索机制、编排系统、约束文件、验证流程。
Fowler 的同事 Birgitta Böckeler 在 martinfowler.com 发表了完整的 Harness Engineering 文章,Fowler 进一步引入了精确的分类体系。
3.2 Guides 和 Sensors:前馈与反馈
Harness 由两类控制组成:
Guides(前馈控制)——在 AI 行动之前约束和引导它。系统提示词、AGENTS.md、约束文档、编码规范都是 Guides。它们提高 AI 第一次就做对的概率。
Sensors(反馈控制)——在 AI 行动之后观察和纠正它。测试、Linter、类型检查、代码审查都是 Sensors。它们帮助 AI 自我修正。
关键洞察:两者缺一不可。 只有 Guides 没有 Sensors,AI 会编码规则但永远不知道规则是否生效;只有 Sensors 没有 Guides,AI 会不断犯同样的错误。
3.3 计算型 vs 推理型:确定性与非确定性的二次划分
Fowler 进一步把 Guides 和 Sensors 按执行方式分为两类:
计算型——确定性、快速、由 CPU 执行。测试、Linter、类型检查、结构分析。毫秒到秒级完成,结果可靠。
推理型——语义分析、AI 代码审查、”LLM as Judge”。由 GPU/NPU 执行,更慢更贵,结果具有非确定性。
|
|
|
|
|---|---|---|
| 计算型 |
|
|
| 推理型 |
|
|
Fowler 的核心建议:能用计算型解决的,不要用推理型。 一旦某个规则可以形式化为确定性的检查,就把它从推理型转化为计算型——这能给你更多保证。
Birgitta 的实验证实了这一点:静态分析对 AI Agent 比对人类更有用,因为 AI 会认真处理每一个警告,不会像人类那样偷懒忽略。
3.4 转向循环:人的新角色
在 Harness Engineering 中,人的核心工作不是写代码,而是持续迭代 Harness。
每当 AI 反复出现某个问题,就改进 Guides 或 Sensors,让这个问题在未来更不可能发生。Fowler 把这叫转向循环(Steering Loop):
问题出现 → 诊断 Harness 缺陷 → 改进 Guide 或 Sensor → 问题消失或减少
这个循环中,AI 本身也可以帮助改进 Harness——写结构测试、从观察到的模式生成规则、搭建自定义 Linter、从代码考古中提取指南。
3.5 OpenAI 的百万行实验
2025 年 8 月起,OpenAI 做了一个极端实验:3 名工程师,5 个月,100 万行代码,零手写。连 AGENTS.md 都是 AI 写的。
结果:平均每人每天合并 3.5 个 PR,且吞吐量随团队扩大而增长。
关键变量不是模型——GPT-4 从头用到尾,模型没变。变的是 Harness。
他们的 Harness 包含三层:
-
上下文工程——知识库 + 动态上下文(可观测性、浏览器)
-
架构约束——LLM 驱动 + 确定性 Linter + 结构测试
-
垃圾回收——定期 Agent 扫描文档不一致、约束违规,对抗熵增
核心哲学:当 Agent 遇到困难时,把它当作信号——识别缺少什么(工具、护栏、文档),然后反馈回仓库,让 Agent 自己写修复。
四、What/How 循环:编程的本质没有变
Fowler 和 Unmesh Joshi、Rebecca Parsons 的三人对话,把讨论拉回了更本质的层面。
4.1 编程是什么
编程的核心是映射:把领域概念的”做什么”(What)映射到计算模型的”怎么做”(How)。这个映射不是一次性的,而是在持续反馈循环中迭代建立的。
TDD 本质上是把这个循环操作化了:先写测试表达 What,再写实现表达 How,测试结果提供反馈,驱动下一轮迭代。
4.2 LLM 在循环中的位置
LLM 是这个循环中的翻译层——它能在已有的抽象体系内高效生成代码,但它不能替代人类建立稳定抽象的工作。
Fowler 的核心判断:
“Prompt 本身满足了一个场景,但没有构建解决方案的结构来适应未来的场景。”
LLM 依赖成熟度。如果一种语言不够成熟,或者你在探索新范式,LLM 的训练数据就不够,它就不够用。人类可以用 LLM “幻觉出一些奇怪但有潜力的东西,然后在上面构建”,但必须由人类迭代地驱动代码,构建稳定的结构。
4.3 函数长度问题的 AI 时代答案
Adam Tornhill 在 Fowler 的网站上讨论了一个经典问题:函数应该多长?
在 AI 时代,这个问题有了新维度。研究表明,当有意义的标识符被替换为任意名称时,LLM 的性能显著下降。当前模型严重依赖字面特征——名称、结构和局部上下文——而非推断的语义。
Fowler 的结论没变,但理由更充分了:函数的关键不是行数,而是意图与实现的分离。如果你需要花精力看一段代码才能搞清楚它在做什么,就把它提取成函数,用函数名表达那个”做什么”。
在 AI 时代,这个原则有了额外的工程意义:良好的函数边界不仅是给人读的,也是给 AI 读的。AI 依赖显式表达,函数名就是最重要的显式信号。
五、工程师角色的重塑
方法论讲完了。但方法论最终要落到人身上——工程师的角色正在发生什么变化?
5.1 从写代码到审核 Diff
Fowler 引用 Chris Parsons 的话,直指一个正在发生的现实:
“如果你是一位高级工程师,担心你的工作正在悄悄变成审批 diff——确实如此。”
这不是悲观,是事实。但 Fowler 给出了出路:
“出路是训练 AI 让 diff 第一次就是对的,让自己成为塑造 Harness 的人,让这项工作成为你被衡量的可见成果。这个角色会像复利一样增长,而审查永远不会。”
5.2 验证重于生成
Fowler 在 2025 年 3 月写下的原则,到 2026 年 4 月仍然成立,但有一个关键演进:
2025 年:”每个变更在发布前必须经过验证。”
2026 年:”验证”的含义变了。以前是”你亲自读过”。现在 Agent 的吞吐量太大了,验证必须意味着”被测试、类型检查器、自动化门禁检查过,或者在你判断重要的地方由你亲自检查”。
检查仍然发生,只是不总是发生在你脑子里。
Chris Parsons 的总结更锋利:
“一个能在下午生成五个方案并验证全部五个的团队,会超越一个只生成一个方案然后等一周反馈的团队。游戏不再是’我们能多快构建’,而是’我们能多快判断这是否正确’。”
5.3 六种 AI 研发方法论的光谱
Fowler 的团队评估了当前主流的 AI 研发方法论,从最自由到最约束:
|
|
|
|
|
|---|---|---|---|
| Vibe Coding |
|
|
|
| Spec-Driven Dev |
|
|
|
| Agentic Engineering |
|
|
|
| Harness Engineering |
|
|
|
| Design-First |
|
|
|
| Human-in-the-Loop |
|
|
|
Fowler 对 Spec-Driven Development 的批评尤其值得注意。他的团队发现了六个系统性问题:工作流过于僵硬(修个 typo 也要走完整规格流程)、审查疲劳(审 markdown 比审代码还累)、脆弱控制(AI 经常忽略或过度解读规格)、规格漂移(规格和代码必然分化)、受众不清、以及历史重演——SDD 和 2000 年代的模型驱动开发(Model-Driven Development,用高层抽象模型自动生成代码)如出一辙,同样的承诺,同样的陷阱。
六、Fowler 没有回答的问题
Fowler 诚实地承认了他不知道的事情。
“编程的未来是什么?”——”我不知道。而且我认为任何声称知道的人,都在从不恰当的孔说话。”
“AI 是不是泡沫?”——”当然是泡沫。所有重大技术进步都伴随着经济泡沫,从运河到铁路到互联网。我们知道这个泡沫几乎 100% 会破,但我们不知道什么时候破,因此不知道它在此之前会长多大,产生多少真实价值。”
“初级工程师会被淘汰吗?”——”不知道。但我们知道的是:如果 Vibe Coding 切断了学习循环,就没有人能成长为高级工程师。”
这三个”不知道”比任何确定性的断言都更有价值。它们划出了认知的边界——在这个边界之内,Fowler 给出了精确的方法论;在这个边界之外,他选择诚实。
软件工程的确定性终结了。
但 Fowler 说的不是”终结”,是”转变”。确定性没了,但工程思维没有消失——它只是换了一种形式。从”保证正确”变成”管理不确定性”,从”写代码”变成”构建让 AI 正确写代码的环境”,从”我验证”变成”系统验证”。
造桥的人早就知道怎么在不确定的世界里建确定的东西。现在轮到写代码的人学这门课了。
Fowler 在 2025 年 6 月的文章结尾写了一句话,既是判断,也是邀请:
“这种非确定性的演进,在我们职业的历史上是前所未有的。这让我相当兴奋。”
夜雨聆风