技术架构方法论 · 第 5 课

决策留痕:ADR 与 arc42

半年后没人记得"当初为什么这么选",于是新人推倒重来,把当年否掉的坑重新踩一遍。ADR 就是治这个病的。

⏱ 约 15 分钟 📌 前置:第 3 课 📎 文档化速查

知识点一:ADR——一页纸记住"为什么"

代码记录了系统"是什么",但"为什么是这样"只存在于当事人脑子里,而人会离职、会遗忘。Michael Nygard 2011 年提出 ADRadr.github.io):每个重大架构决策写一页纸,进代码仓库,跟代码一起演化。Nygard 格式只有五节:

# ADR-007: 竞价裁定采用单写入点串行裁定

## 状态
已接受(2026-07-30)

## 背景
驱动属性排序中一致性居首:截止瞬间必须产生全局唯一
成交结果,出错直接引发资金纠纷。备选方案:
A) 单写入点串行裁定  B) 分布式锁  C) 乐观并发+冲突重试

## 决策
采用 A:所有出价路由到单一裁定服务实例,按到达序串行裁定。

## 后果
+ 唯一成交有结构性保证,无分布式一致性协议的复杂度
- 写入吞吐受单点上限约束(压测目标 5000 TPS,当前够用)
- 故障转移窗口(≤5s)内不可写,需配合出价缓冲队列
- 否掉 B:锁服务自身的可用性成为新依赖;
  否掉 C:重试风暴在截止瞬间不可控

三个写作要点:

什么决策值得写 ADR 判据和第 1 课的 ASR 反问同构:"这个决策改了,架构会跟着变吗?"会 → 写。风格选择、数据拆分、关键中间件选型、重大取舍(评审标记的权衡点)都该写;库的小版本升级不用。经验值:一个系统头一年 10-30 篇。

知识点二:arc42——文档的骨架,按需裁剪

ADR 记决策,但新人还需要一份"系统总览"。arc42 给出 12 节标准骨架,官方态度就是按需裁剪——填满 12 节不是规范,是灾难。推荐最小集(7 节):

arc42 节写什么对应本课程
1. 目标与质量要求驱动属性排序 + 质量属性场景第 1 课产物
2. 约束技术/组织/合规约束第 1 课产物
3. 上下文C4 上下文图第 4 课产物
4. 方案策略风格选择与理由(一段话)第 2 课产物
5. 构建块视图C4 容器图(+ 关键组件图)第 4 课产物
9. 架构决策ADR 索引本课产物
11. 风险与技术债评审的风险清单第 3 课产物

注意:整个课程每一课的产物,恰好填进这份骨架——方法论走完,架构文档自动成形,不存在"设计完了再补文档"这回事。

知识点三:落地约定

随堂测验

1. ADR 的「后果」一节为什么必须写负面代价?
2. 一个已接受的决策后来被推翻了,正确做法是?
3. arc42 十二节骨架的正确用法是?

实战练习:写你的第一篇 ADR

你的任务(10 分钟):用 Nygard 格式为拍卖系统写一篇 ADR,题目:"围观推送采用事件驱动最终一致通道"。要求:背景引用你的驱动属性排序;至少列 2 个备选;后果栏必须有减号;把第 3 课挖出的"围观者可能基于旧价出价"风险体现在后果里。

写完再看:参考答案
# ADR-008: 围观推送采用事件驱动最终一致通道

## 状态
已接受(2026-07-30)

## 背景
驱动排序:一致性 > 可用性 > 伸缩/低延迟。数万人围观的
扇出压力不能回压竞价核心(一致性优先的单写入点)。
备选:A) 事件总线+推送集群  B) 围观者轮询API
C) 推送与裁定同库同步写

## 决策
采用 A:裁定服务发布价格事件到总线,独立推送集群
订阅并经 WebSocket 扇出,允许亚秒级延迟。

## 后果
+ 扇出与裁定解耦,围观规模水平扩展,不威胁一致性
+ 削峰:总线吸收截止前的事件洪峰
- 最终一致:围观者可能看到旧价并据此出价被拒,
  需前端明示"出价以服务端裁定为准"(对应风险 R-02)
- 消息总线成为推送链路单点,需给出总线故障降级方案
  (降级为 B 的轮询,另立行动项)
- 否掉 B:数万人轮询对 API 是自伤式压力;
  否掉 C:同步写扇出会把围观负载灌进裁定路径,
  与第一驱动属性直接冲突

检查你的版本:背景有没有排序?备选有没有否决理由?减号是不是具体到可验证(而非"有一定复杂度"这类空话)?三项都有,就是合格的 ADR。

课后延伸

主推资料源ADR 模板与示例集(GitHub)——Nygard 原始模板加几十种变体与真实案例;adr.github.io 是社区权威站。arc42 各节写法见官方文档,模板速查见文档化速查

💬 写好的 ADR 贴回对话,我按三项检查逐条点评。

← 第 4 课:C4 分层画图 下一课:综合演练——全流程 Kata →