コードリライティング
プログラム理解とかプログラムスライシングでweb検索していたら、CodeSurferというソフトがあるらしい。その名前でもういちど検索すると、IEEE Software JULY/AUGUST 2003(Software Inspection特集号)の記事に説明があるようだ。("Tool Support for Fine-Grained Software Inspection"(Paul Anderson, Thomas Reps, Tim Teitelbaum, and Mark Zarins, pp.42-50)[アブストラクト和訳]])
たまたま自宅にその号があったので、読んでみた。よさそうに思えるので開発元の企業のwebサイトに行ってみると、Flashで作ったデモを見ることができた。それを見ると、たしかにプログラム理解の助けにはなりそうだ。ただ、詳細はよくわかるが全体像をつかむことは難しそうだ。
それはともかく、同じ雑誌に"Practical Code Inspection Techniques for Object-Oriented Systems: An Experimental Comparison"(Alastair Dunsmore, Marc Roper, and Murray Wood pp.21-29)[アブストラクト和訳]]))という記事があった。
コード・インスペクションの3種類の方法をとりあげて比べるという記事(論文)だ。抽象化駆動技法(Abstraction-driven technique)、ユースケース技法(Use-Case technique)とチェックリスト技法(Checklist technique)というのがあるそうな。
この記事の主旨としては、チェックリスト技法、抽象化駆動技法、ユースケース技法の順に効果が高い(バグを見つけるまでの時間が短い)ということだ。
チェックリスト技法の効果が高いというのは、そのチェックリストの質に大いに依存すると思う。もし、バグを見つけるという目的に対してうまく作られたチェックリストがあるという前提でなら、それはそういう結果になるだろうなと思う。効果的なチェックリストの作り方がわからないと意味が薄いのではないだろうか。
体系的に準備ができる方法といえる、ユースケース技法の効果が低いのが意外。
抽象化駆動技法というのは、要するにコードをより直接的に意図を反映するように読み、その内容を自然言語で表現するといういわば書き換えだ。
ユースケース技法はコードとは別にユースケースシナリオが与えられていて、それとコードを突き合わせて矛盾がないか検査しようという方法らしい。
コードだけをじっくり読む抽象化駆動技法のほうがバグが早く見つかるというのでは、ユースケースシナリオの立つ瀬がないように思える。
ユースケースシナリオが与えられることによって、注意がシナリオとコードの両方に分散し、コードをしっかり読まなくなってしまうのだろうか。
プログラムの理解において、バグの発見が早いという指標が妥当かという点も疑問だ。バグというのはプログラマーの勘違い・うっかり間違いである可能性が高い。であれば、バグの発見しやすさというのは詳細に対する厳格性が発揮しやすいかどうかということになりそうだ。プログラムの本来の目的やシステムにおける役割の理解とは別の観点での理解度ということになるだろう。
そう考えれば、ユースケース技法がバグの発見という点では抽象化駆動技法に一歩譲るというのもうなずけることかもしれない。
その記事からのコード例のひとつ:
public boolean isRegistered(String e) { int i = 0; while ((i < theUsers.size()) && ((((Person)theUsers.elementAt(i)). getEmail()).equals(e)) i++; return i < theUsers.size(); }
この、例として掲げられているコードを抽象化駆動技法(Abstraction-driven Technique)で読むと、こうなる、と書いてある。
Returns true if the input string e matches the email address of one of the Person elements in the user collection: otherwise, return false.
日本語訳:
もし入力文字列 e が user コレクション中の Person 要素 のひとつの email アドレスと一致すれば、真を返す: そうでなければ、偽を返す。
上のコードを書き換えてみる。
最後のreturnの式には、if文でも書ける。
whileの直前にある変数iの宣言と初期化と、while文の本体にあるi++とを、まとめてfor文に変更することができる。そうすると、こうなる。
public boolean isRegistered(String e) { for (int i = 0; ((i < theUsers.size()) && ((((Person)theUsers.elementAt(i)).getEmail()).equals(e)); i++) ; if (i < theUsers.size()) return true; return false; }
for文の脱出条件は二つの条件式の論理和(&&)だ。その2つの条件が両方とも真になる場合にだけfor文を抜けることができるので、途中で抜けた場合(2番目の条件が偽になるとき)にだけtrueを返すことになる。
public boolean isRegistered(String e) { for (int i = 0; i < theUsers.size(); i++) if (!(((Person)theUsers.elementAt(i)).getEmail()).equals(e)) return true; return false; }
たぶん、この形式で書くのが、いちばん英語での表現に近いんじゃないかと思う。(もっとも、書き換える過程で、元の例のコードの2番目の条件式の真偽はさかさまになっていることに気がついた。まあ、ご愛嬌ということだろう。)