
配套视频:https://www.bilibili.com/video/BV1zB64BkEyc/
引言:一个不得不说的秘密
"大家好,我先坦白一件事。"Netflix 的工程师 Jake Nations 在演讲开场就抛出了一个令人不安的confession:"我发布了一段自己并不完全理解的代码——用AI生成、测试通过、部署上线,但我无法解释它是如何工作的。"
停顿片刻后,他环视台下:"关键是,我敢打赌你们每个人都做过同样的事。"
这不是个例,而是2024年软件开发的新常态。我们正站在一个历史转折点:代码生成的速度已经超越了人类理解的速度。这不是第一次软件危机,但却是第一次面临无限规模的危机。
第一部分:历史总在重演
1968年的警钟
让我们回到1968年。那一年,一群计算机科学家聚在一起,讨论一个紧迫的问题:软件危机。项目延期、质量低下、需求无法满足——这些问题听起来是不是很熟悉?
Dijkstra 当时说了一句经典的话:"当我们只有少数弱小的计算机时,编程只是个小问题;如今我们有了巨型计算机,编程却成了巨大的难题。"
他的洞察是:硬件性能增长了一千倍,社会对软件的需求也相应增长了一千倍。程序员必须在方法和手段之间找到平衡,来支撑这种指数级的增长。
危机的循环
这种模式此后不断重演:
70年代:C语言出现 → 我们能编写更大的系统
80年代:个人电脑普及 → 人人都能编写软件
90年代:面向对象编程 → 带来了"继承层级地狱"(谢谢你,Java)
2000年代:敏捷开发 → Scrum Master 和 Sprint 流程
2010年代:云计算、移动互联、DevOps → 软件真正"吞噬了世界"
2020年代:AI、Copilot、Cursor、Claude → 代码随说随有
每一代人都突破了上一代的瓶颈,但也创造了新的复杂性。而这一次,规模变了——它是无限的。
"没有银弹"的预言
1986年,Fred Brooks(《人月神话》的作者)写了一篇论文《没有银弹》。他的核心论点是:不会有任何单一创新能带来软件生产力的数量级提升。
为什么?
因为编程的难点从来不是代码的机制、语法或打字。真正难的是理解问题本质并设计解决方案。没有工具能消除这一根本困难。
我们创造的每种工具和技术都简化了操作机制,但核心挑战——弄清楚该构建什么、如何运作——依然同样困难。
第二部分:简单与容易的致命混淆
两个被混用的词
如果问题不在机制本身,为何我们仍不断优化它?经验丰富的工程师为何会写出自己都看不懂的代码?
答案在于两个我们经常混淆的词:简单(Simple)和容易(Easy)。
Clojure 语言的创造者 Rich Hickey 在2011年的演讲《Simple Made Easy》中精确定义了这两个概念:
简单(Simple)
词源:sim-plex,单一编织
含义:无纠缠、各司其职、互不交织
本质:关乎结构
容易(Easy)
词源:adjacent,邻近的
含义:触手可及、无需努力
本质:关乎距离
举个例子:
复制粘贴 Stack Overflow 的答案 → 容易
理解为什么这个方案有效 → 简单
AI:终极的"容易按钮"
这里是关键:我们不能单靠愿望让复杂变简单,但总能让事情更容易。
简洁需要思考、设计和梳理。但让事情变容易?只需放近一点:
安装一个包
用AI生成
从Stack Overflow抄个答案
人性天生倾向走捷径,这是进化的结果。但AI将这条捷径变得毫无阻力。
为何还要思考架构,当代码瞬间就能生成?
一个典型的崩溃过程
让我展示这是如何发生的。假设我们要给应用添加身份验证:
第1轮:"添加认证功能"
得到一个简洁的
auth.js文件看起来不错!
第5轮:"现在也要添加 OAuth"
现在有了
auth.js和oauth.js开始有点复杂了
第12轮:"会话好像坏了,有很多冲突"
开始修修补补
第20轮:你已经不是在讨论了
你在管理一个复杂到连自己都记不全的上下文
废弃方法留下的无效代码
被"修复"到能跑的测试
三种不同解决方案的碎片
每条新指令都在覆盖前一条的架构模式:
"让认证在这里工作" → AI照做
"修复这个错误" → AI照做
对错误的架构决策毫无阻力
代码只是被动适应你的最新请求。每次互动都在选择容易而非简单。而容易总是意味着更多复杂性。
我们明知不该这样,但当捷径如此顺手,我们还是会走。复杂性正在累积,直到为时已晚。
第三部分:复杂性的真面目
AI眼中的代码库
AI将简单发挥到了极致:明确需求,即刻生成代码。但这里有个危险:
生成的代码会将你代码库中的每个模式一视同仁。
当代理分析你的代码库时:
第47行的认证检查 → 这是一种模式
那段奇怪的、像GraphQL一样运作的gRPC代码(2019年写的)→ 也是一种模式
技术债 → 不被识别为债务,只是更多代码
两种复杂性
Fred Brooks 在《没有银弹》中指出,每个系统都有两种主要复杂性:
1. 本质复杂性(Essential Complexity)
问题本身的固有难度
用户需要支付、订单必须履行
这是软件系统存在的理由
2. 偶然复杂性(Accidental Complexity)
我们在实现过程中添加的所有其他东西
变通方案、防御性代码、框架
曾经合理的抽象
为了让代码运行而拼凑的一切
在真实代码库中,这两类复杂性无处不在,且相互交织。分离它们需要上下文、历史和经验。
生成的输出不做这种区分。所有模式都被原样保留。
Netflix的真实案例
这是我在Netflix工作中的一个真实例子:
我们有一个系统,在旧的授权代码(大约5年前写的)和新的集中式认证系统之间有一个抽象层。当时我们没时间重构整个应用,所以只是在中间加了个适配层。
现在有了AI,这似乎是个绝佳的重构机会——直接迁移到新系统。看起来只是个简单请求,对吧?
错了。
旧代码与其授权模式紧密耦合:
权限检查混杂在业务逻辑中
角色假定深植于数据模型
认证调用散落在数百个文件中
代理会启动重构,改几个文件后就会遇到"这取决于..."——它无法理清依赖关系,然后:
失控
放弃
或者更糟:试图保留部分旧逻辑,用新系统重新实现
问题在于:它看不到缝隙。它无法识别业务逻辑在哪里结束、认证逻辑从哪里开始。一切都纠缠在一起。
即使有完美的信息,当你的偶然复杂性达到这种程度时,AI也找不到清晰的路径。我发现它只会在顶部添加更多层。
我们能做什么?
我们能分辨差异——至少在我们放慢脚步思考时可以。我们知道哪些模式是本质的,哪些只是几年前某人的解决方式。
我们掌握着AI无法推断的上下文,但前提是我们必须花时间做出这些区分。
第四部分:解决方案——三阶段方法论
面对百万行代码
那么,如何在面对庞大代码库时区分偶然复杂性与本质复杂性?
我负责的Netflix代码库约有一百万行Java代码,主服务大约500万个token。没有任何上下文窗口能装下它。
最初,我想:"或许我可以直接复制大量代码到上下文中,看看AI能否自动弄清发生了什么。"
就像之前的授权重构一样,输出因自身复杂性而迷失了。
我不得不另辟蹊径。
从500万token到2000字
我必须有所取舍:
设计文档
架构图
核心接口
关键组件
然后,我花时间撰写了组件应该如何交互、应该遵循什么模式的详细需求。
我在写规范。
500万个token变成了2000字的说明书。然后,我更进一步,将该规范转化为一组精确的代码执行步骤——没有模糊指令,只有精确的操作序列。
结果?更清晰、更专注、更易理解的代码。因为是我首先定义的,我规划了它的执行。
这就是我所说的**"上下文压缩"**(Context Compression),你也可以叫它上下文工程或规范驱动开发——名字不重要。
重要的是:思考和规划成为了大部分工作。
三阶段详解
让我详细讲解这个方法如何实际运作:
阶段一:研究(Research)
把所有前期资料都提供给AI:
架构图
文档
Slack讨论串
尽可能多的相关上下文
然后利用代理分析代码库并绘制依赖关系图。
这不应是一次性过程。我倾向于逐步探查:
"缓存是怎么处理的?"
"出错时如何处理?"
当分析错误时,我会纠正它。如果缺少上下文,我会补充。每次迭代都在优化分析结果。
输出:一份研究文档
呈现已有内容及其关联
你的修改将影响什么
数小时的探索被压缩成几分钟的阅读
关键检查点:这是将分析与现实对照验证的时刻——整个流程中最具决定性的环节。在这里发现错误,可以防患于未然。
阶段二:规划(Planning)
有了可靠的研究成果,我们制定详细实施方案:
真实的代码结构
函数签名
类型定义
数据流
这个计划应该详细到任何开发者都能遵循。我把它比作"数字填色"——你应该能把它交给最初级的工程师说:"照着做。"即使逐行照搬也能正常运行。
这一步是我们做出关键架构决策的地方:
确保复杂逻辑正确
确保业务需求遵循良好实践
确保服务边界清晰、职责分明
避免不必要的耦合
我们能提前发现问题,因为我们经历过。AI没有这种经验——它将每个模式都视为必需项。
这一步的真正神奇之处在于审查速度:几分钟内就能验证此方案,明确知道将构建什么。
为了跟上代码生成速度,我们必须能够同样快速地理解我们正在做的事。
阶段三:实施(Implementation)
现在我们有了清晰的计划和研究支持,这一阶段应该相当简单。这正是关键所在。
当AI有明确的规范可遵循时:
上下文保持简洁专注
避免了长对话导致的复杂性螺旋
只有3个聚焦输出,而非50条演进式消息
每个都经验证后才推进
没有被废弃的方法,没有冲突的模式,没有那些导致处处留下无效代码的"等等,其实不用"时刻。
真正的好处:你可以用后台代理来完成这项工作。因为你已经完成了所有思考和繁重工作,它可以直接开始执行。你去处理其他事,稍后回来快速审查。
你只需确认它符合你的计划,而不是试图判断是否有新内容被发明出来。
方法的本质
关键是:我们并非用AI代替思考。
我们用它加速机械部分,同时保持自身理解能力:
研究更快
规划更周全
执行更清晰
但思考、综合与判断——仍由我们负责。
第五部分:实战检验
授权重构的续篇
还记得我说AI搞不定的那个授权重构吗?现在我们真正在着手处理,并开始取得进展。
但问题不是我们找到了更好的提示。
我们发现甚至无法开始研究、规划、实施——我们必须先手动做一次。
没有AI,只是:
读代码
理清依赖
进行更改
看看什么会崩溃
说实话,这很麻烦。但它至关重要。
这次手动迁移揭示了:
隐藏的约束
哪些不变量必须保持成立
若认证变更,哪些服务会中断
仅靠代码分析无法发现的问题。
将经验转化为知识
然后,我们将那个手动迁移的Pull Request提交到研究流程中,作为研究的起点。
AI就能看出干净的迁移是什么样子。
但每个实体都有些不同,所以我们必须去询问它:
"这个加密的内容怎么处理?"
"这个未加密的呢?"
我们必须每次都提供额外上下文,经过多次迭代。
然后,也只有那时,我们才能生成一个可能一举成功的计划。
"可能"是关键词——我们仍在验证、仍在调整、仍在发现边界情况。
核心教训
三阶段法并非魔法。它只有在我们手动完成一次迁移后才有效。
我们必须赢得理解,才能将其编码到流程中。
我仍然认为没有银弹——不是更好的提示、更好的模型,甚至不是写更好的规范。
只是深入理解你的系统的工作,深入到你可以安全地对它进行更改。
第六部分:更深层的危机
"能用"还不够
那么,为何要这么麻烦?为何不直接用AI迭代直到成功?最终模型不会足够强大,直接就能用吗?
对我来说,"能用"还不够。
有区别:
通过测试的代码 vs 能在生产环境存活的代码
今天能运行的系统 vs 未来可被他人修改的系统
知识鸿沟
真正的问题是知识鸿沟:
当AI能在几秒内生成数千行代码,理解它却可能耗去你:
数小时
数天
甚至永远(如果真那么错综复杂)
我们正在失去的能力
这是很少有人讨论的一点:
每次我们为了跟上生成速度而跳过思考,我们不只是在添加无法理解的代码——我们正在失去识别问题的能力。
那种直觉,那种在提醒你"嘿,这变得复杂了"的本能——当你不理解自己的系统时,它会萎缩。
模式识别的来源
模式识别源于经验:
当我发现危险架构时,是因为我曾在凌晨3点处理过它
当我推动更简单的方案时,是因为我不得不维护过别人的复杂替代方案
AI只生成你要求的内容。它不编码从过往失败中提炼的经验教训。
三阶段法弥合了这一差距。它将理解压缩为可以按生成速度审查的产物。
没有它,我们只是在累积复杂度,速度快于我们理解它的能力。
结论:软件的人类本质
每一代的危机
AI彻底改变了我们编写代码的方式。
但老实说,我认为它并未改变软件本身失败的根本原因。
每一代都面临过自己的软件危机:
Dijkstra那一代通过创立软件工程学科来应对
我们这一代面临的是无限代码生成的挑战
真正的解决方案
我认为解决之道不是另一个工具或方法论。
而是记住我们始终明白的事:软件是人类的事业。
难的从来不是敲代码,而是清楚该写什么代码。
未来属于谁?
真正出色的开发者不会是:
❌ 生成代码最多的人
而会是:
✅ 真正理解所构建系统的人
✅ 仍能看清问题本质的人
✅ 能意识到正在解决错误问题的人
那依然是我们,也只能是我们。
最后的问题
我想留下一个问题。
我认为问题不在于我们是否会使用AI——那已是定局,船已起航。
对我来说,真正的问题是:
当AI编写了大部分代码时,我们是否还能理解自己的系统?
实践指南:七条行动原则
基于这次演讲,这里是我们可以立即采取的行动:
1. 采用结构化方法
不要直接让AI生成代码。先研究,再规划,最后实施。
2. 设置人工检查点
在每个阶段结束时验证。研究准确吗?计划合理吗?实施符合规范吗?
3. 压缩上下文
不要把整个代码库扔给AI。提炼出本质,写成清晰的规范。
4. 先手动理解
对于复杂的重构,先手动做一次。赢得理解,再自动化。
5. 保持思考主导
AI是加速机械部分的工具,不是思考的替代品。架构决策必须由人做出。
6. 重视简单性
每次选择"容易"而非"简单"时,问自己:这会增加多少偶然复杂性?
7. 培养模式识别
不要完全依赖AI。通过深度参与代码,积累识别问题的直觉。
尾声
软件危机从未真正消失,它只是换了形式。
从Dijkstra警告的"巨型计算机",到今天的"无限代码生成",本质挑战始终如一:如何在复杂性增长的同时保持理解?
AI给了我们前所未有的生产力,但也带来了前所未有的风险。如果我们不小心,我们将成为第一代被自己的代码库困住的工程师——不是因为代码太少,而是因为代码太多,多到无法理解。
好消息是:解决方案就在我们手中。
不是更好的AI,不是更大的上下文窗口,而是更好的思考方式——一种将AI作为思考的放大器,而非替代品的方式。
当我们学会在生成代码之前先生成理解,我们就能驾驭这个无限的时代。
否则,我们只是在以光速积累技术债。
选择权在我们手中。
如果这篇文章对你有帮助,欢迎点赞、收藏、转发。也欢迎在评论区分享你的经验,我们一起交流学习!
我是 dtsola【IT解决方案架构师 | AI创业者】 ;专注AI创业、商业、技术、心理学、哲学内容分享。
提供服务:AI项目咨询 | 技术解决方案 | IT项目实施 | 企业技术顾问
博客:https://www.dtsola.com
公众号&VX:dtsola
需提供服务,加微信 dtsola,备注:IT咨询,并说明来意。
#独立开发者 #AI编程 #个人开发者 #一人公司 #程序员 #软件开发者 #创业者 #数字游民 #AI创业 #软件工程