流水线通常四段:格式、审查、测试、门控。 串起来之后最重要的设计不是顺序,是「前面倒了,后面还跑不跑」。 实测四段全跑六十六秒;第一段倒只用两秒,第三段倒已经花掉六十五秒。 顺序该按「发现问题的成本」排。
上一节只做一件事:审查。这一节把审查放进一条完整的流水线。 这一节真跑了两种失败位置,看短路的收益差多少。
一、四个阶段
格式:跑格式化和 lint。两秒,最便宜,改得动就直接改。 审查:让模型看这次改动。十八秒,只报会出问题的地方。 测试:跑受影响的测试。四十五秒,最贵,不过就不许合。
门控:汇总前三个的结论,决定通过与否。一秒,只读不判。 四段的耗时差二十多倍。这个差决定了它们该怎么排。
二、真跑:两种失败位置
演示跑两次:第一次让格式段失败,第二次让测试段失败。 格式段失败:整条用两秒,后面三段全跳过。 测试段失败:整条用六十五秒,只有门控被跳过。
同样的失败,一个花两秒、一个花六十五秒。这就是顺序的价值。
三、短路省的是时间
四段全跑六十六秒。第一段就倒,只用两秒——省了六十四秒。 审查那十八秒最该省:代码连格式都不对,让模型看一遍只是浪费。 所以排序的原则是:越便宜、越机械的越靠前。
这和 5.7 节那三条质量钩子的排序是同一条:格式归工具、规则归 lint、能不能交归测试。
四、阶段之间传什么
不要传「上一步的日志」,传「上一步的结论」:通过与否、几条问题、问题在哪几行。 日志是给人看的,结论是给下一段用的。混在一起,下一段就要去解析人的话。 这也正是 4.7 节那四个字段的用途:状态、摘要、证据、下一步。
门控段只读结论,所以它一秒就能跑完——它不需要重新理解任何东西。
五、一个反模式
把审查放在测试后面。看着合理(先保证能跑),实际很亏。 测试跑四十五秒才失败,前面十八秒的审查白做了;而审查本来能提前发现「这段逻辑根本不对」。 更糟的是:测试失败时你看不到审查意见,于是修完测试再跑一次,才看到审查说的那个问题。
所以顺序该按「发现问题的成本」排,不是按「重要性」排。
六、动手 Demo:四阶段流水线:失败一次,后面还跑不跑
CI 里一条流水线通常是串起来的:格式检查、审查、测试、门控。 串起来之后最重要的设计不是顺序,是「前面倒了,后面还跑不跑」。
stages = [(u"格式", 2, True), (u"审查", 18, True),
(u"测试", 45, True), (u"门控", 1, True)]
for i, (nm, cost, _ok) in enumerate(stages):
if stopped:
continue # 前面倒了,这一段不跑
实跑输出:
--------------------------------------------------------------------
四阶段流水线:失败一次,后面还跑不跑
--------------------------------------------------------------------
CI 里一条流水线通常是串起来的:格式检查、审查、测试、门控。
串起来之后最重要的设计不是顺序,是「前面倒了,后面还跑不跑」。
① 四个阶段
--------------------------------------------------------------------
| 阶段 | 做什么 | 耗时(秒) | 这一段失败怎么办 |
|---|---|:---:|:---:|
| 1 格式 | 跑格式化与 lint | 2 | 改得动就直接改 |
| 2 审查 | 让模型看这次改动 | 18 | 只报会出问题的地方 |
| 3 测试 | 跑受影响的测试 | 45 | 不过就不许合 |
| 4 门控 | 汇总结果、决定通过与否 | 1 | 只读前面三段的结论 |
② 真跑:两种失败位置
--------------------------------------------------------------------
第 1 阶段失败时:
| 阶段 | 耗时 | 结果 | 状态 |
|---|---|:---:|:---:|
| 1 格式 | 2 秒 | 失败 | 跑了 |
| 2 审查 | — | 跳过 | 没跑 |
| 3 测试 | — | 跳过 | 没跑 |
| 4 门控 | — | 跳过 | 没跑 |
整条流水线用了 2 秒,剩下 3 个阶段被跳过。
第 3 阶段失败时:
| 阶段 | 耗时 | 结果 | 状态 |
|---|---|:---:|:---:|
| 1 格式 | 2 秒 | 通过 | 跑了 |
| 2 审查 | 18 秒 | 通过 | 跑了 |
| 3 测试 | 45 秒 | 失败 | 跑了 |
| 4 门控 | — | 跳过 | 没跑 |
整条流水线用了 65 秒,剩下 1 个阶段被跳过。
③ 短路省的是时间
--------------------------------------------------------------------
四段全跑要 66 秒。第一段就倒,只用 2 秒;第三段才倒,已经花掉 65 秒。
审查这 18 秒是最该省的:代码连格式都不对,让模型看一遍只是浪费。
所以顺序的原则是:越便宜、越机械的越靠前。这和 5.7 节那三条质量钩子的排序是同一条。
④ 阶段之间传什么
--------------------------------------------------------------------
不要传「上一步的日志」,传「上一步的结论」:通过与否、几条问题、问题在哪几行。
日志是给人看的,结论是给下一段用的。混在一起,下一段就要去解析人的话。
这也是 4.7 节那四个字段的用途:状态、摘要、证据、下一步。
⑤ 一个反模式
--------------------------------------------------------------------
把审查放在测试后面。看着合理(先保证能跑),实际很亏:
测试跑 45 秒才失败,前面 18 秒的审查白做了;而审查本来能提前发现「这段逻辑根本不对」。
顺序该按「发现问题的成本」排,不是按「重要性」排。
! 耗时是这一课设定的数,不是一个真实仓库的实测值——它演示的是排序逻辑。
①四段耗时差二十多倍:格式两秒、审查十八秒、测试四十五秒、门控一秒。这个差决定了它们该怎么排。 ②格式段失败整条只用两秒、后面三段全跳过;测试段失败整条用六十五秒、只有门控被跳过。 同样的失败,一个花两秒、一个花六十五秒。 ③审查那十八秒最该省:代码连格式都不对,让模型看一遍只是浪费。 所以排序原则是越便宜、越机械的越靠前。 ④阶段之间传结论不传日志:通过与否、几条问题、问题在哪几行。门控段只读结论,所以它一秒就能跑完。 ⑤反模式是把审查放在测试后面:测试跑四十五秒才失败,前面十八秒的审查白做了, 而且测试失败时你看不到审查意见。
30 秒实验
- 把审查和测试换个位置,重跑两种失败位置,各花多少秒? 差的这些时间,在一天提十次 PR 的团队里是多少?
- 给门控段加上「汇总要读全部日志」,重跑一遍。它的耗时涨到几秒?这说明「传结论」省的是什么?
- 把四段的耗时换成你自己项目里的真实值,重排一次顺序。结论变了吗?
常见误区
- 把最贵的放最前面(比如先跑全量测试)。一次小错就要等几分钟才知道。
- 阶段之间传日志。下一段要去解析人的话,慢且容易错。
- 前面失败还让后面继续跑。浪费时间,还可能让后面的失败掩盖前面的原因。
- 审查放在测试后面。测试一失败,审查意见根本没人看。
- 以为顺路就是顺序。顺序该按「发现问题的成本」排,不是按流程的自然感觉排。
自测三问(点开对答案)
1. 四段流水线该怎么排序? —— 越便宜、越机械的越靠前:格式、审查、测试、门控。判据是「发现问题的成本」。 2. 为什么前面失败要让后面短路? —— 省时间,也避免后面的失败掩盖前面的原因。四段全跑六十六秒,第一段就倒只用两秒。 3. 阶段之间该传什么? —— 传结论不传日志:通过与否、几条问题、问题在哪几行。门控段只读结论就能一秒跑完。流水线定了,下一节解决一个体感问题:它跑的时候,我怎么知道它在干什么。
- ☐ (本篇完,下一篇 7.6 流式输出:实时监控长耗时任务)
相关笔记
- 工程实战二:三条质量钩子的排序
- 从软件工程看:阶段之间传哪四个字段
- Claude Code 橙皮书 · 索引
- 🐎 Claude Code 实战 · 索引