“我写了连我自己都看不懂的代码,我敢打赌你肯定也干过”——Jake Nations, Netflix

AAI Engineer
컴퓨터/소프트웨어경영/리더십AI/미래기술

Transcript

00:00:00[音乐]
00:00:21>> 嘿,大家好,下午好。
00:00:22在演讲开始前,我先来做个小小的坦白。
00:00:26我曾经交付过一些连我自己都不太理解的代码。
00:00:29生成代码,测试,部署,但我却解释不清它的工作原理。
00:00:33但关键在于,我敢打赌你们每一个人也都这么干过。
00:00:37>> [笑声]
00:00:40>> 既然我们都承认不再能完全理解自己交付的代码了,
00:00:41那么我想带大家回顾一下,看看这种情况是如何发生的。
00:00:44首先,回顾历史,我们会发现历史总是在重演。
00:00:46其次,我们陷入了一个陷阱。
00:00:50我们混淆了“容易”和“简单”这两个概念。
00:00:52最后,问题是有解决办法的,但这需要我们不再外包自己的思考。
00:00:55过去几年,我在 Netflix 致力于推动 AI 工具的应用。
00:01:00我不得不说,这种加速效应是非常真实的。
00:01:05以前需要几天才能处理完的积压任务,现在只需几小时。
00:01:07那些挂账多年的大型重构项目,也终于动工了。
00:01:10但问题也随之而来。
00:01:15大型生产系统总是会以意想不到的方式崩溃。
00:01:16看看最近 Cloudflare 发生的事故就知道了。
00:01:19当故障发生时,你最好能理解你正在调试的代码。
00:01:21而现在的麻烦是,我们生成代码的速度和规模实在太快了。
00:01:23我们的理解力已经快跟不上这种节奏了。
00:01:28天知道,我自己也感同身受。
00:01:29我生成了一堆代码,看着它们心想:我完全不知道这是干嘛的。
00:01:34但既然测试通过了,能跑通,我就直接上线了。
00:01:39其实,这种现象并不新鲜。
00:01:41每一代软件工程师最终都会遇到瓶颈,
00:01:44即软件的复杂度超出了他们的管理能力。
00:01:48我们不是第一代面临“软件危机”的人,
00:01:50但我们是第一代在如此“无限规模”的自动化生成面前面临危机的人。
00:01:52让我们退后一步,看看这一切是从哪里开始的。
00:01:56在 60 年代末、70 年代初,当时的一群聪明顶顶的计算机科学家聚在一起说,
00:01:58嘿,我们正处于一场软件危机中。
00:02:03市场对软件的需求巨大,而我们却根本无法跟上进度。
00:02:06项目周期太长,进展极其缓慢。
00:02:11我们的工作做得不够好。
00:02:15于是 Dijkstra 留下了那段著名的名言。
00:02:16他说,当我只有几台性能微弱的计算机时,(我转述一下那段长文)
00:02:20编程只是一个小问题。
00:02:23而现在我们拥有了巨型计算机,编程也随之变成了一个巨型问题。
00:02:26他是在解释,虽然硬件性能增长了 1000 倍,
00:02:31社会对软件的需求也按比例同步增长了。
00:02:34这就留给了我们这些程序员一个难题:如何用有限的手段来支撑这种爆发式增长?
00:02:37这种循环一直在发生。
00:02:4170 年代我们有了 C 语言,于是可以编写更大的系统。
00:02:4380 年代个人电脑普及,每个人都能写代码。
00:02:4790 年代我们迎来了面向对象编程。
00:02:50还有 Java 带来的那些令人头疼的继承层级。
00:02:532000 年代出现了敏捷开发,
00:02:56有了冲刺周期和 Scrum 大师来发号施令,瀑布模型消失了。
00:03:002010 年代是云、移动端和 DevOps 的天下,
00:03:03软件真正“吞噬了世界”。
00:03:06而今天,我们有了 AI:Co-Pilot, Cursor, Claude, Codex, Gemini 等等。
00:03:09我们生成代码的速度已经和描述需求的速度一样快了。
00:03:10模式仍在继续,但规模已经发生了质变,现在是无限生成的时代。
00:03:17Fred Brooks,你们可能知道他写了《人月神话》。
00:03:19他在 1986 年还写了一篇论文叫《没有银弹》。
00:03:23在文中,他断言没有任何单一的技术创新
00:03:29能让软件生产力产生数量级的提升。
00:03:32为什么?
00:03:36因为他认为最难的部分并不是编码的技巧、语法、打字或模板代码。
00:03:38而是真正理解问题并设计解决方案。
00:03:40没有任何工具可以消除这种根本性的困难。
00:03:44迄今为止我们创造的所有工具和技术,都只是让编码的“机械过程”变得更容易。
00:03:45但核心挑战——搞清楚该构建什么,以及它如何运作——依然很难。
00:03:49既然问题不在机械操作上,为什么我们还要一直针对它进行优化呢?
00:03:52资深工程师又是如何落得理解不了自己代码的境地的?
00:03:55我认为答案在于我们经常混淆的两个词:“简单 (Simple)”和“容易 (Easy)”。
00:03:57我们倾向于交替使用它们,
00:04:00但它们的含义完全不同。
00:04:06在昨晚的讲师晚宴上,我被曝光是个 Clojure 迷,
00:04:09所以这一点对我来说很清晰。
00:04:14Clojure 语言的创始人 Rich Hickey 在他 2011 年的演讲
00:04:16《Simple Made Easy》中对此做了解释。
00:04:18他定义“简单”意味着单一,没有交织纠缠。
00:04:21每个部分只做一件事,不与其他部分纠缠在一起。
00:04:23而他定义的“容易”意味着近在咫尺,触手可及。
00:04:25就是那些不费吹灰之力就能获取的东西。
00:04:29复制,粘贴,交付。
00:04:33“简单”关乎结构,“容易”关乎便利。
00:04:36事实是,我们无法仅仅靠许愿就让事情变得“简单”。
00:04:39“简单”需要思考、设计和解耦。
00:04:41但我们总能让事情变得更“容易”。
00:04:43只要把它放得近一点就行。
00:04:45安装个包,用 AI 生成,或者从 Stack Overflow 抄一段答案。
00:04:48追求“容易”是人类的天性。
00:04:51我们的基因就是这样设定的。
00:04:54就像我说的,从 Stack Overflow 抄代码,因为它就在那儿。
00:04:56用那些通过底层魔法帮你处理好一切的框架,装上就能跑。
00:04:57但“容易”不代表“简单”。
00:05:03“容易”意味着你可以快速往系统里塞东西。
00:05:06“简单”意味着你可以理解你所做的工作。
00:05:07每次选择“容易”,我们都是在用当下的速度换取未来的复杂度。
00:05:10老实说,这种权衡以前确实行得通。
00:05:14代码库中积累复杂度的速度足够慢,
00:05:15让我们在需要时有时间去重构、反思和重建。
00:05:18但我认为 AI 打破了这种平衡。
00:05:20因为它就是那个终极的“一键容易”按钮。
00:05:24它让“容易”这条路变得如此顺滑,以至于我们甚至不再考虑“简单”那条路。
00:05:27既然代码可以瞬间生成,为什么还要去思考架构?
00:05:31让我给你们演示一下这是如何发生的。
00:05:34一个简单的任务是如何在我们都喜爱的对话界面中
00:05:36演变成一团乱麻的。
00:05:37这是一个人为构思的例子,假设我们有个应用,
00:05:38我们想加个身份验证功能。
00:05:41输入“添加 auth”,我们得到了一个整洁的 auth.js 文件。
00:05:44迭代几次,到了第五轮对话。
00:05:47你说:好吧,现在再加上 OAuth 吧,
00:05:50于是我们有了 auth.js 和 OAuth.js。
00:05:52继续迭代,发现 Session 机制坏了。
00:05:55出现了一堆冲突。
00:05:57等你进行到第 20 轮对话时,那已经不是在讨论了。
00:06:01你是在管理一个复杂到连你自己都记不清所有约束条件的“上下文”。
00:06:02那些废弃方案留下的死代码。
00:06:04那些为了“能跑就行”而强行修好的测试。
00:06:07三种不同解决方案的残骸碎片,因为你最后反悔了。
00:06:11每一条新指令都在破坏原本的架构模式。
00:06:12我们说让这里的身份验证跑通,它做到了。
00:06:15我们说修复这个错误,它也做到了。
00:06:18系统对错误的架构决策完全没有抵抗力。
00:06:20代码只会不断变形以满足你最新的请求。
00:06:22每一次交互都是在选择“容易”而非“简单”。
00:06:25而“容易”总是意味着更高的复杂度。
00:06:28我们心知肚明,但当这条路走起来如此轻松时,我们还是会选它。
00:06:31复杂度会不断累积,直到积重难返。
00:06:33AI 真正将“容易”推向了逻辑上的极致。
00:06:35决定你想要的,瞬间得到代码。
00:06:38但其中蕴含着危险。
00:06:40生成的代码对你代码库中的所有模式都一视同仁。
00:06:43当 AI 代理分析你的代码库时,每一行都会被视为需要保留的模式。
00:06:46第 47 行的身份验证检查?那是一个模式。
00:06:50我 2019 年随手加的那些把 gRPC 伪装成 GraphQL 的古怪代码?
00:06:52那也是一个模式。
00:06:58技术债在它眼里不是债,只是更多的代码而已。
00:07:00真正的痛点在于复杂度。
00:07:02我知道我在这次演讲中一直提到这个词,却没给它下个定义。
00:07:06理解它最好的方式就是:它是“简单”的反面。
00:07:10它意味着交织纠缠。
00:07:13当事情变得复杂,所有东西都会牵一发而动全身。
00:07:18你没法在改动一个地方的同时不影响到另外十个地方。
00:07:19回到 Fred Brooks 的《没有银弹》。
00:07:22他在文中指出,每个系统中都有两种主要的复杂度。
00:07:25一种是“本质复杂度 (Essential complexity)”,这是你试图解决的问题
00:07:29本身所固有的根本难度。
00:07:31用户需要付费,订单必须履行。
00:07:33这是你的软件系统存在的初衷所带来的复杂度。
00:07:36第二种是所谓的“偶然复杂度 (Accidental complexity)”。
00:07:41即我们一路走来添加的所有其他东西:权宜之计、防御性代码、
00:07:43框架、以及曾经合理但现在过时的抽象。
00:07:47这些都是为了让代码跑起来而拼凑出的东西。
00:07:51在真实的生产代码中,这两种复杂度无处不在。
00:07:53它们紧紧纠缠在一起,想要剥离它们需要背景知识、
00:07:56历史经验和洞察力。
00:08:00而生成的输出完全不做这种区分。
00:08:03因此,每一个旧模式都在被不断延续。
00:08:06这里有一个我们在 Netflix 遇到的真实案例。
00:08:09我接手的一个系统,在五年前写的旧授权代码
00:08:11和新的集中式认证系统之间有一个抽象层。
00:08:16当时我们没时间重构整个应用,
00:08:19所以只是加了个中间层(Shim)。
00:08:20现在有了 AI,这本该是重构代码以直接使用新系统的绝佳机会,
00:08:24看起来是个很简单的请求,对吧?
00:08:26但结果并非如此,旧代码与它的授权模式耦合得太深了,
00:08:32权限检查被编织在业务逻辑中,
00:08:35角色假设被固化在数据模型里,授权调用散落在数百个文件中。
00:08:41AI 代理开始重构,改了几个文件后,
00:08:42就遇到了无法解开的依赖,然后彻底失控并放弃。
00:08:44或者更糟,它会试图保留旧系统的一些逻辑,
00:08:47并在新系统中重新实现一遍,我觉得这也很糟糕。
00:08:50问题是,它看不出其中的界限。
00:08:56它无法分辨业务逻辑在哪里结束,授权逻辑在哪里开始。
00:08:59一切都纠缠在一起,即使拥有完整的信息,
00:09:03AI 也找不到一条清晰的路径。
00:09:07当你的“偶然复杂度”纠缠到这种程度时,
00:09:10AI 并不是帮你把事情变好的最佳选择。
00:09:16我发现它只会往上面再加几层负担。
00:09:19我们人类能看出区别,或者说至少当我们慢下来思考时能看出区别。
00:09:23我们知道哪些模式是本质的,
00:09:26哪些只是几年前某人的临时方案。
00:09:30我们掌握着 AI 无法推断出的上下文,
00:09:33前提是我们要在动手前花时间做好这些区分。
00:09:35那么具体该怎么做呢?
00:09:38当你面对一个庞大的代码库时,
00:09:40该如何剥离偶然复杂度和本质复杂度?
00:09:45我在 Netflix 维护的代码库大约有 100 万行 Java 代码,
00:09:47其中的核心服务上次检查时大约有 500 万个 Token。
00:09:50我能接触到的任何上下文窗口都装不下它。
00:09:53所以当我想要处理它时,我起初想,嘿,
00:09:56也许我可以把大段大段的代码复制到上下文中,
00:10:01看看某种模式是否会浮现,
00:10:04看看它能否自行理清到底发生了什么。
00:10:07结果就像之前那个身份验证重构的例子一样,
00:10:10输出结果迷失在了自身的复杂度中。
00:10:13因此我被迫尝试不同的方法。
00:10:17我必须筛选要包含的内容:设计文档、架构图、
00:10:19关键接口等等。
00:10:23并花时间写下组件应该如何交互的要求,以及要遵循的模式。
00:10:24实际上,我是在编写一份规格说明(Spec)。
00:10:26500 万个 Token 被浓缩成了 2000 字的规格说明。
00:10:29结果输出迷失在了自身的复杂性之中。
00:10:31因此,我被迫采取不同的方法。
00:10:34我必须筛选要包含的内容:设计文档、架构图、
00:10:37关键接口等等。
00:10:39并花时间写下组件应如何交互、
00:10:42以及应遵循哪些模式的要求。
00:10:43看,我当时其实是在编写规格说明书。
00:10:45500 万个 Token 变成了 2,000 字的规范。
00:10:49然后更进一步,根据该规范
00:10:52创建一套精确的待执行代码步骤。
00:10:55没有模糊的指令,只有精确的操作序列。
00:10:58我发现这样生成的代码更简洁、更专注,我也能理解。
00:11:02所以我先进行定义,并规划其执行过程。
00:11:05这就是我前阵子称之为“上下文压缩”的方法。
00:11:11但你也可以叫它上下文工程,或者开发中的频谱分析,
00:11:13随你怎么称呼。
00:11:15名字并不重要。
00:11:16唯一重要的是,思考和规划占据了工作的大部分。
00:11:20让我向大家介绍一下这在实践中是如何运作的。
00:11:22首先是第一步,第一阶段:研究。
00:11:26我会预先提供所有资料。
00:11:28架构图、文档、Slack 聊天记录。
00:11:31这些我们已经讨论过很多次了。
00:11:32但关键是尽可能带入所有
00:11:35与你即将进行的更改相关的上下文。
00:11:36然后利用智能代理分析代码库,
00:11:39梳理出组件和依赖关系。
00:11:42这不该是一个一蹴而就的过程。
00:11:43我喜欢不断试探,比如问:“缓存怎么处理?”
00:11:46“如何处理故障?”
00:11:47当它的分析出错时,我会纠正它。
00:11:49如果它缺少上下文,我就补充给它。
00:11:51每一次迭代都会完善它的分析。
00:11:55这里的产出是一份单一的研究文档。
00:11:57记录了:现有的内容、各部分的连接方式、
00:11:59以及你的更改会产生什么影响。
00:12:01数小时的探索被压缩成了几分钟的阅读量。
00:12:03我知道 Dex 今天早上提过,但这里的人工检查环节至关重要。
00:12:09这是你根据现实情况验证分析的地方,
00:12:12也是整个过程中杠杆率最高的时刻。
00:12:15在这里发现错误,可以防止以后发生灾难。
00:12:17接下来进入第二阶段。
00:12:20现在你手中有了经过验证的研究结果,
00:12:22我们要制定详细的实施计划,包括实际的代码结构、
00:12:25函数签名、类型定义和数据流。
00:12:28你希望这个计划详细到任何开发者都能遵循。
00:12:30我把它比作“按数字填色”。
00:12:32你应该能把它交给最初级的工程师并告诉他:“照着做”。
00:12:35如果他们逐行复制,代码就应该能直接运行。
00:12:38在这一步,我们会做出许多重要的架构决策。
00:12:43确保复杂的逻辑是正确的。
00:12:45确保业务需求遵循了良好的实践。
00:12:50确保有良好的服务边界、清晰的隔离,
00:12:52并防止任何不必要的耦合。
00:12:54我们在问题发生前就发现它们,因为我们亲历过。
00:12:57AI 没有这个能力。
00:12:59它把看到的每一个模式都视为必须遵循的要求。
00:13:01这一步真正的魔力在于评审速度。
00:13:05我们可以在几分钟内验证该计划,并准确知道将要构建什么。
00:13:10为了跟上我们想要生成代码的速度,
00:13:13我们也必须能以同样的速度理解我们正在做的事情。
00:13:18最后,我们进行实施。既然已经有了清晰的计划
00:13:22和明确的研究支持,这个阶段应该非常简单。
00:13:26而这正是重点所在。
00:13:28当 AI 有明确的规范可以遵循时,上下文就会保持整洁且聚焦。
00:13:32我们防止了长时间对话带来的复杂性螺旋。
00:13:36我们不再需要 50 条消息来演进代码,
00:13:38而是只有三个聚焦的产出,且每个产出在继续前都经过了验证。
00:13:41没有被遗弃的方法,没有冲突的模式,
00:13:44也没有那种“等等,其实……”的时刻,导致到处留下废弃代码。
00:13:48对我来说,这带来的真正回报是你可以使用后台代理
00:13:52来完成大部分工作,因为你已经预先完成了所有的思考和艰苦工作。
00:13:56它可以直接开始实施,你可以去做别的事情,
00:13:59然后再回来评审。
00:14:01你可以快速评审,因为你只是在验证它是否符合你的计划,
00:14:04而不是试图搞清楚它是否胡乱发明了什么。
00:14:07这里的关键是,我们并不是在让 AI 替我们思考。
00:14:12我们是在利用它来加速机械性的部分,
00:14:15同时保持我们理解它的能力。
00:14:17研究更快了,规划更周密了,实施也更简洁了。
00:14:21但是,思考、综合和判断,这些仍然掌握在我们手中。
00:14:26还记得我说过 AI 无法处理的那个权限重构吗?
00:14:34事实是,我们现在正在着手处理它,
00:14:37并且已经开始取得一些进展了。
00:14:39但这并不是因为我们找到了更好的提示词。
00:14:42我们发现甚至无法直接跳入任何研究、规划和
00:14:45实施阶段。
00:14:46我们实际上必须亲手进行这项更改。
00:14:49没有 AI,只是阅读代码,理解依赖关系,
00:14:52并进行更改看看会出什么问题。
00:14:53老实说,那次手动迁移非常痛苦,但至关重要。
00:14:59它揭示了所有隐藏的约束、哪些不变性必须保持,
00:15:02以及如果权限更改,哪些服务会崩溃。
00:15:05这些东西,无论多少代码分析都无法替我们挖掘出来。
00:15:09然后我们将那次手动迁移的拉取请求输入到研究流程中,
00:15:14将其作为后续任何研究的种子。
00:15:19这样 AI 就能看到一次干净的迁移应该是怎样的。
00:15:23问题是,每个实体都略有不同,所以我们必须去
00:15:27询问它,说:“嘿,这个该怎么办?”
00:15:29有些内容是加密的,有些则不是。
00:15:32我们必须通过多次迭代,每次都提供额外的上下文。
00:15:35然后,也只有在那个时候,我们才能生成一个可能一次性成功的计划。
00:15:41这里的关键词是“可能”,我们仍在验证、
00:15:45仍在调整,也仍在发现边缘案例。
00:15:47三阶段方法并非灵丹妙药。
00:15:55它之所以奏效,仅仅是因为我们亲手完成了一次迁移。
00:15:57在将理解编码到流程中之前,我们必须先赢得这种理解。
00:16:01我仍然认为没有银弹。
00:16:02我不认为会有更好的提示词、更好的模型,甚至是写出更好的规范。
00:16:06只有深入了解你的系统,
00:16:09才能安全地对其进行更改。
00:16:11那么,为什么要费这么大劲呢?
00:16:15为什么不直接让 AI 迭代到成功为止?
00:16:18最终模型会变得足够强大,一切都会迎刃而解。
00:16:21对我来说,“能跑通”是不够的。
00:16:24能通过测试的代码与能在生产环境中存活的代码之间是有区别的。
00:16:28在今天能运行的系统与
00:16:31未来能被他人修改的系统之间,也存在区别。
00:16:34真正的挑战在于知识鸿沟。
00:16:38当 AI 可以在几秒钟内生成数千行代码时,
00:16:41理解这些代码可能需要你花几个小时,如果很复杂,甚至要花几天。
00:16:45谁知道呢,如果真的那么乱,可能永远也理解不了。
00:16:48这里有一点我认为目前还没什么人讨论过。
00:16:52每当我们为了赶上生成速度而跳过思考时,
00:16:56我们不仅仅是在添加不理解的代码。
00:16:58我们还在丧失识别问题的能力。
00:17:00那种直觉——“嘿,这变得太复杂了”——
00:17:03当你不再理解自己的系统时,这种直觉就会萎缩。
00:17:09模式识别源于经验。
00:17:11我能识破危险的架构,
00:17:12是因为我曾在凌晨三点爬起来处理过它。
00:17:16我推行更简单的方案,
00:17:17是因为我曾被迫去维护别人留下的复杂替代方案。
00:17:21AI 只是生成你要求它生成的东西。
00:17:23它不会吸收过去失败的教训。
00:17:25三阶段方法弥合了这一差距。
00:17:29它将理解压缩成我们可以随生成速度一起评审的产物。
00:17:33如果没有它,我们积累复杂性的速度就会超过我们理解它的速度。
00:17:39AI 改变了我们写代码的一切方式,但老实说,
00:17:44我不认为它改变了软件本身失败的任何原因。
00:17:47每一代人都面临着他们自己的软件危机。
00:17:50戴克斯特拉(Dijkstra)那一代人通过创建软件工程学科来应对,
00:17:54而现在我们面临着无限代码生成的挑战。
00:17:56我不认为解决方案是另一种工具或方法论。
00:18:01而是要记住我们一直以来都知道的真理:软件是一项人类事业。
00:18:05难点从来不在于敲代码。
00:18:06而在于最初就知道该敲什么。
00:18:09那些能够胜出的开发者将不仅仅是生成代码最多的人。
00:18:13而是那些理解自己所构建内容的人,
00:18:15是那些仍能看清接缝、能意识到自己正在解决错误问题的人。
00:18:19那还是我们。
00:18:20也只能是我们。
00:18:21我想留下一个问题,而且我不认为问题在于
00:18:25我们是否会使用 AI。
00:18:26那是定局。
00:18:28大势已定。
00:18:30对我来说,问题将在于当 AI 编写我们大部分代码时,
00:18:33我们是否还能理解自己的系统。
00:18:35谢谢大家。
00:18:37>> [掌声]
00:18:39[音乐]

Key Takeaway

在 AI 辅助开发的时代,工程师必须拒绝将思考外包,通过深度参与架构规划和逻辑验证,确保代码的“简单”性与可维护性。

Highlights

混淆“容易”(Easy)与“简单”(Simple)是导致代码复杂度失控的根本原因。

AI 虽然极大地加速了代码生成,但也打破了人类理解力与代码复杂度之间的平衡。

Fred Brooks 的“没有银弹”理论依然适用:AI 只能解决机械性的编码,无法替代对问题的本质理解。

Netflix 实践中的“三阶段方法”(研究、规划、实施)是应对无限代码生成的有效策略。

过度依赖 AI 会导致工程师“直觉萎缩”,丧失识别危险架构和底层问题的能力。

软件开发的难点从未改变:不在于如何敲代码,而在于最初就知道该敲什么以及它为何运作。

Timeline

引言:我们交付了自己都不懂的代码

演讲者 Jake Nations 以一种幽默且真诚的“坦白”拉开序幕,承认即使是像他这样的资深工程师也会交付自己无法完全解释的代码。他指出在 Netflix 推动 AI 应用过程中,开发速度虽有质的飞跃,但也带来了理解力跟不上生成速度的隐患。当大型系统在生产环境中崩溃时,如果开发者不理解底层逻辑,调试将变成一场灾难。这段开场白强调了现状的紧迫性:测试通过并不代表代码是安全的。这种现象反映了现代软件开发中效率与透明度之间的严重脱节。

历史循环:从 60 年代的软件危机到 AI 时代

本段回顾了计算机科学史上不断重复的“软件危机”,引用了 Dijkstra 关于硬件增长带动软件复杂度同步增长的论点。从 70 年代的 C 语言到 90 年代的面向对象,再到如今的 AI,每一代技术都在试图解决前一代留下的规模瓶颈。演讲者提到 Fred Brooks 的《没有银弹》,指出软件的“本质复杂度”是无法通过工具消除的。AI 虽然让编码的机械过程变得无限快,但理解问题和设计方案的根本困难依然存在。这部分内容旨在提醒听众,我们正处于第一代面临“无限规模”自动化代码生成的危机之中。

核心矛盾:“容易”不等于“简单”

演讲者引用 Rich Hickey 的理论,深度剖析了“容易”(Easy)与“简单”(Simple)的本质区别。简单意味着逻辑解耦、不纠缠,而容易则仅仅代表触手可及、方便快捷。AI 是终极的“一键容易”按钮,它让开发者跳过架构思考直接获得结果,导致系统复杂度在不知不觉中累积。通过一个身份验证功能的迭代例子,他展示了多轮对话如何让代码变成一团乱麻,并充满了废弃逻辑和冲突模式。这种权衡实际上是以当下的开发速度换取未来的系统坍塌。最终,AI 会将所有的技术债视为合法的模式进行延续,进一步固化复杂度。

复杂度分析:本质复杂度与偶然复杂度的交织

这部分重点讨论了系统中的两种复杂度:业务固有的“本质复杂度”和由于技术决策、过时抽象产生的“偶然复杂度”。在 Netflix 的真实案例中,旧的授权代码与业务逻辑深度纠缠,导致 AI 在尝试重构时由于无法理清依赖关系而彻底失控。AI 无法像人类一样识别哪些是必须保留的业务逻辑,哪些是早该废弃的临时方案。人类工程师的价值在于拥有 AI 无法推断的上下文背景和历史经验。只有通过慢下来思考并做好区分,才能避免让 AI 只是在原有负担上再叠加新的负担。这强调了人工干预在处理复杂系统重构时的不可替代性。

实战策略:应对大规模代码的“三阶段方法”

为了解决百万行级别代码库的维护问题,演讲者提出了“上下文压缩”的三阶段流程:研究、规划与实施。在研究阶段,利用 AI 代理分析文档和代码以生成研究文档,并由人工进行高杠杆的真实性验证。规划阶段则要求制定像“按数字填色”一样精确的执行规格说明书,确保架构决策在动手前就已明确。最后的实施阶段在清晰规范的指引下变得非常简单且聚焦,有效防止了长对话带来的逻辑偏离。这种方法的核心在于将思考、综合和判断保留在人类手中,而仅将机械执行外包给 AI。这不仅提高了效率,更重要的是保持了开发者对系统的完整理解力。

深度反思:理解是安全更改的唯一前提

在演讲的最后,Jake 分享了一个即使使用 AI 也必须先手动迁移代码的案例,强调“赢得理解”是无法跳过的步骤。他警告说,如果我们为了赶速度而跳过思考,不仅会引入坏代码,还会导致识别复杂度和潜在风险的“直觉萎缩”。代码能跑通与能在生产环境中长期存活、可维护是有本质区别的,后者需要人类积累的模式识别经验。AI 改变了写代码的方式,但没有改变软件失败的原因,即缺乏对系统底层逻辑的掌控。他总结道,胜出的开发者将是那些在 AI 时代依然能看清代码接缝、理解构建初衷的人。最后,他呼吁大家思考:当 AI 编写大部分代码时,我们是否还真的拥有这些系统。

Community Posts

No posts yet. Be the first to write about this video!

Write about this video