You can just choose how many bugs you want now

You can just choose how many bugs you want now

现在,你可以随心所欲地决定软件里有多少 Bug 了

There’s a bizarre aspect of AI coding that I’ve been trying to put my finger on, and I think it’s this: you can basically just decide how many bugs you want your software to have now. AI 编程中有一个我一直试图琢磨透的怪现象,我想大概是这样的:现在,你基本上可以随心所欲地决定你的软件里要有多少个 Bug。

We discovered this first with security, because of course security bugs are the most non-negotiable ones. But I think once the vulnpocalypse is over, we’ll start to turn our attention to other types of bugs: correctness, performance, accessibility, reliability, etc. 我们最初是在安全性方面发现这一点的,因为安全漏洞显然是最不容妥协的。但我认为,一旦“漏洞末日”(vulnpocalypse)过去,我们将开始把注意力转向其他类型的 Bug:正确性、性能、可访问性、可靠性等等。

Some of us are already doing this. For example, I find myself spending a lot of time these days in code review, using tools like my triple-agent code review skill as well as Geoffrey Litt’s explain-diff skill. My experience is that, in a complex system, you can basically find as many bugs as you ask the agents for. If you get tired of tackling bugs in the PR itself, have no fear: the agent will also find plenty of preexisting bugs for you to spend time on. The question is just when you want to stop and call it “done.” 我们中有些人已经在这样做了。例如,我发现自己最近花了很多时间在代码审查上,使用诸如我的“三重代理代码审查”(triple-agent code review)技能以及 Geoffrey Litt 的“解释差异”(explain-diff)技能等工具。我的经验是,在一个复杂的系统中,你基本上可以要求代理找出任意数量的 Bug。如果你厌倦了处理 PR 本身中的 Bug,别担心:代理还会为你找出大量预先存在的 Bug,供你消磨时间。问题仅仅在于你何时想停下来,并宣布它“完成了”。

Of course the bugs are not free to fix. There are still many tradeoffs to consider: lines-of-code versus likelihood that the bug will actually occur, the risk of introducing new bugs in a complex solution, the cost of making the code harder to understand for future reviewers or agents, etc. But the finding of the bugs has become nearly free, and AI agents are also capable of finding very subtle, intricate bugs that otherwise could have flown under the radar for years. 当然,修复 Bug 并非没有代价。仍有许多权衡需要考虑:代码行数与 Bug 实际发生的可能性之间的平衡、在复杂解决方案中引入新 Bug 的风险、使代码对未来的审查者或代理更难理解的成本等等。但发现 Bug 的成本已经几乎为零,而且 AI 代理还能够发现那些极其微妙、复杂的 Bug,否则这些 Bug 可能多年都不会被察觉。

What we do with this situation is the interesting question. As many have noted, it doesn’t seem like the overall polish of software has increased since AI coding became a thing. If anything, there is just more junk and shovelware out there, of dubious quality. I think this demonstrates that, although our ability to find new bugs has skyrocketed, our overall tolerance for bugs has not changed. 我们如何应对这种情况是一个有趣的问题。正如许多人所指出的,自从 AI 编程出现以来,软件的整体精致度似乎并没有提高。如果说有什么变化的话,那就是市面上出现了更多质量堪忧的垃圾软件和敷衍之作。我认为这表明,尽管我们发现新 Bug 的能力突飞猛进,但我们对 Bug 的整体容忍度并没有改变。

There are still plenty of winds blowing in the opposite direction: 依然有许多因素在阻碍着进步:

  • The preventable problem paradox: if an incident occurs and you swoop in to fix it, you’re a hero. If you prevent the problem from ever occurring in the first place, then nobody knows you did anything. 可预防问题的悖论: 如果发生了事故,你冲进去修复它,你就是英雄。如果你从一开始就预防了问题的发生,那么没人会知道你做了什么。
  • Related: the pressure inside many software orgs is to keep shipping visible results, not to fine-tune something that already “works.” With AI coding this is magnified: management often assumes that 10x productivity means 10x more visible features and apps. 相关因素:许多软件组织内部的压力在于不断交付可见的成果,而不是去微调那些已经“能用”的东西。 在 AI 编程的加持下,这种压力被放大了:管理层通常认为 10 倍的生产力意味着 10 倍的可见功能和应用。
  • Laziness: one of the classic virtues of a programmer, this time working against us. I find myself mentally exhausted after slogging through the umpteenth AI-generated bug report, which requires me to carefully think through intricate aspects of the system and weigh the pros and cons of fixing it. I imagine many of my peers in the industry have just tuned out AI code reviews or only focus on the most critical findings. 懒惰: 程序员的经典美德之一,这次却在阻碍我们。在处理了无数份 AI 生成的 Bug 报告后,我感到精疲力竭,因为这需要我仔细思考系统的复杂方面,并权衡修复它的利弊。我想业内许多同行可能已经不再关注 AI 代码审查,或者只关注最关键的发现。

Avoiding epicycles

避免“本轮”陷阱

There are a few ways we can approach this problem, though, that don’t require unending toil. One way is to set up the agent on a loop, e.g. “do a code review, fix all critical/high/medium issues, then repeat.” I find this can work, but it has a tendency to create lots of epicycles. 不过,我们有几种方法可以解决这个问题,而无需无休止的苦干。一种方法是将代理设置为循环运行,例如:“进行代码审查,修复所有关键/高/中等优先级的问题,然后重复。”我发现这确实有效,但它往往会产生大量的“本轮”(epicycles)。

If you’re not familiar with the concept: in the pre-Copernican model of the solar system, ancient astronomers “fixed” miscalculations in the planets’ orbits by simply adding more circles to their movement. This improved the accuracy of the predictions, but at the cost of making the overall model more complicated. Obviously just saying “the earth moves around the sun” greatly simplifies the whole thing, but first you need the insight to make this simplification possible. 如果你不熟悉这个概念:在哥白尼之前的太阳系模型中,古代天文学家通过简单地在行星运动中增加更多的圆圈来“修正”轨道计算错误。这提高了预测的准确性,但代价是使整个模型变得更加复杂。显然,只需说“地球绕着太阳转”就能极大地简化整个问题,但首先你需要具备实现这种简化的洞察力。

I’ve found that AI agents are pretty bad at such dramatic simplifications (in other words, “LLMs can’t jump”). They will happily build one epicycle per bug until the code is a spaghetti mess. So a valuable part of AI code review is still to ask questions like “How can we make this simpler?” and “Is there a fundamental flaw with the codebase that we should fix before we tackle this class of bugs?” 我发现 AI 代理在进行这种剧烈简化方面表现很差(换句话说,“大语言模型不会跳跃式思维”)。它们会乐此不疲地为每个 Bug 增加一个“本轮”,直到代码变成一团乱麻。因此,AI 代码审查的一个重要部分仍然是提出诸如“我们如何让它更简单?”以及“在处理这类 Bug 之前,代码库是否存在我们需要修复的根本性缺陷?”之类的问题。

Another technique that works well is to have good tests. (Easier said than done!) For example, when I was playing around with vibe coding the W3C IndexedDB API, it became pretty clear to me that an agent could just grind through the test suite, and if it got close to 100% then I could be reasonably certain to have a bug-free implementation. But the only reason this works is because the Web Platform Tests are a phenomenally good test suite, honed by years of independent browser implementers discovering odd bugs and adding test cases for every unlikely scenario you can think of. 另一种行之有效的方法是拥有良好的测试。(说起来容易做起来难!)例如,当我尝试用“直觉编程”(vibe coding)来编写 W3C IndexedDB API 时,我很清楚代理可以遍历测试套件,如果覆盖率接近 100%,那么我可以相当确定实现是无 Bug 的。但这之所以有效,仅仅是因为 Web Platform Tests 是一个极其出色的测试套件,它经过多年来独立浏览器实现者们的打磨,他们发现了各种奇怪的 Bug,并为你能想到的每一个不可能的场景都添加了测试用例。

Most companies, in their first-party codebases, could only dream of such a test suite. I can imagine, though, that if you’re building a system from scratch, and especially if your goal is to reproduce the output of an existing system, then you can get pretty far by just putting all your effort into the test suite and then letting the agent go nuts on the rest. PGRust seems to be having some success with this. 大多数公司在自己的代码库中,只能梦想拥有这样的测试套件。不过我可以想象,如果你是从零开始构建一个系统,尤其是如果你的目标是复现现有系统的输出,那么你可以通过将所有精力投入到测试套件中,然后让代理去处理剩下的部分,从而取得很大的进展。PGRust 在这方面似乎取得了一些成功。

A third technique is to just simplify your system design so that whole classes of bugs become impossible. For example, I’ve long been an advocate for multi-page apps (MPAs) over single-page apps (SPAs), just because, with MPAs, entire bug categories simply don’t exist: breaking the back button, losing scroll state, leaking client-side memory, improper accessibility during page navigations, etc. Of course you lose some power with a simpler system versus a complex one, and maybe a reasonable answer is to deliberately choose a more complex system while also just fixing all the bugs. I feel though that this would still have a tendency towards epicycles, and I would much rather read (or debug!) a codebase built on simpler principles rather than o 第三种技术是简化你的系统设计,使得整类 Bug 变得不可能发生。例如,我一直主张使用多页应用(MPA)而不是单页应用(SPA),仅仅因为使用 MPA,整类 Bug 根本就不存在:比如破坏后退按钮、丢失滚动状态、客户端内存泄漏、页面导航期间的可访问性问题等等。当然,与复杂系统相比,你会失去一些功能,也许一个合理的答案是刻意选择一个更复杂的系统,同时把所有的 Bug 都修复掉。但我感觉这仍然会有产生“本轮”的倾向,我宁愿阅读(或调试!)基于更简单原则构建的代码库,也不愿……