architecture-decision-record
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseArchitecture Decision Records
架构决策记录(ADR)
ADR Template
ADR 模板
Every ADR follows this structure:
markdown
undefined每一份ADR均遵循以下结构:
markdown
undefinedADR-NNN: Title of the Decision
ADR-NNN: 决策标题
Status
状态
[Proposed | Accepted | Deprecated | Superseded by ADR-NNN]
[提议中 | 已通过 | 已弃用 | 被ADR-NNN取代]
Context
背景
What is the issue that we are seeing that motivates this decision or change?
Describe the forces at play (technical, political, social, project-related).
Include any constraints, requirements, or assumptions.
当前面临的问题是什么,促使我们做出该决策或变更?
描述相关影响因素(技术、政策、团队、项目相关)。
包含所有约束条件、需求或假设前提。
Decision
决策内容
What is the change that we are proposing and/or doing?
State the decision in full sentences using active voice.
Be specific about what will be done.
我们提议或即将执行的变更是什么?
使用主动语态的完整句子陈述决策。
明确具体执行方案。
Consequences
决策后果
What becomes easier or more difficult because of this decision?
List both positive and negative consequences.
Include any follow-up actions required.
undefined该决策会让哪些事情变得更简单或更复杂?
列出正面和负面后果。
包含所需的后续行动。
undefinedWhen to Write an ADR
何时编写ADR
Write an ADR for any decision that meets one or more of these criteria:
| Trigger | Example |
|---|---|
| Adopting or replacing a technology | Switching from REST to GraphQL |
| Changing an architectural pattern | Moving from monolith to microservices |
| Infrastructure decisions | Choosing a cloud provider or database |
| API design choices | Choosing pagination strategy |
| Authentication/authorization strategy | Adopting OAuth2 with PKCE |
| Data model decisions | Choosing between SQL and NoSQL |
| Cross-cutting concerns | Standardizing error handling or logging |
| Process or convention changes | Adopting conventional commits |
| Build/deployment decisions | Choosing CI/CD platform |
| Decisions that are hard to reverse | Anything with significant migration cost |
当决策满足以下任一标准时,需编写ADR:
| 触发场景 | 示例 |
|---|---|
| 采用或替换某项技术 | 从REST切换至GraphQL |
| 变更架构模式 | 从单体架构迁移至微服务架构 |
| 基础设施决策 | 选择云服务商或数据库 |
| API设计选择 | 选择分页策略 |
| 认证/授权策略 | 采用OAuth2 with PKCE |
| 数据模型决策 | 在SQL与NoSQL之间选择 |
| 横切关注点决策 | 统一错误处理或日志规范 |
| 流程或约定变更 | 采用规范化提交格式 |
| 构建/部署决策 | 选择CI/CD平台 |
| 难以回滚的决策 | 任何具有显著迁移成本的决策 |
Do NOT Write an ADR For
无需编写ADR的场景
- Routine implementation choices with low impact
- Temporary decisions that will be revisited within days
- Individual code-level decisions that are covered by style guides
- Choices that are trivially reversible
- 低影响的常规实现选择
- 数日内会重新评估的临时决策
- 已被代码风格指南覆盖的单个代码级决策
- 可轻易回滚的选择
Status Lifecycle
状态生命周期
Proposed --> Accepted --> Deprecated
--> Superseded by ADR-NNN| Status | Meaning |
|---|---|
| Proposed | Under discussion, not yet decided |
| Accepted | Decision has been agreed upon and should be followed |
| Deprecated | No longer relevant due to changes in the project or environment |
| Superseded by ADR-NNN | Replaced by a newer decision; link to the replacement |
提议中 --> 已通过 --> 已弃用
--> 被ADR-NNN取代| 状态 | 含义 |
|---|---|
| 提议中 | 处于讨论阶段,尚未做出最终决策 |
| 已通过 | 决策已达成共识,需遵照执行 |
| 已弃用 | 因项目或环境变更,已不再具有相关性 |
| 被ADR-NNN取代 | 被较新的决策替代;需链接至替代决策的ADR |
Rules
规则
- An ADR is immutable once accepted; never edit the original text
- To change a decision, write a new ADR that supersedes the old one
- Update the old ADR's status to "Superseded by ADR-NNN"
- Keep deprecated and superseded ADRs in the repository for history
- ADR一旦通过即不可修改;切勿编辑原始文本
- 若需变更决策,需编写新的ADR取代旧版本
- 将旧ADR的状态更新为“被ADR-NNN取代”
- 已弃用或被取代的ADR需保留在代码库中,以供追溯历史
Evaluating Alternatives
备选方案评估
Use a structured comparison for every ADR with multiple options.
对于存在多个选项的ADR,需采用结构化方式进行比较。
Pros/Cons Matrix
优缺点矩阵
markdown
undefinedmarkdown
undefinedOption A: PostgreSQL
选项A: PostgreSQL
Pros:
- Mature, well-understood RDBMS
- Strong ACID guarantees
- Excellent tooling ecosystem
Cons:
- Horizontal scaling requires additional tooling
- Schema migrations needed for changes
优点:
- 成熟、广为人知的关系型数据库管理系统(RDBMS)
- 强大的ACID保证
- 完善的工具生态系统
缺点:
- 水平扩展需要额外工具支持
- 数据模型变更需执行 schema 迁移
undefinedOption B: MongoDB
加权标准矩阵
Pros:
- Flexible schema for evolving data models
- Built-in horizontal scaling (sharding)
Cons:
- Weaker transaction support (multi-document)
- Team has limited operational experience
undefined对于复杂决策,可针对加权标准为每个选项评分:
markdown
| 评估标准 | 权重 | PostgreSQL | MongoDB | DynamoDB |
|-----------------------|--------|------------|---------|----------|
| 团队技术经验 | 5 | 5 | 2 | 2 |
| 扩展性 | 4 | 3 | 4 | 5 |
| 查询灵活性 | 4 | 5 | 3 | 2 |
| 运维成本 | 3 | 3 | 3 | 4 |
| ACID合规性 | 3 | 5 | 3 | 3 |
| **加权总分** | | **80** | **57** | **60** |计算方式:每个选项的(权重 × 评分)之和。
Weighted Criteria Matrix
文件命名与存储
—
约定规范
For complex decisions, score each option against weighted criteria:
markdown
| Criteria | Weight | PostgreSQL | MongoDB | DynamoDB |
|-----------------------|--------|------------|---------|----------|
| Team expertise | 5 | 5 | 2 | 2 |
| Scalability | 4 | 3 | 4 | 5 |
| Query flexibility | 4 | 5 | 3 | 2 |
| Operational cost | 3 | 3 | 3 | 4 |
| ACID compliance | 3 | 5 | 3 | 3 |
| **Weighted Total** | | **80** | **57** | **60** |Calculation: sum of (weight x score) for each option.
| 规范类型 | 规则 | 示例 |
|---|---|---|
| 编号规则 | 四位数字前置补零的连续编号 | |
| 文件名称 | | |
| 存储位置 | 代码库根目录下的 | |
| 标题格式 | ADR-NNN: 祈使句格式 | ADR-003: 使用PostgreSQL作为存储引擎 |
File Naming and Storage
目录结构
Conventions
—
| Convention | Rule | Example |
|---|---|---|
| Numbering | Zero-padded 4-digit sequential | |
| File name | | |
| Storage location | | |
| Title format | ADR-NNN: Imperative sentence | ADR-003: Use PostgreSQL for storage |
项目根目录/
docs/
adr/
0001-record-architecture-decisions.md
0002-use-typescript-for-backend.md
0003-use-postgresql-for-primary-storage.md
0004-adopt-rest-api-style.md
0005-use-jwt-for-authentication.md
README.md (可选的索引文件)Directory Structure
将ADR与代码及问题关联
project-root/
docs/
adr/
0001-record-architecture-decisions.md
0002-use-typescript-for-backend.md
0003-use-postgresql-for-primary-storage.md
0004-adopt-rest-api-style.md
0005-use-jwt-for-authentication.md
README.md (optional index)- 在受影响的代码区域附近的注释中引用ADR:
typescript
// 参见ADR-003: 使用PostgreSQL作为主存储 // docs/adr/0003-use-postgresql.md const db = new Pool({ connectionString: DATABASE_URL }); - 在ADR的页脚链接至相关的问题或PR:
markdown
## 参考资料 - GitHub Issue: #142 - Pull Request: #158 - 相关ADR: ADR-002
Linking ADRs to Code and Issues
示例ADR 1: 选择主数据库
- Reference the ADR in code comments near the affected area:
typescript
// See ADR-003: Use PostgreSQL for primary storage // docs/adr/0003-use-postgresql.md const db = new Pool({ connectionString: DATABASE_URL }); - Link to the relevant issue or PR in the ADR footer:
markdown
## References - GitHub Issue: #142 - Pull Request: #158 - Related: ADR-002
markdown
undefinedExample ADR 1: Choosing a Primary Database
ADR-003: 使用PostgreSQL作为主存储
—
状态
markdown
undefined已通过
ADR-003: Use PostgreSQL for Primary Storage
背景
Status
—
Accepted
我们的应用需要一个主数据存储来管理用户账户、订单及产品库存。我们的需求如下:
- 金融交易需强一致性
- 支持跨关联实体的复杂查询(关联查询)
- 团队拥有总计5年的PostgreSQL使用经验
- 预期规模:2年内最大表达到1000万行
- 以读操作为主,偶尔出现写操作峰值
我们评估了三个选项:PostgreSQL、MongoDB和DynamoDB。
Context
决策内容
Our application needs a primary data store for user accounts, orders,
and product inventory. We expect the following requirements:
- Strong consistency for financial transactions
- Complex queries across related entities (joins)
- Team has 5 years of collective PostgreSQL experience
- Expected scale: 10M rows in the largest table within 2 years
- Read-heavy workload with occasional write bursts
We evaluated three options: PostgreSQL, MongoDB, and DynamoDB.
我们将使用PostgreSQL 16作为主数据库。
我们将使用迁移工具(golang-migrate)管理schema变更,并强制所有schema变更需经过审核的迁移文件。
我们将在生产环境中通过PgBouncer实现连接池。
Decision
决策后果
We will use PostgreSQL 16 as our primary database.
We will manage schema changes with a migration tool (golang-migrate)
and enforce that all schema changes go through reviewed migration files.
We will use connection pooling via PgBouncer for production deployments.
正面影响:
- 团队可凭借现有经验立即开展工作
- ACID事务简化了订单与支付逻辑
- 丰富的查询能力减少了应用层的数据处理工作
- 拥有庞大的监控与备份工具生态
负面影响:
- 若增长远超预期,水平写扩展将需要分片或只读副本支持
- Schema迁移增加了数据模型变更的复杂度
- 需自行管理连接池与性能调优
后续行动:
- 在基础设施配置中搭建PgBouncer
- 创建迁移工作流并记录在开发者指南中
- 建立备份与时间点恢复流程
undefinedConsequences
示例ADR 2: API风格
Positive:
- Team can be productive immediately with existing expertise
- ACID transactions simplify order and payment logic
- Rich query capabilities reduce application-level data manipulation
- Large ecosystem of monitoring and backup tools
Negative:
- Horizontal write scaling will require sharding or read replicas if we exceed expected growth significantly
- Schema migrations add friction to data model changes
- We need to manage connection pooling and tuning ourselves
Follow-up actions:
- Set up PgBouncer in the infrastructure configuration
- Create a migration workflow and document in the developer guide
- Establish backup and point-in-time recovery procedures
undefinedmarkdown
undefinedExample ADR 2: API Style
ADR-004: 为公开API采用REST风格
—
状态
markdown
undefined已通过
ADR-004: Adopt REST for Public API
背景
Status
—
Accepted
我们正在为第三方集成构建公开API。该API将被不同技术水平的合作伙伴使用。我们需要在REST、GraphQL和gRPC之间做出选择。
关键因素:
- 合作伙伴期望文档完善、稳定的API
- 大多数使用者为Web应用和移动客户端
- 希望最小化合作伙伴的接入难度
- 内部服务间通信为独立需求(将在后续ADR中讨论内部RPC)
Context
决策内容
We are building a public API for third-party integrations. The API
will be consumed by partners with varying levels of technical
sophistication. We need to choose between REST, GraphQL, and gRPC.
Key factors:
- Partners expect a well-documented, stable API
- Most consumers are web applications and mobile clients
- We want to minimize onboarding friction for partners
- Internal services also need to communicate, but that is a separate concern (see future ADR for internal RPC)
我们将为面向公众的API采用RESTful API设计。
约定规范:
- 请求与响应体使用JSON格式
- URL路径使用复数资源名词(如:/api/v1/orders)
- 列表接口采用基于游标分页
- 通过URL路径前缀进行版本控制(/api/v1/, /api/v2/)
- 遵循api-design skill中的标准HTTP状态码
我们将使用OpenAPI 3.1编写规范,并据此生成文档。
Decision
决策后果
We will adopt RESTful API design for our public-facing API.
Conventions:
- JSON request and response bodies
- Plural resource nouns in URL paths (e.g., /api/v1/orders)
- Cursor-based pagination for list endpoints
- Versioning via URL path prefix (/api/v1/, /api/v2/)
- Standard HTTP status codes per our api-design skill
We will use OpenAPI 3.1 for specification and generate
documentation from it.
正面影响:
- 合作伙伴学习成本低(REST被广泛熟知)
- OpenAPI工具可自动生成SDK
- 可通过HTTP标准实现缓存(ETags、Cache-Control)
- 易于使用curl、Postman或任何HTTP客户端进行测试
负面影响:
- 与GraphQL相比存在过度获取或获取不足的问题
- 复杂数据需求需多次请求
- 版本控制需要维护并行实现
后续行动:
- 创建OpenAPI规范文件
- 搭建API文档生成流水线
- 定义错误响应格式(参见api-design skill)
undefinedConsequences
示例ADR 3: 认证策略
Positive:
- Low learning curve for partners (REST is widely understood)
- OpenAPI tooling enables auto-generated SDKs
- Cacheable via HTTP standards (ETags, Cache-Control)
- Easy to test with curl, Postman, or any HTTP client
Negative:
- Over-fetching and under-fetching compared to GraphQL
- Multiple roundtrips for complex data needs
- Versioning requires maintaining parallel implementations
Follow-up actions:
- Create the OpenAPI specification file
- Set up API documentation generation pipeline
- Define the error response format (see api-design skill)
undefinedmarkdown
undefinedExample ADR 3: Authentication Strategy
ADR-005: 使用带短期访问令牌的JWT进行认证
—
状态
markdown
undefined已通过
ADR-005: Use JWT with Short-Lived Access Tokens for Authentication
背景
Status
—
Accepted
我们需要对用户进行认证并授权API请求。应用同时拥有Web前端和移动客户端。需求如下:
- 无状态认证以简化水平扩展
- 支持无需重新完整认证的令牌刷新
- 具备泄露令牌的吊销能力
- 兼容OAuth2以支持未来的第三方集成
评估的选项:
- 基于会话的认证,使用服务端存储
- 带长期令牌的JWT
- 带短期访问令牌与刷新令牌的JWT
Context
决策内容
We need to authenticate users and authorize API requests. The
application has both a web frontend and mobile clients. Requirements:
- Stateless authentication to simplify horizontal scaling
- Support for token refresh without full re-authentication
- Revocation capability for compromised tokens
- Compatibility with OAuth2 for future third-party integrations
Options evaluated:
- Session-based authentication with server-side storage
- JWT with long-lived tokens
- JWT with short-lived access tokens and refresh tokens
我们将使用基于JWT的认证方案,具体如下:
- 访问令牌: 15分钟有效期,使用RS256签名
- 刷新令牌: 7天有效期,存储在数据库中,每次使用时轮换(刷新令牌轮换)
- 令牌存储: 访问令牌存储在前端内存中,刷新令牌存储在httpOnly安全Cookie中
- 吊销机制: 刷新令牌可通过从数据库删除实现吊销;访问令牌有效期较短,大多数场景下无需显式吊销
- 密钥轮换: RSA密钥对每季度轮换一次,通过JWKS端点对外提供
Decision
决策后果
We will use JWT-based authentication with:
- Access tokens: 15-minute expiry, signed with RS256
- Refresh tokens: 7-day expiry, stored in the database, rotated on each use (refresh token rotation)
- Token storage: Access token in memory (frontend), refresh token in httpOnly secure cookie
- Revocation: Refresh tokens can be revoked by deleting from the database; access tokens are short-lived enough to not require explicit revocation in most cases
- Key rotation: RSA key pairs rotated quarterly with JWKS endpoint
正面影响:
- 访问令牌验证无状态(无需每次请求查询数据库)
- 刷新令牌轮换限制了被盗令牌的有效窗口
- RS256允许无需共享签名密钥即可验证令牌
- JWKS端点支持密钥轮换且无需停机
负面影响:
- 无法立即吊销访问令牌(15分钟窗口)
- 缓解方案:对于关键操作(密码修改、检测到泄露),维护一个短期的拒绝列表,由中间件检查
- 刷新令牌存储增加了数据库依赖
- 客户端的令牌处理逻辑复杂
- 密钥轮换流程需要谨慎实现
后续行动:
- 实现JWKS端点
- 创建令牌验证中间件
- 为前端和移动团队编写令牌刷新流程文档
- 搭建认证失败尝试的监控
undefinedConsequences
ADR审核 Checklist
Positive:
- Stateless verification of access tokens (no database lookup per request)
- Refresh token rotation limits the window for stolen tokens
- RS256 allows verification without sharing the signing key
- JWKS endpoint enables key rotation without downtime
Negative:
- Cannot instantly revoke access tokens (15-minute window)
- Mitigation: for critical actions (password change, detected breach), maintain a short-lived deny list checked by middleware
- Refresh token storage adds database dependency
- Token handling complexity on the client side
- Key rotation process needs careful implementation
Follow-up actions:
- Implement the JWKS endpoint
- Create middleware for token verification
- Document the token refresh flow for frontend and mobile teams
- Set up monitoring for failed authentication attempts
undefined在通过ADR之前,需验证以下内容:
- 背景部分清晰解释了问题,新成员也能理解
- 列出并评估了所有可行的备选方案
- 决策内容明确、无歧义
- 已承认正面和负面后果
- 已识别后续行动
- ADR已链接至相关问题或PR
- 文件遵循命名规范(NNNN-title-slug.md)
- 状态在审核时设为“提议中”,批准后设为“已通过”
- 至少两名团队成员已审核该ADR
ADR Review Checklist
—
Before accepting an ADR, verify:
- Context explains the problem clearly enough that someone new can understand it
- All viable alternatives are listed and evaluated
- The decision is stated explicitly and unambiguously
- Both positive and negative consequences are acknowledged
- Follow-up actions are identified
- The ADR is linked to relevant issues or PRs
- The file follows naming conventions (NNNN-title-slug.md)
- Status is set to "Proposed" for review, "Accepted" after approval
- At least two team members have reviewed the ADR
—