« マスターテーブルと「有効期間」 | トップページ | セット商品の原価と在庫推移 »

2012.03.04

逆方向バリデーションを自動化する

 バリデーション(入力値の妥当性検査)の仕様を「テーブルの拡張定義」とみなして、アプリではなくDB側に置く。これによってさまざまな効果がもたらされるが、その中で今回取り上げたいのは「逆方向バリデーションが自動化される」という利点だ。逆方向バリデーションはこれまで、個々の案件において場当たり的に対処されてきたグレーゾーンであった。これが自動化されることで、問題を構造的に扱えるようになる。

 まず、「逆方向バリデーション問題」の様相を確認しておこう。たとえば、(1)の商品テーブル上には「販売まるめ数」があって、受注テーブルの「受注数」はその倍数値でなければいけないとする。この場合、受注データの保守アプリにおいて、販売まるめ数が'10'である商品Aの受注数として'55'を指定するとエラーである。55は10の倍数ではないからだ。

(1)受注数は販売まるめ数の倍数であること

[商品] 商品id、商品名、販売まるめ数
+   00001 商品A  10(20に変更することを許す?)

└―…[受注] 受注id、受注日、商品id、受注数、出荷状況...
      000123 20xx/05/12 00001  50  未出荷

 では、(1)で例示したような受注データを追加した後で、商品Aの販売まるめ数を'10'から'20'に変更すべき必要が生じたらどうなるか。既存の受注データの受注数50は、20の倍数ではない。そのようなデータ状況をもたらす変更要求を、商品メンテナンスアプリは受け入れるべきか否か――これが「逆方向バリデーション問題」である。この例のように、複数のテーブルが関わるバリデーションには「正方向」だけでなく「逆方向」の側面がある。

 変更を受け入れるべきかどうかの選択肢にはいくつかある。経験上、以下のYが適切とみなされることが多いだろうとは言えるが、ケースバイケースである。

X:関連する受注の状態によらず変更は許される

Y:関連する受注の状態によって変更は許される

Z:関連する受注の状態によらず変更は許されない

 正しい仕様がいずれであるにせよ、逆方向バリデーションはこれまで、保守アプリや別途のバッチ処理に手作業で組み込まれてきた。コードの重複感や変に込み入った感じがあるうえに、少なくとも私の経験では場当たり的に対処されてきた。「よく考えたら逆方向の整合性チェックも要るよなぁ」みたいないい加減なノリでそれは組み込まれた。

 双方向バリデーションを同等に扱うために、「逆方向」の仕様検討もなんらかの形で強制されたほうがいい。それも「設計標準」あたりで注意喚起するだけでは十分ではなく、開発基盤によって強制されるべきだ。そのためにどうすればいいか。次のようなしくみを盛り込めばよい。

 まず、DOA(データ中心アプローチ)の基本テーゼである「データのカプセル化」の指針にしたがって、バリデーションルールをテーブルの仕様として組み込めるようにする。データ保守アプリの実行時にその仕様が動的に注入されることで、個々のデータがバリデートされる。上の例では、まるめ数と受注数との制約関係は「受注テーブルの仕様」として登録され、「受注メンテナンス」等のアプリにそのルールが組み込まれて検査される。ここまではわりとよく聞く話だと思う。

 さらに、データ保守アプリには、「参照元テーブル(更新対象テーブルを参照しているテーブル)」上のバリデーションルールが自動的に(動的に)注入されたらいい。「商品メンテナンス」を例とすれば、商品の参照元である受注テーブル上のバリデーションルールが組み込まれ、商品テーブルの新しいまるめ数の値に対して既存の受注データとの整合性が保たれているかどうかが検査される。

[商品] 商品id (バリデーションルール)
+        |
|        ↓注入 <正方向>
| ┌────────────┐
| │  商品メンテナンス  │
| └────────────┘
|           ↑注入 <逆方向>
|           |
└―…[受注] 受注id (バリデーションルール)

 すると何が起こるか。商品メンテナンス上でまるめ数を変更すると「既存の受注データと不整合が生じるため、まるめ数の変更は許されません」といったエラーメッセージが返る。これはアプリの動きとして正しいのかもしれないし、そうでないのかもしれない。いずれにせよ、開発者は逆方向バリデーションを意識せざるを得なくなる。そこで必要ならば、受注テーブル側のバリデーションを「受注数は販売まるめ数の倍数であること」ではなく「受注数が変更された場合、その値は販売まるめ数の倍数であること」とするといった調整を施せばよい(その場合、商品メンテナンスはまるめ数の変更を許すだろう。なぜなら受注数は変更されていないから)。最悪その調整を忘れていたとしても、不整合を引き起こす更新要求が素通りすることはない。

 注意してほしいのはこのしくみが、バリデーションルールをテーブル側の仕様として組み込んだゆえにこそ、実現可能となっている点だ。つまりバリデーションルールは、アプリから引き剥がされることで初めて、開発基盤によって「正方向」にも「逆方向」にも適用可能な操作要素になる。もしアプリ側の仕様として組み込んでしまえば、逆方向バリデーションの仕様として適宜抽出・操作することはほとんど不可能だ(注)。

 なお、逆方向バリデーションを自動化するために克服すべき課題がある。参照元がとくに多いテーブルの場合、逆方向バリデーションに時間がかかる点だ。とはいえマシンの性能は良くなるばかりだし、ロジック上も工夫の余地がある。たとえば、チェックオンリー(更新ボタンではなくEnterを押す操作)のときには逆方向バリデーションを実行させないとか、変更された項目から影響を受けるバリデーションだけを選択的に実行させるといった工夫もできる。

 拙作の開発基盤XEAD Driverでは、逆方向バリデーションが進行している間、パネルの右下に「クロスチェック中」と示されたプログレスバーが現れる(下図)。たいていは一瞬で消えてしまうので気づかれないのだが、商品テーブルに対しては参照元が20個以上関連しているため、商品保守パネルではプログレスバーの動きを視認できる。事情を知らなければ「ナンダコレハ」だろうが、この記事を読んだ方であれば「アアコレカ」と思ってもらえるだろう。「オオスゴイ」と感心されそうにないほど地味なのが悲しいのだが。

20120304

本ブログでの関連記事:
バリデーションの双方向性問題を解く

注:DBMS付随のトリガーにバリデーションが組み込まれた場合でも、同様の問題が生じる。この意味においても、開発基盤上で実装されたトリガーのほうが使い勝手が良い。参考記事:開発基盤のトリガーとDBMSのトリガー

|

« マスターテーブルと「有効期間」 | トップページ | セット商品の原価と在庫推移 »

コメント

渡辺様
受注数が「10の倍数」単位から「20の倍数」単位に変わったとして、
すでに受注した分まで「20の倍数」単位でないとダメな理由が分かりません。
来月から「20の倍数」単位で受注するとして、今月分や先月分が「20の倍数」単位でなければいけないという部分をもう少し教えてください。
例として分かりやすくするために、「何時から」という条件部分を省略したのでしょうか?

投稿: 久保田英雄 | 2012.03.05 11:45

久保田さま

この例では発効日がPKに複合されていないので、まるめ数は期間別属性ではないという前提です。まるめ数が10から20に変わるのは、商品の販売方針が実際に変わったか、あるいはまるめ数の当初の登録値が間違っていたか、などのいくつかの理由が考えられます。それが期間別属性ではないのであれば、少なくとも未出荷分については新しい(正しい)まるめ数が考慮されることになるでしょう。顧客と相談して受注数を変えなければいけない事態かもしれないし、そうでないかもしれない。答えはケースバイケースですが、少なくとも参照元テーブルのデータ状況を無視すべきではない。そういう話です。

なお、この例では関連するテーブルが「マスターとトランザクション」ですが、「マスターとマスター」とか「トランザクションとトランザクション」の例もあるでしょう。それらを一般化したうえでの問題提起としてご理解ください。

投稿: わたなべ | 2012.03.05 18:44

この記事へのコメントは終了しました。

トラックバック


この記事へのトラックバック一覧です: 逆方向バリデーションを自動化する:

« マスターテーブルと「有効期間」 | トップページ | セット商品の原価と在庫推移 »