架構決策紀錄 是做什麼的?
在編程會話期間捕捉架構決策。與其讓決策只存在於 Slack 討論串、PR 評論或某人的記憶中,不如讓此技能產出結構化的 ADR 文件,與程式碼並存。
何時啟動
- 使用者明確說「讓我們記錄這個決策」或「記一個 ADR」
- 使用者在重要的替代方案之間做選擇(框架、函式庫、模式、資料庫、API 設計)
- 使用者說「我們決定...」或「我們選 X 而不選 Y 的原因是...」
- 使用者問「為什麼我們選了 X?」(讀取既有 ADR)
- 在規劃階段討論架構權衡時
ADR 格式
使用 Michael Nygard 提出的輕量級 ADR 格式,針對 AI 輔助開發進行調整:
# ADR-NNNN:[決策標題]
**日期**:YYYY-MM-DD
**狀態**:proposed | accepted | deprecated | superseded by ADR-NNNN
**決策者**:[參與者]
## 背景
是什麼樣的問題促使了這個決策或變更?
[2-5 句話描述情境、約束條件及相關影響因素]
## 決策
我們提議及/或正在進行的變更為何?
[1-3 句話清楚陳述決策]
## 考慮過的替代方案
### 替代方案 1:[名稱]
- **優點**:[好處]
- **缺點**:[缺點]
- **未選用原因**:[拒絕此方案的具體理由]
### 替代方案 2:[名稱]
- **優點**:[好處]
- **缺點**:[缺點]
- **未選用原因**:[拒絕此方案的具體理由]
## 後果
因為這個變更,哪些事變得更簡單或更困難?
### 正面
- [好處 1]
- [好處 2]
### 負面
- [權衡取捨 1]
- [權衡取捨 2]
### 風險
- [風險與緩解措施]
工作流程
捕捉新的 ADR
當檢測到決策時刻時:
- 初始化(僅首次) — 如果
docs/adr/不存在,先詢問使用者確認,再建立目錄、一個內含索引表格表頭(見下方 ADR 索引格式)的README.md,以及一個供手動使用的空白template.md。未經明確同意不得建立任何檔案。 - 識別決策 — 擷取核心的架構選擇
- 收集背景 — 是什麼問題引發此決策?存在哪些約束條件?
- 記錄替代方案 — 考慮過哪些其他選項?為何拒絕?
- 陳述後果 — 有哪些權衡取捨?什麼變得更簡單/更困難?
- 指派編號 — 掃描
docs/adr/中的既有 ADR,然後遞增 - 確認與寫入 — 將 ADR 草稿呈現給使用者審閱。僅在使用者明確核准後才寫入
docs/adr/NNNN-decision-title.md。如果使用者拒絕,則放棄草稿,不寫入任何檔案。 - 更新索引 — 附加到
docs/adr/README.md結尾
讀取既有 ADR
當使用者問「為什麼我們選了 X?」時:
- 檢查
docs/adr/是否存在 — 如果不存在,回應:「此專案中找不到任何 ADR。您想開始記錄架構決策嗎?」 - 如果存在,掃描
docs/adr/README.md索引以尋找相關條目 - 讀取符合的 ADR 檔案,並呈現「背景」與「決策」章節
- 如果找不到相符項目,回應:「未找到該決策的 ADR。您想現在記錄一個嗎?」
ADR 目錄結構
docs/
└── adr/
├── README.md ← 所有 ADR 的索引
├── 0001-use-nextjs.md
├── 0002-postgres-over-mongo.md
├── 0003-rest-over-graphql.md
└── template.md ← 供手動使用的空白範本
ADR 索引格式
# 架構決策紀錄
| ADR | 標題 | 狀態 | 日期 |
|-----|------|------|------|
| [0001](0001-use-nextjs.md) | 使用 Next.js 作為前端框架 | accepted | 2026-01-15 |
| [0002](0002-postgres-over-mongo.md) | 使用 PostgreSQL 而非 MongoDB 作為主要資料儲存 | accepted | 2026-01-20 |
| [0003](0003-rest-over-graphql.md) | 使用 REST API 而非 GraphQL | accepted | 2026-02-01 |
決策檢測訊號
留意對話中表示架構決策的以下模式:
明確訊號
- 「我們就用 X 吧」
- 「我們應該用 X 而不是 Y」
- 「這個權衡取捨值得,因為...」
- 「把這個記為 ADR」
隱含訊號(建議記錄 ADR — 未經使用者確認不要自動建立)
- 比較兩個框架或函式庫後得出結論
- 做出附帶理由的資料庫綱要設計選擇
- 在架構模式之間做選擇(單體 vs 微服務,REST vs GraphQL)
- 決定驗證/授權策略
- 在評估替代方案後選擇部署基礎設施
好的 ADR 應具備什麼
應做
- 具體明確 — 寫「使用 Prisma ORM」而非「使用一個 ORM」
- 記錄原因 — 理由比做了什麼更重要
- 包含被拒絕的替代方案 — 未來開發者需要知道考慮過哪些選項
- 誠實說明後果 — 每個決策都有權衡取捨
- 保持簡短 — 一份 ADR 應該能在 2 分鐘內讀完
- 使用現在式 — 寫「我們使用 X」而非「我們將會使用 X」
不應做
- 記錄瑣碎決策 — 變數命名或格式設定不需要 ADR
- 寫成論文 — 如果背景章節超過 10 行,就太長了
- 省略替代方案 — 「我們就是選了它」不是有效的理由
- 未標記日期就回溯補登 — 若記錄過去決策,請註明原始日期
- 讓 ADR 過時 — 被取代的決策應引用其替代者
ADR 生命週期
proposed → accepted → [deprecated | superseded by ADR-NNNN]
- proposed:決策正在討論中,尚未確定
- accepted:決策已生效並被遵循
- deprecated:決策已不再相關(例如功能已移除)
- superseded:較新的 ADR 取代了此 ADR(務必連結至替代者)
值得記錄的決策類別
| 類別 | 範例 |
|---|---|
| 技術選型 | 框架、語言、資料庫、雲端供應商 |
| 架構模式 | 單體 vs 微服務、事件驅動、CQRS |
| API 設計 | REST vs GraphQL、版本策略、驗證機制 |
| 資料建模 | 綱要設計、正規化決策、快取策略 |
| 基礎設施 | 部署模型、CI/CD 管道、監控堆疊 |
| 安全性 | 驗證策略、加密方式、機密管理 |
| 測試 | 測試框架、涵蓋率目標、E2E 與整合測試平衡 |
| 流程 | 分支策略、審查流程、發布節奏 |
與其他技能的整合
- 規劃員代理:當規劃員提出架構變更時,建議建立 ADR
- 程式碼審查員代理:標記那些引入架構變更但缺少對應 ADR 的 PR