Systematic Debugging Skill
Systematic Debugging 是 Superpowers 中最重要的除錯型 skills 之一,專注於系統化地診斷和解決程式錯誤、bug 和異常行為。
何時使用
在以下情況中使用 Systematic Debugging skill:
✅ 必須使用的情境:
- 程式出現預期外的行為
- 測試失敗且原因不明
- 功能無法正常運作
- 效能問題需要診斷
- 收到使用者的 bug 回報
❌ 不適合的情境:
- 需要先明確問題(應先用 brainstorming)
- 需要先驗證問題存在(應先用 verification)
- 簡單的語法錯誤(直接修正即可)
系統化除錯流程
第 1 步:定義問題
清楚定義遇到的問題:
問題描述:
- 期望行為:點擊「刪除」按鈕後,項目從列表消失
- 實際行為:點擊後項目仍在列表中
- 重現步驟:1. 新增項目 → 2. 點擊刪除 → 3. 項目仍存在
- 錯誤訊息:無
第 2 步:收集資訊
系統化地收集相關資訊:
收集的資訊:
✓ 瀏覽器 console 訊息
✓ 網路請求狀態
✓ 應用程式 log
✓ 資料庫狀態
✓ 重現的步驟
✓ 問題發生的頻率
第 3 步:形成假設
基於收集的資訊形成假設:
假設 1:刪除按鈕的 onClick 事件沒正確綁定
假設 2:刪除 API 呼叫失敗但沒有錯誤處理
假設 3:前端狀態更新邏輯有誤
假設 4:刪除後重新抓取資料失敗
第 4 步:驗證假設
系統化地驗證每個假設:
驗證假設 1:
- 檢查按鈕的 onClick 屬性 ✓ 正確綁定
- 在 onClick 中加入 console.log ✓ 有被呼叫
→ 假設 1 不成立
驗證假設 2:
- 檢查網路請求 ✓ API 成功回應 200
- 檢查回應內容 ✓ 回應正確
→ 假設 2 不成立
驗證假設 3:
- 檢查狀態更新邏輯 ✓ 發現問題:setState 沒正確處理
→ 假設 3 成立!
第 5 步:實作修正
根據驗證結果實作修正:
// 問題程式碼
const handleDelete = (id: number) => {
deleteTodo(id);
setTodos(todos.filter(todo => todo.id !== id)); // ❌ todos 是舊值
};
// 修正後程式碼
const handleDelete = (id: number) => {
deleteTodo(id);
setTodos(prevTodos => prevTodos.filter(todo => todo.id !== id)); // ✅ 使用函式形式
};
第 6 步:驗證修正
確認修正有效:
驗證步驟:
✓ 點擊刪除按鈕
✓ 項目立即從列表消失
✓ 頁面刷新後項目仍消失(持久化正確)
✓ 多個項目刪除都正常
→ 修正成功!
如何使用
觸發詞
「使用 systematic-debugging skill 診斷刪除功能的問題」
實際範例
範例 1:診斷 API 錯誤
使用者輸入:
使用 systematic-debugging skill 診斷使用者登入功能的問題
AI 回應:
## 開始系統化除錯
### 第 1 步:定義問題
問題描述:
- 期望行為:輸入正確帳密後登入成功
- 實際行為:顯示「登入失敗」錯誤
- 重現步驟:1. 輸入正確 email 和密碼 → 2. 點擊登入 → 3. 顯示錯誤
- 錯誤訊息:「Invalid credentials」
### 第 2 步:收集資訊
檢查網路請求:
```http
POST /api/auth/login
Request: {
"email": "user@example.com",
"password": "password123"
}
Response: 401 Unauthorized
{
"error": "Invalid credentials"
}
檢查後端 Log:
[INFO] Login attempt for: user@example.com
[ERROR] Password mismatch
第 3 步:形成假設
假設 1:前端密碼欄位名稱錯誤 假設 2:後端密碼驗證邏輯有誤 假設 3:資料庫中的密碼雜湊有問題
第 4 步:驗證假設
驗證假設 1:
- 檢查前端表單 ✓ password 欄位正確
- 檢查 API 呼叫 ✓ 傳送正確的 password → 假設 1 不成立
驗證假設 2:
- 檢查後端驗證邏輯
// 發現問題
if (user.password_hash === password) { // ❌ 直接比較雜湊值和明文
return true;
}
→ 假設 2 成立!
第 5 步:實作修正
// 修正後
import bcrypt from 'bcrypt';
if (await bcrypt.compare(password, user.password_hash)) { // ✅ 使用 bcrypt.compare
return true;
}
第 6 步:驗證修正
測試登入: ✓ 正確密碼登入成功 ✓ 錯誤密碼顯示錯誤 ✓ 帳號不存在顯示錯誤
→ 問題解決!
### 範例 2:診斷效能問題
**使用者輸入**:
使用 systematic-debugging skill 診斷頁面載入緩慢的問題
**AI 回應**:
開始診斷效能問題
第 1 步:定義問題
問題描述:
- 期望行為:頁面在 2 秒內載入完成
- 實際行為:首屏載入需要 8 秒
- 影響範圍:所有使用者都遇到
- 開始時間:最近一週開始出現
第 2 步:收集資訊
使用 Chrome DevTools 分析:
Performance 分析:
- JavaScript 執行:5.2 秒
- 渲染:1.8 秒
- 網路請求:1 秒
主要耗時項:
- Data fetching: 4 秒
- Component rendering: 1.2 秒
Network 分析:
緩慢的 API:
- GET /api/items: 3.8 秒
- GET /api/categories: 0.2 秒
第 3 步:形成假設
假設 1:API 查詢效率低(缺少索引) 假設 2:API 回傳過多資料 假設 3:前端資料處理邏輯低效 假設 4:Component 重複渲染
第 4 步:驗證假設
驗證假設 1:
- 檢查資料庫查詢
SELECT * FROM items; -- 全表掃描,無索引
→ 問題確認!
驗證假設 2:
- 檢查 API 回應大小:2.5 MB
- 檢查欄位:包含不必要的大文字欄位 → 也是問題!
第 5 步:實作修正
-- 修正 1:加上索引
CREATE INDEX idx_items_category ON items(category);
-- 修正 2:優化查詢
SELECT id, name, price FROM items
WHERE category = ?
LIMIT 50;
// 修正 3:前端只抓取必要資料
const { data } = await useFetch('/api/items?fields=id,name,price&limit=50');
第 6 步:驗證修正
效能測試:
- API 回應時間:3.8 秒 → 0.3 秒
- 頁面載入時間:8 秒 → 1.8 秒 → 效能大幅改善!
## 除錯技巧
### 1. 二分法
使用二分法快速定位問題:
將程式分為前後兩段:
- 前半段正常 → 問題在後半段
- 後半段正常 → 問題在前半段
持續二分直到定位到問題
### 2. 最小化重現
建立最小化的重現案例:
```typescript
// 複雜的問題情境
// → 簡化為最小程式碼
function reproduceBug() {
const result = processItem({ id: 1, name: 'Test' });
console.log(result); // 預期 X,實際 Y
}
3. 日誌追蹤
使用日誌系統化追蹤:
function handleDelete(id: number) {
console.log('[DEBUG] handleDelete called with id:', id);
const response = await deleteItem(id);
console.log('[DEBUG] deleteItem response:', response);
updateState();
console.log('[DEBUG] state updated');
}
4. 漸進式隔離
逐步隔離問題範圍:
第 1 步:確定是前端還是後端問題
第 2 步:確定是哪個模組的問題
第 3 步:確定是哪個函式的問題
第 4 步:確定是哪行程式碼的問題
除錯工具
前端除錯工具
- Browser DevTools:Console、Network、Performance
- React DevTools:Component 樹、State、Props
- Vue DevTools:組件樹、Vuex state
後端除錯工具
- Logging: Winston、Pino、Bunyan
- Debugger:Node.js Inspector、Chrome DevTools
- APM:New Relic、Data Dog
資料庫除錯工具
- Query Analyzer:EXPLAIN、Slow Query Log
- Monitoring:Prometheus、Grafana
常見錯誤模式
1. 非同步錯誤
// ❌ 錯誤
const result = fetchData();
console.log(result); // undefined
// ✅ 正確
const result = await fetchData();
console.log(result); // 正確資料
2. 狀態錯誤
// ❌ 錯誤:使用舊狀態
setTodos([...todos, newTodo]);
// ✅ 正確:使用函式形式
setTodos(prevTodos => [...prevTodos, newTodo]);
3. 型別錯誤
// ❌ 錯誤:沒有型別檢查
function process(data: any) {
return data.value; // 可能是 undefined
}
// ✅ 正確:使用型別
function process(data: { value: string }) {
return data.value;
}
與其他 Skills 組合
推薦組合
Verification + Systematic Debugging
verification-before-completion → systematic-debugging
先驗證問題存在,再系統化除錯
Systematic Debugging + Test-Driven Development
systematic-debugging → test-driven-development
除錯後加入測試防止回歸
最佳實踐
1. 保持冷靜
遇到 bug 時保持系統化思考:
- 不要盲目嘗試
- 系統化地收集資訊
- 形成假設後再驗證
2. 記錄學習
將除錯過程記錄下來:
除錯筆記:
- 問題描述
- 解決過程
- 最終方案
- 預防措施
3. 建立測試
除錯後建立回歸測試:
test('should delete item correctly', () => {
// 確保 bug 不會再出現
});
4. 根本原因分析
不只解決症狀,要找到根本原因:
症狀:頁面載入緩慢
↓
直接原因:API 查詢慢
↓
根本原因:缺少資料庫索引
↓
解決方案:加上索引
Systematic Debugging 是解決程式問題的關鍵 skill,系統化的除錯方法能大幅提升解決效率!