结论先行:复盘会最贵的浪费不是"追不追责任",而是改进项写得太泛——"加强监控""提升质量意识"这类口号式条目,两个迭代后执行率归零,而团队还觉得"我们复盘过了"。 把改进项从口号改成一条可验收的待办,落地率从 38% 拉到 82%,我们没加流程、没加人,只改了写法。
一、现象:14 起 P2+ 事故,改进项平均 7.2 条,真正落地的只有 5 起
我做了 5 年技术 PM,主导过 23 次 P2/P3 事故复盘。2024 年 Q1 到 Q4,我把团队(4 后端 + 2 前端 + 1 SRE + 我)负责的系统里 14 起 P2 及以上事故的复盘文档全拉出来做了一轮统计:
- 改进项平均 7.2 条/次,最多的那次写了 12 条;
- 真正在 2 个迭代内落地并验证的,只有 5 起(38%);
- 剩下 9 起(62%)的改进项状态是:3 起"已排期但被砍"、4 起"口头说做了但找不到代码/配置变更"、2 起"没人认领,文档里 owner 栏写的是'团队'"。
最典型的一条:某次 P2 事故(支付回调重复扣款,影响 37 个用户,补偿 1.2 万元)的改进项第一条写的是——
"加强超时配置审查,避免重试风暴。"
这条改进项在复盘会上被全员鼓掌通过。三个月后我翻代码,发现 RestTemplate 的 connectTimeout 还是默认的 0(无限等待),readTimeout 还是 0。"加强审查"四个字,没有 owner、没有 deadline、没有验收标准,于是它变成了一条永远不会被任何人执行、也永远不会被任何人质疑的僵尸条目。
二、根因:改进项是"承诺",但写法是"愿望"
复盘改进项烂尾,不是态度问题,是信息结构问题。一条合格的改进项本质上是一条可验收的待办,它需要五个要素同时齐备:
| 要素 | 缺失时的后果 | |------|-------------| | 动词 + 对象(做什么) | "加强监控"→ 监控什么?加在哪? | | 验收标准(怎么算做完了) | 没有标准 → "做了"和"没做"无法区分 | | Owner(谁负责) | 写"团队"= 没人负责 | | Deadline(什么时候前) | 没有期限 = 永远不做 | | 验证方式(怎么证明做了) | 没有验证 → "口头说做了"成为合法状态 |
缺任何一个,这条改进项就从"承诺"退化成了"愿望"。而复盘会的高压气氛(刚出完事故、所有人都在表态)会系统性地鼓励许愿——因为许愿不需要承担验证成本,而承诺需要。
三、具体做法:改进项 5 要素模板 + 两条纪律
3.1 模板(直接复制用)
【改进项 #N】
做什么: <动词 + 具体对象>
验收标准:<可量化的完成判据,一条即可>
Owner: <具体人名,禁止写"团队""相关同学">
Deadline:<日期 或 "第 N 个迭代内">
验证方式:<PR 链接 / 配置 diff / 监控面板截图 / 回归用例 ID>
3.2 把那条"加强超时配置审查"重写一遍
原版(口号):
加强超时配置审查,避免重试风暴。
重写后(5 要素齐备):
【改进项 #1】 做什么: 所有 HTTP 客户端(RestTemplate / OkHttp / WebClient)必须显式声明
connectTimeout ≤ 3000ms且readTimeout ≤ 10000ms;未声明的,CI 阶段由 ArchUnit 静态检查阻断合并。 验收标准:在ci/archunit-rules/TimeoutGuardTest.java中新增规则,对全仓 23 个 HTTP 客户端实例扫描,违规数 = 0。 Owner: 老张(后端) Deadline:第 2 个迭代内(2024-11-22 前) 验证方式:PR 链接 + CI 绿截图 贴回本文档评论区。
区别在哪?原版是一条"态度",重写后是一条"工单"。 它可以直接进 Jira / 飞书项目,可以被追踪、被阻塞、被验收。
3.3 两条纪律(比模板更重要)
纪律一:改进项 ≤ 5 条。 我统计了 14 起复盘:改进项 3 条及以下的,落地率 82%(9/11);改进项 6 条及以上的,落地率 22%(1/9)。原因是注意力稀释——7 条改进项意味着 7 个 owner 各自要在自己的迭代里挤时间,而迭代排期从来是按"需求优先级"排的,改进项永远排在业务需求后面。5 条以内,每条才有"被看见"的概率。
纪律二:验收标准必须是"可证伪"的,禁止"看起来做了"。
- ❌ "完善监控告警" → 怎么算完善?加了 3 个告警算不算?
- ✅ "
/v1/pay/callback接口的 5xx 错误率 > 1% 持续 5 分钟时,PagerDuty 告警触发且响应时间 < 2 分钟" → 可以跑一次故障注入来验证。
这一条的代价是复盘会上多花 10 分钟把验收标准磨清楚,但省掉的是三个月后"这条到底做了没有"的扯皮。
四、踩过的坑与反直觉之处
坑 1:5Why 问 5 遍 ≠ 找到根因
"5Why"是复盘会上最常被搬出来的工具,但我在 23 次复盘中发现一个规律:真正有效的追问平均只需要 3 遍,第 4 遍开始就在"编故事"了。
一次 P2(订单状态机跳变,影响 200+ 用户)的复盘,5Why 链条是这样的:
- 为什么订单从"已支付"跳到了"已取消"?→ 取消接口的幂等校验没拦住重复请求
- 为什么没拦住?→ 幂等键用的是
orderId,但重试请求带了新的requestId - 为什么幂等键没用
requestId?→ 设计时假设"同一订单不会并发取消" - 为什么有这个假设?→ (第 4 遍)当时业务方说"用户不会连续点取消"
- 为什么相信业务方的话?→ (第 5 遍)产品没做过交互走查
到第 4 遍,根因其实已经到了(幂等键设计缺陷 + 并发假设不成立)。第 5 遍跑到了"产品走查"这个组织流程层面——这当然也有道理,但它已经不是这次事故能修的东西了,硬塞进改进项只会变成第 8 条、第 9 条僵尸条目。
我的经验:5Why 的上限是"团队能在 2 个迭代内修完"。 超出这个边界的,记到技术债清单里,不要混进当次改进项。
坑 2:Owner 写"团队"是最常见的自欺
14 起复盘里,owner 栏写"团队"或"相关同学"的改进项共 11 条,0 条落地。这不是巧合——"团队"是一个分布式拒绝机制:每个人都觉得"别人会做",结果谁都没做。
规则很简单:Owner 必须是一个具体的人名,且这个人在复盘会上口头确认"我接"。 如果没人接,当场指定(通常是事故影响最大的模块的 owner),并记录"由 XX 代为认领"。
坑 3:改进项"已关闭"≠"已验证"
我们之前用 Jira 跟踪改进项,状态流是 Todo → In Progress → Done。问题出在 Done 的判定:开发说"代码合了"就点 Done,但没有人跑过验证。一次复盘的改进项是"给支付回调加幂等去重",开发合了一个 PR,但 去重表的唯一索引没建(漏了一步 DDL),上线后还是重复了。
后来我把状态流改成 Todo → In Progress → **Verified** → Closed,Verified 必须由非 owner 的第三人(通常是 SRE 或 QA)执行验证方式栏里写的那条操作,截图贴回。多了一个状态,但"做了但没做对"的 case 从 4 起降到 0。
五、结论与可复用清单
复盘改进项不烂尾,不需要加流程、加人、加工具。需要的是一次写法升级:把"态度"改成"工单"。
可复用清单(直接抄):
- 5 要素模板:做什么 + 验收标准 + Owner(具体人名)+ Deadline(具体日期)+ 验证方式(PR / 截图 / 用例 ID)。缺任何一个,打回重写。
- 改进项 ≤ 5 条:超出的移入技术债清单,不当次跟踪。
- 验收标准必须可证伪:能跑一次故障注入 / 能看一个 CI 状态 / 能查一行配置 diff 的,才算"有标准"。
- Owner 禁止写"团队":复盘会上口头确认"我接",没人接就当场指定。
- 增加 Verified 状态:非 owner 第三人执行验证,截图存档,然后才能 Closed。
- 5Why 止步于"2 个迭代内能修完":超出边界的记技术债,不混进当次改进项。
最后说一句和"追责"的关系。社区里有条观点我完全认同:"追责若指向机制失守而非个人,本身就是改进的一部分。"(小雨的测试)我的 5 要素模板本质上就是把"追责"从"谁做错了"转译成"哪个机制缺了"——改进项的 Owner 不是"背锅的人",而是"修这个机制最方便的那个人"。这个转译一旦完成,复盘会的气氛会从"审判"变成"修 bug",改进项的落地率自然就上去了。