目录
3106 字
16 分钟
Code Review 人间百态:LGTM 背后的真相

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. 注意力是线性的,理解成本不是。 读第 1 行和读第 900 行时,你脑子里的上下文不一样。diff 越大,后半段的边际审查质量越低。这就是 200–400 行这条线的技术依据,不是什么整齐的约定。

  2. 社会压力会替代技术判断。 作者在等,评审在排队,最省事的动作是批准。这不是人品问题,是排队系统的默认输出——只要「批准」比「问一句」便宜,系统就会生产批准。

  3. 不可执行的判断等于没有判断。 「这个函数太长了」信息量为零。可执行的版本是:「第 40–70 行的三个分支只为了处理空值,建议在入口处归一化,这段就不需要了。」给出替代实现,或给出明确阈值,才算反馈。

  4. 评审的好处是沉默的。 一个被拦下的 bug 不会出现在任何看板上,写代码的产出却会。就像《如何向爸妈解释你的工作》里说的:中间环节的工作之所以难被认可,是因为它最成功的形态就是「什么都没发生」。

五、六个今天就能用上的杠杆#

  1. 把 PR 变小。 理想 200 行以内,硬上限 400。纯机械改动(重命名、格式化、移动文件)单独开一个 PR——它应该由工具生成,也应该由工具批准。

  2. PR 描述先写「为什么」。 reviewer 的第一分钟应该花在理解意图上,而不是从 diff 里反推意图。写清三件事:改之前是什么行为、改之后是什么行为、为什么必须改。

  3. 给评论分级。 最简单三档:nit:(可改可不改)、suggestion:(建议但非阻塞)、blocking:(必须改,且要写清判据)。有了分级,作者知道该改哪些,reviewer 也才敢把小事写出来——小事能写出来,人才不会把意见攒成一次爆发。

  4. 把机械检查全部交给机器。 格式、lint、类型、单测、依赖漏洞扫描——这些都有确定答案,让 CI 去说。人的注意力只该花在机器回答不了的问题上:设计是否合理、命名是否表达了意图、边界语义是否说清了。

  5. 给评审定 SLA,先修排队、再修审查。 在 DORA 那套指标里,change lead time 的大头常常不在写代码,而在等。24 小时内首响应是个务实的目标。这里有个会自我强化的循环:响应越慢,diff 越大;diff 越大,评审越烂;评审越烂,响应越慢。

  6. 作者先自审一遍。 提交前自己把 diff 从头看一遍。这一步能摘掉相当一部分「我自己都看得出来不对」的问题,也能顺手给 reviewer 写一句导航:「重点看 auth/session.ts,其它都是机械改动。」

六、AI 时代的新问题#

2026 年,评审被两头同时夹击。

一头是供给。 AI 让写代码变快了,同一个人一天产出的 diff 可能是过去的几倍,《AI 生成代码的翻车现场》里那类问题也更容易被一并产出来。但评审通道的宽度没有变——原来 200–400 行/次的通道,现在每天要过更多行。这不是 reviewer 变懒了,是流程被供给了。

另一头是审阅者。 AI reviewer 很擅长一致性检查:命名风格、代码模式、已知漏洞库。这部分它确实比人强,也比人便宜。但它不擅长两个问题——「这个需求本身对不对」和「这段代码三个月后还有没有人敢动」。它能给出很多「可能存在 X 风险」,很少能说出「如果这样,那设计里有三个地方会同时崩」。

所以合理的分工大致是:

  • 机器负责一致性:格式、模式、已知缺陷、测试覆盖率;
  • 人负责意图:这个改动是不是解决问题的正确方式,这个新增抽象是否值得它的维护成本。

要小心的最后一件事是评论通胀:当一条「建议添加错误处理」的评论成本接近零时,评论数量会涨,而每条评论的平均判断力会掉。数量不是质量——这和《技术债的识别与管理》里的逻辑一样:能被自动产出的东西,不能直接当作产出。

写在最后#

LGTM 的真相,通常不是「审阅者不负责任」。

一个人在一天里被塞进六个 800 行的 PR,每个都要求他承担一次事故的连带责任,那他给出的最优解就是最快地点下批准。这是流程设计的结果,不是道德水平的结果。

反过来也成立:当你把 diff 压到 200 行、把机械检查交给 CI、在描述里先写清「为什么」,LGTM 会自己变回一句真话——因为这时候它真的只值 40 秒。

参考来源#

延伸阅读:本博客里还有两篇讲「评审之外的另一半」的文章——《Git 工作流最佳实践:从 rebase 到 squash》和《代码可读性:写出别人看得懂的代码》。

Code Review 人间百态:LGTM 背后的真相
https://www.hehonglei.cn/posts/code-review-hall-of-fame/
作者
Honglei He
发布于
2026-10-11
许可协议
CC BY-NC-SA 4.0