一个熟悉的场景
先说三个场景。它们由多个项目里的常见问题拼合而成,不对应任何一家公司,也不指向任何具体的个人。
第一个场景:订单服务上线两年,代码从三千行长到四万行。每个人都能说出“这里有问题”,但没人说得清问题在哪一层。有人提议拆微服务,拆到一半发现订单、库存、支付共享同一张表,跨服务查询比原来还慢。项目停在中途,新旧两套逻辑同时存在,发布一次要改五个仓库。
第二个场景:支付回调偶尔重复,财务每月对账都能找出几笔重复扣款。开发加了一个 if status == "PAID" { return },管了两周,又出现“已取消订单被支付”的新工单。没人知道订单到底允许哪些状态迁移,因为规则散落在十几个 handler 里,每个 handler 都只写了“自己关心的那一段”。
第三个场景:一次架构评审会开了三个小时。方案 PPT 有四十页,讲了分层、缓存、消息队列、服务网格。有人问“如果库存服务超时,订单是失败还是继续”,回答是“我们会做熔断”。再问“熔断打开后用户看到什么”,会场安静了。最后结论是“方案整体可行,细节再细化”。
这三个场景看似不同,根因是同一个:系统里没有一个地方能回答“允许发生什么、为什么这样选、错了从哪里改回来”。
拆开看,它们都缺三样东西:
- 缺显式规则:状态迁移、数据所有权、接口契约散落在代码和口头约定里,没有单一事实来源;
- 缺决策记录:选了什么、否决了什么、什么条件下重新评估,没有人写下来;
- 缺验证手段:规则有没有被绕过,只能等线上事故或评审时靠人肉检查。
这三样东西恰好对应卷一的三个关键词:边界、决策、可执行约束。
市面上的架构书,缺了哪一层
架构书大致分两类。
第一类讲概念:分层、六边形、微服务、事件驱动、CQRS、Saga,每一章一个模式,配一张图和一段优缺点。读完能说出名词,但回到自己的系统,仍然不知道“我这个订单服务该不该拆”“这个一致性要求该放在哪一层”。
第二类讲框架:Spring Cloud 怎么配、Kubernetes 怎么部署、Kafka 怎么调参。它们很有用,但答案绑定在具体工具上。工具一换,判断方法就丢了;更麻烦的是,读者容易把“框架支持这个功能”当成“我的系统需要这个功能”。
中间缺的那一层,是从约束到决策、再到可执行检查的过程:
- 当前真正的约束是什么(团队、流量、一致性、预算、发布频率);
- 在这些约束下,有哪些备选方案;
- 为什么选这个、否决那个;
- 选错时,什么信号出现就应该重新评估;
- 这条决策能不能写成测试、检查命令或评审清单。
这套书想补的就是这一层。它不试图穷举模式,也不绑定框架,而是把每个架构问题还原成“约束—决策—验证”的链条。
本书的四个立场
立场一:架构是决策,不是图
架构图是决策的表达,不是决策本身。一张画得很漂亮的分层图,如果代码里没有任何依赖检查,它描述的只是“希望”,不是“事实”。
判断一个架构描述是否有效,可以问三个问题:它有没有写清备选方案?有没有写清否决理由?有没有写清什么条件下重新评估?三个都答不上来,那多半是宣传材料,不是架构文档。
立场二:边界先于拆分
很多团队遇到问题的第一反应是“拆”。拆服务、拆仓库、拆团队。但如果业务边界、数据所有权和事务边界还没画清,拆分只是把单体的问题复制成分布式问题:原来是一个事务,现在是一致性补偿;原来是一次调用,现在是超时、重试、幂等和链路追踪。
所以卷一先讲限界上下文、聚合、模块和端口,再讲绞杀者迁移。顺序反过来,就会得到一堆“分布式单体”:服务是独立的,数据库是共享的,发布还是要一起发。
立场三:约束必须可验证
“领域层不能依赖数据库”“订单状态只能通过状态机修改”“支付回调必须幂等”——这些话在评审会上都对,但如果没有测试或检查命令,它们在三个月后就会失效。
可验证不等于要写很重的测试。很多约束只需要一个包依赖检查、一个表驱动单测、一个契约测试,成本很低。真正贵的不是检查,是事后发现约束早就被绕过。
立场四:组织边界会变成系统边界
康威定律不是一句玩笑。团队怎么分工、谁拥有哪份数据、谁有权批准接口变更,最终都会反映到系统结构上。反过来,系统结构也会固化组织权力:一个共享数据库会让“数据 owner”这个概念名存实亡。
卷一会把组织问题单独放一章,不是因为它是“软技能”,而是因为很多技术决策的阻力根本不在技术层。一个拆分方案在技术上成立,但两个团队都不愿意放弃自己的写权限,它就不会落地。
一个完整的判断示例
抽象地讲“约束—决策—验证”容易空。用一个具体问题走一遍。
问题是:下单时,库存应该同步预留,还是先创建订单、再异步预留?
先列约束:
- 用户下单后马上进入支付,库存状态必须在他付款前确定;
- 当前没有成熟的对账任务,也没有跨服务补偿框架;
- 超卖的赔付和客诉成本,高于短暂的下单失败;
- 库存服务只有一个团队维护,SLA 还没有正式承诺。
再列备选:
- A:同步预留。订单创建请求内调用库存,成功才把订单置为已预留;失败直接返回缺货。
- B:异步预留。订单先创建成功,发消息给库存,失败再取消订单并退款。
- C:本地预扣表。先在订单库写预扣记录,后台任务与库存服务对齐。
然后写否决理由:
- B 的问题不是技术不可行,而是失败发生在用户付款之后。退款链路、客诉解释和财务对账都要为这个小概率路径付出长期成本;当前没有对账能力,这个成本不可控。
- C 的复杂度接近 A,但没有消除不一致窗口,只是把窗口从请求内移到后台任务里;在库存服务 SLA 未承诺的情况下,窗口可能很长。
最后写后果和触发条件:
- 选 A 的正面是库存与订单同成败,负面是库存服务故障时下单不可用,下单延迟受库存 P99 影响;
- 当库存服务给出正式 SLA、补偿对账连续运行一个季度无差异、或大促期间业务明确接受少量超卖换下单成功率时,重新评估。
这段推导不保证结论永远正确。它保证的是:三个月后有人问“为什么不用异步”,文档里有答案;约束变了,也知道从哪里改。
这就是本书每一章想提供的粒度:不是“最佳实践”,而是一条可以复查的决策链。
与站内文章的关系
站内已经有一批架构与分布式主题的单篇文章,覆盖 C4、ADR、DDD、六边形、API 契约、CQRS、幂等、可观测性、发布策略等题目。它们提供概念背景和模式卡片,本书不重复定义,而是在需要时用一段话概括并链接过去。
区别在于:单篇文章回答“这个模式是什么”,本书回答“在 arch-lab 的具体约束下,为什么选它、代码落在哪、怎么验证、什么时候该退出”。同一个名词,在书里必须带一个可执行产物或一份带备选方案的决策记录,否则就不写。
为什么是四卷
架构问题太多,放在一本书里会变成百科。四卷按“先画边界、再谈性能、再处理分布式、最后管演进”的顺序拆开:
| 卷 | 书名 | 核心问题 |
|---|---|---|
| 卷一 | 架构基础与边界 | 边界画在哪,决策怎么表达和验证 |
| 卷二 | 高性能与高可用 | 在既定边界内,怎么把延迟、吞吐和故障处理好 |
| 卷三 | 分布式与数据一致性 | 跨节点之后,时间、顺序、复制和一致性怎么处理 |
| 卷四 | 演进与治理 | 系统变大、团队变多之后,怎么持续演进而不失控 |
这个顺序不是“学习难度”,而是依赖关系。卷二讨论缓存和异步时,默认你已经知道数据所有权和事务边界;卷三讨论复制和共识时,默认你已经知道哪些状态必须强一致;卷四讨论平台工程和 SLO 时,默认你已经有一组可观测的边界。
卷一不追求性能数字,也不展开分布式共识。它只做一件事:把后面三卷要用的“地图”画出来。地图画错,后面跑得越快,错得越远。
每卷留下的东西
读完一卷,应该留下可复查的产物,而不只是笔记:
| 卷 | 读完应留下 |
|---|---|
| 卷一 | C4 视图、5 份 ADR、风险台账、模块依赖测试、一次评审记录 |
| 卷二 | 压测基线、容量模型、缓存与限流配置、故障演练记录 |
| 卷三 | 复制与分区方案、一致性模型选择、对账与补偿流程 |
| 卷四 | SLO 与错误预算、发布与回滚流程、平台契约、成本模型 |
这些产物不一定都用在同一个系统上,但它们提供了一个模板:下次遇到类似问题,知道该从哪里开始、该记录什么、该用什么验证。
为什么用 Go 主线,Java 对照
本书以 Go 1.26 为主线。原因不是 Go 比 Java 好,而是它足够“薄”:
- 标准库就能写出 HTTP 服务、并发任务和测试,不需要先引入一套框架;
- 接口是隐式的,讲端口与适配器时,读者能看到依赖方向本身,而不是被注解和容器遮住;
- 错误是值,讲错误契约和状态机时,控制流更接近代码的真实形状;
- 编译快、工具链统一,代码片段可以真的抽出来跑。
Java 21 作为对照出现,主要用在三个地方:类型系统(sealed interface、record)、并发模型(虚拟线程与 goroutine)、异常层次(checked exception 与 error 值)。对照只谈结构与语义,不做“语言优劣”之争,也不引入 Spring 生态。Java 代码尽量只用 JDK 自带 API,确保读者不需要装 Maven 或 Gradle 就能验证。
这个选择有一个代价:Go 的生态习惯和 Java 团队的习惯不同,某些在 Java 里理所当然的做法(比如重量级框架、运行时代理)在 Go 里并不常见。书中会明确指出这些差异,不把一种语言的惯性包装成普遍规律。
本书不做什么
明确边界,比罗列内容更重要。这套书不试图做下面几件事:
不写语言教程。 Go 的语法、Java 的集合、SQL 基础,默认读者已经会。看不懂代码时,应该去查语言文档,而不是在架构书里补基础。
不写框架手册。 不教 Spring Cloud 怎么配、Istio 怎么装、Kafka 怎么调参。工具会变,判断框架不会;书里只在必要处提到工具,并说明它替我们承担了哪部分复杂度。
不推导分布式算法。 Paxos、Raft 的证明、向量时钟的完备性,属于卷三。卷一只需要知道“哪些问题会跨节点出现”,不需要现在解决它们。
不承诺生产级性能数字。 arch-lab 是样本,不是压测平台。卷一给出的数字只用于验证边界和契约,不用来证明某个架构“更快”。
不提供组织变革方案。 书里会讲团队边界如何影响系统边界,但不会告诉读者怎么说服老板重组团队。那是另一个学科。
写作约定
为了让不同章节可以独立阅读,书里统一了几条约定:
- 代码标记:Go 代码块用
// file:、// tier:、// verify:三行注释标记来源、运行级别和验证命令;代码可以被脚本抽取到临时模块里编译。 - 运行级别:L1 是纯逻辑单包,L2 是进程内端到端,L3 是真依赖(PostgreSQL/Redis),L4 是多节点与故障注入。卷一以 L1 为主,第 12 章至少一个 L2。
- 术语:聚合、限界上下文、端口、适配器、防腐层、outbox 等词,第一次出现时给英文和本书用法;附录 A 有完整术语表。
- 站内链接:所有指向站内文章的链接使用 Hugo 的
relref,避免 URL 大小写和中文路径带来的死链。 - 版本:Go 1.26.0、PostgreSQL 18.4、Docker 29.7.2、Java 21(Temurin 容器)。版本变化时,先验证再改结论。
- 数字:没有命令和输出的数字,一律写成目标值或示例参数;不把设计目标伪装成实测结果。
这些约定看起来琐碎,但它们决定了书里的结论能不能被复核。技术写作最怕的不是观点不同,而是读者无法判断哪句话是事实、哪句话是作者的偏好。
贯穿项目 arch-lab
全书用一个订单交易系统 arch-lab 串起来。它包含订单、库存、支付三个核心聚合,五个 API 端点,一套显式状态机,以及从内存适配器到 PostgreSQL 的两级存储。
arch-lab 不是生产系统。它刻意做小,小到可以在一篇文章里讲清一个完整决策;但它又足够真,每个取舍都有代价:
- 同步预留库存保住了不超卖,代价是库存服务故障时下单不可用;
- 模块化单体保住了事务简单,代价是不能按模块独立扩缩容;
- outbox 保住了消息可靠,代价是发布延迟和重复消费;
- 防腐层保住了领域干净,代价是多一层翻译和未知状态处理。
书里不会说“选 A 就对了”。它会说:在当前约束下选 A,因为 B 和 C 的代价在这里不可接受;如果约束变成 X,就应该重新评估。
对“实测”的承诺
技术书最容易失去信任的地方,是数字。
“QPS 提升 300%”“延迟降低 80%”——如果没有机器、版本、数据集、命令和原始输出,这些数字和广告没有区别。本书的规则是:
- 写“实测”,必须附命令、环境(机器架构、Go/Java/数据库版本)和输出;
- 只跑过一次的,注明“单次运行”,不包装成稳定结论;
- 没有跑过的,写“目标值”“示例参数”或“预期行为”,不写“实测”;
- 压测数字必须说明并发模型、数据规模、预热方式和失败率;
- 版本号以实际验证过的环境为准,不写“最新版”。
这条规则会让书里少一些漂亮的数字,但会让读者多一分可复现的信任。
适合谁,不适合谁
适合:
- 有 2–5 年后端经验,写过业务代码,但没系统做过架构决策的工程师;
- 正在负责一个中型系统,感觉“能跑但改不动”,需要一套判断框架的技术负责人;
- 准备架构评审、技术方案评审,想知道该问什么、怎么记录反对意见的读者;
- 写 Go 或 Java,愿意动手跑测试,而不是只读结论的读者。
不适合:
- 完全没写过后端代码、想先学语言语法的读者;
- 想找“微服务从 0 到 1 实战”或“Kubernetes 保姆教程”的读者;
- 希望每个问题都有唯一正确答案的读者——架构决策几乎总是在约束下选次优解;
- 只想看性能数字、不想看推导过程的读者。
三类读者的不同读法
业务开发。 你的目标是“下次改需求时知道该动哪一层”。重点读第 1、4、5、7 章,配合每章的测试自己写一遍。第 2 章的 ADR 可以先看格式,等项目里真的要做决策时再回来补。
技术负责人。 你的目标是“让团队的决策可复查”。重点读第 2、8、9、12、13 章,特别是风险台账和评审记录。代码可以挑着跑,但 ADR 和评审清单要完整写一次。
架构评审者。 你的目标是“在评审会上问到点上”。先读第 2.3 节和附录 C,再回头看第 3、6、10、11 章的边界问题。你不需要记住所有代码,但要知道每个决策的失效信号。
怎么读
第一次读,按顺序从第 1 章走到第 13 章。每章都有代码和检查命令,跳读会错过“约束怎么变成断言”的关键一步。
手上有具体问题,直接查目录篇的症状对照表。
要评审方案,先读第 2.3 节和第 13.2 节,再用附录 C 的清单自查。
读代码时,至少跑一次 gofmt、go vet 和 go test。书里的代码块带 file/tier/verify 标记,可以被抽取到临时模块里编译;跑不通的代码,不值得相信它对应的结论。
开工前的八个问题
在动手改自己的系统之前,先回答下面八个问题。答不上来的,就是卷一要补的地方:
- 这个系统最核心的三个业务概念是什么?它们各自拥有哪些数据?
- 哪些状态迁移是合法的?规则写在哪里,有没有测试穷举?
- 哪些操作必须在一个事务里完成?哪些可以最终一致?
- 模块之间的依赖方向是什么?有没有检查命令,还是只靠口头约定?
- 一个请求穿过哪些服务?每一跳的超时预算分别是多少?
- 重复请求、重复消息、重复回调,分别由哪一层负责去重?
- 系统出故障时,第一眼从哪里看出“卡在哪一步”?
- 最近一次架构决策是什么?备选方案是什么?什么条件下会推翻它?
这八个问题没有标准答案,但它们能暴露“规则没有落点”的位置。卷一不会替你回答,但会给你一套把答案写下来、并让代码检查它的方法。
六个常见问题
没有 Go 基础,能读吗?
能读,但会慢。书里的 Go 代码只用到结构体、接口、error、goroutine、标准库 HTTP 和 testing,不涉及泛型技巧或运行时黑魔法。如果这些词陌生,建议先补一门 Go 入门课,再回来读第 3 章之后的代码。
为什么不直接讲微服务?
因为微服务是边界清楚之后的一种部署选择,不是架构起点。第 4 章先讲模块化单体,第 8 章才讲怎么迁移。直接讲微服务,读者容易学会“怎么拆”,却不知道“拆到哪里为止”。
书里的代码能直接用在生产吗?
不能。arch-lab 是教学样本,省略了鉴权细节、审计、限流、灰度、监控告警等生产必需项。它的价值是展示结构和决策,不是提供可直接复制的脚手架。生产代码需要按你的约束重新设计。
每章都写 ADR,会不会太重?
书里写 ADR 是为了示范“决策可复查”。实际项目中不需要每件事都写长文档:一个影响多个团队、难以回退、或三个月后会被追问“为什么”的决策,才值得写。小的实现选择写在提交信息或代码注释里就够了。
读完卷一,够不够应付面试?
能覆盖架构设计题里“如何划分边界、如何做取舍、如何评审方案”这一类问题,但不够覆盖分布式算法、性能调优和具体框架细节。面试更看重你能否把约束讲清楚,而不是背出多少模式名。
为什么不给一套统一的最佳实践?
因为最佳实践依赖约束。两人团队的最优解和两百人团队的最优解不同;日订单一千和日订单一千万的瓶颈不同。书里给的是判断方法:先列约束,再列备选,再写否决理由和重新评估条件。方法可以迁移,结论不能。
卷一的写法从哪来
卷一的 13 章不是先定大纲再找材料,而是反过来:先盘点站内已有的架构与分布式文章,找出重复、空缺和只有结论没有代码的部分,再决定每一章要补什么。
盘点时用了三条规则:
- 已经讲清概念的文章,只作为背景链接,不重写;
- 多篇文章重复讲同一模式(比如网关、服务网格、链路追踪),合并成书里的一节,只保留判断依据;
- 只有结论、没有可执行产物的题目,必须补代码、测试或 ADR,否则不进书。
大致对应关系如下:
| 站内已有内容 | 卷一怎么用 |
|---|---|
| 设计原则、模式对比 | 第 1 章只取判断框架,不重复清单 |
| C4、ADR、架构评审 | 第 2 章改为 arch-lab 的四级视图与五份具体 ADR |
| DDD、限界上下文、事件驱动 | 第 3 章改为订单域的事件风暴产物与聚合边界 |
| 模块化单体、六边形、API 契约 | 第 4–5 章补端口测试、依赖检查与契约文件 |
| 数据一致性、CQRS、分布式事务 | 第 6 章只讲订单数据的所有权与事务边界,分布式留到卷三 |
这张表也解释了为什么书里有些题目看起来“讲过”:概念确实讲过,但约束、代码、否决理由和失效信号是新的。重复概念没有价值,重复判断过程才有。
版本与反馈
书中版本以实际验证过的环境为准:Go 1.26.0、PostgreSQL 18.4、Docker 29.7.2、Java 21(Temurin 容器)、Hugo 0.163.3+extended。版本升级后,代码可能需要小改,但判断框架不变。
如果发现代码跑不通、数字对不上,或某段推导有遗漏,欢迎带着命令和输出指出。技术书最怕的不是被批评,而是错误被当成结论传播。
最后
架构不是让人显得聪明的名词集合,也不是一张挂在墙上的图。它是在资源有限、信息不全、团队会变的情况下,仍然能让系统做出可解释决策的一套约束。
这套约束写下来,才有可能被讨论;能被讨论,才有可能被改进;能被测试,才不至于在半年后悄悄失效。
具体来说,读完卷一,你应该能独立完成下面四件事:
- 画出一份四级视图,并说清每一级给谁看、回答什么问题;
- 为三个关键决策写出带备选方案和重新评估条件的 ADR;
- 把至少一条模块依赖或状态迁移规则变成 CI 里的检查;
- 说清当前系统最贵的三个变更,以及它们为什么贵;
- 给出一次“不拆分”的理由,而不只是“拆分”的理由;
- 主持一次评审,记录反对意见、风险和明确的结论。
如果暂时做不到,也没关系。先从一个小系统、一条规则、一个测试开始。架构判断力不是读出来的,是在一次次“写下来、被质疑、再修正”里长出来的。
写这套书的另一个原因,是希望读者少走一点“先拆了再说”的弯路。拆分本身不难,难的是拆完之后,边界还在、数据还对得上、故障还能定位。卷一先把这些难的部分讲清楚,后面的性能、分布式和治理才有稳固的落点。
这也是为什么书里反复出现“代价”这个词。每个选择都有代价,承认代价,才能在下一次约束变化时知道该改哪里;只讲收益的方案,通常还没被真正评审过。
如果读完卷一,你能在自己的系统里指出三条“没有落点的规则”,并把其中一条变成测试或检查命令,这本书就没白写。
这本书不会替你做决定,但它会尽量把每个决定的代价写清楚。剩下的,是在你自己的约束里,选一个能承担、也能改回来的答案。
如果只能记住一句话:先写清允许发生什么,再讨论用什么技术实现。
顺序反了,技术就会替你做决定。
这也是本书坚持每章都给可执行产物、而不是只给结论的原因。
Leeting Yan
2026 年 10 月
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。