一个 38 行的改动从提交到合并走了 49 小时,其中人工阅读 22 分钟。剩下那 48 小时不是"评审慢",是改动在等一个有空的人。团队的反应通常是"加评审人"或"定 SLA",两者都跳过了真问题:评审要的是一段足够长、不被打断的时间,而这不能塞进队列任意位置。
这篇给判据:成本结构、瓶颈位置、哪些优化真的有效。
1. 评审负载的三个成本
| 成本 | 形态 | 谁承担 | 可见性 |
|---|---|---|---|
| 等待 | 作者空转 | 作者 | 高,被当成正常 |
| 上下文重建 | 重新加载意图与历史讨论 | 评审者 | 低,不计入工时 |
| 质量下降 | 深度审查退化为格式检查 | 全团队 | 极低,几季后认账 |
三者是递进关系。等待最容易看见,也最容易被行政手段压缩;上下文重建是隐性的,只能靠减少评审次数降;质量下降是延迟的,显形时账已记到测试头上。
提交 09:12
├─ CI 通过 09:19
├─ 指派评审人 09:19
├─ 首次反馈 次日 11:40 ← 26 小时后
├─ 作者修改 次日 14:05
├─ 二次反馈 第三日 10:20
└─ 合并 第三日 11:02
// 改动 38 行,净评审 22 分钟;瓶颈不是阅读速度,是"找到一段能读的时间"
2. 评审消耗的是连续时间
评审用不了碎片时间,不是不愿意,是做不到。读 diff 要求把"原来怎么跑"和"改完怎么跑"同时装进脑子,这个状态建立要十几分钟,被打断一次就归零。
| 时间形态 | 支撑的深度 | 来源 |
|---|---|---|
| 10–15 分钟碎片 | 格式、命名、笔误 | 会议间隙、等构建 |
| 45 分钟连续 | 单文件逻辑、边界条件 | 上午第一段 |
| 90 分钟连续 | 跨模块影响面、失败路径 | 需主动预约 |
所以"评审容量"不能按"每天 8 小时的 10%"算。正确口径是每人每天有几段 45 分钟以上、不被打断的窗口——多数团队 1 到 2 段。
// 容量粗算(典型量级,按团队实际校准)
可评审窗口 = 1.5 段/人/天(45min 以上、不被打断)
有效速率 = 150–250 行/45min(含理解上下文,不含验证)
六人团队日容量 = 6 × 1.5 × 200 ≈ 1800 行
// 口径:所有评审阅读量合计不超此值,不是"每天新增 1800 行"
3. 决定评审时长的四个因素
| 因素 | 影响形态 | 可优化性 | 手段 | 代价 |
|---|---|---|---|---|
| 改动大小 | 近似线性,过规模后超线性 | 高 | 拆分 | 协调成本上升 |
| 影响面 | 非线性,跨模块多一次加载 | 中 | 声明影响面 | 写不清就是没想清 |
| 熟悉度 | 熟人 20 分钟,生人 90 分钟 | 中 | 固定模块负责人 | 人休假就断 |
| 队列长度 | 饱和后起决定作用 | 高 | 限在制品 | 与"随时能提"冲突 |
前三项没调好就调第四项,等于给漏水的桶加水。队列一进饱和区,前三项的优化全被抹平:等待时间由"前面排了几个"决定。
4. "改动越小越快"的边界
这句话有下限。
| 单次改动 | 净评审时长 | 次数 | 总人工 | 协调成本 |
|---|---|---|---|---|
| 800 行 | 90 分钟以上,质量不可靠 | 1 | 90+ | 低 |
| 300 行 | 约 35 分钟 | 1 | 35 | 低 |
| 100 行 | 约 12 分钟 | 1 | 12 | 低 |
| 30 行 × 5 | 约 5 分钟 | 5 | 25 | 中:CI×5 |
| 10 行 × 15 | 约 3 分钟 | 15 | 45 | 高:15 次唤醒 |
曲线在 100–300 行触底。再往下拆,上升的主要不是阅读时间是唤醒次数——它不进任何计时器,总被低估。
真正的下限不是行数,而是"一个可被独立验证的行为变更"。单独存在无法验证的改动(只有另一半才生效的开关)再小也不该单提。
5. 队列长度由在制品决定
等待时间不是评审速度的函数,是在制品数的函数。
// Little's law:平均排队 = 在制品 / 吞吐率
在制品 12,每周处理 8 → 平均排队 1.5 周
// 压到 1 天要吞吐 60/周(不可能)或在制品 1.6(不现实)
// 现实解只有一个:同时开着的改动数量必须降下来
| 在制品 | 每周吞吐 | 平均排队 | 团队观感 |
|---|---|---|---|
| 8 | 8 | 1 周 | 看运气 |
| 16 | 8 | 2 周 | 评审太慢,得加人 |
| 32 | 8 | 4 周 | 直接合,不看了 |
最后一行是真正的失效点:排队到一定程度,团队会绕开评审而不是等待。负载管理的目标不是让人看得更快,是让队列短到没人想绕开。
6. 指定评审人与自选评审人
| 维度 | 指定 | 自选 |
|---|---|---|
| 保证 | 一定有人看 | 看的人大概率懂 |
| 失效 | 指给不熟的人 | 没人认领 |
| 负载 | 集中到少数"可靠的人" | 熟人圈,新人进不来 |
| 适用 | 关键路径、合规、跨团队接口 | 探索性改动、文档 |
有效组合是两层:机器可读的归属规则保底,人可补充。
src/payment/** @team-payment
migrations/** @db-owner
规则的价值不在"指定",在可审计:谁默认队列堆了 20 个待评审,一眼看得出;自选没这个性质,负载不均只能靠感觉。
7. 过载不会表现为抱怨
过载表现为评审行为形态的变化:
- 净评审时长骤降,从 40 分钟掉到 6 分钟——阅读退化为扫一眼;
- 评论只剩 LGTM——已经没有判断发生;
- 主动跳过测试文件——最该看的部分被放弃;
- 首轮反馈变快、二次反馈变慢——成本从评审者转到作者。
最后一条最像"变快了",实际把一轮评审变成三轮;只看首次反馈时长的度量会奖励它。
8. 吞吐手段按成本排序
| 顺序 | 手段 | 成本 | 收益 | 副作用 |
|---|---|---|---|---|
| 1 | 减少单次改动量 | 作者组织成本 | 高,缩短净时长 | 拆过头协调反超 |
| 2 | 明确评审范围 | 十分钟 | 高,省掉搜索 | 写错会漏看 |
| 3 | 异步评审 | 文化与工具改造 | 中,移出会议 | 讨论发散 |
| 4 | 增加评审者 | 招募与培养 | 中,短期扩容量 | 责任分散 |
| 5 | 强制时限 | 一个配置 | 看似高,实为转移 | 时限一到就过 |
前三项动结构,后两项动压力。压力见效快、退化也快:加人三个月后回到原点,新人熟悉度没建立,队列又长回来了。
范围声明是最便宜的杠杆:
─── 改动范围
src/order/ 下的重试逻辑与退避策略
─── 不在范围
支付网关签名实现(另一 PR)
─── 评审重点
1. 重试上限与幂等键是否配合成立
2. 超时预算是否被翻倍(单次 800ms × 4 次)
3. 退避耗尽后的错误码是否与契约一致
9. 评审 SLA 的作用与副作用
SLA 能保证"有人看一眼",不能保证"看懂了"。三种写法后果完全不同:
// A. 提醒式:4 小时无首次反馈 → 频道提醒
// 副作用可忽略;解决的是遗忘,不是容量
// B. 升级式:12 小时无反馈 → 升级到模块 owner
// 副作用是噪声;升级走成常规后失效
// C. 强制式:24 小时自动合并(无需 approve)
// 门禁形同虚设,被绕过的总是最难的那部分改动
C 的危险在于短期有效:队列短了,指标好看了;代价在两三个季度后以"线上问题查不出是谁引入"的形式出现。
10. 评审与质量门禁的分工
第一手段不是排班,是把能自动化的判断搬走。
| 检查项 | 门禁 | 人 |
|---|---|---|
| 格式、命名、import 顺序 | 是 | 否,看到也不该说 |
| 依赖方向、分层违规 | 是(结构断言) | 仅无法自动修时 |
| 语义正确性、边界条件 | 否 | 是 |
| 失败路径与重试语义 | 否 | 是 |
| 数据迁移可逆性 | 部分(dry-run) | 是 |
判据:能写成确定性断言的意见必须工具化;写不成断言的,才有资格占用连续时间。 同一条意见出现三次还没工具化,说明团队在用最贵的资源做最便宜的事。
11. 度量:五个数
| 指标 | 定义 | 读法 | 误读风险 |
|---|---|---|---|
| 首次反馈时长 | 提交到首条意见 | 队列健康度 | 只压它奖励敷衍 |
| 净评审时长 | 在评审页的实际时长 | 审查深度 | 无埋点只能用评论数代理 |
| 评论密度 | 意见数/百行 | 改动复杂度 | 高密度可能是格式噪声 |
| 被打回率 | 需二次修改的比例 | 首轮质量 | 降低可能是标准降低 |
| 负载分布 | 最大/最小队列比 | 单点依赖 | 均衡不等于健康 |
// 首次反馈时长(PR 事件流,分钟)
ttfr = first_event(type == "review") - first_event(type == "ready_for_review")
// 净评审时长需前端埋点;无埋点时用"评论时间戳首尾跨度"作下界
判据:首次反馈在改善而净评审在恶化,你优化的是队列,不是评审。
12. 排错:五种"评审很慢"
| 现象 | 真实原因 | 处理 |
|---|---|---|
| 平均等两天,评审者说"我天天看" | 队列超过日容量,他看到队尾 | 先降在制品 |
| 大改动快过、小改动慢 | 大改动被当事件,小改动没人认领 | 给默认评审人 |
| 加两人,等待没变 | 新人不熟,净评审翻倍 | 先做知识转移 |
| 意见很多但作者不改 | 阻塞项过多即无优先级 | 限制阻塞项数量 |
| 合并很快但线上问题变多 | 强制 SLA 或门禁被绕 | 时限改升级,不改自动合并 |
第一条是最常见的误诊:团队看到"评审者不积极",实际是他的日容量被队列吞掉了——他在看,只是永远看队头以外。
13. 边界:什么时候不值得做
| 场景 | 值得吗 | 理由 |
|---|---|---|
| 单人变更 | 不值得 | 没有队列,只有有空/没空 |
| 纯文案、配置、版本升级 | 不值得 | 净评审趋零,成本更高 |
| 已有强自动化门禁兜底 | 收益低 | 人工评审已退化为确认 |
| 多人跨模块、改动频繁 | 值得 | 队列效应显形 |
适用前提只有两条:有队列,且队列长度影响交付。不成立时,做 TTFR 看板只是让团队优化一个不存在的问题。
14. 自测
- 日历时间 49 小时、净评审 22 分钟,先动哪一头?
- 为什么"每人每天 10% 时间评审"这个口径是错的?
- 改动从 300 行拆到 10 行,总人工为什么反而上升?
- 在制品 16、每周吞吐 8,平均排队多长?加评审人能改善吗?
- 首次反馈变快、二次反馈变慢,评审者在做什么?
- 同一条评审意见第三次出现时,正确处置是什么?