SKILL.md
readonlyread-only
name
documentation-and-adrs
description
記錄決策與文件。在進行架構決策、變更公開 API、推出功能,或需要記錄未來工程師與代理理解程式碼所需的背景資訊時使用。
文件與架構決策記錄 (ADR)
概述
記錄決策,而不只是程式碼。最有價值的文件捕捉的是 為什麼 —— 導致某個決策的背景、限制與取捨。程式碼顯示 做了什麼;文件解釋 為什麼這樣做 以及 考慮過哪些替代方案。這個背景對於未來在程式碼庫中工作的人類與代理至關重要。
使用時機
- 做出重要的架構決策
- 在競爭方案之間做選擇
- 新增或變更公開 API
- 推出會改變使用者行為的功能
- 新團隊成員(或代理)加入專案時
- 當你發現自己反覆解釋同一件事時
何時不該使用: 不要記錄顯而易見的程式碼。不要添加只是重複程式碼的註解。不要為一次性原型寫文件。
架構決策記錄 (ADR)
ADR 捕捉重大技術決策背後的理由。這是你所能寫出的最有價值的文件。
何時撰寫 ADR
- 選擇框架、函式庫或主要依賴
- 設計資料模型或資料庫綱要
- 選擇驗證策略
- 決定 API 架構(REST vs. GraphQL vs. tRPC)
- 在建置工具、託管平台或基礎設施之間做選擇
- 任何逆轉成本高昂的決策
ADR 範本
將 ADR 存放在 docs/decisions/ 中,並使用連續編號:
# ADR-001:使用 PostgreSQL 作為主要資料庫
## 狀態
已接受 | 被 ADR-XXX 取代 | 已棄用
## 日期
2025-01-15
## 背景
我們需要一個任務管理應用程式的主要資料庫。關鍵需求:
- 關聯式資料模型(使用者、任務、團隊之間的關係)
- 任務狀態變更的 ACID 交易
- 支援任務內容的全文搜尋
- 提供代管服務(小團隊、有限營運能力)
## 決策
使用 PostgreSQL 搭配 Prisma ORM。
## 考慮過的替代方案
### MongoDB
- 優點:彈性綱要,容易上手
- 缺點:我們的資料本質上是關聯式的;需要手動管理關係
- 拒絕原因:在文件型資料庫中處理關聯式資料會導致複雜的 join 或資料重複
### SQLite
- 優點:零設定、嵌入式、讀取快速
- 缺點:有限的並行寫入支援,生產環境無代管服務
- 拒絕原因:不適合生產環境的多使用者網頁應用程式
### MySQL
- 優點:成熟、廣泛支援
- 缺點:PostgreSQL 在 JSON 支援、全文搜尋與生態系工具方面更佳
- 拒絕原因:PostgreSQL 更符合我們的功能需求
## 影響
- Prisma 提供型別安全的資料庫存取與遷移管理
- 我們可以使用 PostgreSQL 的全文搜尋,無需額外引入 Elasticsearch
- 團隊需要 PostgreSQL 知識(標準技能,風險低)
- 託管於代管服務(Supabase、Neon 或 RDS)
ADR 生命週期
PROPOSED → ACCEPTED → (SUPERSEDED 或 DEPRECATED)
- 不要刪除舊的 ADR。 它們保留了歷史背景。
- 當決策變更時,撰寫新的 ADR 來引用並取代舊的。
行內文件
何時加註解
註解 為什麼,而不是 做什麼:
// 不好:重複程式碼
// 計數器加 1
counter += 1;
// 好:解釋非顯而易見的意圖
// 速率限制使用滑動視窗 — 在視窗邊界重置計數器,
// 而非固定排程,以防止視窗邊緣的突發攻擊
if (now - windowStart > WINDOW_SIZE_MS) {
counter = 0;
windowStart = now;
}
何時不加註解
// 不要註解不言自明的程式碼
function calculateTotal(items: CartItem[]): number {
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
// 不要留下你應該現在就做的 TODO 註解
// TODO: 加入錯誤處理 ← 直接加上去
// 不要留下被註解掉的程式碼
// const oldImplementation = () => { ... } ← 刪掉它,git 有歷史紀錄
記錄已知陷阱
/**
* 重要:此函式必須在第一次渲染前呼叫。
* 如果在 hydration 後呼叫,會導致無樣式內容閃爍,
* 因為 SSR 期間主題上下文不可用。
*
* 完整設計理由請見 ADR-003。
*/
export function initializeTheme(theme: Theme): void {
// ...
}
API 文件
對於公開 API(REST、GraphQL、函式庫介面):
與型別同行(TypeScript 優先)
/**
* 建立新任務。
*
* @param input - 任務建立資料(標題必填,描述選填)
* @returns 建立的任務,包含伺服器產生的 ID 與時間戳
* @throws {ValidationError} 如果標題為空或超過 200 個字元
* @throws {AuthenticationError} 如果使用者未驗證
*
* @example
* const task = await createTask({ title: '買菜' });
* console.log(task.id); // "task_abc123"
*/
export async function createTask(input: CreateTaskInput): Promise<Task> {
// ...
}
REST API 的 OpenAPI / Swagger
paths:
/api/tasks:
post:
summary: 建立任務
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTaskInput'
responses:
'201':
description: 任務已建立
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
'422':
description: 驗證錯誤
README 結構
每個專案都應有涵蓋以下內容的 README:
# 專案名稱
一段描述此專案用途的文字。
## 快速開始
1. 複製儲存庫
2. 安裝依賴:`npm install`
3. 設定環境:`cp .env.example .env`
4. 啟動開發伺服器:`npm run dev`
## 指令
| 指令 | 說明 |
|---------|-------------|
| `npm run dev` | 啟動開發伺服器 |
| `npm test` | 執行測試 |
| `npm run build` | 生產環境建置 |
| `npm run lint` | 執行 lint |
## 架構
簡要概述專案結構與關鍵設計決策。
詳細內容請參考 ADR。
## 貢獻方式
如何貢獻、編碼標準、PR 流程。
更新日誌維護
對於已推出的功能:
# 更新日誌
## [1.2.0] - 2025-01-20
### 新增
- 任務分享:使用者可與團隊成員分享任務 (#123)
- 任務指派電子郵件通知 (#124)
### 修正
- 快速點擊建立按鈕時出現重複任務 (#125)
### 變更
- 任務列表現在每頁載入 50 個項目(原為 20 個)以改善使用者體驗 (#126)
給代理的文件
針對 AI 代理背景的特殊考量:
- CLAUDE.md / rules 檔案 — 記錄專案慣例,讓代理遵循
- 規格檔案 — 保持規格更新,讓代理建置正確的內容
- ADR — 幫助代理理解過去決策的原因(避免重新決策)
- 行內陷阱 — 防止代理掉入已知陷阱
常見合理化藉口
| 合理化藉口 | 現實 |
|---|---|
| 「程式碼本身就是文件」 | 程式碼顯示做了什麼。它不顯示為什麼、哪些替代方案被拒絕、或有哪些限制。 |
| 「等 API 穩定後再寫文件」 | 當你撰寫文件時,API 會更快穩定。文件是設計的第一個測試。 |
| 「沒人看文件」 | 代理會看。未來的工程師會看。三個月後的你自己也會看。 |
| 「ADR 是額外負擔」 | 花 10 分鐘寫 ADR 可以避免六個月後花 2 小時爭論同一個決策。 |
| 「註解會過時」 | 關於 為什麼 的註解是穩定的。關於 做什麼 的註解會過時——這就是為什麼你只寫前者。 |
紅旗
- 沒有書面理由的架構決策
- 沒有文件或型別的公開 API
- 未說明如何執行專案的 README
- 被註解掉的程式碼而非刪除
- 存在數週的 TODO 註解
- 在有重大架構選擇的專案中沒有 ADR
- 重複程式碼而非解釋意圖的文件
驗證
完成文件後:
- [ ] 所有重大架構決策都有對應的 ADR
- [ ] README 涵蓋快速開始、指令與架構概述
- [ ] API 函式有參數與回傳型別的文件
- [ ] 已知陷阱已在相關位置行內記錄
- [ ] 沒有殘留的被註解掉的程式碼
- [ ] 規則檔案(CLAUDE.md 等)是最新且準確的






