debugging について
開発者やチーム向けのデバッグスキルです。再現と証拠の収集から根本原因の修正、再発防止までを整理し、テストやエスカレーション、チーム連携も扱います。
主な機能
- 01再現手順と証拠の収集
- 02仮説の順位付けと個別検証
- 03根本原因の修正と回帰テスト
- 04再発防止、記録、エスカレーション
活用シーン
- 01本番アラートやQA報告の調査
- 02不安定なテストや断続的な障害の追跡
- 03性能低下や連携問題の診断
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ krzysztofsurdy/ code-virtuoso --skill debuggingインストール後、Claude Code で/debuggingを入力して読み込まれたか確認します。
同梱ファイルreferences/bug-categories.mdreferences/post-mortem-template.md
詳細
デバッグ
バグを発見して修正するための体系的な方法です。症状への対処より根本原因の分析を優先し、直感より証拠を重視し、再発後の対応より予防を重視します。
鉄則
根本原因を特定せずに修正しないでください。 バグが発生する「場所」だけでなく、「なぜ」発生するのかを説明できるようになるまで、決して修正を適用しないでください。症状だけを修正すると、新たなバグが生まれます。
使用する場面
- QA からのバグ報告、または本番環境でのアラート
- 原因がはっきりしないテスト失敗
- 断続的、または不安定な動作
- パフォーマンスの低下
- 「以前は動作していた」予期しない動作
- コンポーネント間の統合の失敗
ワークフロー
フェーズ 1:再現
調査を始める前に、確実に再現できる状態を作ります。
- エラーメッセージ、スタックトレース、ログ、スクリーンショット、ユーザーの操作手順など、すべての証拠を集めます
- 環境、データの状態、ユーザーの操作、タイミングなど、正確な条件を特定します
- バグの発生に不要なものをすべて取り除き、最小限の再現手順を作成します
- 再現が安定していることを確認します(断続的に発生する場合は、頻度と条件を記録します)
- 他の人が手順に従えるよう、再現手順を正確に書き残します
成果物:文書化した再現手順、最小限のテストケース
再現できない場合:試したことを記録し、環境の違いを確認して、計測情報を追加し、次に発生するのを待ちます。推測でフェーズ 2 に進まないでください。再現できないバグは記録し、「修正」しません。
フェーズ 2:調査
証拠を体系的に集めます。まだ仮説を立ててはいけません。このフェーズでは、説明ではなく観察に注力します。
- エラーメッセージとスタックトレースを、最初の行だけでなく、すべての行を最後まで読みます
- 最近の変更について Git の履歴を確認します(
git log --since="2 weeks ago"、git bisect) - エントリーポイントから失敗箇所までのデータフローを追跡します
- 境界を確認します。データがコンポーネント、サービス、またはレイヤーの境界を越えるのはどこですか?
- 環境のコンテキスト(バージョン、設定、依存関係、リソースの状態)を集めます
- 影響範囲を把握します。他に何が影響を受けていますか?これは局所的な失敗ですか、それともシステム全体に及ぶ問題ですか?
本番環境と開発環境でのデバッグ:
- 本番環境:まず影響を評価し、緩和策を講じます。調査の前に影響範囲を縮小できますか?読み取り専用アクセスのみを使用し、本番環境の状態を変更してデバッグしてはいけません。
- 開発環境:すべてを自由に制御できます。ブレークポイントの使用、状態の変更、一時的なログの追加を自由に行えます。
成果物:証拠ログ(確認した内容、場所、タイムスタンプ)、影響を受けたコンポーネントのマップ
フェーズ 3:仮説を立てる
証拠の強さに基づいて、競合する仮説に順位を付けます。
- 考えられる原因をすべて列挙します。最初に思いついた考えに固執しないでください
- 各仮説をバグのカテゴリに分類します(バグカテゴリのリファレンスを参照)
- 証拠の強さ(強/中/弱)、検証可能性(容易/困難)、可能性をそれぞれ評価します
- 可能性が最も高く、かつ最も検証しやすい仮説から選びます
- 各仮説を「裏付ける」ものと「否定する」ものを定義します
仮説テーブルの例:
| # | 仮説 | カテゴリ | 証拠 | 検証可能性 | テスト計画 |
|---|---|---|---|---|---|
| 1 | 更新後にキャッシュが古いデータを返す | 状態 | 書き込みから 2 秒後にも古い値がログに記録されている | 容易 | キャッシュを迂回して比較する |
| 2 | 2 つのワーカー間の競合状態 | 競合状態 | 断続的に発生し、高負荷との相関がある | 中 | ロックを追加し、ストレステストを行う |
| 3 | 上流の API が予期しない形式を返す | 統合 | 現時点で証拠なし | 容易 | 生のレスポンスを記録する |
成果物:証拠とテスト計画を添えた、順位付け済みの仮説一覧
フェーズ 4:テスト
仮説を一度に 1 つずつ検証します。テストごとに変更する変数は 1 つだけにします。
- 変更を 1 つ加えて、結果を観察します
- 仮説が確かめられたら、フェーズ 5 に進みます
- 仮説が否定されたら、エビデンスログを更新して次の仮説に進みます
- 結論が出ない場合は、計測を追加してエビデンスを集めます
- 仮説が 3 つ続けて否定されたら、作業を止めて前提を再検討します。バグのモデルが間違っている可能性があります。
危険信号(直ちにフェーズ 2 に戻ります):
- 「とりあえず応急処置をして、調査は後で」
- 複数のことを一度に変更する
- 理解せずに修正する
- なぜ機能するのか理解せず、インターネットで見つけた修正をコピー&ペーストする
出力:エビデンスの連鎖で裏付けられた根本原因
フェーズ 5:修正
症状が現れる場所ではなく、原因となっている箇所で修正を実装します。
- まず、バグを再現する失敗テストを書きます
- 根本原因に対処する、単一で的を絞った変更として修正を実装します
- 失敗していたテストが通ることを確認します
- 回帰を検出するため、テストスイート全体を実行します
- 修正内容を自分でレビューします。正しく、最もシンプルな解決策になっていますか?
修正の原則:
- エラーが現れる場所ではなく、不正なデータや状態が発生する SOURCE で修正します
- 多層防御を追加します。SOURCE を修正した後も、境界で検証します
- 実行時検証よりも、不正な状態を表現できないようにすることを優先します
- 1 つのバグ = 1 つの修正 = 1 つのコミット = 1 つのテスト
出力:回帰テストを含む修正、すべてのテストが通る状態
フェーズ 6:再発防止
この種のバグが再発しないようにします。
- 不正なデータが入り込んだ境界で、防御的な検証を追加します
- エラーメッセージを改善します。6 か月後でも、このエラーをすぐに理解できますか?
- 本番環境で発生した問題であれば、モニタリング/アラートを更新します
- バグが重大であれば、事後分析を作成します(事後分析テンプレートを参照)
- 調査結果をチームと共有します。そうすることで、組織の知見が蓄積されます
出力:再発防止策、事後分析(重大な場合)
バグのカテゴリ別の戦略
バグの種類によって、適切な調査方法は異なります。詳しくはバグカテゴリのリファレンスを参照してください。
| カテゴリ | 最初に行うこと | 主な手法 |
|---|---|---|
| ロジックエラー | コードを読み、条件を追跡する | ラバーダック法による確認、真理値表 |
| データの問題 | 各境界で実際のデータと期待されるデータを調べる | 境界でのログ記録、データフローの追跡 |
| 状態/競合状態 | すべての状態変更にタイムスタンプを追加する | シーケンス図、並行性の分析 |
| インテグレーションの失敗 | API コントラクトへの準拠を確認する | リクエスト/レスポンスのログ記録、コントラクトテスト |
| パフォーマンス | 推測する前にプロファイリングする | プロファイラー、フレームグラフ、クエリ分析 |
| 環境 | 正常な環境と問題のある環境を比較する | 差分分析、設定の監査 |
| 断続的/不安定 | まず可観測性を高める | 統計的なログ記録、ストレステスト |
エスカレーションの基準
次の場合はデバッグを中止し、エスカレーションします。
- 初期見積もり時間の 2 倍を超えて作業しても、意味のある進展がない
- 修正に、自分のコンポーネントの範囲を超えたアーキテクチャの変更が必要
- 根本原因が、自分では管理できない依存関係にある
- 同じ領域で 3 件以上のバグが見つかった。これは、パッチを追加するのではなく、コードの再設計が必要であることを意味します
- バグによって、根本的な設計上の欠陥が明らかになった
- 本番環境への影響が拡大しており、修正するより回避策やロールバックのほうが早い
エスカレーション先:
| 状況 | エスカレーション先 |
|---|---|
| 設計またはアーキテクチャの問題 | アーキテクト |
| 再現できず、追加情報が必要 | QA チーム |
| スコープ、優先度、トレードオフに関する質問 | PM/プロダクトオーナー |
| 依存関係またはインフラストラクチャの問題 | プラットフォーム/DevOps チーム |
| セキュリティへの影響が判明した | 直ちにセキュリティチーム |
判断のフレームワーク
修正の深さ
- エラーが現れる場所ではなく、不正なデータや状態が発生する SOURCE で修正します
- 多層防御を追加します。SOURCE を修正した後も、境界で検証します
- 実行時検証よりも、不正な状態を表現できないようにすることを優先します
修正の範囲
- 周辺のコードには手を加えず、特定のバグだけを修正します
- 近くにほかの問題があれば、別途報告します。バグ修正の範囲を広げないでください
- 1つのバグ = 1つの修正 = 1つのコミット = 1つのテスト
書き換えとパッチの使い分け
- パッチ:局所的なバグで、根本原因が明確であり、コードにほかの問題がない場合
- 書き換え:同じモジュールに3つ以上のバグがあり、根本原因が構造的で、修正より書き換えのほうが簡単な場合
- ロールバック:本番環境で重大な問題が発生しており、以前のバージョンが動作していた場合。まずロールバックし、その後でデバッグします
チームの役割との連携
このデバッグワークフローは、チーム全体のプロセスと連携します。
| フェーズ | チームとの連携 |
|---|---|
| 再現 | QA は再現手順を含むバグ報告を行います。不十分な場合は、詳細を求めます |
| 調査 | アーキテクトは、コンポーネントの依存関係と影響範囲の把握を支援します |
| 修正 | 2人目の目で修正によるリグレッションを検出できるよう、マージ前に同僚がコードをレビューします |
| 防止 | 事後分析をチームと共有し、対応項目をバックログで管理します |
このライブラリのほかのスキルを使う場合:
| 状況 | 推奨スキル |
|---|---|
| バグ修正で設計上の問題が明らかになった | design-patterns |
| 修正にリファクタリングが伴う | refactoring |
| SOLID 違反が根本原因である | solid |
| 修正の PR | pr-message-writer |
品質チェックリスト
バグ修正を完了とする前に、以下を確認してください。
- 根本原因を特定し、記録した
- 修正前から失敗するテストがあった
- 症状ではなく根本原因に対処した
- テストスイート全体が成功する
- 正しさを保つ最もシンプルな解決策である
- 必要に応じてエラーメッセージを改善した
- 重大なバグについて事後分析を作成した
- バグが共有コンポーネントに影響する場合、チームに通知した
重要なルール
-
根本原因なしに修正しないこと。 これは絶対のルールです。バグがなぜ存在するのか説明できないなら、調査はまだ終わっていません。
-
まず再現すること。 再現できないものを調査しないでください。再現できない場合は、可観測性を追加して待ちます。
-
変数を1つずつテストすること。 仮説の検証中は、一度に1つだけ変更します。複数の変数を変更すると、結果を解釈できなくなります。
-
直感より証拠を重視すること。 証拠を記録してください。「X かもしれない」は仮説ではありません。「ログ行 Y に値 Z が表示されているが、本来は W である」が仮説です。
-
修正の前後でテストすること。 リグレッションテストのない修正は、再び壊れます。
-
ためらわずにエスカレーションすること。 いつ調査を止めて助けを求めるべきかを知るのもスキルです。上記のエスカレーション基準を参照してください。
-
次の担当者のために記録すること。 この領域を次にデバッグするのは、6か月後のあなたかもしれません。コードベースの可観測性を、調査前より高めておきましょう。
-
本番環境を変更してデバッグしないこと。 調査は読み取り専用で行います。修正は通常のデプロイパイプラインを通じて適用します。
-
範囲を厳守すること。 バグだけを修正します。ほかの改善は別のチケットにします。
-
学んだことを共有すること。 重大なバグはすべて、チームにとって学びの機会です。事後分析は責任追及のためではなく、組織の記憶として残すものです。