架构决策记录与架构评审

半年后有人问「为什么这里用消息而不用 RPC」,如果回答是「当时那个人已经离职了」,那么这个系统就进入了一种危险状态:没人知道约束是怎么来的,也就没人敢改任何一个约束。架构决策记录(Architecture Decision Record,ADR)解决的是决策的可追溯性,架构评审解决的是决策的质量下限——两者一个是记账,一个是把关。

结论先行

问题不是 ADR 的做法ADR 的做法
决策依据散落在群聊、会议纪要、某个人的记忆里一页 Markdown 进仓库,与代码同生命周期
决策变更直接改代码,旧理由被覆盖追加新 ADR,标注取代关系,历史不可篡改
新人上手靠口口相传,三个月才敢动核心模块读一遍 ADR 目录就知道系统为什么长这样
争议复盘「当初是谁定的」「当初的假设是什么,现在是否仍成立」
评审开会拍板,事后补文档先有决策提案,评审只需针对提案挑毛病

一句话:ADR 记录的是决策和它的代价,不是设计文档。它不描述系统怎么工作,只回答「我们选了什么、放弃了什么、为什么」。

ADR 模板(可直接抄)

# ADR-0007:订单读模型使用独立的查询库

- 状态:已接受(Accepted)
- 日期:2026-03-11
- 决策者:订单域负责人(R)、架构组(C)、DBA(C)
- 关联:取代 ADR-0002;被 ADR-0011 部分修订
- 影响范围:order-service、order-query、数据平台

## 背景与问题
订单详情页需要按多维度组合筛选,主库已无法在不影响写入的情况下支撑该查询。
当前用从库满足读流量,但复杂查询导致从库延迟升高,进而影响其他业务的读一致性。

## 决策
为订单读场景引入独立查询库(写入通过领域事件同步),订单主库不再承载复杂查询。

## 备选方案
1. 继续扩从库:成本低,但延迟问题无法根治,只是把问题推后。
2. 引入搜索引擎承载筛选:查询能力最强,但带来第二套数据模型与运维成本。
3. 独立查询库(选中):数据模型可针对读场景重建,与主库解耦。

## 后果
- 正面:复杂查询与写入互不影响;读模型可独立扩展与重建。
- 负面:读模型存在秒级延迟,需在交互上明确「最终一致」;新增一套同步链路与监控。
- 中性:团队需掌握事件消费与重建流程。

## 验证与复核
- 适应度函数:读模型同步延迟 P99 < 3s;读库与主库的对账差异率 < 0.01%。
- 复核时间点:上线后 3 个月,评估是否因延迟问题需要改回从库方案。

模板里有几个字段最容易被省略,但它们恰恰是 ADR 的价值所在:备选方案(证明做过比较)、负面后果(证明知道代价)、复核时间点(证明这不是永久真理)。

什么时候必须写 ADR

必须写可以不写
引入或更换基础设施组件(数据库、消息、缓存、网关)局部重构、方法抽取、命名调整
服务拆分、合并、边界调整单模块内实现细节选择
同步改异步、引入最终一致性加一个字段、加一个接口,且无跨团队影响
数据存储模型变更(分片、读写分离、迁移策略)依赖版本升级(除非有兼容性风险)
跨团队接口契约与版本策略纯前端交互细节
明确放弃某个方案(说明「不做什么」)已有 ADR 覆盖且未偏离的常规实现

判断标准很实用:这个决定如果半年后被推翻,会不会有人不理解当初为什么这么定? 会,就该写。

ADR 的状态与生命周期

提议(Proposed) → 已接受(Accepted) → 已废弃(Deprecated)
                          ↓
                   被取代(Superseded by ADR-00xx)

规则:
- 历史 ADR 只追加、不修改;状态变更也通过新增记录或在文件头更新状态字段完成
- 被推翻的决策不改写原文,只标注「被 ADR-00xx 取代」并说明新决策的起点
- 状态为「提议」的 ADR 允许在评审中被打回,允许长期挂着(说明还没决定)
- ADR 与被取代的代码一起删除是错误做法:代码可以删,决策历史要留

文件组织建议:docs/adr/0007-order-read-model.md,一个决策一页,编号全局递增,目录即索引。写在代码仓库里,跟代码一起评审、一起走版本管理。

架构评审检查清单

评审不是重讲一遍设计,而是有目的地找风险。按维度过一遍,能覆盖绝大多数事故场景:

维度要问的问题
需求与质量属性这个设计对应哪条质量属性场景?指标是多少,谁验收?
边界与依赖新增了哪些依赖?依赖方向是否单向?有没有环?
数据所有权谁拥有这份数据?有没有跨服务直连别人的库?
失败与降级依赖不可用时发生什么?超时、重试、熔断、降级是否成对出现?
一致性强一致还是最终一致?不一致的窗口多久,业务能否接受?
容量与成本峰值 QPS 与数据增长多少?成本估算与扩容路径是什么?
可观测性SLI/SLO 是什么?traceId 是否贯通?新链路的告警与大盘在哪?
安全与权限数据分级、鉴权点、敏感字段脱敏与审计在哪里?
演进与回滚如何灰度?如何回滚?数据变更能否回退?
组织与运维谁负责值班?谁拥有这套服务?运维复杂度是否超出团队能力?

评审产出必须具体:同意 / 有条件同意(列出条件与责任人)/ 打回(说明缺什么信息)。一句「再想想」不是评审结论。

如何避免「评审变成审批」

评审一旦变成签字流程,就会立刻退化成两个后果:提案人只写能通过的内容,评审人只做形式检查。避免方法:

  • 默认异步:提案先以 ADR 形式发出,评论在文档里留痕,只有争议点才开会。
  • 按影响面分级:小改动轻量评审(异步两三天),跨团队变更标准评审(30 分钟时间盒),不可逆的重大变更才走完整评审。
  • 评审找风险,不找答案:评审者的职责是提问与指出遗漏,不是替提案人重新设计。
  • 明确决策权:评审给出意见,决策权归提案团队。人人可否决等于无人负责。
  • 条件要可验证:有条件同意必须写成可检查的条目(加上限流、补压测、补对账),并在 ADR 里标注关闭状态。
  • 允许试错:给不可逆性低的选择留出「先做,设复核时间点」的通道,否则所有决策都会被推给最高层。
  • 复核不是重审:到复核时间点看的是「当初的假设是否仍然成立」,而不是重新吵一遍。

常见误区

误区后果正确做法
ADR 写成设计文档篇幅失控,没人读,写完就过期一页以内,只写决策、备选与后果
只记录最终选择后人重复评估同一个被否掉的方案备选方案与被否原因必须写
不写负面后果团队对代价无预期,出了问题算「意外」显式列出成本、延迟、复杂度
评审开成汇报会提案人念 PPT,没人提问提前发 ADR,会上只讨论争议项
评审结论没有责任人与时限条件永不被关闭,风险长期挂着条件 + owner + 截止时间,进跟踪列表
推翻决策时改写历史决策链条断裂,无法复盘判断过程只追加新 ADR,标注取代关系
所有变更都走完整评审评审排队成为交付瓶颈,团队开始绕过分级评审,按影响面与不可逆性匹配投入

小结:ADR 用「背景、决策、备选方案、后果、状态」五段一页纸把决策的代价与依据固化在仓库里,历史只追加不修改;该写 ADR 的是引入组件、调整边界、改变一致性或存储模型这类被推翻后需要解释的决定;架构评审按清单找风险、给可验证的条件、按影响面分级并默认异步,把决策权留给提案团队——评审是把关,不是审批。

笔记加载中…