恐ろしきデバッグ

先日の問題はなんとか解決することに成功した。
本来ならばどうやって解決したのか、その解決手段についてここに記録しておくべきが筋なのだろうが残念ながらすべて忘れてしまった。正直必死にネットで情報収集をしながらあれこれいじっていたらいつのまにかgrubが表示され亡くなった、という具合だ。なんとかwindowsXPで起動することには成功したので、そこからubuntuに関わりそうな部分をあらかた削除してもう一度インストールし直して今に至る。Linuxの便利さを知ってしまうとwindowsに戻ろうという気にはなれなかった。
メインPCの復旧に成功はしたものの、近頃熱中していたゲーム「mine craft」のセーブデータが失われてしまったのが非常に悔やまれる。

復旧後、あらかたブラウザやEmacsのインストールなどのセッティングをし終えてまずとりかかったのは大学のプログラミング課題だった。本来ならまだ余裕のある期間なのだが、最後にソースコードを書いてから随分経ってしまっていて、久しぶりにコードをガリガリ書きたくなったという気持ちが強かった。結果として6月中に終わらせる課題が金曜と土日で終わってしまった。少し行き急ぎすぎてしまったかもしれない。このぽっかりと空いた空白期間を、何か別のことに費やすべきだろう。

さて、今回取り組んだ課題は「ソーティング」についてだ。選択ソートとマージソートを実際にプログラミングして実行させ、その比較回数を解析するというものだった。どうせならヒープソートクイックソートなど他の種類のソーティングについてもやってみたいとは思うが、僕のいる学科でそこまでのレベルを要求するのは無茶な話ということなのか、今回の課題ではこの2つのソーティングしか扱わなかった。

前回の課題は「連立方程式の解法プログラム」、連立方程式ガウス-ジョーダン法とガウスの消去法の2つのアルゴリズムで解き、その演算回数を解析するというものだった。この時僕は今までの「C言語を習うためのコード」とは違う「アルゴリズムを学ぶためのコード」を初めて書いた。それまではプログラムの入門書に書いてありそうな数十行で済むコードしか書いてこなかったため、100行を超えるような本格的なコード生成作業は新鮮に感じられた。前々から試してみたかったモジュール化などを試して見ることができた。さらにはエラーチェックの手法や動的メモリ確保など、思っても見なかった副次的恩恵をも得ることができた。
長期に渡るコーディングのつらさを、めんどくささを感じることもあったが、プログラミングで得るものも大きかったと思う。

では今回の課題、「ソーティング」はどうだったろうか。感想としては「あっけない」だろうか。
課題の中で前々から疑問に感じていた「argc」や「**argv」を理解することができたし、ファイル入出力を何度も使うことでそこのあたりについての不安感もある程度は解消された。最終的には削除されたが、get文やfget文を試す機会もあったし、なによりもマージソートがより強力なソーティングであることを実感できた。(選択ソートについては既に以前書いたことがあった)
だが、たった3日で全てが終わってしまうのはなんともあっけないと言わざるを得なかった。それに前回に比べ使用する関数も種類が少なかったように感じる。既知の課題である選択ソートについてはいいとして、マージソートは書いてしまえば案外にあっけないものだった。アルゴリズムを理解する際に「これは少々苦労するかもな」と懸念を感じていたが、なんと課題の設問にコードがそのまま全部載っていた上に(少々見辛くはあったが)実行する操作はすっきりとしたものだった。与えられた配列とは別に3つの配列を用意し分割と統合を再帰的に繰り返すだけという簡潔といってもいいほどの内容に、最初は驚いた。
そういったことを思うと、今回の課題は逆に「3日もかけてしまった」と言えるかもしれない。眠気に負けて中断したり、コーディング作業に飽きて休憩したり等の遅延はあったものの、最初の二日間はほぼ順調だった。アルゴリズムの仕組みや比較回数の解析を手書きで説明する設問が面倒だけどそれくらいかな、と思っているとそれが起きた。

正体不明のエラーだ。
エラーは何回かコードをいじってだまらせることができた。もうよく覚えていないが、何か些細な書き間違いをしていたと思う。それよりも困ったのはコンパイルを通ったあと、端末上で表示される明らかに間違っている値だ。ほとんどの数字に0が代入されていた時には頭を抱えた。入力値を再表示する際にはなんの異変もなかったから、マージソートにかける部分でエラーが起こっていることはすぐにわかった。だが、コンパイルを通ってしまった以上実際のコードのどの部分に不具合が生じているのかはまったくわからない状況である。うんうんうなりながらコードを一から点検し、リコンパイルしては再実行の繰り返しが何時間か続いた。
最終的にはfor文の中で、for文の変数とは別変数を操作する際にfor文の外と内との整合性がとれていないということに気がついてことなきをえた。そこに気がつくまでにかなりの時間を要した。前回の課題のようなエラーチェックを使えない分、質が悪かった。
「ソーティング」課題で一番教訓となったのは間違いなくデバッグだった。今まで何冊かエンジニアリングに関する本を読んできたがそのどれもがデバッグには気を付けなければならないと書いてあった。その意味がようやくにして本当の意味で理解できた。デバッグ作業はかくもつらいものなのかと痛感した。これから先もきっとこのような、いやこの程度ではまだまだと思うくらいのつらいデバッグ作業がまちかまえてるのかと思うとすこしげんなりしてくる。

だが、つらいデバッグを終えたあと、プログラムが期待通りの振る舞いを見せた時にとったガッツポーズの高揚は何物にも代えがたい経験だった。あれがまた味わえるというのであれば、僕はきっとこれからもプログラミングを続けていくだろうなと思う。


最後にたまたまネットでみかけて面白いと思ったフレーズを。
デバッグは最初にコードを書くのより2倍難しい。つまり、もしあなたが知力を振り絞ってコードを書いたのなら、あなたは(定義から明らかなように)それをデバッグできるほど賢くない。- Brian Kernighan