技术决策与 ADR
决策真正稀缺的,不是结论,而是上下文
很多团队其实并不缺结论。
缺的是:
- 这个结论为什么当时成立
- 当时有哪些约束
- 还认真考虑过哪些方案
- 团队接受了什么代价
时间一长,这些背景就会流失。
后来的人只会看到“系统现在是这样”,却不知道:
- 这是主动选择
- 还是历史偶然
- 是长期方向
- 还是临时妥协
ADR 的价值,就在于把这些背景留下来。
先把 ADR 讲清楚
ADR 是 Architecture Decision Record。
简单说,就是一条关键技术决策的记录。
它不是长篇设计文档的替代品。
它更像是一个轻量、稳定、长期可查的决策档案。
它要回答的核心问题通常是:
- 做了什么决定
- 在什么上下文里做的
- 为什么这样选
- 带来了什么后果
如果 RFC 更像“待评审提案”,那 ADR 更像“已经做出的关键决定的留档”。
为什么团队会反复争同样的问题
很大一个原因是,过去的决策只有结果,没有解释。
于是新成员加入、系统边界变化、业务压力变化时,团队很自然会问:
- 为什么不用另一个方案
- 为什么历史上要这样拆
- 为什么这里非要维持兼容
如果没有决策记录,这些问题每次都只能靠“老人回忆”。
这会带来两个问题:
- 讨论成本越来越高
- 决策质量越来越依赖少数人记忆
ADR 的作用,就是把这类知识从口头经验里解耦出来。
什么样的决定值得写 ADR
不是所有决定都值得写。
如果连一个组件名怎么取都写 ADR,团队很快会失去耐心。
更适合写 ADR 的通常是这些决定:
- 会影响长期架构走向
- 会绑定团队一段时间内的约束
- 回头看时很容易被重新质疑
- 会影响多个项目或多个团队
例如:
- 状态管理策略
- API 规范策略
- monorepo / 多仓方案
- SSR / CSR / RSC 的总体边界
- 日志与监控标准
- 前端构建链路线
ADR 解决的不是“写文档”问题,而是“保留决策记忆”问题
很多系统会经历:
- 原始作者离开
- 业务阶段变化
- 新技术生态变化
- 组织结构调整
这时最容易丢失的,不是代码本身。
而是“当初为什么这么做”。
代码能告诉你当前形状。
ADR 才能告诉你决策逻辑。
一条好 ADR 的核心结构
一个经典且实用的 ADR 通常至少包含:
标题
要具体到决策本身。
例如:
- “采用 TanStack Query 统一服务端状态管理”
- “前端应用统一迁移到 pnpm workspace”
不要写成:
- “技术优化”
- “系统升级”
状态
常见状态包括:
- proposed
- accepted
- deprecated
- superseded
状态的价值在于告诉后来的人:
这不是一条永远正确的真理,而是一条有生命周期的决定。
上下文
这是最值钱的部分之一。
你需要说明:
- 当时系统处于什么阶段
- 主要痛点是什么
- 有哪些关键约束
- 哪些现实条件影响了决定
决策
明确写出最终选择。
不要写成模棱两可的态度。
后果
写清楚这个决定带来的收益和代价。
这也是很多文档最容易偷懒的地方。
备选方案
说明为什么没选其他方案。
不是为了证明“我们考虑过”。
而是为了给未来重评估提供基线。
上下文为什么一定要写
因为离开上下文,很多决策都无法被公平评价。
比如今天看一个旧决定,可能会觉得:
- 为什么不用更现代的工具
- 为什么不直接一步到位
但如果当时的现实是:
- 团队对某技术完全不熟
- 发布窗口很紧
- 存量系统迁移成本极高
- 关键依赖不兼容
那同一个决定就会显得合理得多。
这就是为什么 ADR 不是给过去辩护。
而是保留当时判断所依赖的现实。
“后果”这一节为什么非常重要
很多人写 ADR 时,重点都在“为什么这么选”。
但从长期维护角度看,“选了之后意味着什么”同样重要。
后果里应该诚实写出:
- 会多出哪些维护成本
- 会失去哪些旧能力
- 团队需要补哪些新习惯
- 未来可能触发什么迁移点
如果只写收益,不写代价,ADR 的可信度会下降很多。
ADR 和 RFC、design doc 的关系
可以把它们看成不同层次的文档:
- RFC 更像正在讨论中的提案
- design doc 更偏设计与实施细节
- ADR 更偏最终关键决策留档
它们不是互斥关系。
一个成熟的团队经常是这样衔接:
- 先在 RFC 里讨论方向
- 在 design doc 里展开实现细节
- 用 ADR 把关键结论长期留存
技术决策为什么不能只靠口头共识
因为口头共识会随时间变形。
今天大家都清楚的事,三个月后、半年后、新人加入后,可能就不再清楚。
而且口头共识还有一个问题:
大家经常以为自己理解一致,实际理解并不一致。
书面决策至少能逼迫团队把模糊点说清楚。
一个成熟 ADR 的写法,应该尽量避免什么
1. 避免口号化
比如:
- “为了提升效率,采用新方案”
- “为了架构升级,进行统一改造”
这些都太空。
2. 避免把历史改写成必然
现实中的决定几乎都带有妥协。
不要把过去写成“当时只有这一条路”。
3. 避免只写结论,不写被放弃的东西
如果没有备选方案,后来的人很难判断这个决定是否还值得继续。
4. 避免决策状态长期不更新
如果一个决定已经被替代,却没有写明,ADR 就会开始误导人。
决策索引为什么值得做
当 ADR 累积多起来后,团队很容易再遇到一个问题:
文档有了,但很难找。
所以通常值得做一个索引:
- 编号
- 标题
- 状态
- 日期
- 被谁替代
这样后来的人就能更快理解系统演进脉络。
ADR 最常见的几个价值
避免重复争论
不是说以后永远不能再讨论。
而是至少先站在同一份历史事实之上讨论。
帮助 onboarding
新人可以更快理解系统为什么长成今天这样。
帮助复盘
当某个决定后来出现问题时,可以更清楚地回看当时 assumptions 是否失效。
降低单点记忆依赖
这点在人员流动后会非常明显。
一个典型例子:为什么只看结果会误判
假设团队现在在用 Webpack,后来的人很容易直接下结论:
- 为什么不早点换 Vite
但如果 ADR 里写清楚当时的背景:
- 项目是大型多页面存量系统
- 自定义 loader 与 plugin 很多
- 构建链路与发布平台深度耦合
- 当时关键依赖对新工具链支持并不稳定
那这个决定就不再只是“保守”。
它可能是一种在现实约束下的理性选择。
这也是 ADR 真正有用的地方。
技术决策为什么总要和组织现实一起看
很多决策不是纯技术题。
它们会同时受这些因素影响:
- 团队熟悉度
- 招聘市场
- 上线节奏
- 合规要求
- 跨团队协作方式
如果 ADR 只写技术优缺点,不写这些现实约束,后续读者仍然很难真正理解它。
中国互联网语境下,ADR 最容易遇到什么阻力
比较常见的是:
- 节奏快,觉得写文档太慢
- 决策经常在会议里快速拍板
- 业务变化快,担心写了也过时
这些担心都真实存在。
所以国内团队落 ADR,通常更适合轻量化:
- 文档短一些
- 聚焦关键决定
- 和实际项目节点绑定
不要一上来就做成厚重制度。
海外互联网语境里,为什么 ADR 更容易长期保留
很多海外团队异步协作更多,跨时区沟通更常见,也更强调书面决策和演进记录。
这会让 ADR 更容易成为长期协作接口。
这背后并不只是文化偏好。
它本质上是在回答:
当团队无法时时同步时,关键决策如何被准确传递。
这类主题为什么很适合做 senior 表达训练
因为它特别容易被讲成模板题。
比如:
- ADR 有标题、状态、上下文、决策、后果
这当然没错。
但真正更像 senior 的讲法会继续说明:
- 为什么上下文比结论更稀缺
- 为什么后果一定要诚实写
- ADR 和 RFC、design doc 怎么配合
- 为什么决策要有生命周期,而不是写完就封存
建议实践
实践 1:补写一条真实 ADR
练什么:
把口头记忆转成可追溯决策。
最小交付物:
一条完整 ADR。
验收标准:
- 有明确上下文
- 有清晰决策
- 有诚实后果
常见误区:
- 写成结果公告
实践 2:给一组 ADR 建索引
练什么:
把零散决策连成演进脉络。
最小交付物:
一页 ADR index。
验收标准:
- 能看见状态和替代关系
- 能快速定位关键决策
常见误区:
- 只有标题列表,没有状态和时间
实践 3:做一次“决策失效”复盘
练什么:
理解技术决策的生命周期。
最小交付物:
一篇针对旧 ADR 的 revisiting note。
验收标准:
- 能说明当时为什么成立
- 能说明现在为什么需要调整
常见误区:
- 只用今天的眼光否定过去