デバッグ方法の基本

ども、山中です。
今回は、デバッグ方法を挙げてみます。
様々な環境別に、デバッグ方法は存在しますが、抽象的に捉えれば基本は同じです。
今回は抽象的なデバッグ方法をご紹介します。

早く結論を知りたい人用

対策
  • ログを仕込んで情報を得よう
  • 仕様を読もう
  • 根拠の無い思い込みを排除しよう
予防策
  • 同じ文字を打ち込む場合は、コピー&ペーストを使おう
  • スペルチェックを使おう

今回の前提条件
  • エラーメッセージを直接検索エンジンへ使いません
  • 他の人に頼りません
前提条件は上記のような事としましたが、現実的な仕事の範囲では、上記前提条件を
崩す必要があります。
しかし、自分のレベルアップや、上記前提条件を崩せないような状況を考えると、
今回のデバッグ方法は役に立つはずです。

今回の足がかり


エラーメッセージがある場合を考慮します。


デバッグ時の留意点


エラーメッセージと、エラーの原因は必ずしも一致しない

エラーメッセージがある場合でも、必ず留意すべき事があります。
それは、
「エラーメッセージと、エラーの原因は必ずしも一致しない」
という事実です。
ソフトウェアも人の体と同じようなもので、
「肩こりの原因が、実は遠くの血管が詰まっているせいだった」
という事があります。
いわゆる遠因というものです。
「あれ~、これスイッチ入れても動かないよ~?」
「よし、調べてみよう。う~んこの部品も壊れてないし、この部品も壊れてない・・・

なんでだろう」
→電源プラグが抜けている


エラーの発生原因が一つとは限らない

結果と原因は、一対一対応すれば良いのですが、一対多対応する事があります。
結果というのは、原因に対応するidではありません。
人の体で例えると、風邪症状の原因が、様々なウィルスが起こすものだという事です。
原因から結果は導けますが、結果から原因が導けない例です。


という上記の前提を元に、今起きている現象を事実として進める

事が大事です。
バグの原因調査は、事実を理解する事から始まります。
事実を理解したのち、今ある事実から、原因を仮定します。
仮定した原因が正しいかどうかを調べるための情報を集め、
仮定が誤っていたら、再度事実を見つめなおします。

エラーメッセージの内容


エラーメッセージが具体的にどこのコードに問題があるか示している


エラーメッセージにエラー発生箇所のファイル、行番号がある

まずは、エラーメッセージとエラー発生箇所のコードを照らし合わせます。
原因が分かれば、その場で修正します。
良くある原因の種類
  • typo(打ち間違い)
  • コピー&ペースト後の変更漏れ
  • 仕様を分かってない
typo(打ち間違い)
良くある要因
typoを引き起こす要因の一つが、一度打ち込んだ単語を、再度打ち込む事です。



予防策
同じ単語を二度以上使う場合、二度目はコピー&ペーストにすると良いです。
Vimを使ってる方であれば、`yiw`を使えば楽です。(`yiw`→`ciw`→`Ctrl+r, 0`)
置換したい場合であれば、一括置換するのも良い手だと思います。

対策
typoがある事を疑う場合は、単語のチェックを行う機能があるテキストエディタを
使うと良いでしょう。
不審な単語には、下波線を付けてくれるでしょう。
文書作成ソフト等でも単語のチェックをやってくれます。
gVimでの「スペリングチェック」


コピー&ペースト後の変更漏れ

良くある要因
変更箇所が二箇所以上ある場合に、起き易い現象です。

予防策
コピー&ペーストした対象部分を1行、1文字ずつ読みます。
また、入念にやりたい場合は、コピー&ペーストした対象以外の部分も、
同様に1行、1文字ずつ読みます。
ここで大事な事は、「見る」ではなく「読む」です。
特に声に出して読む事で、何がおかしいかについて気付けます。
人の脳は、間違っている事でも、頭が勝手に補正して、誤りに気付かないように
してしまうからです。
(個人的に特に厄介に感じる事は、「間違っていないはずだ」という「根拠の無い
思い込み」に囚われる事です。
また、「根拠があっても、証拠が足りていなかったり、前提が誤っていたりする
場合も厄介です)
「わしたははれるでしょう」
→「あしたははれるでしょう」の言い間違いだと気付きますが、
「わした」を「あした」へ直そう、とは思いません。
(なぜなら、頭の中では既に「わした」は「あした」に修正済みだからです)


対策
予防策も対策として使えます。
他には、最初から「何を変更すべきだったのか?」を整理すれば大丈夫です。
仕様を分かっていない
良くある要因
資料が見つからなかったり、聞ける人がいなかったりする場合が要因として
あるでしょう。
他には、「仕様は分からないけどとりあえずやってみよう」とやってみた場合も
要因としてあるでしょう。

予防策
仕様を読みましょう。「仕様がどこにあるか分からない」?探しましょう。
探し方は、その仕様次第です。オープンな仕様であれば、ググれば見つかりますし、
オープンでなければ、オープンでないなりの仕様入手方法が必要です。
(ドキュメントが存在しない事もありますから、その場合はソースコードの入手が
必要ですね)


特に、ソフトウェアで重要なのは、「バージョン」です。
メジャーバージョンアップがあった場合(番号の一番大きいものが増えた場合)、
「今までの常識が全て変わった」と思うぐらいに、仕様変更があったと思いましょう。
上司が変わったり、自分の役職が変わったりするのと同じぐらいの違いです。
慣れ親しんだ環境は、既に魔の巣窟と化しています。
RPGをレベル1から始めるぐらいの気持ちで、仕様書から読みましょう。


対策
仕様を読みましょう。

原因が分からない場合

あらゆるコードの間にログを仕込む


実際にどこで何が起きているかを把握する事が何よりも先決です。
  • どういう経路を通っているのか
  • どういうデータの変化があるのか
を理解する事で、何が問題となっているかを推測しやすくなります。
「あらゆるコード」とは、自分が追加や変更したコード以外の事も指します。
使っているライブラリであっても、もし編集してコンパイル出来るならば、ログを
仕込む価値があります。
「正しい"はず"だ」を「~という根拠があるから、正しい」と言えるようにする
もし根拠を集めた後に、まだ原因が分からなくて解決していないなら、
その根拠自体も疑いましょう。
世の中、例外だらけです。前提条件は容易く覆ります。


もし使えるなら、デバッガを使ってブレークポイントを設定する事も良い方法です。

エラーメッセージが具体的にどこのコードに問題があるか示していない


上記の「原因が分からない場合」と同じ対策が必要です。
また、「今何が分かっていて、今何が分からないか」を書き出してみましょう。
「分からない事が分からない」という状況であるならば、「事実」を書き出しましょう。
見たり、聞いたりして、自分の中に湧き上がる言葉を書き出せばいいだけです。
今目に見えている事は、嘘ではありませんから。
「事実」から出発し、自分の意思を少し加えれば、迷いつつも方向性が定まるはずです。


以上、今回は抽象的なお話でした。
今はプログラムの世界も、非常に広範な世界になってきて、
抽象的な理解だけでは苦しい場面も増えてきました。
しかし、抽象的な事は物事の骨組みですので、骨組みさえ分かっていれば、後は
肉付けをがんばればいいのです。
(その肉付けが大変な世界になってきている、、というのは、多様性こそが
本質であろう、という事でもあります)