エラーは一行で起きない: frameCountで読む、状態が壊れた瞬間

naoya

Hatched by naoya

Aug 10, 2026

1 min read

88%

0

エラーが出た瞬間、私たちはたいていコードの一行を探し始めます。しかし、本当に探すべきものは一行ではなく、時間の中で何が変化したかかもしれません。

SyntaxError、ReferenceError、TypeError、RangeError。これらの名前は、プログラムがどの種類の約束を破ったのかを教えてくれます。一方、frameCount は、プログラムが実行開始から何回進んだのかを記録します。一見すると、前者はエラー処理、後者はアニメーションやゲーム制作のための単なるシステム変数です。

けれども、この二つを組み合わせると、デバッグについて重要な見方が現れます。エラーは、コードの欠陥そのものではなく、時間の流れの中で約束が破られた瞬間に現れる観測結果であるという見方です。

この視点に立つと、デバッグは「間違った行を当てる作業」から、「プログラムの状態がいつ、どのように変質したかを再構成する作業」へ変わります。

エラーメッセージは判決ではなく、観測記録である

エラーメッセージを読むとき、多くの人はそこに原因が直接書かれていると思いがちです。TypeErrorと表示されれば、「型が間違っている」と理解し、該当しそうな行を修正しようとします。もちろん分類は役に立ちますが、エラー名だけでは問題の全体像は分かりません。

たとえば、文字列と数値を足そうとしてTypeErrorが発生したとします。原因は、その行に突然現れたとは限りません。数値であるはずの変数が、数十フレーム前の処理で文字列に置き換わっていた可能性があります。あるいは、入力を受け取った瞬間から、想定とは異なる値が入っていたのかもしれません。

つまり、エラーが発生した場所と、エラーを生み出した場所は一致しないことがあります。

frameCount は、このずれを考えるための具体的な手がかりになります。draw が実行されるたびに増え続けるこの値は、プログラムの現在地を示します。画面に何かが表示されているとき、そこには必ず「何回目の更新処理の結果なのか」という時間情報があります。

エラーの行を読むだけでは足りない。エラーが起きた時点までの履歴を読まなければ、状態の変化は見えない。

エラーメッセージは、裁判官が下す判決というより、故障した機械から届く警報に近いものです。「この瞬間、この操作は成立しなかった」と知らせているだけで、「最初に何が悪かったか」まで保証してはいません。警報を止めるだけなら、その場の値を強引に変える方法もあります。しかし、故障の連鎖を理解しなければ、次のフレームで別のエラーが生まれます。

デバッグの本質は、時間を切り分けること

問題を解決するとき、まず実際に動かしてエラーを再現することが重要です。これは単なる形式的な手順ではありません。再現できない問題について考えると、私たちは記憶や推測を事実の代わりに使ってしまうからです。

再現できたら、次に見るべきなのはコード全体ではなく、エラーが起きるまでの時間の区間です。プログラムを一枚の静止画として見るのではなく、フレームの連続として見るのです。

例えば、画面上の円の大きさを変えるプログラムを考えてみます。円の大きさを表す変数 size を毎フレーム増加させ、一定の範囲を超えたら小さく戻すつもりだったとします。しかし、ある条件分岐の中で size に文字列が代入されると、しばらくは画面に変化が現れないかもしれません。その後、数値との加算や比較が必要になったフレームで、初めてTypeErrorや期待外れの動作が現れます。

この場合、エラーが出たフレームだけを見ても十分ではありません。少なくとも次の四つを確認する必要があります。

  1. エラーが初めて発生したフレーム
  2. 直前にその値を書き換えたフレーム
  3. その値が最初に想定外の型や範囲になったフレーム
  4. 正常に動作していた最後のフレーム

この調査は、時間的な二分探索に似ています。まず正常な区間と異常な区間を分けます。次に境界付近を調べ、どの時点で状態が変わったかを絞り込みます。すべてのコードを同時に疑うのではなく、正しく動いている部分を候補から切り捨てることで、原因の探索空間を小さくできます。

ここで、正常なケースとの比較が強力になります。エラーが起きる入力と起きない入力、エラーが出るフレームと出ないフレーム、値が数値のまま進む実行と文字列に変わる実行を比べるのです。違いは、必ずしも見た目の大きな差として現れません。たった一つの代入、条件式の境界、初期化のタイミングが、後のフレームで大きな結果になります。

エラーの種類とフレームの履歴を組み合わせる

エラーの分類は、問題の種類を示す地図です。フレームの履歴は、問題が発生した経路を示す足跡です。地図だけでも、足跡だけでも不十分ですが、二つを重ねると調査の精度が上がります。

SyntaxErrorは、プログラムが実行される前に文法という約束が破られている状態です。この場合、時間の流れはまだ始まっていません。括弧や記号、構造を確認し、まず実行可能な形に戻す必要があります。

ReferenceErrorは、存在しない変数や関数を参照した状態です。これは、ある名前がいつ使えるようになったのか、あるいはどの範囲で存在しているのかを調べる問題です。特定のフレームだけで発生するなら、条件分岐の内側でしか定義されていない値を、別の場面で使っている可能性があります。

TypeErrorは、値の種類と操作の組み合わせが成立していない状態です。ここでは、現在の値だけでなく、その値がどのフレームで型を変えたのかを確認します。変数名が同じでも、時間によって中身が変わるなら、それは一つの変数ではなく、履歴を持つ状態です。

RangeErrorは、値が許された範囲を外れた状態です。これは特に、frameCount のような増加し続ける値と相性がよくありません。フレーム数をそのまま座標、配列の位置、角度、繰り返し回数に使うと、長時間の実行によって初めて範囲外に到達することがあります。

この整理から、実用的なデバッグ表を作れます。

確認するもの問い
種類文法、参照、型、範囲のどの約束が破られたか
時点何フレーム目で初めて異常になったか
直前の変化その値は直前にどこで書き換えられたか
正常例正常な実行では同じ時点に何が起きているか
前提自分が正しいと思っている値や条件は本当に確認済みか

最後の「前提」が特に重要です。デバッグでは、見ている部分が正しいと思い込むこと自体が大きな障害になります。「この変数はずっと数値のはずだ」「この関数は毎回呼ばれているはずだ」「この条件は一度しか成立しないはずだ」。こうした「はず」は、検証されるまで事実ではありません。

プログラムを状態の物語として読む

コードは、命令の一覧として読むこともできます。しかし、動いているプログラムは命令の一覧ではありません。変数、入力、条件、画面、時間が互いに影響し合う状態の物語です。

frameCount は、その物語にページ番号を付けます。ページ番号がなければ、どの出来事が先で、どの結果が後なのか分かりません。エラーが発生した行だけを読むことは、物語の最後の一文だけを読んで、登場人物の行動理由を推測するようなものです。

この考え方を実際のコードに取り入れるには、重要な変数の状態をフレームと一緒に記録します。例えば、次のような情報です。

console.log(frameCount, size, typeof size);

この記録から分かるのは、単に「エラーが出た」という事実ではありません。何フレーム目に、どの値が、どの型で存在していたかです。さらに、値が変わる箇所の直後にも記録を置けば、変化の起点を追跡できます。

ただし、記録を増やせば増やすほどよいわけではありません。大量のログは、別のノイズになります。まずは問題に関係する変数を一つか二つ選び、正常な実行と異常な実行を比較します。デバッグとは、情報を集めることではなく、原因を識別できる情報だけを残すことです。

この方法は、プログラミング以外にも応用できます。実験が失敗したなら、失敗した結果だけでなく、どの時点で条件が変わったかを記録します。仕事のミスが起きたなら、最後に間違えた操作だけでなく、正常だった状態からの最初の差分を探します。人間関係の行き違いでも、結果の発言だけを裁くのではなく、どの時点で前提がずれたかを見ることができます。

Key Takeaways

  1. エラー名を分類として使う:SyntaxError、ReferenceError、TypeError、RangeErrorのどの約束が破られたのかを最初に確認する。
  2. エラーが起きた時点と原因が生まれた時点を分ける:現在の値だけでなく、何フレーム前に状態が変わったかを調べる。
  3. 正常なケースと異常なケースを比較する:コード全体を疑うのではなく、両者の最初の差分を探す。
  4. 前提をログで検証する:「数値のはず」「呼ばれるはず」と考えず、値、型、フレーム数を実際に確認する。
  5. 記録を絞る:すべてを出力するのではなく、原因を特定するために必要な状態だけを追跡する。

エラーは、プログラムが時間を持っている証拠である

初心者はエラーを、コードが自分に反抗している合図だと感じるかもしれません。しかし、エラーはもっと有益なものです。それは、プログラムがどのような約束に従い、どの時点でその約束から外れたのかを知らせる観測窓です。

frameCount を意識すると、デバッグの対象は一行のコードから、時間の中で変化する状態へ広がります。エラーは点ではなく、そこへ至る軌跡の終点です。重要なのは、終点を消すことではなく、正常な軌跡から最初に分岐した地点を見つけることです。

良いデバッグとは、エラーを黙らせることではない。プログラムがどの瞬間に、自分の前提を裏切ったのかを理解することである。

次にエラーが出たとき、いきなり修正案を考えないでください。まず、何フレーム目なのか、直前まで何が正常だったのか、どの値が最初に変わったのかを尋ねてみましょう。その瞬間、エラーは邪魔な赤い文字ではなく、プログラムの時間的な構造を読み解くための案内板になります。

Sources

← Back to Library

Hatch New Ideas with Glasp AI 🐣

Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)

Start Hatching 🐣