---
title: "Systematic Debugging — 4 つの段階で根本原因を突き止めます。直す前に、まず不具合を理解します"
description: "4 つの段階で根本原因を突き止めます。直す前に、まず不具合を理解します"
upstream_path: user-guide/skills/bundled/software-development/software-development-systematic-debugging.md
upstream_blob: 09c9e3c2680db08f11e052cfe148f17147a6184f
sources:
  - https://hermes-agent.nousresearch.com/docs/user-guide/skills/bundled/software-development/software-development-systematic-debugging
---

# Systematic Debugging {#systematic-debugging}

4 つの段階で根本原因を突き止めます。直す前に、まず不具合を理解します。

## skill の情報 {#skill-metadata}

| | |
|---|---|
| 提供元 | 最初から入っています |
| パス | `skills/software-development/systematic-debugging` |
| バージョン | `1.1.0` |
| 作者 | Hermes Agent（obra/superpowers から取り入れています） |
| ライセンス | MIT |
| 対応プラットフォーム | linux, macos, windows |
| タグ | `debugging`, `troubleshooting`, `problem-solving`, `root-cause`, `investigation` |
| 関連 skill | [`test-driven-development`](/hermes/docs/user-guide/skills/bundled/software-development/software-development-test-driven-development/), [`plan`](/hermes/docs/user-guide/skills/bundled/software-development/software-development-plan/), [`subagent-driven-development`](/hermes/docs/user-guide/skills/optional/software-development/software-development-subagent-driven-development/) |

## 参考: SKILL.md 全文 {#reference-full-skillmd}

:::info
以下は、この skill が呼び出されたときに Hermes が読み込む定義の全文です。skill が有効なあいだ、エージェントはこれを指示として受け取ります。
:::

# 順序立てたデバッグ {#systematic-debugging}

## 概要 {#overview}

当てずっぽうの修正は時間を浪費し、新しい不具合を生みます。その場しのぎの手当ては、奥にある問題を覆い隠します。

**基本の考え方:** 修正に手をつける前に、必ず根本原因を突き止めます。症状だけを直すのは失敗です。

**この手順の文言を破ることは、デバッグの精神を破ることです。**

## 鉄の掟 {#the-iron-law}

```
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
```

段階 1 を終えていないなら、修正案を出すことはできません。

## フィードバックループの決まり {#the-feedback-loop-rule}

フィードバックループこそがデバッグの本体です。コードを読んで仮説を組み立てる前に、利用者が遭遇したその症状でちゃんと赤（失敗）になり、不具合が直れば緑（成功）になる、**きつく絞った**コマンドを用意するか、すでにあるものを見つけます。きつく絞ったループとは、速く、毎回同じ結果になり、エージェントが自分で実行でき、そして「落ちなければよい」ではなくこの不具合をつかまえられるだけの具体性がある、ということです。

きれいな再現が難しいときほど、ループづくりに時間をかけます。赤にできるループがないまま推測することこそ、この skill が防ごうとしている失敗の形です。

## 使いどころ {#when-to-use}

技術的な問題なら、どれにでも使います。

- テストの失敗
- 本番で起きている不具合
- 想定と違うふるまい
- 性能の問題
- ビルドの失敗
- 連携まわりの問題

**とくに次のときに使ってください。**

- 時間に追われているとき（急ぎの場面ほど当て推量に流れます）
- 「ちょっと直すだけ」で済みそうに見えるとき
- すでに複数の修正を試したあと
- 前の修正が効かなかったとき
- 問題をまだ十分に理解できていないとき

**次のような理由で飛ばしてはいけません。**

- 単純そうに見える（単純な不具合にも根本原因はあります）
- 急いでいる（急ぐほど手戻りが確定します）
- 今すぐ直してほしいと言われている（もがくより順序立てたほうが速いです）

## 4 つの段階 {#the-four-phases}

次の段階に進む前に、必ずその段階を終わらせてください。

---

## 段階 1: 根本原因の調査 {#phase-1-root-cause-investigation}

**どんな修正にも手をつける前に:**

### 1. エラーメッセージをていねいに読む {#1-read-error-messages-carefully}

- エラーや警告を読み飛ばさない
- そこに答えそのものが書かれていることがよくあります
- スタックトレースは最後まで読む
- 行番号、ファイルパス、エラーコードを控える

**やること:** 関係するソースファイルを `read_file` で読みます。エラー文字列をコードベースから探すには `search_files` を使います。

### 2. きつく絞ったフィードバックループを作る {#2-build-a-tight-feedback-loop}

- 利用者が遭遇したその症状を、コマンド 1 本で起こせますか
- そのコマンドは、この不具合があるときに失敗し、直ったときにだけ通りますか
- 何度も回せるくらい速いですか
- 毎回同じ結果になりますか。ときどきしか起きない不具合なら、デバッグできる程度まで再現率を上げられますか
- 再現できないなら、推測せずにデータをもっと集めます。

**ループの組み立て方 — だいたいこの順で試します:**

1. 不具合まで届く継ぎ目に置いた**失敗するテスト**。単体でも、結合でも、端から端までのものでもかまいません。
2. 動かしている開発サーバーに向けた **HTTP スクリプトや curl**。
3. 決まった入力を与える **CLI の実行**。標準出力・標準エラーを期待した出力と突き合わせます。
4. DOM・コンソール・通信を検査する**ヘッドレスブラウザのスクリプト**（Playwright や Puppeteer）。
5. **記録した通信の再生**。HAR、リクエストの中身、イベントログ、キューのメッセージ、Webhook の本文など。
6. 系のうち役に立つ最小の一部だけを起動し、失敗する経路を呼ぶ**使い捨ての足場**。
7. 広い入力空間で、ときどき出力が間違う類いの不具合に対する**プロパティテストやファジング**のループ。
8. 既知の 2 つの状態のあいだで不具合が現れたときに `git bisect run` に渡せる**二分探索用の足場**。
9. 旧版と新版、2 つの設定、2 つの提供元、2 つのデータ群を比べる**差分ループ**。
10. **人が介在するスクリプト**は最後の手段としてだけ。人の操作手順を書き出し、その結果を記録して、ループとしての形を保ちます。

**ループができたら、さらに絞り込みます。**

- 速くする: 準備をキャッシュし、範囲を狭め、関係のない初期化を飛ばす。
- 信号を鋭くする: ざっくりした成功ではなく、その症状そのものを検査する。
- 結果を安定させる: 時刻を固定し、乱数の種を決め、ファイルシステムを切り離し、通信を凍結する。

結果が揺れる不具合では、当面の目標は完璧さではなく再現率の高さです。きっかけを 100 回走らせ、並列にし、負荷をかけ、タイミングの窓を狭め、あるいは sleep を挟みます。半分の確率で起きるならデバッグできますが、100 回に 1 回ではたいてい無理です。

**やること:** `terminal` ツールで、きつく絞ったループを走らせます。

```bash
# 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. 最近の変更を確かめる {#3-check-recent-changes}

- これを引き起こしそうな変更は何か
- git の差分、直近のコミット
- 新しく入った依存、設定の変更

**やること:**

```bash
# 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. 部品が複数ある系では証拠を集める {#4-gather-evidence-in-multi-component-systems}

**系が複数の部品でできているとき（API → サービス → データベース、CI → ビルド → デプロイ など）:**

**修正案を出す前に、診断用の記録を仕込みます。**

部品と部品の境目ごとに、次を行います。

- その部品に入ってくるデータを記録する
- その部品から出ていくデータを記録する
- 環境変数や設定が伝わっているかを確かめる
- 各層で状態を確認する

まず一度走らせて、どこで壊れているかを示す証拠を集めます。
そのうえで証拠を読み、失敗している部品を特定します。
それからその部品を掘り下げます。

### 5. データの流れをたどる {#5-trace-data-flow}

**エラーが呼び出し階層の深いところで起きているとき:**

- おかしな値はどこで生まれたのか
- おかしな値を渡してこの関数を呼んだのは誰か
- 出どころが見つかるまで上流へたどり続ける
- 症状の場所ではなく、出どころで直す

**やること:** `search_files` で参照をたどります。

```python
# 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 の確認リスト {#phase-1-completion-checklist}

- [ ] エラーメッセージを最後まで読み、意味を理解した
- [ ] きつく絞ったループのコマンドがあり、少なくとも一度は走らせた
- [ ] ループは赤にできる。近くの別の失敗ではなく、利用者のその症状を検査している
- [ ] ループは毎回同じ結果になる。揺れる不具合なら、デバッグできるだけの再現率がある
- [ ] 最近の変更を洗い出し、目を通した
- [ ] 証拠が集まった（ログ、状態、データの流れ）
- [ ] 問題を特定の部品やコードまで絞り込んだ
- [ ] 根本原因の仮説を言葉にでき、検証できる

**ここで止まります:** なぜ起きているのかを理解するまで、段階 2 に進まないでください。

---

## 段階 2: パターンの分析 {#phase-2-pattern-analysis}

**直す前に、パターンを見つけます。**

### 0. 再現を最小にする {#0-minimize-the-reproduction}

ループが赤になったら、赤のままでいられる最小の場面まで再現を縮めます。入力、呼び出し元、設定、データ、手順を**ひとつずつ**削り、削るたびにループを回し直します。失敗を成り立たせている要素だけを残します。

残った要素をどれか取り除くとループが緑になる、という状態になれば完了です。最小の再現は仮説の範囲を狭め、そのままいちばんきれいな回帰テストになることもよくあります。

### 1. 動いている例を探す {#1-find-working-examples}

- 同じコードベースの中から、似ていて動いているコードを見つける
- 壊れているものと似ていて、動いているものは何か

**やること:** `search_files` で近いパターンを探します。

```python
search_files("similar_pattern", path="src/", file_glob="*.py")
```

### 2. 手本と見比べる {#2-compare-against-references}

- あるパターンを実装しているなら、手本の実装を最後まで読む
- ざっと見ずに、一行ずつ読む
- 当てはめる前に、そのパターンを完全に理解する

### 3. 違いを洗い出す {#3-identify-differences}

- 動いているものと壊れているもので、何が違うのか
- どんなに小さくても、違いをすべて書き出す
- 「これは関係ないはず」と決めつけない

### 4. 依存を把握する {#4-understand-dependencies}

- これは他にどんな部品を必要とするのか
- どんな設定や環境が要るのか
- どんな前提を置いているのか

---

## 段階 3: 仮説と検証 {#phase-3-hypothesis-and-testing}

**科学のやり方で進めます。**

### 1. 反証できる仮説を順位づけて立てる {#1-form-ranked-falsifiable-hypotheses}

- どれかを試す前に、ありそうな仮説を 3〜5 個出します。
- ありそうさと、反証にかかる手間の軽さで順位をつけます。
- それぞれの仮説が何を予言するかを言葉にします。「X が原因なら、Y を変える（または観測する）と Z が起きるはずだ」という形です。
- 検証できる予言を持たない仮説は、捨てるか、鋭くし直します。

利用者がその場にいるなら、試す前に順位づけた一覧を見せます。その分野の知識から、順位が一気に入れ替わることがあります。利用者が席を外しているなら、自分の順位づけのまま進めます。

### 2. 最小の形で試す {#2-test-minimally}

- 順位がいちばん高い仮説を、できるだけ小さな探りで試します。
- 変える要素は一度にひとつだけにします。
- 複数のことを同時に直さないでください。
- 使えるならデバッガや REPL での確認を優先します。ブレークポイント 1 個は、ログ 10 行に勝ります。
- ログを足すなら、一時的な行すべてに `[DEBUG-a4f2]` のような固有の目印を付けます。あとで一度検索するだけで片付きます。

### 3. 次に進む前に確かめる {#3-verify-before-continuing}

- 効きましたか → 段階 4 へ
- 効きませんでしたか → 新しい仮説を立てる
- その上に修正を積み重ねないでください

### 4. わからないとき {#4-when-you-dont-know}

- 「X が理解できていません」と言う
- 知っているふりをしない
- 利用者に助けを求める
- もっと調べる

---

## 段階 4: 実装 {#phase-4-implementation}

**症状ではなく、根本原因を直します。**

### 1. 失敗するテストを用意する {#1-create-failing-test-case}

- できるだけ単純な再現にする
- できるなら自動テストにする
- 直す前に必ず用意する
- `test-driven-development` の skill を使う

### 2. 修正はひとつだけ入れる {#2-implement-single-fix}

- 突き止めた根本原因に対処する
- 一度にひとつの変更だけ
- 「ついでに」の改善はしない
- リファクタリングを一緒に混ぜない

### 3. 修正を検証する {#3-verify-fix}

```bash
# Run the specific regression test
pytest tests/test_module.py::test_regression -v

# Run full suite — no regressions
pytest tests/ -q
```

### 4. 修正が効かないとき — 3 回の掟 {#4-if-fix-doesnt-work-the-rule-of-three}

- **止まります。**
- 数えます。ここまでいくつ修正を試しましたか
- &lt; 3 なら: 段階 1 に戻り、新しくわかったことを踏まえて分析し直します
- **3 以上なら: 止まって、設計そのものを疑います（下の 5 番）**
- 設計の話をしないまま 4 つ目の修正に手を出さないでください

### 5. 修正が 3 回以上失敗したら: 設計を疑う {#5-if-3-fixes-failed-question-architecture}

**設計の問題を示すパターン:**

- 修正するたびに、別の場所で共有状態や結合が新しく見つかる
- 修正するのに「大がかりな作り直し」が必要になる
- 修正するたびに、よそで新しい症状が出る

**止まって、前提そのものを問い直します。**

- このやり方は、そもそも筋がよいのか
- 「惰性だけで続けている」のではないか
- 症状を直し続けるのではなく、設計を作り直すべきではないか

**これ以上修正を試す前に、利用者と相談してください。**

これは仮説がはずれたのではなく、設計が間違っているということです。

---

## 危険なサイン — 止まって手順に戻る {#red-flags-stop-and-follow-process}

自分がこう考えていることに気づいたら、要注意です。

- 「とりあえず今は応急処置で、調査はあとで」
- 「X を変えて、動くか見てみよう」
- 「変更をいくつか入れて、テストを回そう」
- 「テストは省いて、手で確かめればいい」
- 「たぶん X だから、そこを直そう」
- 「よくわかっていないけど、これで動くかもしれない」
- 「パターンは X だけど、少しアレンジして当てはめよう」
- 「主な問題はこれです（調査せずに修正案を並べる）」
- データの流れをたどる前に解決策を出している
- **「あと 1 回だけ修正を試す」（すでに 2 回以上試している）**
- **修正するたびに、別の場所で新しい問題が出る**

**どれも意味するところは同じです。止まって、段階 1 に戻ります。**

**修正が 3 回以上失敗したら:** 設計を疑ってください（段階 4 の 5 番）。

## よくある言い訳 {#common-rationalizations}

| 言い訳 | 実際のところ |
|--------|---------|
| 「単純な問題だから手順は要らない」 | 単純な問題にも根本原因はあります。単純な不具合なら手順はすぐ終わります。 |
| 「緊急だから手順を踏む時間はない」 | 順序立てたデバッグは、当て推量でもがくより速いです。 |
| 「まずこれを試して、それから調べる」 | 最初の修正がその後の型を決めます。はじめから正しくやります。 |
| 「修正が効くと確かめてからテストを書く」 | 検証していない修正は定着しません。先にテストを書けば証明になります。 |
| 「まとめて直したほうが時間の節約になる」 | 何が効いたのか切り分けられません。新しい不具合の原因にもなります。 |
| 「手本が長いので、要点だけ取り入れる」 | 半端な理解は不具合を確実に生みます。最後まで読んでください。 |
| 「問題が見えたから直そう」 | 症状が見えることと、根本原因がわかることは違います。 |
| 「あと 1 回だけ修正を試す」（2 回以上失敗したあと） | 3 回以上の失敗は設計の問題です。もう一度直すのではなく、やり方を疑ってください。 |

## 早見表 {#quick-reference}

| 段階 | 主にやること | 達成の目安 |
|-------|---------------|------------------|
| **1. 根本原因** | エラーを読む、再現する、変更を確かめる、証拠を集める、データの流れをたどる | 何が起きていて、なぜかを理解できている |
| **2. パターン** | 動いている例を探す、比べる、違いを洗い出す | 何が違うのかがわかっている |
| **3. 仮説** | 仮説を立て、最小の形で試し、変える要素はひとつずつ | 仮説が確かめられたか、新しい仮説が立った |
| **4. 実装** | 回帰テストを用意し、根本原因を直し、検証する | 不具合が解消し、テストがすべて通る |

## Hermes Agent との組み合わせ {#hermes-agent-integration}

### 調査に使うツール {#investigation-tools}

段階 1 では、次の Hermes のツールを使います。

- **`search_files`** — エラー文字列を探し、関数の呼び出しをたどり、パターンを見つけます
- **`read_file`** — 行番号つきでソースを読み、正確に分析します
- **`terminal`** — テストを走らせ、git の履歴を確かめ、不具合を再現します
- **`web_search`/`web_extract`** — エラーメッセージやライブラリの資料を調べます

### delegate_task と組み合わせる {#with-delegatetask}

部品が絡み合った込み入ったデバッグでは、調査用のサブエージェントを送り出します。

```python
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']
)
```

### test-driven-development と組み合わせる {#with-test-driven-development}

不具合を直すときは、次の順に進めます。

1. 不具合を再現するテストを書く（RED）
2. 順序立ててデバッグし、根本原因を突き止める
3. 根本原因を直す（GREEN）
4. そのテストが修正を証明し、再発を防ぐ

## 実際の効き目 {#real-world-impact}

これまでのデバッグ作業から。

- 順序立てたやり方: 15〜30 分で修正
- 当てずっぽうのやり方: 2〜3 時間もがく
- 一度で直る割合: 95% 対 40%
- 新たに生まれた不具合: ほぼゼロ 対 よくある

**近道はありません。当て推量もしません。順序立てたやり方が必ず勝ちます。**
