架构决策记录

architecture-decision-records
分类通用
作者Agentic Awesome Skills 社区
许可MIT
评分4.50/5
使用16.0K

架构决策记录 (Architecture Decision Records)

创建、维护和管理架构决策记录 (ADR) 的全面模式,用于捕捉重大技术决策背后的上下文和原由。

适用场景

  • 做出重大架构决策时
  • 记录技术选型时
  • 记录设计权衡 (Trade-offs) 时
  • 新团队成员入职引导时
  • 回溯历史决策时
  • 建立决策流程时

不适用场景

  • 仅需记录细小的实现细节时
  • 变更仅为微小补丁或常规维护时
  • 没有需要捕捉的架构决策时

操作指南

1. 捕捉决策上下文、约束条件和驱动因素。
2. 记录考虑过的方案及其权衡。
3. 记录最终决策、原由及其后果。
4. 关联相关的 ADR,并随时间更新状态。

核心概念

1. 什么是 ADR?

架构决策记录 (ADR) 包含:

  • 上下文 (Context):为什么需要做出这个决策

  • 决策 (Decision):我们决定了什么

  • 后果 (Consequences):结果会产生什么影响

2. 何时编写 ADR

| 编写 ADR | 跳过 ADR |
|-----------|----------|
| 采用新框架 | 次要版本升级 |
| 数据库技术选型 | Bug 修复 |
| API 设计模式 | 实现细节 |
| 安全架构 | 常规维护 |
| 集成模式 | 配置变更 |

3. ADR 生命周期

code
Proposed (提议) → Accepted (通过) → Deprecated (弃用) → Superseded (被取代)
              ↓
           Rejected (拒绝)

模板

模板 1:标准 ADR (MADR 格式)

markdown
# ADR-0001: 使用 PostgreSQL 作为主数据库

状态

Accepted (通过)

上下文

我们需要为新的电子商务平台选择一个主数据库。系统将处理:

  • 约 10,000 个并发用户

  • 具有层级分类的复杂产品目录

  • 订单和支付的事务处理

  • 产品的全文搜索

  • 门店定位的地理空间查询

团队拥有 MySQL、PostgreSQL 和 MongoDB 的经验。财务交易需要满足 ACID 特性。

决策驱动因素

  • 必须满足 ACID 特性 以处理支付
  • 必须支持复杂查询 用于报表
  • 应支持全文搜索 以降低基础设施复杂度
  • 应具有良好的 JSON 支持 以应对灵活的产品属性
  • 团队熟悉度 可缩短上手时间

考虑的方案

方案 1: PostgreSQL

  • 优点: 符合 ACID 特性,优秀的 JSON 支持 (JSONB),内置全文搜索,PostGIS 支持地理空间,团队有经验
  • 缺点: 复制配置比 MySQL 略复杂

方案 2: MySQL

  • 优点: 团队非常熟悉,复制简单,社区庞大
  • 缺点: JSON 支持较弱,无内置全文搜索(需依赖 Elasticsearch),无原生地理空间支持(需扩展)

方案 3: MongoDB

  • 优点: 模式灵活,原生 JSON,水平扩展
  • 缺点: (决策时) 多文档事务缺乏 ACID 支持,团队经验有限,需要严格的模式设计纪律

决策

我们将使用 PostgreSQL 15 作为主数据库。

原由

PostgreSQL 在以下方面达到了最佳平衡:
1. ACID 兼容性...


1. ACID 合规性:对于电子商务交易至关重要
2. 内置功能(全文检索、JSONB、PostGIS):降低了基础设施的复杂度
3. 团队熟悉度:对 SQL 数据库的熟悉程度降低了学习曲线
4. 成熟的生态系统:拥有优秀的工具链和社区支持

虽然复制(replication)略显复杂,但相比于减少额外服务(无需单独部署 Elasticsearch)而言,这种复杂度是可以接受的。

后果

正面影响

  • 单一数据库即可处理交易、搜索和地理空间查询
  • 降低运维复杂度(需要管理的服务更少)
  • 为财务数据提供强一致性保证
  • 团队可以利用现有的 SQL 专业知识

负面影响

  • 需要学习 PostgreSQL 的特定功能(JSONB、全文检索语法)
  • 垂直扩展的限制可能导致需要更早地部署只读副本
  • 部分团队成员需要进行 PostgreSQL 专项培训

风险

  • 全文检索的扩展性可能不如专业的搜索引擎
  • 缓解方案:在设计时预留未来必要时添加 Elasticsearch 的可能性

实现注意事项

  • 使用 JSONB 处理灵活的产品属性
  • 使用 PgBouncer 实现连接池
  • 为只读副本配置流复制(streaming replication)
  • 使用 pg_trgm 扩展实现模糊搜索

相关决策

  • ADR-0002:缓存策略 (Redis) —— 与数据库选择互补
  • ADR-0005:搜索架构 —— 如果需要 Elasticsearch,可能会取代本决策

参考资料

  • 内部文档:/docs/benchmarks/database-comparison.md 中的性能基准测试
code
### 模板 2:轻量级 ADR
markdown

ADR-0012: 前端开发采用 TypeScript

状态: 已通过
日期: 2024-01-15
决策者: @alice, @bob, @charlie

背景

我们的 React 代码库已增长至 50 多个组件,与 prop 类型不匹配和 undefined 相关的 Bug 报告日益增多。而 PropTypes 仅能提供运行时检查。

决策

所有新前端代码采用 TypeScript。现有代码逐步迁移。

后果

优点: 在编译时捕获类型错误,更好的 IDE 支持,代码自文档化。

缺点: 团队有学习曲线,初期开发速度下降,构建复杂度增加。

缓解措施: 组织 TypeScript 培训,通过设置 allowJs: true 允许渐进式采用。

code
### 模板 3:Y-Statement 格式
markdown

ADR-0015: API 网关选型

构建微服务架构 的背景下,
面对 需要集中式 API 管理、身份验证和限流 的需求,
我们决定选择 Kong Gateway
而非 AWS API Gateway 和自定义 Nginx 方案
旨在实现 供应商无关性、插件可扩展性以及团队对 Lua 的熟悉度
并接受 我们需要自行管理 Kong 基础设施 这一事实。

code
### 模板 4:弃用 ADR
markdown

ADR-0020: 弃用 MongoDB 改用 PostgreSQL

状态

已通过(取代 ADR-0003)

背景

ADR-0003 (2021) 因模式(schema)灵活性需求而选择 MongoDB 存储用户配置文件。此后:

  • MongoDB 的多文档事务在我们的用例中仍然存在问题

  • 我们的模式已趋于稳定,极少变更

  • 我们在其他服务中积累了 PostgreSQL 的专业经验

  • 同时维护两种数据库增加了运维负担

决策

弃用 MongoDB 并将用户配置文件迁移至 PostgreSQL。

迁移计划

1. 第一阶段(我们...

code
1. 第一阶段(第 1-2 周):创建 PostgreSQL 模式,启用双写
2. 第二阶段(第 3-4 周):回填历史数据,验证一致性
3. 第三阶段(第 5 周):将读取切换至 PostgreSQL,进行监控
4. 第四阶段(第 6 周):移除 MongoDB 写入,停用旧库

影响

正面影响

  • 统一数据库技术,降低运维复杂度
  • 用户数据支持 ACID 事务
  • 团队可集中提升 PostgreSQL 专业能力

负面影响

  • 迁移工作量(约 4 周)
  • 迁移过程中存在数据问题的风险
  • 失去部分模式(Schema)灵活性

经验教训

基于 ADR-0003 的经验总结:

  • 过高估计了模式灵活性的收益

  • 低估了维护多个数据库的运维成本

  • 在技术决策时应考虑长期维护成本

模板 5:征求意见稿 (RFC) 风格

markdown
# RFC-0025:在订单管理中采用事件溯源 (Event Sourcing)

摘要

建议在订单管理领域采用事件溯源模式,以提高可审计性,支持时间点查询并赋能业务分析。

动机

当前面临的挑战:
1. 审计需求需要完整的订单历史记录
2. 无法查询“订单在时间点 X 的状态是什么?”
3. 分析团队需要事件流来构建实时仪表盘
4. 客服人员手动重建订单状态,效率低下

详细设计

事件存储 (Event Store)

OrderCreated { orderId, customerId, items[], timestamp } OrderItemAdded { orderId, item, timestamp } OrderItemRemoved { orderId, itemId, timestamp } PaymentReceived { orderId, amount, paymentId, timestamp } OrderShipped { orderId, trackingNumber, timestamp }
code
### 投影 (Projections)
  • CurrentOrderState:用于查询的物化视图
  • OrderHistory:用于审计的完整时间线
  • DailyOrderMetrics:分析聚合数据

技术选型

  • 事件存储:EventStoreDB(专用数据库,支持投影)
  • 考虑过的替代方案:Kafka + 自定义投影服务

缺点

  • 团队学习曲线较陡
  • 相比 CRUD 复杂度增加
  • 需要谨慎设计事件(存储后不可更改)
  • 存储量持续增长(事件永不删除)

替代方案

1. 审计表:更简单,但不支持时间点查询
2. 现有数据库的 CDC:实现复杂,且未改变数据模型
3. 混合模式:仅对订单状态变更使用事件溯源

待解决问题

  • [ ] 事件模式的版本管理策略
  • [ ] 事件的保留策略
  • [ ] 为了性能而设置的快照频率

实施计划

1. 针对单一订单类型进行原型开发(2 周)
2. 开展事件溯源团队培训(1 周)
3. 全面实施与迁移(4 周)
4. 持续监控与优化(长期)

参考资料

ADR 管理

目录结构

code
docs/
├── adr/
│   ├── README.md           # 索引与指南
│   ├── template.md         # 团队 ADR 模板
│   ├── 0001-use-postgresql.md
│   ├── 0002-caching-strategy.md
│   ├── 0003-mongodb-user-profiles.md  # [已弃用]
│   └── 0020-deprecate-mongodb.md      # 取代 0003

ADR 索引 (README.md)

markdown
# 架构决策记录 (ADR)

本目录包含 [项目名称] 的架构决策记录 (ADR)。

索引

| ADR | 标题 | 状态 | 日期 |
|-----|-------|--------|------|
| 0001 | 使用 PostgreSQL 作为主数据库 | 已接受 | 2024-01-10 |
| 0002 | 使用 Redis 的缓存策略 | 已接受 |


epted | 2024-01-12 |
| 0003 | MongoDB for User Profiles | Deprecated | 2023-06-15 |
| 0020 | Deprecate MongoDB | Accepted | 2024-01-15 |

创建新的 ADR

1. 将 template.md 复制为 NNNN-title-with-dashes.md
2. 填写模板
3. 提交 PR 进行评审
4. 批准后更新此索引

ADR 状态

  • Proposed (提议):讨论中
  • Accepted (通过):已决策,正在实施
  • Deprecated (弃用):不再适用
  • Superseded (被取代):被另一个 ADR 取代
  • Rejected (拒绝):经过考虑但未采用
code
### 自动化 (adr-tools)
bash

安装 adr-tools

brew install adr-tools

初始化 ADR 目录

adr init docs/adr

创建新 ADR

adr new "Use PostgreSQL as Primary Database"

取代某个 ADR

adr new -s 3 "Deprecate MongoDB in Favor of PostgreSQL"

生成目录

adr generate toc > docs/adr/README.md

关联相关 ADR

adr link 2 "Complements" 1 "Is complemented by"
code
## 评审流程
markdown

ADR 评审清单

提交前

  • [ ] 上下文清晰地解释了问题
  • [ ] 考虑了所有可行方案
  • [ ] 优缺点分析客观平衡
  • [ ] 记录了后果(正面和负面)
  • [ ] 关联了相关的 ADR

评审期间

  • [ ] 至少 2 名资深工程师评审
  • [ ] 咨询了受影响的团队
  • [ ] 考虑了安全性影响
  • [ ] 记录了成本影响
  • [ ] 评估了可逆性

通过后

  • [ ] 更新 ADR 索引
  • [ ] 通知团队
  • [ ] 创建实施任务单 (Tickets)
  • [ ] 更新相关文档
```

最佳实践

建议 (Do's)

  • 尽早编写 ADR —— 在实施开始之前
  • 保持简洁 —— 最多 1-2 页
  • 诚实面对权衡 —— 包含真实的缺点
  • 关联相关决策 —— 构建决策图谱
  • 更新状态 —— 被取代时及时标记为弃用

禁忌 (Don'ts)

  • 不要修改已通过的 ADR —— 编写新的 ADR 来取代它
  • 不要跳过上下文 —— 后续阅读者需要背景信息
  • 不要隐藏失败 —— 被拒绝的决策同样有价值
  • 不要含糊其辞 —— 具体的决策,具体的后果
  • 不要忘记实施 —— 没有行动的 ADR 是浪费

资源

局限性

  • 仅在任务明确符合上述范围时使用此技能。
  • 不要将输出结果视为环境特定验证、测试或专家评审的替代方案。
  • 如果缺少必要的输入、权限、安全边界或成功标准,请停止并请求澄清。