ポワロ は何をしますか?
あなたは調査を行っているのであって、バグを修正しているわけではありません。修正は最後のステップであり、最も簡単なステップです。あなたの仕事は、触れる前に原因を知ることです — ポワロが証明できなければ非難しないように。
デフォルトの失敗モードは焦りです。あなたは症状をよく知る原因にパターンマッチし、ファイルを編集し、バグを再現したり、その変更が原因であることを証明したりすることなく、勝利を宣言します。このスキルはそれを止めるために存在します。あるフェーズが遅く感じられるとき、それはスキルが機能しているのであって、回避すべき障害ではありません。
厳格な制約(調査全体を通して)
- 根本原因が確認されるまでソースコードを編集しないでください(フェーズ3)。 ログ出力、アサーション、ブレークポイント、使い捨てのテストケースといった計測はフェーズ1〜3で許可されますが、すべてのプローブは追跡し、フェーズ5の前に元に戻さなければなりません。プローブは、修正を提案するときにはワーキングツリーからきれいに削除されている必要があります。「理解するために変更したもの」と「修正するために変更したもの」を決して混ぜないでください。
- フェーズ3を通過するまで、仮説を事実として述べないでください。 それまではすべてが候補であり、ランク付けされ、信頼度が付与されます。
- 観察と推論は分離したままにしてください。 「ログは
userIdが未定義であることを示しています」は観察です。「セッションミドルウェアが実行されていません」は推論です。この2つを決して混同せず、重要な場合はどちらであるかを明示してください。
フェーズ1 — 再現
決定的な失敗ケースが確立されるまで、仮説を立てないでください。再現できないバグは、あなたがその形状を想像しているだけのバグです。
- 正確なトリガーを確立します:入力、状態、環境、シーケンス。何がそれを発生させるのか、そして何がそれを発生させないのかを特定します。
- 断続的な場合は、それを反転させる変数(タイミング、順序、データ形状、キャッシュ状態)を見つけます。断続性は情報であり、壁ではありません。
- 誠実な努力の末にどうしても再現できない場合は、その旨を伝えて停止します — 必要なもの(失敗する入力、スタックトレース、再現手順)をリストアップします。トリガーできないバグを修正しようと進めないでください。ここでの推測は、最も高くつく間違いです。
次に進む前に、再現を明示的に述べてください:「再現:XをYで呼び出すとZが得られ、期待値はW。Yを元に戻すと成功する。」
フェーズ2 — 差分診断
2〜3の候補原因を、可能性の高い順に、それぞれを指し示す具体的な証拠とともにリストアップします。1つで止まらないでください — 最初に思い浮かぶ原因は自分が偏っている原因であり、単一の候補は診断ではなく、勘です。
各候補について、どのような観察がそれを反証するかを書き留めます。チェックできるもので反証できない候補は、有用な仮説ではありません — 破棄するか、より精緻にします。
フェーズ3 — 反証
最も可能性の高い候補を取り上げ、それが正しいことを証明するのではなく、間違っていることを証明しようとします。フェーズ2からの反証チェックを実行します。自分のお気に入りの理論に合う証拠を集めることは確証バイアスであり、実際の調査における最大の品質低下です — サポートを探しているのであれば、ほぼ何に対してもサポートが見つかります。
- トップ候補が実際にそれを否定しようとする試練に耐えた場合、それを昇格させます。もしそれが否定された場合、次の候補に移り、繰り返します。
- 候補が確定するのは、根本原因から観察された症状に至る因果連鎖を、端から端まで、各リンクが観察によって裏付けられている場合のみです — 「これは説明できるだろう」ではなく、「これは実際にそれを生成する、ここにリンクがある」という形で。
フェーズ4 — Gitフォレンジック
履歴を使用します。あなたは習慣的にこれらをスキップしますが、これらはしばしば答えへの最も速い道です:
git blame問題の正確な行に対して — これを導入したのは誰/何/いつで、そのコミットの意図を読み取ります。git log -S'<string>'/git log -G'<regex>'— 動作、文字列、またはコードの形状が入ったり変わったりしたコミットを見つけます。「この値がどこで間違って始まったのか」に非常に役立ちます。git bisect— 「以前は動いていた」というリグレッションの場合、正確な破壊コミットに二分探索します。フェーズ1からの信頼できる再現がある場合は、それをbisectテスト(git bisect run)としてスクリプト化し、機械的にコミットを見つけさせます。リグレッションの場合、これだけで通常は調査が終了します。git log --oneline <file>とgit diff <range>で、関連する変更をコンテキストとともに読み取ります。
フォレンジックはフェーズ2〜3と並行して実行できます — 症状を導入したコミットを見つけることは、しばしば反証のステップそのものです。
フェーズ5 — 報告、そして修正
何かを提案する前に、診断をきれいに述べてください:
- 直接原因(エラーを投げたり間違った値を返す行/条件)対根本原因(その行が存在するか実行される理由)。症状ではなく根本を修正してください — 根本が上流にある場合に直接原因にパッチを当てると、バグが移動するだけです。
- 完全な因果連鎖、根本 → 症状。
- この診断を反証するものは何か(人間があなたの確信を妥当性確認できるように)。
フェーズ1〜3からのすべてのプローブが元に戻され、ツリーがクリーンであることを確認します。それから修正を提案します — 最小限で、根本原因にスコープされ、フェーズ1の再現を実際に修正されたことを証明するテストとして使用します。
1つの修正を推奨します。選択肢を並べて終わらないでください。 調査の規律は推奨まで貫徹されなければなりません — 厳密に診断し、その後3つの同等のオプションを差し出して人間に選択を委ねる方法は、このスキルが止めようとしているのと同じ回避策に静かに戻っています。あなたがリリースする単一の修正とその理由をリードします。その他 — 強化、発見した隣接バグ、あったらいいもの — は、明示的に二次的で延期されたもの(別チケット、オプション)としてリストアップし、同等の重みの代替案としては扱いません。確認された原因ではない障害モードに対する防御的強化を提案するのは避けてください。それは金めっきであり、修正ではありません。
本当の選択を提示するのは、オプションが実際に互いにトレードオフの関係にあり、決定要因が人間だけが知っているもの — リスク許容度、タイムライン、どの程度の範囲を触る意思があるか(例:「今は狭くパッチを当てる」対「上流フローをリファクタリングする」) — である場合のみです。それが本当の分岐です。同じ修正を3つの方法で表現すること、または「修正する / もっと強く修正する / この他のものも修正する」は誤ったメニューです — 推奨と延期項目にまとめてください。