对重要的技术和架构决策进行结构化记录,确保决策有据可查、有理可循,避免"为什么当初这样设计?"的困惑,支持未来的决策追溯和变更。
- 选择技术栈(语言/框架/数据库/云服务)
- 确定系统架构模式(单体/微服务/Serverless)
- 选择第三方服务或库(有 2+ 候选方案时)
- 做出影响多个模块的设计决策
- 推翻或修改之前的架构决策
- 任何"6 个月后可能忘记为什么这样做"的决定
触发条件(满足任一即需要):
- 决策影响 2 个以上模块/服务
- 决策难以逆转或逆转成本高
- 存在 2 个以上合理候选方案
- 决策涉及性能/安全/可扩展性权衡
- 未来团队成员需要理解决策背景
不需要 ADR 的情况:
- 简单的实现细节(变量命名、文件组织)
- 遵循已有规范的常规操作
- 可轻松撤销的小改动
回答以下问题:
- 驱动因素: 什么促使我们需要做这个决策?
- 约束条件: 有哪些不可改变的约束?(时间/预算/技术/团队能力)
- 利益相关者: 谁关心这个决策?
- 时间压力: 什么时候必须决定?
对每个候选方案评估:
| 维度 | 权重 | 方案 A | 方案 B | 方案 C |
|---|---|---|---|---|
| 性能满足度 | /5 | /5 | /5 | |
| 可维护性 | /5 | /5 | /5 | |
| 学习成本 | /5 | /5 | /5 | |
| 社区/生态 | /5 | /5 | /5 | |
| 长期成本 | /5 | /5 | /5 | |
| 团队匹配度 | /5 | /5 | /5 | |
| 可扩展性 | /5 | /5 | /5 |
使用标准 ADR 格式(见模板):
# ADR-XXX: [决策标题]
## 状态
Proposed / Accepted / Deprecated / Superseded by ADR-YYY
## 上下文
[什么问题/需求驱动了这个决策]
## 决策
[我们决定采用什么方案]
## 理由
[为什么选择这个方案,关键权衡是什么]
## 后果
### 正面
- ...
### 负面
- ...
### 风险
- ...
## 替代方案
[考虑过但未选择的方案及原因]当需要推翻旧决策时:
- 创建新 ADR,状态标注
Supersedes ADR-XXX - 将旧 ADR 状态改为
Superseded by ADR-YYY - 在新 ADR 中说明:
- 什么变了(环境/需求/认知)
- 为什么旧方案不再适用
- 迁移计划和成本
- 永远不要删除旧 ADR,保留历史
- 决策上下文已清晰描述
- 至少评估了 2 个候选方案
- 评估维度覆盖了关键因素
- 决策理由明确(不是"感觉好")
- 正面和负面后果都已列出
- 风险已识别并有缓解方案
- ADR 已编号并存入 docs/adr/
- 相关代码/配置已按决策实施
- 团队成员已知晓决策
| 输出物 | 格式 | 存放位置 |
|---|---|---|
| ADR 文档 | Markdown | docs/adr/ADR-XXX-title.md |
| 方案对比表 | 表格 | ADR 文档内 |
| 决策索引 | 列表 | docs/adr/README.md |
- 格式:
ADR-001,ADR-002, ...(三位数递增) - 文件名:
ADR-001-choose-database.md - 状态流转:
Proposed → Accepted → (Deprecated | Superseded)
| 误区 | 正确做法 |
|---|---|
| 决策不记录,全靠记忆 | 写下来,未来的你会感谢现在的你 |
| 只记录结论不记录理由 | 理由比结论更重要(环境变了需要重新评估) |
| 追求"完美决策" | 在信息有限时做"足够好"的决策,记录假设 |
| 删除过时决策 | 标记为 Superseded,保留历史 |
| 所有决定都写 ADR | 只记录重要的、难逆转的决策 |
| 写完就锁死不变 | ADR 是活的,环境变了可以重新决策 |