效能看板上线三个月后,通常会出现三种变化:PR 拆得更碎、提交更频繁、评论数上升。数字变好看了,交付没变快。这不是团队道德问题,而是指标设计的必然结果——任何被观察的量都会被优化,优化方向由指标定义决定,而不是由目标决定。
度量本身没有错。错的是把"代理指标"当成"目标本身",以及把度量结果交给一个会改变行为的机制(比如绩效)。这篇给的是判据:度量什么、怎么组合、数据从哪来、结果怎么用、什么时候该停手。
1. 古德哈特定律在研发场景的具体形态
| 指标 | 被优化后的行为 | 真实代价 |
|---|---|---|
| 代码行数 | 拆行、少用库、复制粘贴 | 可读性下降,维护成本上升 |
| 提交次数 | 无意义小提交、频繁 rebase | 历史不可读,回滚粒度失真 |
| PR 数量 | 把一次改动拆成五个 PR | 评审碎片化,集成风险后移 |
| 缺陷数(越低越好) | 不登记缺陷、改称"需求" | 缺陷转入暗账,逃逸率上升 |
| 工时填报 | 填满、对齐期望值 | 数据失真,且消耗真实工时 |
共同结构:指标定义得越窄,绕过它的成本越低。代码行数只看新增,绕过方式就是复制;缺陷数只看登记数,绕过方式就是不登记。设计指标时要问的第一句不是"这个数好不好看",而是"如果我想让这个数变好又不想真的改进,代价是多少"。绕过成本低的指标不能单独使用。
2. 四个层次与各自的代理指标
| 层次 | 想回答的问题 | 代理指标 | 失真点 |
|---|---|---|---|
| 交付吞吐 | 单位时间能交付多少 | 部署频率、需求周期时间 | 拆小需求刷频率 |
| 交付稳定性 | 交付后是否可靠 | 变更失败率、恢复时长 | 少报事故、延长判定窗口 |
| 响应能力 | 从想法到上线多快 | 前置时间、评审等待时长 | 跳过评审、缩范围 |
| 工程质量 | 长期是否可持续 | 返工率、逃逸缺陷、on-call 负载 | 把返工记为"新需求" |
四层必须同时存在。只测吞吐,团队会牺牲质量换速度;只测质量,速度会被无谓拖慢。单层度量一定诱导局部最优。
3. DORA 四项的口径细节
四项指标(部署频率、变更前置时间、变更失败率、恢复时长)的价值全在口径。口径不清,四个数字可以同时"变好"而系统没变。
| 指标 | 起点 | 终点 | 计数单位 | 常见篡改 |
|---|---|---|---|---|
| 部署频率 | — | 生产部署事件 | 每服务、按天/周计 | 把配置改动、灰度重启算作部署 |
| 变更前置时间 | 首次提交 | 该变更上线 | 按变更(commit 集合) | 起点改成"提 PR",排除本地开发 |
| 变更失败率 | 上线 | 判定失败 | 失败部署 / 总部署 | 提高失败判定门槛、延长观察窗 |
| 恢复时长 | 故障开始 | 服务恢复 | 按事件 | 起点改成"被发现" |
# 口径必须写成配置,而不是写在文档里靠人记
metrics:
deploy:
source: ci_pipeline_success # 只认全流程成功的流水线
env: production
exclude: [config_only, restart] # 排除,避免刷频率
lead_time:
start: first_commit_on_branch
end: deployed_to_production
change_failure:
window_hours: 24 # 观察窗固定,不允许临时缩短
signals: [rollback, hotfix, slo_breach]
口径写进配置的价值是可审计:任何人改口径都留在版本历史里,而不是悄悄改了看板。
4. 个体指标与团队指标
| 维度 | 团队指标 | 个体指标 |
|---|---|---|
| 博弈空间 | 有限(需协同) | 极大(可单独优化) |
| 典型后果 | 改流程 | 改行为、藏信息 |
| 适用场景 | 改进对话、容量规划 | 几乎无:连"代码评审数"都会导致走过场 |
| 例外 | — | 极短期的辅导反馈,且不公开、不归档 |
结论很硬:个体指标一旦进入考核或公开排名,数据必然失真。原因不是人品,而是个体指标几乎总能被单方面优化——把 PR 拆小、把评论拆多条、把任务拆分,都不需要别人配合。
5. 组合使用:至少两两搭配
单个指标必然被优化,所以指标要成对出现,且配对的两项优化方向相反。
| 主指标 | 配平指标 | 组合含义 |
|---|---|---|
| 部署频率 | 变更失败率 | 快而不炸 |
| 前置时间 | 返工率 | 快且一次做对 |
| 吞吐(需求数) | 逃逸缺陷率 | 多而不漏 |
| 评审速度 | 评审意见采纳率 | 快而不走过场 |
| 覆盖率 | 变异杀伤率 / 逃逸缺陷 | 测得多且测得准 |
配对原则:一项衡量速度,一项衡量代价。两项同时改善才是真改善;一项改善另一项恶化,说明资源只是被搬了个位置。
6. 数据来源:自动采集 vs 人工填报
| 来源 | 可靠性 | 成本 | 适用 |
|---|---|---|---|
| 工具链自动采集(Git、CI、部署系统、监控) | 高,但受口径影响 | 一次性接入 + 维护 | 吞吐、稳定性、前置时间 |
| 人工填报(工时、故事点、满意度) | 低,易对齐期望 | 持续消耗工时 | 只用于定性参考 |
# 自动采集的最小骨架:从流水线与部署记录拉事件,而不是问人
curl -s "$CI_API/pipelines?status=success&ref=main" \
| jq -r '.[] | [.id, .created_at, .updated_at] | @tsv' > deploy.tsv
人工填报的数据一旦进入考核,就变成"填报质量"的度量而非"工作实际"的度量。采集本身也要验证:
-- 覆盖率与缺失:先证明数据可信,再解释结论
SELECT date, COUNT(*) AS deploys,
SUM(CASE WHEN pipeline_id IS NULL THEN 1 ELSE 0 END) AS unknown_source,
SUM(CASE WHEN duration_min IS NULL THEN 1 ELSE 0 END) AS missing_duration
FROM deploy_events GROUP BY date ORDER BY date DESC LIMIT 14;
能自动采集的绝不手工填,这条纪律比指标选型更重要。
7. 结果怎么用:改进对话 vs 绩效考核
| 用途 | 行为反应 | 长期结果 |
|---|---|---|
| 团队复盘、找瓶颈 | 暴露问题、讨论流程 | 指标逐步逼近真实 |
| 跨团队排名 | 藏问题、抢定义 | 数据失真,互害 |
| 个人绩效 | 博弈、拆指标 | 度量体系报废 |
一个可操作的判据:如果某个指标的结果会让某个人的收入变化,这个指标就不再是度量工具,而是激励工具。激励工具需要另一套设计(简单、可验证、难绕过),不能和诊断工具混用。
8. 基线与趋势:跨团队横比几乎总是错的
| 比较方式 | 可用性 | 原因 |
|---|---|---|
| 自身同比 / 环比 | 高 | 上下文一致,变化可归因 |
| 同团队不同季度 | 高 | 同上 |
| 跨团队横比 | 低 | 业务复杂度、遗留系统、依赖数量不同 |
| 跨公司基准 | 极低 | 口径与业务形态不可比 |
-- 趋势看分位数与移动窗口,而不是月度平均
SELECT week, percentile_cont(0.5) WITHIN GROUP (ORDER BY lead_hours) AS p50,
percentile_cont(0.9) WITHIN GROUP (ORDER BY lead_hours) AS p90
FROM deploy_events GROUP BY week ORDER BY week;
均值会把长尾吃掉。一个团队 90% 的变更一天上线、10% 卡两周,均值看起来"三天",实际体验是"经常卡住"。看 P50 与 P90 的差,比看均值有用。
9. 反面指标:衡量代价而非产出
| 反面指标 | 定义 | 为什么重要 |
|---|---|---|
| 返工率 | 上线后 30 天内被修改的需求占比 | 直接反映"一次做对"的能力 |
| 逃逸缺陷率 | 生产发现的缺陷 / 全部缺陷 | 反映质量门禁是否有效 |
| on-call 负担 | 每班次有效告警数、夜间唤醒次数 | 反映系统可运维性 |
| 变更回滚率 | 回滚次数 / 部署次数 | 与部署频率配对 |
| 等待时长 | 评审、环境、依赖审批的排队时间 | 常是前置时间的主要成分 |
反面指标的妙处在于难以美化:要让返工率下降,只能真的少返工;要让 on-call 负担下降,只能真的少故障。
10. 引入节奏:先观察三个月
第 1 月:只采集,不公开,不解释 → 校准口径,找数据缺口
第 2 月:团队内可见,只讨论异常 → 建立"指标用于诊断"的共识
第 3 月:进入复盘议程,关联具体事件 → 开始产生改进项
之后:每季度复核指标是否仍有效
顺序反过来(先公开排名、后补口径)几乎必然失败:团队会先学会应付,再也没人相信数据。
11. 排错:五种"数字好看但没用"
| 现象 | 原因 | 处理 |
|---|---|---|
| 部署频率翻倍但用户无感 | 把配置改动、重启算作部署 | 收紧事件定义,排除非代码变更 |
| 前置时间变短但上线更慢 | 起点从"首次提交"改成"提 PR" | 口径写进配置并留版本历史 |
| 失败率异常低 | 判定门槛提高或观察窗缩短 | 固定 24 小时窗口与三类信号 |
| 覆盖率上升但线上缺陷没少 | 只测容易测的分支 | 配平逃逸缺陷率与变异杀伤率 |
| 各团队指标都很好、整体交付没变 | 单指标各自优化 | 换成成对指标,看组合而非单项 |
12. 边界:什么时候该停手
| 场景 | 判断 | 理由 |
|---|---|---|
| 团队小于十人 | 不必建体系 | 沟通成本低于度量成本 |
| 指标被用于考核 | 必然失真 | 激励与诊断不能混用 |
| 度量成本高于收益 | 停手 | 采集与解释工时超过改进收益 |
| 业务处于探索期 | 只测稳定性 | 吞吐指标会误导方向 |
| 数据源不稳定 | 先修工具链 | 假数据比没数据更糟 |
| 已能凭事件定位问题 | 减指标 | 指标多会稀释注意力 |
最后一条常被低估:指标数量与有效性成反比。一个团队同时看二十个指标时,没人会因为任何一个数字变化而行动。
13. 自测
- 判断一个指标能不能单独使用,先问哪个问题?
- 部署频率被"刷"的两种典型方式和对应的排除规则是什么?
- 为什么个体指标几乎必然导致博弈,即使团队初衷是好的?
- 配对指标的原则是什么?举一组速度与代价的搭配。
- 跨团队横比为什么几乎总是错的?该用什么替代?
- 指标被用于绩效考核后,最先失真的通常是什么?