🐝

【全 1 選】デバッグ、バグ原因の見つけ方: 「事実」を「集める」

に公開

対象読者

  • 今まさにバグに詰まっている方
  • デバッグでにっちもさっちも行かなくて泣きそうな方😭
  • プログラミング初心者の方

要約 TL;DR

  • デバッグの秘訣はただ一つ: 「事実」「集める」 こと。
  • 事実に着目する理由: 事実は裏切らないから。仮説推論は先にやると非効率だから、事実が集まってからやろう。
  • 事実を 「集める」には、主体性が必要💪。事実は勝手には浮かび上がらない。
  • デバッグに詰まったら...それでも事実を集める。でも事実を集めるために一旦休むのも手。

議論しないこと

  • バグを治すべきかどうかの意思決定
    • 今回は、バグを治さなければならない時の、バグ原因の見つけ方の話です。
  • 要因を見つけた後の解決方法
    • 解決策を講じる前段階の「何が原因なんだろう?」にフォーカスします。
  • バグ予防の方法[1]

本論

背景

ITと言われる領域では、Python, AWS, Excel まで、数多の道具 (言語、フレームワーク、ソフト)を使って開発します。
道具の多様さを問わず、開発では共通の事象に出くわします。「あれ、せっかく組んだのに、なんか思ったのと違う動きをするぞ」 と。これぞ不具合、バグです。

ここで問題です。 あなたはバグを見つけてしまいました。あなたは責任を持ってバグを治さないといけません。皆さんはバグに直面したとき、何から着手しますか?

疑問符

「....うーん、何が原因だろう?」と背景要因の「考察」を始めてしまう。

なんとこれは罠中の罠なのです(!)。
私も開発を始めた当初はこの罠で引っかかっておりました😭 教えてくださった前職の上司には感謝です。

はい、効率的な答えは一つしかありません。「事実」を「集める」 ことです。
「事実」を「集める」とは?そしてどうしてそうすべきなの?を考えて参ります。

「事実」とは?

ここで事実とは、「客観的な何か」「データ」「主観でないもの」 を指します。

事実 vs 推測の具体例:

❌ 推測、主観

  • 「きっとAPIが重いんだろう」
  • 「たぶんメモリが足りないせい」
  • 「前回動いたから今回も大丈夫なはず」

✅ 客観的な事実

  • エラーログにConnectionTimeout: 30秒でタイムアウトと記録
  • タスクマネージャーでメモリ使用率97%を確認
  • print(response.status_code) で実際に404が返ってきている
  • デバッガで変数の中身がNoneだった
  • 同じコードを別環境で実行すると正常動作する

欲しいのはとにかく、テコでも動かない、変わらないものです。
思い込みは不要です。なので、もはや思い込みでないも全てが、全てが証拠になり得るレベルだと思います。

ただ注意したい対象もあります:

⚠️ 主観と客観の間

  • 「ここはこの変数がこう動いて、こう動く」という観念

これは意識上の概念の連続だからなのか、実態と揃っていない、つまり勘違いが起きがちです。なので、上記のようなものを考えているなと自覚したら、一旦やめるか、本当に実態と即しているか慎重に「事実」に照らしましょう。

事実を「集める」とは?

「客観的なもの」は勿論、我々の生きる世界にそこかしこにあります。[2]
でもそれを我々が意識しているとは限りません。[3]
事実は待っていても降ってきません。 自分から取りに行かないと、現れないものです。例えば、次の作業が必要です。

  • ログを取る
  • print を挟む
  • テストを書く
  • 環境情報を調べる

探偵が現場で証拠を探すように、バグの「証拠」も、あなたが意識的に探しに行く必要があるのです。

これを「スポットライト」で例えてみましょう。
事実という光が、ステージ上の無数の潜在要因から、照らし出します

     💡        💡        💡
   ログ確認    変数確認   環境確認
     \        |        /
      \       |       /
       \      |      /
        \     |     /
         \    |    /
          \   |   /
           ✨コード不具合✨
        [暗闇の中の問題原因のステージ]
     ●API問題    ●メモリ不足
  ●ネットワーク      ●DB問題
     ●設定ミス   ●コード不具合

光が集まることで、特定に近づきます。

スポットライト

(※事実の具体的な集め方については、別途詳しく記事にする予定です)

なぜ事実を集める?

事実が仮説を絞り込むからです。
事実がある程度集まってから、仮説を考えましょう。

今回の議論は、飽くまで前後関係の話なのです。何しろ最終的に解決する時というのは、「ここが問題で、この問題が起きた!」という洞察が伴います。この洞察は、紛れもなく思考です。主観と言えば主観だし、妄想とも言えます。

妄想は偽であり得ますが、事実は真です。妄想で事実は変わりませんが、事実は簡単に妄想を打ち砕きます。先に妄想すると時間の無駄となりうるから、先に事実を、光を集めるのです。
そうして正しい妄想にたどり着かせるのです。

実際のデバッグケース

ケース:「ユーザー登録ができない」

よくある悪い例:
「うーん、バリデーションエラーかな?それともデータベースの問題?」と考え込む

事実収集アプローチ:

  1. ブラウザの開発者ツールでネットワークタブ確認 → 500 Internal Server Error
  2. サーバーログ確認 → KeyError: 'email'
  3. フォームのHTMLソース確認 → input要素のname属性がuser_emailになっている

結果: 3分で原因特定。フロントとバックでフィールド名の食い違いが判明。

実践的なデバッグのコツ

  • とにかくデータを集めるのです。 事実を集めても、まだバグがわからない、仮説が違った場合、大抵事実が足りなかったり、予想外の見落としがあります。気づくためには、経験を積むか(無論すぐには無理)、周りに相談しましょう。他人は、自分とは異なる世界の見方があるため、他の事実に注意が行き、解決するかもしれません。

  • それでもいい事実が集まらない時は?一旦休みましょう。:

    • リフレッシュすることで、集中力が上がります。
    • 後で見たりすると、それまで気づかなかった予想外のところへ注意がいくものです。

サボり

  • 問題が起きたレイヤーに関していうと、大抵自分の身の回りとか、そのバグが起きたところの周辺に要因がありがちです。アプリなら、OS や通信の不具合でなく、内部の関数とか。大きい敵を見つける前に、まずは徹底的に周辺を調査しましょう。

「近いところから探す」の具体例:

ケース:「データベースに保存したはずのデータが見つからない」

よくある悪い例:
「データベースのレプリケーション設定が間違ってるのかも?」「キャッシュサーバーの問題?」と大きなシステムを疑う

近いところから探すアプローチ:

  1. まず該当の関数内をチェック → user.save()の直後にprint(user.id)を追加
  2. 出力結果:None → 保存処理でエラーが起きている
  3. さらに近く:user.emailを確認 → test@invalidという不正な形式
  4. バリデーション部分を確認 → 例外が握りつぶされていた

結果: 問題は遠大なインフラではなく、その関数の例外処理だった。

まとめ

  • バグ要因が見つからないときは、考えるよりも前に、「事実」を「集める」ことに集中しましょう!
  • ハマるとしんどいのがデバッグですが、落ち着いて、時には休んで取り組みましょう!

脚注

脚注
  1. 根本的なバグ解決という意味では、そもバグを出さないことが大事です。またお金をいただいている製品でバグが起きたら、直す以外にも、現状の復旧や切り戻しも必要でしょう。それら傾向と対策は例えばIPAの障害分析が詳しいです。 ↩︎

  2. 「そんなそんな、そもそも存在って何?客観的な物が存在しているって言えるの?」といった存在論的議論なんてこの世には存在しません。いいね? ↩︎

  3. [余談]脳神経上では視覚上にあるものと捉えているものでも、私たちが注意しているとは限りません。こうした事象について、近年の自然言語処理AIないしLLMも類似している気がします。人もAIも同様に、「注意」無くして、問題解決はあり得ないということです。自然言語AIで基底となるのは、Attention=注意機構という構造です。このAttention機構は「情報の流れ」の学習にとても強力です。ところで「問題解決」というのは、「情報の流れ」を伴うとみなせます。このAttention機構が、「問題解決」特有の「情報の流れ」パターンの学習を可能にしている、のかもしれません。人の注意も、Attention機能も、類似した役目を果たしている...のかもしれません。(ここまで妄想) ↩︎

Discussion