プログラミングに関する雑多なあれこれ
今号から、「プログラミングの光景」と題して連載することになった高林と申します。プログラミングは趣味として、仕事として、かれこれ10年ほど行ってきました。本連載ではプログラミングに関する雑多な事柄について書く予定です。
第1回は、プログラミングとは切っても切れない関係にある「デバッグ」について取り上げてみようと思います。
デバッグの時間
ソフトウェア開発において、デバッグに要する時間は相当のものです。プログラマとしては「いやいや、自分はそれほどデバッグに時間を使ってないよ」と否定したいところですが、冷静に考えてみると、現実には自分が考えているよりも(そうであってほしいと考えているよりも)デバッグに時間を要しているように思えます。それに、バグは他人が書いたコードに混入していることもあるので、たとえ自分がバグを入れなくてもデバッグするはめになります。
デバッグの方法論についてはさまざまな文献で取り上げられています。デバッグで難しいのはバグの原因を見つけることです。原因さえ特定できてしまえば、修正自体はたいていの場合、簡単に片づきます。バグの原因を見つけ出す主要な方法には次のようなものがあります。
- 最後にいじったところを疑う
- デバッガで挙動を追う
- printfやログを大量に入れる
- 各種のデバッグ用ツールを使う(Cならvalgrindとか)
- バグが再現するコード・データをできるかぎり短くする(分割と統治)
- 気分転換してほかのことをやる
- 身近な人に相談する(説明しているうちに自分で原因に気づく)
最後の、「身近な人に相談する」に関しては、状況を説明することが重要なので、相談相手は人ではなく、ぬいぐるみでもよいという説があります。
バグの予防
デバッグの時間を減らすには、バグを出さないに越したことはありません。バグを予防する主要な方法には次のようなものがあります。
- ユニットテスト・リグレッション(回帰)テストをしっかりやる
- コンパイラの警告を最大にする
- コードレビューをする
- きれいなコードを書く
ユニットテストの重要性については近年、多くの文献で強調されており、私の経験としても、ユニットテストのおかげでデバッグに要する時間はかなり減ったという実感があります。
と言いつつも、「このくらいの小さな関数ならテストを書かなくてもいいだろう」とついさぼってしまい、何時間もプログラムを走らせたのちに結果が間違っている(バグっている)のに気づくというときがいまだにあります。
また、大規模なデータを処理するプログラムを開発する上では、いきなりでかいデータでテストをしないで、まずは小さなデータでテストをするのが効果的です。ついつい、「一発で動いたらいいなあ」という期待のもとに、本番のでかいデータで実行してしまいがちですが、一発で動いたためしはありません。
デバッグ仕事人
通常、プログラマはたいていの問題は自分で解決しようとしますが、どうしても手に追えない場合は、周りのプログラマに救援を求めることがあります。前述のとおり、他人に相談すると、説明しているうちに自分で原因に気づくことが多いのですが、中にはそう簡単には直らない厄介な問題もあります。
このようなとき、「どれどれ、ちょっと見せて」といって他人のデバッグを手伝うのは楽しいものです。どうして楽しいのか考えてみると、次のような理由に思い当たりました。
- バグの原因を見つけたときに気分がいい(鼻が高くなる)
- 直接的には自分の問題ではない(他人事の感覚なので気楽)
デバッグで苦しんでいる張本人と比べて、第三者である助っ人は客観的にコードを見ることができるので、張本人が見落としていた問題に気づくことはよくあります。また、「この挙動は以前に見たことがあるぞ」と、過去の事例に照らし合わせて勘が働くことがあります。
C++でいえば、メンバ変数の未初期化やスレッドのスタックのオーバフローによるバグは、一度遭遇したことのある人ならば勘が働きますが、初めてのときは厄介なバグです。ペアデバッギングはこうしたノウハウの伝承に効果的です。
ただ、助っ人としてバグを潰したときの「鼻が高くなる」の態度が鼻につくと 二度と頼まれなくなる恐れがあります。時代劇の主人公のように「名を名乗るほどの者ではござらん」といって去っていくのがクールなデバッグ仕事人の態度というものです。
まとめ
今回はデバッグについて書きました。次回からもこの調子で、プログラミングに関する雑多な事柄について書いていく予定です。