工程复盘模板:从事实、判断到改进行动

0阅读10分钟

复盘要基于事实

上个迭代结束后,团队开了一次常规复盘。半小时过去,发言集中在「这次需求变太多了」「测试时间不够」「跨组协调太慢」。我翻了下记录,全是感受,没有一条带数据。

这不是复盘,是吐槽大会。

工程复盘最容易掉进的坑,就是大家凭印象讨论、凭情绪下结论。谁声音大谁主导,最后产出五六条「加强沟通」「提高质量」之类的空话,写进文档再没人看。

Google SRE 书里有一句话我印象很深:「Postmortems are letters you write to future team members.」复盘文档是写给未来团队成员看的,不是写给今天参会的人看的。这意味着它必须自包含、有数据、可追溯,而不是几个模糊的形容词。

这篇文章把复盘拆成一个可操作的模板。从收集事实开始,经过根因分析,最后落到可跟踪的改进行动。每个环节我都会给出具体做法和容易踩的坑。

理论框架:复盘不是总结,是结构化的事后分析

Postmortem 和 Retrospective 的区别

很多团队把事故复盘(Postmortem)和迭代回顾(Retrospective)混为一谈。两者目标不同,颗粒度也不同。

维度Postmortem(事故复盘)Retrospective(迭代回顾)
触发条件具体事故或线上故障固定节奏(每迭代/每月)
关注范围单一事件的根因和影响一段时间内的整体改进
参与角色直接相关人 + SRE全团队
输出物RCA 报告 + 修复 Action改进行动列表
时间压力事故发生后 48-72 小时内按迭代节奏

这篇文章的模板偏 Postmortem,但框架同样适用于 Retrospective——只是后者通常不需要深入到日志级的事实梳理。

5 Whys 不是万能药

5 Whys 是丰田生产系统里发展出来的根因分析方法。美团技术团队在实践中总结了一套流程:先用七何模型(What / Who / Where / When / How / Why / How much)记录事件全貌,再连续追问为什么,串联因果链条,直到找到制度层面的根因。

但 5 Whys 有一个常见误用:只沿着一条因果链往下追,忽略了并行原因。实际工程中,一个问题往往是多个因素叠加的结果。这时候需要结合鱼骨图的思路,从人、流程、工具、环境四个维度分别追问。

无责文化是前提

Atlassian 的 Postmortem 指南强调一点:blameless 不等于 no accountability。不追责的意思是,讨论焦点放在「系统为什么允许这个错误发生」,而不是「谁犯了这个错」。

这不是政治正确。Google SRE 的实践证明,一旦复盘变成追责大会,工程师就会隐藏信息,复盘质量直接归零。你得到的不是真相,而是一个经过自我保护过滤后的版本。

PagerDuty 也指出:「A successful postmortem process is based on a culture of honesty, learning, and accountability. Culture change requires management buy-in.」管理层的支持是复盘文化落地的必要条件。

模板结构:八个模块逐一展开

一份完整的复盘文档,我通常按以下结构组织:

模块一:事实收集

在讨论任何原因之前,先把事实铺开。事实包括:

  • 时间线:从第一个异常信号到问题完全恢复,按时间排序。精确到分钟。
  • 影响范围:多少用户受影响?哪些功能不可用?持续多久?
  • 检测方式:是告警发现的,还是用户反馈的?
  • 关键数据:错误率、延迟、QPS、错误日志片段。

这一步的关键是:只记录,不解释。任何带有判断的描述(「因为 XX 没做好」)都要删掉。

# 好做法:纯事实描述
timeline:
  - time: "2026-06-20T14:32:00+08:00"
    event: "监控告警:订单服务 P99 延迟超过 3s"
  - time: "2026-06-20T14:35:00+08:00"
    event: "值班人员开始排查,发现数据库连接池耗尽"
  - time: "2026-06-20T14:52:00+08:00"
    event: "扩容连接池后恢复,持续 20 分钟"
 
# 坏做法:混入主观判断
timeline:
  - time: "2026-06-20T14:32:00+08:00"
    event: "由于数据库配置不当,导致系统变慢"
  # ❌ "配置不当"是结论,不是事实。事实阶段不应出现归因

模块二:做得好的地方

复盘不只找问题。识别有效做法同样重要——否则你会在修复问题的同时,不小心改掉那些有用的实践。

# 好做法:具体描述有效实践
## 做得好的地方
1. 告警在 3 分钟内触达值班人员,MTTD(平均检测时间)符合 SLA
2. 值班人员按 Runbook 执行了连接池扩容操作,未做临时 patch
3. 恢复后立即建立了事后分析文档,没有拖过 48 小时
 
# 坏做法:笼统表扬
## 做得好的地方
1. 大家反应很快
2. 团队协作不错
# ❌ 没有具体行为,下次无法复现

模块三:问题与根因分析

这一步是复盘的核心。把每个问题单独拿出来,用 5 Whys 追到系统层面的根因。

# 问题:数据库连接池耗尽
 
## 5 Whys 分析
1. **为什么连接池耗尽?**
   → 慢查询占用了大量连接,释放速度跟不上请求速度
2. **为什么有慢查询?**
   → 新上线的报表查询缺少索引,全表扫描
3. **为什么缺少索引的查询能上线?**
   → SQL Review 流程跳过了这个查询,因为它是通过 ORM 动态生成的
4. **为什么 ORM 生成的查询不经过 SQL Review?**
   → Review 流程只覆盖手写 SQL,未覆盖 ORM 查询
5. **为什么流程存在这个盲区?**
   → 半年前引入新 ORM 框架时,没有同步更新 Review 规则
 
## 根因
SQL Review 流程未覆盖 ORM 动态生成的查询,导致缺少索引的慢查询进入生产环境。

根因分析要回答三个问题:问题为什么发生?为什么没有被提前拦截?为什么没有系统性防范?

# 好做法:三维度追问
1. 因何爆发?—— 直接技术原因
2. 因何未拦截?—— 检测/预防机制的缺口
3. 因何无系统性防范?—— 制度/流程/工具层面的缺失
 
# 坏做法:停在技术修复
1. 因何爆发?—— 慢查询
2. 解决方案:加索引
# ❌ 加了索引还会有下一个慢查询。问题在于流程缺口,不在单条 SQL

模块四:指标变化

用数据说话。对比事故发生前后的关键指标。

指标事故前事故期间事故后数据来源
P99 延迟200ms4500ms180msAPM
错误率0.1%12.3%0.08%日志聚合
订单成功率99.5%67.2%99.6%业务监控
数据库连接使用率35%100%42%数据库监控

没有指标的复盘,说服力减半。如果团队还没有建设基础监控,这件事本身就应该成为一条 Action。

模块五:复盘流程图

把复盘过程标准化,可以减少遗漏。下面是我实际使用的复盘流程:

流程图画布 · 115%
Mermaid 流程图加载中...

关键节点:每个 Action 必须满足三个条件——有明确的 Owner、有 Deadline、能在任务系统中被追踪。否则这条 Action 就不会被执行。

模块六:改进行动

这是复盘最容易烂尾的地方。十几条 Action 列出来,三个月后回头看,一条都没做。

经验是:每次复盘最多定 3 条 Action。选影响最大、投入最合理的那几条。做完再回来加。

# 好做法:具体、可追踪
actions:
  - id: ACTION-001
    description: "在 SQL Review 规则中增加 ORM 动态查询的扫描配置"
    owner: "@zhangsan"
    priority: P0
    deadline: "2026-07-05"
    tracker: PROJ-1234
    verification: "CI 中 ORM 生成的 SQL 能触发慢查询检测"
    status: in_progress
 
  - id: ACTION-002
    description: "为报表查询添加复合索引 (tenant_id, created_at)"
    owner: "@lisi"
    priority: P0
    deadline: "2026-06-28"
    tracker: PROJ-1235
    verification: "报表查询 P95 < 500ms"
    status: done
 
# 坏做法:模糊、无人跟
actions:
  - "优化数据库性能"
  - "加强代码审查"
  - "完善监控告警"
# ❌ 没有 Owner、没有 Deadline、没有验收标准,永远不会被执行

模块七:行动优先级排序

不是所有改进都同等重要。用「影响 × 投入」矩阵来排序:

象限影响大 + 投入小影响大 + 投入大影响小 + 投入小影响小 + 投入大
策略立即执行排入下个迭代顺手做了暂不处理,记录在案
举例补 SQL Review 规则引入查询分析引擎加一条告警规则重构 ORM 层

模块八:闭环检查

复盘文档写完后,设一个 30 天后的检查点。检查内容包括:

  • Action 是否全部完成?
  • 未完成的 Action 原因是什么?是优先级变了,还是被阻塞了?
  • 已完成的 Action 是否有效?指标是否有改善?
  • 是否需要新增 Action?
# 30 天后检查模板
review_at: "2026-07-25"
actions_status:
  - id: ACTION-001
    status: done
    effect: "SQL Review 已覆盖 ORM 查询,拦截了 3 条潜在慢查询"
  - id: ACTION-002
    status: done
    effect: "报表查询 P95 从 2.1s 降到 320ms"
  - id: ACTION-003
    status: blocked
    reason: "依赖基础设施团队提供查询分析引擎,已排入 Q3"

实战案例

案例一:接口字段变更导致客户端崩溃

这是美团技术团队分享过的一个真实场景,我做了适当改编。

场景:iOS 客户端在发版后大面积崩溃,crash 日志指向一个 JSON 解析异常。

问题排查过程

步骤做了什么发现了什么
1查看 crash 堆栈NSNull 被当作 String 解析
2对比 API 响应变化后端新增了 3 个可选字段,部分用户返回 null
3检查 API 变更流程后端只通知了 Android 团队,iOS 团队未收到
4追问为什么 iOS 没收到没有强制的跨端 API 变更通知机制
5追问为什么客户端能崩iOS 端没有对可选字段做 nil 兜底

根因

  1. API 变更没有强制跨端同步流程
  2. 客户端代码对可选字段缺少防御性处理
  3. 团队在质量上存在盲目自信,没有代码审查制度

修复方案

// 坏做法:直接强转,不处理 null
let username = response["username"] as! String
// ❌ 如果 username 为 null 或类型不对,直接 crash
 
// 好做法:防御性解析
struct UserResponse: Codable {
    let username: String?
    let email: String?
    let nickname: String?
 
    enum CodingKeys: String, CodingKey {
        case username, email, nickname
    }
 
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // 所有可选字段都提供默认值
        self.username = try container.decodeIfPresent(String.self, forKey: .username) ?? ""
        self.email = try container.decodeIfPresent(String.self, forKey: .email) ?? ""
        self.nickname = try container.decodeIfPresent(String.self, forKey: .nickname) ?? "用户"
    }
}
// ✅ 即使后端返回 null,客户端也不会崩溃

制度层面的改进

actions:
  - "建立 API 变更的跨端通知机制:后端修改接口必须在跨端周会同步"
  - "客户端所有 API 响应字段必须使用 Codable + decodeIfPresent"
  - "新增 API 变更 Checklist,包含:向前兼容 / 可选字段 / 跨端通知"

案例二:数据库连接池耗尽

场景:某次发版后,订单服务 P99 延迟从 200ms 飙升到 4500ms,持续约 20 分钟。

时间线

14:30  新版本上线
14:32  监控告警:订单服务 P99 > 3s
14:35  值班人员开始排查
14:38  发现数据库连接池使用率 100%
14:42  定位到一条全表扫描的慢查询
14:48  临时方案:扩容连接池 + 限流报表服务
14:52  P99 恢复到正常水平

5 Whys 分析

1. 为什么 P99 飙升?
   → 数据库连接池被耗尽

2. 为什么连接池耗尽?
   → 新上线的报表查询没有索引,每次执行 3-5 秒,占满连接

3. 为什么没有索引的查询能上线?
   → 这条 SQL 是 ORM 动态生成的,绕过了 SQL Review

4. 为什么 ORM 生成的 SQL 不需要 Review?
   → Review 规则只覆盖了手写 SQL 文件

5. 为什么规则有这个盲区?
   → 半年前引入新 ORM 框架时,没有同步更新 Review 流程

修复方案对比

-- 坏做法:只加索引,不改流程
CREATE INDEX idx_report_tenant_created
ON orders (tenant_id, created_at);
-- ❌ 解决了当前慢查询,但下一条 ORM 生成的慢查询还会出问题
 
-- 好做法:加索引 + 在 CI 中检测 ORM 慢查询
CREATE INDEX idx_report_tenant_created
ON orders (tenant_id, created_at);
 
-- 同时在 CI 管道中增加 ORM SQL 分析步骤
-- ci/sql-review.yml
sql_review:
  sources:
    - type: manual    # 手写 SQL
      path: "db/migrations/"
    - type: orm       # ORM 生成的 SQL
      config: "config/orm-review.yml"
      rules:
        - max_execution_time: 500ms
        - require_index: true
        - reject_full_table_scan: true

案例三:复盘会议跑偏

场景:一次迭代回顾,30 分钟的会议,20 分钟在讨论一个需求评审的细节。最后 10 分钟草草列了 8 条 Action,没人认领。

问题分析

问题原因修复
讨论跑偏没有 Time Keeper,没有议程会前发议程,每个议题限时
Action 太多试图一次解决所有问题最多 3 条,选投入产出比最高的
没人认领没有提前分配会前初步指定 Owner,会上确认
没有跟进没有录入跟踪系统会后当天录入 Jira/Linear

复盘会议的标准流程

meeting_agenda:
  - item: "回顾上次 Action 完成情况"
    time: "5min"
    owner: "Scrum Master"
  - item: "快速过数据:本迭代交付量、Bug 数、关键指标"
    time: "5min"
    owner: "Tech Lead"
  - item: "做得好的(每人 1-2 条)"
    time: "5min"
    owner: "全员"
  - item: "待改进的(每人 1-2 条)"
    time: "5min"
    owner: "全员"
  - item: "选出 Top 3 改进项,指定 Owner 和 Deadline"
    time: "10min"
    owner: "Tech Lead 主持"

常见反模式与修正

复盘这件事,做多了会发现反模式就那几种。整理成表,方便对照:

反模式表现后果修正方法
情绪发泄会「XX 部门太不靠谱了」团队对立,没有产出回到事实,要求给出数据和具体时间线
泛泛总结「要加强沟通」「要提高质量」写了等于没写每条 Action 必须可验证,有 Owner
追责大会「这个问题是 XXX 造成的」没人敢说真话主持人明确开场:对事不对人
Action 堆积一次列出 15 条改进一条都做不完最多 3 条,选影响最大的
复盘拖延事故两周后才开细节模糊,变成猜测48-72 小时内完成,趁记忆新鲜
只有问题没有亮点全程在批评团队士气下降强制先说做得好的,再说待改进的
复盘无闭环上次 Action 从不检查同样的问题反复出现每次复盘先回顾上次 Action

复盘检查清单

按阶段分组,每次复盘可以对照勾选:

会前准备

  • 事故发生后 48-72 小时内启动复盘
  • 收集完整的时间线,精确到分钟
  • 整理关键指标数据(错误率、延迟、影响用户数)
  • 准备会议议程,每个议题分配时间
  • 邀请直接相关人,避免无关人员

会中讨论

  • 主持人开场声明:对事不对人,无责复盘
  • 先过事实和数据,再讨论原因
  • 先说做得好的,再说待改进的
  • 每个问题做 5 Whys 分析,追到系统层面
  • 根因覆盖三个维度:技术原因 + 检测缺口 + 制度缺失
  • 改进 Action 不超过 3 条

Action 落地

  • 每条 Action 有明确的 Owner(一个人,不是团队)
  • 每条 Action 有 Deadline
  • 每条 Action 录入任务跟踪系统(Jira / Linear / 飞书)
  • 每条 Action 有可验证的完成标准

闭环检查

  • 30 天后检查 Action 完成情况
  • 已完成的 Action 评估效果(指标是否有改善)
  • 未完成的 Action 说明原因并决定继续还是放弃
  • 复盘文档归档,团队可见

参考资料

评论 0

0 / 1000