# Claude Code 教學：一些實作上的眉眉角角

**URL:** https://vip.studycamp.tw/t/claude-code-%E6%95%99%E5%AD%B8%EF%BC%9A%E4%B8%80%E4%BA%9B%E5%AF%A6%E4%BD%9C%E4%B8%8A%E7%9A%84%E7%9C%89%E7%9C%89%E8%A7%92%E8%A7%92/8781
**Category:** Generative AI 生成式人工智慧
**Tags:** claude-code
**Created:** [2026年五月14日 04:03 UTC](https://vip.studycamp.tw/t/claude-code-%E6%95%99%E5%AD%B8%EF%BC%9A%E4%B8%80%E4%BA%9B%E5%AF%A6%E4%BD%9C%E4%B8%8A%E7%9A%84%E7%9C%89%E7%9C%89%E8%A7%92%E8%A7%92/8781 "2026-05-14T04:03:41Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![sky](https://vip.studycamp.tw/user_avatar/vip.studycamp.tw/sky/32/8098_2.png) [@sky](https://vip.studycamp.tw/u/sky)
#### Post date: [2026年五月14日 04:03 UTC](https://vip.studycamp.tw/t/claude-code-%E6%95%99%E5%AD%B8%EF%BC%9A%E4%B8%80%E4%BA%9B%E5%AF%A6%E4%BD%9C%E4%B8%8A%E7%9A%84%E7%9C%89%E7%9C%89%E8%A7%92%E8%A7%92/8781/1 "2026-05-14T04:03:43Z")

</div>

前一篇文章「 [**鄭智維先生的 Claude Code 實戰指南：30 個技巧 + 8 個踩坑**](https://vip.studycamp.tw/t/%E9%84%AD%E6%99%BA%E7%B6%AD%E5%85%88%E7%94%9F-claude-code-%E5%AF%A6%E6%88%B0%E6%8C%87%E5%8D%97%EF%BC%9A30-%E5%80%8B%E6%8A%80%E5%B7%A7-8-%E5%80%8B%E8%B8%A9%E5%9D%91/8779)」是根據鄭先生臉書分享的圖片，由 Claude 衍生展開。這一篇則是由 Claude 自行撰寫。

在開始之前，先說一點心得：

> 如果沒有經過這樣的過程，而是一開始就直接請 Claude 撰寫「 **Claude Code 實作指引** 」的話，內容應該會是現在的十分之一不到。
> 
> 這不是 AI 的錯，是我們下的指令不對。
> 
> 所以，未來我們要請 Claude 撰寫某個主題的文章時，如何更完整呢？
> 
> 簡單的說： **提供一個 roadmap** 。這個 roadmap 告訴 Claude 如何進行，有了這個 roadmap (就像是 Claude Code 的 Claude.md)，Claude 就不只是撰寫一篇文章，而是根據 roadmap 上的每個點，有歷史脈絡的各自撰寫一篇文章。

> **以本文為例，roadmap 如下（點擊展開）：**
>
> 用使用者心智模型的成熟度來組織結構，而不是用難度分層。
> 
> 原作者是以「功能介紹」為主軸，Claude 的版本則是以「你可能會在哪裡出問題」為主軸。
> 
> 新增了指令設計、驗證與品質控制、團隊協作等新主題，以及失敗模式的系統分析。
> 
> ### 一、重新認識這個工具
> 
> > 先破除錯誤預設，再建立正確操作模型
> 
> 1. Claude Code 的操作模型：Agent，不是 Assistant
> 2. Context Window 是最重要的資源，不是功能
> 3. Session 是工作單位，不是對話單位
> 4. Claude Code 看到的世界：它能感知什麼、感知不到什麼
> 5. 它的信心和它的準確率是兩件事
> 
> ### 二、指令設計
> 
> > 這是最被低估的核心技能
> 
> 1. 描述結果，不描述步驟
> 2. 給約束，不給自由
> 3. 把驗證標準寫進指令
> 4. 用檔案路徑代替描述
> 5. 歧義是你的責任，不是它的問題
> 
> ### 三、工作流程設計
> 
> > 任務怎麼拆、Session 怎麼管
> 
> 1. 任務拆解的原則：原子性和可驗證性
> 2. Session 邊界的設計
> 3. Git 是 Session 之間唯一可靠的記憶
> 4. Worktree 讓並行成為可能
> 5. Human-in-the-loop 不是效率問題，是風險管理
> 
> ### 四、長期記憶系統
> 
> > CLAUDE.md 和 Skill 的完整設計
> 
> 1. CLAUDE.md 的三層結構：專案、模組、個人
> 2. 什麼該寫進 CLAUDE.md，什麼不該
> 3. Skill 的參數化設計
> 4. 設定檔納入版本控制的團隊意義
> 5. 記憶系統的維護：什麼時候該更新
> 
> ### 五、驗證與品質控制
> 
> > 新增主題
> 
> 1. 「完成」的定義要在任務開始前就說清楚
> 2. 測試先行的工作流程
> 3. 讓它 review 自己的輸出
> 4. 讓它 review 你的輸出
> 5. 什麼程度的輸出值得信任，什麼程度需要人工複查
> 
> ### 六、工具整合
> 
> > MCP 和外部系統
> 
> 1. MCP 的正確心智模型：能力擴充，不是魔法
> 2. 選現成 MCP 還是自建的判斷標準
> 3. 自建 MCP 的最小可行設計
> 4. MCP 的 debug 方法論
> 5. 工具鏈的複雜度管理
> 
> ### 七、常見失敗模式
> 
> > 更系統化的進化版踩坑區
> 
> 1. 速度陷阱：跑得快但方向錯
> 2. 信任陷阱：它說完成就以為完成
> 3. 脈絡陷阱：Session 狀態污染
> 4. 規模陷阱：小資料通過、真實環境爆炸
> 5. 依賴陷阱：套件升級的隱性風險
> 6. 理解陷阱：codebase 是它寫的但你看不懂
> 
> ### 八、團隊協作
> 
> > 新增主題
> 
> 1. 讓 Claude Code 的行為在團隊內一致
> 2. Skill 和 CLAUDE.md 的共同維護機制
> 3. AI 生成的程式碼如何做 code review
> 4. 什麼應該讓 Claude Code 做，什麼應該人自己寫
> 5. 團隊對 Claude Code 輸出的共同品質標準

* * *

## ▌1. 重新認識這個工具

學習操作技巧之前，先調整好我們的預設認知。錯誤的心智模型（我們對 Claude Code 運作方式的預設理解想像）會讓我們把每一條技巧都用錯方向。

### 01｜Claude Code 的操作模型：Agent，不是 Assistant

大多數人接觸 Claude Code 之前，已經用過某種 AI 工具：ChatGPT、GitHub Copilot、或是 Claude.ai 的對話介面。這些工具建立了一個預設：你問，它答，你決定要不要用。

Claude Code 的設計預設完全不同。

它被設計成一個 Agent，意思是：它會主動採取行動，而不只是回應你的問題。它會自己讀檔案、自己跑指令、自己修改程式碼、自己驗證結果。你給的不是問題，而是任務。它交付的不是答案，而是結果。

這個差別在實際操作上的影響：

- 當你說「這個 function 有 bug」，Assistant 模型的回應是解釋 bug 在哪、建議怎麼修。Agent 模型的回應是直接去找那個 function、分析 bug、修好它、跑測試確認修好了。
- 當你說「幫我整理這個專案的文件」，Assistant 模型會給你一份整理建議。Agent 模型會直接去讀所有文件、找出不一致的地方、然後動手修改。

帶錯心態的兩種常見結果：

第一種是低估：只拿 Claude Code 來問問題，從不讓它真正動手。等於買了一個工具只用來當裝飾。

第二種是驚嚇：沒有預期它會直接改檔案，結果它改了一堆東西，你不知道它動了哪裡、為什麼這樣動。

正確的心態是：你是在交派任務給一個會主動執行的工程師，不是在查詢一個知識庫。

### 02｜Context Window 是最重要的資源，不是功能

Claude Code 的所有行為都發生在 context window 裡。它能「記住」的一切——你的指令、它讀過的檔案、它執行過的指令、對話的歷史——全部存在這個有限的空間裡。

Context window 滿了之後會發生什麼：

不是報錯，也不是停止運作。它會繼續運作，但早期的內容會被推出 context，它的「記憶」開始出現缺口。症狀是：

- 它開始忘記你在 Session 初期說過的限制
- 它對 codebase 的理解開始出現矛盾
- 它會重複做已經做過的事，或是忽略已經確認過的決定
- 回應品質明顯下降，開始出現不確定的猜測

Context window 的實際管理方式：

- 不要在同一個 Session 裡做太多事（這就是為什麼要每個任務開新 Session）
- 讓它讀的檔案要精準，不要叫它「讀整個專案」，而是「讀 `services/order.py` 和 `tests/test_order.py`」
- 長對話中途如果感覺品質下降，不要繼續撐，開新 Session 重新交代背景

把 context window 想成工作桌面：桌面越亂，工作效率越低。保持桌面整潔是你的責任，不是它的。

### 03｜Session 是工作單位，不是對話單位

這個概念很多人沒有刻意想過，但它決定了你整個工作流程的設計。

Session 在 Claude Code 裡代表什麼：

一個 Session 是一段有開始、有結束的工作上下文。Session 開始時，它的記憶是空的（除了 CLAUDE.md 提供的長期設定）。Session 結束後，對話裡發生的一切不會自動保留到下一個 Session。

Session 不是對話的自然延伸，而是工作的邊界。

正確的 Session 設計原則：

- 一個 Session 對應一個原子任務
- Session 的開場要交代清楚：任務是什麼、相關的檔案在哪、完成的標準是什麼
- Session 的結尾要有一個明確的收尾動作：commit、存檔、或是輸出一份摘要

Session 之間如何傳遞資訊：

不是靠「繼續上次的對話」，而是靠：

- Git commit（記錄程式碼的當前狀態）
- CLAUDE.md（記錄長期有效的規則）
- 你自己寫的任務說明（每個新 Session 的開場白）

### 04｜Claude Code 看到的世界：它能感知什麼、感知不到什麼

Claude Code 不是全知的。它只能感知你明確給它的資訊，加上它自己主動去讀取的資訊。

它能感知的：

- 你在 Session 裡說的所有內容
- 它主動讀取的本地檔案（你告訴它路徑，或它自己判斷需要讀）
- 它執行的指令的輸出（stdout、stderr）
- CLAUDE.md 的內容
- 透過 MCP 串接的外部系統

它感知不到的：

- 你沒有告訴它、它也沒有主動讀取的程式碼
- 口頭討論過但沒有寫進 CLAUDE.md 的決定
- 上一個 Session 裡發生的事（除非你重新告訴它）
- 你的心理預期（「我以為它知道不能動這個檔案」）
- 程式碼的歷史脈絡（某個設計為什麼這樣做，除非有 comment 或文件）

實際影響：

很多時候 Claude Code 「做錯了」，不是因為它能力不足，而是因為它沒有感知到關鍵資訊。在抱怨它之前，先問自己：「它做這個決定的時候，它知道什麼？它不知道什麼？」

### 05｜它的信心和它的準確率是兩件事

這條是最容易被忽略、但影響最深遠的認知校正。

Claude Code 的回應語氣通常很確定。它說「好的，我已經修好這個 bug 了」的語氣，和「好的，我已經修好這個 bug 了，但我不太確定這樣對不對」的語氣，表面上看起來差不多，但背後的準確率可能差很多。

它為什麼聽起來總是很確定：

它的訓練方式讓它傾向於給出明確的答案，而不是不斷說「我不確定」。這在大多數情況下是有用的，但也意味著：它的語氣不能作為準確率的指標。

具體的風險場景：

- 它修了一個 bug，說「修好了」，但實際上只修了其中一個觸發路徑
- 它說「測試全部通過」，但它跑的是舊版的測試，新功能沒有對應的測試
- 它說「這個設計符合你的架構規範」，但它對你的架構規範的理解是基於不完整的資訊

正確的應對方式：

不是不信任它，而是把驗證步驟系統化，不依賴它的自我評估。讓測試說話，讓 diff 說話，讓你自己的眼睛說話。它的信心是參考，不是保證。

* * *

## ▌2. 指令設計

最重要的核心技能。工具再強，指令寫得不好，輸出就不會好。很多人把 Claude Code 的輸出品質不穩定，歸咎於工具本身，但真正的原因往往在指令下的不好。

### 01｜描述結果，不描述步驟

這是指令設計最根本的原則，也是最難內化的一條。

人在思考一個任務時，自然的方式是想「我要怎麼做」：先做 A，再做 B，然後做 C。把這個思考過程直接寫進指令，就變成了步驟式指令。步驟式指令的問題是：你描述的步驟是你對問題的解法，但你對 codebase 的了解不一定比 Claude Code 深，你選的步驟不一定是最適合的路徑。

步驟式指令 vs 結果式指令的對比：

```auto
# 步驟式（低效）
「把 get_user function 改成 async，
 在裡面加上 try-except，
 exception 的時候 return None，
 然後把所有呼叫這個 function 的地方加上 await」

# 結果式（高效）
「get_user 目前在資料庫連線失敗時會讓整個程式 crash。
 我希望它能夠優雅地處理失敗，
 讓呼叫端能夠判斷操作是否成功並決定後續行為。
 請根據現有 codebase 的錯誤處理模式來實作。」

```

結果式指令讓 Claude Code 根據它對你整個 codebase 的理解來選擇最適合的實作方式。它可能選擇你沒想到的、但更適合你現有架構的解法。

例外情況：

如果你有強烈的技術理由要求特定的實作方式（例如效能限制、團隊規範、外部系統的介面要求），明確指定是對的。結果式指令的精神不是「什麼都不說」，而是「說清楚你真正在意的是什麼」。

### 02｜給約束，不給自由

直覺上你可能覺得給 Claude Code 越多自由度，它能發揮越好。實際上相反：清晰的約束讓它的輸出更準確、更符合你的需求。

自由度高的指令會讓它在大量的可能性空間裡自己做選擇。它做的選擇不一定是你想要的，而且你很難預測它會選什麼。

沒有約束 vs 有約束的對比：

```auto
# 沒有約束（危險）
「幫我優化這個資料庫查詢」

# 有約束（安全）
「幫我優化這個資料庫查詢。
 限制條件：
 - 不能改動 schema
 - 不能引入新的 index（需要 DBA 審核）
 - 查詢時間目標是從現在的 800ms 降到 200ms 以下
 - 不能用 raw SQL，維持現有的 ORM 風格」

```

約束的作用不只是限制它不能做什麼，更重要的是讓它理解你的決策邊界。知道了邊界，它在邊界內的判斷反而更準確。

常見的重要約束類型：

- 技術限制（不能引入新依賴、不能改 interface、不能動某些檔案）
- 風格約束（遵循現有的 error handling 模式、命名規範）
- 範圍約束（只改這個模組、不要動測試以外的地方）
- 品質約束（改完要通過現有測試、不能降低測試覆蓋率）

### 03｜把驗證標準寫進指令

「做完」的定義如果不寫進指令，它就會用自己的標準來判斷完成。它的標準不一定是你的標準。

沒有驗證標準的指令：

```auto
「幫我重構 OrderService」

```

它做完之後告訴你「完成了」。但完成是什麼意思？程式碼能跑？測試通過？效能改善了？文件更新了？你不知道，它也不確定，雙方各自用不同的標準在溝通。

有驗證標準的指令：

```auto
「幫我重構 OrderService。
 完成的標準：
 1. pytest tests/test_order_service.py 全部通過
 2. mypy 對 order_service.py 沒有任何錯誤
 3. 沒有新增任何 public method（只是內部重組）
 4. 每個 private method 都有 docstring 說明它在做什麼
 
 完成後把驗證結果逐條回報給我。」

```

驗證標準的另一個作用是：讓它在執行過程中自我校準。它知道最終要達到什麼標準，中途發現方向不對時會自己調整，而不是做完一個不符合標準的結果再告訴你。

### 04｜用檔案路徑代替描述

當你需要它理解某段程式碼、某個模組、或某份文件時，給路徑比給描述有效得多。

描述 vs 路徑的對比：

```auto
# 描述（低效）
「我有一個處理訂單狀態的 service，
 裡面有幾個方法負責狀態轉換，
 幫我看看有沒有問題」

# 路徑（高效）
「請讀 services/order_state_machine.py，
 分析狀態轉換邏輯，
 找出可能的競爭條件（race condition）」

```

路徑的好處是精準且無歧義。你的描述和它理解的描述之間有解讀空間，路徑沒有。

進階用法：

```auto
# 給多個相關檔案
「請先讀以下檔案再開始：
 - models/order.py（Order 的資料結構）
 - services/order_service.py（業務邏輯）
 - tests/test_order_service.py（現有測試，理解預期行為）
 讀完後告訴我你的理解，確認後再開始修改。」

```

讓它在開始工作之前先彙報它的理解，是一個有效的校準步驟。你確認它的理解正確之後，後續的工作方向就不容易跑偏。

### 05｜歧義是你的責任，不是它的問題

這條是心態問題，但影響非常實際。

當 Claude Code 的輸出不符合你的預期，第一個反應往往是「它理解錯了」。但更準確的問法是：「我的指令有沒有給它足夠的資訊做出正確的判斷？」

歧義的幾種常見來源：

第一種是術語歧義。你說「優化這個 function」，優化是指效能、可讀性、還是記憶體使用量？你心裡有答案，但指令裡沒有說。

第二種是範圍歧義。你說「修好這個 bug」，修好是指修掉這個特定的觸發路徑，還是找出並修好所有類似的問題？

第三種是優先級歧義。你說「讓這段程式碼更好」，在效能和可讀性之間衝突時，它應該優先哪個？

第四種是隱性前提。你覺得「當然不能動 production config」，但你沒有說，它不知道。

消除歧義的實際方法：

寫完指令之後，用一個簡單的測試：如果一個剛加入團隊、聰明但對這個專案完全不熟悉的工程師收到這個指令，他有沒有足夠的資訊做出正確的判斷？

如果答案是沒有，繼續補充，直到答案是有。

* * *

## ▌3. 工作流程設計

指令設計解決的是「單次任務怎麼說清楚」，工作流程設計解決的是「多個任務怎麼組織」。兩者都重要，但大多數人只想到前者。

### 01｜任務拆解的原則：原子性和可驗證性

任務拆解不是把一件大事切成幾件小事這麼簡單。拆得不好，小任務之間會有隱性依賴、邊界模糊、驗證困難等問題，反而比不拆更麻煩。

好的任務拆解需要同時滿足兩個條件：

原子性：每個子任務是獨立可執行的單位。

原子性的意思是：這個子任務可以在不依賴其他子任務「進行中狀態」的情況下獨立完成。它可以依賴其他任務的「完成結果」（例如上一個任務的 commit），但不能依賴另一個任務「還沒做完的中間狀態」。

可驗證性：每個子任務有明確的完成標準。

完成標準要在任務開始前就定義好，而且要是客觀可檢查的，不能是「看起來差不多了」。

一個實際的拆解範例：

任務：「把現有的同步 API 改成非同步」

錯誤的拆法：

```auto
1. 改 controller 層
2. 改 service 層
3. 改 repository 層
4. 更新測試

```

這個拆法的問題是步驟 1-3 之間有強依賴，controller 改成 async 之後，如果 service 還沒改，整個系統是壞的狀態，無法驗證。

正確的拆法：

```auto
1. 在不改現有同步介面的情況下，
   為每個 service method 新增對應的 async 版本
   → 驗證：新的 async method 有獨立測試且通過

2. 逐一把 controller 切換到呼叫 async 版本
   → 驗證：每切換一個 endpoint，對應的整合測試通過

3. 確認所有 controller 都切換完畢後，
   移除舊的同步版本
   → 驗證：沒有任何程式碼呼叫舊版 method，測試全過

```

這個拆法的每個步驟結束時，系統都處於可運作的狀態，可以獨立驗證。

### 02｜Session 邊界的設計

知道「一個 Session 做一件事」之後，下一個問題是：一件事的邊界在哪裡？

Session 邊界的設計有三個判斷標準：

第一：這個任務完成後，有沒有一個自然的 checkpoint？

Checkpoint 是指一個可以獨立存在的穩定狀態，例如一個可以 commit 的程式碼狀態、一份可以獨立閱讀的文件、一個通過的測試套件。如果沒有自然的 checkpoint，可能是任務還需要繼續拆。

第二：這個任務需要多少背景資訊？

如果一個任務需要讀取超過 10-15 個檔案才能開始工作，context 很快會被資訊佔滿，工作品質會在中途下降。這是訊號：任務範圍太大，或是需要先把相關的背景資訊整理進 CLAUDE.md，再以精簡的方式在 Session 裡引用。

第三：這個任務的輸出會成為下一個任務的輸入嗎？

如果是，兩個任務應該是不同的 Session，中間靠 git commit 或文件傳遞狀態。如果不是，考慮它們是否真的是獨立的任務，還是同一個任務的兩個部分。

Session 開場的標準格式：

一個好的 Session 開場應該包含：

```auto
任務：[一句話說明這個 Session 要完成什麼]
相關檔案：[列出需要讀取的檔案路徑]
背景：[任何不在程式碼裡但必要的上下文]
完成標準：[客觀可驗證的完成條件]
限制：[不能做的事]

```

不需要每次都用這個格式，但這五個元素都應該在開場時涵蓋到。

### 03｜Git 是 Session 之間唯一可靠的記憶

這條值得單獨強調，因為很多人低估了它的重要性。

Claude Code 沒有跨 Session 的記憶。CLAUDE.md 提供的是規則和偏好，不是狀態。真正能可靠地記錄「現在的 codebase 是什麼狀態」的，只有 git。

這個認知帶來的具體實踐：

勤 commit，而且 commit message 要有意義。

不是做完一個大功能才 commit，而是每完成一個可驗證的子任務就 commit。Claude Code 在新 Session 裡可以透過 `git log` 和 `git diff` 理解最近發生了什麼，但它能理解的品質完全取決於你的 commit message 品質。

好的 commit message 對 Claude Code 的意義：

```auto
# 對 Claude Code 幾乎沒用的 commit message
「update order service」

# 對 Claude Code 有用的 commit message
「refactor(order): 將狀態轉換邏輯抽取到 OrderStateMachine

原本散落在 OrderService 各個 method 裡的狀態轉換判斷，
統一移到新的 OrderStateMachine class。
OrderService 的 public interface 維持不變。
相關測試在 tests/test_order_state_machine.py」

```

第二種 commit message 讓下一個 Session 的 Claude Code 在讀 git log 時，能夠精確理解這個改動的意圖、範圍、和影響，不需要重新讀完所有改動的程式碼。

用 git 做安全網：

在開始任何較大的修改之前，確保當前狀態有一個乾淨的 commit。這樣無論 Claude Code 在中途做了什麼奇怪的事，你都有一個確定可以回到的點。

### 04｜Worktree 讓並行成為可能

當你有多個獨立任務需要同時進行，Worktree 是讓它們真正互不干擾的機制。

Worktree 的核心概念：

Git Worktree 讓你在同一個 repository 裡，同時 checkout 多個 branch 到不同的目錄。每個目錄是完全獨立的工作環境，有自己的工作區狀態，不會互相污染。

```bash
# 主目錄：main branch，日常工作
~/projects/myapp/

# 建立第二個 worktree 給 feature 開發
git worktree add ~/projects/myapp-feature feature/async-refactor

# 建立第三個 worktree 給緊急 hotfix
git worktree add ~/projects/myapp-hotfix hotfix/payment-crash

# 查看所有 worktree 狀態
git worktree list

```

之後在三個不同的終端機視窗，分別在三個目錄下啟動 Claude Code，三個 Session 完全隔離，各自處理自己的任務。

Worktree 特別適合的場景：

- 讓 Claude Code 在 feature branch 跑一個耗時的重構任務，同時你繼續在 main branch 做其他工作
- 同時有 hotfix 和 feature 開發進行，需要在不同 branch 之間快速切換而不影響彼此
- 需要在不同的實驗性方向之間比較結果，各自跑完再決定採用哪個

Worktree 的注意事項：

同一個 branch 不能同時被兩個 worktree checkout。如果你需要在同一個 branch 上開兩個 Session，考慮改成用兩個不同的 branch，最後再 merge。

### 05｜Human-in-the-loop 不是效率問題，是風險管理

很多人把 Human-in-the-loop（人工確認節點）理解成「不信任 AI 所以要一直監視它」。這個理解是錯的。

正確的理解是：在任務流程的關鍵節點，有些判斷需要業務知識或風險承擔能力，這些判斷只有人能做。

哪些節點應該設置人工確認：

第一類：不可逆操作前。

刪除資料、修改 migration、改動對外的 API interface、部署到生產環境。這些操作一旦執行，rollback 的成本很高。在這些操作前停下來讓人確認，不是不信任 Claude Code，而是承認這個決定的後果需要人來承擔。

第二類：方向性判斷點。

當任務進行到一個岔路口，兩個方向都技術上可行，但選擇哪個取決於業務優先級或團隊偏好。Claude Code 可以列出選項和各自的取捨，但決定應該由你來做。

第三類：跨越模組邊界時。

當一個任務的修改從一個模組延伸到另一個模組，確認這個延伸是你預期的，而不是它自己判斷需要這樣做的。

在指令裡設置確認節點的寫法：

```auto
請依序執行以下步驟。
每個步驟完成後停下來，
等我明確說「繼續」才執行下一步。

步驟 1：讀取所有相關檔案，
        列出你的修改計畫和預計影響的範圍。
        （我會在這裡確認計畫是否正確）

步驟 2：執行修改。
        （我會在這裡確認 diff 是否符合預期）

步驟 3：跑測試並回報結果。
        （我會在這裡決定是否需要補充測試）

步驟 4：生成 commit message，等我確認後再 commit。

```

這個寫法讓流程有結構、有節奏，不是隨機暫停，而是在有意義的點讓人介入。

* * *

## ▌4. 長期記憶系統

Claude Code 沒有跨 Session 的自動記憶。但這不代表你每次都要從零開始交代背景。長期記憶系統的設計，就是把「需要每次重複說的事」沉澱成結構化的文件，讓 Claude Code 在每個 Session 開始時自動載入。

設計得好，新 Session 的開場白可以很短。設計得不好，你會發現自己每次都在重複解釋同樣的事。

### 01｜CLAUDE.md 的三層結構：專案、模組、個人

CLAUDE.md 不是一個單一的檔案，而是一個階層式的設定系統。Claude Code 會根據當前工作目錄，自動合併讀取不同層級的 CLAUDE.md。

三層結構：

```auto
~/ # 第一層：個人全域設定
└── CLAUDE.md # 適用於所有專案的個人偏好

~/projects/myapp/ # 第二層：專案層級
└── CLAUDE.md # 這個專案的架構、規範、限制

~/projects/myapp/
├── services/
│ └── CLAUDE.md # 第三層：模組層級
└── tests/
    └── CLAUDE.md # 測試目錄的特定規範

```

各層應該放什麼：

個人全域層（`~/CLAUDE.md`）：

放你在所有專案裡都適用的個人偏好，例如：

```markdown
## 溝通偏好
- 每個步驟完成後主動回報結果，不要等我問
- 不確定時先列出選項和各自的取捨，不要自己猜測決定
- 錯誤訊息貼完整，不要自己節錄

## 程式碼風格偏好
- 函式命名用動詞開頭
- 優先可讀性，在沒有明確效能需求的情況下不要過度優化
- 每個 public function 都要有 type hint

```

專案層（`~/projects/myapp/CLAUDE.md`）：

放這個專案特有的資訊：

```markdown
## 專案概述
訂單管理系統，處理電商平台的訂單生命週期。
Tech stack：FastAPI + PostgreSQL + Redis + Celery

## 目錄結構
- models/：SQLAlchemy ORM models
- services/：業務邏輯，不直接操作資料庫
- repositories/：所有資料庫操作集中在這裡
- api/：FastAPI route handlers，只做輸入驗證和呼叫 service

## 架構規則
- Service 層不能直接 import SQLAlchemy session，必須透過 repository
- API 層不能包含業務邏輯，業務邏輯一律在 service 層
- 不使用全域狀態，所有依賴透過 dependency injection 傳入

## 禁止事項
- 不直接修改 alembic migration 檔案
- 不動 config/production.yaml
- 不在沒有對應測試的情況下新增 public method

```

模組層（`~/projects/myapp/services/CLAUDE.md`）：

放這個模組特有的細節：

```markdown
## Services 模組規範
- 每個 service class 對應一個業務領域
- Method 命名：動詞 + 名詞（create_order, cancel_order）
- 所有 service method 都要有對應的 unit test
- 錯誤處理：業務邏輯錯誤用自訂 Exception，
  系統錯誤讓它往上傳播

```

三層合併的效果：

Claude Code 在 `services/` 目錄工作時，會同時讀取個人全域層、專案層、和 services 模組層的設定，三層規則同時生效，不需要你在每個 Session 裡重複說明。

### 02｜什麼該寫進 CLAUDE.md，什麼不該

CLAUDE.md 寫太少，每個 Session 都要重複交代背景。寫太多，關鍵資訊被稀釋，Claude Code 反而抓不到重點。

應該寫進 CLAUDE.md 的：

- 長期穩定的規則：不常改變的架構決策、命名規範、禁止事項
- 非顯而易見的約束：外部系統的特殊行為、歷史遺留的技術債說明、某個設計看起來奇怪但有原因的地方
- 溝通協議：你希望它在不確定時怎麼做、驗證的標準格式、回報的方式
- 工具和環境資訊：測試指令、build 指令、常用的 debug 工具

不應該寫進 CLAUDE.md 的：

- 任務特定的細節：某次特定任務的背景，寫進去之後對其他任務沒有意義，反而佔用空間
- 會頻繁改變的資訊：如果某條規則每週都在變，它不適合放在 CLAUDE.md，應該在每個 Session 開場時說明
- 可以從程式碼直接讀出來的資訊：如果 Claude Code 讀一下 `models/order.py` 就能理解 Order 的結構，不需要在 CLAUDE.md 裡重複描述
- 過長的背景故事：CLAUDE.md 超過 500 行之後，效果會開始遞減。資訊量越大，每條規則被注意到的機率越低

一個實用的判斷標準：

問自己：「這條資訊，是不是每一個在這個專案工作的 Session 都需要知道？」如果是，寫進 CLAUDE.md。如果只是某些 Session 需要，在那個 Session 的開場時說就好。

### 03｜Skill 的參數化設計

Skill 是把可重複使用的工作流程封裝成模板。但 Skill 設計得不好，會變成一個太死板、無法適應不同情境的硬編碼流程。

參數化的概念：

好的 Skill 有明確的「輸入變數」，呼叫時填入具體的值，Skill 的流程根據這些值調整行為。

一個設計良好的參數化 Skill：

```markdown
# Skill: 新增 Repository Method

## 輸入參數
- ENTITY：操作的資料實體（例如 Order、User、Payment）
- METHOD_TYPE：操作類型（get_by_id / list_by_filter / create / update / delete）
- SPECIAL_REQUIREMENTS：任何特殊需求（選填）

## 執行步驟

### 步驟 1：理解現有模式
讀取 repositories/{ENTITY}Repository.py，
分析現有 method 的命名風格、參數格式、回傳型別、錯誤處理方式。
如果檔案不存在，讀取其他任意一個 Repository 作為參考。

### 步驟 2：實作 method
根據 METHOD_TYPE 和現有模式實作新的 method。
- get_by_id：回傳 Optional[{ENTITY}]
- list_by_filter：回傳 List[{ENTITY}]，支援分頁
- create：回傳新建的 {ENTITY}，失敗時 raise RepositoryError
- update：回傳更新後的 {ENTITY}，找不到時 raise NotFoundError
- delete：回傳 bool，找不到時 raise NotFoundError

如果有 SPECIAL_REQUIREMENTS，在符合以上規範的前提下處理。

### 步驟 3：補充測試
在 tests/repositories/test_{ENTITY}Repository.py 新增對應測試。
至少涵蓋：正常流程、資料不存在的情況、資料庫錯誤的情況。

### 步驟 4：驗證
執行 pytest tests/repositories/test_{ENTITY}Repository.py
回報結果。

## 禁止事項
- 不在 Repository 裡包含業務邏輯
- 不直接操作其他 Entity 的 table（跨 entity 操作透過 transaction service）

```

呼叫這個 Skill 的方式：

```auto
使用「新增 Repository Method」Skill：
ENTITY = Order
METHOD_TYPE = list_by_filter
SPECIAL_REQUIREMENTS = 需要支援按日期範圍和狀態複合篩選，
                       且結果要支援游標分頁（cursor-based pagination）

```

這樣的設計讓同一個 Skill 可以適應不同的 entity 和操作類型，不需要為每個情境寫一個獨立的 Skill。

Skill 的組織方式：

```auto
.claude/
└── skills/
    ├── add-repository-method.md
    ├── add-api-endpoint.md
    ├── code-review.md
    ├── write-migration.md
    └── debug-production-issue.md

```

每個 Skill 一個檔案，檔名清楚說明用途。需要使用時：

```auto
載入 .claude/skills/add-api-endpoint.md，
執行這個 Skill，參數如下：...

```

### 04｜設定檔納入版本控制的團隊意義

這不只是個人的好習慣，而是影響整個團隊協作品質的實踐。

應該 commit 的設定檔：

```auto
專案根目錄/
├── CLAUDE.md # 必須 commit
└── .claude/
    ├── config.json # 專案層級設定，必須 commit
    └── skills/ # 所有 Skill 檔案，必須 commit
        ├── add-endpoint.md
        ├── code-review.md
        └── write-migration.md

```

不應該 commit 的設定檔：

```auto
~/.claude/config.json # 個人全域設定，不 commit
.claude/config.local.json # 個人本地覆寫，加入 .gitignore

```

為什麼這對團隊很重要：

當 CLAUDE.md 和 Skill 檔案納入版本控制，整個團隊的 Claude Code 行為會趨於一致。新成員 clone 專案之後，Claude Code 就知道這個專案的架構規則、命名規範、禁止事項，不需要靠口耳相傳。

更重要的是：設定檔的演進歷史本身就是決策歷史。 當你在 CLAUDE.md 裡加了一條「不直接修改 migration 檔案」，commit message 應該說明為什麼，例如：

```auto
docs(claude): 禁止直接修改 migration 檔案

過去兩次事故都是因為手動修改了已部署的 migration，
導致 schema 和 migration 歷史不一致。
所有 migration 修改必須透過 alembic revision 指令新增。

```

六個月後新成員看到這條規則，能理解背後的原因，而不只是看到一條沒有脈絡的禁令。

### 05｜記憶系統的維護：什麼時候該更新

CLAUDE.md 和 Skill 不是寫完就不動的文件。它們需要隨著專案演進而更新，否則會從「有用的指引」變成「過時的誤導」。

觸發更新的訊號：

第一個訊號：你在 Session 裡重複說了三次以上的同一件事。

如果你發現自己在不同的 Session 裡一直說「對了，我們不用 ORM，直接用 raw SQL」，這條資訊應該進 CLAUDE.md，而不是繼續靠你記得說。

第二個訊號：Claude Code 做了一個「它不應該這樣做」的決定。

當 Claude Code 的判斷和你的預期不符，有兩種可能：一是指令不清楚，二是 CLAUDE.md 沒有涵蓋這個情境。釐清之後，把缺少的規則補進去。

第三個訊號：技術規範改變了。

換了測試框架、改了 error handling 的模式、引入了新的架構層。對應的 CLAUDE.md 和 Skill 要同步更新，否則它會照舊規範做事。

第四個訊號：某個 Skill 的輸出品質開始下降。

Skill 寫好之後不是永遠有效的。當 codebase 的結構改變，Skill 裡描述的路徑、模式、規範可能已經過時。定期回頭檢查 Skill 的輸出，確認它還在產生符合預期的結果。

維護的實際做法：

不需要定期排程「更新 CLAUDE.md」，而是把更新變成工作流程的一部分：

```auto
每個 Sprint 結束時，花 10 分鐘回顧：
- 這個 Sprint 裡有沒有重複說過的事？→ 補進 CLAUDE.md
- 有沒有 Claude Code 做了不符預期的決定？→ 補對應的規則
- 有沒有技術決策改變？→ 更新對應的規則和 Skill

```

把這個回顧變成習慣，CLAUDE.md 就會隨著專案成長而越來越準確，而不是越來越過時。

* * *

## ▌5. 驗證與品質控制

這可能是本文中，對實際產品品質影響最大的部分。

很多人把 Claude Code 的工作流程設計成：下指令 → 它執行 → 接受輸出。

這個流程在任務簡單、風險低的情況下沒問題。但當任務複雜度提高，沒有系統性的驗證機制，錯誤會在你不知情的情況下累積，直到某個時間點集中爆發。

### 01｜「完成」的定義要在任務開始前就說清楚

這條看起來像是第二章指令設計的重複，但角度不同。指令設計章節說的是「怎麼寫出好指令」，這裡說的是「為什麼驗證標準必須是指令的一部分，而不是事後補充的要求」。

沒有預先定義完成標準會發生什麼：

Claude Code 完成任務後，它會用自己的標準評估「完成了沒有」。它的標準通常是：程式碼語法正確、邏輯看起來合理、如果有跑測試的話測試通過。

這個標準和你的標準之間可能有很大的落差：

- 你的標準可能包含效能要求，它的標準沒有
- 你的標準可能包含某個特定的錯誤處理模式，它用了不同但技術上正確的模式
- 你的標準可能包含文件更新，它認為「程式碼改好了就完成了」

事後提出額外要求的成本：

當你在它說「完成了」之後才說「對了，還需要更新文件」，它需要重新理解當前狀態，可能已經消耗了大量 context，回應品質開始下降。更糟的是，它可能在「補文件」的過程中對已有的程式碼做出不必要的小調整，引入新的問題。

預先定義完成標準的模板：

```auto
任務完成的標準（全部達到才算完成）：

程式碼層面：
□ pytest tests/[相關測試檔案] 全部通過
□ mypy [相關檔案] 無錯誤
□ ruff check [相關檔案] 無警告

功能層面：
□ [具體的功能行為描述]
□ [邊界案例的處理方式]

文件層面：
□ docstring 更新（如果 public interface 有改變）
□ CHANGELOG.md 新增對應項目

完成後請逐條確認以上標準，
並回報每一條的驗證結果。

```

把這個模板存進你的 Skill 系統，每個任務開始前調整具體的內容，而不是每次從頭想。

### 02｜測試先行的工作流程

測試先行（Test First）在 Claude Code 的語境下，意義和傳統 TDD 略有不同。傳統 TDD 強調的是設計驅動，Claude Code 語境下的測試先行強調的是驗證標準的具象化。

在開始實作之前先寫測試，等於是把你對「正確行為」的理解，轉化成機器可以執行的規格。這個規格比自然語言描述更精確，也更難有歧義。

具體的工作流程：

```auto
# 第一步：描述行為，讓它寫測試
「針對 PaymentService.process_refund，先寫測試。
 不要實作，只寫測試。

 需要涵蓋的情境：
 1. 正常退款成功：金額正確退回，訂單狀態更新為 refunded
 2. 金額超過原始訂單金額：應拋出 InvalidRefundAmountError
 3. 訂單狀態不允許退款（例如已是 refunded）：
    應拋出 InvalidOrderStateError
 4. 金融系統呼叫失敗：應拋出 PaymentGatewayError，
    且不應改變訂單狀態（確認原子性）
 5. 部分退款：金額小於原始金額，狀態更新為 partially_refunded

 寫完之後跑測試，確認全部是紅燈（失敗）再告訴我。」

```

```auto
# 第二步：確認測試邏輯正確後，再開始實作
「測試邏輯正確。
 現在實作 process_refund，目標是讓所有測試通過。
 不要修改測試，只實作 method。」

```

```auto
# 第三步：測試全過後，考慮重構
「所有測試通過了。
 在不改變任何測試的前提下，
 看看實作有沒有可以整理的地方。
 如果有，說明你打算怎麼整理，等我確認再動。」

```

這個流程的關鍵價值：

測試是你和 Claude Code 之間對「正確」的共同定義。一旦測試寫好並確認邏輯正確，後續的實作和重構都有一個客觀的驗證標準，不需要靠你的主觀判斷來評估「改得對不對」。

### 03｜讓它 review 自己的輸出

在你接受任何輸出之前，讓 Claude Code 先對自己的工作做一次批判性的審查。

這聽起來像是讓它自己給自己打分數，效果有限。但實際上，生成輸出和審查輸出是兩個不同的認知過程。它在生成時做的是建構，在審查時做的是批判。兩個過程會發現不同的問題。

有效的自我 review 指令：

```auto
你剛才完成了 process_refund 的實作。
在我 review 之前，請你先做一次批判性的自我審查。

審查重點：
1. 情境 4（金融系統失敗）的原子性是否真的保證了？
   如果在扣款成功但更新訂單狀態失敗的情況下，
   系統的狀態是什麼？
2. 所有的自訂 Exception 是否都有足夠的資訊讓呼叫端判斷如何處理？
3. 有沒有任何你在實作時做了假設但沒有明確說出來的地方？
4. 測試有沒有測到你實際實作的邏輯，
   還是測試在測一個你以為會發生但實際上不會發生的情境？

誠實地回報你發現的問題，即使需要修改你剛才的輸出。

```

這個步驟最有價值的地方：

第四點——讓它審查測試本身是否真的在測它實作的邏輯——是人工 review 最容易忽略的盲點。測試通過了，但測試測的是錯誤的東西，這種情況比你想像的更常見。

### 04｜讓它 review 你的輸出

反過來，你自己寫的程式碼，也可以讓 Claude Code 做 review。這不是因為你比它差，而是因為它有幾個人工 review 做不到的優勢。

Claude Code 做 code review 的獨特優勢：

- 不會因為看太久而麻木：人工 review 大量 diff 時，注意力會下降，後面的內容容易漏看。它不會。
- 對 pattern 的記憶比人強：它可以同時記住整個 codebase 的命名規範、架構模式，不會因為「這個 reviewer 不熟這個模組」而漏掉不一致的地方。
- 沒有社交顧慮：它不會因為這是資深工程師寫的就不敢指出問題。

設計有效的 review 指令：

```auto
請 review 以下 git diff。
這是我自己寫的程式碼，不是你生成的。

重點檢查以下項目，每項都要明確回答有沒有問題：

1. 邏輯正確性
   - 是否有邏輯錯誤或遺漏的 edge case？

2. 錯誤處理
   - 所有可能的失敗路徑是否都有處理？
   - Exception 的型別和訊息是否足夠讓呼叫端判斷？

3. 架構一致性（參照 CLAUDE.md 的規範）
   - 是否有違反分層架構的地方？
   - 命名是否符合現有規範？

4. 測試品質
   - 測試是否真的在測實作邏輯？
   - 有沒有明顯缺少的測試案例？

5. 你個人認為最值得關注的一個問題
   （不限於以上四類）

[貼上 git diff]

```

讓 review 更有針對性：

你對自己的弱點比 Claude Code 更了解。如果你知道自己習慣性地忽略 null check、或是容易在 async 程式碼裡製造 race condition，把這些加進 review checklist，讓它特別關注你的盲點。

### 05｜什麼程度的輸出值得信任，什麼程度需要人工複查

不是所有 Claude Code 的輸出都需要同樣強度的驗證。把驗證資源集中在高風險的輸出，低風險的輸出用輕量的方式確認，是有效率的品質控制。

風險分級的判斷框架：

低風險輸出（輕量驗證即可）：

- 新增的功能有完整的測試覆蓋，且測試是先於實作寫好的
- 修改範圍完全在一個獨立模組內，沒有跨越模組邊界
- 有明確的 rollback 機制（例如 feature flag）
- 修改的是新建的程式碼，不是改動現有的邏輯

輕量驗證：跑測試、快速掃一遍 diff、確認沒有明顯的問題。

中風險輸出（需要仔細 review）：

- 修改了現有的業務邏輯
- 跨越了模組邊界，影響到多個地方
- 改動了 public interface（即使是向後相容的改動）
- 涉及並發、快取、或狀態管理的程式碼

仔細 review：逐行看 diff、確認測試覆蓋了所有修改路徑、讓它做自我 review。

高風險輸出（必須人工深度審查）：

- 涉及認證、授權、資料加密的程式碼
- 資料庫 migration
- 改動了對外的 API contract
- 涉及金融交易或不可逆操作的邏輯
- 效能關鍵路徑的修改

深度審查：除了以上所有步驟，還需要在 staging 環境實際驗證、考慮讓另一個人也 review、可能需要額外的壓力測試或安全審查。

一個容易忽略的原則：

當你不確定某個輸出的風險等級時，預設往高一級處理。驗證的成本遠低於修復生產環境問題的成本。

* * *

## ▌6. 工具整合

工具整合是 Claude Code 能力邊界的延伸機制。原生的 Claude Code 能做的事是有限的：讀寫本地檔案、執行 bash 指令、理解程式碼。透過 MCP（Model Context Protocol），這個邊界可以向外擴展到幾乎任何系統。

但工具整合也是最容易踩坑的領域。整合得好，Claude Code 的能力成倍放大。整合得不好，複雜度上升、debug 困難、而且問題出現時很難定位根源。

### 01｜MCP 的正確心智模型：能力擴充，不是魔法

很多人第一次接觸 MCP 時，把它理解成「讓 Claude Code 連上外部服務」。這個理解方向對，但不夠精確，容易產生錯誤的預期。

更精確的理解：

MCP 是一個標準化的介面協議，讓 Claude Code 能夠呼叫外部定義的工具（tools）。每個 MCP server 對外暴露一組工具，每個工具有明確的名稱、描述、和參數格式。Claude Code 在執行任務時，會根據工具的描述判斷什麼時候需要呼叫哪個工具。

這個架構有幾個重要的含意：

第一，Claude Code 的判斷基於工具的描述，不是工具的實作。

如果一個工具的描述寫得不清楚，Claude Code 可能在不適當的時機呼叫它，或是在應該呼叫時沒有呼叫。工具描述的品質直接影響整合效果。

第二，MCP 只是橋樑，外部系統的限制仍然存在。

Claude Code 透過 MCP 呼叫 Linear API，並不代表它突破了 Linear API 的 rate limit、權限控制、或資料範圍限制。外部系統的所有約束依然適用。

第三，工具呼叫是同步的，會佔用 context。

每次工具呼叫的請求和回應都會佔用 context window 的空間。如果一個任務需要大量的工具呼叫，context 消耗會比純文字任務快得多。

正確的預期設定：

MCP 讓 Claude Code 獲得它原本沒有的能力，但這些能力的邊界由外部系統決定，不是由 Claude Code 決定。整合之後，Claude Code 能做的事是「在它的判斷能力範圍內，操作外部系統能做的事」，兩者的交集，不是兩者的聯集。

### 02｜選現成 MCP 還是自建的判斷標準

面對一個整合需求，第一個決策點是：用現成的開源 MCP server，還是自己建一個？

優先選現成 MCP 的情況：

- 目標服務是主流工具（GitHub、Linear、Notion、Slack 等），社群已有維護良好的 MCP server
- 你需要的功能是該服務的標準操作，現成 MCP 已經涵蓋
- 團隊沒有維護自建 MCP server 的資源

現成 MCP 的主要優點是零開發成本、有社群維護、文件相對完整。缺點是你無法完全控制它的行為，遇到問題時 debug 路徑更長。

應該自建 MCP 的情況：

- 目標是公司內部系統，沒有現成的 MCP server
- 現成 MCP server 的功能不符合需求，需要客製化
- 需要整合多個內部系統，自建一個統一的 MCP server 比串接多個獨立的更合理
- 對安全性有嚴格要求，不希望透過第三方 MCP server 傳遞敏感資料

一個常被忽略的中間選項：

在決定自建之前，先評估能不能用 bash 工具解決。很多「需要 MCP 整合」的需求，實際上可以靠一個簡單的 shell script 加上 Claude Code 的 bash 執行能力來完成，不需要完整的 MCP server 架構。

```bash
# 例如，查詢內部 API 不一定需要 MCP
# 一個簡單的 wrapper script 就夠了
#!/bin/bash
# internal_api.sh
curl -H "Authorization: Bearer $INTERNAL_API_TOKEN" \
     "https://internal.company.com/api/$1"

```

然後在 CLAUDE.md 裡說明這個 script 的存在和用途，Claude Code 就可以在需要時直接呼叫它。這個方案的維護成本遠低於完整的 MCP server。

### 03｜自建 MCP 的最小可行設計

如果評估後確定需要自建，從最小可行的範圍開始，不要一開始就設計大而全的系統。

最小可行 MCP server 的設計原則：

只做唯讀操作。

第一版只實作查詢類的工具（get、list、search），不實作寫入操作。唯讀操作的風險極低，可以快速驗證整合是否正常運作。寫入操作在確認整合穩定之後再加。

每個工具只做一件事。

不要設計「萬能工具」，例如「操作工單系統」這樣的工具太寬泛。應該是「get\_ticket」、「list\_tickets\_by\_assignee」、「search\_tickets\_by\_keyword」這樣的細粒度工具。細粒度的工具讓 Claude Code 更容易判斷什麼時候用哪個，也讓 debug 更容易。

工具描述比實作更重要。

每個工具的 description 要精確說明：這個工具做什麼、什麼時候應該用它、回傳的資料格式是什麼。Claude Code 完全依賴這個描述來判斷是否呼叫這個工具。

一個實際的最小可行範例（Python）：

```python
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import httpx
import os

server = Server("company-internal-v1")

@server.list_tools()
async def list_tools():
    return [
        types.Tool(
            name="get_ticket",
            description="""從公司內部工單系統取得單一 ticket 的詳細資訊。
            使用時機：當需要了解特定 ticket 的內容、狀態、負責人時。
            回傳：ticket 的標題、描述、狀態、負責人、建立時間。
            注意：只能查詢你有權限存取的 ticket。""",
            inputSchema={
                "type": "object",
                "properties": {
                    "ticket_id": {
                        "type": "string",
                        "description": "Ticket ID，格式為 PROJ-1234"
                    }
                },
                "required": ["ticket_id"]
            }
        ),
        types.Tool(
            name="list_my_open_tickets",
            description="""列出目前指派給當前使用者的所有未完成 ticket。
            使用時機：需要了解目前有哪些待處理工作時。
            回傳：ticket 列表，每個包含 id、標題、優先級、最後更新時間。
            限制：最多回傳 50 筆，按優先級排序。""",
            inputSchema={
                "type": "object",
                "properties": {},
                "required": []
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    token = os.environ.get("INTERNAL_API_TOKEN")
    if not token:
        raise ValueError("INTERNAL_API_TOKEN 環境變數未設定")

    async with httpx.AsyncClient() as client:
        if name == "get_ticket":
            ticket_id = arguments["ticket_id"]
            response = await client.get(
                f"https://internal.company.com/api/tickets/{ticket_id}",
                headers={"Authorization": f"Bearer {token}"},
                timeout=10.0
            )
            response.raise_for_status()
            data = response.json()
            # 只回傳必要欄位，不回傳整個 API response
            result = {
                "id": data["id"],
                "title": data["title"],
                "description": data["description"],
                "status": data["status"],
                "assignee": data["assignee"]["name"],
                "created_at": data["created_at"]
            }
            return [types.TextContent(
                type="text",
                text=str(result)
            )]

        elif name == "list_my_open_tickets":
            response = await client.get(
                "https://internal.company.com/api/tickets",
                params={"assignee": "me", "status": "open", "limit": 50},
                headers={"Authorization": f"Bearer {token}"},
                timeout=10.0
            )
            response.raise_for_status()
            data = response.json()
            tickets = [
                {
                    "id": t["id"],
                    "title": t["title"],
                    "priority": t["priority"],
                    "updated_at": t["updated_at"]
                }
                for t in data["tickets"]
            ]
            return [types.TextContent(
                type="text",
                text=str(tickets)
            )]

async def main():
    async with stdio_server() as streams:
        await server.run(
            *streams,
            server.create_initialization_options()
        )

if __name__ == " __main__":
    import asyncio
    asyncio.run(main())

```

幾個實作細節值得注意：

只回傳必要欄位，不把整個 API response 丟給 Claude Code。API response 往往包含大量 Claude Code 不需要的欄位，全部回傳會不必要地佔用 context window。

明確設定 timeout，避免外部 API 沒有回應時整個工具呼叫無限等待。

認證資訊一律從環境變數讀取，不在程式碼裡 hardcode，也不在 MCP server 的設定檔裡明文儲存。

### 04｜MCP 的 debug 方法論

MCP 整合出問題時，錯誤可能發生在四個不同的層：Claude Code 的判斷層、MCP 協議層、MCP server 的實作層、外部系統層。有系統的 debug 方法論可以大幅縮短定位問題的時間。

逐層排查的流程：

第一層：確認 MCP server 是否正常啟動。

```bash
# 直接執行 MCP server，看有沒有啟動錯誤
python your_mcp_server.py

# 或檢查 Claude Code 的 MCP 連線狀態
# 在 Claude Code 裡執行：
/mcp

```

如果 MCP server 連不上，後面的層都不需要看。

第二層：確認工具列表是否正確載入。

```auto
# 在 Claude Code Session 裡問它：
「列出你目前可以使用的所有工具，包括來自 MCP 的工具。」

```

如果它列不出你期望的工具，問題在 MCP server 的 `list_tools` 實作，或是 Claude Code 的 MCP 設定檔。

第三層：獨立測試工具呼叫。

```auto
# 要求 Claude Code 直接呼叫特定工具，
# 不要讓它自己判斷要不要呼叫：
「請直接呼叫 get_ticket 工具，ticket_id 是 PROJ-1234，
 不管結果如何都回報給我。」

```

如果工具呼叫失敗，看錯誤訊息判斷是 MCP server 的問題還是外部 API 的問題。

第四層：直接測試外部 API。

```bash
# 繞過 MCP，直接呼叫外部 API
curl -H "Authorization: Bearer $INTERNAL_API_TOKEN" \
     "https://internal.company.com/api/tickets/PROJ-1234"

```

如果直接呼叫也失敗，問題在外部系統（認證、權限、API 本身的問題），和 Claude Code 無關。

一個容易忽略的 debug 工具：

在 MCP server 的實作裡加上詳細的 logging，把每次工具呼叫的請求參數和回應都記錄下來。這在 debug 時可以讓你精確看到 Claude Code 傳了什麼參數、外部 API 回傳了什麼，不需要靠猜測。

```python
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger( __name__ )

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    logger.debug(f"工具呼叫：{name}，參數：{arguments}")
    # ... 實作 ...
    logger.debug(f"工具回應：{result}")
    return result

```

### 05｜工具鏈的複雜度管理

隨著整合的工具越來越多，複雜度會快速上升。工具鏈的複雜度管理是一個長期問題，不是一次性的設計決策。

複雜度上升的警訊：

- Claude Code 開始呼叫錯誤的工具（把本來應該用工具 A 的情境用了工具 B）
- 工具呼叫的頻率異常高，消耗大量 context
- 某個任務失敗了，但你不確定是哪個工具出了問題
- 新加入的工具和現有工具的描述有重疊，讓 Claude Code 難以判斷要用哪個

管理複雜度的實際做法：

工具數量控制。

每個 MCP server 的工具數量建議不超過 10-15 個。超過這個數量，Claude Code 在選擇工具時的準確率會開始下降。如果工具很多，考慮按功能領域拆成多個 MCP server，在 CLAUDE.md 裡說明每個 server 負責的範疇。

工具描述的唯一性原則。

每個工具的描述要能讓 Claude Code 清楚區分它和其他工具的差別。如果兩個工具的描述讀起來很像，要明確在描述裡說明它們的差異和各自的適用情境。

```markdown
# 容易混淆的描述（不好）
get_order：取得訂單資訊
get_order_detail：取得訂單詳細資訊

# 清楚區分的描述（好）
get_order：取得訂單的摘要資訊（id、狀態、總金額、建立時間）。
           適用於需要快速確認訂單狀態、不需要明細的情況。
           
get_order_detail：取得訂單的完整資訊，包含所有商品明細、
                  物流資訊、付款紀錄、歷史狀態變更。
                  適用於需要深入分析特定訂單的情況。
                  注意：回傳資料量較大，只在必要時使用。

```

定期審查工具使用情況。

每隔一段時間，回顧一下哪些工具被頻繁使用、哪些幾乎從來不被用。幾乎不被用的工具可能是描述寫得不好（讓 Claude Code 不知道什麼時候用它），也可能是這個工具的需求本來就很少，可以考慮移除。

* * *

## ▌7. 常見失敗模式

前面六項主題，討論的是「怎麼做對」。本主題討論的是「為什麼會做錯」。

失敗模式和踩坑清單的差別在於：踩坑清單告訴你「不要做 X」，失敗模式分析告訴你「為什麼你會自然而然地走向 X、X 會怎麼讓你付出代價、以及怎麼建立系統來避免它」。

知道不該做什麼不夠，你需要理解失敗的機制，才能在它發生之前認出它。

### 01｜速度陷阱：跑得快但方向錯

這是使用 Claude Code 之後最常見的第一個失敗模式，而且通常要等到損失已經造成才會被發現。

陷阱的機制：

Claude Code 的執行速度很快。一個任務可能在幾分鐘內就有大量的輸出：程式碼修改、測試、文件。這個速度會產生一種「進展感」，讓你覺得事情在快速往前走。

問題是，速度和方向是兩個獨立的維度。你可以很快地朝錯誤的方向前進。

速度陷阱的具體場景：

你給了一個描述不夠精確的任務，Claude Code 做了一個「合理但不是你要的」的解釋，然後快速地在這個錯誤的解釋上建構了大量的輸出。你因為看到大量輸出而感到滿意，沒有在早期確認方向，等到最後才發現整個方向跑偏了。

這時你面對的不只是一個錯誤，而是一大堆建立在錯誤基礎上的輸出，要全部推翻重來。

速度陷阱的特徵：

- 任務初期沒有讓它彙報理解和計畫，直接讓它開始做
- 中途沒有設置確認節點，讓它一口氣跑完
- 看到大量輸出就覺得進展良好，沒有仔細確認方向

系統性的預防機制：

任何超過一個檔案修改的任務，都要求它在開始實作之前先說明計畫：

```auto
在開始任何修改之前，先告訴我：
1. 你理解這個任務的目標是什麼
2. 你打算修改哪些檔案、每個檔案改什麼
3. 你預期的完成結果是什麼

等我確認計畫正確之後再開始。

```

這個步驟花不了幾分鐘，但可以在方向錯誤的時候，把損失控制在「計畫需要修正」而不是「大量輸出需要推翻」。

### 02｜信任陷阱：它說完成就以為完成

這個失敗模式的危險程度在於：它不會立即顯現。程式碼在開發環境跑得好好的，測試通過，它也說完成了。問題在幾天後、幾週後、或是上線後才出現。

陷阱的機制：

Claude Code 的語氣天然傾向於確定。它說「完成了」、「測試全部通過」、「這個實作是正確的」，語氣和它真的確定時完全一樣。這不是它在說謊，而是它的輸出模式就是這樣設計的。

加上它確實完成了大部分的工作，很容易讓你建立「它說完成就是完成了」的習慣。這個習慣在低風險任務上沒有明顯問題，但在高風險任務上會積累成嚴重的品質問題。

信任陷阱的幾種典型變體：

變體一：測試通過但測試寫錯了。

它寫的測試在語法上正確，邏輯上也看起來合理，但測試的斷言沒有真正驗證到你在意的行為。測試通過只代表「它寫的測試通過了」，不代表「你在意的行為是正確的」。

變體二：修好了這條路徑，但沒修另一條。

你報告了一個 bug 的具體觸發方式，它修好了那個特定的觸發路徑，但根本原因沒有解決，只是那個特定的情境不會觸發了。其他情境下同樣的問題依然存在。

變體三：功能正確但效能有問題。

它實作的功能邏輯完全正確，測試也通過，但在真實資料規模下有 N+1 query 問題或記憶體洩漏。這類問題在測試環境的小資料量下完全不會顯現。

變體四：當下正確但未來會壞。

它的實作依賴了某個外部系統的當前行為，但這個行為在文件裡標注為「不保證穩定」。它沒有注意到這個標注，你也沒有。

建立系統性的驗證習慣：

不依賴它的自我評估，建立獨立的驗證清單。依任務的風險等級，選擇對應強度的驗證：

```auto
低風險任務：
□ 跑相關測試，確認通過
□ 快速掃一遍 diff，確認沒有明顯問題

中風險任務：
□ 跑完整測試套件
□ 逐行看 diff
□ 讓它做自我 review
□ 確認測試本身的邏輯正確

高風險任務：
□ 以上所有步驟
□ 在 staging 環境實際執行
□ 考慮讓另一個人也 review
□ 確認邊界案例和錯誤路徑都有測試

```

### 03｜脈絡陷阱：Session 狀態污染

這個失敗模式很隱蔽，因為它的症狀看起來像「Claude Code 變笨了」，而不是「我的工作流程有問題」。

陷阱的機制：

在一個 Session 裡，Claude Code 對 codebase 的理解是動態建構的。Session 初期它讀了某些檔案，建立了某個理解。隨著對話進行，這個理解會被後續的資訊修改、補充、有時也會被覆蓋。

問題是，當 Session 變長、做了多件事之後，它的理解可能處於一個混合狀態：部分基於 Session 初期讀取的舊版程式碼，部分基於它自己修改後的新版程式碼，部分基於你中途補充的資訊。這個混合狀態不是任何一個時間點的真實狀態，是一個被污染的脈絡。

脈絡污染的具體症狀：

- 它對同一個 function 的描述在 Session 前期和後期不一致
- 它修改了一個它「以為」還是舊版的東西，但那個東西其實已經在這個 Session 裡被改過了
- 它引用了一個你在 Session 中途說「不要用這個做法」的模式
- 它的回應開始出現自相矛盾的地方

脈絡污染的高發情境：

- Session 持續超過 30-40 個來回
- 在同一個 Session 裡先做了 A，又根據 A 的結果做了 B，又根據 B 的結果做了 C
- 中途多次改變了任務的方向或範圍
- 讓它讀了大量的檔案，context 佔用量很高

預防和處理：

預防的根本方法是控制 Session 的長度和範圍，一個 Session 只做一件清楚定義的事。

當你感覺到脈絡污染的症狀時，不要繼續在同一個 Session 裡試圖修正，直接開新 Session。在新 Session 的開場，明確說明當前的狀態：

```auto
新 Session。當前狀態：
- 剛完成了 [已完成的任務]，相關 commit 是 [commit hash]
- 接下來要做的是 [新任務]
- 特別注意：[任何需要明確說明的當前狀態]

請先用 git log --oneline -5 確認當前的 commit 狀態，
再開始工作。

```

### 04｜規模陷阱：小資料通過、真實環境爆炸

這個失敗模式的代價往往在上線後才顯現，而且很難快速回滾。

陷阱的機制：

Claude Code 在開發和測試環境裡工作。這些環境的資料量通常遠小於生產環境，並發量也低，資料的分布也比生產環境乾淨。它寫出來的程式碼在這個環境裡完全正確，但有些問題只有在生產環境的規模下才會顯現。

規模陷阱的幾種常見形式：

N+1 Query 問題：

它實作的查詢邏輯在 10 筆資料下執行時間 50ms，完全感覺不到問題。但在 10 萬筆資料下，同樣的邏輯可能需要執行 10 萬次資料庫查詢，讓整個系統癱瘓。

記憶體問題：

它把整個查詢結果載入記憶體再做處理。測試資料 100 筆，完全沒問題。生產資料 100 萬筆，記憶體直接爆掉。

鎖競爭問題：

它的實作在低並發下完全正常。但在生產環境的高並發下，某個地方的鎖競爭讓系統的吞吐量驟降，甚至造成死鎖。

資料品質問題：

測試資料是乾淨的，每個欄位都有值，格式都正確。生產資料裡有 null 值、有格式異常的歷史資料、有各種邊界情況。它的程式碼沒有處理這些情況，上線後第一個不乾淨的資料就讓系統崩潰。

在指令層面預防規模問題：

對任何涉及資料查詢或處理的任務，在指令裡明確說明規模預期：

```auto
實作這個查詢功能時，請考慮以下規模：
- 資料量：orders 表目前有 500 萬筆，每天新增約 1 萬筆
- 並發：峰值約 200 個並發請求
- 資料品質：有約 3% 的歷史資料有 null 欄位

實作完成後，請主動說明：
1. 這個實作在上述規模下的預期效能
2. 有沒有潛在的 N+1 query 問題
3. 記憶體使用量的預期
4. 對 null 值的處理方式

```

讓它在實作時就考慮規模問題，比事後發現問題再修要省很多時間。

### 05｜依賴陷阱：套件升級的隱性風險

套件版本管理是一個看起來簡單、實際上充滿隱性風險的領域。讓 Claude Code 管理套件升級時，這些風險會被放大。

陷阱的機制：

Claude Code 對套件版本的知識來自訓練資料的截止日期。它可能不知道某個套件在最新版本裡有 breaking change、某個套件的行為在新版裡有細微但重要的改變、或是某個套件目前有已知的安全漏洞需要特定方式處理。

更危險的是，它傾向於把「測試通過」等同於「升級安全」。但如前所述，測試通過只代表現有測試覆蓋的行為沒有改變，不代表所有行為都沒有改變。

依賴陷阱的幾種形式：

直接依賴的 breaking change：

它把某個套件從 v2 升到 v3，v3 有 breaking change，但它沒有仔細讀 CHANGELOG，或是它的訓練資料裡沒有這個版本的資訊，結果某些功能在新版下行為改變了，但測試沒有覆蓋到。

間接依賴的連鎖反應：

你的直接依賴沒有升版，但它升級了一個套件的間接依賴。間接依賴的行為改變比直接依賴更難追蹤，因為你通常不會直接意識到它的存在。

時間炸彈：

新版套件標注了某個 API 為 deprecated，會在下一個 major version 移除。現在還能用，但六個月後當你再次升級，這個 API 消失了，造成意外的 breaking change。

正確的套件升級流程：

不要讓 Claude Code 一次升級所有套件。給它一個嚴格的流程：

```auto
套件升級流程（每次只升一個）：

1. 確認目標套件的當前版本和目標版本
2. 讀取該套件從當前版本到目標版本的 CHANGELOG，
   特別標注所有 breaking change 和行為改變
3. 評估這些改變對我們的 codebase 的影響
4. 如果有影響，先說明需要哪些對應的程式碼修改，
   等我確認後再執行升級
5. 執行升級
6. 跑完整測試套件
7. 特別針對 CHANGELOG 裡標注的改變，
   確認對應的行為是否如預期

每個套件升級成功後單獨 commit，再進行下一個。

```

### 06｜理解陷阱：codebase 是它寫的但你看不懂

這是六個失敗模式裡最長期、影響最深遠的一個。它不會在某次任務後立即爆發，而是隨著時間慢慢積累，最終讓整個專案的可維護性崩潰。

陷阱的機制：

Claude Code 的速度和能力讓你很容易養成一個習慣：接受它的輸出，確認能跑，然後繼續下一個任務。這個習慣在短期內提高了效率，但每次這樣做，你對自己 codebase 的理解就下降一點。

累積下來，你的 codebase 裡有越來越多你能跑但說不清楚的程式碼。你知道它能做什麼，但你不知道它為什麼這樣實作、它依賴了什麼假設、它在什麼情況下會出問題。

這個狀態在日常正常運作時不會有明顯症狀。但當問題出現時——上線後的 bug、效能問題、需要修改某個你沒有真正理解的模組——你會發現自己完全無法獨立處理，只能再次依賴 Claude Code。這是一個自我強化的依賴循環。

理解陷阱的早期警訊：

- 有人問你「這段程式碼在做什麼」，你說不清楚
- 你需要修改一個模組，但你不確定改了之後會影響哪些地方
- 你看著一段程式碼，知道它是最近加的，但想不起來為什麼這樣寫
- 你在 code review 裡批准了一個你沒有真正理解的 PR

在工作流程裡建立理解的機制：

第一，讓它解釋，不只是讓它做：

```auto
實作完成後，用非技術語言解釋這個實作：
1. 整體的設計思路是什麼
2. 最關鍵的三個設計決策是什麼、為什麼這樣決定
3. 這個實作依賴了哪些假設，如果假設不成立會怎樣
4. 未來如果要修改這個模組，最需要注意什麼

```

第二，定期進行「理解審計」：

每隔一段時間，隨機選取幾個最近由 Claude Code 生成或修改的模組，試著向自己解釋它在做什麼、為什麼這樣做。說不清楚的地方，回去讀程式碼，或是讓 Claude Code 解釋。

第三，讓理解成為完成標準的一部分：

```auto
這個任務的完成標準包括：
- 功能正確（測試通過）
- 我能夠向團隊成員解釋這個實作的設計思路
  （你需要在完成後給我一個可以用來解釋的摘要）

```

最根本的心態：

Claude Code 是你的工程夥伴，不是你的替代品。它寫的程式碼是你的 codebase，你需要對它負責。你能夠對某段程式碼負責的前提，是你真正理解它。

速度是手段，理解是底線。不能理解的程式碼，不管跑得多好，都是未來的風險。

* * *

## ▌8. 團隊協作

前七個主題討論的大多是個人使用的視角。但在真實的工程環境裡，Claude Code 通常不是只有你一個人在用。當整個團隊都在使用 Claude Code，而每個人的使用方式、設定、和品質標準都不一樣，問題就會從個人層面升級到組織層面。

以下為你說明：如何讓 Claude Code 在團隊裡成為一個一致的、可預期的工程工具，而不是每個人各自為政的個人助理。

### 01｜讓 Claude Code 的行為在團隊內一致

當團隊裡有五個人都在用 Claude Code，如果每個人的設定不同，會發生什麼：

A 的 Claude Code 知道這個專案不能直接改 migration 檔案，B 的不知道。A 產出的程式碼遵循 repository pattern，C 產出的直接在 service 層操作資料庫。D 的 Claude Code 每次完成任務都會跑測試驗證，E 的從來不跑。

結果是：codebase 裡混雜了不同風格、不同規範、不同品質標準的程式碼。Code review 變得困難，因為 reviewer 不確定哪些差異是刻意的技術選擇，哪些是 Claude Code 自己發揮的結果。技術債以前所未有的速度累積。

一致性的核心機制是共享設定：

把所有影響 Claude Code 行為的設定納入版本控制，讓每個人 clone 專案之後，Claude Code 的行為就自動一致。

```auto
專案根目錄/
├── CLAUDE.md # 專案層級規範
└── .claude/
    ├── config.json # 工具設定（MCP server 等）
    └── skills/ # 共享的 Skill 庫
        ├── add-endpoint.md
        ├── write-migration.md
        ├── code-review.md
        └── debug-issue.md

```

CLAUDE.md 作為團隊規範的載體：

CLAUDE.md 不只是給 Claude Code 看的文件，也是團隊工程規範的一份具體化記錄。它應該涵蓋的內容和一份好的「新人入職工程規範」高度重疊：

```markdown
# [專案名稱] 工程規範

## 架構概述
[專案的分層架構說明]

## 核心規則
這些規則適用於所有程式碼修改，
不管是人寫的還是 AI 生成的：

1. Service 層不直接操作資料庫
2. 所有 public method 必須有 type hint
3. 所有新功能必須有對應的測試
4. Migration 只能透過 alembic revision 新增，
   不能直接修改現有 migration 檔案

## 禁止事項
[明確列出絕對不能做的事]

## 驗證標準
每次任務完成的最低驗證標準：
- pytest 相關測試通過
- mypy 無錯誤
- ruff check 無警告

```

這份文件同時服務兩個讀者：Claude Code（每個 Session 自動載入）和新加入的團隊成員（了解專案規範的第一份文件）。

### 02｜Skill 和 CLAUDE.md 的共同維護機制

共享設定納入版本控制只是第一步。更難的問題是：這些設定怎麼維護？誰負責更新？更新的流程是什麼？

沒有維護機制的常見結果：

CLAUDE.md 在專案初期寫好，之後就沒有人更新。六個月後技術規範已經改變，但 CLAUDE.md 還停留在舊版，Claude Code 照著過時的規範做事，產出不符合現在標準的程式碼。Skill 也一樣：寫好之後沒有人維護，隨著 codebase 結構改變，Skill 的輸出品質越來越差，最後大家就不用了。

建立維護機制的幾個具體做法：

第一，指定維護負責人。

CLAUDE.md 和 Skill 庫應該有明確的負責人（通常是 tech lead 或 senior engineer）。負責人不需要獨自維護所有內容，但需要確保維護工作有在發生，以及評估 PR 裡對這些檔案的修改。

第二，讓更新成為日常工作流程的一部分。

不要等到「有空的時候」再更新 CLAUDE.md，因為那個時間通常不會到來。把更新嵌入現有的工作流程：

```auto
Sprint 結尾的 retrospective 增加一個固定議題：
「這個 Sprint 裡，有沒有需要更新 CLAUDE.md 或 Skill 的地方？」

技術決策被做出時（例如換了 ORM、改了錯誤處理模式），
把更新 CLAUDE.md 列為這個決策的交付物之一。

新的 Skill 需求出現時（例如有人說「我每次都要重複說同樣的事」），
把建立 Skill 列為技術工作的一部分。

```

第三，Skill 和 CLAUDE.md 的 PR 需要特別的 review。

對這些檔案的修改影響範圍比一般程式碼更大，因為它會改變所有人的 Claude Code 行為。建議：

- 修改 CLAUDE.md 或 Skill 的 PR 需要至少兩個人 review
- PR 描述要說明為什麼要做這個改動、預期的影響是什麼
- Merge 後主動通知團隊，讓大家知道規範有更新

第四，版本化重要的設定變更。

當 CLAUDE.md 有重大的規範改變（例如從一個架構模式切換到另一個），在 CHANGELOG 裡記錄這個改變，說明從什麼版本開始適用新規範。這樣當你在看舊的 code 時，能夠理解為什麼那時候的程式碼和現在的規範不一樣。

### 03｜AI 生成的程式碼如何做 Code Review

當團隊開始大量使用 Claude Code，code review 的性質會改變。reviewer 面對的不再是「同事寫的程式碼」，而是「同事用 Claude Code 生成的程式碼」。這兩者需要不同的 review 策略。

AI 生成程式碼的特徵：

- 語法和風格通常正確：Claude Code 很少犯語法錯誤或明顯的風格問題，這些問題在 review 時往往不是重點
- 邏輯可能過度自信：它的實作看起來完整，但可能在邊界案例上有問題
- 可能缺乏業務脈絡：技術上正確，但沒有反映業務規則或歷史決策的細節
- 測試可能測錯方向：測試覆蓋率看起來不錯，但測試在驗證錯誤的行為

針對 AI 生成程式碼的 review 重點調整：

傳統 code review 的重點通常是：語法、風格、邏輯、測試覆蓋。

針對 AI 生成程式碼，重點應該調整為：

```auto
降低關注：
- 語法正確性（通常不是問題）
- 基本風格一致性（如果有 linter 自動檢查）

提高關注：
- 業務邏輯的正確性
  （它有沒有正確理解業務規則，不只是技術規則）
- 邊界案例和錯誤路徑
  （測試有沒有覆蓋到真實環境會遇到的情況）
- 對現有架構的影響
  （它的修改有沒有破壞任何隱性的架構假設）
- 可維護性
  （這段程式碼，不看 Claude Code 的生成脈絡，
   還能不能被人理解和維護）

```

PR 描述的新標準：

當使用 Claude Code 生成的程式碼提 PR，PR 描述應該包含：

```markdown
## 這個 PR 做了什麼
[功能描述]

## 技術決策說明
[說明主要的設計選擇和原因，
 特別是那些 Claude Code 自己做的判斷]

## 驗證方式
[說明如何驗證這個 PR 的正確性，
 包括測試覆蓋了哪些情境]

## 已知限制
[任何已知的邊界案例、效能限制、
 或未來需要改進的地方]

## AI 生成的部分
[說明哪些部分是 Claude Code 生成的、
 哪些是人工調整的，
 以及人工 review 的重點在哪裡]

```

最後一個區塊「AI 生成的部分」值得特別說明。透明地標注哪些是 AI 生成的，讓 reviewer 知道把注意力集中在哪裡，也讓未來維護這段程式碼的人理解它的來源和背景。

### 04｜什麼應該讓 Claude Code 做，什麼應該人自己寫

這是一個需要團隊明確討論和達成共識的問題，不能讓每個人各自決定。

不同的分工策略會產生截然不同的結果：

如果沒有共識，自然的傾向是「什麼都讓 Claude Code 做，因為它快」。這個策略在短期內提高了速度，但長期會讓團隊對 codebase 的理解集體下降，形成前一章提到的理解陷阱的團隊版本。

一個實用的分工框架：

以「重要性」和「重複性」兩個維度來判斷：

```auto
高重要性 + 低重複性：
→ 人主導，Claude Code 輔助
範例：核心業務邏輯設計、架構決策、
      安全關鍵的實作、性能關鍵路徑

高重要性 + 高重複性：
→ 人設計 Skill，Claude Code 執行，人驗證
範例：標準的 CRUD 實作、測試撰寫、
      API endpoint 新增

低重要性 + 低重複性：
→ Claude Code 主導，人做基本確認
範例：文件整理、程式碼格式化、
      簡單的重構

低重要性 + 高重複性：
→ 完全自動化，不需要 Claude Code 介入
範例：linting、格式化、簡單的 CI 檢查

```

有幾類程式碼建議永遠由人主導撰寫：

第一，認證和授權邏輯。這類程式碼的錯誤影響面廣，且錯誤的方式往往不會被一般測試發現。人需要深入理解這段邏輯，不能只是確認「測試通過」。

第二，資料 migration。每個 migration 都是不可逆的，錯誤的 migration 在生產環境造成的損失可能無法完全復原。需要人完全理解並承擔責任。

第三，涉及金融或法律合規的邏輯。這類邏輯的正確性標準不只是技術層面的，還有業務和法律層面的要求，人需要完全理解並能夠解釋給非技術人員。

第四，系統核心的抽象層。例如你的 base model、核心的 middleware、共用的 utility。這些東西影響整個 codebase，對它們的理解深度決定了你對整個系統的掌控程度。

### 05｜團隊對 Claude Code 輸出的共同品質標準

最後一條，也是讓前面所有討論能夠落地的關鍵：團隊需要對「什麼樣的 Claude Code 輸出是可接受的」有明確的共同標準。

沒有共同標準的問題不只是品質不一致，而是當問題發生時，團隊沒有共同的語言討論問題，也沒有共同的基準評估改進。

建立共同品質標準的幾個層面：

第一層：技術標準（客觀可測量的）。

這部分相對容易達成共識，因為有客觀的衡量方式：

```markdown
## 技術品質標準（所有程式碼，不管來源）

自動化檢查（CI 強制執行）：
- pytest 全部通過
- mypy 無錯誤
- ruff check 無警告
- 測試覆蓋率不低於目前的基準線

人工確認：
- 新增的 public method 有 docstring
- 有 breaking change 時有對應的 migration guide
- 效能關鍵路徑有 benchmark 數據

```

第二層：可理解性標準（主觀但可討論的）。

這部分比較難量化，但可以用具體的問題來評估：

```markdown
## 可理解性標準

reviewer 應該能夠回答以下問題：
1. 這段程式碼解決的業務問題是什麼？
2. 主要的設計選擇是什麼、為什麼這樣選？
3. 這段程式碼在什麼情況下會出問題？
4. 如果需要修改，最需要注意什麼？

如果 reviewer 回答不出這些問題，
PR 應該要求 author 補充說明，
而不是直接 approve。

```

第三層：流程標準（確保標準被執行的機制）。

光有標準不夠，需要機制確保標準被執行：

```markdown
## 流程標準

PR 提交前：
- Author 必須自行跑完所有自動化檢查
- Author 必須完成 PR 描述的所有區塊

PR review 時：
- 至少一個 reviewer 必須實際在本地跑過這段程式碼
- 涉及高風險領域的 PR 需要兩個 reviewer

Merge 後：
- 在 staging 環境驗證功能正常
- 如果這個 PR 改動了 CLAUDE.md 或 Skill，
  通知團隊並在下次同步時說明

```

讓標準演進，不要讓它僵化：

品質標準不是一次定好就永遠不變的。隨著團隊對 Claude Code 的使用經驗累積、隨著專案的規模和複雜度增加、隨著遇到的問題改變，標準也應該跟著調整。

建議每個 quarter 回顧一次品質標準：

```auto
回顧問題：
1. 這個季度因為品質問題造成的最大問題是什麼？
   現有標準有沒有能夠預防它？
2. 現有的哪些標準在實際執行中太困難、
   導致大家繞過它而不是遵守它？
3. Claude Code 的使用方式有沒有改變？
   標準需要對應調整嗎？

```

標準的目的是讓團隊能夠持續地產出可信賴的程式碼，不是讓標準本身成為目的。如果某條標準在實際執行中產生的阻力大於它提供的保護，它需要被修改，而不是被繞過。

## ▌結語

八章寫完，回到最根本的問題：Claude Code 改變了什麼，沒有改變什麼。

改變了的：

執行速度。一個需要三天的重構，可能在幾小時內完成。一份需要半天的技術文件，可能在一個小時內有初稿。這個速度的改變是真實的，不是誇大的。

沒有改變的：

判斷什麼值得做，需要你。理解業務脈絡，需要你。承擔技術決策的後果，需要你。維護一個可以被人理解和修改的 codebase，需要你。對你的系統在任何情況下的行為負責，需要你。

Claude Code 把執行的成本降低了，但它沒有降低判斷的成本，也沒有降低理解的必要性。如果你用 Claude Code 的速度產出了大量你不理解的程式碼，你沒有提高效率，你只是把問題往後推，而且因為速度更快，問題累積的速度也更快。

最後一個實際建議：

定期問自己這個問題：「如果 Claude Code 明天停止服務，我的 codebase 的狀況如何？我還能繼續維護它嗎？」

如果答案是肯定的，你用 Claude Code 的方式是對的。如果答案是否定的，值得認真思考工作流程的哪個環節需要調整。

工具服務於人，不是人依賴工具。

* * *

## ▌參考資料

> [@鄭智維先生 Claude Code 實戰指南：30 個技巧 + 8 個踩坑](https://vip.studycamp.tw/t/%E9%84%AD%E6%99%BA%E7%B6%AD%E5%85%88%E7%94%9F-claude-code-%E5%AF%A6%E6%88%B0%E6%8C%87%E5%8D%97%EF%BC%9A30-%E5%80%8B%E6%8A%80%E5%B7%A7-8-%E5%80%8B%E8%B8%A9%E5%9D%91/8779/1):
>
> 在 [鄭智維先生](https://www.facebook.com/wesley.cheng.39) 的臉書看到 [Claude Code 30 個技巧 + 8 個踩坑](https://www.facebook.com/wesley.cheng.39/posts/pfbid0a8t6VimGPkSFvvGdYphY1rBPNZsBbHhnFvLbRYj48KiabbTBBZnGdVJG2oBA3uRql) 文章分享，看起來是之後開課的章節規劃。 我請 Claude Code 針對鄭先生分享的圖檔，寫了兩篇文章。 這是第一篇，請 Claude Code 根據這些要點，提出看法。 接著讓 Claude Code 跳出這張圖的範疇，另外寫一篇文章「[Claude Code 教學：一些實作上的眉眉角角](https://vip.studycamp.tw/t/claude-code-%E6%95%99%E5%AD%B8%EF%BC%9A%E4%B8%80%E4%BA%9B%E5%AF%A6%E4%BD%9C%E4%B8%8A%E7%9A%84%E7%9C%89%E7%9C%89%E8%A7%92%E8%A7%92/8781/1)」。 ▌1. 入門…
