■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2009年04月27日

    Java総合講座 - 初心者から達人へのパスポート
                  vol.150

                                セルゲイ・ランダウ
 バックナンバー: http://www.flsi.co.jp/Java_text/
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


[このメールマガジンは、画面を最大化して見てください。]


========================================================
◆ 01.SOAPのアプリケーション(Webサービス)
========================================================


「契約による設計(Design By Contract)」(あるいは「契約によるプログラミング
(Programming By Contract)」)は、Eiffel(エッフェル)というオブジェクト指向
言語の創始者であるバートランド・マイヤー(Bertrand Meyer)が、その著書「
Object-oriented Software Construction」の中で提唱した、ソフトウエアの品質および
生産性を向上するための考え方です。
ここで言う「契約」はあくまで比喩的に使っている言葉であり、我々が商取引などで
行っている本当の契約とは違います。平たく言うと、「約束ごと」と言い換えたほう
が分かりやすいでしょう。

「契約による設計(Design By Contract)」は、プログラムが仕様通りに作られてい
ることを確証するための方法として考えられたもので、クラス(のメソッド)側と
クラス(のメソッド)の呼び出し側との間の約束ごとをプログラムの中に明記する
という方法を取ります。

この約束ごととは何かというと、「あなたがこういう条件(事前条件(precondition))
に従えば、私はこういう結果(事後条件(postcondition))をもたらすことを約束しま
す。」という内容の宣言です。
噛み砕くと、「メソッドに渡す引数の値が予め決められた条件(事前条件)に従って
いれば、このメソッドは仕様通りの結果(事後条件)を返します。(逆にもし、引数の
値が、決められた条件に従っていない場合は、どんな結果を返すか保証できません。)」
ということです。

具体的にどのようにして約束ごとを明記するかというと、プログラム内にAssertion
(表明)と呼ばれるコードを入れることによって事前条件や事後条件を明記します。

実際に、
「宿泊日数(numOfNights)は1以上でなければならない。」
「宿泊人数(numOfLodgers)は1以上でなければならない。」
という事前条件をAssertionを使って明記してみましょう。

Javaでは、このAssertionは次のようなコードで表記します。

assert numOfNights >= 1;
assert numOfLodgers >= 1;

あるいは、(numOfNightsやnumOfLodgersは整数なので)上記の条件は、

assert numOfNights > 0;
assert numOfLodgers > 0;

というふうに書いても同じです。
なお、一般にassertの右側には普通の論理式を記述できるので、
上記の2行の文は、

assert numOfNights > 0 && numOfLodgers > 0;

のように1つの文にまとめてもかまいません。


そしてもし、上記の条件を守らなかった場合は、これらのassertというコードを
実行したときにAssertionErrorというエラーが発生します。


といっても、ここまでの説明だけでは、まだ何のためにAssertion(assertという
コード)を入れるのか、よく理解できないかもしれません。

というわけで、実際に簡単なプログラムを書いて、このassertの機能をテストして
みましょう。
下記のような(AssertTestというクラス名の)クラスを作成してみて下さい。

--------------------------------------------------------
public class AssertTest {

    public static void main(String[] args) {
        try {
            AssertTest test = new AssertTest();
            test.warikan(5, 0);
        } catch (AssertionError e) {
            System.out.println("Precondition failure!");
        }
    }

    public int warikan(int numOfNights, int numOfLodgers) throws AssertionError {
        assert numOfNights > 0 && numOfLodgers > 0;
        return numOfNights * 50000 / numOfLodgers;
    }

}
--------------------------------------------------------

このwarikan()というメソッドは、事前条件として引数のnumOfNightsとnumOfLodgersが
どちらも0より大(つまり、正の数)でなければならないという仕様になっています。
そして、その仕様をassertのコード、すなわち

assert numOfNights > 0 && numOfLodgers > 0;

で表明しています。

これを保管(コンパイル)してから実行してみましょう。

これを普通に実行しても、assertの機能は働きません。

実は、普通に実行すると、assertのコードが無いものとして扱われて、事前条件の
チェックは行われません。そして、そのまま

return numOfNights * 50000 / numOfLodgers;

の行まで実行されて、0で割り算をしてしまうために(0で割り算してはいけないことは
数学で習ったことと思います)例外ArithmeticExceptionが返ってきます。
このような例外が返ってくると、一見、warikan()メソッドが悪いと思ってしまうかも
しれませんが、本当はwarikan()メソッドを呼び出したmain()側が事前条件に違反して
いることが悪いのです。
このことを確証するためには、assertの機能を有効にしておく必要があります。

assertの機能を有効にするためには、実行時にオプションの

-enableassertions
または、その省略形である
-ea

を指定する必要があります。

これは、コマンド・ラインでは、

java -ea AssertTest

のように指定すればいいし、Eclipseで実行する場合は、パッケージ・エクスプロー
ラー内でAssertTest.javaを右クリック→「実行」→「構成および実行」を選択し、
「引数」タブをクリックして、「VM引数」の欄に
-enableassertions
または、
-ea
を入力してから「実行」ボタンをクリックすればいいです。

(ただし、この「構成および実行」のウインドウに設定したVM引数は、必要なくなった
ら削除しておいてください。さもなければ、あとで、普通に実行した場合(つまり、
AssertTest.javaを右クリック→「実行」→「Javaアプリケーション」を選択した
場合)にも、そのままVM引数が有効のままになってしまいます。)


こうしてassertのコードがはいっているメソッドをテストすると、事前条件が満たされ
ていない(違反している)場合には、ただちにAssertionErrorを投げてメソッドが終了
してしまいますから、要するにメソッドは実行されないことになります。
そもそもこの場合は、事前条件に違反した呼び出し側が悪いのであって、こういう
場合にはメソッドをテストしても意味がないわけなのです。こういうときにもし
assertのコードを入れておかないと(あるいはassertのコードを入れてあってもassert
の機能を有効にしていないなら)、メソッドが実行されて、おかしな結果(今回は
ArithmeticException)が返ってきて、メソッドが悪いのではないかと疑って、メソッド
を修正しようとしてしまう恐れがあります。
仕様に正しく従っている場合には、そのような修正は不要(そのメソッドが悪いの
ではなく、メソッドを呼び出している側が悪いのであり、修正すべきなのは呼び出し
側)なはずなのであり、このような修正は間違い(もしくは余計なこと)なのです。

今回は、簡単なプログラムでテストしたので、Assertionのありがたみが実感しにく
かったかもしれませんが、実際のソフトウエア開発では、はるかに複雑なプログラム
を扱うことになりますから、assertのコードを入れておかないと、こういった見極め
が困難になり、生産性を大幅に落とすことになり、ひいては品質を上げるために大変な
苦労をすることになってくるのです。


ただし、このassertのコードはテスト時のみに有効にすべきものであり、テストが
すべて完了(テストで不具合が判明したものがすべて修正されて、最終的にテスト
結果がすべて合格になったとき)になって、本番運用に入るときには、上記の
-enableassertions
または、
-ea
のオプションは外します。(このとき、プログラムには一切変更は加えません。あく
まで実行時オプションが変わるだけです。)


(次回に続く)


では、今日はここまでにします。



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      http://www.flsi.co.jp/Java_text/
★このメールマガジンは
     「まぐまぐ(http://www.mag2.com)」
 を利用して発行しています。
★バックナンバーは
      http://www.flsi.co.jp/Java_text/
 にあります。
★このメールマガジンの登録/解除は下記Webページでできます。
      http://www.mag2.com/m/0000193915.html
★このメールマガジンへの質問は下記Webページにて受け付けて
 います。わからない所がありましたら、どしどしと質問をお寄
 せください。
      http://www.flsi.co.jp/Java_text/
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Copyright (C) 2009 Future Lifestyle Inc. 不許無断複製