AI时代的代码审查
随着AI让代码产出越来越快,代码审查成了团队将个人成果转化为共同理解、集体判断和持久软件的关键环节。
我以前觉得代码审查主要是一个必要的检查点:在代码进入公共代码库之前必须经过的一步,有时有用,有时拖沓,常常给人拖累感。
自从AI编程工具成了日常工作的部分之后,我开始以不同的眼光看待代码审查。
第一个变化并不是代码突然变好了,也不是bug消失了,而是初稿来得更快了。PR变得更容易创建,但不一定更容易理解。审查队列可能更快积压起来,而审查所需的认知负担并没有减少,有时反而增加了。
这让我更认真地思考:代码审查的真正目的是什么?
当代码变得廉价,理解就变得昂贵
很长一段时间以来,我们一直在努力缩短“想法”与“初稿”之间的距离。AI把这段距离缩得更短。这很有用:它能帮人打破僵局、探索不同方案、减少重复性工作。
但速度会改变稀缺性。当代码更容易产出时,理解就变得更难守护。一个改动今天能跑通,却可能留下一些谁都不记得曾经做过的假设。
AI生成的代码让这个问题更加微妙,因为它常常看起来像“成品”。它可能看上去规范、连贯,但实际上并不契合系统,或者忽略了某个领域规则,又或者假设了一条在生产环境中并不成立的错误路径。
这就是为什么代码审查依然重要。不是因为人比AI更会打字,也不是因为每一行代码都值得怀疑。审查,是把个人的产出转化为团队共识。
当代码变得更廉价,理解就成了稀缺资源。而代码审查,正是团队保护这种理解的方式之一。
审查的真正目的
我想坦诚说一件事。我见过的大多数代码审查,包括我自己做过的,大多只是扫一眼表面问题:命名、格式、明显的逻辑错误。而这些问题,工具越来越多地能在人打开PR之前就捕捉到。
所以,人们自然会想:人类还有必要读代码吗?也许只要验证输出就够了:跑通测试、点一点功能、确认行为正确。
但输出验证只能告诉我们,在我们想到要测试的那些情况下发生了什么。而审查,是我们去发现那些我们的测试根本没有想过的有风险的地方。
审查更高的价值在于判断。
这个改动符合我们约定的架构吗?它尊重了那些只存在于我们脑子里、没有写在任何文档里的领域规则吗?它引入了将来要偿还的耦合吗?它是否暴露了敏感数据、或者跳过了权限检查,当风险是与背景相关,而非关结构?
有人可能会说,更好的智能体框架、更强的评测、更清晰的提示词、更周到的智能体工作流,可以降低这些风险。团队确实应该用这些工具。但是,即使是一个非常强大的AI工作流,仍然需要有人来负责判断:这个改动是否契合产品、架构、实际运行环境,以及团队愿意交付的质量标准。
这些都是关于共同所有权的问题。AI能生成代码,但它不拥有这个系统。拥有系统的是我们。
我不得不做的转变是:从把审查看作“找bug”,转变为把它看作“判断的检查点”。 bug当然重要,但更深层的问题是:我们是否理解这段代码为什么能工作、什么时候会失败、将来会让我们付出什么代价?
上下文问题
我参与过的大多数既慢又痛苦的审查,都有一个共同根源:审查者只能从代码本身反向推导出作者的想法。
PR描述含糊不清,需求信息不完整。用了AI,但没人说哪些部分是用AI生成的、哪些是人工检查过的、哪些假设还没有被验证。审查者打开diff,开始做侦探的工作。
这不是审查。这是重构思路。而且非常累人。
解决办法不是加流程,而是在审查开始之前,由作者提供更多的上下文。一个好的PR应该回答:这个问题解决了什么?哪些是有意改动的?哪些是有意放在范围之外的?AI用在了哪里,作者亲自验证了哪些部分?审查者应该重点关注什么?还有哪些不确定的地方?
这些不需要很长。几句话往往就够了。但没有它们,团队里的每个审查者都得独立重建同一份思维模型。这是浪费时间,而且会随着每个PR被成倍放大。
最快的审查,不是评论最少的那个,而是在第一条评论写下之前,上下文就已经很清晰的那个。
作者的责任
AI让生成代码变得容易,但这不意味着第一个生成的版本就该直接变成PR。
我逐渐形成了一种纪律,我称之为作者的责任:在你请求另一个人花时间检查你的工作之前,你自己应该已经认真地投入过注意力。读一遍代码,能简化就简化,删掉与目标无关的改动,确保你能解释清楚每一个改动的文件以及为什么改。
我用的检验标准很简单:如果我解释不了这个实现,我就还没有准备好请求审查。
这不是反AI。这是支持“问责制”。一旦作者不再是那个理解代码的人,审查者就成了第一个真正认真思考这段代码的工程师。那不是协作,那是把责任向上外包,交给一个本职是保护代码库的人,而不是替你做设计工作的人。
还有一个有力的论点是:PR要尽量小。AI让忽略这一点变得很有诱惑力。一个生成的diff可能会非常大。但人没法很好地审查巨大的diff。我们只会扫一眼,我们会批准那些并没有完全理解的改动,因为返回代价太高,而且PR已经挂了三天了。这就是技术债务进入系统的方式:不是因为没人关心,而是因为审查的体量已经大到失去了意义。
如果你的团队正在用AI更快地交付代码,你应该对PR的大小要求更严格,而不是更宽松。
当一个大的改动不可避免时,作者应该把机械性的部分和判断密集的部分分开:隔离生成的改动,说明整体策略,让审查的表面范围比实际diff更小。
审查者应该关注什么
如果我们承认应该将格式化、静态检查、基本测试执行这些事交给工具,那么人类的审查时间就太宝贵了,不应该花在工具已经能做的事情上。问题是,审查者应该关注什么?
架构与契合度:这个改动属于我们已经搭建的结构吗?它引入了不必要的耦合或重复吗?
领域正确性:它遵循了那些只存在我们脑子里的规则吗?比如数据如何流转、哪些字段是敏感的、什么条件下允许用户执行什么操作。
运行风险:当它失败时会发生什么?错误处理是诚实的吗?重试循环会不会导致下游过载?
安全假设:扫描器能找到有漏洞的模式,而人能找到危险的假设。扫描器可能不知道某个端点绕过了团队的标准权限校验,或者某个API响应里返回的字段本不该暴露给这个调用者。这些都是上下文问题,而不是模式问题。
可维护性:六个月后,另一个开发者还能理解这段代码吗?作者自己还能理解吗?
最后这一点比听起来重要得多。大量使用AI的一个隐性成本是:开发者可能会交付他们并不真正拥有的代码。而审查应该成为一个检查点,确保所有权的转移是真实的。作者真的理解他们要合并的代码,而不仅仅是通过测试。
审查是学习,不仅仅是把关
我还没提到的代码审查的另一个、我认为长远来看最重要的那个理由是:审查是团队建立共同判断力的方式。
初级工程师看到资深工程师指出一个抽象为什么有风险,就学到了东西;后端开发者读了一条解释前端如何依赖某个API契约的评论,就理解了依赖;新成员通过审查中发现隐藏的领域规则,而不是在一份没人看的wiki里,就吸收了它们。
在AI时代,这个学习功能变得更重要,而不是不重要。如果AI写了更多的初稿,人类就少了些自然的机会去遇到完整的设计问题和权衡。审查就变成了工程判断力发展和传播的主要场所之一。
AI可以解释通用概念,这很有用。但代码审查教给团队的是专属的判断力:这个代码库接受什么样的权衡、哪些抽象以前失败过、这个产品里哪些风险真正重要、这里的“质量”到底意味着什么。
实际操作
以上所有这些,并不意味着审查应该很慢,而是说它应该有目的性。
对作者来说: 在开PR之前先自我审查;写清晰的描述;说明哪里用了AI、验证了什么;让PR足够小,小到审查者真的能思考它;并标出哪些地方需要关注,哪些地方可以快速略过。
对审查者来说: 从需求开始,而不是从diff开始;检查解决方案是否符合架构;寻找隐藏的假设;将测试视为意图的证据,而不是装饰;区分哪些是必须改的,哪些是“可以更好”;先提问,不要先指责。
对双方来说: 把代码和人分开,审查不是一场表演,不是用来证明专业能力或捍卫决策的;审查是两个或更多的工程师,试图让系统变得比他们任何一个人独自工作时更好。
AI可以生成代码,可以总结diff,可以建议边界情况,可以标记可疑模式。这些都是真正有用的贡献。
即使AI能访问大量的上下文,“能访问”不等于“能负责”。它可以检索架构笔记、总结故障报告、从代码库里推断模式,但它不会承担一个糟糕的抽象、一次脆弱的发布、或者一个让未来一年维护更困难的决定所带来的后果。
我们的目标不是不信任AI,而是设计出这样的工作流:AI提高杠杆,但不会削弱所有权。
**而代码审查,正是所有权得以行使的地方。**在AI时代,这个功能并没有过时,它比以往任何时候都更必要,因为代码来得更快了,而判断,仍然必须来自我们自己。