从约束到架构决策记录
架构决策记录(ADR)保存一个重要技术选择的上下文、备选方案、决定和后果,让团队能够理解并验证当时的取舍。
1. 识别值得记录的决策
ADR 适合影响广、代价高或以后难以逆转的选择,例如:
- 单体、模块化单体或微服务的边界;
- 数据存储、一致性和跨地域方案;
- 对外 API、事件和身份协议;
- 高可用、安全和合规策略;
- 核心框架、运行平台与构建方式。
普通实现细节和容易回退的局部改动可以留在代码评审中。每个小选择都写 ADR,会让决策日志充满噪声;关键决定没有记录,则会让后来者只能从代码猜测原因。
判断方法是:如果一年后有人想改掉它,是否需要知道当时的业务约束和被放弃的方案?答案为是,就值得记录。
2. 约束先于方案
决策从问题和约束开始。约束可以来自:
- 目标用户量、延迟和 SLO;
- 数据一致性、隐私和地域要求;
- 交付期限、预算和可用人力;
- 现有系统、迁移窗口和兼容期限;
- 团队技能、值班和平台能力;
- 供应商限制与退出成本。
约束要尽可能量化。“高性能”无法筛选方案,“P99 低于 200 ms,峰值每秒 5000 次请求”才可以。仍不确定的内容标为假设,并写出验证方法。
如果评审直接从“用 Kafka 还是 RabbitMQ”开始,团队很容易比较功能清单,却忘记要解决的问题。
3. 备选方案使用同一组标准
至少保留一个可行替代方案和“维持现状”。对每个方案按同一维度比较:
- 是否满足必须约束;
- 实现、迁移和学习成本;
- 运行、故障和安全风险;
- 可观测性与验证方式;
- 可逆性、锁定和退出成本;
- 对未来变化的影响。
关键结论需要证据,例如原型、压测、故障注入、供应商文档或现网数据。无法在当前阶段验证的风险要显式保留,不能用主观评分制造确定感。
对明显不满足硬约束的方案,可以说明原因后提前淘汰,不需要写成同样长度。
4. ADR 保持短而完整
一份 ADR 至少包含:
# 标题
- 状态:Proposed / Accepted / Superseded
- 日期:
- 负责人:
## 上下文与问题
## 约束与假设
## 考虑过的方案
## 决定
## 后果
## 验证与复审条件
“决定”要写清选了什么和适用范围;“后果”同时记录获得的能力、承担的成本和后续工作。ADR 解释为什么做出选择,详细实现放到设计文档和代码中。
标题直接写结论,例如“订单事件采用 transactional outbox 发布”,比“消息方案选型”更容易浏览决策日志。
5. 决策状态保留演进关系
ADR 可以经历 Proposed、Accepted、Rejected、Deprecated 和 Superseded 等状态。团队接受后,不直接改写原记录来适配新结论。
新证据出现时,新建 ADR 并链接被替代记录。这样可以看到:
- 原决定在什么约束下成立;
- 哪项约束或证据发生了变化;
- 新决定从何时开始生效;
- 哪些系统仍处于迁移期。
草案阶段可以正常修改。接受后只修正链接和明显文字错误,结论变化通过新记录表达。
6. 决策连接到验证
ADR 不是评审结束后的存档。它应连接到:
- 原型、基准和风险验证任务;
- 实现 issue 与代码评审;
- SLO、成本和业务指标;
- 迁移阶段、回滚和退出条件;
- 需要复审的日期或触发事件。
例如选择异步复制以降低写延迟,就应记录允许的 RPO、复制延迟告警和灾后对账方案。指标长期超出边界时,自动触发复审比等到故障后重新争论更有效。
架构测试也可以验证决定,例如禁止模块依赖环、限制数据库访问或检查 API 兼容性。
7. 评审关注未知风险
ADR 评审先确认问题、约束和决策负责人,再讨论方案。评论需要指出具体风险、缺失证据或冲突约束;“我更喜欢另一个框架”不构成阻塞理由。
无法达成一致时,由事先明确的决策负责人基于现有证据决定,记录少数意见和需要观察的风险。重大安全、合规或不可逆数据风险则由相应责任人拥有否决权。
评审时间也要有边界。可逆决策可以用小实验快速验证;高代价不可逆决策需要更充分的证据和更广的参与者。
8. 一个简化示例
订单服务需要可靠发布领域事件,约束是数据库提交与事件不能永久分离、现有团队只运维 MySQL 和 Kafka、允许秒级发布延迟。
备选方案包括数据库与 Kafka 分布式事务、业务代码直接双写,以及 transactional outbox。团队选择 outbox,因为它利用本地事务保证业务记录和待发事件共同提交,发布器可以重试;代价是消费者必须幂等、需要清理事件表并监控发布延迟。
验证项包括故障注入、重复事件测试和发布延迟 SLO。若未来数据库原生 CDC 成为统一平台能力,再复审发布器实现。
9. 面试题
9.1 做技术选型时怎样形成可追溯的架构决策
出现公司:字节跳动
考察重点
- 问题、硬约束、假设和证据。
- 备选方案、后果与可逆性。
- ADR 生命周期、验证和复审条件。
相关内容:第 1 节“识别值得记录的决策”至第 7 节“评审关注未知风险”。
参考回答
我会先写清业务问题、成功指标和必须满足的约束,把不确定内容标成假设。然后让维持现状和其他可行方案按相同标准比较,包括功能、迁移、运行风险、成本、可逆性和退出代价;关键结论用原型、压测或现网数据验证。
最终 ADR 记录上下文、约束、方案、决定、正负后果、负责人和验证条件。决定接受后保持原记录稳定,未来约束变化时用新 ADR 替代并建立链接。实现任务、指标、迁移和架构测试都关联到决定;无法共识时由明确的决策负责人判断,同时保留异议和需要继续观察的风险。