架构决策记录 是做什么的?
在编码会话期间捕获架构决策。与其让决策只存在于 Slack 线程、PR 评论或某人的记忆中,不如让本技能生成结构化的 ADR 文档,这些文档与代码共存。
何时激活
- 用户明确说“让我们记录这个决策”或“把这个做成 ADR”
- 用户在重要的备选方案之间做选择(框架、库、模式、数据库、API 设计)
- 用户说“我们决定...”或“我们做 X 而不是 Y 的原因是...”
- 用户问“为什么我们选择了 X?”(阅读现有 ADR)
- 在规划阶段,讨论架构权衡时
ADR 格式
使用 Michael Nygard 提出的轻量级 ADR 格式,针对 AI 辅助开发进行了调整:
# ADR-NNNN:[决策标题]
**日期**:YYYY-MM-DD
**状态**:proposed | accepted | deprecated | superseded by ADR-NNNN
**决策者**:[参与决策的人]
## 上下文
促成这个决策或变更的问题是?
[2-5 句话描述情况、约束条件以及各种影响因素]
## 决策
我们提议和/或正在进行的更改是什么?
[1-3 句话清晰陈述决策]
## 考虑的备选方案
### 备选方案 1:[名称]
- **优点**:[好处]
- **缺点**:[弊端]
- **不采纳的原因**:[该方案被拒绝的具体理由]
### 备选方案 2:[名称]
- **优点**:[好处]
- **缺点**:[弊端]
- **不采纳的原因**:[该方案被拒绝的具体理由]
## 后果
这个变更让什么事情变得更容易或更困难?
### 正面影响
- [好处 1]
- [好处 2]
### 负面影响
- [权衡 1]
- [权衡 2]
### 风险
- [风险及其缓解措施]
工作流程
捕获新的 ADR
当检测到决策时刻时:
- 初始化(仅首次) — 如果
docs/adr/不存在,请在创建目录之前询问用户确认,目录中应包含一个包含索引表头的README.md(见下方 ADR 索引格式),以及一个供手动使用的空白template.md。未经明确同意,请勿创建文件。 - 识别决策 — 提取正在做出的核心架构选择
- 收集上下文 — 是什么问题促成了这个决策?存在哪些约束?
- 记录备选方案 — 还考虑了哪些其他选项?为什么被拒绝?
- 陈述后果 — 存在哪些权衡?什么事情变得更容易/更困难?
- 分配编号 — 扫描
docs/adr/中的现有 ADR,然后递增编号 - 确认并写入 — 将 ADR 草稿呈现给用户审阅。只有在用户明确批准后,才写入
docs/adr/NNNN-decision-title.md。如果用户拒绝,则丢弃草稿,不写入任何文件。 - 更新索引 — 追加到
docs/adr/README.md
阅读现有 ADR
当用户问“为什么我们选择了 X?”时:
- 检查
docs/adr/是否存在——如果不存在,回复:“该项目中未找到 ADR。您想开始记录架构决策吗?” - 如果存在,扫描
docs/adr/README.md索引以查找相关条目 - 读取匹配的 ADR 文件,并呈现“上下文”和“决策”部分
- 如果未找到匹配项,回复:“未找到该决策对应的 ADR。您现在想记录一个吗?”
ADR 目录结构
docs/
└── adr/
├── README.md ← 所有 ADR 的索引
├── 0001-use-nextjs.md
├── 0002-postgres-over-mongo.md
├── 0003-rest-over-graphql.md
└── template.md ← 供手动使用的空白模板
ADR 索引格式
# 架构决策记录
| ADR | 标题 | 状态 | 日期 |
|-----|------|------|------|
| [0001](0001-use-nextjs.md) | 使用 Next.js 作为前端框架 | accepted | 2026-01-15 |
| [0002](0002-postgres-over-mongo.md) | 使用 PostgreSQL 而非 MongoDB 作为主数据存储 | accepted | 2026-01-20 |
| [0003](0003-rest-over-graphql.md) | 使用 REST API 而非 GraphQL | accepted | 2026-02-01 |
决策检测信号
观察对话中表明架构决策的以下模式:
显式信号
- “我们选择 X”
- “我们应该用 X 而不是 Y”
- “这个权衡是值得的,因为...”
- “把这个记录为 ADR”
隐式信号(建议记录 ADR —— 未经用户确认请勿自动创建)
- 比较两个框架或库并达成结论
- 做出数据库模式设计选择并给出理由
- 选择架构模式(单体 vs 微服务,REST vs GraphQL)
- 决定身份验证/授权策略
- 在评估备选方案后选择部署基础设施
如何写好 ADR
应该做
- 具体明确 — 写“使用 Prisma ORM”而不是“使用 ORM”
- 记录原因 — 理由比结果更重要
- 包含被拒绝的备选方案 — 未来的开发者需要知道考虑了哪些选项
- 诚实地陈述后果 — 每个决策都有权衡
- 保持简洁 — 一个 ADR 应在 2 分钟内读完
- 使用现在时 — 写“我们使用 X”而不是“我们将使用 X”
不应该做
- 记录琐碎决策 — 变量命名或格式选择不需要 ADR
- 写长篇大论 — 如果上下文部分超过 10 行,就是太长了
- 省略备选方案 — “我们只是选了它”不是有效的理由
- 不注明就补录 — 如果记录过去的决策,请注明原始日期
- 让 ADR 过时 — 被取代的决策应引用其替代者
ADR 生命周期
proposed → accepted → [deprecated | superseded by ADR-NNNN]
- proposed:决策正在讨论中,尚未确定
- accepted:决策已生效并正在被遵循
- deprecated:决策已不再相关(例如,功能已移除)
- superseded:新的 ADR 取代了此 ADR(始终链接取代者)
值得记录的决策类别
| 类别 | 示例 |
|---|---|
| 技术选择 | 框架、语言、数据库、云提供商 |
| 架构模式 | 单体 vs 微服务、事件驱动、CQRS |
| API 设计 | REST vs GraphQL、版本控制策略、身份验证机制 |
| 数据建模 | 模式设计、规范化决策、缓存策略 |
| 基础设施 | 部署模型、CI/CD 流水线、监控栈 |
| 安全 | 身份验证策略、加密方法、密钥管理 |
| 测试 | 测试框架、覆盖率目标、E2E 与集成测试的平衡 |
| 流程 | 分支策略、审查流程、发布节奏 |
与其他技能的集成
- 计划者代理:当计划者提出架构变更时,建议创建 ADR
- 代码审查者代理:标记那些引入了架构变更但没有相应 ADR 的 PR