目录
17:48 提的 PR,1400 行 diff。
17:49 一条评论:LGTM 👍
40 秒读完 1400 行,平均 35 行每秒。这个速度不叫审阅,叫签收。
LGTM 有意思的地方在于它是二值的、不可证伪的:「我仔细看了,逻辑没问题」用的是它,「我今天想早点下班」用的也是它。字面上完全一样。
下面这份图鉴,每一条都试着把这层压缩解开,看看底下是什么。以及——研究数据说,这件事本来应该怎么干。
一、评审现场图鉴
「LGTM 👍」型
见上。
顺带一个不严谨但很有用的观察:LGTM 出现的频率和 diff 的大小正相关。 40 行的 PR 下面往往有七八条讨论,1400 行的 PR 下面常常只有一个 👍。这不是巧合,第三节会给出原因。
「nit:」型
1400 行改动里,唯一一条评论落在了缩进上:
nit: 这里建议用 2 空格
nit 是 nitpick 的缩写,本意是「吹毛求疵,我知道这不重要」。但在实践里,它经常变成 reviewer 证明自己确实打开过这个页面的收据。
「bikeshed」型
1957 年,C. Northcote Parkinson 讲过一个虚构的委员会:审议核电站反应堆,3 分钟通过;审议自行车棚用什么建材,吵了 45 分钟。
理由很朴素——反应堆没人真懂,车棚人人都懂。当一件事超出所有人的判断力时,众人会自动退回到自己有资格表态的那一小块地方。
代码里一模一样:一个 40 行的并发改造无人评论,而变量叫 data2 还是 result,下面挂了 40 条回复。
「这个函数太长了」型
没有阈值,没有替代方案,没有指认哪一段是多余的。作者收到之后只能猜,最常见的应对是把函数机械地拆成两个——原来的问题一点没变。
「大 PR 恐惧症」型
reviewer 打开 3000 行的 diff,滚了两屏,心想「这么大的改动,作者肯定自己测过了」,于是 LGTM。
「AI reviewer」型(2026 新增)
把 diff 丢给模型,回车,粘贴:
这里可能存在空指针风险,建议添加错误处理。
结构完整、语气专业、定位模糊——「这里」是哪里?哪个输入会触发?
「评论区比代码精彩」型
一个 rename PR,代码改了 6 行,评论 60 条。最后大家达成共识:下次单独开一个 PR 改名字。
(然后并没有下次。)
二、把「LGTM」拆开:它到底在说什么
同一个 LGTM,至少压着三种不同的意思:
| 可能的语义 | 说的是什么 | 代价 |
|---|---|---|
| 信任代理 | 「作者比我熟这块,我信他」 | 信任被固化成了流程 |
| 社交润滑 | 「我不想当那个卡住 PR 的人」 | 拦截功能静默失效 |
| 免责声明 | 「我点了批准,出事别找我」 | 责任被形式化地转移了 |
区分方法意外的简单:看它有没有伴随一句「我重点看了 X」。
真读过的审阅者,几乎总会说出自己看了什么、跳过了什么。这条经验在实践中比任何流程文档都准——因为「看过」这件事没法伪装成沉默。
三、研究怎么说:评审真正抓到了什么
起源:从「正式检查」到「现代评审」
1976 年,IBM 的 Michael Fagan 发表了设计评审与代码检查(inspection)的流程,把评审定义成一道有角色、有清单、有度量的质量门禁:主持人、读者、记录员、作者,按行逐条过。这是评审第一次被制度化。
2008 年,Google 为 Android 项目做了 Gerrit,评审被工具化成异步、轻量、贴着每一次提交走的一步。评审从「一场会议」变成了「一个页面」——这就是今天说的 modern code review。
工具变了,隐含的假设也变了:正式检查假设评审是一个高成本的仪式,所以要做厚;现代评审假设它是一个低成本的日常动作,所以要做薄。问题出在中间:流程做薄了,但期待还留在厚的那一端。
微软的研究:找 bug 并不是第一名
Bacchelli 和 Bird 在 ICSE 2013 发表的《Expectations, Outcomes, and Challenges of Modern Code Review》,在微软做了访谈、现场观察和评论分类,结论相当反直觉:
- 开发者自报的最高动机确实是找缺陷;
- 但在 200 次评审、570 条评论的实际分类里,「代码改进」占 29%,「发现缺陷」只占 14%;
- 而且被发现的缺陷大多是小颗粒的:边界情况、运算符优先级、配置值写错——不是架构问题,也不是安全问题;
- 真正的收益反而落在知识传递、团队认知、替代方案讨论上。
翻译一下:你指望评审拦住线上事故,但数据说它更擅长让大家知道彼此在干什么。这不是坏事,前提是你别对它抱错的期待。
Google 的研究:评审是轻的,而且必须轻
Sadowski 等人 2018 年的《Modern Code Review: A Case Study at Google》看了约 900 万次变更:
- 75% 的变更只有一位审阅者;
- 变更的中位数大小是 24 行,35% 只碰一个文件;
- 超过 80% 的评审一轮就结束,70% 的变更在 24 小时内合入。
Google 自己工程实践文档里的建议也朴素到近乎无聊:普通 CL 大概 100 行是合理的,1000 行基本就太大了。
注意这里的方向:不是「Google 的员工更自律所以 diff 小」,而是在 Google 的流程里,一个 1400 行的 CL 根本走不到合并那一步——它会在评审入口就被要求拆开。
Cisco 的实验:超过 400 行,审查开始失效
SmartBear 整理的 Cisco 案例(2500 次评审、50 名程序员、320 万行代码,追踪 MeetingPlace 团队 10 个月)给出了量化边界:
- 一次审阅 200–400 行是有效区间;
- 检查速度超过 500 行/小时之后,缺陷发现密度显著下降;建议控制在 300–500 行/小时;
- 单次评审超过 60 分钟,效果开始明显衰减;
- 有的整理给出的分组数据更直观:1–200 行的检出率约 87%,超过 1000 行掉到三成以下。
把这些放在一起
四组独立证据,指向同一个结论:
代码评审不是一道「质量门」,而是一条「注意力通道」。 它的通过量有上限——200–400 行、60 分钟、500 行/小时。你把它当门,就得接受这道门的宽度;你一次往门口推 3000 行,得到的不是更严格的审查,而是更快的批准。
这也正面回答了第一节那个观察:为什么 LGTM 在大 PR 上出现得更频繁。
四、四个让评审失效的机制
-
注意力是线性的,理解成本不是。 读第 1 行和读第 900 行时,你脑子里的上下文不一样。diff 越大,后半段的边际审查质量越低。这就是 200–400 行这条线的技术依据,不是什么整齐的约定。
-
社会压力会替代技术判断。 作者在等,评审在排队,最省事的动作是批准。这不是人品问题,是排队系统的默认输出——只要「批准」比「问一句」便宜,系统就会生产批准。
-
不可执行的判断等于没有判断。 「这个函数太长了」信息量为零。可执行的版本是:「第 40–70 行的三个分支只为了处理空值,建议在入口处归一化,这段就不需要了。」给出替代实现,或给出明确阈值,才算反馈。
-
评审的好处是沉默的。 一个被拦下的 bug 不会出现在任何看板上,写代码的产出却会。就像《如何向爸妈解释你的工作》里说的:中间环节的工作之所以难被认可,是因为它最成功的形态就是「什么都没发生」。
五、六个今天就能用上的杠杆
-
把 PR 变小。 理想 200 行以内,硬上限 400。纯机械改动(重命名、格式化、移动文件)单独开一个 PR——它应该由工具生成,也应该由工具批准。
-
PR 描述先写「为什么」。 reviewer 的第一分钟应该花在理解意图上,而不是从 diff 里反推意图。写清三件事:改之前是什么行为、改之后是什么行为、为什么必须改。
-
给评论分级。 最简单三档:
nit:(可改可不改)、suggestion:(建议但非阻塞)、blocking:(必须改,且要写清判据)。有了分级,作者知道该改哪些,reviewer 也才敢把小事写出来——小事能写出来,人才不会把意见攒成一次爆发。 -
把机械检查全部交给机器。 格式、lint、类型、单测、依赖漏洞扫描——这些都有确定答案,让 CI 去说。人的注意力只该花在机器回答不了的问题上:设计是否合理、命名是否表达了意图、边界语义是否说清了。
-
给评审定 SLA,先修排队、再修审查。 在 DORA 那套指标里,change lead time 的大头常常不在写代码,而在等。24 小时内首响应是个务实的目标。这里有个会自我强化的循环:响应越慢,diff 越大;diff 越大,评审越烂;评审越烂,响应越慢。
-
作者先自审一遍。 提交前自己把 diff 从头看一遍。这一步能摘掉相当一部分「我自己都看得出来不对」的问题,也能顺手给 reviewer 写一句导航:「重点看
auth/session.ts,其它都是机械改动。」
六、AI 时代的新问题
2026 年,评审被两头同时夹击。
一头是供给。 AI 让写代码变快了,同一个人一天产出的 diff 可能是过去的几倍,《AI 生成代码的翻车现场》里那类问题也更容易被一并产出来。但评审通道的宽度没有变——原来 200–400 行/次的通道,现在每天要过更多行。这不是 reviewer 变懒了,是流程被供给了。
另一头是审阅者。 AI reviewer 很擅长一致性检查:命名风格、代码模式、已知漏洞库。这部分它确实比人强,也比人便宜。但它不擅长两个问题——「这个需求本身对不对」和「这段代码三个月后还有没有人敢动」。它能给出很多「可能存在 X 风险」,很少能说出「如果这样,那设计里有三个地方会同时崩」。
所以合理的分工大致是:
- 机器负责一致性:格式、模式、已知缺陷、测试覆盖率;
- 人负责意图:这个改动是不是解决问题的正确方式,这个新增抽象是否值得它的维护成本。
要小心的最后一件事是评论通胀:当一条「建议添加错误处理」的评论成本接近零时,评论数量会涨,而每条评论的平均判断力会掉。数量不是质量——这和《技术债的识别与管理》里的逻辑一样:能被自动产出的东西,不能直接当作产出。
写在最后
LGTM 的真相,通常不是「审阅者不负责任」。
一个人在一天里被塞进六个 800 行的 PR,每个都要求他承担一次事故的连带责任,那他给出的最优解就是最快地点下批准。这是流程设计的结果,不是道德水平的结果。
反过来也成立:当你把 diff 压到 200 行、把机械检查交给 CI、在描述里先写清「为什么」,LGTM 会自己变回一句真话——因为这时候它真的只值 40 秒。
参考来源
- Expectations, Outcomes, and Challenges of Modern Code Review(Bacchelli & Bird, ICSE 2013)
- Modern Code Review: A Case Study at Google(Sadowski et al., ICSE-SEIP 2018)
- Best Practices for Peer Code Review — SmartBear(Cisco 案例)
- Design and code inspections to reduce errors in program development(Fagan, 1976)
- Google Engineering Practices:Small CLs
- The Law of Triviality(Parkinson, 1957)
- DORA:Software Delivery Performance Metrics
延伸阅读:本博客里还有两篇讲「评审之外的另一半」的文章——《Git 工作流最佳实践:从 rebase 到 squash》和《代码可读性:写出别人看得懂的代码》。