# 2026-01-31 无限软件危机与氛围编程：Netflix三阶段解法

\[2026-01-31] 无限软件危机与氛围编程：Netflix 三阶段解法

本工作流强调：批注为阅读时的火花（磨刀石比喻），整理仅为结构化与沉淀；产出是人类笔记，便于后续再勾连与二创。

***

### 1. 软件工程的核心

> 专注于管理复杂代码库与推动高质量工程实践。软件工程的核心。

**对应原文**：Jake Nations 至今在软件工程和大规模 AI/ML 系统设计领域拥有 13 年以上经验，专注于管理复杂代码库与推动高质量工程实践。在 Netflix，他负责推动技术架构与严谨开发流程，强调要理解系统本质、控制复杂性以及在 AI 时代保持代码和设计的可维护性。

***

### 2. 不能把「思考」外包出去

> 不能把「思考」这件事外包出去。

**对应原文**：我想带大家回顾一下，这种情况是如何发生的。首先，回顾历史，你会发现历史总是在重复。其次，我们其实掉进了一个陷阱：把「容易」和「简单」混为一谈。最后，我认为是有解法的，但前提是，我们不能把「思考」这件事外包出去。

***

### 3. 第一批面临无限生成规模的人

> 我们并不是第一批面临「软件危机」的人，但我们是第一批面临这种无限生成规模情况的人。

**对应原文**：过去几年，我在 Netflix 推动 AI 工具的落地应用，可以非常负责任地说，这种加速是真实存在的。……但问题在于，大型生产系统总是会以意想不到的方式出现故障。……说实话，我自己就干过这种事：生成了一大段代码，看了一眼，心里很清楚自己完全不知道它在干嘛。但测试过了，也能跑，那就先上线再说吧。这其实并不是什么新鲜事。每一代软件工程师最终都会遇到一个瓶颈：软件复杂度超出了他们的管理能力。

***

### 4. 太阳底下没有新鲜事

> 太阳底下没有新鲜事。

**对应原文**：这种循环不断上演。七十年代，我们有了 C 语言，可以构建更大的系统；八十年代，个人计算机普及，每个人都能写软件；九十年代，对象化编程盛行，继承层级复杂到失控，某种程度上「感谢」Java；进入新世纪，敏捷开发、冲刺、敏捷教练登场，瀑布模型被宣判「过时」；再后来是云计算、移动开发、DevOps，软件真正「吞噬了世界」。

***

### 5. 理解问题并设计出正确方案（金句）

> 还真是金句频出：理解问题本身，并设计出正确的解决方案。

**对应原文**：Fred Brooks 除《人月神话》作者之外，还写过一篇非常重要的论文，叫《没有银弹》（No Silver Bullet）。他在文中明确指出：不存在任何一种单一的技术创新，能够在软件生产率上带来数量级的提升。原因很简单：真正困难的部分，从来不是代码的机械层面，……而是理解问题本身，并设计出正确的解决方案。这一点，是任何工具都无法替代的。……我认为，答案就在两个我们经常混用的词上：简单和容易。

***

### 6. 容易 vs 简单：用当下速度换未来复杂度

> 人类天生就会选择容易的那条路。每一次我们选择容易，其实都是在用当下的速度，换未来的复杂度。

**对应原文**：Rich Hickey……认为，「简单」指的是结构上的单一、无纠缠，每个部分只做一件事，彼此之间不互相缠绕；而「容易」指的则是距离上的接近，是不是顺手、是不是不用费力就能拿到……简单关乎结构，容易关乎便利。问题在于，简单是无法靠「许愿」得到的，需要思考、设计和拆解。而容易却随处可得：装个包、让 AI 生成、从 Stack Overflow 抄一段代码。人类天生就会选择容易的那条路。……每一次我们选择容易，其实都是在用当下的速度，换未来的复杂度。……但 AI 打破了这个平衡。它把「容易」推向了极致，极致到我们甚至不再考虑「简单」这条路。

***

### 7. 第二十次迭代：从讨论设计到管理复杂上下文

> 到了第二十次迭代时，你已经不再是在「讨论设计」，而是在被迫管理一个极其复杂的上下文，甚至已经记不清自己到底引入过多少约束条件。

**对应原文**：当代码能瞬间生成时，为什么还要思考架构呢？通过对话一步步生成代码，看起来很自然，也很舒服，但它非常容易把一个本来简单的任务，演变成一团复杂的混乱。……到了第二十次迭代时，你已经不再是在「讨论设计」，而是在被迫管理一个极其复杂的上下文，甚至已经记不清自己到底引入过多少约束条件。代码库里开始出现来自废弃方案的死代码……（至）在真实的代码库里，这两种复杂度往往纠缠在一起，想要分离它们，需要对历史、上下文和经验的深刻理解。而 AI 并不会区分这些，它只会把所有模式一并保留下来。

***

### 8. 上下文压缩与 SICP 的呼应

> 我把这种方法称为「上下文压缩」，你也可以叫它「上下文工程」或「规格驱动开发」，名字并不重要。重要的是，思考和规划成为了工作的主体。「SICP：所用之物与所做之事的本质区别」Netflix 这个 case 很值得参考，尤其对于高复杂度的系统。

**对应原文**：问题在于，它无法看到表象之下的东西，无法区分业务逻辑在哪里结束、授权逻辑在哪里开始。所有东西都纠缠在一起，即使有完整的信息，AI 也找不到一条清晰的路径。当你的偶然复杂度到这种程度时，AI 不仅帮不上忙，反而只会在上面添加更多的层。……我其实是在写一个规格说明。五百万个 tokens 最终变成了两千字的规格说明。……我把这种方法称为「上下文压缩」，你也可以叫它「上下文工程」或「规格驱动开发」，名字并不重要。重要的是，思考和规划成为了工作的主体。

***

### 9. 方法论背后的本质：足够深入的理解

> 是方法论，也是本质。真正重要的，始终是那件最朴素、也最困难的事情：足够深入地理解你的系统，理解到你可以安全地对它做出修改为止。

**对应原文**：我依然认为，并不存在所谓的银弹。没有更好的提示词，没有万能的模型，甚至也不是写得更漂亮的规格文档。真正重要的，始终是那件最朴素、也最困难的事情：足够深入地理解你的系统，理解到你可以安全地对它做出修改为止。……这中间存在一个认知鸿沟。当 AI 可以在几秒钟内生成成千上万行代码时，理解这些代码却可能要花你几个小时；如果系统足够复杂，可能需要几天；甚至在极端情况下，你可能永远都无法真正理解它。

***

### 10. 直觉与坏味道：来自经验的模式识别

> 直觉 or 嗅觉，代码的坏味道 callback。当我坚持推动更简单的方案时，是因为我曾经接手并维护过别人留下的复杂系统。

**对应原文**：模式识别（pattern recognition）来源于经验。我一眼就能看出某种架构是危险的，那是因为我就那个曾经凌晨三点还在被它折磨的人；当我坚持推动更简单的方案时，是因为我曾经接手并维护过别人留下的复杂系统。

***

### AI 总结分析

你的十条批注形成一条清晰主线：**在「无限软件危机」下，软件工程的核心仍是理解与可控的复杂度，思考不能外包，而「容易」与「简单」的混淆被 AI 放大**。

* **定位（1、2）**：Jake 的职责——管理复杂代码库、高质量工程实践；前提——思考必须留在人这一侧。
* **时代感（3、4）**：每一代都有软件危机，但这一代第一次面对「无限生成规模」；历史在重复，工具在换，本质难度没变。
* **概念锚点（5、6）**：Brooks「理解问题、设计正确方案」与 Hickey「简单 vs 容易」被反复勾连；你的批注点出金句，并强调「选容易 = 用当下速度换未来复杂度」。
* **对话式 AI 的陷阱（7）**：迭代到后面不是在讨论设计，而是在管理复杂上下文与约束，AI 不区分本质/偶然复杂度，技术债在 AI 眼里只是「更多代码」。
* **解法（8、9）**：Netflix 的「上下文压缩/规格驱动」把五百万 tokens 压成两千字规格，让思考和规划成为主体；你联想到 SICP「所用之物与所做之事」的区分，并强调方法论奏效的前提是「先赢得理解」——没有银弹，本质仍是足够深入的理解。
* **人的不可替代（10）**：模式识别来自经验；能闻出坏味道、坚持更简单方案，是因为吃过苦、维护过别人的复杂系统，这是 AI 无法内化的。

整体上，批注把文章从「危机描述 + 三阶段方法」提炼成：**简单与容易的区分、本质/偶然复杂度的区分、以及「理解」作为人类核心职责**。适合作为后续写「AI 时代工程实践」或「复杂度与可维护性」时的磨刀石。

***

### 原文

来源：<https://www.infoq.cn/article/EA06AZH0wl5qpy9qiwPY>\
标题：Cursor 们疯狂生码，引爆无限软件危机！Netflix 大佬警告：氛围编程正把我们带向灾难，程序员得动脑子\
作者：褚杏娟，2025-12-24

***

在上世纪六十年代末，随着系统规模增长到开发者已无法有效掌控的程度，「软件危机」（Software Crisis）这一说法首次出现。此后，每一代人似乎都用更强大的工具「解决」了这场危机，但结果往往只是制造出了更大的问题。

Netflix 工程主管 Jake Nations 表示，如今，AI 正在把这一循环加速到一个新的阶段：无限软件危机（Infinite Software Crisis）。由 AI 生成的代码库，本质上是生成它们的那一连串曲折对话的映射。每一次澄清、每一次方向调整，都会被直接固化进系统架构中。我们正在用 vibe coding 的方式，一步步走向灾难。

Jake Nations 至今在软件工程和大规模 AI/ML 系统设计领域拥有 13 年以上经验，专注于管理复杂代码库与推动高质量工程实践。在 Netflix，他负责推动技术架构与严谨开发流程，强调要理解系统本质、控制复杂性以及在 AI 时代保持代码和设计的可维护性。

针对上述问题，Jake 认为解决之道只有一个：选择「简单」，而不是「容易」。一次冗长的对话很容易；而划分清晰、边界明确的独立阶段，才是真正的简单。他提出了一种三阶段方法论，并指出，当所有人都在以机器的速度竞相生成代码时，真正能够脱颖而出的工程师，是那些能够判断系统何时开始变得纠缠、复杂的人。在无限代码生成的时代，人类在最关键的节点上进行判断，将成为核心竞争优势。

下面是 Jake 的演讲分享，我们对此进行了翻译，并在不改变原意基础上进行了删减，以飨读者。

#### 我们正在交付自己并不真正理解的代码

我交付过一些自己其实并不完全理解的代码。这些代码是 AI 生成出来的，测试也跑过，上线也没出问题，但如果你让我解释它到底是怎么工作的，我说不清楚。说实话，我敢打赌，在座的每一个人都做过同样的事。

所以，不如我们干脆承认一个事实：我们现在都在交付自己并不完全理解的代码。

我想带大家回顾一下，这种情况是如何发生的。首先，回顾历史，你会发现历史总是在重复。其次，我们其实掉进了一个陷阱：把「容易」和「简单」混为一谈。最后，我认为是有解法的，但前提是，我们不能把「思考」这件事外包出去。

过去几年，我在 Netflix 推动 AI 工具的落地应用，可以非常负责任地说，这种加速是真实存在的。以前需要好几天才能完成的待办事项，现在几个小时就能搞定；那些在计划里躺了好几年的大型重构，终于开始被真正推进。

但问题在于，大型生产系统总是会以意想不到的方式出现故障。看看最近 Cloudflare 发生的事情就知道了。一旦真的出问题，你必须非常清楚自己正在调试的代码是怎么运作的。而现实是，我们现在生成代码的速度和规模实在太快了，理解能力已经明显跟不上了。

说实话，我自己就干过这种事：生成了一大段代码，看了一眼，心里很清楚自己完全不知道它在干嘛。但测试过了，也能跑，那就先上线再说吧。这其实并不是什么新鲜事。每一代软件工程师最终都会遇到一个瓶颈：软件复杂度超出了他们的管理能力。

我们并不是第一批面临「软件危机」的人，但我们是第一批面临这种无限生成规模情况的人。

#### 软件危机，一直在循环

如果我们把时间往前拨，你会看到类似的故事一再发生。

在上世纪六十年代末到七十年代初，一群当时最聪明的计算机科学家聚在一起，提出了一个判断：我们正身处一场软件危机之中。社会对软件的需求急剧增长，但我们的开发能力却严重跟不上，项目周期过长、效率低下，整体表现并不理想。

Edsger Dijkstra 曾有一句非常经典的话，大意是：当我们只有少量、性能很弱的计算机时，编程只是一个小问题；而当我们拥有了性能极其强大的计算机之后，编程反而变成了一个巨大的问题。他解释道，随着硬件性能提升了几个数量级，社会对软件的需求也成比例增长，最终压力就全部落在了程序员身上：我们必须在「手段」和「目标」之间找到支撑如此庞大软件体系的方法。

这种循环不断上演。七十年代，我们有了 C 语言，可以构建更大的系统；八十年代，个人计算机普及，每个人都能写软件；九十年代，对象化编程盛行，继承层级复杂到失控，某种程度上「感谢」Java；进入新世纪，敏捷开发、冲刺、敏捷教练登场，瀑布模型被宣判「过时」；再后来是云计算、移动开发、DevOps，软件真正「吞噬了世界」。

而今天，我们迎来了 AI。Copilot、Cursor、Claude、Codex、Gemini，只要你能描述清楚需求，代码几乎可以瞬间生成。模式没有变，但规模彻底变了：它已经是无限的了。

#### 难点从来不在「写代码」

Fred Brooks 除《人月神话》作者之外，还写过一篇非常重要的论文，叫《没有银弹》（No Silver Bullet）。他在文中明确指出：不存在任何一种单一的技术创新，能够在软件生产率上带来数量级的提升。

原因很简单：真正困难的部分，从来不是代码的机械层面，比如、输入、样板代码这些，而是理解问题本身，并设计出正确的解决方案。这一点，是任何工具都无法替代的。

我们过去发明的所有工具和方法，几乎都在让「机械部分」变得更容易，但核心挑战始终没有改变：我们仍然需要弄清楚到底该构建什么，以及它应该如何运作。

既然问题不在写代码本身，那为什么我们总是在优化这些「机械层面」的东西？为什么经验丰富的工程师，也会写出自己看不懂的代码？

我认为，答案就在两个我们经常混用的词上：简单和容易。

Rich Hickey，也就是 Clojure 语言的创造者，在他的演讲《Simple Made Easy》中，对这两个概念做过非常清晰的区分。他认为，「简单」指的是结构上的单一、无纠缠，每个部分只做一件事，彼此之间不互相缠绕；而「容易」指的则是距离上的接近，是不是顺手、是不是不用费力就能拿到，比如复制、粘贴、直接上线。

简单关乎结构，容易关乎便利。

问题在于，简单是无法靠「许愿」得到的，需要思考、设计和拆解。而容易却随处可得：装个包、让 AI 生成、从 Stack Overflow 抄一段代码。人类天生就会选择容易的那条路。但容易并不等于简单。容易意味着你可以很快往系统里加东西；简单意味着你能真正理解自己已经做过的事情。每一次我们选择容易，其实都是在用当下的速度，换未来的复杂度。

说实话，这种权衡在过去确实是有效的。复杂度积累得足够慢，我们还有机会通过重构、反思和重建来解决。但 AI 打破了这个平衡。它把「容易」推向了极致，极致到我们甚至不再考虑「简单」这条路。

#### 对话式 AI，正在放大复杂度

当代码能瞬间生成时，为什么还要思考架构呢？通过对话一步步生成代码，看起来很自然，也很舒服，但它非常容易把一个本来简单的任务，演变成一团复杂的混乱。

比如，我们有一个应用，想为它引入一套身份认证机制。我们对 AI 说：「加一个 OAuth 认证流程」，于是生成了一个看起来很干净的 oauth.js 文件。随着不断迭代，又多出来一些配套的处理文件，看起来一切似乎还算合理。接着，我们又提出新的需求：「还要支持另一种 OAuth 认证流程。」于是代码库里同时出现了 oauth.js 和 oauth2.js 两套实现。我们继续通过对话不断迭代，很快就发现会话管理开始出问题，各种冲突接踵而至。

到了第二十次迭代时，你已经不再是在「讨论设计」，而是在被迫管理一个极其复杂的上下文，甚至已经记不清自己到底引入过多少约束条件。代码库里开始出现来自废弃方案的死代码，有为了「先跑起来」而被强行修复的测试，还有来自三种不同解决思路的残留片段，因为每一次新的指令，都会在不知不觉中覆盖之前的架构决策。

我们说「让认证逻辑在这里生效」，它照做了；我们说「修复这个错误」，它同样完成了。但它对糟糕的架构决策本身没有任何约束或抵抗力，代码只会不断变形，以满足你最新提出的需求。

每一次对话，其实都在选择「容易」而不是「简单」。而「容易」的必然结果，就是复杂度不断叠加。AI 会机械地满足你的每一次最新指令，却不会对糟糕的架构决策产生任何阻力。

AI 真的把「容易」推向了逻辑极致：你想要什么，代码就能瞬间得到。但这里的危险在于，生成的代码会平等对待你代码库中的每一个模式。当智能体分析你的代码库时，每一行代码都会变成一个需要保留的模式：第 47 行的身份验证检查是一个模式，我 2019 年写的那段奇怪的、像 GraphQL 一样工作的 gRPC 代码也是一个模式。

技术债在 AI 眼里并不是「债」，只是更多的代码而已。

真正的问题在于复杂度。我知道我在演讲中反复提到这个词，却没有真正定义它，但最好的理解方式是：它是简单的对立面，本质就是「纠缠」。当系统变得复杂时，一切都会相互影响，你几乎无法只改一个地方而不波及其他部分。每一次交互都是在选择容易而非简单，而容易总是意味着更多的复杂度。我们其实知道更好的做法，但当容易的路这么容易走时，我们还是会选择它。复杂度会不断累积，直到为时已晚。

回到 Fred Brooks 的理论，他将系统中的复杂度分为两类：

* 第一类是本质复杂度（Essential Complexity），也就是问题本身的难度：用户要支付、订单要履约，这些决定了系统为什么存在。
* 第二类是偶然复杂度（Accidental Complexity），这是我们在实现过程中不断叠加上去的东西：临时方案、防御性代码、曾经合理但现在过时的框架和抽象。

在真实的代码库里，这两种复杂度往往纠缠在一起，想要分离它们，需要对历史、上下文和经验的深刻理解。而 AI 并不会区分这些，它只会把所有模式一并保留下来。

#### AI 真正需要的不是「更好的提示词」

有一个来自 Netflix 实际工作的例子。

我们有一个系统，在大约五年前写的旧授权代码和新的集中式 OAuth 系统之间建有一个抽象层。我们当时没有时间重建整个应用，所以就在两者之间加了一个适配层。现在有了 AI，这似乎是一个直接重构代码以使用新系统的好机会，对吧？但事实并非如此。

旧代码与它的授权模式耦合得太紧了：权限检查穿插在业务逻辑中，角色假设嵌入在数据模型里，OAuth 调用分散在数百个文件中。智能体会开始重构并处理了几个文件后，就会遇到无法梳理的依赖，然后要么失控放弃，要么更糟。它会试图保留旧系统中的一些现有逻辑，并使用新系统重新实现，我觉得这也很糟糕。

问题在于，它无法看到表象之下的东西，无法区分业务逻辑在哪里结束、授权逻辑在哪里开始。所有东西都纠缠在一起，即使有完整的信息，AI 也找不到一条清晰的路径。当你的偶然复杂度到这种程度时，AI 不仅帮不上忙，反而只会在上面添加更多的层。

但我们人类可以区分，至少当我们放慢速度思考时可以。我们知道哪些模式是本质的，哪些只是几年前某人的解决方案。我们掌握着 AI 可以推断但需要我们提前花时间区分的上下文。

那么具体该怎么做呢？当你面对一个庞大的代码库时，如何区分本质复杂度和偶然复杂度？

我在 Netflix 工作的代码库有大约一百万行 Java 代码，上次检查时大约有五百万个 tokens，我能访问的任何上下文窗口都装不下它。因此，在着手处理这个问题时，我最初的设想是，将代码库的大量内容直接复制到上下文中，看看模型能否自行识别出关键模式并理解系统结构。但结果就和之前的授权重构并无二致，生成的结果很快陷入了自身复杂度之中。

这迫使我不得不尝试另一种方法：我必须选择要包含的内容，如设计文档、架构图、关键接口等等，然后花时间写下组件应该如何交互以及要遵循的模式。

我其实是在写一个规格说明。五百万个 tokens 最终变成了两千字的规格说明。更进一步，我把这个规格说明转化为了一套精确的代码执行步骤，没有模糊的指令，只有精确的操作序列。我发现这样生成的代码更干净、更聚焦，因为我先定义了需求，再规划了执行过程。

我把这种方法称为「上下文压缩」，你也可以叫它「上下文工程」或「规格驱动开发」，名字并不重要。重要的是，思考和规划成为了工作的主体。让我给你们详细介绍一下这个方法在实践中是如何运作的。

#### 三阶段方法论

第一阶段：研究。我会把所有相关的东西都提供给 AI，包括架构图、文档、Slack 对话记录。

这一点我其实已经反复强调过很多次了，但核心只有一句话：尽可能把所有与你即将做出的修改相关的上下文一次性带进来，然后再使用智能代理去分析整个代码库，梳理系统的组成部分以及它们之间的依赖关系。

这绝对不是一次性完成的过程。我通常会不断追问，比如缓存是怎么处理的？失败场景是如何应对的？如果它的分析有误，我会直接纠正；如果它缺少关键信息，我就补充上下文。每一轮交互，都会让它的分析更加精细。

这一阶段的产出是一份完整的研究文档：系统里目前都有哪些东西、它们之间是如何相互连接的、你即将做出的改动会影响到哪些部分。原本需要花上好几个小时甚至更久的探索过程，被压缩成了几分钟的阅读时间。

我知道 Dex 之前也提到过这一点，但我还是要强调：这里的人工检查点（human checkpoint）至关重要。这是整个流程中投入产出比最高的时刻，你需要把分析结果与现实系统进行对照，在这里发现错误的话就能避免之后发生的灾难性后果。

第二阶段：制定可以「照着做」的实现计划。已经有了可靠研究结论的前提下，我们开始制定一份极其详细的实现计划，包括真实的代码结构、函数签名、类型定义、数据流等。

这份计划的目标，是做到任何一名开发者都可以直接照着执行。我常把它比作「数字填色」：你可以把它交给团队里最初级的工程师，对他说「照着这个来做」。只要他逐行照抄，最终结果就应该是正确可用的。

大量关键的架构决策，正是在这一阶段完成的。我们会在这里确保复杂逻辑是正确的，业务需求遵循良好实践，服务边界清晰，职责划分干净，同时避免任何不必要的耦合。之所以能在问题发生之前就识别它们，是因为我们曾经亲身踩过这些坑。而 AI 并没有这种经验，它会把代码中看到的每一种模式，都当作「必须遵守的约束」。

这一阶段真正的「魔法」，在于评审速度。我们可以在几分钟之内完成对整个方案的验证，并且清楚地知道接下来到底会构建出什么。而如果我们想跟上代码生成的速度，就必须以同样快的速度理解自己正在做的事情。

第三阶段：实现。最后才是实现，一旦我们有了清晰的研究结论和明确的实现计划，这一步反而应该是最简单的，而这正是我们希望看到的结果。

当 AI 有一份清楚、具体的规格说明可以遵循时，上下文就会保持干净且聚焦。我们避免了冗长对话导致的复杂度螺旋。相比五十轮不断「进化」的代码修改，现在只需要三次高度聚焦的输出，而且每一步都会在进入下一阶段前完成验证。没有被放弃的方案，没有相互冲突的模式，也不会再出现那种「等等，其实应该这样」的瞬间，没有留下遍地的死代码。

在我看来，这种方法真正的好处是：你可以把大量工作交给后台运行的智能体来完成。因为所有真正困难、需要动脑子的事情，已经提前由你完成了。智能体只需要按照计划开始实现。你可以去处理别的事情，回来时只需要快速评审结果，因为你检查的只是「它是否遵循了计划」，而不是试图弄清楚它是不是凭空「发明」了什么。

我们不是用 AI 来替我们思考，而是用它来加速机械性的工作，同时保持我们对代码的理解能力。研究更快了，规划更全面了，实施也更干净了。但思考、综合和判断，仍然是我们的责任。

还记得我之前说的那个 AI 无法处理的授权系统重构吗？现在我们实际上已经开始推进它，并且取得了一些实质性的进展。但这并不是因为我们找到了更好的提示词，恰恰相反，我们发现，连研究、规划、实现这些阶段都无法一开始就交给 AI。最终，我们不得不亲自下场，手工完成这次修改：不借助 AI，只是阅读代码、理解依赖关系，然后一步步改动，看哪里会出问题。

说实话，这次人工迁移过程非常痛苦，但至关重要。它揭示了所有隐藏的约束条件、必须遵守的不变式，以及一旦授权逻辑发生变化，哪些服务会直接崩溃。这些信息，是任何自动化代码分析都不可能替我们挖掘出来的。

然后，我们把这个手动迁移的拉取请求纳入了研究过程，让它作为后续所有研究工作的基础。即便如此，由于不同实体之间仍然存在差异，我们还是需要不断追问：这个该怎么处理、哪些数据是加密的哪些不是，每一次都要补充额外的上下文，并经过多轮迭代。

直到这时，我们才有可能生成一份「或许能一次成功」的计划。注意，这里的关键词是「或许」。我们仍然在持续验证、不断调整，并持续发现新的边界情况。

这套三阶段方法并不是什么魔法。它之所以能奏效，只是因为我们曾经亲手完成过一次迁移。在把理解写进流程之前，我们必须先赢得这种理解。

我依然认为，并不存在所谓的银弹。没有更好的提示词，没有万能的模型，甚至也不是写得更漂亮的规格文档。真正重要的，始终是那件最朴素、也最困难的事情：足够深入地理解你的系统，理解到你可以安全地对它做出修改为止。

那为什么还要折腾这一整套流程呢？为什么不干脆一直和 AI 反复迭代，直到「能用」为止？反正模型迟早会变得足够强，最后不就都能跑起来了吗？

在我看来，「能跑」本身并不够。通过测试的代码和能在生产环境长期稳定运行的代码之间，是有本质区别的；今天还能工作的系统，和未来还能被别人安全修改的系统，也是两回事。

这中间存在一个认知鸿沟。当 AI 可以在几秒钟内生成成千上万行代码时，理解这些代码却可能要花你几个小时；如果系统足够复杂，可能需要几天；甚至在极端情况下，你可能永远都无法真正理解它。

#### 软件，终究是一项人类的事业

还有一个我觉得几乎没人认真讨论过的问题：每一次为了跟上生成速度而跳过思考，我们失去的并不只是对代码的理解。我们正在逐渐丧失一种能力：识别问题的能力，那种会提醒你「等等，这里开始变复杂了」的直觉，如果你长期不真正理解自己的系统，是会慢慢退化的。

模式识别（pattern recognition）来源于经验。我一眼就能看出某种架构是危险的，那是因为我就那个曾经凌晨三点还在被它折磨的人；当我坚持推动更简单的方案时，是因为我曾经接手并维护过别人留下的复杂系统。

AI 只会生成你让它生成的东西，它并不会内化那些来自失败的教训。

三阶段方法，正是用来弥合这道鸿沟的。它把「理解」压缩成一系列可以在生成速度下被快速审查的产出物。如果没有这一层，我们只是在用一种自己无法理解的速度，不断累积复杂度。

AI 确实彻底改变了我们写代码的方式，但坦率地说，我并不认为但它并没有改变软件失败的根本原因。每一代人都会遭遇属于自己的软件危机。Dijkstra 那一代，通过建立软件工程这门学科来应对；而我们这一代，面对的是无限规模的代码生成。

答案并在于下一个工具或新的方法论，而在于重新记起一个我们早就知道的事实：软件始终是一项人类的事业。困难的从来不是敲代码，而是在一开始就知道该敲什么。

最终能够走得更远的开发者，并不只是那些生成代码最多的人，而是那些仍然理解自己在构建什么、能够看清系统接缝、敢于质疑问题本身是否正确的人。

我想用一个问题来结束今天的分享，这个问题并不是「我们会不会使用 AI」，那早已是既定事实。真正的问题是：当 AI 写下大部分代码的时候，我们是否仍然理解自己的系统？

参考链接：<https://www.youtube.com/watch?v=eIoohUmYpGI>
