systematic-debugging について
Systematic Debuggingは、コードを変更する前に技術的な問題を調査するようエージェントを導くスキルです。再現可能なテストループ、根本原因の分析、仮説の検証、修正後の確認を4段階で進めます。
主な機能
- 01修正前に根本原因を調査
- 02高速で再現可能なテストループを構築
- 03変更、データフロー、コンポーネント境界を追跡
- 04仮説を順位付けして一つずつ検証
- 05回帰テストを追加して修正を確認
活用シーン
- 01失敗したテストや本番環境のバグを調査
- 02断続的な挙動を再現して分析
- 03システムコンポーネントをまたぐ問題を追跡
- 04無関係な変更を避けて修正案を検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nousresearch/ hermes-agent --skill systematic-debuggingインストール後、Claude Code で/systematic-debuggingを入力して読み込まれたか確認します。
詳細
系統的なデバッグ
概要
場当たり的な修正は時間を浪費し、新たなバグを生みます。手早いパッチは根本的な問題を覆い隠します。
基本原則: 修正を試みる前に、必ず根本原因を見つけてください。症状への対処は失敗です。
このプロセスの文言だけに従い、その精神に反することは、デバッグの精神に反することです。
鉄則
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
フェーズ 1 を完了していない場合、修正案を提示することはできません。
フィードバックループのルール
フィードバックループこそがデバッグ作業です。仮説を立てるためにコードを読む前に、ユーザーが報告した症状を正確に再現して失敗し、バグ修正後に成功する厳密なコマンドを作成するか、特定してください。厳密なループは高速で、決定論的で、エージェントが実行でき、このバグを確実に検出するものでなければなりません。単に「クラッシュしない」だけでは不十分です。
クリーンな再現が難しい場合は、ループの構築に十分な労力をかけてください。失敗を検出できるループなしに推測することこそ、このスキルが防ごうとしている失敗パターンです。
使用する場面
あらゆる技術的な問題に使用します。
- テストの失敗
- 本番環境のバグ
- 予期しない動作
- パフォーマンスの問題
- ビルドの失敗
- インテグレーションの問題
特に次のような場合に使用してください。
- 時間に追われている(緊急時には推測に頼りたくなります)
- 「すぐにできる簡単な修正」が明らかに思える
- すでに複数の修正を試した
- 以前の修正がうまくいかなかった
- 問題を十分に理解できていない
次の場合も省略しないでください。
- 問題が単純に見える(単純なバグにも根本原因があります)
- 急いでいる(急ぐと手戻りが確実に増えます)
- 誰かが今すぐ直すよう求めている(試行錯誤を繰り返すより、体系的に進める方が速いです)
4 つのフェーズ
次のフェーズに進む前に、各フェーズを必ず完了してください。
フェーズ 1:根本原因の調査
修正を試みる前に、必ず以下を行ってください。
1. エラーメッセージを注意深く読む
- エラーや警告を読み飛ばさないでください
- 正確な解決策が記されていることがよくあります
- スタックトレースを最後まで読んでください
- 行番号、ファイルパス、エラーコードを確認してください
アクション: 関連するソースファイルに対して read_file を使用してください。コードベース内でエラー文字列を探すには search_files を使用してください。
2. 厳密なフィードバックループを構築する
- 1 つのコマンドで、ユーザーが報告した症状を正確に再現できますか?
- このバグがあるとコマンドは失敗し、バグを修正した場合にのみ成功しますか?
- 繰り返し実行できるほど高速ですか?
- 決定論的ですか? 不安定なバグの場合、デバッグできるほど再現率を高められますか?
- 再現できない場合は、推測せず、さらにデータを集めてください。
ループの構築方法 — おおよそ次の順番で試してください。
- バグに到達する接点における失敗するテスト:ユニット、インテグレーション、またはエンドツーエンド。
- 実行中の開発サーバーに対する HTTP スクリプト/curl。
- フィクスチャ入力を使った CLI の呼び出し。stdout/stderr を期待される出力と比較します。
- DOM、コンソール、またはネットワークを検証するヘッドレスブラウザースクリプト(Playwright/Puppeteer)。
- 記録済みのトレースを再生:HAR、リクエストペイロード、イベントログ、キューメッセージ、または Webhook の本文。
- システムの最小限の有用な部分を起動し、失敗する経路を呼び出す使い捨てのハーネス。
- 広範な入力空間で断続的に誤った出力が発生する場合のプロパティ/ファジングループ。
- 既知の 2 つの状態の間でバグが発生した場合の、
git bisect runに適した二分探索用ハーネス。 - 旧バージョンと新バージョン、2 つの設定、2 つのプロバイダー、または 2 つのデータセットを比較する差分ループ。
- 最後の手段としてのみ、人間が介在するスクリプトを使用します。人間の手順をスクリプト化し、その結果を記録して、ループの構造を保ちます。
ループを構築したら、さらに厳密にします。
- 高速化する:セットアップをキャッシュし、対象範囲を絞り、無関係な初期化を省きます。
- シグナルを明確にする:一般的な成功ではなく、症状そのものを検証します。
- 決定性を高める:時刻を固定し、乱数シードを指定し、ファイルシステムを分離し、ネットワークを固定します。
非決定的なバグでは、まず再現率を高めることを目指します。完璧である必要はありません。トリガーを 100 回実行したり、並列化したり、負荷をかけたり、タイミングの範囲を狭めたり、スリープを挿入したりします。50%の確率で発生する不安定なバグはデバッグできますが、1%では通常困難です。
アクション: terminal ツールを使用して、厳密なループを実行してください。
# Run a specific failing test
pytest tests/test_module.py::test_name -v
# Or run a scripted repro
python scripts/repro_bug.py
# Or run a high-repetition flaky repro
for i in {1..100}; do pytest tests/test_flake.py::test_name -q || break; done
3. 最近の変更を確認する
- 原因となりうる変更は何ですか?
- Git の差分、最近のコミット
- 新しい依存関係、設定の変更
アクション:
# Recent commits
git log --oneline -10
# Uncommitted changes
git diff
# Changes in specific file
git log -p --follow src/problematic_file.py | head -100
4. 複数のコンポーネントで構成されるシステムの証拠を集める
システムに複数のコンポーネントがある場合(API → サービス → データベース、CI → ビルド → デプロイ):
修正を提案する前に、診断用の計測を追加します:
各コンポーネントの境界ごとに:
- コンポーネントに入力されるデータを記録する
- コンポーネントから出力されるデータを記録する
- 環境設定/構成の伝播を確認する
- 各レイヤーの状態を確認する
1 回実行して、問題が発生する場所を示す証拠を集めます。 その後、証拠を分析して、問題のあるコンポーネントを特定します。 その後、その特定のコンポーネントを調査します。
5. データフローをたどる
エラーがコールスタックの深い場所で発生している場合:
- 不正な値はどこで発生していますか?
- どこからこの関数が不正な値とともに呼び出されましたか?
- 発生源が見つかるまで上流をたどります
- 症状ではなく発生源を修正します
アクション: search_files を使って参照をたどります:
# Find where the function is called
search_files("function_name(", path="src/", file_glob="*.py")
# Find where the variable is set
search_files("variable_name\\s*=", path="src/", file_glob="*.py")
フェーズ 1 の完了チェックリスト
- エラーメッセージをすべて読み、内容を理解した
- 短いループを実行するコマンドがあり、少なくとも 1 回実行した
- ループで失敗を検出できる:近似した別の失敗ではなく、ユーザーが示した症状そのものを検証する
- ループが決定的である、または不安定なバグの再現率がデバッグに十分な高さである
- 最近の変更を特定して確認した
- 証拠(ログ、状態、データフロー)を集めた
- 問題を特定のコンポーネント/コードに切り分けた
- 根本原因の仮説を立て、検証できる
停止: なぜ発生しているかを理解するまで、フェーズ 2 に進まないでください。
フェーズ 2:パターン分析
修正する前にパターンを見つけます:
0. 再現条件を最小化する
ループで失敗することを確認したら、失敗し続ける最小のシナリオまで再現条件を絞り込みます。入力、呼び出し元、設定、データ、手順を一度に 1 つずつ削り、そのたびにループを再実行します。失敗に不可欠なものだけを残します。
残った要素をどれか 1 つでも取り除くとループが成功する状態になったら完了です。最小の再現条件は仮説の範囲を狭め、最も明快な回帰テストになることもよくあります。
1. 動作する例を見つける
- 同じコードベース内で、類似した動作するコードを見つける
- 壊れているものと似ていて、正常に動作するものは何ですか?
アクション: search_files を使って比較できるパターンを見つけます:
search_files("similar_pattern", path="src/", file_glob="*.py")
2. 参照実装と比較する
- パターンを実装する場合は、参照実装を最後まで完全に読む
- ざっと目を通すだけにしない — すべての行を読む
- 適用する前に、パターンを十分に理解する
3. 違いを特定する
- 動作するものと壊れているものの違いは何ですか?
- どんなに小さな違いでも、すべて列挙する
- 「これは関係ないはず」と決めつけない
4. 依存関係を理解する
- どのコンポーネントが必要ですか?
- どの設定、構成、環境が必要ですか?
- どのような前提がありますか?
フェーズ 3:仮説とテスト
科学的な方法:
1. 検証可能な仮説を可能性の高い順に立てる
- 1 つをテストする前に、妥当な仮説を 3~5 個挙げます。
- 可能性の高さと、反証の容易さに基づいて順位を付けます。
- 各仮説が予測することを明示します:「原因が X なら、Y を変更または観察すると Z が起きるはずです。」
- 検証可能な予測を立てられない仮説は、破棄するか、より明確にします。
ユーザーが応答可能な場合は、テストの前に順位付けしたリストを提示します。ユーザーの専門知識によって、順位がすぐに変わるかもしれません。ユーザーが離席中の場合は、その順位付けに基づいて進めます。
2. 最小限のテストを行う
- 最も順位の高い仮説を、可能な限り小さな調査でテストします。
- 一度に変更する変数は 1 つにします。
- 複数のことを一度に修正しないでください。
- デバッガー/REPL で確認できる場合はそれを優先します。ブレークポイント 1 つでログ 10 個分の情報が得られます。
- ログを追加する場合は、すべての一時的な行に
[DEBUG-a4f2]のような一意の接頭辞を付け、検索 1 回で削除できるようにします。
3. 続行する前に検証する
- うまくいきましたか? → フェーズ 4
- うまくいきませんでしたか? → 新しい仮説を立てる
- 修正を重ねて追加しない
4. 分からない場合
- 「X が理解できません」と伝える
- 分かったふりをしない
- ユーザーに助けを求める
- さらに調査する
フェーズ 4:実装
症状ではなく根本原因を修正します。
1. 失敗するテストケースを作成する
- 可能な限りシンプルな再現手順
- 可能であれば自動テスト
- 修正前に必ず作成する
test-driven-developmentスキルを使用する
2. 修正を 1 つ実装する
- 特定した根本原因に対処する
- 一度に変更するのは 1 つだけ
- 「ついでに」改善しない
- リファクタリングを同時に行わない
3. 修正を検証する
# Run the specific regression test
pytest tests/test_module.py::test_regression -v
# Run full suite — no regressions
pytest tests/ -q
4. 修正が機能しない場合 — 3 回ルール
- 停止します。
- これまでに試した修正の回数を数えます。
- 3 回未満の場合:フェーズ 1 に戻り、新しい情報をもとに再分析します
- 3 回以上の場合:停止して、アーキテクチャに疑問を持ちます(以下のステップ 5)
- アーキテクチャについて議論せずに、修正案 4 を試してはいけません
5. 3 回以上の修正に失敗した場合:アーキテクチャに疑問を持つ
アーキテクチャ上の問題を示すパターン:
- 修正のたびに、別の場所で新たな共有状態や結合が明らかになる
- 修正を実装するために「大規模なリファクタリング」が必要になる
- 修正のたびに、別の場所で新しい症状が発生する
停止して、根本的な前提に疑問を持ちます。
- このパターンは根本的に妥当ですか?
- 「惰性だけでこの方法に固執」していませんか?
- 症状の修正を続けるのではなく、アーキテクチャをリファクタリングすべきですか?
修正をさらに試す前に、ユーザーと話し合ってください。
これは仮説の失敗ではありません。アーキテクチャが間違っています。
危険信号 — 停止して手順に従う
次のように考えていることに気づいたら:
- 「とりあえず簡単に修正して、調査は後で」
- 「X を変えて動くか試してみよう」
- 「変更をいくつか加えて、テストを実行しよう」
- 「テストは省略して、手動で確認しよう」
- 「おそらく X だろう。修正してみよう」
- 「完全には理解していないけれど、うまくいくかもしれない」
- 「パターンには X とあるけれど、少し変えてみよう」
- 「主な問題は次のとおりです:[調査せずに修正を列挙する]」
- データフローを追跡する前に解決策を提案する
- 「もう一度修正を試す」(すでに 2 回以上試している場合)
- 修正のたびに、別の場所で新たな問題が明らかになる
これらはすべて、停止してフェーズ 1 に戻るべきという意味です。
3 回以上の修正に失敗した場合: アーキテクチャに疑問を持ちます(フェーズ 4 のステップ 5)。
よくある正当化
| 言い訳 | 実態 |
|---|---|
| 「問題は単純だから、手順は必要ない」 | 単純な問題にも根本原因があります。手順に従っても、単純なバグならすぐに解決できます。 |
| 「緊急で、手順に従う時間がない」 | 系統的なデバッグは、推測と試行錯誤を繰り返すよりも速く解決できます。 |
| 「まずこれを試してから調査しよう」 | 最初の修正が、その後の進め方を決めます。最初から正しく行いましょう。 |
| 「修正が機能することを確認してからテストを書こう」 | テストしていない修正は定着しません。まずテストを書けば、それを確認できます。 |
| 「複数の修正を一度に行えば時間を節約できる」 | 何が機能したのかを切り分けられず、新たなバグを引き起こします。 |
| 「参考資料が長すぎるので、パターンを応用しよう」 | 理解が不完全だと、必ずバグにつながります。最後まで読みましょう。 |
| 「問題がわかった。修正しよう」 | 症状を見たことと、根本原因を理解したことは同じではありません。 |
| 「もう一度修正を試す」(2 回以上失敗した後) | 3 回以上の失敗は、アーキテクチャ上の問題を示します。再度修正するのではなく、パターンに疑問を持ちましょう。 |
クイックリファレンス
| フェーズ | 主な作業 | 成功基準 |
|---|---|---|
| 1. 根本原因 | エラーを読む、再現する、変更を確認する、証拠を集める、データフローを追跡する | 何が、なぜ起きているのかを理解する |
| 2. パターン | 機能している例を探す、比較する、違いを特定する | 何が異なるのかを把握する |
| 3. 仮説 | 理論を立て、最小限のテストを行い、一度に 1 つの変数だけを変更する | 仮説を確認するか、新たな仮説を立てる |
| 4. 実装 | 回帰テストを作成する、根本原因を修正する、検証する | バグが解決し、すべてのテストに合格する |
Hermes Agent の統合
調査ツール
フェーズ 1 では、次の Hermes ツールを使用します。
search_files— エラー文字列を検索し、関数呼び出しを追跡し、パターンを探しますread_file— 正確に分析できるよう、行番号付きでソースコードを読みますterminal— テストを実行し、Git の履歴を確認し、バグを再現しますweb_search/web_extract— エラーメッセージやライブラリのドキュメントを調査します
delegate_task を使用する場合
複数のコンポーネントにまたがる複雑なデバッグでは、調査用のサブエージェントを起動します。
delegate_task(
goal="Investigate why [specific test/behavior] fails",
context="""
Follow systematic-debugging skill:
1. Read the error message carefully
2. Reproduce the issue
3. Trace the data flow to find root cause
4. Report findings — do NOT fix yet
Error: [paste full error]
File: [path to failing code]
Test command: [exact command]
""",
toolsets=['terminal', 'file']
)
テスト駆動開発を使う
バグを修正する場合:
- バグを再現するテストを書く(RED)
- 根本原因を見つけるため、体系的にデバッグする
- 根本原因を修正する(GREEN)
- テストで修正を検証し、再発を防ぐ
実際の効果
デバッグセッションの結果:
- 体系的なアプローチ:修正に15〜30分
- 場当たり的な修正:2〜3時間の試行錯誤
- 初回で修正できる割合:95% 対 40%
- 新たに発生するバグ:ほぼゼロ 対 頻繁に発生
近道をしない。推測しない。常に体系的に進めることが最善です。