← バージョニング・パッケージ管理 開発プロセス・品質 →

📑 この章の目次

title: デバッグの作法 icon: 🐛 card_desc: バグの原因を論理的に切り分ける手順 — 再現/切り分け/仮説検証・二分法・最小再現例・root causeの追求 slug: 11-debugging

11 デバッグの作法 — バグの原因を論理的に切り分ける手順

プログラムは必ずバグ(不具合)を出す。重要なのは「直すこと」でなく「なぜ起きるかを突き止めること」。当てずっぽうでなく、論理的に原因を切り分ける作法。


一言でいうと

バグは必ず発生します。素人は「とりあえず直す」を繰り返し、プロは「なぜ起きるかの原因(根本原因)」を突き止めてから直します。この章では、原因を論理的に切り分ける3ステップ(再現 → 切り分け → 仮説検証)と、原因のありかを絞る手法を扱います。


1. なぜデバッグの作法が必要なのか

「当てずっぽう修正」の罠

バグを見つけた時、こう直したくなります。

これが「当てずっぽう修正」の罠です。原因を分からずに直すと、別の問題を生んだり、同じバグが何度も再発したりします。

「直す」より「特定する」が難しい

バグ修正の時間の大部分は、コードを直す作業でなく、原因を見つける作業に使われます。「どこが悪いか」が分かれば直すのは早い。だからこそ「原因を論理的に特定する作法」が問われます。


2. デバッグとは —— バグの原因を特定する作業

言葉の意味

「デバッグ」という言葉は、虫(バグ)を取り除く(除去する)イメージから来ています(1940年代、実際の虫がコンピュータの継ぎ目に入って故障した逸話が由来とされます)。

修正より「特定」が本質

デバッグで時間がかかるのは「どこに原因があるか」を絞り込む作業です。コード全体から1箇所の原因を探すのが難しく、ここを論理的にやるか当てずっぽうにやるかで、修复までの時間が何倍も違います。


3. 🔑 核心の3ステップ —— 再現・切り分け・仮説検証

ステップ1: 再現(確実に同じ症状を起こす)

まず「どんな手順で起きるか」を確定させます。「たまに落ちる」では直せません。誰がやっても同じく起きる再現手順を作ります。再現できないバグは直せない(再現しないと確認できないから)。

ステップ2: 切り分け(原因のありかを絞る)

どこが悪いか」を消去法で絞ります。「ここではない」「あそこでもない」と範囲を狭め、最終的に原因の1箇所を残します(次節の手法で行います)。

ステップ3: 仮説検証(「ここが原因」と実験で確かめる)

〇〇が原因だろう」という仮説を立て、それを実験で確かめます。「この行を直したら直るはず」→ 実際に直す → 直ったら仮説正解(新たな問題が出ていないかも確認)・直らなければ別の原因。仮説を行き当たりばったりでなく、証拠に基づいて立てるのが作法です。

例えていうと: 医者の診断

医者は「とりあえず薬を出す」でなく、**問診(症状を聞く=再現)→ 検査(異常の場所を絞る=切り分け)→ 診断(〇〇病だろう=仮説)→ 治療(薬で治るか確かめる=検証)**と進めます。デバッグも同じです。「症状を直す」前に「原因を診る」のがプロの作法。


4. 切り分けの手法

二分法(バイセクション)

原因のありかを半分ずつ絞る手法です。「前半のコードか後半か」を確かめ→悪い方をさらに半分→…と絞り込み、最短で原因にたどり着きます。Git では git bisect(良い版と悪い版を指定し、原因コミットを二分探索で特定)という機能が定番です。

ログと print で状態を可視化

プログラムの中の状態(変数の値・どこまで進んだか)を外から見えなくするため、ログ(→ 第8章)や print で出力して可視化します。「ここまでは合っている・ここで変わった」が見えると、原因のありかが一気に絞れます。

「直近の変更」に着目

昨日まで動いていた」なら、原因は最近の変更にあります。最近変えたコミット・設定・ライブラリ更新(→ 第10章)を疑うのが鉄則です。長く動いていたものが突然壊れる場合、新しく入れたものが原因であることが多い。


5. 🔑 再現性と最小再現例

再現性 —— 毎回起きる vs たまに起きる

不安定なバグは「条件」を疑います(タイミング・データの内容・同時アクセス等)。何が揃った時に起きるかを突き止めると、再現性が上がります。

最小再現例(MRE)

バグを起こす手順から不要な部分を削ぎ落とし、「これだけで起きる」最小の手順・コードを作ります。これを最小再現例MRE/エムアールイー/Minimal Reproducible Example)と呼びます。

最小例を作る過程そのものが原因特定になります。「この部分を消してもまだ起きる」→ その部分は無関係、「消したら起きなくなった」→ その部分が原因、と消去法で原因が際立つからです。質問サイト等で助けを求める時も、最小例があると回答がつきやすい。


6. なぜ「論理的デバッグ」が開発の作法なのか

作法として位置づけられる理由

面接・実務での意味


7. よくある落とし穴と対処

落とし穴 何が起きるか 正しい対応
当てずっぽうに直す 別のバグを生む・同じバグが再発 原因を仮説検証してから直す・「なぜ直ったか」を説明する
症状だけ直す 根本原因が残り、別の場所で再発 root cause(根本原因)まで遡って直す
再現しないまま進める 「たまに落ちる」が永遠に直らない 確実な再現手順を先に作る・条件を特定する
ログを見ずに推測 外れの仮説で時間を浪費 ログ・print で状態を可視化してから仮説を立てる
直近の変更を疑わない 「急に壊れた」の原因を見逃す 最近の変更(コミット・設定・ライブラリ)を先に疑う
直したら終わり なぜ直ったか不明・再発時にまた迷う 再発防止のテストを残す・原因を記録に残す

💡 ラバーダック・デバッグrubber duck debugging/ゴムアヒル技法): バグに詰まったら、机の上のゴムアヒル(または誰か)に向かって、コードを1行ずつ口頭で説明するという古典的技法。「人に説明するつもりで話す」と、自分の勘違いや飛ばしに気づくことが多く、説明中に原因に気づくことがよくあります。1人で詰まった時の強い味方です。


まとめ

💡 次のステップ: バグの原因を論理的に突き止める手順が見えました。次は、そもそもバグを出しにくくする仕組みです。第12章開発プロセス・品質」では、テスト・Lint・型チェックで、バグを未然に防ぎ・早く見つける品質の作法を扱います。