3秒でわかる
期待どおりに動かない原因を突き止めて直す作業。当てずっぽうで書き換えるのではなく、事実を集めて原因の範囲を狭めていく手順のことを指します。
30秒図解
もう少し詳しく
どういうものか
デバッグは、プログラムが期待した動きをしない原因を特定し、修正する一連の作業である。語源は 1947 年にハーバード大学の計算機から実際に蛾が見つかった逸話とされ、不具合そのものをバグと呼ぶ。
作業の中身は、症状の再現、原因のある範囲の絞り込み、仮説の検証、修正、そして修正が効いたことの確認という流れになる。コードを読む時間より、事実を集める時間の方が長い。
なぜ必要か
エラーメッセージが指す行と、原因のある行は一致しないことが多い。undefined is not a function が出た行は、値が壊れた場所ではなく、壊れた値を使った場所である。原因は数十行前の代入や、API のレスポンス形式の変更にある。
だから「エラーの行を書き換えてみる」進め方では直らない。値がどこまで正しく、どこから壊れたかを実際に観測して境界を見つける作業が必要になる。
具体例
まず値を出して、想定と実際の食い違いを見る。
const res = await <a href="/glossary/fetch-api" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">fetch</a>("/api/orders");
const data = await res.json();
console.log("status", res.status); // 200 ではなく 401 かもしれない
console.log("typeof data", typeof data); // <a href="/glossary/array" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">配列</a>のつもりが<a href="/glossary/object" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">オブジェクト</a>かもしれない
console.table(data.items ?? []);
const total = data.items.reduce((sum, item) => {
console.log(item.id, item.price, typeof item.price); // "1200" と文字列かもしれない
return sum + item.price;
}, 0);console.log を並べるだけでも十分に効くが、ブラウザの開発者ツールや VS Code のデバッガでブレークポイントを置くと、その時点の変数をまとめて見られる。ステップ実行で 1 行ずつ進めれば、値が壊れた行がそのまま分かる。
つまずきやすいところ
一度に複数箇所を書き換えてしまうと、直った理由も直らない理由も分からなくなる。変更は 1 つずつ入れて、そのつど確認する。
再現手順が固まっていない状態で原因を探すのも遠回りになる。「たまに落ちる」は、入力データ、実行順序、時刻、キャッシュのどれかが違っている。100% 再現する手順を作るところまでが、実質的にデバッグの半分を占める。
思い込みの確認も要点になる。「ここは通っているはず」の行が実は通っていないことがあるので、console.log("ここまで来た") のような確認を惜しまない。
覚え方
デバッグは推理ではなく計測である。頭の中で原因を当てにいく前に、値を 1 つ表示する方が速い。
