« プログラミングを始めるには(12) | Main | プログラミングを始めるには(14) »

August 03, 2014

プログラミングを始めるには(13)

プログラミングを始めるにはデバグが容易でなければならない。

プログラムは書けるようになればそれで良いというものではない。自分または他人が期待する動作をしなければ意味がない。そのためには期待通りの動作をしているかどうかを確認する必要があるが、それはプログラミング言語や動作環境に大きく左右される。デバグが難しい、あるいは面倒な場合、バグの摘出はどんどん後工程に持ち越され、後になればなるほど解析を困難にする。

プログラマの性格に左右されるとは思うが、動くかどうかは置いといて、さっさと設計書通りのコーディングを終わらせたいという人から、書くからには設計書を鵜呑みにせず、場合によってはインタフェースだけを念頭に置いてじっくりコーディングし、動作するかどうか自信がない部分は動かしながら進める人まで、樣々であると思われる。後者に近いほど結果的な(絕對的な)品質は良くなるが、品質管理ではそんなふうにコーディングする人のことは考慮しないで品質計畫を立てるために、プロセス的な品質管理においては困ったことになる。

個人的には、假に自分で書いた設計であってもその通りにコーディングしたことは無いし、初めて使うライブラリを呼び出す場合は、簡單なドライバを書いて必ず動作確認したものだ。なので、コーディングが終わるとともにフラグ取りも、單體試驗もほとんど終わっている。ただし、勘違いしていた場合は悲慘なことになるだろう。

こういうやり方は、自分の端末でエディタを使ってコーディングし、自分の端末でコンパイルし、實行形式のファイルまで作成出來る環境でなければ不可能だ。コーディングペーパーにプログラムを書き、それをカードにパンチして計算機に讀み込ませていた時代に、上記のようなやり方をしていた人が居たとは思えない。そもそもプログラムの走行やデバグは實機でなければ出來ないので、自分に割り當てられたマシンタイム以外にやりたくても出來なかったのだ。しかも、ちょっとでもバグがあれば再開處理が動いて、バグ解析が困難極まりない。

當時に比べればソフトウェア工學もずいぶん進步したと思うが、今でもスクラッチ開發では當時の文化が色濃く殘っているし、その當時を經驗している人は、單體試驗や結合試驗でバグが出ないプログラムの品質を良いと評價することは絕對にない。そしてそういう人たちの指導を受けて育つ若いプログラマは、バグが出ないと怒られるので、ウソのバグ票を書いたりする。そんなことをしていて品質の良いプログラムが出來るわけがない。

いずれにしても、書いたプログラムがちゃんと動作するかどうか確認出來る環境がなければ話にならないし、確認するのが面倒では問題を見つけられない。

Screenshot_from_20140803_11


C言語のプログラムをgdbで走行するとこんな感じになる。Missing separate...という變なメッセージが出ているが氣にしない。ここまでに、0002.cを-gオプション付きでコンパイルし、0002という實行ファイルを作成する、Emacsの中でgdbを起動(M-x gdb)し、main關數の先頭にブレイクポイントを設定(b main)し、runしたところである。Emacsの中で實行しているとはいえ、ちゃんと實行している行と、ブレイクポイントがある行を表示している。

Screenshot_from_20140803_135301


Emacsを端末ウインドウ(Gnome端末)で動かすとこんな感じになり、ブレイクポイントや實行行はキャラクタ表示される。GNUスタイルのインデントは「=>」を表示するためかと勘繰りたくなるところだが、むかしからGNUのコーディングスタイルはC言語でもLispでもインデントが2カラムだった。ステップ實行していき、print文を實行するとinput/outputというバッファが現れて、端末への表示狀況を確認出來る。こんなのはむかしはなく、print文の表示はgdbのコマンドバッファに表示されていた。それに端末ウインドウでもちゃんとキーワードがハイライトされていて、このへんにはさすがに時の流れを感じさせられる。

Ws000093


C言語のプログラムをgdbで走行する場合、Emacsは外部のgdbプロセスと通信する形で行なうが、Emacsの中でemacs-lispのデバグ走行を行う場合は、Emacsの中だけで完結する。先日のエラトステネスのふるいを走行する場合、M-x edebug-all-defs、M-x eval-bufferを實行すれば準備完了で、あとは實行したい關數を起動すれば良い。すると、あらかじめブレイクポイントを設定しておかなくても、最初に實行する關數の先頭でストップする。さらにEmacsはリカーシブ編集モードになり、モード名のところには「*Debugging*」と追加表示される。

このあとは、スペースキー(edebug-step-mode)でどんどんステップ實行していき、關數呼び出しのところに來るとその關數に實行行が移る。ここではバッファ中のすべての關數がedebugの對象になっているが、もしも走行する必要のない關數が混じっている場合は、個々にedebug-defunすれば良い。edebug中に「t」(edebug-trace-mode)または「T」(edebug-Trace-fast-mode)をタイプすると、どんどん自動的にステップ實行する。「T」は高速トレースモードだ。「h」とタイプすると現在カーソルがあるところまで實行して停止する。

しかしこのようなデバグ方法の場合は、やはり再歸呼び出しが無い方が良いと思われる。たとえばrange關數では、關數の處理結果が一番深い再歸に達した後で(10)、(9 10)、(8 9 10)、と順番に連續表示されるが、ループで書き直したrange2という關數なら實行中にtoという變數を常に參照可能だ。

Ws000094


ループで書いた處理をトレースするとこんな感じになる。關數呼び出しのパラメータと戾り値が分かるわけだ。上手く關數分けをして書けば、これだけでも十分なデバグ情報になる。

Ws000095


最後にちょっと變わった例を。餘程變わった人でないとこういう書き方はしないと思うが、この2つのうちSchemerは上のような書き方を好む?らしい。しかし、こういう場合でもedebug-eval-top-level-formを使えば追いかけることが可能だ。下の例は關數名を使わない書き方に直しただけで、最初からこんなふうに書く人はほとんどいない。

|

« プログラミングを始めるには(12) | Main | プログラミングを始めるには(14) »

Comments

Post a comment



(Not displayed with comment.)


Comments are moderated, and will not appear on this weblog until the author has approved them.



TrackBack

TrackBack URL for this entry:
http://app.cocolog-nifty.com/t/trackback/74224/60090736

Listed below are links to weblogs that reference プログラミングを始めるには(13):

« プログラミングを始めるには(12) | Main | プログラミングを始めるには(14) »