以增量方式交付變更。當實作任何涉及多個檔案的功能或變更時使用。當你準備一次寫入大量程式碼,或某個任務大到無法一次完成時使用。
增量實作
概述
以薄的垂直切片建構——實作一個片段、測試、驗證,然後擴展。避免一次完成整個功能。每個增量應讓系統保持在可運作、可測試的狀態。這是讓大型功能變得可管理的執行紀律。
使用時機
- 實作任何跨多個檔案的變更
- 從任務分解中建構新功能
- 重構現有程式碼
- 任何時候你忍不住想在測試前寫超過約 100 行程式碼
何時不使用: 單一檔案、單一函式的變更,且範圍已經很小。
增量循環
┌──────────────────────────────────────┐
│ │
│ 實作 ──→ 測試 ──→ 驗證 ──┐ │
│ ▲ │ │
│ └───── 提交 ◄─────────────┘ │
│ │ │
│ ▼ │
│ 下一個切片 │
│ │
└──────────────────────────────────────┘
對於每個切片:
- 實作 最小的完整功能片段
- 測試 — 執行測試套件(如果沒有測試則撰寫一個)
- 驗證 — 確認切片如預期運作(測試通過、建置成功、手動檢查)
- 提交 — 用描述性訊息儲存進度(關於原子提交的指引,請參閱
git-workflow-and-versioning) - 移動到下一個切片 — 繼續前進,不要重新開始
切片策略
垂直切片(首選)
建構一條完整的路徑貫穿整個堆疊:
切片 1:建立任務(資料庫 + API + 基本 UI)
→ 測試通過,使用者可以透過 UI 建立任務
切片 2:列出任務(查詢 + API + UI)
→ 測試通過,使用者可以看到他們的任務
切片 3:編輯任務(更新 + API + UI)
→ 測試通過,使用者可以修改任務
切片 4:刪除任務(刪除 + API + UI + 確認)
→ 測試通過,完整 CRUD 完成
每個切片提供可運作的端到端功能。
合約優先切片
當後端和前端需要平行開發時:
切片 0:定義 API 合約(型別、介面、OpenAPI 規格)
切片 1a:根據合約實作後端 + API 測試
切片 1b:根據符合合約的模擬資料實作前端
切片 2:整合並進行端到端測試
風險優先切片
先處理風險最高或不確定的部分:
切片 1:證明 WebSocket 連線可運作(風險最高)
切片 2:在已驗證的連線上建構即時任務更新
切片 3:加入離線支援和重新連線
如果切片 1 失敗,你會在投入切片 2 和 3 之前發現。
實作規則
規則 0:簡單優先
在寫任何程式碼之前,問:「最簡單可行的方式是什麼?」
寫完程式碼後,根據以下檢查點審視:
- 能否用更少的行數完成?
- 這些抽象化是否值得其複雜度?
- 資深工程師看到這個會不會說「你為什麼不直接...」?
- 我是在為假設的未來需求而建構,還是為當前的任務?
簡單性檢查:
✗ 為一個通知建立帶中介管線的通用 EventBus
✓ 簡單的函式呼叫
✗ 為兩個相似元件使用抽象工廠模式
✓ 兩個直接的元件加上共用工具
✗ 為三個表單使用設定驅動的表單建構器
✓ 三個表單元件
三行相似的程式碼勝過過早的抽象化。先實作直覺、明顯正確的版本。只有在測試證明正確性後才進行最佳化。
規則 0.5:範圍紀律
只觸碰任務所需的內容。
不要:
- 「清理」與你的變更相鄰的程式碼
- 重構你未修改的檔案中的匯入
- 移除你不完全理解的註解
- 加入規格中沒有的功能,只因為「看起來有用」
- 在你只是閱讀的檔案中現代化語法
如果你注意到任務範圍外有值得改進的地方,記錄下來——不要修正:
注意到但未觸碰:
- src/utils/format.ts 有一個未使用的匯入(與此任務無關)
- 認證中介軟體可以使用更好的錯誤訊息(獨立任務)
→ 需要我為這些建立任務嗎?
規則 1:一次只做一件事
每個增量只改變一個邏輯項目。不要混合關注點:
不好: 一個提交同時加入新元件、重構現有元件、並更新建置設定。
好: 三個獨立的提交——每個變更一個。
規則 2:保持可編譯
每個增量之後,專案必須能建置,且現有測試必須通過。不要在切片之間讓程式碼庫處於損壞狀態。
規則 3:為未完成功能使用功能開關
如果某個功能尚未準備好給使用者,但你需要合併增量:
// 進行中功能的功能開關
const ENABLE_TASK_SHARING = process.env.FEATURE_TASK_SHARING === 'true';
if (ENABLE_TASK_SHARING) {
// 新的分享 UI
}
這讓你可以將小增量合併到主分支,而不暴露未完成的工作。
規則 4:安全預設值
新程式碼應預設為安全、保守的行為:
// 安全:預設關閉,選擇加入
export function createTask(data: TaskInput, options?: { notify?: boolean }) {
const shouldNotify = options?.notify ?? false;
// ...
}
規則 5:易於回退
每個增量應可獨立回退:
- 新增變更(新檔案、新函式)容易回退
- 對現有程式碼的修改應最小且集中
- 資料庫遷移應有對應的回退遷移
- 避免在同一個提交中刪除某物並取代它——將它們分開
與代理協作
當指示代理以增量方式實作時:
「我們來實作計劃中的任務 3。
先只做資料庫結構變更和 API 端點。
先不要碰 UI——我們在下一個增量再做。
實作完成後,執行 `npm test` 和 `npm run build` 來確認
沒有東西壞掉。」
明確說明每個增量中哪些在範圍內、哪些不在範圍內。
增量檢查清單
每個增量完成後,確認:
- [ ] 變更只做一件事且完整完成
- [ ] 所有現有測試仍然通過(
npm test) - [ ] 建置成功(
npm run build) - [ ] 型別檢查通過(
npx tsc --noEmit) - [ ] Linting 通過(
npm run lint) - [ ] 新功能如預期運作
- [ ] 變更已提交並附有描述性訊息
注意: 在可能影響該項目的變更後,才執行每個驗證指令。成功執行後,除非程式碼已變更,否則不要重複執行相同指令——在未變更的程式碼上重新執行不會增加資訊。
常見合理化藉口
| 合理化藉口 | 現實 |
|---|---|
| 「我最後再一起測試」 | 錯誤會疊加。切片 1 的錯誤會讓切片 2-5 都錯。每個切片都要測試。 |
| 「一次做完比較快」 | 感覺比較快,直到東西壞掉而你找不到是 500 行中的哪一行造成的。 |
| 「這些變更太小了,不值得分開提交」 | 小提交是免費的。大提交隱藏錯誤並讓回退痛苦。 |
| 「我之後再加功能開關」 | 如果功能未完成,就不該對使用者可見。現在就加上開關。 |
| 「這個重構很小,可以包含進來」 | 重構與功能混合會讓兩者都更難審查和除錯。將它們分開。 |
| 「讓我再跑一次建置指令以確保安全」 | 成功執行後,除非程式碼已變更,否則重複執行相同指令不會增加任何東西。在後續編輯後再執行,而不是為了安心。 |
紅旗
- 寫了超過 100 行程式碼卻沒有執行測試
- 單一增量中包含多個不相關的變更
- 「讓我順便快速加上這個」的範圍擴張
- 跳過測試/驗證步驟以求更快
- 增量之間建置或測試失敗
- 大量未提交的變更累積
- 在第三個使用案例要求之前就建立抽象化
- 觸碰任務範圍外的檔案「趁我在這裡」
- 為一次性操作建立新的工具檔案
- 連續兩次執行相同的建置/測試指令,中間沒有任何程式碼變更
驗證
完成任務的所有增量後:
- [ ] 每個增量都已個別測試並提交
- [ ] 完整測試套件通過
- [ ] 建置乾淨
- [ ] 功能如規格所述端到端運作
- [ ] 沒有未提交的變更遺留
參閱
每個增量的驗證是局部檢查。在宣告任務完成之前,套用專案層級的完成定義作為最終關卡,這是每個增量無論任務為何都必須通過的標準門檻。請參閱 references/definition-of-done.md。






