59.4 效能改进方法
一句话
效能改进的顺序是定基线 → 画价值流找约束 → 一次只改一个 → 同口径验证 → 标准化;跳过任何一步,“改进”都会变成把等待搬个地方,或者用加班换一个好看的数字。
六种方法,各管一段
| 方法 | 解决的问题 | 产出 | 典型周期 | 失败模式 |
|---|---|---|---|---|
| 价值流映射(VSM) | 时间到底花在哪 | 阶段表 + 等待时间 + 流动效率 | 3–5 天工作坊 | 画完挂墙,不落到约束 |
| 约束理论(TOC) | 先改哪一个 | 约束 + 挖尽/提升方案 | 1–2 周 | 改非瓶颈,产出不变 |
| PDCA / 改善 kata | 怎么持续改 | 每周一个小实验 | 持续 | 没有标准,改完就回退 |
| 平台工程 | 重复劳动 | 自助平台(脚手架、环境、流水线) | 1–2 季度 | 建了没人用 |
| 团队拓扑(74.1 康威定律及其逆定律) | 组织边界拖慢交付 | 团队边界 + 交互模式 | 1–2 季度 | 只改组织图,不改依赖 |
| SPACE 框架 | 该度量哪些维度 | 满意度/绩效/活动/协作/效率与流动 | 1 季度 | 又变成一套考核指标 |
选型很简单:不知道时间花在哪 → VSM;知道了但不确定先改哪个 → TOC;改完守不住 → PDCA + 标准化;同一件事十个团队重复做 → 平台工程;改流程到顶了 → 团队拓扑。
第一步:画价值流,先承认时间在等
VSM 只做三件事:列出阶段、标出每段的增值时间与等待时间、算出流动效率:
流动效率 = 增值时间 / 总时间
一个典型的需求交付(示例数据,用于演示算法,不是实测):
| 阶段 | 增值时间 | 等待时间 | 累计 |
|---|---|---|---|
| 需求澄清 | 4h | 0 | 4h |
| 等排期 | 0 | 96h | 100h |
| 开发 | 16h | 0 | 116h |
| 等评审 | 0 | 24h | 140h |
| 评审 | 2h | 0 | 142h |
| 等测试环境 | 0 | 12h | 154h |
| 测试 | 8h | 0 | 162h |
| 等发布窗口 | 0 | 48h | 210h |
| 发布 + 观察 | 1h | 0 | 211h |
| 合计 | 31h | 180h | 211h(约 8.8 天) |
流动效率 = 31 / 211 = 14.7%,等待占 85%。这意味着:把开发速度提高一倍,总周期只从 211 小时降到 203 小时(−3.8%);把“等排期”从 96 小时压到 48 小时,总周期直接降 23%。
🔑 改进的第一原则:先砍等待,再提速度。等待是大头,而且砍等待通常不需要写代码。
VSM 的四条操作纪律:
- 范围先窄:第一次只画
commit → deploy,一周内能画完;画全流程容易陷进“需求该谁负责”的争论。 - 时间要粗:分钟级的步骤可以合并,天级的等待必须单列(DORA 的 VSM 指南明确说“低精度就够”)。
- 标注数据来源:哪些是流水线时间戳,哪些是访谈估的,分开标;估的不能拿去当 KPI。
- 只选一个约束:画完会看到很多问题,投票选一个“影响目标且团队能改”的。
第二步:用 TOC 五步锁住约束
| 步骤 | 研发里的动作 | 判据 |
|---|---|---|
| ① 识别约束 | 看哪一列长期堆积、哪个等待最长 | 队列长度与等待时间,不看感觉 |
| ② 挖尽约束 | 不花钱先提瓶颈利用率:评审 SLA、限制同时在评审数、测试分片 | 瓶颈的空闲时间 < 10% |
| ③ 让其它服从 | 非瓶颈不要 100% 满负荷,留 15%–20% 余量吸收波动 | 上游不往瓶颈灌过量 WIP |
| ④ 提升约束 | 加人、买环境、自动化、外包 | 前一步已无可挖 |
| ⑤ 回到第一步 | 约束会移动(评审快了,测试环境变成新瓶颈) | 每月重画一次队列 |
顺序不能反:在没挖尽之前就加人,等于用钱买库存。而“让其它服从”最反直觉——开发满负荷、测试空闲,看起来高效,实际是在制造排队。
第三步:一次只改一个,并且证明它有用
动的是约束:先用 59.2 交付周期与吞吐 的 W = L/λ 确认“改完周期会降、吞吐不会崩”,再设计实验。
改进实验的假设要写成可检验的一句话:
如果 [把评审从串行改为并行 + 限制同时评审 5 个],
则 [变更前置时间 P85] 在 [8 周] 内 [下降 ≥ 20%],
因为 [等待评审的时间占前置时间的 30%]。
判定不能看“改完好像快了”。前置时间是长尾分布,样本少时 20% 的差异可能纯属运气:
#!/usr/bin/env python3
"""experiment.py —— 改完到底有没有用:中位数 + 置换检验 + Bootstrap 区间。
A 组 = 改动前 14 次部署,B 组 = 改动后 14 次部署(前置时间,小时)。
真实效应设为 -20%,看 14 个样本能不能证明它。
"""
import math
import random
from statistics import median
random.seed(59)
def lognormal(med, sigma, n):
return [med * math.exp(random.gauss(0, sigma)) for _ in range(n)]
A = lognormal(46, 0.55, 14) # 改动前:中位 46 小时
B = lognormal(37, 0.55, 14) # 改动后:中位 37 小时(真实效应 -20%)
def diff_med(x, y):
return median(x) - median(y)
obs = diff_med(A, B)
# ① 置换检验:28 个样本随机重分组 20000 次,看"纯运气"能造出多大差异
pool, count = A + B, 0
for _ in range(20000):
random.shuffle(pool)
if abs(diff_med(pool[:14], pool[14:])) >= abs(obs):
count += 1
p = count / 20000
# ② Bootstrap:有放回重采样,得到中位数差的 95% 区间
boot = []
for _ in range(20000):
ra = [random.choice(A) for _ in A]
rb = [random.choice(B) for _ in B]
boot.append(diff_med(ra, rb))
boot.sort()
lo, hi = boot[int(0.025 * len(boot))], boot[int(0.975 * len(boot))]
print(f"A 组(改动前)中位 {median(A):.1f}h,B 组(改动后)中位 {median(B):.1f}h")
print(f"B 组中位数比 A 低 {obs:.1f}h({obs/median(A):.0%});均值低 "
f"{sum(A)/len(A)-sum(B)/len(B):.1f}h({1-sum(B)/len(B)/(sum(A)/len(A)):.0%})")
print(f"置换检验 p = {p:.3f}(20000 次重排);Bootstrap 95% 区间 "
f"[{lo:.1f}, {hi:.1f}] 小时")
print("结论:", "显著" if p < 0.05 and lo > 0 else "不显著——不能排除运气")
print()
# ③ 每组需要多少样本(正态近似,双侧 α=0.05,power=0.8)
print("每组所需样本量(σ/中位数 ≈ 0.55,双侧 α=0.05,power=0.8):")
for eff in (0.30, 0.20, 0.10):
n = math.ceil(16 * (0.55 / eff) ** 2)
print(f" 检测 {eff:.0%} 的改善:n ≈ {n} 次部署/组"
f"(每周 10 次部署 → 约 {n/10:.0f} 周)")
本机实测输出(Python 3.14.8):
A 组(改动前)中位 46.7h,B 组(改动后)中位 34.4h
B 组中位数比 A 低 12.3h(26%);均值低 11.4h(22%)
置换检验 p = 0.169(20000 次重排);Bootstrap 95% 区间 [-6.0, 26.2] 小时
结论: 不显著——不能排除运气
每组所需样本量(σ/中位数 ≈ 0.55,双侧 α=0.05,power=0.8):
检测 30% 的改善:n ≈ 54 次部署/组(每周 10 次部署 → 约 5 周)
检测 20% 的改善:n ≈ 121 次部署/组(每周 10 次部署 → 约 12 周)
检测 10% 的改善:n ≈ 484 次部署/组(每周 10 次部署 → 约 48 周)
这份输出要读出三层意思:
- 真实效应是 −20%,样本只有 14+14,中位数差 26%,p = 0.169——证明不了。区间 [−6.0, 26.2] 跨 0,意思是“改进可能有效,也可能反向”。
- 不是改进没用,是样本不够。要在 10% 的效应上达到 80% 把握,每组需要约 484 次部署;按每周 10 次,要 48 周。所以小改进不该靠结果指标证明,应该先看过程指标(等待时长、评审排队数)——它们样本量大、噪声小。
- 判定规则要提前写死:p < 0.05 且区间不跨 0 才算“验证通过”;否则只能标“方向正确、未证明”,继续观察或换指标。事后改判定标准,等于自欺。
第四步:按“影响 × 置信度 / 成本”排序
改进项永远比资源多,排序公式:
score = 影响(1–5)× 置信度(1–5)/ 成本(人周,最小 1)
| 候选改进 | 影响 | 置信度 | 成本(人周) | 分数 |
|---|---|---|---|---|
| 发布审批分级(低风险自动放行) | 4 | 3 | 1 | 12.0 |
| 评审并行化 + 同时评审上限 | 4 | 4 | 2 | 8.0 |
| 测试环境自助申请 | 5 | 4 | 4 | 5.0 |
| CI 构建提速(缓存 + 分片) | 2 | 5 | 2 | 5.0 |
| 需求就绪定义(DoR)落地 | 3 | 2 | 3 | 2.0 |
两条读法:
- 成本低、置信度中等的项排前面,因为“先拿到一个可验证的胜仗”比“押注一个大改造”更能推动后续改进。
- 影响大但成本高的项(测试环境)不是不做,是排第二波:等第一波验证了方法、建立了信任,再动它。
⚠️ 排序不是一次性的:每完成一项,影响与置信度都要按实测更新;分数不动,说明没有学习。
第五步:落地——采集、看板、验证、回退
指名:自建最小采集(本节与 59.1 DORA 四指标 的脚本)+ 任意图表工具即可起步;需要开箱看板时用 Apache DevLake (opens new window)(开源,内置 DORA 看板);只需要基线自评时用 DORA Quick Check (opens new window)(免费问卷);SaaS 方案有 LinearB、Sleuth。DevLake 与 SaaS 的部署未在本机验证,按官方文档执行。
可抄:把采集挂到 cron,每周一早上跑一次,追加到 CSV:
# crontab -e 里加一行;路径按实际改
17 9 * * 1 cd /srv/dora && python3 dora_collect.py /srv/app deploy.jsonl >> metrics.csv
可验:跑完应当看到一行汇总(本机用样例数据实测):
窗口 2026-09-02 ~ 2026-09-24(3.2 周);提交 120,部署 46(计划内 40,计划外 6,失败 4)
部署频率 12.6/周 | 前置时间 中位 23.5h P85 64.0h | CFR 9% | 恢复 65m | 返工率 13%
可退:脚本只读 git log 与 deploy.jsonl,不改生产;回退 = 删掉 crontab 那一行 + 停用看板,零残留。若用 DevLake,回退 = 停容器,数据留在自己的库。
标准化(最容易被跳过的一步):改进验证通过后,必须落到下面四处之一,否则人一走就回退;进度排进演进路线图(58.4 演进路线图),复盘走 56.6 无指责复盘。
| 载体 | 放什么 | 例子 |
|---|---|---|
| 流水线模板 | 门禁、并行化、缓存配置 | 评审 SLA 检查、CI 分片 |
| 评审清单 | 人工判断的标准 | “PR > 400 行需拆分” |
| ADR | 为什么这么定、什么时候复审 | 发布审批分级规则(58.1 ADR 实践) |
| 债登记 | 没做完的部分、触发条件 | 测试环境自助的二期(58.2 技术债管理) |
边界:什么时候别用这套
- 团队 < 10 人、交付链路短:VSM 与统计检验的成本高于收益,每周看板对话 + 直接改更快。
- 约束在组织外部(合规审批、供应商、商店审核):团队改不动,先做“隔离 + 并行”,别把外部约束算进团队指标。
- 系统还没跑通(0→1 阶段):先保证能交付,再谈流动效率;此时度量会诱导团队挑容易的活。
- 准备裁员或重组:任何度量都会被解读为裁员依据,数据必然失真;此时只做对话,不做度量。
反模式
| 反模式 | 后果 |
|---|---|
| 先买工具/上平台,再找问题 | 平台建成没人用,改进变成采购项目 |
| 一次改五个(CI、评审、环境、审批、组织) | 无法归因,哪个有效说不清,回退时也不知道退哪个 |
| 没有基线就开改 | 改完只能“感觉快了”,无法证明,下次预算拿不到 |
| 用平均值判定改进 | 长尾噪声把 20% 的效应淹掉,或把噪声当成绩 |
| 只改编码段 | 等待占 85%,编码提速一倍总周期只降 4% |
| 把改进目标写进 KPI | 指标被优化,改进变成数字游戏(59.3 度量的陷阱) |
| 改进不标准化 | 靠人记、靠热情维持,换人或忙起来就回退 |
| 照搬别团队的目标值 | 约束不同、起点不同,抄数字只会制造挫败 |
| 平台只建不迁 | 新旧两套并存,重复劳动反而增加 |
关联
- 前置:59.1 DORA 四指标(基线从哪来)、59.2 交付周期与吞吐(WIP 与瓶颈的算术)
- 并列:58.1 ADR 实践(改进规则的落点)、58.4 演进路线图(改进要排进路线图才有资源)、74.1 康威定律及其逆定律(流程改不动时动边界)
- 下游:58.2 技术债管理(没做完的改进进债登记)、56.6 无指责复盘(改进项的复盘机制)、59.3 度量的陷阱(改进指标本身别变成目标)
自检
Q1 VSM 画出来流动效率 15%,等待主要在“等排期”。团队却决定先优化 CI 构建时间(从 20 分钟压到 5 分钟)。这个决定错在哪?
▸ 答案:错在改的不是约束。等排期占了大头,CI 节省的 15 分钟对总周期 211 小时的影响不到 0.1%;而且 CI 只在开发完成后才发生,对“排队等排期”没有任何作用。正确动作是先动排期队列(WIP 上限、需求就绪定义、分批排期),CI 优化排在其后。
Q2 为什么“一次只改一个”不是保守,而是必需?
▸ 答案:因为改进的验证依赖归因。同时改五个,指标变好无法知道是哪个起作用,变差也不知道退哪个;更糟的是,五项里通常只有一项是约束,其余四项可能互相抵消(例如同时降 WIP 又加需求,周期不变)。一次一个还能让团队看到“改动→结果”的因果,建立改进的信心。
Q3 改进后中位数降了 26%,但 p = 0.169。这算失败吗?接下来做什么?
▸ 答案:不算失败,算“未证明”。14+14 个样本对 20% 的效应本来就不够(每组约需 121 次)。接下来三选一:① 延长观察窗口到 8–12 周;② 改用噪声更小的过程指标(等待时长、评审队列长度);③ 扩大样本(更多服务/团队,但要同口径)。不能做的是:直接宣布成功,或者因为 p 值不显著就回退一个方向正确的改动。
Q4 约束在测试环境,团队却加了两个开发。为什么吞吐不会涨?
▸ 答案:TOC 的结论——系统产出等于瓶颈产出。测试环境每天只能验 8 个变更,开发从 6 人加到 8 人只会让“待测试”队列更长、WIP 更高、周期更长(利特尔法则:λ 不变、L 上升 → W 上升)。正确动作是挖尽测试环境(并行环境、测试分片、环境即服务),或提升其产能。
Q5 排序表里“发布审批分级”分数最高(12),但它影响只有 4 分。为什么低成本项容易排前面,什么时候会误导?
▸ 答案:公式里成本在分母,1 人周的项天然占优——这符合“先拿快赢”的策略。误导发生在两种情况下:① 低成本项的置信度虚高(以为改个规则就行,实际审批涉及合规,落地成本被低估);② 快赢项改完约束没动(审批分级只对低风险变更有效,高风险批次仍卡在同一个审批人)。所以分数只用来排序,落地前要用 VSM 复核“它是否真的动了约束”。
Q6 改进上线三个月后回退了,最可能的原因是什么?
▸ 答案:没有标准化。改进靠“某个人盯着”“大家这段时间比较自觉”,一旦换人、赶版本、组织调整,行为就回到旧路径。检查四处:流水线模板、评审清单、ADR、债登记——改进如果只存在于会议纪要里,就等于没做。回退不是执行问题,是设计问题。
Q7 什么时候该动组织结构,而不是继续改流程?
▸ 答案:当 VSM 显示大量等待来自跨团队交接(同一需求要在 3 个团队间流转、每次交接等 3–5 天),且流程优化已经把单团队内部压到极限时。此时瓶颈是边界,不是步骤;动作是按业务能力重划团队边界、减少交接(见 74.1 康威定律及其逆定律),或者用平台/契约把交接变成自助。
Q8 要不要买商业 DORA 平台?判据是什么?
▸ 答案:先看三个条件:① 应用数量 ≥ 10 且部署系统不统一,手工采集成本高;② 已经有明确的改进议程(知道拿数据做什么);③ 能接受数据落到第三方或愿意自托管。三条不满足时,先用本节脚本 + 表格跑 4–8 周,验证“数据会被用来做决策”再采购。反过来的顺序(先买平台再找问题)是本节第一条反模式。