name: 架构决策记录 description: 撰写和维护架构决策记录(ADRs),遵循技术决策文档的最佳实践。适用于记录重大技术决策、审查过去的架构选择或建立决策流程时使用。
架构决策记录
创建、维护和管理架构决策记录(ADRs)的综合模式,以捕捉重大技术决策的背景和原理。
何时使用此技能
- 做出重大架构决策
- 记录技术选择
- 记录设计权衡
- 新团队成员入职
- 审查历史决策
- 建立决策流程
核心概念
1. 什么是ADR?
一个架构决策记录捕捉:
- 背景:为什么需要做出决策
- 决策:我们决定了什么
- 后果:结果是什么
2. 何时撰写ADR
| 撰写ADR | 跳过ADR |
|---|---|
| 新框架采用 | 次要版本升级 |
| 数据库技术选择 | 错误修复 |
| API设计模式 | 实现细节 |
| 安全架构 | 常规维护 |
| 集成模式 | 配置更改 |
3. ADR生命周期
提议 → 接受 → 废弃 → 替代
↓
拒绝
模板
模板1:标准ADR(MADR格式)
# ADR-0001:使用PostgreSQL作为主数据库
## 状态
已接受
## 背景
我们需要为新电子商务平台选择主数据库。系统将处理:
- 约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合规性**对电子商务交易至关重要
2. **内置能力**(全文搜索,JSONB,PostGIS)减少基础设施复杂性
3. **团队熟悉度**与SQL数据库减少学习曲线
4. **成熟生态系统**与优秀的工具和社区支持
复制略复杂,但被减少额外服务(无需单独的Elasticsearch)所抵消。
## 后果
### 正面
- 单个数据库处理交易、搜索和地理空间查询
- 减少操作复杂性(管理更少服务)
- 为金融数据提供强一致性保证
- 团队可以利用现有SQL专业知识
### 负面
- 需要学习PostgreSQL特定功能(JSONB,全文搜索语法)
- 垂直扩展限制可能需要更早的读副本
- 一些团队成员需要PostgreSQL特定培训
### 风险
- 全文搜索可能不如专用搜索引擎扩展好
- 缓解:设计为可能需要添加Elasticsearch
## 实现注释
- 使用JSONB用于灵活的产品属性
- 使用PgBouncer实现连接池
- 设置流复制用于读副本
- 使用pg_trgm扩展进行模糊搜索
## 相关决策
- ADR-0002:缓存策略(Redis)—补充数据库选择
- ADR-0005:搜索架构—如需要Elasticsearch可能替代
## 参考资料
- [PostgreSQL JSON文档](https://www.postgresql.org/docs/current/datatype-json.html)
- [PostgreSQL全文搜索](https://www.postgresql.org/docs/current/textsearch.html)
- 内部:性能基准在`/docs/benchmarks/database-comparison.md`
模板2:轻量级ADR
# ADR-0012:采用TypeScript进行前端开发
**状态**:已接受
**日期**:2024-01-15
**决策者**:@alice, @bob, @charlie
## 背景
我们的React代码库已增长到50多个组件,与属性类型不匹配和未定义错误相关的错误报告增加。PropTypes仅提供运行时检查。
## 决策
对所有新前端代码采用TypeScript。逐步迁移现有代码。
## 后果
**好**:在编译时捕获类型错误,更好的IDE支持,自文档化代码。
**坏**:团队学习曲线,初始速度下降,构建复杂性增加。
**缓解**:TypeScript培训会议,允许逐步采用,设置`allowJs: true`。
模板3:Y-Statement格式
# ADR-0015:API网关选择
在**构建微服务架构**的背景下,
面临**需要集中API管理、认证和速率限制**,
我们决定选择**Kong Gateway**
而非**AWS API Gateway和自定义Nginx解决方案**,
以实现**供应商独立性、插件可扩展性和团队对Lua的熟悉度**,
接受**我们需要自己管理Kong基础设施**。
模板4:废弃ADR
# ADR-0020:废弃MongoDB,转用PostgreSQL
## 状态
已接受(替代ADR-0003)
## 背景
ADR-0003(2021年)因模式灵活性需求选择MongoDB用于用户配置文件存储。自那时起:
- MongoDB的多文档交易对我们的用例仍有问题
- 我们的模式已稳定且很少更改
- 我们现在从其他服务获得PostgreSQL专业知识
- 维护两个数据库增加操作负担
## 决策
废弃MongoDB,将用户配置文件迁移到PostgreSQL。
## 迁移计划
1. **阶段1**(第1-2周):创建PostgreSQL模式,启用双写
2. **阶段2**(第3-4周):回填历史数据,验证一致性
3. **阶段3**(第5周):切换到PostgreSQL读取,监控
4. **阶段4**(第6周):移除MongoDB写入,退役
## 后果
### 正面
- 单一数据库技术减少操作复杂性
- 为用户数据提供ACID交易
- 团队可以专注于PostgreSQL专业知识
### 负面
- 迁移努力(约4周)
- 迁移期间数据问题风险
- 失去一些模式灵活性
## 经验教训
从ADR-0003经验记录:
- 模式灵活性益处被高估
- 多个数据库的操作成本被低估
- 考虑长期维护在技术决策中
模板5:请求评论(RFC)风格
# RFC-0025:采用事件溯源进行订单管理
## 总结
提议为订单管理领域采用事件溯源模式,以提高可审计性、启用时间查询并支持业务分析。
## 动机
当前挑战:
1. 审计需求需要完整的订单历史
2. “时间X时的订单状态?”查询不可能
3. 分析团队需要事件流进行实时仪表板
4. 客户支持的订单状态重建是手动的
## 详细设计
### 事件存储
OrderCreated { orderId, customerId, items[], timestamp } OrderItemAdded { orderId, item, timestamp } OrderItemRemoved { orderId, itemId, timestamp } PaymentReceived { orderId, amount, paymentId, timestamp } OrderShipped { orderId, trackingNumber, timestamp }
### 投影
- **当前订单状态**:用于查询的物化视图
- **订单历史**:完整的审计时间线
- **每日订单指标**:分析聚合
### 技术
- 事件存储:EventStoreDB(专门构建,处理投影)
- 考虑替代:Kafka + 自定义投影服务
## 缺点
- 团队学习曲线
- 比CRUD增加复杂性
- 需要仔细设计事件(存储后不可变)
- 存储增长(事件从不删除)
## 替代方案
1. **审计表**:更简单但不启用时间查询
2. **从现有数据库CDC**:复杂,不改变数据模型
3. **混合**:仅事件溯源用于订单状态更改
## 未解决问题
- [ ] 事件模式版本控制策略
- [ ] 事件保留策略
- [ ] 性能的快照频率
## 实现计划
1. 原型与单一订单类型(2周)
2. 团队培训事件溯源(1周)
3. 完全实现和迁移(4周)
4. 监控和优化(持续)
## 参考资料
- [Martin Fowler的事件溯源](https://martinfowler.com/eaaDev/EventSourcing.html)
- [EventStoreDB文档](https://www.eventstore.com/docs)
ADR管理
目录结构
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)
# 架构决策记录
此目录包含[项目名称]的架构决策记录(ADRs)。
## 索引
| ADR | 标题 | 状态 | 日期 |
| ------------------------------------- | -------------------------------- | ---------- | ---------- |
| [0001](0001-use-postgresql.md) | 使用PostgreSQL作为主数据库 | 已接受 | 2024-01-10 |
| [0002](0002-caching-strategy.md) | 缓存策略与Redis | 已接受 | 2024-01-12 |
| [0003](0003-mongodb-user-profiles.md) | MongoDB用于用户配置文件 | 已废弃 | 2023-06-15 |
| [0020](0020-deprecate-mongodb.md) | 废弃MongoDB | 已接受 | 2024-01-15 |
## 创建新ADR
1. 复制`template.md`到`NNNN-title-with-dashes.md`
2. 填充模板
3. 提交PR供审查
4. 批准后更新此索引
## ADR状态
- **提议中**:讨论中
- **已接受**:决策已定,实施中
- **已废弃**:不再相关
- **已替代**:被另一个ADR替换
- **已拒绝**:考虑过但未采纳
自动化(adr-tools)
# 安装adr-tools
brew install adr-tools
# 初始化ADR目录
adr init docs/adr
# 创建新ADR
adr new "使用PostgreSQL作为主数据库"
# 替代ADR
adr new -s 3 "废弃MongoDB,转用PostgreSQL"
# 生成目录
adr generate toc > docs/adr/README.md
# 链接相关ADRs
adr link 2 "补充" 1 "被补充"
审查流程
## ADR审查清单
### 提交前
- [ ] 背景清晰解释问题
- [ ] 所有可行选项已考虑
- [ ] 优点/缺点平衡且诚实
- [ ] 后果(正面和负面)已记录
- [ ] 相关ADRs已链接
### 审查中
- [ ] 至少2名高级工程师审查
- [ ] 受影响团队已咨询
- [ ] 安全影响已考虑
- [ ] 成本影响已记录
- [ ] 可逆性已评估
### 接受后
- [ ] ADR索引已更新
- [ ] 团队已通知
- [ ] 实施工单已创建
- [ ] 相关文档已更新
最佳实践
应该做的
- 及早撰写ADRs — 实施开始前
- 保持简短 — 最多1-2页
- 诚实地描述权衡 — 包括真实缺点
- 链接相关决策 — 构建决策图
- 更新状态 — 替代时废弃
不应该做的
- 不要更改已接受的ADRs — 撰写新的替代
- 不要跳过背景 — 未来读者需要背景
- 不要隐藏失败 — 被拒绝的决策有价值
- 不要模糊 — 具体决策,具体后果
- 不要忘记实施 — 无行动的ADR是浪费