強い型付け vs. 強いテスト

テスト=コンパイルという考え - 個人事業主のつぶやきを見て、とりあえず私もBEST SOFTWARE WRITINGの「強い型付け vs 強いテスト」を読んでみた。
非常に示唆に飛んだ内容だった。
Thinking in JavaのBruce Eckelがこのようなエッセイを書いたことに驚いた。

チェック例外とチェックされない例外

Javaの例外にはチェック例外(検査例外)とチェックされない例外(非検査例外、実行時例外)がある。
Eckelはチェックされない例外推奨派である。
私もEckelと同じくチェックされない例外派。
理由は

  • 例外をcatchしたって何か処理することなんてほとんどない。ログ出力だって、スタックトレースがあるんだから大丈夫。
  • チェック例外が発生するメソッドのコールを追加する際に「どうせcatchしたって何もしないんだから」ということでthrows句にチェック例外を追加してしまうと・・・チェック例外を追加したメソッドをコールしている箇所は全てコンパイルエラーになる。とても耐えられない!

ということで以前に担当したプロジェクトではプロジェクト専用のチェックされない例外を用意し、デフォルトではそれを使うルールにした。
で、コントローラ層で例外をcatchしログ出力するようにした。
Seasar2のソースを見ると同じくチェックされない例外を基本にしているみたい。
Seasar2ではIOExceptionなどのチェック例外が発生した場合はそれをチェックされない例外でラップした上でthrowしなおしている。
私が担当したプロジェクトでも同じようにした。


ちなみに、Springの作者であるRod Johnsonが書いた実践J2EEシステムデザインの「4.1.8 例外処理:検査例外と実行時例外」にチェック例外とチェックされない例外のどちらを使うべきかのまとめが書いてある。
Rod Johnson自身はケースバイケースという考えのようだ。

仕様書の補完としてのRuby

Eckelは以下のように述べている。

これ(Python)は擬似コードとして使えるくらいシンプルであるだけでなく、実際に実行できてしまうという素晴らしい性質を備えている

これってすごいことではないか。
UMLの補完としてOCLてのがあるが動かせるわけではない。
#もしかして動かせる環境があるのかも知れないが私は知らない。
だったら、OCLの代わりにPythonRubyを使えばいい。いや、Ruby限定にしちゃえ!
ていうかUMLの補完というより、仕様書の補完に使えないか?
とかく仕様書はあいまいという指摘を受けることが多いが、Rubyで補完すればいいんだよ。
だって動くんだよ!これ以上あいまいさのない記述方法ってある?
だから、RSpecというのが登場したのか。
仕様書の内容をRSpecで書くことができれば、それをパスする実装を書けばいっちょあがり!
すべてこれでいけるとは思わないけど、そこそこはいけるんじゃないかなあ。

テスト中毒

Eckelはいいこと書いているね。

テストされていないものは、壊れていると思え。

その通り!


はっきり言って私はテスト中毒である。テストコードがないと非常に気持ち悪い。
テスト書いてない奴見ると、「よくコード書けるな」とある意味感心する。
昨年のことだが、Excelで客先向けのツールを作るということで初めてExcelVBAで実装した。
ExcelVBAでユニットテスト書く奴なんて滅多にいないだろうけど、そこはテスト中毒者。
当然のごとく「VBAUnitってないかなあ」と探してそのものずばりを見つけた。
おかげでストレスがたまらずに実装できた。
ちなみにここが役に立った。
ただし、ダウンロード先のリンクが切れているので注意。


私はこれまでC,Javaといった静的型付け言語で開発してきたので、Rubyにひかれつつも動的型付けに対する不安がぬぐいきれなかったのは事実。
しかし、Eckelは

プログラミング言語が静的型付けであれ、動的型付けであれ、プログラムの正しさを保証する唯一の方法は、プログラムの正しさを定義しているところのテストをすべて通すということだ。

と述べている。そして、

静的型付け言語で書かれたプログラムがコンパイルできたというのは、テストのいくつかを通ったにすぎない

とも。
そうか、そういうことなんだよな。
ということで、動的型付けに対する不安はテストで解消すればいいんだということが分かって安心した。
テスト中毒者はテスト書くのを全くいとわないんだから。
テスト中毒でよかったよ。

テスト=コンパイルという考え

id:toshiyuki_saitoさんは「テストはコンパイルの一部とみなすべきだ!という主張」と書いているけどよく読むとEckelはそういったことは書いていない。
コンパイルがテストの一部ということであって、テストがコンパイルの一部というわけではない。
でも、テストがコンパイルの一部という考えは面白い。
いっそのことテストがなければコンパイルできないようになればいいのに。
Rubyだったらテストなしで動かす場合はいきなりエラーになるとか。
でもそうなると気軽に試すことができなくなるか。
テストなしで動かしたい場合のオプションを用意すればいいかな。