documentation-and-adrs
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDocumentation and ADRs
文档与架构决策记录(ADR)
Overview
概述
Document decisions, not just code. The most valuable documentation captures the why — the context, constraints, and trade-offs that led to a decision. Code shows what was built; documentation explains why it was built this way and what alternatives were considered. This context is essential for future humans and agents working in the codebase.
记录决策,而不仅仅是代码。最有价值的文档会记录「为什么」—— 即引导决策产生的上下文、约束和权衡。代码展示了构建了「什么」;文档则解释了「为什么要这么构建」以及「曾考虑过哪些替代方案」。这些上下文对于未来在代码库中工作的开发人员和Agent来说至关重要。
When to Use
适用场景
- Making a significant architectural decision
- Choosing between competing approaches
- Adding or changing a public API
- Shipping a feature that changes user-facing behavior
- Onboarding new team members (or agents) to the project
- When you find yourself explaining the same thing repeatedly
When NOT to use: Don't document obvious code. Don't add comments that restate what the code already says. Don't write docs for throwaway prototypes.
- 制定重大架构决策
- 在多种可行方案中做选择
- 新增或修改公共API
- 发布会改变用户侧行为的功能
- 为新团队成员(或Agent)做项目入职培训
- 你发现自己需要反复解释同一件事的时候
不适用场景: 不要给显而易见的代码写文档,不要添加和代码功能完全重复的注释,不要给用完就丢的原型写文档。
Architecture Decision Records (ADRs)
架构决策记录(ADR)
ADRs capture the reasoning behind significant technical decisions. They're the highest-value documentation you can write.
ADR 会记录重大技术决策背后的原因,是你能写的价值最高的文档。
When to Write an ADR
什么时候需要写ADR
- Choosing a framework, library, or major dependency
- Designing a data model or database schema
- Selecting an authentication strategy
- Deciding on an API architecture (REST vs. GraphQL vs. tRPC)
- Choosing between build tools, hosting platforms, or infrastructure
- Any decision that would be expensive to reverse
- 选择框架、库或核心依赖
- 设计数据模型或数据库 schema
- 选择身份验证策略
- 确定API架构(REST vs GraphQL vs tRPC)
- 选择构建工具、托管平台或基础设施
- 任何逆转成本很高的决策
ADR Template
ADR模板
Store ADRs in with sequential numbering:
docs/decisions/markdown
undefined将ADR存放在目录下,按顺序编号:
docs/decisions/markdown
undefinedADR-001: Use PostgreSQL for primary database
ADR-001: Use PostgreSQL for primary database
Status
Status
Accepted | Superseded by ADR-XXX | Deprecated
Accepted | Superseded by ADR-XXX | Deprecated
Date
Date
2025-01-15
2025-01-15
Context
Context
We need a primary database for the task management application. Key requirements:
- Relational data model (users, tasks, teams with relationships)
- ACID transactions for task state changes
- Support for full-text search on task content
- Managed hosting available (for small team, limited ops capacity)
We need a primary database for the task management application. Key requirements:
- Relational data model (users, tasks, teams with relationships)
- ACID transactions for task state changes
- Support for full-text search on task content
- Managed hosting available (for small team, limited ops capacity)
Decision
Decision
Use PostgreSQL with Prisma ORM.
Use PostgreSQL with Prisma ORM.
Alternatives Considered
Alternatives Considered
MongoDB
MongoDB
- Pros: Flexible schema, easy to start with
- Cons: Our data is inherently relational; would need to manage relationships manually
- Rejected: Relational data in a document store leads to complex joins or data duplication
- Pros: Flexible schema, easy to start with
- Cons: Our data is inherently relational; would need to manage relationships manually
- Rejected: Relational data in a document store leads to complex joins or data duplication
SQLite
SQLite
- Pros: Zero configuration, embedded, fast for reads
- Cons: Limited concurrent write support, no managed hosting for production
- Rejected: Not suitable for multi-user web application in production
- Pros: Zero configuration, embedded, fast for reads
- Cons: Limited concurrent write support, no managed hosting for production
- Rejected: Not suitable for multi-user web application in production
MySQL
MySQL
- Pros: Mature, widely supported
- Cons: PostgreSQL has better JSON support, full-text search, and ecosystem tooling
- Rejected: PostgreSQL is the better fit for our feature requirements
- Pros: Mature, widely supported
- Cons: PostgreSQL has better JSON support, full-text search, and ecosystem tooling
- Rejected: PostgreSQL is the better fit for our feature requirements
Consequences
Consequences
- Prisma provides type-safe database access and migration management
- We can use PostgreSQL's full-text search instead of adding Elasticsearch
- Team needs PostgreSQL knowledge (standard skill, low risk)
- Hosting on managed service (Supabase, Neon, or RDS)
undefined- Prisma provides type-safe database access and migration management
- We can use PostgreSQL's full-text search instead of adding Elasticsearch
- Team needs PostgreSQL knowledge (standard skill, low risk)
- Hosting on managed service (Supabase, Neon, or RDS)
undefinedADR Lifecycle
ADR生命周期
PROPOSED → ACCEPTED → (SUPERSEDED or DEPRECATED)- Don't delete old ADRs. They capture historical context.
- When a decision changes, write a new ADR that references and supersedes the old one.
PROPOSED → ACCEPTED → (SUPERSEDED or DEPRECATED)- 不要删除旧ADR,它们记录了历史上下文
- 当决策发生变更时,编写新的ADR,在内容中引用并说明旧ADR已被取代
Inline Documentation
行内文档
When to Comment
什么时候需要写注释
Comment the why, not the what:
typescript
// BAD: Restates the code
// Increment counter by 1
counter += 1;
// GOOD: Explains non-obvious intent
// Rate limit uses a sliding window — reset counter at window boundary,
// not on a fixed schedule, to prevent burst attacks at window edges
if (now - windowStart > WINDOW_SIZE_MS) {
counter = 0;
windowStart = now;
}注释要解释「为什么」,而不是「是什么」:
typescript
// BAD: Restates the code
// Increment counter by 1
counter += 1;
// GOOD: Explains non-obvious intent
// Rate limit uses a sliding window — reset counter at window boundary,
// not on a fixed schedule, to prevent burst attacks at window edges
if (now - windowStart > WINDOW_SIZE_MS) {
counter = 0;
windowStart = now;
}When NOT to Comment
什么时候不需要写注释
typescript
// Don't comment self-explanatory code
function calculateTotal(items: CartItem[]): number {
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
// Don't leave TODO comments for things you should just do now
// TODO: add error handling ← Just add it
// Don't leave commented-out code
// const oldImplementation = () => { ... } ← Delete it, git has historytypescript
// Don't comment self-explanatory code
function calculateTotal(items: CartItem[]): number {
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
// Don't leave TODO comments for things you should just do now
// TODO: add error handling ← Just add it
// Don't leave commented-out code
// const oldImplementation = () => { ... } ← Delete it, git has historyDocument Known Gotchas
记录已知的坑
typescript
/**
* IMPORTANT: This function must be called before the first render.
* If called after hydration, it causes a flash of unstyled content
* because the theme context isn't available during SSR.
*
* See ADR-003 for the full design rationale.
*/
export function initializeTheme(theme: Theme): void {
// ...
}typescript
/**
* IMPORTANT: This function must be called before the first render.
* If called after hydration, it causes a flash of unstyled content
* because the theme context isn't available during SSR.
*
* See ADR-003 for the full design rationale.
*/
export function initializeTheme(theme: Theme): void {
// ...
}API Documentation
API文档
For public APIs (REST, GraphQL, library interfaces):
对于公共API(REST、GraphQL、库接口):
Inline with Types (Preferred for TypeScript)
与类型定义写在一起(TypeScript优先方案)
typescript
/**
* Creates a new task.
*
* @param input - Task creation data (title required, description optional)
* @returns The created task with server-generated ID and timestamps
* @throws {ValidationError} If title is empty or exceeds 200 characters
* @throws {AuthenticationError} If the user is not authenticated
*
* @example
* const task = await createTask({ title: 'Buy groceries' });
* console.log(task.id); // "task_abc123"
*/
export async function createTask(input: CreateTaskInput): Promise<Task> {
// ...
}typescript
/**
* Creates a new task.
*
* @param input - Task creation data (title required, description optional)
* @returns The created task with server-generated ID and timestamps
* @throws {ValidationError} If title is empty or exceeds 200 characters
* @throws {AuthenticationError} If the user is not authenticated
*
* @example
* const task = await createTask({ title: 'Buy groceries' });
* console.log(task.id); // "task_abc123"
*/
export async function createTask(input: CreateTaskInput): Promise<Task> {
// ...
}OpenAPI / Swagger for REST APIs
REST API用OpenAPI / Swagger编写
yaml
paths:
/api/tasks:
post:
summary: Create a task
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTaskInput'
responses:
'201':
description: Task created
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
'422':
description: Validation erroryaml
paths:
/api/tasks:
post:
summary: Create a task
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTaskInput'
responses:
'201':
description: Task created
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
'422':
description: Validation errorREADME Structure
README结构
Every project should have a README that covers:
markdown
undefined每个项目都应该包含README,覆盖以下内容:
markdown
undefinedProject Name
Project Name
One-paragraph description of what this project does.
One-paragraph description of what this project does.
Quick Start
Quick Start
- Clone the repo
- Install dependencies:
npm install - Set up environment:
cp .env.example .env - Run the dev server:
npm run dev
- Clone the repo
- Install dependencies:
npm install - Set up environment:
cp .env.example .env - Run the dev server:
npm run dev
Commands
Commands
| Command | Description |
|---|---|
| Start development server |
| Run tests |
| Production build |
| Run linter |
| Command | Description |
|---|---|
| Start development server |
| Run tests |
| Production build |
| Run linter |
Architecture
Architecture
Brief overview of the project structure and key design decisions.
Link to ADRs for details.
Brief overview of the project structure and key design decisions.
Link to ADRs for details.
Contributing
Contributing
How to contribute, coding standards, PR process.
undefinedHow to contribute, coding standards, PR process.
undefinedChangelog Maintenance
更新日志维护
For shipped features:
markdown
undefined针对已发布的功能:
markdown
undefinedChangelog
Changelog
[1.2.0] - 2025-01-20
[1.2.0] - 2025-01-20
Added
Added
- Task sharing: users can share tasks with team members (#123)
- Email notifications for task assignments (#124)
- Task sharing: users can share tasks with team members (#123)
- Email notifications for task assignments (#124)
Fixed
Fixed
- Duplicate tasks appearing when rapidly clicking create button (#125)
- Duplicate tasks appearing when rapidly clicking create button (#125)
Changed
Changed
- Task list now loads 50 items per page (was 20) for better UX (#126)
undefined- Task list now loads 50 items per page (was 20) for better UX (#126)
undefinedDocumentation for Agents
Agent专属文档
Special consideration for AI agent context:
- CLAUDE.md / rules files — Document project conventions so agents follow them
- Spec files — Keep specs updated so agents build the right thing
- ADRs — Help agents understand why past decisions were made (prevents re-deciding)
- Inline gotchas — Prevent agents from falling into known traps
针对AI Agent的上下文需要特殊注意:
- CLAUDE.md / 规则文件 — 记录项目规范,确保Agent遵守
- 需求规格文件 — 保持规格更新,确保Agent构建的内容符合预期
- ADR — 帮助Agent理解过去的决策原因(避免重复决策)
- 行内坑点说明 — 避免Agent踩到已知的问题
Common Rationalizations
常见的错误认知
| Rationalization | Reality |
|---|---|
| "The code is self-documenting" | Code shows what. It doesn't show why, what alternatives were rejected, or what constraints apply. |
| "We'll write docs when the API stabilizes" | APIs stabilize faster when you document them. The doc is the first test of the design. |
| "Nobody reads docs" | Agents do. Future engineers do. Your 3-months-later self does. |
| "ADRs are overhead" | A 10-minute ADR prevents a 2-hour debate about the same decision six months later. |
| "Comments get outdated" | Comments on why are stable. Comments on what get outdated — that's why you only write the former. |
| 错误认知 | 实际情况 |
|---|---|
| "代码是自解释的" | 代码只展示了做了什么,不会说明为什么这么做、哪些方案被否决了、有什么约束条件 |
| "等API稳定了我们再写文档" | 写文档的过程本身就是对设计的第一轮测试,写文档会让API更快稳定 |
| "没人会看文档" | Agent会看,未来的工程师会看,三个月后的你自己也会看 |
| "写ADR太费时间" | 花10分钟写的ADR可以避免半年后针对同一个决策花2小时争论 |
| "注释会过时" | 解释「为什么」的注释是稳定的,只有解释「是什么」的注释才容易过时——这也是为什么你只需要写前者 |
Red Flags
危险信号
- Architectural decisions with no written rationale
- Public APIs with no documentation or types
- README that doesn't explain how to run the project
- Commented-out code instead of deletion
- TODO comments that have been there for weeks
- No ADRs in a project with significant architectural choices
- Documentation that restates the code instead of explaining intent
- 架构决策没有书面的理由说明
- 公共API没有文档或类型定义
- README没有说明如何运行项目
- 保留了注释掉的代码而不是直接删除
- 存在了数周的TODO注释
- 有大量架构选择的项目却没有任何ADR
- 文档只是重复代码的功能,没有解释背后的意图
Verification
校验清单
After documenting:
- ADRs exist for all significant architectural decisions
- README covers quick start, commands, and architecture overview
- API functions have parameter and return type documentation
- Known gotchas are documented inline where they matter
- No commented-out code remains
- Rules files (CLAUDE.md etc.) are current and accurate
完成文档编写后检查:
- 所有重大架构决策都有对应的ADR
- README包含快速开始、常用命令和架构概述
- API函数都有参数和返回值的文档说明
- 已知坑点在对应的行内位置做好了文档说明
- 没有残留的注释掉的代码
- 规则文件(CLAUDE.md等)是最新且准确的