前一篇文章「 鄭智維先生的 Claude Code 實戰指南:30 個技巧 + 8 個踩坑」是根據鄭先生臉書分享的圖片,由 Claude 衍生展開。這一篇則是由 Claude 自行撰寫。
在開始之前,先說一點心得:
如果沒有經過這樣的過程,而是一開始就直接請 Claude 撰寫「Claude Code 實作指引」的話,內容應該會是現在的十分之一不到。
這不是 AI 的錯,是我們下的指令不對。
所以,未來我們要請 Claude 撰寫某個主題的文章時,如何更完整呢?
簡單的說:提供一個 roadmap。這個 roadmap 告訴 Claude 如何進行,有了這個 roadmap (就像是 Claude Code 的 Claude.md),Claude 就不只是撰寫一篇文章,而是根據 roadmap 上的每個點,有歷史脈絡的各自撰寫一篇文章。
以本文為例,roadmap 如下(點擊展開):
用使用者心智模型的成熟度來組織結構,而不是用難度分層。
原作者是以「功能介紹」為主軸,Claude 的版本則是以「你可能會在哪裡出問題」為主軸。
新增了指令設計、驗證與品質控制、團隊協作等新主題,以及失敗模式的系統分析。
一、重新認識這個工具
先破除錯誤預設,再建立正確操作模型
- Claude Code 的操作模型:Agent,不是 Assistant
- Context Window 是最重要的資源,不是功能
- Session 是工作單位,不是對話單位
- Claude Code 看到的世界:它能感知什麼、感知不到什麼
- 它的信心和它的準確率是兩件事
二、指令設計
這是最被低估的核心技能
- 描述結果,不描述步驟
- 給約束,不給自由
- 把驗證標準寫進指令
- 用檔案路徑代替描述
- 歧義是你的責任,不是它的問題
三、工作流程設計
任務怎麼拆、Session 怎麼管
- 任務拆解的原則:原子性和可驗證性
- Session 邊界的設計
- Git 是 Session 之間唯一可靠的記憶
- Worktree 讓並行成為可能
- Human-in-the-loop 不是效率問題,是風險管理
四、長期記憶系統
CLAUDE.md 和 Skill 的完整設計
- CLAUDE.md 的三層結構:專案、模組、個人
- 什麼該寫進 CLAUDE.md,什麼不該
- Skill 的參數化設計
- 設定檔納入版本控制的團隊意義
- 記憶系統的維護:什麼時候該更新
五、驗證與品質控制
新增主題
- 「完成」的定義要在任務開始前就說清楚
- 測試先行的工作流程
- 讓它 review 自己的輸出
- 讓它 review 你的輸出
- 什麼程度的輸出值得信任,什麼程度需要人工複查
六、工具整合
MCP 和外部系統
- MCP 的正確心智模型:能力擴充,不是魔法
- 選現成 MCP 還是自建的判斷標準
- 自建 MCP 的最小可行設計
- MCP 的 debug 方法論
- 工具鏈的複雜度管理
七、常見失敗模式
更系統化的進化版踩坑區
- 速度陷阱:跑得快但方向錯
- 信任陷阱:它說完成就以為完成
- 脈絡陷阱:Session 狀態污染
- 規模陷阱:小資料通過、真實環境爆炸
- 依賴陷阱:套件升級的隱性風險
- 理解陷阱:codebase 是它寫的但你看不懂
八、團隊協作
新增主題
- 讓 Claude Code 的行為在團隊內一致
- Skill 和 CLAUDE.md 的共同維護機制
- AI 生成的程式碼如何做 code review
- 什麼應該讓 Claude Code 做,什麼應該人自己寫
- 團隊對 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 結果式指令的對比:
# 步驟式(低效)
「把 get_user function 改成 async,
在裡面加上 try-except,
exception 的時候 return None,
然後把所有呼叫這個 function 的地方加上 await」
# 結果式(高效)
「get_user 目前在資料庫連線失敗時會讓整個程式 crash。
我希望它能夠優雅地處理失敗,
讓呼叫端能夠判斷操作是否成功並決定後續行為。
請根據現有 codebase 的錯誤處理模式來實作。」
結果式指令讓 Claude Code 根據它對你整個 codebase 的理解來選擇最適合的實作方式。它可能選擇你沒想到的、但更適合你現有架構的解法。
例外情況:
如果你有強烈的技術理由要求特定的實作方式(例如效能限制、團隊規範、外部系統的介面要求),明確指定是對的。結果式指令的精神不是「什麼都不說」,而是「說清楚你真正在意的是什麼」。
02|給約束,不給自由
直覺上你可能覺得給 Claude Code 越多自由度,它能發揮越好。實際上相反:清晰的約束讓它的輸出更準確、更符合你的需求。
自由度高的指令會讓它在大量的可能性空間裡自己做選擇。它做的選擇不一定是你想要的,而且你很難預測它會選什麼。
沒有約束 vs 有約束的對比:
# 沒有約束(危險)
「幫我優化這個資料庫查詢」
# 有約束(安全)
「幫我優化這個資料庫查詢。
限制條件:
- 不能改動 schema
- 不能引入新的 index(需要 DBA 審核)
- 查詢時間目標是從現在的 800ms 降到 200ms 以下
- 不能用 raw SQL,維持現有的 ORM 風格」
約束的作用不只是限制它不能做什麼,更重要的是讓它理解你的決策邊界。知道了邊界,它在邊界內的判斷反而更準確。
常見的重要約束類型:
- 技術限制(不能引入新依賴、不能改 interface、不能動某些檔案)
- 風格約束(遵循現有的 error handling 模式、命名規範)
- 範圍約束(只改這個模組、不要動測試以外的地方)
- 品質約束(改完要通過現有測試、不能降低測試覆蓋率)
03|把驗證標準寫進指令
「做完」的定義如果不寫進指令,它就會用自己的標準來判斷完成。它的標準不一定是你的標準。
沒有驗證標準的指令:
「幫我重構 OrderService」
它做完之後告訴你「完成了」。但完成是什麼意思?程式碼能跑?測試通過?效能改善了?文件更新了?你不知道,它也不確定,雙方各自用不同的標準在溝通。
有驗證標準的指令:
「幫我重構 OrderService。
完成的標準:
1. pytest tests/test_order_service.py 全部通過
2. mypy 對 order_service.py 沒有任何錯誤
3. 沒有新增任何 public method(只是內部重組)
4. 每個 private method 都有 docstring 說明它在做什麼
完成後把驗證結果逐條回報給我。」
驗證標準的另一個作用是:讓它在執行過程中自我校準。它知道最終要達到什麼標準,中途發現方向不對時會自己調整,而不是做完一個不符合標準的結果再告訴你。
04|用檔案路徑代替描述
當你需要它理解某段程式碼、某個模組、或某份文件時,給路徑比給描述有效得多。
描述 vs 路徑的對比:
# 描述(低效)
「我有一個處理訂單狀態的 service,
裡面有幾個方法負責狀態轉換,
幫我看看有沒有問題」
# 路徑(高效)
「請讀 services/order_state_machine.py,
分析狀態轉換邏輯,
找出可能的競爭條件(race condition)」
路徑的好處是精準且無歧義。你的描述和它理解的描述之間有解讀空間,路徑沒有。
進階用法:
# 給多個相關檔案
「請先讀以下檔案再開始:
- models/order.py(Order 的資料結構)
- services/order_service.py(業務邏輯)
- tests/test_order_service.py(現有測試,理解預期行為)
讀完後告訴我你的理解,確認後再開始修改。」
讓它在開始工作之前先彙報它的理解,是一個有效的校準步驟。你確認它的理解正確之後,後續的工作方向就不容易跑偏。
05|歧義是你的責任,不是它的問題
這條是心態問題,但影響非常實際。
當 Claude Code 的輸出不符合你的預期,第一個反應往往是「它理解錯了」。但更準確的問法是:「我的指令有沒有給它足夠的資訊做出正確的判斷?」
歧義的幾種常見來源:
第一種是術語歧義。你說「優化這個 function」,優化是指效能、可讀性、還是記憶體使用量?你心裡有答案,但指令裡沒有說。
第二種是範圍歧義。你說「修好這個 bug」,修好是指修掉這個特定的觸發路徑,還是找出並修好所有類似的問題?
第三種是優先級歧義。你說「讓這段程式碼更好」,在效能和可讀性之間衝突時,它應該優先哪個?
第四種是隱性前提。你覺得「當然不能動 production config」,但你沒有說,它不知道。
消除歧義的實際方法:
寫完指令之後,用一個簡單的測試:如果一個剛加入團隊、聰明但對這個專案完全不熟悉的工程師收到這個指令,他有沒有足夠的資訊做出正確的判斷?
如果答案是沒有,繼續補充,直到答案是有。
▌3. 工作流程設計
指令設計解決的是「單次任務怎麼說清楚」,工作流程設計解決的是「多個任務怎麼組織」。兩者都重要,但大多數人只想到前者。
01|任務拆解的原則:原子性和可驗證性
任務拆解不是把一件大事切成幾件小事這麼簡單。拆得不好,小任務之間會有隱性依賴、邊界模糊、驗證困難等問題,反而比不拆更麻煩。
好的任務拆解需要同時滿足兩個條件:
原子性:每個子任務是獨立可執行的單位。
原子性的意思是:這個子任務可以在不依賴其他子任務「進行中狀態」的情況下獨立完成。它可以依賴其他任務的「完成結果」(例如上一個任務的 commit),但不能依賴另一個任務「還沒做完的中間狀態」。
可驗證性:每個子任務有明確的完成標準。
完成標準要在任務開始前就定義好,而且要是客觀可檢查的,不能是「看起來差不多了」。
一個實際的拆解範例:
任務:「把現有的同步 API 改成非同步」
錯誤的拆法:
1. 改 controller 層
2. 改 service 層
3. 改 repository 層
4. 更新測試
這個拆法的問題是步驟 1-3 之間有強依賴,controller 改成 async 之後,如果 service 還沒改,整個系統是壞的狀態,無法驗證。
正確的拆法:
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 開場應該包含:
任務:[一句話說明這個 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 的意義:
# 對 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 到不同的目錄。每個目錄是完全獨立的工作環境,有自己的工作區狀態,不會互相污染。
# 主目錄: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 可以列出選項和各自的取捨,但決定應該由你來做。
第三類:跨越模組邊界時。
當一個任務的修改從一個模組延伸到另一個模組,確認這個延伸是你預期的,而不是它自己判斷需要這樣做的。
在指令裡設置確認節點的寫法:
請依序執行以下步驟。
每個步驟完成後停下來,
等我明確說「繼續」才執行下一步。
步驟 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。
三層結構:
~/ # 第一層:個人全域設定
└── CLAUDE.md # 適用於所有專案的個人偏好
~/projects/myapp/ # 第二層:專案層級
└── CLAUDE.md # 這個專案的架構、規範、限制
~/projects/myapp/
├── services/
│ └── CLAUDE.md # 第三層:模組層級
└── tests/
└── CLAUDE.md # 測試目錄的特定規範
各層應該放什麼:
個人全域層(~/CLAUDE.md):
放你在所有專案裡都適用的個人偏好,例如:
## 溝通偏好
- 每個步驟完成後主動回報結果,不要等我問
- 不確定時先列出選項和各自的取捨,不要自己猜測決定
- 錯誤訊息貼完整,不要自己節錄
## 程式碼風格偏好
- 函式命名用動詞開頭
- 優先可讀性,在沒有明確效能需求的情況下不要過度優化
- 每個 public function 都要有 type hint
專案層(~/projects/myapp/CLAUDE.md):
放這個專案特有的資訊:
## 專案概述
訂單管理系統,處理電商平台的訂單生命週期。
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):
放這個模組特有的細節:
## 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:
# 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 的方式:
使用「新增 Repository Method」Skill:
ENTITY = Order
METHOD_TYPE = list_by_filter
SPECIAL_REQUIREMENTS = 需要支援按日期範圍和狀態複合篩選,
且結果要支援游標分頁(cursor-based pagination)
這樣的設計讓同一個 Skill 可以適應不同的 entity 和操作類型,不需要為每個情境寫一個獨立的 Skill。
Skill 的組織方式:
.claude/
└── skills/
├── add-repository-method.md
├── add-api-endpoint.md
├── code-review.md
├── write-migration.md
└── debug-production-issue.md
每個 Skill 一個檔案,檔名清楚說明用途。需要使用時:
載入 .claude/skills/add-api-endpoint.md,
執行這個 Skill,參數如下:...
04|設定檔納入版本控制的團隊意義
這不只是個人的好習慣,而是影響整個團隊協作品質的實踐。
應該 commit 的設定檔:
專案根目錄/
├── CLAUDE.md # 必須 commit
└── .claude/
├── config.json # 專案層級設定,必須 commit
└── skills/ # 所有 Skill 檔案,必須 commit
├── add-endpoint.md
├── code-review.md
└── write-migration.md
不應該 commit 的設定檔:
~/.claude/config.json # 個人全域設定,不 commit
.claude/config.local.json # 個人本地覆寫,加入 .gitignore
為什麼這對團隊很重要:
當 CLAUDE.md 和 Skill 檔案納入版本控制,整個團隊的 Claude Code 行為會趨於一致。新成員 clone 專案之後,Claude Code 就知道這個專案的架構規則、命名規範、禁止事項,不需要靠口耳相傳。
更重要的是:設定檔的演進歷史本身就是決策歷史。 當你在 CLAUDE.md 裡加了一條「不直接修改 migration 檔案」,commit message 應該說明為什麼,例如:
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」,而是把更新變成工作流程的一部分:
每個 Sprint 結束時,花 10 分鐘回顧:
- 這個 Sprint 裡有沒有重複說過的事?→ 補進 CLAUDE.md
- 有沒有 Claude Code 做了不符預期的決定?→ 補對應的規則
- 有沒有技術決策改變?→ 更新對應的規則和 Skill
把這個回顧變成習慣,CLAUDE.md 就會隨著專案成長而越來越準確,而不是越來越過時。
▌5. 驗證與品質控制
這可能是本文中,對實際產品品質影響最大的部分。
很多人把 Claude Code 的工作流程設計成:下指令 → 它執行 → 接受輸出。
這個流程在任務簡單、風險低的情況下沒問題。但當任務複雜度提高,沒有系統性的驗證機制,錯誤會在你不知情的情況下累積,直到某個時間點集中爆發。
01|「完成」的定義要在任務開始前就說清楚
這條看起來像是第二章指令設計的重複,但角度不同。指令設計章節說的是「怎麼寫出好指令」,這裡說的是「為什麼驗證標準必須是指令的一部分,而不是事後補充的要求」。
沒有預先定義完成標準會發生什麼:
Claude Code 完成任務後,它會用自己的標準評估「完成了沒有」。它的標準通常是:程式碼語法正確、邏輯看起來合理、如果有跑測試的話測試通過。
這個標準和你的標準之間可能有很大的落差:
- 你的標準可能包含效能要求,它的標準沒有
- 你的標準可能包含某個特定的錯誤處理模式,它用了不同但技術上正確的模式
- 你的標準可能包含文件更新,它認為「程式碼改好了就完成了」
事後提出額外要求的成本:
當你在它說「完成了」之後才說「對了,還需要更新文件」,它需要重新理解當前狀態,可能已經消耗了大量 context,回應品質開始下降。更糟的是,它可能在「補文件」的過程中對已有的程式碼做出不必要的小調整,引入新的問題。
預先定義完成標準的模板:
任務完成的標準(全部達到才算完成):
程式碼層面:
□ pytest tests/[相關測試檔案] 全部通過
□ mypy [相關檔案] 無錯誤
□ ruff check [相關檔案] 無警告
功能層面:
□ [具體的功能行為描述]
□ [邊界案例的處理方式]
文件層面:
□ docstring 更新(如果 public interface 有改變)
□ CHANGELOG.md 新增對應項目
完成後請逐條確認以上標準,
並回報每一條的驗證結果。
把這個模板存進你的 Skill 系統,每個任務開始前調整具體的內容,而不是每次從頭想。
02|測試先行的工作流程
測試先行(Test First)在 Claude Code 的語境下,意義和傳統 TDD 略有不同。傳統 TDD 強調的是設計驅動,Claude Code 語境下的測試先行強調的是驗證標準的具象化。
在開始實作之前先寫測試,等於是把你對「正確行為」的理解,轉化成機器可以執行的規格。這個規格比自然語言描述更精確,也更難有歧義。
具體的工作流程:
# 第一步:描述行為,讓它寫測試
「針對 PaymentService.process_refund,先寫測試。
不要實作,只寫測試。
需要涵蓋的情境:
1. 正常退款成功:金額正確退回,訂單狀態更新為 refunded
2. 金額超過原始訂單金額:應拋出 InvalidRefundAmountError
3. 訂單狀態不允許退款(例如已是 refunded):
應拋出 InvalidOrderStateError
4. 金融系統呼叫失敗:應拋出 PaymentGatewayError,
且不應改變訂單狀態(確認原子性)
5. 部分退款:金額小於原始金額,狀態更新為 partially_refunded
寫完之後跑測試,確認全部是紅燈(失敗)再告訴我。」
# 第二步:確認測試邏輯正確後,再開始實作
「測試邏輯正確。
現在實作 process_refund,目標是讓所有測試通過。
不要修改測試,只實作 method。」
# 第三步:測試全過後,考慮重構
「所有測試通過了。
在不改變任何測試的前提下,
看看實作有沒有可以整理的地方。
如果有,說明你打算怎麼整理,等我確認再動。」
這個流程的關鍵價值:
測試是你和 Claude Code 之間對「正確」的共同定義。一旦測試寫好並確認邏輯正確,後續的實作和重構都有一個客觀的驗證標準,不需要靠你的主觀判斷來評估「改得對不對」。
03|讓它 review 自己的輸出
在你接受任何輸出之前,讓 Claude Code 先對自己的工作做一次批判性的審查。
這聽起來像是讓它自己給自己打分數,效果有限。但實際上,生成輸出和審查輸出是兩個不同的認知過程。它在生成時做的是建構,在審查時做的是批判。兩個過程會發現不同的問題。
有效的自我 review 指令:
你剛才完成了 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 指令:
請 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 架構。
# 例如,查詢內部 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):
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 是否正常啟動。
# 直接執行 MCP server,看有沒有啟動錯誤
python your_mcp_server.py
# 或檢查 Claude Code 的 MCP 連線狀態
# 在 Claude Code 裡執行:
/mcp
如果 MCP server 連不上,後面的層都不需要看。
第二層:確認工具列表是否正確載入。
# 在 Claude Code Session 裡問它:
「列出你目前可以使用的所有工具,包括來自 MCP 的工具。」
如果它列不出你期望的工具,問題在 MCP server 的 list_tools 實作,或是 Claude Code 的 MCP 設定檔。
第三層:獨立測試工具呼叫。
# 要求 Claude Code 直接呼叫特定工具,
# 不要讓它自己判斷要不要呼叫:
「請直接呼叫 get_ticket 工具,ticket_id 是 PROJ-1234,
不管結果如何都回報給我。」
如果工具呼叫失敗,看錯誤訊息判斷是 MCP server 的問題還是外部 API 的問題。
第四層:直接測試外部 API。
# 繞過 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 回傳了什麼,不需要靠猜測。
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 清楚區分它和其他工具的差別。如果兩個工具的描述讀起來很像,要明確在描述裡說明它們的差異和各自的適用情境。
# 容易混淆的描述(不好)
get_order:取得訂單資訊
get_order_detail:取得訂單詳細資訊
# 清楚區分的描述(好)
get_order:取得訂單的摘要資訊(id、狀態、總金額、建立時間)。
適用於需要快速確認訂單狀態、不需要明細的情況。
get_order_detail:取得訂單的完整資訊,包含所有商品明細、
物流資訊、付款紀錄、歷史狀態變更。
適用於需要深入分析特定訂單的情況。
注意:回傳資料量較大,只在必要時使用。
定期審查工具使用情況。
每隔一段時間,回顧一下哪些工具被頻繁使用、哪些幾乎從來不被用。幾乎不被用的工具可能是描述寫得不好(讓 Claude Code 不知道什麼時候用它),也可能是這個工具的需求本來就很少,可以考慮移除。
▌7. 常見失敗模式
前面六項主題,討論的是「怎麼做對」。本主題討論的是「為什麼會做錯」。
失敗模式和踩坑清單的差別在於:踩坑清單告訴你「不要做 X」,失敗模式分析告訴你「為什麼你會自然而然地走向 X、X 會怎麼讓你付出代價、以及怎麼建立系統來避免它」。
知道不該做什麼不夠,你需要理解失敗的機制,才能在它發生之前認出它。
01|速度陷阱:跑得快但方向錯
這是使用 Claude Code 之後最常見的第一個失敗模式,而且通常要等到損失已經造成才會被發現。
陷阱的機制:
Claude Code 的執行速度很快。一個任務可能在幾分鐘內就有大量的輸出:程式碼修改、測試、文件。這個速度會產生一種「進展感」,讓你覺得事情在快速往前走。
問題是,速度和方向是兩個獨立的維度。你可以很快地朝錯誤的方向前進。
速度陷阱的具體場景:
你給了一個描述不夠精確的任務,Claude Code 做了一個「合理但不是你要的」的解釋,然後快速地在這個錯誤的解釋上建構了大量的輸出。你因為看到大量輸出而感到滿意,沒有在早期確認方向,等到最後才發現整個方向跑偏了。
這時你面對的不只是一個錯誤,而是一大堆建立在錯誤基礎上的輸出,要全部推翻重來。
速度陷阱的特徵:
- 任務初期沒有讓它彙報理解和計畫,直接讓它開始做
- 中途沒有設置確認節點,讓它一口氣跑完
- 看到大量輸出就覺得進展良好,沒有仔細確認方向
系統性的預防機制:
任何超過一個檔案修改的任務,都要求它在開始實作之前先說明計畫:
在開始任何修改之前,先告訴我:
1. 你理解這個任務的目標是什麼
2. 你打算修改哪些檔案、每個檔案改什麼
3. 你預期的完成結果是什麼
等我確認計畫正確之後再開始。
這個步驟花不了幾分鐘,但可以在方向錯誤的時候,把損失控制在「計畫需要修正」而不是「大量輸出需要推翻」。
02|信任陷阱:它說完成就以為完成
這個失敗模式的危險程度在於:它不會立即顯現。程式碼在開發環境跑得好好的,測試通過,它也說完成了。問題在幾天後、幾週後、或是上線後才出現。
陷阱的機制:
Claude Code 的語氣天然傾向於確定。它說「完成了」、「測試全部通過」、「這個實作是正確的」,語氣和它真的確定時完全一樣。這不是它在說謊,而是它的輸出模式就是這樣設計的。
加上它確實完成了大部分的工作,很容易讓你建立「它說完成就是完成了」的習慣。這個習慣在低風險任務上沒有明顯問題,但在高風險任務上會積累成嚴重的品質問題。
信任陷阱的幾種典型變體:
變體一:測試通過但測試寫錯了。
它寫的測試在語法上正確,邏輯上也看起來合理,但測試的斷言沒有真正驗證到你在意的行為。測試通過只代表「它寫的測試通過了」,不代表「你在意的行為是正確的」。
變體二:修好了這條路徑,但沒修另一條。
你報告了一個 bug 的具體觸發方式,它修好了那個特定的觸發路徑,但根本原因沒有解決,只是那個特定的情境不會觸發了。其他情境下同樣的問題依然存在。
變體三:功能正確但效能有問題。
它實作的功能邏輯完全正確,測試也通過,但在真實資料規模下有 N+1 query 問題或記憶體洩漏。這類問題在測試環境的小資料量下完全不會顯現。
變體四:當下正確但未來會壞。
它的實作依賴了某個外部系統的當前行為,但這個行為在文件裡標注為「不保證穩定」。它沒有注意到這個標注,你也沒有。
建立系統性的驗證習慣:
不依賴它的自我評估,建立獨立的驗證清單。依任務的風險等級,選擇對應強度的驗證:
低風險任務:
□ 跑相關測試,確認通過
□ 快速掃一遍 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 的開場,明確說明當前的狀態:
新 Session。當前狀態:
- 剛完成了 [已完成的任務],相關 commit 是 [commit hash]
- 接下來要做的是 [新任務]
- 特別注意:[任何需要明確說明的當前狀態]
請先用 git log --oneline -5 確認當前的 commit 狀態,
再開始工作。
04|規模陷阱:小資料通過、真實環境爆炸
這個失敗模式的代價往往在上線後才顯現,而且很難快速回滾。
陷阱的機制:
Claude Code 在開發和測試環境裡工作。這些環境的資料量通常遠小於生產環境,並發量也低,資料的分布也比生產環境乾淨。它寫出來的程式碼在這個環境裡完全正確,但有些問題只有在生產環境的規模下才會顯現。
規模陷阱的幾種常見形式:
N+1 Query 問題:
它實作的查詢邏輯在 10 筆資料下執行時間 50ms,完全感覺不到問題。但在 10 萬筆資料下,同樣的邏輯可能需要執行 10 萬次資料庫查詢,讓整個系統癱瘓。
記憶體問題:
它把整個查詢結果載入記憶體再做處理。測試資料 100 筆,完全沒問題。生產資料 100 萬筆,記憶體直接爆掉。
鎖競爭問題:
它的實作在低並發下完全正常。但在生產環境的高並發下,某個地方的鎖競爭讓系統的吞吐量驟降,甚至造成死鎖。
資料品質問題:
測試資料是乾淨的,每個欄位都有值,格式都正確。生產資料裡有 null 值、有格式異常的歷史資料、有各種邊界情況。它的程式碼沒有處理這些情況,上線後第一個不乾淨的資料就讓系統崩潰。
在指令層面預防規模問題:
對任何涉及資料查詢或處理的任務,在指令裡明確說明規模預期:
實作這個查詢功能時,請考慮以下規模:
- 資料量: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 一次升級所有套件。給它一個嚴格的流程:
套件升級流程(每次只升一個):
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
在工作流程裡建立理解的機制:
第一,讓它解釋,不只是讓它做:
實作完成後,用非技術語言解釋這個實作:
1. 整體的設計思路是什麼
2. 最關鍵的三個設計決策是什麼、為什麼這樣決定
3. 這個實作依賴了哪些假設,如果假設不成立會怎樣
4. 未來如果要修改這個模組,最需要注意什麼
第二,定期進行「理解審計」:
每隔一段時間,隨機選取幾個最近由 Claude Code 生成或修改的模組,試著向自己解釋它在做什麼、為什麼這樣做。說不清楚的地方,回去讀程式碼,或是讓 Claude Code 解釋。
第三,讓理解成為完成標準的一部分:
這個任務的完成標準包括:
- 功能正確(測試通過)
- 我能夠向團隊成員解釋這個實作的設計思路
(你需要在完成後給我一個可以用來解釋的摘要)
最根本的心態:
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 的行為就自動一致。
專案根目錄/
├── 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 看的文件,也是團隊工程規範的一份具體化記錄。它應該涵蓋的內容和一份好的「新人入職工程規範」高度重疊:
# [專案名稱] 工程規範
## 架構概述
[專案的分層架構說明]
## 核心規則
這些規則適用於所有程式碼修改,
不管是人寫的還是 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,因為那個時間通常不會到來。把更新嵌入現有的工作流程:
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 生成程式碼,重點應該調整為:
降低關注:
- 語法正確性(通常不是問題)
- 基本風格一致性(如果有 linter 自動檢查)
提高關注:
- 業務邏輯的正確性
(它有沒有正確理解業務規則,不只是技術規則)
- 邊界案例和錯誤路徑
(測試有沒有覆蓋到真實環境會遇到的情況)
- 對現有架構的影響
(它的修改有沒有破壞任何隱性的架構假設)
- 可維護性
(這段程式碼,不看 Claude Code 的生成脈絡,
還能不能被人理解和維護)
PR 描述的新標準:
當使用 Claude Code 生成的程式碼提 PR,PR 描述應該包含:
## 這個 PR 做了什麼
[功能描述]
## 技術決策說明
[說明主要的設計選擇和原因,
特別是那些 Claude Code 自己做的判斷]
## 驗證方式
[說明如何驗證這個 PR 的正確性,
包括測試覆蓋了哪些情境]
## 已知限制
[任何已知的邊界案例、效能限制、
或未來需要改進的地方]
## AI 生成的部分
[說明哪些部分是 Claude Code 生成的、
哪些是人工調整的,
以及人工 review 的重點在哪裡]
最後一個區塊「AI 生成的部分」值得特別說明。透明地標注哪些是 AI 生成的,讓 reviewer 知道把注意力集中在哪裡,也讓未來維護這段程式碼的人理解它的來源和背景。
04|什麼應該讓 Claude Code 做,什麼應該人自己寫
這是一個需要團隊明確討論和達成共識的問題,不能讓每個人各自決定。
不同的分工策略會產生截然不同的結果:
如果沒有共識,自然的傾向是「什麼都讓 Claude Code 做,因為它快」。這個策略在短期內提高了速度,但長期會讓團隊對 codebase 的理解集體下降,形成前一章提到的理解陷阱的團隊版本。
一個實用的分工框架:
以「重要性」和「重複性」兩個維度來判斷:
高重要性 + 低重複性:
→ 人主導,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 輸出是可接受的」有明確的共同標準。
沒有共同標準的問題不只是品質不一致,而是當問題發生時,團隊沒有共同的語言討論問題,也沒有共同的基準評估改進。
建立共同品質標準的幾個層面:
第一層:技術標準(客觀可測量的)。
這部分相對容易達成共識,因為有客觀的衡量方式:
## 技術品質標準(所有程式碼,不管來源)
自動化檢查(CI 強制執行):
- pytest 全部通過
- mypy 無錯誤
- ruff check 無警告
- 測試覆蓋率不低於目前的基準線
人工確認:
- 新增的 public method 有 docstring
- 有 breaking change 時有對應的 migration guide
- 效能關鍵路徑有 benchmark 數據
第二層:可理解性標準(主觀但可討論的)。
這部分比較難量化,但可以用具體的問題來評估:
## 可理解性標準
reviewer 應該能夠回答以下問題:
1. 這段程式碼解決的業務問題是什麼?
2. 主要的設計選擇是什麼、為什麼這樣選?
3. 這段程式碼在什麼情況下會出問題?
4. 如果需要修改,最需要注意什麼?
如果 reviewer 回答不出這些問題,
PR 應該要求 author 補充說明,
而不是直接 approve。
第三層:流程標準(確保標準被執行的機制)。
光有標準不夠,需要機制確保標準被執行:
## 流程標準
PR 提交前:
- Author 必須自行跑完所有自動化檢查
- Author 必須完成 PR 描述的所有區塊
PR review 時:
- 至少一個 reviewer 必須實際在本地跑過這段程式碼
- 涉及高風險領域的 PR 需要兩個 reviewer
Merge 後:
- 在 staging 環境驗證功能正常
- 如果這個 PR 改動了 CLAUDE.md 或 Skill,
通知團隊並在下次同步時說明
讓標準演進,不要讓它僵化:
品質標準不是一次定好就永遠不變的。隨著團隊對 Claude Code 的使用經驗累積、隨著專案的規模和複雜度增加、隨著遇到的問題改變,標準也應該跟著調整。
建議每個 quarter 回顧一次品質標準:
回顧問題:
1. 這個季度因為品質問題造成的最大問題是什麼?
現有標準有沒有能夠預防它?
2. 現有的哪些標準在實際執行中太困難、
導致大家繞過它而不是遵守它?
3. Claude Code 的使用方式有沒有改變?
標準需要對應調整嗎?
標準的目的是讓團隊能夠持續地產出可信賴的程式碼,不是讓標準本身成為目的。如果某條標準在實際執行中產生的阻力大於它提供的保護,它需要被修改,而不是被繞過。
▌結語
八章寫完,回到最根本的問題:Claude Code 改變了什麼,沒有改變什麼。
改變了的:
執行速度。一個需要三天的重構,可能在幾小時內完成。一份需要半天的技術文件,可能在一個小時內有初稿。這個速度的改變是真實的,不是誇大的。
沒有改變的:
判斷什麼值得做,需要你。理解業務脈絡,需要你。承擔技術決策的後果,需要你。維護一個可以被人理解和修改的 codebase,需要你。對你的系統在任何情況下的行為負責,需要你。
Claude Code 把執行的成本降低了,但它沒有降低判斷的成本,也沒有降低理解的必要性。如果你用 Claude Code 的速度產出了大量你不理解的程式碼,你沒有提高效率,你只是把問題往後推,而且因為速度更快,問題累積的速度也更快。
最後一個實際建議:
定期問自己這個問題:「如果 Claude Code 明天停止服務,我的 codebase 的狀況如何?我還能繼續維護它嗎?」
如果答案是肯定的,你用 Claude Code 的方式是對的。如果答案是否定的,值得認真思考工作流程的哪個環節需要調整。
工具服務於人,不是人依賴工具。