目录
正在加载目录…
专栏文章
专栏文章
决策与权衡专栏
1. 决策与权衡总览:从选项到可审阅的承诺 2. 决策记录ADR:让技术决策可追溯可演进 3. 决策矩阵与权衡:在多目标下显式取舍 4. 可逆性与双向门:降低决策的不可逆成本 5. Premortem与预承诺:在行动前发现失败路径 6. 决策与权衡综合实践:做一次可复盘的技术选型 7. 附录:ADR 模板与示例

决策记录ADR:让技术决策可追溯可演进

发布于 2026-08-25 10:46 · 最后编辑于 2026-08-25 10:46 · 字数 3,032 👁 8 次阅读

TL;DR:架构决策记录(ADR)是一份轻量文档,记录“做了什么决策、为什么、基于什么假设、放弃了什么”。它不是设计文档,而是决策的留痕——让半年后没人记得“为什么选了 A”时仍能回溯推理。ADR 的关键属性是可演进:新决策可取代旧决策,形成决策树而非孤立文件。一份合格的 ADR 必须包含上下文、决策、后果与假设,且假设是可证伪的——若假设不成立,决策应被推翻。

概念解释

ADR 的由来与定义

架构决策记录(Architecture Decision Record,ADR)由 Michael Nygard 在 2011 年的文章《Documenting Architecture Decisions》中提出。它的诞生源于一个普遍痛点:团队做过无数技术决策,但绝大多数只存在于 Slack 消息、会议纪要或某个人的脑子里,半年后无人能回答“为什么当时选了 A 而不是 B”。ADR 的定义很简单——每个重要决策写一份短文档(通常 1-2 页),放在代码仓库里随代码版本管理

ADR 不同于设计文档:设计文档描述系统“长什么样”,ADR 描述“为什么决定让它长这样”。它也不替代 RFC——RFC 是决策前的讨论,ADR 是决策后的留痕。一份 ADR 回答四个问题:上下文(面临什么问题)、决策(选了什么)、后果(带来什么)、假设(基于什么前提)。

supersede(取代)机制

ADR 不是写完就冻结的。Nygard 提出 ADR 可被取代:当新决策推翻旧决策时,不删除旧 ADR,而是新建一份 ADR 并标注它取代了哪份旧 ADR,同时在旧 ADR 顶部标注“已被 ADR-XXX 取代”。这形成一棵决策树——能追溯每次决策变迁的来龙去脉。这是 ADR 区别于普通文档的核心属性:它让决策历史可演进且不丢失。

决策状态

每份 ADR 有生命周期状态:Proposed(提议中,待评审)→ Accepted(已采纳,将执行)→ Deprecated(已废弃)或 Superseded(已被取代)。状态让团队知道这个决策是否仍有效,避免基于过时 ADR 行动。

ADR 与 ADR-Tools / MADR

社区发展出多种 ADR 变体:轻量版(Nygard 原版四要素)、MADR(Multiple-Attribute Decision Record,含多属性评分)、Y-Statements(Why/What/How 结构)。本专栏用 Nygard 原版为主,因为它最轻量、上手最快,复杂决策可参考 MADR 的评分思路(见 决策矩阵与权衡:在多目标下显式取舍)。

为什么 ADR 要放代码仓库

ADR 放在代码仓库而非 Wiki/Confluence,是因为:① 随 git 历史可追溯每次修改;② 代码 review 流程天然覆盖决策评审;③ 与代码同生命周期,不会因 Wiki 迁移而丢失。这是 ADR 区别于“记在文档系统”的关键实践。

目录

章节说明
为什么需要 ADR口头共识的问题
ADR 的内容结构上下文、决策、后果、假设
supersede 与决策树决策如何演进
软件工程示例技术选型 ADR
适用边界与误用何时该写何时不该写

为什么需要 ADR

没有 ADR 的团队会反复经历同一类对话:

adr vs consensus

场景没有 ADR有 ADR
“为什么用 MySQL 不用 PG?”没人记得,或各执一词查 ADR-007,看当时上下文与权衡
出了问题,是该推翻决策还是执行偏差?重新开会从头争论对比 ADR 的假设,看哪个前提变了
新人入职问“为什么这样设计”老人凭记忆讲,常遗漏自己读 ADR 理解决策脉络
半年后想换技术栈不确定当时选型的约束是否还在翻 ADR 的假设清单,逐条核对是否仍成立

ADR 解决的核心问题是决策的遗忘与不可审阅性。它不保证选对,但保证选错后能快速定位“哪个假设错了”——这是从“反复争论”到“定向复盘”的关键跳跃。

ADR 的内容结构

一份合格的 ADR 包含四要素:

adr content structure

要素回答什么常见错误
上下文(Context)面临什么问题、有什么约束只写结论不写背景,后人不知为何要决策
决策(Decision)选了什么、为什么选它只写“选 A”不写“放弃了 B/C 的什么”
后果(Consequences)带来什么正向与负向影响只写优点不写代价,误导后续
假设(Assumptions)基于什么前提;若前提不成立决策应推翻假设藏在脑里不写明,无法证伪

假设是最易被忽略也最关键的要素。没有显式假设的 ADR 只是一份结论备忘,无法在前提变化时触发重新决策。假设必须是可证伪的——能写出“若观察到 X,则假设 Y 不成立,决策需重评”。

supersede 与决策树

ADR 的演进不是覆盖旧文件,而是新建并链接:

adr evolution tree

ADR-007: 选用 MySQL 作为订单库(Accepted)
   ↑ 取代
ADR-012: 迁移到 PostgreSQL(Accepted)
   ↑ 取代
ADR-019: 订单库分库分表到 TiDB(Accepted)

每份新 ADR 顶部写“Supersedes ADR-XXX”,旧 ADR 顶部写“Superseded by ADR-YYY”。这棵决策树让团队看清:每次技术变迁的触发条件(哪个假设变了)、当时的权衡放弃旧方案的代价。没有这棵树,技术栈演进就只剩“现在长这样”,失去变迁逻辑。

练习

选一个你所在系统的技术决策(如选了某框架、某中间件),按四要素写一份 ADR。重点检查:假设是否可证伪?后果是否包含负向影响?若找不到当初的上下文,就把“现在能推断的”写明并标注“上下文为事后重建”。

软件工程示例

某团队要为订单服务选缓存方案。朴素做法是开会拍板“用 Redis”。写 ADR 则是:

要素内容
上下文订单服务 QPS 峰值 5w,读多写少;现有本地缓存击穿风险;团队有 Redis 运维经验但无 Cluster 经验
决策选用 Redis 主从版(非 Cluster);读穿透用布隆过滤
后果正向:低延迟、团队熟悉、运维成本低;负向:单点风险需哨兵、数据量增长后需迁移 Cluster
假设① 订单数据量两年内不超 50G;② QPS 增长不超 3 倍;③ 团队能掌握哨兵运维。任一不成立则需重评

这份 ADR 半年后若数据量逼近 50G,假设①触发,团队知道该启动迁移评估而非继续加内存——这就是显式假设的价值。它与 因果与证据总览:从主张到可验证决策 的证据思维一致:假设即待检验的因果主张。

适用边界与误用

  • 不必为每个小决策写 ADR:低风险可逆决策(如函数命名、内部工具选型)写 ADR 是负担。ADR 留给影响面大或不可逆的决策。
  • ADR 不是审批流:它是记录而非审批工具;若变成走流程填表,就失去留痕价值。
  • ADR 不替代设计文档:设计文档描述系统结构,ADR 只记录决策理由。
  • ADR 不保证选对:它让选错后可定向复盘,而非保证不选错。
  • 不要等决策完美才写:决策一旦做出就写,哪怕后续被取代——被取代的 ADR 同样有价值,它记录了“曾这样想过”。

关联笔记

  • 决策与权衡总览:从选项到可审阅的承诺(决策三层结构中的“承诺”层)
  • 决策矩阵与权衡:在多目标下显式取舍(ADR 的“决策”要素可用矩阵支撑)
  • 可逆性与双向门:降低决策的不可逆成本(判断哪些决策值得写 ADR)
  • Premortem 与预承诺:在行动前发现失败路径(ADR 的假设可由 Premortem 识别)

参考资料

← 返回列表

评论 (0)

暂无评论,来留下第一条吧。
登录注册 后才能发表评论