Claude Codeでバグを素早く見つけて修正するテクニック
エラー解析からホットフィックスまでのデバッグワークフロー
デバッグにおけるClaude Codeの強み
デバッグは開発時間の大きな割合を占める作業です。Claude Codeはエラーメッセージの解析、コードの論理的な追跡、修正案の提示を高速に行えるため、デバッグワークフローを劇的に加速できます。
従来のデバッグでは、エラーメッセージをGoogle検索し、Stack Overflowの回答を読み、自分のコードに当てはめるという手順が必要でした。Claude Codeなら、エラーの文脈(コードベース全体)を理解した上で、プロジェクト固有の修正案を即座に提示してくれます。
Claude Codeデバッグの5ステップ
- バグの記述: 症状・再現手順・期待される動作を伝える
- 調査: Claude Codeが関連ファイルを読み取り原因を探る
- 根本原因の特定: 表面的な症状ではなく本質的な原因を突き止める
- 修正の実施: 適切な修正コードを生成・適用する
- 検証: 修正が正しく機能し、副作用がないことを確認する
バグの種類と対処アプローチ
バグにはさまざまな種類があり、それぞれ最適なアプローチが異なります。Claude Codeに伝える情報もバグの種類によって変わります。
| バグの種類 | 特徴 | Claude Codeへの伝え方 | 難易度 |
|---|---|---|---|
| 構文エラー | コードが実行できない | エラーメッセージをそのまま貼り付け | ★☆☆ |
| ロジックバグ | 動くが結果が間違い | 期待値と実際の出力を両方提示 | ★★☆ |
| 非同期処理バグ | タイミング依存で不安定 | 発生条件・頻度・レースコンディションの疑いを伝える | ★★★ |
| 依存関係バグ | ライブラリ更新で動かない | バージョン情報・変更ログの要点を共有 | ★★☆ |
| 環境依存バグ | 特定環境でのみ発生 | 環境の差異(OS、Node版、設定等)を列挙 | ★★☆ |
| パフォーマンス問題 | 動作が遅い・メモリリーク | プロファイル結果・ボトルネック箇所を共有 | ★★★ |
実践例1: ランタイムエラーのデバッグ
最も基本的なデバッグパターンです。エラーメッセージとスタックトレースをClaude Codeに渡して、原因と修正を依頼します。
エラーメッセージを貼り付けてデバッグ依頼
あなた: 以下のエラーが発生しています。原因を調査して修正してください。
TypeError: Cannot read properties of undefined (reading 'map')
at UserList (/src/components/UserList.tsx:24:31)
at renderWithHooks (react-dom.development.js:14985)
at mountIndeterminateComponent (react-dom.development.js:17811)
Claude Code: エラーを分析します。UserList.tsxの24行目で、undefinedに対して
.map()を呼び出しています。該当ファイルを確認します。
[UserList.tsx を読み取り]
原因が特定できました。useQueryで取得したデータに対して、ローディング中の
ガード処理がありません。
// 修正前(24行目)
const userItems = data.users.map(user => ...);
// 修正後
if (isLoading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
if (!data?.users) return <EmptyState />;
const userItems = data.users.map(user => ...);
この修正により、データ取得完了前にmapが呼ばれることを防ぎます。
適用してよろしいですか?
実践例2: ロジックバグのデバッグ
ロジックバグはエラーが出ないため、最も厄介なバグです。「期待される動作」と「実際の動作」を明確に伝えることが重要です。
期待値と実際の出力を比較してデバッグ
あなた: 税込価格の計算がおかしいです。
- 商品価格: 1980円、税率: 10%
- 期待される結果: 2178円
- 実際の結果: 2177円
calculateTaxIncludedPrice関数を調べてください。
Claude Code: 関数を確認します。
[utils/price.ts を読み取り]
問題を発見しました。浮動小数点演算の丸め誤差です。
// 現在のコード
function calculateTaxIncludedPrice(price: number, taxRate: number): number {
return Math.floor(price * (1 + taxRate)); // 1980 * 1.1 = 2177.9999... → 2177
}
// 修正案: 整数演算で計算
function calculateTaxIncludedPrice(price: number, taxRate: number): number {
return Math.floor(price + price * taxRate + 0.5);
// または: Math.round(price * (1 + taxRate))
}
JavaScriptの浮動小数点数では 1980 * 1.1 が正確に 2178 にならず、
2177.9999...となるため、Math.floorで切り捨てられて2177になります。
実践例3: 非同期処理のバグ
レースコンディションやデッドロックなど、タイミングに依存するバグは再現が難しく、デバッグに時間がかかります。Claude Codeに処理フローを分析させると効果的です。
レースコンディションの調査
あなた: ユーザー登録フォームで、送信ボタンを素早く2回クリックすると
ユーザーが重複登録されることがあります。registerUser関数と
関連するAPIハンドラーを調べてください。
Claude Code: フロントエンドとバックエンドの両方を確認します。
[components/RegisterForm.tsx, api/users/route.ts を読み取り]
2つの問題を発見しました。
問題1(フロント): ボタンの二重クリック防止がない
// 修正: 送信中フラグを追加
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async () => {
if (isSubmitting) return;
setIsSubmitting(true);
try { await registerUser(formData); }
finally { setIsSubmitting(false); }
};
問題2(バックエンド): ユニーク制約がない
// 修正: DBレベルでの一意性保証
await db.execute(`
INSERT INTO users (email, name)
SELECT ?, ?
WHERE NOT EXISTS (SELECT 1 FROM users WHERE email = ?)
`, [email, name, email]);
フロントとバックの両方で対策することが重要です。
実践例4: パフォーマンス問題の調査
アプリケーションの動作が遅い場合、ボトルネックの特定が最初のステップです。Claude Codeにコードを分析させ、N+1クエリやメモリリークなどの典型的な問題を検出させましょう。
N+1クエリ問題の検出と修正
あなた: /api/posts のレスポンスが遅いです(3秒以上かかる)。
投稿一覧を取得するAPIですが、投稿数が増えるほど遅くなります。
パフォーマンス問題を調べてください。
Claude Code: APIハンドラーを分析します。
[api/posts/route.ts を読み取り]
典型的なN+1クエリ問題を発見しました。
// 現在のコード(N+1問題あり)
const posts = await db.query('SELECT * FROM posts LIMIT 50');
for (const post of posts) {
post.author = await db.query(
'SELECT name, avatar FROM users WHERE id = ?', [post.user_id]
); // 50件のpostに対して50回のクエリが発生
post.comments_count = await db.query(
'SELECT COUNT(*) FROM comments WHERE post_id = ?', [post.id]
); // さらに50回のクエリ → 合計101クエリ
}
// 修正: JOINとサブクエリで1回のクエリに統合
const posts = await db.query(`
SELECT p.*, u.name AS author_name, u.avatar AS author_avatar,
(SELECT COUNT(*) FROM comments c WHERE c.post_id = p.id) AS comments_count
FROM posts p
JOIN users u ON p.user_id = u.id
ORDER BY p.created_at DESC
LIMIT 50
`);
101回のDBクエリが1回に削減され、レスポンス時間は大幅に改善されます。
デバッグ効率を上げるプロンプトのコツ
効果的なバグ報告の5要素
- 再現手順: 「〇〇を入力して△△ボタンをクリックすると」
- 期待される動作: 「□□が表示されるはず」
- 実際の動作: 「××というエラーが出る」
- 環境情報: OS、ブラウザ、Node/PHPバージョンなど
- エラーログ: スタックトレース、コンソール出力をそのまま
プロのヒント: エラーメッセージは省略せず、スタックトレース全体をClaude Codeに渡しましょう。省略すると、重要な手がかりが失われることがあります。また、「たぶんこの辺が原因」という推測も一緒に伝えると、調査の出発点になります。
デバッグ後のベストプラクティス
バグを修正したら、再発防止のための対策も一緒に依頼しましょう。
修正後にやるべきこと
- テストの追加: 「このバグを再現するテストケースを書いて」と依頼する
- 類似バグの検索: 「同じパターンのバグが他にないか検索して」と依頼する
- 根本原因の共有: チーム向けに原因と対策をドキュメント化する
- 防御的コーディング: バリデーションやガード句を追加して同種のバグを予防する
- コミットメッセージ: バグの原因と修正内容を明記した詳細なコミットメッセージを書く