1 分

Claude Codeによるバグトリアージ: 迅速な修正のための実践ループ

Claude Codeを使った反復可能なバグトリアージループ:再現、最小化、証拠に基づく原因特定、回帰テスト追加、狭い修正と検証。

Claude Codeによるバグトリアージ: 迅速な修正のための実践ループ

バグトリアージとは何か、そしてループが重要な理由

バグは、毎回の報告が一度きりの謎になると偶発的に感じられます。コードをつついていくつか試し、問題が消えることを期待する。たまにそれで直ることもありますが、学びは少なく、同じ問題が別の形で再発します。

バグトリアージはその反対です。不確実性を速やかに減らす方法です。目的はすべてをただちに直すことではありません。目的はあいまいな訴えを明確でテスト可能な宣言に変え、その宣言がもはや成り立たないことを示す最小の変更をすることです。

だからこのループが重要です:再現し、最小化し、証拠を伴って考えられる原因を特定し、回帰テストを追加し、狭い修正を実装し、そして検証する。各ステップが特定の種類の推測を取り除きます。ステップを飛ばすと、後でより大きな修正、副作用、あるいは「直った」と見せかけたまま実際は直っていないバグに苦しむことになります。

現実的な例を示します。ユーザーが「保存ボタンが時々何もしない」と言ったとします。ループがなければUIコードを漁り、タイミングや状態、ネットワーク呼び出しを変更してしまうかもしれません。ループを使うと、まず「時々」を「この正確な条件下では毎回」に変えます。たとえば:「タイトルを編集して、すぐにタブを切り替えると、保存が無効のままになる。」この一文だけで進展です。

Claude Codeは思考の速度を上げる手助けになります:レポートを正確な仮説に変え、どこを見ればいいかを提案し、失敗するはずの最小のテストを示してくれます。コード、ログ、最近の差分を素早くスキャンしてもっともらしい説明を生成するのに特に役立ちます。

それでも重要なのはあなた自身の検証です。自分の環境でバグが実際に発生することを確認してください。良い話に聞こえるだけではなく、ログ、トレース、失敗するテストなどの証拠を優先してください。修正はできるだけ小さくし、回帰テストで証明し、明確なチェックで検証して別のバグを生まないようにします。

見返りは、小さく安全な修正です。説明でき、防衛でき、再発を防げる修正が得られます。

トリアージ用ワークスペースの準備(コードに触る前に)

良い修正はクリーンなワークスペースと単一の明確な問題文から始まります。Claudeに聞く前に、ひとつの報告を選び、次のように書き直してください:

「私がXをすると、Yを期待するが、Zが起きる。」

その文が書けないなら、まだバグではなく謎を抱えています。

初めに基本情報を集めておけば、何度も戻る手間が省けます。これらの詳細が、提案をあいまいではなくテスト可能にします:アプリのバージョンやコミット(ローカル、ステージング、プロダクションのどれか)、環境詳細(OS、ブラウザ/デバイス、機能フラグ、リージョン)、正確な入力(フォームフィールド、APIペイロード、ユーザー操作)、誰が見ているか(全員、特定ロール、単一アカウント/テナント)、期待することの定義(文言、UI状態、ステータスコード、ビジネスルール)。

次に、証拠を保存してください。タイムスタンプひとつで何時間も節約できます。イベント周辺のログ(可能ならクライアントとサーバー)、スクリーンショットや短い録画、リクエストIDやトレースID、正確なタイムスタンプ(タイムゾーン込み)、問題を引き起こす最小のデータスニペットを取得します。

例:Koder.aiが生成したReactアプリで「Payment succeeded」と表示されるが注文は「Pending」のままになる。ユーザーロール、正確な注文ID、APIレスポンスボディ、該当リクエストIDのサーバーログ行を記録します。これでClaudeにあるフローに集中するように頼めます。

最後に終了ルールを設定します。コードを書き始める前に何をもって「直った」と見なすかを決めてください:特定のテストが通ること、UI状態が変わること、ログにエラーが出なくなること、さらに毎回実行する短い検証チェックリスト。こうすれば症状を「直した」として別のバグを出さずに済みます。

バグ報告をClaudeに対する正確な質問に変える

雑然としたバグ報告は事実、推測、感情が混ざっています。助けを求める前に、Claudeが証拠付きで答えられるような明確な質問に変えましょう。

まず、機能と失敗を名指しする1文の要約を作ります。良い例:「下書きを保存するときに、モバイルでタイトルが消えることがある。」悪い例:「下書きが壊れている。」その文がトリアージスレッド全体のアンカーになります。

次に見たものと期待したものを分けます。退屈で具体的に:押したボタン、画面のメッセージ、ログ行、タイムスタンプ、デバイス、ブラウザ、ブランチ、コミット。もしまだ無ければ、その旨を書きます。

貼り付け可能な簡単な構成:

  • Summary (one sentence)
  • Observed behavior (what happened, including any error text)
  • Expected behavior (what should happen)
  • Repro steps (numbered, smallest set you know)
  • Environment (app version, device, OS, browser, config flags)

欠けている詳細があれば、はい/いいえで答えられる質問にして尋ねてください:新しいアカウントで起きるか?モバイルのみか?リフレッシュ後だけか?最後のリリース以降か?シークレットウィンドウで再現するか?

Claudeは「レポート整形屋」としても有用です。元の報告(スクリーンショットのテキスト、ログ、チャットの断片を含む)を貼り付けて、こう頼んでください:

「これを構造化されたチェックリストに書き直して。矛盾を指摘して。トップ5の欠けている事実をはい/いいえ質問で挙げて。原因はまだ推測しないで。」

もしチームメイトが「ランダムに落ちる」と言ったら、それをテスト可能な形に押し上げてください:「iPhone 14、iOS 17.2で2/10回失敗、Saveを素早く2回タップすると発生」——これで意図的に再現できます。

ステップ1 - バグを確実に再現する

バグを任意に発生させられないなら、その後の作業はすべて推測です。

まず、問題を示せる最小限の環境で再現します:ローカルのdevビルド、最小ブランチ、最小データセット、できるだけ少ないサービスで。

正確な手順を書き留め、他の人が質問せずにそのまま実行できるようにします。コマンド、ID、サンプルペイロードをそのままコピーできる形式で含めてください。

シンプルなキャプチャテンプレート:

  • Setup: branch/commit, config flags, database state (empty, seeded, production copy)
  • Steps: numbered actions with exact inputs
  • Expected vs actual: what you thought would happen, what happened instead
  • Evidence: error text, screenshots, timestamps, request IDs
  • Frequency: always, sometimes, first run only, only after a refresh

頻度は戦略を変えます。"Always"のバグは反復が速くて扱いやすい。"Sometimes"はタイミング、キャッシュ、レースコンディション、隠れた状態を示すことが多い。

再現ノートができたら、Claudeにアプリを書き換えず不確実性を減らすための素早いプローブを頼んでください。良いプローブは小さいものです:失敗境界付近の1行のログ(入力、出力、キーとなる状態)、特定コンポーネントのデバッグフラグ、決定論的な挙動を強制する方法(固定乱数シード、固定時刻、単一ワーカー)、問題を引き起こす小さなシードデータセット、再生できる単一のリクエスト/レスポンスペア。

例:サインアップフローが「ときどき」失敗する場合、Claudeは生成されるユーザーID、メール正規化結果、ユニーク制約エラーの詳細をログに出し、同じペイロードを10回実行することを提案するかもしれません。もし失敗がデプロイ直後の最初の実行だけなら、マイグレーション、キャッシュウォームアップ、欠落したシードデータを疑うべきです。

ステップ2 - 小さく、再現可能なテストケースに最小化する

Test server-side fixes
Prototype Go plus PostgreSQL flows and reproduce API edge cases with less friction.

良い再現は有用です。最小の再現は強力です。理解が速く、デバッグしやすく、誤って「直った」ことが起きにくいからです。

必要ないものはすべて削ぎ落とします。長いUIフローのあとでバグが出るなら、まだ発生する最短経路を見つけます。オプションの画面、機能フラグ、無関係な統合を取り除き、バグが消えるか残るかを確認します。

次にデータを縮めます。大きなペイロードが必要なら、壊れる最小のペイロードを探します。500件のリストが必要なら、5件、次に2件、次に1件で試します。フィールドを1つずつ削除します。目標は、バグを再現するために必要最小限の要素だけを残すことです。

実務的な方法は「半分に切って再テストする」:

  • ステップを半分に切ってバグが残るか確認する
  • 残るならさらに半分にする
  • 止まるなら削った半分を戻して別の切り方をする
  • バグを失わずにこれ以上削れなくなるまで繰り返す

例:クーポンを適用するときにチェックアウトページが時々クラッシュする。調べた結果、カートに少なくとも1つの割引対象アイテムがあり、クーポンが小文字で、配送方法が"pickup"のときだけ失敗することが分かった。これが最小ケースだ:1つの割引商品、1つの小文字クーポン、1つのピックアップ設定。

最小ケースが明確になったら、Claudeにそれを小さな再現スキャフォールドに変えてもらいましょう:失敗する関数を最小の入力で呼ぶテスト、縮小したペイロードで1つのエンドポイントを叩く短いスクリプト、1つのルートを訪れて1つのアクションを行う小さなUIテストなど。

ステップ3 - 証拠を伴って考えられる根本原因を特定する

問題を再現でき、最小テストケースを持っているなら、推測はやめてください。短い候補リストに絞り、それぞれを立証または否定するのが目的です。

有用なルールは仮説を3つに抑えること。3つを超えるならテストケースがまだ大きいか観察があいまいです。

症状をコンポーネントにマップする

見ているものを、どこで起きている可能性があるかに変換します。UIの症状が必ずしもUIバグを意味しないことに注意してください。

例:Reactページで「Saved」のトーストが出るが後でレコードが見つからない。これは(1)UI状態、(2)API挙動、(3)データベース書き込み経路のいずれかを示します。

各仮説のための証拠を作る

Claudeに平易な言葉で起こりうる失敗モードを説明してもらい、それぞれを確かめる証拠を尋ねてください。目標は「もしかして」から「これをチェックして」と言える状態にすることです。

3つの一般的な仮説と集めるべき証拠:

  • UI/状態の不整合:クライアントがサーバーの確認前にローカル状態を更新している。証拠:操作前後の状態スナップショットとAPIレスポンスを比較する。
  • APIのエッジケース:ハンドラが200を返すが処理を黙ってスキップしている(バリデーション、IDパース、機能フラグ)。証拠:相関ID付きのリクエスト/レスポンスログを追加し、ハンドラが期待する書き込み呼び出しに到達しているか確認する。
  • DBまたはタイミングの問題:トランザクションがロールバックされる、競合エラーが発生する、あるいは「書き込み後の読み取り」がキャッシュ/レプリカから返る。証拠:実行されたクエリ、影響行数、エラーコードを調べ、トランザクション境界と再試行挙動をログに記録する。

ノートは簡潔に:症状、仮説、証拠、判定。1つの仮説が事実と合致すれば、回帰テストを固定し、必要最低限だけを直す準備ができます。

ステップ4 - 正しい理由で失敗する回帰テストを追加する

良い回帰テストは安全ベルトです。バグが存在したことを証明し、真に直ったかを教えてくれます。

まず、実際の失敗に合った最小のテストを選びます。バグが複数のパートの協調で起きるなら、ユニットテストでは見逃すことがあります。

バグに合ったテストレベルを選ぶ

関数が誤った値を返すならユニットテストを、境界の問題なら統合テストを(APIハンドラ+DB、クライアント+API)、フルユーザーフローが必要ならE2Eを選びます。

Claudeに何か書いてもらう前に、最小化ケースを厳密な期待動作として言い直してください。例:「ユーザーが空のタイトルを保存した場合、APIは'400'と'title required'メッセージを返すこと」。こうすればテストのターゲットが明確になります。

次にClaudeにまず失敗するテストを起草してもらいましょう。セットアップは最小限にし、バグを引き起こすデータだけをコピーしてください。テスト名は内部関数ではなくユーザー体験に基づいて名付けます。

草案を検証する(盲信しない)

ざっと自分で確認してください:

  • 現行コードで意図した理由で失敗するか(フィクスチャ不足や間違ったimportで失敗していないか)
  • アサーションが具体的か(正確なステータスコード、メッセージ、レンダーテキスト)
  • テストが1つのバグだけをカバーしているか
  • 名前がユーザー中心か(例:「rejects empty title on save」ではなく「保存時に空のタイトルを拒否する」など)

テストが正しい理由で失敗したら、狭い修正を自信を持って進められます。

ステップ5 - 狭い修正を実装する

Review fixes on a real URL
Share a stable test build with stakeholders using a custom domain when needed.

小さな再現と失敗する回帰テストがあれば、「掃除しておこう」という誘惑に抵抗してください。目標はテストを正しい理由で通すための最小の変更です。

良い狭い修正は影響範囲が小さいものです。失敗が1つの関数にあるならその関数を直し、モジュール全体を変えないでください。境界チェックが欠けているなら境界でチェックを追加し、呼び出し全体に広げないでください。

Claudeに手伝ってもらうなら、2つの修正案を出してもらい、範囲とリスクで比較してください。例:フォームが空のフィールドでクラッシュする場合、

  • オプションA:submitハンドラに空チェックを入れてエラー表示する。 (小さく安全)
  • オプションB:状態管理をリファクタしてフィールドが空にならないようにする。(広範囲でリスクあり)

通常トリアージではAを選びます:小さく、レビューしやすく、壊す可能性が低い。

狭い修正を保つためのルール:できるだけ少ないファイルを触る、リファクタより局所修正を優先する、悪い値が入る境界でガードを追加する、挙動変更は1つの明確なビフォー/アフターにする。理由が明白でない場合にのみコメントを残します。

具体例:GoのAPIエンドポイントがオプションクエリパラメータがないとpanicするなら、狭い修正はハンドラの境界で空文字を処理する(デフォルトでパースするか、400を返す)。共有パーサユーティリティを変えるのは、回帰テストが共有コードに原因があると証明した場合に限ります。

変更後は失敗したテストと近接する1〜2テストを再実行します。関係ない多くのテストを更新する必要があるなら、変更が広すぎるサインです。

ステップ6 - 明確なチェックで修正を検証する

検証では、1つのテストを通すだけで見逃しがちな問題を捕まえます:ある修正が1つのテストは通すが近いパスを壊す、エラーメッセージを変える、遅いクエリを導入する、など。

まず追加した回帰テストを再実行してください。通ったら近接するテスト(同じファイル、モジュール、同じ入力を扱うもの)を実行します。バグは共有ヘルパー、パース、境界チェック、キャッシュに潜むことが多く、関係ある失敗は近くに出ることが多いです。

その後、元の報告手順に従った簡単な手動チェックを行います。短く具体的に:同じ環境、同じデータ、同じクリックやAPI呼び出しの順序。報告があいまいだったら、あなたが再現に使った正確なシナリオで試します。

簡単な検証チェックリスト

  • 回帰テストが通ること、及び近接テストも確認
  • 手動の再現手順でバグが再現しないこと
  • エラーハンドリングが妥当であること(メッセージ、ステータスコード、リトライ)
  • 端ケースが正しく振る舞うこと(空入力、最大値、特殊文字)
  • 明らかなパフォーマンス悪化がないこと(余分なループ、余分な呼び出し、遅いクエリ)

必要ならClaudeにあなたの変更と失敗シナリオを共有して短い検証プラン(単体、統合、手動チェック)を作ってもらってください。最高のプランは短く実行可能で、5〜8個のチェックに分かれており、それぞれに明確な合否基準があります。

最後に、PRやノートに何を検証したかを書いておきます:実行したテスト、試した手動手順、テストしていない範囲(例:「モバイルは未確認」)など。こうすれば修正が信頼しやすくなります。

よくあるミスと落とし穴(回避方法付き)

Turn bugs into tests
Draft minimal regression tests and tighten them into a reliable safety net.

最速で時間を無駄にする方法は、再現できる前に「直した」と受け入れることです。確実に失敗させられないなら、何が本当に改善したか分かりません。

実務的ルール:正確な手順、入力、環境、何が"間違っている"かを記述できるまでは修正を求めないでください。報告があいまいなら、最初の数分を使って2回実行して同じ結果が出るチェックリストに変えてください。

作業を遅らせる落とし穴

再現ケースなしで修正する。 最小の「毎回失敗する」スクリプトや手順を要求してください。もし「ときどき」なら、タイミングやデータサイズ、フラグ、ログを記録してランダム性を取り除くまで続けてください。

早すぎる最小化。 元の失敗をロックダウンする前にケースを削りすぎると信号を失います。まずベースライン再現を確認し、そこから一つずつ縮めていってください。

Claudeに推測させる。 Claudeは可能性を提案できますが、証拠が必要です。2〜3の仮説と、それぞれを支持/棄却するための具体的観察(ログ行、ブレークポイント、クエリ結果)を求めてください。

間違った理由で通る回帰テスト。 テストが通る理由が失敗パスに到達していないことがあります。修正前にテストが失敗すること、期待するメッセージやアサーションで失敗することを確認してください。

症状を処理してしまい、トリガーを直さない。 nullチェックを追加しただけで「その値はそもそもnullになってはいけない」という本当の問題を隠してしまうことがあります。悪い状態を生む条件を優先して直す方が望ましい場合があります。

終了前の簡単なサニティチェック

新しい回帰テストと元の再現手順を変更前と変更後で実行してください。もしチェックアウトのバグが、配送変更後にプロモコードを適用したときだけ起きるのなら、その全シーケンスを"真実"として保持してください(最小化したテストが小さくても)。

「今は見た目問題ない」で検証が終わるなら、次の人が素早く確かめられるように1つの具体的なチェック(ログ、メトリクス、特定の出力)を追加してください。

迅速なチェックリスト、プロンプトテンプレート、次のステップ

時間がないときは、小さく繰り返せるループが英雄的なデバッグに勝ります。

1ページのトリアージチェックリスト

  • Reproduce:確実な再現を得て、正確な入力、環境、期待値と実際の差分を記録する
  • Minimize:それでも失敗する最小の手順やテストに減らす
  • Explain:2〜3の根本原因候補とそれぞれの証拠を列挙する
  • Lock it in:正しい理由で失敗する回帰テストを追加する
  • Fix + validate:最小の変更を行い、短い検証チェックリストで確認する

最終決定は数行で書いておき、次の人(多くの場合は将来の自分)が信頼できるようにします。役立つフォーマット:"Root cause: X. Trigger: Y. Fix: Z. Why safe: W. What we did not change: Q."。

貼り付けられるプロンプトテンプレート

  • “Given this bug report and logs, ask me only the missing questions needed to reproduce it reliably.”
  • “Help me minimize: propose a smaller test case and tell me what to remove first, one change at a time.”
  • “Rank likely root causes and cite the exact files, functions, or conditions that support each claim.”
  • “Write a regression test that fails only because of this bug. Explain why it fails for the right reason.”
  • “Suggest the narrowest fix, plus a validation checklist (unit, integration, and manual checks) that proves we didn’t break nearby behavior.”

次のステップ:自動化できるものは自動化してください(保存した再現スクリプト、標準テストコマンド、根本原因ノートのテンプレートなど)。

もしあなたがKoder.ai(koder.ai)でアプリを作るなら、Planning Modeはコードに触る前に変更のアウトラインを作るのに役立ち、スナップショット/ロールバックは難しい再現作業中に安全に実験するのを容易にします。修正が検証されたら、ソースをエクスポートしたり、更新したアプリをホストしてデプロイしたりできます(必要ならカスタムドメインも設定可能)。

よくある質問

What is bug triage, in plain terms?

バグトリアージとは、あいまいな報告を「テストできる明確な文」に変え、その文がもう成り立たないことを証明するために最小限の変更を加える習慣です。

それは「すべてを直す」ことよりも不確実性を段階的に減らすことに重きを置きます:再現、最小化、証拠に基づく仮説作成、回帰テスト、狭い修正、検証。

Why does the reproduce → minimize → test → fix loop matter so much?

それぞれのステップが別の種類の推測を取り除くからです。

  • Reproduce: 問題が実在し再現可能であることを証明する
  • Minimize: ノイズを取り除き、関連のない挙動を追わないようにする
  • Hypothesize with evidence: 間違った箇所を直すのを防ぐ
  • Regression test: バグが存在したことと再発しないことを証明する
  • Narrow fix + validation: 副作用や再発を減らす
How do I turn a messy bug report into something actionable?

次のように書き直してください:「私がXをすると、Yを期待するが、Zが起きる」

その後、テスト可能にするために必要なコンテキストだけを集めます:

  • バージョン/コミット + 発生箇所(local/staging/prod)
  • 環境(デバイス、OS、ブラウザ、フラグ、リージョン)
  • 正確な入力/操作
  • 影響範囲(全ユーザー、特定ロール、単一テナント)
  • 証拠(タイムスタンプ、エラーテキスト、リクエスト/トレースID、ログ)
What should I do first if I can’t reproduce the bug?

まずはローカル開発環境など、問題を示せる最小の環境で再現できるか確認してください。

「ときどきしか起きない」なら、変数を制御して決定論的にする努力をします:

  • 同じペイロードを10回再実行する
  • 時刻や乱数を固定できるなら固定する
  • 並行性を下げる(単一ワーカー/スレッド)
  • 失敗しそうな境界に限定したログを追加する

再現できるようになるまでは先に進まないでください。できなければ推測になってしまいます。

How do I minimize a bug to a small test case?

最小化とは、バグを引き起こすために必要なもの以外を削ることです。

実務的な方法は「半分に切って再テストする」:

  • 手順やデータを半分に切ってみる
  • まだ失敗するならさらに半分にする
  • 止まったら戻して別の半分を試す

手順(短いユーザーフロー)とデータ(小さなペイロード、少ないアイテム)の両方を縮め、最小の再現トリガーを見つけます。

How can Claude Code help without turning into guesswork?

Claude Codeは分析を速めますが、検証を置き換えません。

良いリクエスト例:

  • 「ここが再現手順とログです。2〜3個の仮説と、それぞれを確認するための証拠を挙げてください。」
  • 「このdiffとスタックトレースなら、最も怪しい境界はどこですか?」
  • 「この正確なシナリオ用の最小の失敗テストを書いてください。」

その後、ローカルで再現し、ログ/トレースを確認し、テストが正しい理由で失敗することを確かめてください。

How many root-cause hypotheses should I consider at once?

同時に考える仮説は3つに抑えてください。それ以上だと再現ケースがまだ大きいか、観察があいまいなことが多いです。

各仮説について書くもの:

  • symptom(観察)
  • hypothesis(原因の候補)
  • evidence to collect(確認する1つのログ行、ブレークポイント、クエリ結果)
  • verdict(支持/棄却)

これにより作業が前に進みます。

What makes a good regression test for a bug?

バグに合った最小のテストレベルを選んでください:

  • Unit test:単一関数の誤り
  • Integration test:境界(ハンドラ+DB、クライアント+API)
  • End-to-end:フルフローが必要な場合のみ

良い回帰テストは:

  • 現行コードで意図した理由で失敗する
  • 具体的なアサーションを持つ(ステータスコード、メッセージ、表示テキスト)
  • 1つのバグだけを検証する
How do I keep a fix narrow and low-risk?

失敗する回帰テストを通す最小限の変更を行ってください。

経験則:

  • 変更ファイルは最小限にする
  • 悪い値が入る境界で検証を行う
  • トリアージ段階ではガード/バリデーションを優先し、リファクタは避ける
  • 多数の無関係テストを更新する必要があるなら範囲が広すぎるサインです
How do I validate the fix so the bug doesn’t come back?

短いチェックリストで手早く検証してください:

  • 回帰テストが通る
  • 近傍のテスト(同じモジュール/入力)が通る
  • 元の再現手順でバグが再現しない
  • エラーハンドリング(メッセージ、ステータスコード)が妥当
  • 端ケース(空入力、最大長、特殊文字)を簡単に確認
  • 明らかなパフォーマンス低下がない

実行したことと実行しなかったことをPRやノートに記録しておくと信頼できる修正になります。

Related posts