专业书籍精读 · Accelerate · 第 5 章
Accelerate: The Science of Lean Software and DevOps · Ch 5 · Forsgren, Humble & Kim · 2018
上一章说:软件要发得又快又稳,靠的是每天合并、自动检查这些做法。可很多团队会喊冤——我们也想天天发啊,可是发不动。改一行字,要等另外七个组一起排队、等一个月一次的「上线窗口」。第 5 章要回答的就是这个:是什么东西卡住了他们?答案出乎意料——不是他们不努力,是房子的结构不对。
研究者本来以为,做手机 App 的团队肯定比守着几十年老系统的团队快。结果一查数据:老系统、买来的现成软件、装在设备里的软件……做什么类型的系统,几乎看不出快慢差别。跑在几十年前那种老机器上的团队,照样能进最快的那一档。
想象一栋楼,所有房间共用一根总水管,而且没有分闸。你想换自家水龙头,就得通知全楼、约一个统一停水的晚上、所有人一起动工、一起验收。不是换水龙头难,是「必须整栋楼一起来」这件事难。
软件里到处是这种没有分闸的楼:想验证一点小改动,得先把全公司的系统凑齐搭成一整套;想上线,得等所有人都准备好。人越多越难约,于是加人反而更慢。
这一章说,判断一个系统的结构好不好,只需要问两个非常朴素的问题:
一、我能不能自己一个人验?不用把别人的东西凑齐搭一整套,就能把我这块改动大部分检查完。做法上,就是给邻居家做个「假门面」——一个照着约定好的样子应答的替身,我只管测自己这一侧。
二、我能不能自己一个人发?不用等别人、不用挑统一的窗口,我这块想什么时候上线就什么时候上线。前提是我和邻居之间有一份写清楚、不随便变的「接口约定」,我按约定改,就不会砸到别人家。
这两条一旦成立,一件很妙的事情就发生了:沟通量降下来了。原来要开的那些跨部门协调会,本质上是在替「没有分闸」还债。装了分闸,每个小组自己就能把活干完。
最值得记住的一条是关于人多了会怎样。数据显示:结构好的团队,人越多,人均产出还在往上走;结构差的团队,人越多,人均产出反而往下掉——新来的人大部分时间都花在等别人和开会上。所以架构真正决定的不是「技术先不先进」,而是你加的人到底变成了产能,还是变成了协调成本。
还有一条对管理者的提醒:别去规定大家用什么工具。这一章发现,能自己挑趁手工具的团队,反而干得更好——因为工具好不好用,只有天天用它的人知道。
架构好不好,别看图画得多漂亮、也别看是不是最时髦的技术,就问两句话:我能不能自己测完?我能不能自己发出去?两个「能」,剩下的就顺了。诚实的代价是——装分闸要花钱:拆得越开,要管的零件越多、要维护的约定越多,拆过了头,你只是把开会换成了排查故障。
想进到具体机制、研究结论和示意图? → 切到精读版
你以为架构的问题是「该选什么技术、要不要上微服务」,这一章用数据把问题换了个问法:系统属于哪一类(大型机、套装软件、嵌入式、全新绿地)几乎不预测交付效能,能不能独立测试、能不能独立部署才预测。架构的产出不是一张拓扑图,而是一个可观测的组织事实——一个团队能不能不求人就把活从设计干到上线。这也是《Accelerate》全书里对「加人为什么不提速」给出的正面答案。
本章是 Part I「研究发现」的第 5 章:上承第 4 章(技术实践把持续交付拆成可测量的能力),下启第 6 章(把安全融入交付)。它回答的是第 4 章留下的那个尴尬问题——道理都懂,可我们的系统根本不允许我们那么干,怎么办。对应现实里,它正是「单体还是微服务」「要不要建平台团队」「加了人为什么反而更慢」这类争论的实证底本;今天 DORA 把它固化成了两条独立能力条目:松耦合架构 与 松耦合团队。
第 4 章的结论很硬:每天并回主干、可靠的自动化测试、随时可发的主干,这些能力驱动效能。但一个真实团队的日常常常长这样——改一行配置,要先申请那套全公司唯一的集成测试环境(排队 3 天),环境里另一个系统正好坏着(再等 2 天),测完还要等每月一次的发布窗口,窗口当晚 7 个团队一起上线,出事了先花两小时确认是谁的问题。在这种结构里,「每天部署一次」不是纪律问题,是物理上不可能。
所以本章的问题是:持续交付有没有前置条件?如果有,是不是「你得是家新公司、做的是新系统」?它直接决定了两类流行说法成不成立:「我们不适用论」(我们守的是跑了二十年的大型机核心 / 买来的套装软件 / 设备里的固件,那套东西是互联网公司玩的)和「上微服务就好了」(拆成服务,速度自然上来)。
不回答会怎样?两种浪费各走一边:前者用「行业特殊」把自己锁死在年度发布里;后者花两年把一个单体拆成 80 个服务,然后发现这 80 个服务还是必须一起测、一起发——付了分布式的全部代价,一次都没享受到独立发布的好处。本章要做的,就是把「架构好不好」从审美之争变成两条可打分、可与效能做统计检验的具体特征。
研究把受访者做的系统分成许多类:全新绿地系统、面向用户的交互型系统、账目类记录型系统、自研软件、由另一家公司开发的定制软件、买来的套装商业软件(COTS)、跑在自建数据中心里的软件、装在用户设备上的软件、嵌入在硬件产品里的固件、以及大型机(mainframe)软件。然后问:哪一类更容易进高效能组?
答案是:基本上,哪一类都行。系统类型与交付效能之间没有出现显著差异——做大型机的团队照样可以是高效能团队。这一条直接反驳了当时流行的双模 IT(bimodal IT)主张:把「快的创新系统」与「慢的记录系统」分成两种速度分开管理。本书的数据说,慢不是记录型系统的宿命,而是架构与实践的结果。
但有两个例外,它们恰好指向同一个机制:低效能组更可能在做「由另一家公司开发的定制软件」(即外包),也更可能在做大型机系统。注意分寸——这不是说外包团队水平差、大型机技术不行,而是这两种情形通常伴随同一个特征:你需要的改动,控制权不在你手上。代码归另一家公司,或变更必须走另一套审批与排期,牵动的人就多了。本章真正在测的从来不是技术,而是牵动的人有多少。
本章把架构操作化成了两个几乎是白话的问卷条目,任何团队都能当场自答:
注意第二条里那个容易被跳过的词——「并且确实在」(can and do)。架构上「理论上可以独立发」但实际上从来都是跟着大部队一起发,不算数。这是本章最锋利的一刀:它测的是既成事实,不是设计意图。很多号称已经微服务化的组织,正是死在这半句上。
这两条为什么这么灵?因为它们卡住了持续交付的两个瓶颈。可测试性决定反馈有多快:在自己机器上用测试替身跑完的检查是分钟级,必须排队进集成环境的检查是天级;反馈从分钟退化成天,团队就会本能地攒一批改动再测,批量变大,又回到第 4 章那条超线性上涨的冲突曲线。可部署性决定批量有多大:只要必须和别人一起发,你的部署批量就等于所有人的改动之和,一旦出事,第一件事不是修,而是先花时间确认是谁的问题。
架构与团队边界是同一件事的两面(这正是 Conway 定律的现代表述)。本章的「松耦合」判据,除了上面两条技术特征,还包括一组关于自主权的条目——一个团队能不能:
最后一条常被当成琐碎细节,其实是整组判据的试金石:只敢周六凌晨发布,正是因为既不能独立验证、又必须和别人一起发——白天出事牵连面太大。「敢不敢在周二下午三点上线」,是一个不用看架构图就能读到的耦合读数。
还要注意:这套判据里没有一条要求你把系统拆成几十个服务,它们全都在问同一件事——办成一件事要牵动多少人。所以本章反对的不是单体,而是把「必须一起动」制度化的一切安排:唯一的集成环境、统一的发布列车、跨系统的联合验收、必须走别人排期才能做的变更。
本章最有杀伤力的一张数据,是把每位开发者每天的部署次数放在纵轴、团队开发者人数放在横轴:
这解释了《人月神话》那条老结论在今天的作用机制:紧耦合系统里,沟通路径数量随人数近似平方级增长(n 个人两两之间是 n(n-1)/2 条路径,白话说——人翻一倍,要对齐的关系接近翻四倍)。松耦合把这张全连通的网切成若干小组,组内高带宽、组间只走接口,新增的人于是被吸收进某个小组,而不是摊进全局协调网。这条曲线也是最实用的自检工具:团队从 20 人涨到 60 人而交付速度没变快,那不是招错了人,是架构到顶了。
本章有一节专门写给架构师和技术管理者,结论扎人:架构师应该关注工程师与结果,而不是工具与技术。一件工具再先进,如果用它的人讨厌它、或者它并没带来我们真正在意的那些结果(能独立测、能独立发),它就是无关变量。与之配套的发现是:能自己选择工具的团队,持续交付做得更好,进而交付效能也更好——工具趁不趁手,只有天天用它的人有第一手信息。
这条最常被误读成「随便用什么都行」,所以要补上分寸:它反对的是由远离一线的中央小组统一指定,不是反对一切标准。务实的平衡点通常是:基础设施与安全基线统一(否则每个团队都在重造运维),语言与框架尽量留给团队;任何标准都以「它是否让团队更能独立测、独立发」来评判。
实现手段上,本章点到的都是常规牌:用限界上下文与 API 把大领域切成松耦合的小单元,用测试替身与虚拟化让服务能被隔离测试。共同点是——都在减少「必须凑齐才能干活」的场合。
本章的两条判据是目标,不是方案。达成它的手段有好几种,代价各不相同;选错的典型后果,就是那个大家都听过的「拆了两年,发布还是一个月一次」。
表 1 · 四种常见形态:谁真正拿到了独立测 / 独立发
| 能独立测? | 能独立发? | 诚实的代价 | 适用 | |
|---|---|---|---|---|
| 紧耦合单体 | 否,要整套环境 | 否,全量一起发 | 批量与协调成本随人数上升;发布窗口成为瓶颈 | 小团队(< 10 人)早期,速度尚未受架构约束 |
| 模块化单体 | 是,模块内可测 | 一起发,但只有一个部署单元,无需跨团队协调 | 边界靠纪律维持,没有进程隔离,一处失控会腐蚀全局;单次部署仍是全量 | 中等规模、业务边界还在变;想要独立性但不想付分布式的账 |
| 松耦合服务 | 是,替身 + 契约测试 | 是,按需独立部署 | 运维面积成倍增加:可观测性、版本兼容、分布式故障排查都要真金白银 | 多团队并行、规模已把协调成本推成主要瓶颈 |
| 分布式单体 | 否,仍需集成环境 | 否,仍要一起发 | 最差的一档:分布式的全部代价 + 单体的全部约束 | 无——这是要识别并退出的状态 |
表 2 · 症状 → 根因 → 该动哪里(把两条判据落成体检表)
| 你观察到的症状 | 它在说明什么 | 优先动作 |
|---|---|---|
| 只敢周末 / 凌晨发布 | 爆炸半径不可控,且必须多方在场 | 先做到「工作时间可发、可快速回滚」,这是耦合读数最快的一根指针 |
| 集成环境要排队、还经常坏 | 可测试性不达标,反馈从分钟退化到天 | 引入测试替身与契约测试,把「必须凑齐」的场合降到最少 |
| 发布要开跨团队协调会 | 可部署性不达标,部署批量等于所有人之和 | 版本化 API + 向后兼容,让消费者按自己的节奏迁移 |
| 加了人速度没变快 | 沟通路径已随人数平方级增长 | 按限界上下文切团队边界,让新增的人进得了某个小组 |
| 改自己的设计要外部审批 | 自主权不足,架构问题其实是组织问题 | 把决策权下放到团队,中央只守基础设施与安全基线 |
表 3 · 工具与技术选择:中央统一 vs 团队自选
| 中央统一指定 | 团队自选(本章结论倾向) | |
|---|---|---|
| 与效能的关系 | 无证据表明更好 | 与更好的持续交付与交付效能相关 |
| 机制 | 决策者离一线远,缺第一手信息 | 用的人最知道趁不趁手,也更愿意把它调好 |
| 代价 | 标准好维护,但可能标准化了错的东西 | 技术栈发散、招聘与轮岗成本上升、重复造轮子 |
| 务实的平衡 | 基础设施与安全基线统一;语言 / 框架尽量留给团队。判据只有一条:这条标准是让团队更能独立测、独立发,还是更不能? | |
一条排序建议:先做可测试性,再做可部署性。能独立测但暂时还一起发,你至少拿到了分钟级反馈;反过来,能独立发却测不了,等于把没验证过的东西更快地推向生产——这不是提速,是加速踩雷。
这一章是「微服务之争」里最值得反复引用的一段实证,因为它把标准从形式(拆了几个服务)挪到了结果(能不能独立测、独立发)。今天 DORA 把它固化成两条能力——松耦合架构与松耦合团队——供团队自评;它也是「平台工程」的底层理由:平台的价值不在统一了技术,而在让业务团队少求人。
面试高频题「你会把这个单体拆成微服务吗」,本章给的是反问模板:现在哪一步必须凑齐所有系统才能做?发布要牵动几个团队?拆完这两条会变好还是变坏?——说得出「拆完仍然要一起发,所以先不拆,先去掉集成测试的依赖」的人,比背得出微服务优点列表的人深一层。
140+ 个微服务、每个服务一个代码库之后,共享库的版本、测试与运维负担把团队压垮,最终又合并回了单体。文章标题就叫《Goodbye Microservices》。这是「拆分本身不是目的」最诚实的一份自述。A. Noonan「Goodbye Microservices: From 100s of problem children to 1 superstar」, Segment Engineering, 2018 ↗2200 个关键微服务后遭遇了微服务架构的权衡代价,于是用领域化的方式(DOMA)把服务归拢成数十个领域来压制复杂度;他们报告说,减少接入一个新功能所需的对接点之后,接入时间下降了 25%–50%。拆得越细不等于越松耦合——边界画在哪里才是关键。Uber Engineering「Introducing Domain-Oriented Microservice Architecture」 ↗280 万行 Ruby、50 万次提交的巨型 Rails 单体,选择的不是拆成微服务,而是把约 6000 个类逐一归类、重组成组件化的模块化单体,先把边界立住。这正好印证本章:目标是解耦,单体与服务只是两条路径。K. Westerlind「Deconstructing the Monolith」, Shopify Engineering, 2019 ↗200 个服务却必须一起发的,一分都拿不到。① 一句话:架构好不好,不看它属于哪一类系统、用了什么技术,只看两条——能不能独立测、能不能独立发。
② 最反直觉的发现:系统类型(大型机 / 套装软件 / 嵌入式 / 绿地)与交付效能没有显著差异,这直接反驳了「双模 IT」——慢不是记录型系统的宿命。
③ 例外指向同一个机制:低效能组更可能在做外包开发的定制软件与大型机系统——共同点是控制权不在自己手上。
④ 两条操作化判据:大部分测试不需要集成环境;能够并且确实在独立于依赖服务的情况下部署发布。注意「并且确实在」——测的是既成事实,不是设计意图。
⑤ 架构的另一半是团队自主权:改自己系统的设计不必外部许可、完工不必细粒度跨团队协调、能在正常工作时间部署且停机可忽略——最后一条是最省事的耦合读数。
⑥ 规模效应是本章最有杀伤力的数据:每人每天部署次数随团队人数变化,高效能上升、中等持平、低效能下降。机制是紧耦合下沟通路径随人数近似平方级增长(n(n-1)/2),而松耦合把全连通网切成组内高带宽、组间只走接口。
⑦ 架构师应关注工程师与结果,而非工具与技术;能自选工具的团队做得更好,但这不等于取消一切标准——标准要以「是否增强独立测 / 独立发」评判。
⑧ 手段是常规牌:限界上下文 + 版本化 API 切边界,测试替身与虚拟化去掉对集成环境的依赖。拆成服务只是手段之一,模块化单体同样合格。
⑨ 最该记住的失败形态是分布式单体:服务拆了却仍要一起测、一起发——分布式的代价全付了,独立性的收益一分没拿到。实操上先修可测试性、再修可部署性:能独立发却测不了,只是把未验证的东西更快推向生产。
⑩ 读它的分寸:自愿问卷 + 推断性预测分析,方向性强但不是随机对照实验;「架构 → 效能」大概率是双向因果。