Getting started with JSR 303 (Bean Validation) – part 4

今回はバリデーションの使いどころを説明します。


バリデーションはアプリケーションにおいてI/Oが発生する場合は必須と言って
いいほどの処理です。


バリデーションはある条件にもとづき、値の是非を検証します。その是非を検証するための条件は大きく2種類に分類されます。


一つは静的な条件です。もう一つは、動的な条件です。


静的な条件とは主に、プログラム作成時・インスタンス生成時に条件が既知のものを指します。
動的な条件は逆にプログラム作成時・インスタンス生成時に条件が確定していない、未知のものを指します。


さて、ここでバリデーションの実装ポイントを考えて見ましょう。
たとえば、Webシステムでの住所登録アプリケーションがあります。


これは住所登録画面から入力された住所を、既に登録されているかどうかを確認し、登録されていなければ入力された住所にもとづき郵便番号を付加しデータベースに登録するというようなアプリです。


アプリの構成はページクラス、サービスクラス、永続化クラスの三つのクラスとします。この三つのクラスを住所データを保有したBeanクラス(DTO)が経由しながら最終的にデータベースに登録されます。



さて、これらのクラスのどこでバリデーションを実装したらよいのでしょう?
ある人はページクラス、ある人はサービスクラス、ある人は永続化クラス。
さまざまなパターンが考えられます。慎重を期す方はすべてのクラスで実装すべきだという意見もあるかもしれません。


実はアプリケーションのアーキテクチャとバリデーションの設計とは大きくかかわっているのです。


つまり先ほどのアプリケーションは端的に表現しますとページ・サービス・永続化の三層アーキテクチャでした。これは役割を独立化し、仕様の変更が発生しても対象の層だけ変更するといった、保守性の向上等のメリットが享受できます。


この三層アーキテクチャでは分割独立性が高くなりますが、独立性が高くなるとともに担う責務が増すというジレンマが発生します。


その担う責務というのがバリデーションなのです。つまりモジュール独立性を高めれば高めるほど、同じようなバリデーション処理が離散して行くのです。


たとえば、メソッド分割でも同じようなことが考えられます。メソッドの最初にnullチェックを記述してあるものが多々みられますがこれがバリデーション離散の代表的なものと言っていいでしょう。


nullかどうかの単純なバリデーションならばよいですが、そのバリデーション対象のオブジェクトが複数の状態を保持するということであるならば、バリデーションのロジックはモジュール分割する度に分割数に比例して増加していきます。


また、バリデーションを行うためには複数の状態をそれぞれが知っておく必要があるため、結局は分割独立を行ったとしても、バリデーションのための情報依存はのこってしまうことになります。


このようにバリデーション離散は実は保守性を下げる要因の一つなのです。
離散的とは言い換えると横断的と考える事もできます。


横断的であるならばAOPアスペクト指向)が適用できそうだと思いますが、AOPはあくまでもシステム的な共通処理を補完することであり、それぞれがもつ状態に対してアスペクトを適用する事は難しいと考えますし、適用すべきでないと思います。


ではバリデーションはどこに実装するのがよいのでしょう?


たとえば、電車での女性専用車両を考えてみましょう。私は男ですが女性専用車両へ乗ります、すると車掌や周りの女性乗客から、「ここはあなたが乗れる車両ではありません」との指摘を受けるでしょう。指摘されることもいい気はしませんし、指摘だけならよいですが、よくないことにならないとも言い切れません。


これらのことは「私は男だから女性専用車両には乗車できない」との自分自身のバリデーションを実施していれば避けられた問題なのです。
同様に、飲酒状態で車の運転をしようとした場合、「飲酒状態では車の運転はできない」との自分自身のバリデーションを行うことが、免許取り消しや交通事故を避ける方法となります。


上記のようにバリデーションを実装するポイントは状態を持っていて、かつ状態を知る事ができる自分自身が実装することが有用となります。


先ほどの住所登録アプリケーションでは状態を持っていて、かつ対象の状態を知る事ができるのはBeanクラス(DTO)となります。つまりこの住所登録アプリケーションはBeanクラス(DTO)にバリデーションを実装することが効果的と考えられます。


ここで注意しなければいけないのが状態を持っていてかつ対象の状態を知る事ができるということです。これらを満たすのは大半の場合は静的な条件となります。先の「私は男だ」、「私は飲酒状態だ」は自分で事前に知りえた情報ですのでこれらの情報は静的な条件となります。


静的な条件であるならば自分自身に実装すべきであり、それらはカプセル化にも準じることになります。


長くなりましたが、Bean(DTO)が自分自身でバリデーションを実装することがアプリケーションを構築する上で有用と述べましたが、現在、Beanのバリデーションをサポートするための仕様がJSR303(Bean Validation)で策定されています。この仕様は使いやすさ、柔軟性を意識して策定されていますので。ぜひ活用して行きたいものです。