debug について
Systematic Debuggingは、テスト失敗、本番環境のバグ、性能問題、連携問題を調査する開発者向けスキルです。修正の前に根本原因を調べ、パターン分析、仮説検証、修正確認の順に進めます。
主な機能
- 01修正前の根本原因調査
- 02問題の再現と最近の変更の確認
- 03コンポーネント境界とデータフローの追跡
- 04単一仮説を最小変更で検証
- 05段階的な修正と結果確認
活用シーン
- 01本番システムの不具合を特定
- 02テストやビルドの失敗を調査
- 03性能問題や連携異常を診断
- 04修正失敗が続いた際の設計再検討
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ udecode/ dotai --skill debugインストール後、Claude Code で/debugを入力して読み込まれたか確認します。
詳細
体系的なデバッグ
概要
当てずっぽうの修正は時間を浪費し、新たなバグを生みます。手早いパッチは根本的な問題を覆い隠します。
基本原則: 修正を試みる前に、必ず根本原因を見つけてください。症状への対処は失敗です。
このプロセスの文面だけでなく、その精神に反することも、デバッグの精神に反する行為です。
絶対原則
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
フェーズ1を完了していない場合、修正を提案してはいけません。
使用する場面
あらゆる技術的な問題に使用してください。
- テストの失敗
- 本番環境でのバグ
- 予期しない動作
- パフォーマンスの問題
- ビルドの失敗
- 統合に関する問題
特に次のような場合に使用してください:
- 時間に追われている(緊急時は当てずっぽうで対処したくなります)
- 「簡単な修正をひとつだけ」で済みそうに見える
- すでに複数の修正を試している
- 以前の修正が機能しなかった
- 問題を十分に理解できていない
次の場合も省略しないでください:
- 問題が単純に見える(単純なバグにも根本原因があります)
- 急いでいる(急ぐと手戻りは避けられません)
- マネージャーから今すぐ直すよう求められている(行き当たりばったりに対処するより、体系的に進めるほうが速いです)
4つのフェーズ
次のフェーズに進む前に、各フェーズを必ず完了してください。
フェーズ1:根本原因の調査
修正を試みる前に必ず行うこと:
-
エラーメッセージを注意深く読む
- エラーや警告を読み飛ばさない
- 正確な解決策が記載されていることもよくあります
- スタックトレースを最後まで読む
- 行番号、ファイルパス、エラーコードを記録する
-
一貫して再現できるようにする
- 確実に発生させられますか?
- 正確な手順は何ですか?
- 毎回発生しますか?
- 再現できない場合は、推測せず、さらにデータを集める
-
最近の変更を確認する
- 原因となり得る変更は何ですか?
- Git の差分、最近のコミット
- 新しい依存関係、設定の変更
- 環境の違い
-
複数のコンポーネントから成るシステムでは証拠を集める
システムが複数のコンポーネントで構成されている場合(CI → ビルド → 署名、API → サービス → データベースなど):
修正を提案する前に、診断用の計測を追加する:
For EACH component boundary: - Log what data enters component - Log what data exits component - Verify environment/config propagation - Check state at each layer Run once to gather evidence showing WHERE it breaks THEN analyze evidence to identify failing component THEN investigate that specific component例(多層システム):
# Layer 1: Workflow echo "=== Secrets available in workflow: ===" echo "IDENTITY: ${IDENTITY:+SET}${IDENTITY:-UNSET}" # Layer 2: Build script echo "=== Env vars in build script: ===" env | grep IDENTITY || echo "IDENTITY not in environment" # Layer 3: Signing script echo "=== Keychain state: ===" security list-keychains security find-identity -v # Layer 4: Actual signing codesign --sign "$IDENTITY" --verbose=4 "$APP"これにより、どのレイヤーで失敗しているかが明らかになります(シークレット → ワークフロー ✓、ワークフロー → ビルド ✗)
-
データフローをたどる
コールスタックの深い位置でエラーが発生している場合:
組み込みの逆方向トレースを使います。
- 不正な値はどこから来ていますか?
- 何がこの処理を不正な値で呼び出しましたか?
- 発生源が見つかるまで呼び出し元をさかのぼる
- 症状ではなく発生源を修正する
組み込みの深いスタックトレース
バグが実際の発生要因から遠く離れた場所に見える場合に使用します。
よくある兆候:
- エラーがエントリーポイントではなく、実行の深い位置で発生する
- スタックトレースが長い
- 失敗した箇所はわかるが、不正な値の発生元がわからない
- 症状が現れた箇所を修正したくなる
トレースの手順:
- 症状を観察する。
- 直接の原因を特定する。
- 何がその処理を呼び出したかを確認する。
- 最初の不正な入力、誤った前提、または誤ったトリガーが見つかるまでさかのぼる。
- その箇所を修正し、必要に応じて下位レイヤーにも多層防御を追加する。
簡単な例:
await execFileAsync("git", ["init"], { cwd: projectDir });
- 直接の原因:
git initが誤ったディレクトリで実行される - 次の問い:誰が
projectDirを渡したのか? - 次の問い:その誤った
projectDirはどこから来たのか? - 根本原因は、失敗した行よりはるかに上流にある可能性がある
手動でのトレースが行き詰まった場合は、危険な処理の前に計測を追加する:
async function gitInit(directory: string) {
const stack = new Error().stack;
console.error("DEBUG git init:", {
directory,
cwd: process.cwd(),
nodeEnv: process.env.NODE_ENV,
stack,
});
await execFileAsync("git", ["init"], { cwd: directory });
}
トレースのルール: 「この行でクラッシュした」で止めてはいけません。どの呼び出し元、入力、または状態遷移が不正な値を生み出したのかを説明できるまで、追跡を続けてください。
フェーズ 2:パターン分析
修正する前に、パターンを見つけます:
-
動作する例を見つける
- 同じコードベース内で、類似した動作するコードを探します
- 壊れているものと似ていて、正常に動作するものは何ですか?
-
参照実装と比較する
- パターンを実装する場合は、参照実装を最後まで読みます
- 斜め読みせず、すべての行を読みます
- 適用する前に、パターンを完全に理解します
-
違いを特定する
- 正常に動作するものと壊れているものでは、何が違いますか?
- どんなに小さくても、すべての違いを書き出します
- 「関係ないはず」と決めつけません
-
依存関係を理解する
- ほかに必要なコンポーネントは何ですか?
- どのような設定、構成、環境が必要ですか?
- どのような前提に基づいていますか?
フェーズ 3:仮説とテスト
科学的な手法:
-
仮説を 1 つ立てる
- 「Y が原因なので、根本原因は X だと考えます」のように、明確に述べます
- 書き留めます
- 曖昧にせず、具体的にします
-
最小限のテストを行う
- 仮説を検証するために、可能な限り小さな変更を行います
- 一度に変更するのは 1 つの変数だけです
- 複数のことを一度に修正しません
-
続行する前に検証する
- 動作しましたか? はい → フェーズ 4
- 動作しませんでしたか? 新しい仮説を立てます
- 修正をさらに重ねてはいけません
-
分からないとき
- 「X が理解できません」と伝えます
- 分かったふりをしません
- 助けを求めます
- さらに調査します
フェーズ 4:実装
症状ではなく、根本原因を修正します:
-
テスト戦略を決める
複雑さに応じて自動的に判断します:
- テストを書く場合:複雑なアルゴリズム、ビジネスロジック、バグが起きやすいデータ変換
- テストを省略する場合:UI コンポーネント、React フック、単純な CRUD、分かりやすいマッピング、正しいと 100%確信できるもの
- テストの種類:決定論的な単体テストのみ。統合テスト、複雑なモック、非同期処理の複雑さは避けます
テストを書く場合:
- 可能な限り単純な再現方法にします
- 修正前に失敗する自動テストを書きます
- 実装の詳細ではなく、ロジックを検証します
テストを省略する場合:
- 型チェック/リンターで修正を検証します
- UI の変更は手動で検証します
- コードレビューで修正が正しいと確信できることを確認します
-
修正を 1 つ実装する
- 特定した根本原因に対処します
- 一度に変更するのは 1 つだけです
- 「ついでに」改善しません
- リファクタリングをまとめて行いません
-
修正を検証する
テストを書いた場合:
- テストは通りましたか?
- ほかのテストは壊れていませんか?
テストを書いていない場合:
- 型チェックは通りましたか?
- リンターのエラーはありませんか?
- 手動検証で修正を確認できましたか?
必ず確認すること:
- 問題は実際に解決しましたか?
- 関連する機能にリグレッションはありませんか?
-
修正がうまくいかない場合
- 停止します
- 数えます。修正をいくつ試しましたか?
- 3 回未満の場合:フェーズ 1 に戻り、新しい情報をもとに再分析します
- 3 回以上の場合:停止し、アーキテクチャを見直します(下記のステップ 5)
- アーキテクチャについて話し合わずに、4 回目の修正を試してはいけません
-
3 回以上の修正が失敗した場合:アーキテクチャを見直す
アーキテクチャ上の問題を示すパターン:
- 修正するたびに、別の場所で新たな共有状態、結合、問題が見つかる
- 修正の実装に「大規模なリファクタリング」が必要になる
- 修正するたびに、ほかの場所で新たな症状が発生する
停止して、根本から見直します:
- このパターンは根本的に妥当ですか?
- 「ただ惰性で続けている」だけではありませんか?
- 症状の修正を続けるのではなく、アーキテクチャをリファクタリングすべきではありませんか?
さらに修正を試す前に、人間のパートナーと話し合います。
これは仮説の失敗ではありません。アーキテクチャが誤っています。
危険信号 — STOPしてプロセスに従う
次のように考えていることに気づいたら:
- 「とりあえず応急処置して、調査は後で」
- 「Xを変えて、うまくいくか試してみよう」
- 「変更をいくつか加えて、テストを実行しよう」
- 「たぶんXだ。修正してみよう」
- 「完全には理解していないけれど、これでうまくいくかもしれない」
- 「パターンではXだけれど、別の方法で応用しよう」
- 「主な問題はこれです:[調査せずに修正案を列挙]」
- データの流れを追跡する前に解決策を提案している
- 「もう一度修正を試す」(すでに2回以上試した場合)
- 修正するたびに、別の場所で新たな問題が見つかる
- 修正が正しいと確信しているのに、UIコンポーネントのテストを書いている
これらはすべて、STOPしてフェーズ1に戻るべきサインです。
修正に3回以上失敗した場合: アーキテクチャに疑問を持ってください(フェーズ4.5を参照)。
あなたのパートナーが示す、作業がうまく進んでいないサイン
次のような軌道修正に注意してください:
- 「それは起きていないのでは?」 — 確認せずに決めつけています
- 「それで何が分かるの?」 — 証拠を集めるべきでした
- 「推測はやめて」 — 理解しないまま修正を提案しています
- 「徹底的に考えて」 — 症状だけでなく、根本的な要因に疑問を持つべきです
- 「行き詰まっているの?」(不満を感じた様子) — そのアプローチはうまくいっていません
これらが見られたら: STOPしてフェーズ1に戻ってください。
よくある正当化
| 言い訳 | 実際のところ |
|---|---|
| 「問題は簡単だから、プロセスは必要ない」 | 簡単な問題にも根本原因はあります。プロセスを踏んでも、簡単なバグならすぐに解決できます。 |
| 「緊急だから、プロセスにかける時間はない」 | 系統立てたデバッグは、当てずっぽうな試行錯誤を繰り返すよりも速く解決できます。 |
| 「まずこれを試して、それから調査しよう」 | 最初の修正が、その後の進め方の基準になります。最初から正しく進めてください。 |
| 「一度に複数修正すれば時間を節約できる」 | 何が効いたのか切り分けられず、新たなバグの原因になります。 |
| 「参考資料が長すぎるから、パターンを応用しよう」 | 部分的な理解では、バグを避けられません。最後まで読んでください。 |
| 「問題は分かった。修正しよう」 | 症状が見えていることと、根本原因を理解していることは別です。 |
| 「もう一度修正を試す」(2回以上失敗した後) | 3回以上失敗したら、アーキテクチャの問題です。パターンに疑問を持ち、再度修正するのはやめてください。 |
| 「UIの修正にテストは必要ない」 | そのとおりです!UIコンポーネントはユニットテストではなく、型チェックや手動テストで検証します。 |
クイックリファレンス
| フェーズ | 主な作業 | 成功基準 |
|---|---|---|
| 1. 根本原因 | エラーを読み、再現し、変更を確認し、証拠を集める | WHATとWHYを理解する |
| 2. パターン | 動作する例を見つけ、比較する | 違いを特定する |
| 3. 仮説 | 理論を立て、最小限のテストを行う | 仮説を確認するか、新たな仮説を立てる |
| 4. 実装 | テストを作成し、修正し、検証する | バグが解決し、テストに合格する |
プロセスを踏んでも「根本原因が見つからない」場合
系統立てた調査の結果、問題が本当に環境依存、タイミング依存、または外部要因によるものだと分かった場合:
- プロセスを最後まで完了しています
- 調査した内容を記録します
- 適切な対処(再試行、タイムアウト、エラーメッセージ)を実装します
- 今後の調査に備えて、モニタリングやログ出力を追加します
ただし: 「根本原因が見つからない」ケースの95%は、調査が不十分です。
他のスキルとの連携
必要に応じてテストスキルを使用:
- tdd(利用可能な場合)— テストカバレッジが必要な複雑なビジネスロジックを修正するときに使用します
- UIコンポーネント、単純なCRUD、または型チェックや手動テストで検証可能なものには使用しません
実際の効果
デバッグセッションでの比較:
- 体系的なアプローチ:修正に15~30分
- 場当たり的な修正:2~3時間の試行錯誤
- 初回での修正率:95%対40%
- 新たに発生するバグ:ほぼゼロ対頻繁に発生