一、什么是ADR?
ADR(Architecture Decision Record,即架构决策记录)。研发团队里特指"记录一次重要架构决策的短文档"。
| 它是什么 | 它不是什么 |
|---|---|
| 重要架构决策的"决策书"(过去时) | 架构总览(那是"现在是什么") |
| 记录"为什么选 A 不选 B" | 会议纪要(那是过程) |
| 防止"重复讨论 + 推翻重做" | 产品决策(那是 PRD/Roadmap) |
| 写一次、状态变更、几乎不改内容 | 实施细节(那是 PR/Commit) |
# ADR-0001: 选 PostgreSQL 不用 MySQL ## 状态 Accepted ## 背景 - MySQL 5.7 已运行 5 年,数据量 3TB - 性能瓶颈 + EOL 合规压力 - 需要 JSONB、窗口函数、并行查询 ## 考虑的选项 1. MySQL 8.0(升级) 2. PostgreSQL 16(迁移) 3. TiDB(HTAP) ## 决策 选 PostgreSQL 16。 - 否决 MySQL 8:JSON 弱,无法解决 3TB JOIN - 否决 TiDB:运维成本高,收益不明确 ## 后果 - 正面:JSON 性能 +5x - 负面:迁移需 6 周 - 后续:6 个月后 review二、ADR的知识模板如何定义?
2.1 知识模板
| 分类 | 字段 | 类型 | 必填 | 备注 |
|---|---|---|---|---|
| 基础 | 编号 | string | ✓ | 全局唯一,如 0001 |
| 基础 | 标题 | string | ✓ | 动词开头,一句话 |
| 基础 | 状态 | enum | ✓ | Proposed/Accepted/Rejected/Deprecated/Superseded |
| 基础 | 创建日期 | date | ✓ | |
| 基础 | 决策日期 | date | × | 状态变 Accepted 时填 |
| 基础 | 作者 | @user | ✓ | 草稿作者 |
| 基础 | 决策参与者 | list[@user] | ✓ | 参与讨论的人 |
| 基础 | 关联服务/系统 | list[link] | × | |
| 核心 | 背景 | markdown | ✓ | 【核心】面临什么问题,为什么现在要决策,有什么约束 |
| 核心 | 选项 | list(≥2) | ✓ | 【核心】至少 2 个,通常 3-4 个,每个有名称 |
| 核心 | 决策 | markdown | ✓ | 【核心】选了什么,理由是什么 |
| 核心 | 后果 | markdown | ✓ | 【核心】正面 / 负面影响,后续工作 |
| 关联 | superseded by | ADR 编号 | × | 状态为 Superseded 时填 |
| 关联 | 关联代码路径 | list[link] | × | 实施该 ADR 的代码 |
| 关联 | 关联 Runbook | list[link] | × | 涉及运维的填 |
| 关联 | 关联事故档案 | list[link] | × | 事故触发的 ADR 填 |
案例如下:
# ADR-0001: 选 PostgreSQL 不用 MySQL ## 状态 Accepted ## 背景 - 当前订单数据存储在 MySQL 5.7,已运行 5 年 - 数据量增长到 3TB,MySQL 大表 JOIN 性能瓶颈 - 团队对 MySQL 5.7 EOL(2023-10)有合规压力 - 业务需要 JSONB、窗口函数、并行查询 ## 考虑的选项 1. **MySQL 8.0**:升级现有 MySQL,无数据迁移 2. **PostgreSQL 16**:迁移到 PG,功能强,生态成熟 3. **TiDB**:HTAP 方案,水平扩展 ## 决策 **选 PostgreSQL 16**。 理由:JSONB/窗口函数原生支持、并行查询、社区活跃度高于 MySQL 8、 团队已有 PG 经验(3 人)。 **否决 MySQL 8**:JSON 函数能力弱、并行查询有限、升级无法解决 3TB JOIN 瓶颈。 **否决 TiDB**:运维成本高、HTAP 收益对当前业务不明确。 ## 后果 - **正面**:JSON 字段查询性能 +5x,大表 JOIN +3x - **正面**:为后续架构演进(多租户、地理分布)提供更好基础 - **负面**:数据迁移需 6 周,需 0.5 FTE 专注 - **负面**:MySQL 时代的运维经验部分失效 - **后续**:运行 6 个月后 review,看是否需要回退 - **关联**: [迁移项目 #PRJ-2031]三、ADR的更新机制如何设计?
| 触发器 | 触发条件 | 动作 | 责任方 |
|---|---|---|---|
| PR-ingest | PR 实施 ADR 决策 | 自动关联 ADR 编号到 PR | LLM |
| Lint 反查 | 代码偏离 ADR | 告警 + 提醒更新状态 | 自动 |
| 手动状态变更 | 重大事件(事故/技术演进)触发 | 走 PR 改状态 | 决策参与者 |
| 定期 review | 每年/每季度复查 | 检查"过期的 ADR" | 架构师 |
3.1 关键设计点
| 设计点 | 具体要求 |
|---|---|
| 状态变更走 PR | 决策变更要可追溯,不是直接改 |
| Superseded 必须有链接 | superseded by: ADR-0015,可追溯链条 |
| 被 Superseded 的 ADR 不删除 | 历史背景常被翻账 |
| Lint 强制:Accepted 状态 ADR 跟代码一致 | 不一致就告警,推动状态变更 |
| 状态变更要 review | 至少 2 个决策参与者 approve |
| Accepted 后,正文几乎不修改 | 决策的"过去时"是稳定的 |
3.2 反模式
| 反模式 | 后果 |
|---|---|
| 直接修改 ADR 正文(改"决策") | 历史丢失,无法知道"当时怎么想的" |
| 状态不写,默认都是 Accepted | 看不到哪些在讨论、哪些被否决 |
| Superseded 写"已被新方案替代"不写编号 | 追溯链断裂 |
| 删除 Rejected 的 ADR | 未来重新讨论时,前人踩过的坑看不见 |
| 状态变更不通知关联方 | 实施 ADR 的人不知道决策已变 |
四、ADR的质量标准如何定义?
核心判断:ADR 的"质量"= 决策可追溯 + 跟代码一致 + 状态正确。不是"文档漂不漂亮"。
| 指标 | 定义 | 健康值 | 测量方式 |
|---|---|---|---|
| 覆盖率 | 重大决策有 ADR 的比例 | 100% | 抽查 |
| 一致性 | 代码与 ADR 描述一致 | ≥ 95% | Lint |
| 可追溯 | 决策变更链条完整无断裂 | 100% | 自动 |
| 被引用率 | ADR 被代码/Runbook/wiki 引用的比例 | ≥ 80% | 链接统计 |
| 状态正确性 | ADR 状态与现实一致 | ≥ 95% | 季度 review |
4.1 3个反向指标(出现就告警)
| 反向指标 | 告警触发 | 修复动作 |
|---|---|---|
| 裸奔决策 | 重大代码变更(选型/架构)无对应 ADR | 立即告警,要求补 ADR |
| 失信 ADR | 代码严重偏离 ADR 决策 | 立即告警,要求更新状态或同步代码 |
| 僵尸 ADR | 状态长期不更新,引用链断裂 | 季度 review 列出,要求清理 |
4.2 3个质量门槛
| 门槛 | 触发 | 动作 |
|---|---|---|
| 准入门槛(发布前) | 必填字段完整 + 至少 2 个选项 + 决策明确 + 至少 2 个决策参与者 | 缺一不准合并 |
| 持续门槛(运行中) | ADR 跟代码一致 + 状态正确 + 至少被 1 处引用 | 否则季度 review 标 stale |
| 淘汰门槛 | 永不删除,只 Superseded | 归档到superseded/目录 |