懒惰的美德:当AI不再懂得偷懒的艺术

AI 编程哲学

前言

最近读到两篇很棒的博文,让我对 AI 时代的编程有了更深的思考。

一篇是 Bryan Cantrill 的《The peril of laziness lost》(失去懒惰的危险)。Bryan 是 DTrace 的作者、Oxide Computer 的 CTO,系统编程领域的传奇人物。

另一篇是 Mario Zechner 的《Thoughts on slowing the fuck down》(关于放慢脚步的思考)。Mario 是 libGDX 游戏框架的创建者,也是一位经验丰富的开发者和教练。

两位作者从不同角度提出了同一个警告:在 AI 编程时代,我们正失去一些宝贵的东西

Larry Wall 的三美德

要理解他们的观点,得先回到 Larry Wall。

Larry Wall 是谁?Perl 语言的创造者。他在那本著名的《Programming Perl》(被亲切地称为”骆驼书”)里,提出了程序员的三美德:

懒惰、急躁、傲慢

原文是这么说的:

如果我们要讨论好的软件设计,就必须谈到懒惰、急躁和傲慢。这些都是好软件设计的基础。我们都曾掉进复制粘贴的陷阱,其实应该定义更高层的抽象,哪怕只是一个循环或子程序。当然,有些人走向了另一个极端,定义了越来越多的高层抽象,其实应该用复制粘贴。但一般来说,我们大多数人需要思考的是使用更多抽象,而不是更少。

懒惰驱动我们让系统尽可能简单(但不要过于简单!)——开发强大的抽象,让我们能更容易地做更多事情。

懒惰的真正含义

这里的”懒惰”不是贬义词。

它是一种工程智慧

  • 懒得写重复代码 → 所以抽象出通用模块
  • 懒得维护复杂系统 → 所以追求简洁设计
  • 懒得处理边界情况 → 所以在设计时就考虑周全

Bryan 说得很好:

这种看似懒惰的背后,其实是在脑子里反复思考问题。我们承担开发抽象所需的艰难智力工作,部分原因是我们正在优化假设中的未来自己的时间,即使以牺牲当前时间为代价。

这就是 hammock-driven development (吊床驱动开发)的精髓——看似在偷懒,实则在深度思考。

LLM 的问题:不知疲倦的”勤奋”

现在问题来了。LLM 不会累,也不需要优化自己的时间

Bryan 举了一个例子:Garry Tan(Y Combinator 的 CEO)炫耀自己用 LLM 一天写了三万七千行代码,而且”还在加速”。

对比:整个 DTrace 项目大约也就六万行代码。

这意味着什么?

一位波兰工程师 Gregorein 解剖了 Garry Tan 的”newsletter-blog-thingy”项目,结果让人啼笑皆非:

  • 包含多个测试框架(?!)
  • 包含 Rails 的 Hello World 应用(?!)
  • 偷偷塞进去一个文本编辑器
  • 八个不同版本的同一个 logo,其中一个文件大小为零字节
这不是 bug 的问题(这些都能修),也不是方法论的问题。问题在于 LLM 本质上缺乏懒惰的美德。

错误在复合:Mario 的警告

Mario Zechner 从另一个角度提出了更严峻的警告。

他说现在的软件”一切都坏了”——98% 的正常运行时间反而成了常态,界面有各种奇怪的 bug。虽然这不能全怪 AI,但趋势在加速。

复合的”小错误”

Mario 提出了一个很形象的词:booboos(小错误)。

人类也会犯错,但:

  • 人类会学习,不会重复犯同样的错误
  • 人类是瓶颈,一天能写的代码有限
  • 当痛苦积累到一定程度,人类会去修复

但代理(Agents)不一样:

  • 代理没有学习能力(除非你显式教它,但它还是会忘)
  • 代理没有瓶颈,几小时能生成几万行代码
  • 代理不会感到痛苦,所以你不知道错误在积累

这些小错误(重复的代码、无用的方法、错误的抽象)会在代理手中指数级复合。直到有一天,你想加个新功能,发现架构已经烂到无法支持;或者用户数据被删除了,你才发现问题。

复杂性的商人

Mario 还有一个很犀利的观点:代理是“复杂性的商人”(merchants of learned complexity)

代理在训练数据中见过太多糟糕的设计决策。当你让它们帮你设计架构时,它们会引入大量复杂性——各种 Cargo cult 的”行业最佳实践”、为了抽象而抽象的代码、不一致的重复实现。

更糟糕的是,代理只有局部视野。它们看不到整个代码库,看不到之前的决策,所以总是在局部做”看起来对”的选择,最终导致全局的混乱。

Mario 说:”一个 2 人团队用代理,几周内就能达到传统企业代码库的复杂度。”

低召回率的代理搜索

Mario 还指出了一个技术问题:代理搜索的召回率很低

当代理试图重构或修复代码时,它需要先找到所有相关的代码。但无论是用 ripgrep、LSP 服务器还是向量数据库,当代码库变大时,代理总会遗漏一些代码。

结果就是:

  • 遗漏现有代码 → 重复造轮子
  • 遗漏相关代码 → 修复不完整
  • 遗漏上下文 → 引入新的不一致

这就是那些”小错误”产生的根本原因。然后它们会像滚雪球一样,变成一朵“美丽的屎花”(shit flower)

为什么这很危险

把这两篇文章放在一起读,我觉得他们说的是同一件事的两面:

LLM 不会感到需要为自己(或任何人)的未来时间做优化,它们会毫无顾虑地在一层又一层的垃圾上堆叠更多垃圾。

如果不加以约束,LLM 会让系统变得更大,而不是更好——可能迎合了某种扭曲的虚荣心指标,但代价是牺牲了一切真正重要的东西。

最好的工程总是源于约束,而我们人类时间的约束限制了我们对系统认知负荷的容忍度。正是这种约束驱使我们让系统更简单,尽管系统本质上就很复杂。

放慢脚步:我现在怎么做

基于两位作者的观点,我总结了几条实践建议:

1. 限制代码生成量

Mario 建议:给自己设定每天生成代码量的上限,与你能 review 的能力相匹配。

不要追求 37k 行/天,追求 100 行高质量的代码。

2. 手写架构,代理实现

架构、API 设计这些决定系统”气质”的东西,必须手写

用 tab 补全感受代码的构建过程,或者用结对编程的方式和代理一起写。这种摩擦能让你更好地理解系统在”感觉”上是否正确。

3. 把 LLM 当实习生用

它可以帮你写代码,但你需要 review、refactor、甚至重写。

好的代理任务应该是:

  • 范围有限,不需要理解整个系统
  • 有明确的评估标准(可以自动验证结果)
  • 不是关键路径,不会导致数据丢失

4. 追求”少即是多”

当 LLM 给你一大坨代码时,问它:”能不能更简洁?”

学会说”不”本身就是一种能力。做更少的功能,但做对的功能。

5. 保持批判性思维

LLM 生成的代码往往”能用”但”不够好”,别被数量迷惑。

定期重构,防止技术债务累积。如果你连自己写了什么都不知道,当出问题时就无法修复。

结语

Larry Wall 说懒惰是美德,这是一种智慧。

Bryan Cantrill 提醒我们,这种美德在 AI 时代变得更加稀缺。

Mario Zechner 告诉我们,如果不放慢脚步,我们会被代理带入一个复杂性的深渊。

机器不会累,不会觉得麻烦,不会为了追求简洁而绞尽脑汁。这些人类的”弱点”,恰恰是创造力的源泉。

这不是说不该用 AI 工具。而是说:为了将来能少做一点,现在要多做一点思考

这种”懒惰”,才是真正的懒惰。


参考阅读: