一般

没人会读的代码

1
分类:技术博客
作者:Addy Osmani
来源:跳转
发表时间:

内容

两年前我写了一篇关于AI辅助编程的文章,其中一个建议是审查生成代码的每一行。如果放在今天,我的建议会非常不同。

现在我会这样说:你不需要阅读所有代码。但每一处修改仍然需要某种形式的审查,也仍然需要一个人为发布的决定负责。发生变化的是:仔细人工阅读每一行代码不再是提供这种审查的唯一方式,也不总是最好的方式。有些可以主要由AI审查,或者在涉及敏感内容时采用人工与AI混合审查。

Teleport在一个季度内发现了相当于两年的安全漏洞。十三名工程师、最先进的大模型、自有代码库:高严重性漏洞的数量是前两年总和的近两倍。让我感兴趣的是这对工作队列意味着什么。发现漏洞的成本降低了好几倍。但分类没有,而确认哪些真正可利用仍然需要人阅读代码。发现速度快过修复速度,你就用已知的积压换掉了未知的积压。在你动手审查自己的代码库之前,值得先读一读这份报告 → https://fandf.co/4r3xdeX · 由 Teleport 赞助。 #ad

这篇文章要讨论的是我认为应该取代旧方式的做法,以及当什么都没有取代时会发生什么。

上周,Thorsten Ball 发布了一份他关于软件开发未来相信的十六件事的清单。第一条是“代码审查将会消亡”。我同意这份清单的大部分内容,至少在方向上,但我会用不同的方式表达第一条。对很多代码来说,逐行阅读正在消失。但审查——即由某人来决定什么可以发布并为此负责——不会消失。像他这样的清单无法告诉你的是,每一项会以多快的速度到来,以及在行业的哪些部分。这才是我真正与人们有分歧的地方。

同一周,另一篇截然不同的帖子^也走得很远。一位在一家大公司入职两周的工程师写了篇文章,描述他每天的工作就是按下回车键发布没人阅读的代码。超过八百万人看到了它。我认为这两篇文章并不矛盾。一篇描述的是目的地。另一篇描述的是当一家公司在没有修建道路的情况下就驱车前往时会发生什么。

简而言之,我的观点是这样的。我认为,一旦每个行业有了其他充分的理由信任代码,它就会停止逐行阅读大部分代码。

这一次不同的是,写代码的东西无法像旧的代码生成器那样被验证,因为它不会两次给出相同的答案。所以信任必须来自于我们在它周围构建的检查。一个团队或一个行业能多快到达那里,取决于两种成本:检查没人阅读过的工作的成本,以及错过检查而导致的失败需要撤销的成本。

我应该先说明,我并不是中立的。我帮助构建了一个编写代码的工具。当人们说Thorsten是个卖铲子的、告诉每个人都来挖的时候,他说因果关系是反过来的:他构建AI代理是因为他相信它们。对我来说也是如此。

我怀念旧方式吗?说实话,是的。在我的一本JavaScript书籍的最开头,我写道好的代码就像一封给下一个需要维护它的开发者的情书。我是真心的。那是在AI之前,当时我们很多人关心代码本身的工艺。我喜欢Thorsten的那句话:意大利鞋匠仍然存在,但看看你的脚。事情在变化。我得到的是能够非常快速地重塑黏土,以及构建那些我原本会搁置多年、永远不会开始的东西的能力。

审查实际上是为了什么

2013年,微软研究人员研究了代码审查,并询问开发人员为什么他们这样做。发现缺陷是首要答案。评论讲述了另一个故事。在研究人员分类的570条审查评论中,只有14%与缺陷有关。其余的都是关于教学、分享上下文、建议更好的方法以及维护团队规范。审查从来不主要是关于bug的,这就是为什么“机器会审查它”这个答案比听起来要弱得多。

Bug捕获是机器正在做得越来越好的部分。在Anthropic,几乎每个PR都会运行一个自动化的Claude审查员,而工程师标记的其发现错误率不到1%。自启动以来,获得实质性审查评论的PR比例从16%上升到54%。它不会批准任何东西。用Anthropic的话说,“那仍然需要人来决定。”在一项回顾性分析中,Anthropic发现,对每个变更进行自动化审查,可以在大约三分之一的、过去导致 claude.ai 事故的bug到达生产环境之前就将它们捕获。

对于一个从不疲倦的审查员来说,三分之一已经很多了。但它也告诉你一些令人不舒服的事实:大多数那些bug都通过了仔细查看变更的人。我的猜测是,那是因为在生产环境中失败的代码在diff中看起来通常是正常的。

在2026年第二季度,典型的Anthropic工程师每天合并的代码量大约是2024年的八倍,用Anthropic的话说,工程师是“指导和审查,而不是敲代码”。没有人能仔细阅读八倍的代码。从内部来看,我们的工作方式与我过去习惯的非常不同。我们每天在很多产品面上生成大量代码,不再是每一行都能得到仔细的人工阅读。几乎每个变更都会经过自动化审查,一个人仍然批准什么可以合并,而这取决于那个人来决定要深入到什么程度。这个变更需要仔细的人工审查吗?我们现有的工具在这里够用吗?这是系统的敏感部分,需要额外审查吗?如果代码通过了测试,在测试中表现良好,并且在生产环境中运行没有问题,这是一个相当好的信号。

明确其局限性也是值得的。当Anthropic调查自己的工程师时,大多数人说他们只能将工作中0-20%“完全委托”给Claude。其余的仍然涉及主动监督和检查,尤其是在高风险工作上。不阅读每一行并不等于不关注。

更让我担心的是审查曾经做的其他工作。它是初级工程师学习高级工程师思维方式的方式。任何审查员曾经在评论中说过的话,比如“这里我们不那样做”,现在都需要写在技能文档中。否则代理永远不会听到。

当阅读停止了而没有任何东西取代它

问题不是没有人阅读代码。而是没有任何东西取代了阅读。 那个早期的团队没有将信任从diff转移到检查。他们停止阅读diff,然后用速度取代了信任。他们以最糟糕的顺序完成了这个转变,而我的两个成本预测了它的结局。他们通过完全不检查将第一种成本降为零,所以他们将支付第二种成本——撤销那些从未被设计来捕获的失败,而且要加上利息。

这种顺序也不是偶然的。在上面做决定的人做出了一个决定:一旦写代码不再是瓶颈,剩下的唯一问题就是为什么任何事情还是那么慢。这些工具通常是从下往上传播的,由个人开发者决定它们是否有帮助。这种工作方式是自上而下强加的,这个差异很重要。回想一下审查的作用:教学、让人们了解变化、让团队保持自己的质量标准。命令一个团队停止阅读,你不仅仅移除了一项缺陷检查。你告诉他们那个标准不再由他们来掌握了。

有效的版本相比之下显得很无聊。每个PR都会经过一个多代理的第一轮检查,找到bug、验证它们、按严重程度排序并建议修复。对于影响范围小、敏感度低的代码变更——通常有很多这样的代码——可以在第一轮检查返回干净结果后进行较轻的人工审查。核心和敏感路径仍然需要一个负责人和仔细的人工审查,这是我投入注意力的地方。无论哪种方式,一个人批准合并。代理做第一轮检查,人类覆盖影响范围。 在这个循环中没有人会连续十三小时按回车,因为按回车从来就不是人的工作。工作本身是决定什么值得注意。帖子中提到的“没有胜利感”就是这样一种感觉:当一家公司也把这个决定从你手中拿走时。

如果你是那个按回车的人

关于这个话题的大多数建议是写给那些能够制定政策的人的。Reddit帖子中的很多人并没有这个能力。所以如果我处于那份工作入职两周的情况,我会这样做。

真正理解你想要构建的东西。 在代理碰任何东西之前,先写下你在构建什么、它必须不能破坏什么,以及你如何知道它成功了。不需要很长。那是你判断力的所在,也是你以后可以指向的工作部分。帖子中有几个人说了一个类似版本:那些仍然对自己的工作感觉良好的人设计了那个东西,然后让代理去构建它。如果你想要找回胜利感,它就在那些决定中。

用“我能解释这个吗?”作为你的测试。 帖子中的一位设计负责人问他们的团队,在他们把工作称为自己的之前,是否知道“狗身上的每一根毛”。我会将同样的测试应用到代码上。你不需要阅读每一行,但你应该能够解释这个变更做了什么、它影响了什么,以及为什么它可以安全发布。你只能真正对你能解释的事情负责。

对没有审查的内容要诚实。 如果你没有获得时间来理解一个变更,在你所在的地方说出来,比如PR描述中:“代理审查过,测试通过,我没有阅读迁移逻辑。”这不是难缠。这是你避免我在这篇文章末尾提到的crumple zone的方式。一个隐瞒自己阅读了多少的团队无法修复它。

保持你的双手练习。 Anthropic的研究人员描述了一个“监督悖论”:良好地监督Claude需要那些如果你从不使用就会衰退的编码技能。他们那里的一些工程师现在会故意时不时地不使用Claude解决问题,即使他们知道它可以处理。他们中的一个说这“帮助我保持自己的敏锐。”这值得效仿,尤其是在职业生涯早期。

如果你是设定节奏的人

最好的反驳来自那些所有文档和代码都是AI制作 startups:“它们为我们工作,我们不为它们工作。每一件事都有一个负责人,这个人需要能够解释我们做了什么。”如果你就是设定期望的人,以下是我认为由此推导出的内容。

问责制需要相应的权力。 如果一个工程师会在变更失败时被问责,他们需要在变更发布的速度以及他们首先被给予多少时间来理解方面有发言权。让一个人为他们没有设定过的节奏负责,让他们没有时间去理解的代码负责,这正是帖子中所说的当“肉盾”。这不公平,作为一个控制机制也不起作用。

衡量什么发布了,而不是数量。 已合并的PR和代码行数很容易计算,它们也是把按回车变成整个工作的数字。甚至Anthropic自己在关于8倍产出数字的文章中也说,代码行数是“一个不完美的衡量标准”。关注事故、回滚、恢复时间和客户实际体验。

为理解能力做预算,就像其他任何产能一样。 一位评论者直白地说明了新的限制:“写代码不是瓶颈,但阅读和评估是。”Anthropic关于审查也说了大致相同的话。答案不是什么都不读。是逐个领域地决定一个变更需要多少人工关注,并围绕那个来规划工作。自动化审查在这里帮助很大,但Anthropic对其的目标是缩小差距,“让审查者实际能够覆盖正在发布的内容”,而不是把审查者踢出循环。

主动为辅导留出空间。 初级人员过去通过询问高级人员问题和阅读他们的审查评论来学习。如果Claude现在回答了问题,你必须人为创造其余的东西:结对做计划、让初级人员向某个人解释代理写的变更、留一些工作手工做。帖子中有一个比较悲凉的回复是“初级人员呢?”它不应该是你公司的答案。

让你要求人们签署的东西保持在人类能处理的规模。 这对文档和代码都适用。一位评论者的产品团队让AI阅读遗留代码库并生成一份功能和差距报告:一个超过100页的HTML文件和一个包含数百行、30个标签页的电子表格。当他们反馈说这不是人类能消费的,要求从高层差距开始时,他们被当作不是团队合作者。一份没人能读的100页生成报告和没人读的5000行diff有同样的问题。 代理让长文档的制作变得免费。但一个人仍然需要能够判断它们,要求提供一页版本不是阻挠。这是审查。

“但我们的竞争对手不读代码”

我见过的最合理的反驳来自另一位初创公司工程师。他们的管理层甚至不喜欢不阅读就发布。他们只是觉得别无选择,因为下一家公司这么做,他们不能在价格上竞争。我认真对待这个观点。

我的答案是第二种成本。跳过检查不会让失败变得免费。它会把成本推到后面,到时候成本更大,而且落在你的客户身上。

所以我不认为竞争问题是读与不读。问题是哪个团队能够构建真正有效的廉价检查,并将其人员有限的注意力集中在真正能造成伤害的变更上。获胜的团队不是那个什么都不读的。而是那个知道什么值得读的。

那么谁来写测试?

Thorsten清单的一个回复问了我一直在绕圈子的问题。单元测试捕获了你对系统应该如何行为的了解,并将其与你并不完全信任的东西——也就是你自己的未来工作——进行核对。“如果你不信任的东西也在写测试,那它的作用是什么?”

这是个公平的问题。在Anthropic关于奖励黑客的研究中,模型学会了调用sys.exit(0),这样测试工具就会在任何断言失败之前退出。由它正在测试的东西编写或控制的测试并不能证明多少。

出路在于问测试从哪里获得权威。航空业的答案是独立性。DO-178C是机载软件的标准,要求最关键的验证由作者以外的人完成,合格的工具可以作为那个“人”。让一个Claude写测试而另一个写代码可以捕获最粗糙的失败,但第二个相同模型的副本共享第一个的盲点。真正的独立来自于一个不同的真实来源:人写的规格说明、参考实现、证明。

我所知道的最好的例子是Nicholas Carlini的C编译器。十六个Claude代理、近2000次会话、花费略低于2万美元,生产了一个10万行的Rust编译器,可以构建一个可启动的Linux。他的主要教训是关于检查器而不是代理:“任务验证器几乎必须是完美的,否则Claude会解决错误的问题。”当代理在内核上卡住时,他使用GCC作为已知的良好参考来定位每个bug。

SQLite展示了这条路通向何方。这个库大约有15.6万行C代码,而其测试代码是它的590倍。它最彻底的测试套件达到了100%的分支覆盖率,被设计用于满足航空电子测试标准,并且是专有的。SQLite免费提供代码,但对测试收费。所以我会这样重新表述Thorsten的观点。作为写给你未来自我的笔记的单元测试将变得不那么重要,因为你未来的自己不会是改变代码的人。作为对你并不完全信任的作者的独立检查的测试,将是你拥有的最有价值的代码。

昂贵的bug总是在上游

Thorsten说大多数bug来自问错了问题。

Ariane 5在首次飞行的不到一分钟内就被摧毁了,因为从Ariane 4重用的导航代码在Ariane 4从未飞过的轨迹上溢出了。调查委员会发现规格说明中没有包含新的轨迹。火星气候轨道器丢失是因为一个团队的软件产生了磅力·秒,而接口期望的是牛顿·秒。

每一次失败都存在于一个交界处:需求和实际飞行之间的交界、两个团队的单位之间的交界、部署和八台服务器之间的交界。 那就是昂贵的bug所在的地方,也是模型今天最弱的地方。Anthropic自己的评估是,Claude在运行一个明确指定的实验方面可以匹敌熟练的研究人员,但在“Claude在选择目标方面运用判断力方面存在很大的性能差距”。

我写过关于70%问题,后来又写了关于80%问题。每次数字上升,留给人类的是更少的敲代码和更多的判断。这就是我理解Thorsten声称产品、设计和工程三人组将会消失的方式。三个角色之间的交接消失了。三个判断保留下来,无论最终由谁来做:这个东西值得构建吗、它对使用它的人来说能用吗、以及它能撑得住吗。他关于一个特定角色也是对的。那个接收工单、交给代理、报告回来而不添加任何自己判断的人:那个工作正在消失。

说“永不”的行业

通常的反驳是,这些都不适用于bug可能导致重大问题或让人赔钱的行业。今天那些行业确实在阅读代码,我认为它们会比乐观主义者预期的更长时间继续这样做。但它们实际要求的是信任代码的理由,而当它们有理由时,它们以前也接受过机器生成的代码。

你可以验证一个代码生成器,因为它对相同的输入给出相同的输出。语言模型不会。所以目前,在飞行软件上使用模型的实用方式是老办法:一个人阅读它写的东西。前进的道路在检查方面,使用形式证明、合格的静态分析和独立的测试预言机,把模型当作一个不可信的作者,其每个输出都要被验证。

金融比人们想象的更接近。它的规则所说的很多审查实际上是关于问责的。标准大多要求变更由独立的人授权、测试和批准,而不是要求同行阅读每一行。这些都不会阻止代理做实现。它让一个人对批准负责,而那正是人应该在的地方。

计算小数点后的9

我知道的关于时间表的最强烈反对意见来自Andrej Karpathy,他去年说这“更准确地说应该是代理的十年”。他的论点来自自动驾驶,其中“每一个9都是恒定的工作量。”从90%可靠到99%与最初达到90%花费一样多。Waymo始于2009年,现在在第15个城市。

他说9是昂贵的是对的。软件不同于驾驶的地方在于,很多软件可以从模型周围的系统购买它的9,而不是从模型本身。 一个Web应用可以发布在功能开关后面,监控其错误率并在几分钟内回滚。一辆车不能回滚一次碰撞。所以我认为时间表会在我的两个成本中的第二个上分叉:你能在发布后多便宜地捕获和撤销失败。

这里是我的猜测,具体到你可以让我负责的程度:

  • 消费软件、内部工具和大多数SaaS: 对常规变更的逐行阅读在两年内将变得不常见,尽管一个人仍然会批准并拥有它。很多团队已经在那里了。
  • 企业级和金融软件: 代理将在相同的时间表上编写大部分代码,同时保留人工批准作为控制。在三到五年内,那个批准从diff转移到证据。
  • 飞行控制和最高风险医疗设备: 人们将继续逐行阅读。我不期望监管机构在很多年内仅凭合格的检查就接受安全关键代码。

同样值得记住的是,这个对话声音最大的版本发生在什么地方。在最大的泡沫Twitter上,我们走在曲线前面。行业和世界的其余部分迎头赶上还需要很长时间。但方向对我来说很清楚。

代码会发生什么

Thorsten说没有证据表明“好代码”会重要,因为我们所说的它大部分是为了让代码易于人类工作。我同意那些纯粹关于人类舒适度的部分,比如格式。但有些属性现在对代理比我们曾经对它们更重要的:名称足够独特可以grep、模块足够小可以放进上下文窗口、测试失败时清晰、部件之间边界清晰。没有这些,代理仍然会做变更。它只是看不到变更还影响了什么。好代码,现在,就是代理可以在不破坏它看不到的东西的情况下修改的代码。

我参与开源已经很久了,我认为它在这里会演进而不是死去。比以往任何时候都更容易拿一个项目、创建你自己的副本、快速重塑它,而不需要首先理解所有代码。如果越来越多的共享prompt,或者共享最终产物——当人们想要自定义时交给他们的代理——我不会感到惊讶。

开源缺乏的是维护者的注意力,而AI既淹没了它也放大了它。一月,Daniel Stenberg结束了curl的bug赏金,引用了他所说的“AI垃圾报告的爆发”。三个月后,真正漏洞的比例恢复正常,但报告总量是以前的两倍。在一年内,垃圾问题变成了数量问题。最值得分享的东西转向那些制作昂贵但检查起来便宜的东西:测试套件、规格说明、什么被破坏过的记录。

crumple zone

Madeleine Clare Elish 给自动化系统边缘的人发生的事情起了个名字:道德crumple zone。在汽车中,crumple zone被设计用来吸收冲击,这样乘客就不必了。在一个自动化做了大部分工作的系统中,最近的人通常扮演同样的角色。他们为一个他们几乎没有真正权力去防止的失败承担责备。

那个连续十三小时按回车的工程师正站在一个crumple zone里。他们的名字在批准上。但节奏、检查和什么值得阅读的决定都是在别处做出的。当事情破裂时,事故调查会发现批准它的那个人。

逐行阅读从来不是让软件值得信赖的原因。它是一种确保一个人理解他们正在发布什么并处于可以说“不”的位置的方式。逐行阅读对大多数代码正在消失,我认为这没问题。但理解和说“不”的能力不能随之消失。

Teleport在一个季度内发现了相当于两年的安全漏洞。十三名工程师、最先进的大模型、自有代码库:高严重性漏洞的数量是前两年总和的近两倍。让我感兴趣的是这对工作队列意味着什么。发现漏洞的成本降低了好几倍。但分类没有,而确认哪些真正可利用仍然需要人阅读代码。发现速度快过修复速度,你就用已知的积压换掉了未知的积压。在你动手审查自己的代码库之前,值得先读一读这份报告 → https://fandf.co/4r3xdeX · 由 Teleport 赞助。 #ad

所以这是我现在的建议,取代两年前我说的话。知道什么值得阅读。在你不读的代码上,构建你真正信任的检查,并保持它们独立于写代码的任何东西。在代理构建之前写下你要构建什么。能够解释你发布的每一样东西,并对不能解释的保持诚实。如果你为别人设定节奏,给他们与你要求的问责相匹配的权力。

我曾经把好代码称为给下一个开发者的情书。我仍然相信这一点。但越来越多地,下一个开发者是代理,所以情书现在看起来不同了。它是代理可以在不破坏它看不到的东西的情况下修改的代码。工艺没有消失。它转移到了决定代码是否值得被信任的部分。

感谢时事通讯的赞助商们在过去几个月的支持。由于我已全职加入一个新角色,我已暂停未来期刊的赞助。这里表达的观点是我自己的,不代表我的雇主或组织的观点或意见。只要我的想法对你有帮助,我希望继续在时事通讯上写作和分享:)

评论

(0)
未配置登录方式
暂无评论