廉价代码正在改变我的调试方式

HN Claude Code Adoption 2026-08-29T06:25:00.341076

你还记得软件很贵的时候吗?那时候,你不能凭空一挥手,就让一段带着完整测试套件的代码自己冒出来。按那种方式写代码很辛苦,但也很有成就感。当我写的代码片段全都拼在一起,解决了眼前的问题时,我会特别自豪。没有哪个软件能永垂不朽,但如果那段代码不得不被扔掉,我肯定会难过。我在上面花了时间,动了很多脑筋,把它做成了我心目中该有的样子。但现在,代码变得廉价了。

代码很便宜

AI 生成代码的速度,快得几乎跟你想出来的速度一样。和过去我们写代码所花的时间相比,现在动动手的成本几乎可以忽略不计,费用也低得可笑。我们可以先默哀片刻,为我们这门珍贵手艺的新现实而难过……

跟你的悲伤待一会儿……

好了,这一刻结束了。既然我们已经接受了这个事实,就来聊聊这对今天软件构建方式意味着什么。

一种新的调试思路

我想聊一个让我兴奋的具体变化:这给调试带来了新的方法。举个例子,AI 可以立刻生成量身定制的、一次性的调试工具。调试因此变快了,因为我们可以更快地对自己的根因假设进行迭代验证。

目前很多开发者采用 AI 辅助调试的方式,对付复杂 bug 并不好用。我合作过的大多数开发者在 AI 上都是这么说的:“找到 bug 然后修好它。”如果真能这样,那当然很棒,而且对简单 bug 来说确实有效,问题就解决了。但以我的经验,遇到更棘手的问题时,这种做法会给 AI 留下太多猜测空间。它会实现一个根本不好使的“修复”。然后你说:“不行,再试试”,于是又循环一遍。这就像在一个又一个兔子洞里往里跳,盼着 AI 碰巧掉进正确的那个。如果没猜对,你还得把它拽出来,重新开始。

假设驱动的调试

更好的做法,是用 AI 做“假设驱动的调试”。

  1. 收集上下文

  2. 生成假设

  3. 排序并选择一个

  4. 构建一次性工具来验证假设

  5. 要么 AI 自己跑实验,要么在它做不了的时候交给人类

  6. 如果问题没有修复,回到第 2 步;如果修复了,就落地修复方案,并删掉那些临时工具代码。

假设排查工作流程图

工作流拆解见上图,文末附有完整大图的链接。

这套流程自己手动跑也完全可行,但配合 AI 来跑,帮助会大得多。一方面,AI 能飞快地生成大量假设,还能按「可能性 × 验证成本」排出优先级,帮你决定该从哪个假设入手。AI 在验证环节也很擅长:有些假设它能直接替你跑完实验,然后告诉你结论是对是错;就算它做不到,也能给你工具和详细的操作步骤,让你自己动手验证,再把结果喂回给 AI 做分析。

一个真实的例子

拿我实际碰到的 bug 来说。我维护的一个软件产品,前端出了个问题。某个页面上,我们用查询参数(query parameters)来预填一个复杂的多步表单,而这个表单本身又是根据多个数据源动态生成的。Bug 的表现是:预填会间歇性失效,而且每次挂的位置还不一样。开发者在自己的机器上怎么也复现不出来,人为把网速调到很慢也不行。出问题的案例之间,底层数据似乎有些共性,但就是锁定不了原因。

后来,我让 AI 针对可能的原因列出一些假设,并把我怀疑藏有问题的代码区域指给它看。其中一个假设是:这是由复杂的竞态条件(race condition)导致的。这个猜想看起来挺合理,因为有 6 个不同的 API 请求都会以某种方式往表单里灌数据。基于这个假设,我让 AI 写了一段临时代码,让我能通过查询参数给各个 API 调用注入可调的延迟。效果大概是这样:

https://myapp.com/complex-form-page
    ?productsApiDelayMs=1000
    &ordersApiDelayMs=2000
    &cartApiDelayMs=500

这样一来,调试体验变得非常好——我可以轻松尝试不同的请求速度组合,最终定位到了导致 bug 的竞态条件(race condition,多个请求并发执行时因时序问题引发的错误)。实际上有 4 个独立的故障点需要修复。

可能的质疑

看到这里,你可能会问:为什么不用开发者工具里的 Network 面板,单独对某个请求做限速呢?这个质疑合理,因为我确实也可以这么做。我不用它,主要理由是速度和手感。我认为写这种一次性脚本反而更快——这在 AI 出现之前不成立,但现在成立了。

我不太常用开发者工具去给单个请求限速,所以每次都要花时间配置。尤其这次涉及 6 个独立请求,每个都要设置不同的参数,才能精确复现我想要的顺序。而用 AI 生成的自定义工具就完全不同,它完全贴合我的需求:配置很快,而且一眼就能看清当前设置了什么。

这就引出我的第二个理由:这种自定义工具用起来就是更舒服。开发者工具里功能太多,有时候会让人觉得有点眼花缭乱。另外,我们的应用会发出非常多的请求,想在 Network 面板里精准筛出我要看的那几个,我得先记住每个 API 请求对应的 URL 路径,再逐个过滤——这也要花不少时间。

而用 AI 的做法,我只需要说:“给初始化这个表单涉及的所有 API 请求都加一个查询参数,让我能用毫秒级数值来控制延迟。” 然后像上面代码片段里那样,把这些查询参数拼到 URL 里就行。我觉得这比在开发者工具里做请求限速的体验好得多。而且我认为,在很多场景下,这种一次性的小工具都会比标准工具更好用。

为什么没人这么做?

那为什么我没看到更多开发者这样做呢?我想有一部分是习惯使然。我们总是顺手拿起自己最熟悉的东西,不管是 IDE 调试器、开发工具、往代码里塞 console.log,还是别的什么。另一个原因我觉得是,代码在我们心里仍然是“金贵”的。我们习惯了把代码打磨到完美,重构它、评审它、为它写测试。我们在代码上投入了大量时间。所以,创造一段几乎马上就会被扔掉的代码,感觉像是浪费。但代码现在已经很便宜了。作为开发者,我们需要理解“一次性代码”带来的新含义,并相应地调整自己的习惯。

结语

查看原文