Lesson 3: 単純なバグのデバッグ
クラス: 初級
所要時間: 約40分
前提知識: 初級 Lesson 1〜2 完了済み
1. 解説
バグの種類と Claude Code の使い分け
| バグの種類 | 特徴 | Claude Code の活用法 |
|---|---|---|
| 構文エラー | 実行前にわかる | エラーメッセージをそのまま貼る |
| 実行時エラー | 実行中に発生 | スタックトレース + コードを渡す |
| 論理エラー | 実行はされるが結果が違う | 「期待値 vs 実際値」を伝える |
| パフォーマンス | 遅い・メモリを食う | プロファイル結果を見せる |
効果的なバグ報告テンプレート
## バグ報告テンプレート
**ファイル**: src/utils.js
**再現手順**:
1. node -e "const u = require('./src/utils'); u.calculate([1,2,3])"
2. エラーが発生
**エラーメッセージ**:
TypeError: Cannot read properties of undefined (reading 'reduce')
at calculate (src/utils.js:15:24)
**期待する動作**: [1,2,3] の合計 6 が返る
**実際の動作**: TypeError でクラッシュ
**追加情報**: Node.js v20、空配列を渡した場合は正常デバッグの思考プロセス
1. エラーの種類を特定(構文/実行時/論理)
2. エラーの発生箇所を特定(スタックトレース)
3. 原因の仮説を立てる
4. 仮説を検証する(実行・ログ出力)
5. 修正して再検証2. 実践
Step 1: バグだらけのコードを用意
bash
mkdir -p ~/claude-practice/elementary/lesson3
cd ~/claude-practice/elementary/lesson3
cat > buggy_app.js << 'EOF'
// ショッピングカートの計算ロジック
const TAX_RATE = 0.1;
function calcSubtotal(items) {
return items.reduce((sum, item) => sum + item.price * item.quatity, 0); // スペルミス
}
function calcTax(subtotal) {
return subtotal * TAX_RATE;
}
function calcTotal(items) {
const subtotal = calcSubtotal(items);
const tax = calcTax(subtotal);
return subtotal + tax; // 問題なさそうに見えるが...
}
function applyDiscount(total, discountCode) {
const discounts = {
'SAVE10': 0.1,
'SAVE20': 0.2,
'HALFOFF': 0.5
};
const rate = discounts[discountCode];
return total - (total * rate); // rate が undefined のときクラッシュ
}
function formatPrice(price) {
return '$' + price.toFixed(2);
}
// テストデータ
const cartItems = [
{ name: 'Apple', price: 100, quantity: 2 },
{ name: 'Banana', price: 50, quantity: 3 },
{ name: 'Cherry', price: 200, quantity: 1 },
];
console.log('Subtotal:', formatPrice(calcSubtotal(cartItems)));
console.log('Total:', formatPrice(calcTotal(cartItems)));
console.log('With discount:', formatPrice(applyDiscount(calcTotal(cartItems), 'INVALID_CODE')));
EOFStep 2: 実行してエラーを確認
bash
node buggy_app.jsエラーメッセージを確認してから Claude Code へ:
bash
claudebuggy_app.js を実行すると以下のエラーが出ます。
すべてのバグを見つけて修正してください。
[エラーメッセージを貼り付け]
修正前に:
1. 何個のバグが見つかったか
2. 各バグの種類と原因
を説明してください。Step 3: 論理エラーを自分で発見させる
bash
node -e "
const app = require('./buggy_app');
// calcSubtotal のテスト(修正後)
"修正後に期待値と比較:
修正後の calcSubtotal([{price:100, quantity:2}]) の結果が 200 になっていますか?
実際の計算を確認して、論理エラーが残っていないか検証してください。Step 4: デバッグ用ログを追加させる
buggy_app.js の各関数の入口と出口にデバッグ用の console.log を追加してください。
デバッグが終わったら削除できるよう、// DEBUG: というプレフィックスを付けてください。3. 確認課題(Assignment)
課題 3-1: 複数バグの一括修正
bash
cat > ~/claude-practice/elementary/lesson3/multi_bug.js << 'EOF'
function fibonacci(n) {
if (n = 0) return 0; // バグ1: = は代入
if (n == 1) return 1;
return fibonacci(n-1) + fibonacci(n-2);
}
function isPrime(n) {
if (n < 2) return false;
for (let i = 2; i < n; i++) { // バグ2: i*i <= n が正しい(パフォーマンスバグ)
if (n % i === 0) return false;
}
return true;
}
function reverseString(str) {
return str.split('').reverse().join(''); // これは正しい
}
function countOccurrences(arr, target) {
return arr.filter(x => x = target).length; // バグ3: = は代入
}
console.log(fibonacci(10));
console.log(isPrime(17));
console.log(reverseString('hello'));
console.log(countOccurrences([1,2,3,2,1], 2));
EOFmulti_bug.js にあるすべてのバグを特定して修正してください。
バグの種類(構文エラー / 実行時エラー / 論理エラー / パフォーマンス)も分類してください。達成条件: 3つのバグがすべて修正され、各関数が正しい結果を返すこと
課題 3-2: スタックトレースの読み解き
bash
cat > ~/claude-practice/elementary/lesson3/deep_error.js << 'EOF'
function processOrder(order) {
const total = calculateTotal(order.items);
return { orderId: order.id, total, tax: applyTax(total) };
}
function calculateTotal(items) {
return items.map(item => getItemPrice(item)).reduce((a, b) => a + b);
}
function getItemPrice(item) {
return item.product.price * item.quantity;
}
function applyTax(amount) {
return amount * 0.1;
}
processOrder({
id: 'ORD-001',
items: [
{ product: { name: 'A', price: 100 }, quantity: 2 },
{ quantity: 3 }, // product が undefined
]
});
EOF
node ~/claude-practice/elementary/lesson3/deep_error.jsエラーとスタックトレースを Claude Code に渡して修正させせよ。
達成条件: 修正後に processOrder が product が undefined のアイテムを適切に処理すること
課題 3-3: テストで検出されないバグ
bash
cat > ~/claude-practice/elementary/lesson3/silent_bug.js << 'EOF'
function getUniqueUsers(transactions) {
const seen = {};
return transactions.filter(t => {
if (seen[t.userId]) return false;
seen[t.userId] = true;
return true;
});
}
// テスト(パスするが実はバグがある)
const txs = [
{ userId: 1, amount: 100 },
{ userId: 2, amount: 200 },
{ userId: 1, amount: 300 },
];
console.assert(getUniqueUsers(txs).length === 2, 'should be 2 unique users');
console.log('Test passed!');
EOF
node ~/claude-practice/elementary/lesson3/silent_bug.jssilent_bug.js を読んでください。
テストはパスしていますが、特定のケースで正しく動作しない潜在的なバグがあります。
どんな入力値でバグが発生するか特定して修正してください。ヒント: userId が 0 や false の場合を考えてみせよ。
達成条件: 潜在的なバグが発見・修正され、edge case でも正しく動作すること
