還記得三個月前,我決定用 SQLDelight 而不是 Room。當時的理由是什麼?為什麼不選擇 Exposed?有考慮過什麼替代方案嗎?
現在的我完全想不起來了。
這就是軟體開發中的「決策健忘症」。我們做了無數個技術決策,但很少記錄「為什麼」。直到有一天:
這時你才發現,那些關鍵的決策理由都消失在時間的洪流中了。
ADR (Architecture Decision Records) 是一種輕量級的文件格式,專門用來記錄架構決策的:
簡單來說,ADR 就是架構決策的「日記」。
市面上有很多 ADR 格式:
我選擇 MADR (Markdown Architectural Decision Records) 的理由:
# 使用 Clean Architecture 搭配 MVI 模式
* 狀態: 已接受
* 決策者: Sam Zhu
* 日期: 2025-01-11
優點:
MADR 的模板剛剛好:
## 背景與問題陳述
[為什麼需要做決策]
## 決策驅動因素
* [關鍵考量點]
## 考慮的選項
* [選項 1]
* [選項 2]
## 決策結果
選擇 [選項 X],因為...
## 後果
### 正面影響
### 負面影響
不會太簡單(缺少重要資訊),也不會太複雜(寫到不想寫)。
MADR 有狀態管理:
* 狀態: [草案 | 提議 | 已接受 | 已棄用 | 已拒絕]
決策可以演化:
讓我用實際的 MADR 來展示它的威力:
# 使用 SQLDelight 內建 Migration 管理資料庫版本
* 狀態: 已接受
* 決策者: Sam Zhu, Claude (AI Assistant)
* 日期: 2025-01-11
* 技術故事: 需要支援資料庫結構演進,用戶升級時自動遷移
## 背景與問題陳述
Grimo 採用 SQLDelight 作為資料庫層,隨著功能迭代,
資料庫結構會持續演進。我們需要一個可靠的機制來:
1. 管理資料庫版本
2. 自動執行結構遷移
3. 確保資料完整性
4. 支援向後相容
SQLDelight 2.0+ 提供了內建的 migration 支援,
但也可以選擇自行實作或使用第三方方案。
## 決策驅動因素
* **簡單性**:減少外部依賴和複雜度
* **類型安全**:與 SQLDelight 的類型系統整合
* **可測試性**:能夠測試 migration 邏輯
* **跨平台**:支援 KMP 所有目標平台
* **官方支援**:有長期維護保證
## 考慮的選項
### 選項 1: SQLDelight 內建 Migration
使用 `deriveSchemaFromMigrations = true` 和 `.sqm` 檔案
**優點**:
- 與 SQLDelight 深度整合
- 編譯時驗證
- 自動產生 Schema
**缺點**:
- 文件相對較少
- 靈活性受限
### 選項 2: 自訂 Migration 系統
建立自己的版本管理和執行機制
**優點**:
- 完全控制
- 可自訂邏輯
**缺點**:
- 需要大量開發
- 容易出錯
- 測試負擔重
### 選項 3: Flyway/Liquibase
使用成熟的第三方 migration 工具
**優點**:
- 功能豐富
- 社群支援好
**缺點**:
- JVM only,不支援 KMP
- 額外依賴
- 與 SQLDelight 整合困難
## 決策結果
選擇 **選項 1: SQLDelight 內建 Migration**。
理由:
1. 與現有技術棧完美整合
2. 編譯時驗證減少執行時錯誤
3. 支援所有 KMP 平台
4. 維護成本最低
5. 官方持續改進
## 後果
### 正面影響
* 開發速度快,一週內完成實作
* 類型安全,編譯時發現問題
* 與 CI/CD 整合簡單
* 減少專案依賴
### 負面影響
* 需要學習 SQLDelight 特定語法
* 複雜 migration 可能需要 workaround
* 文件和範例相對較少
## 確認
透過以下方式確認決策實施:
1. 所有 migration 測試通過
2. 從 v1 成功升級到 v3
3. 效能符合預期(< 5秒)
4. 程式碼審查通過
## 參考資料
* [SQLDelight 2.0 Migration 文件](https://cashapp.github.io/sqldelight/2.0.0/jvm_sqlite/migrations/)
* [GitHub Issue #2211](https://github.com/cashapp/sqldelight/issues/2211)
三個月後,當我(或其他人)看到這份 MADR:
Q: 為什麼不用 Flyway?
A: 看 MADR - 因為不支援 KMP
Q: 有什麼缺點需要注意?
A: 看 MADR - 複雜 migration 可能需要 workaround
Q: 當初還考慮過什麼?
A: 看 MADR - 自訂系統和第三方工具
新人:「我覺得應該用 Room...」
我:「請先看 ADR-002,裡面有完整評估」
新人:「哦,原來已經討論過了」
我:請根據 ADR-002 幫我實作新的 migration
Claude:根據 ADR-002,我們使用 SQLDelight 內建 migration,
需要在 migrations/ 目錄建立 .sqm 檔案...
不是所有決策都需要 MADR。判斷的標準很簡單:
如果影響整個系統,需要 MADR。如果只影響單一模組但難以改變,也需要 MADR。如果改變成本很高,同樣需要 MADR。其他情況通常不需要。
需要 MADR 的例子:
不需要 MADR 的例子:
好的寫法:
## 背景與問題陳述
隨著團隊規模擴大,程式碼風格不一致問題日益嚴重,
PR review 時常因格式問題產生討論,影響開發效率。
不好的寫法:
## 背景與問題陳述
程式碼很亂。
MADR 文件有清晰的生命週期:從草案開始,識別問題後完成評估變成提議,團隊同意後變成已接受,或者被否決成為已拒絕。已接受的決策可能被新的 ADR 取代而變成已棄用。
0001-use-clean-architecture-with-mvi.md
0002-use-sqldelight-migration.md
0003-adopt-ktfmt-for-code-formatting.md
# 創建新的 MADR
cp docs/architecture/09-decisions/template.md \
docs/architecture/09-decisions/0003-new-decision.md
* 狀態: 提議 # 開放討論
* 決策者: Sam Zhu, Team
* 日期: 2025-01-20
## 評論
- @alice: 選項 2 的成本是否評估過?
- @bob: 建議加入效能考量
## 確認
- [x] 技術 POC 完成
- [x] 團隊 training 完成
- [ ] 生產環境部署
- [ ] 監控指標設定
我:幫我評估是否應該從 REST 改為 GraphQL
Claude:我來幫你撰寫 MADR 草案:
# 從 REST API 遷移到 GraphQL
## 背景與問題陳述
目前的 REST API 存在以下問題:
1. Over-fetching:獲取不需要的資料
2. Under-fetching:需要多次請求
3. 版本管理複雜
## 考慮的選項
1. 保持 REST + 優化
2. 遷移到 GraphQL
3. 採用 gRPC
[繼續生成完整評估...]
我:請審查這份 MADR 是否完整
Claude:審查 MADR-0004:
缺少的部分:
1. 沒有評估遷移成本
2. 缺少效能影響分析
3. 未考慮團隊學習曲線
解法:與 AI 和未來的自己對話
* 決策者: Sam Zhu, Claude (AI), Future Sam
解法:簡化模板,只寫關鍵部分
# 快速 MADR
## 為什麼
[一句話說明問題]
## 選項
1. [選項 A]
2. [選項 B]
## 決定
[選擇] 因為 [原因]
## 風險
[主要風險]
解法:問自己三個問題
MADR 不是官僚文件,而是:
對一人公司特別重要,因為:
記住:最好的 MADR 是寫下來的 MADR,而不是完美的 MADR。
「程式碼展示『如何做』,MADR 記錄『為何這樣做』。」
關於作者:Sam,一人公司創辦人。正在打造 Grimo,一個智能任務管理和分配平台。
專案連結:GitHub - grimostudio