« 「だるいコーディング」を駆逐した後に残る仕事 | トップページ | アプリの類型における処理テーブルの形式化 »

2015.01.03

データ指向設計・開発の実践

 経験豊かな開発者は知っているが、業務システムというものは「データの扱いに関するこまごました制約の塊」のようなところがある。したがって、データ毎のステータス遷移やそれに伴う制約を丹念に整理するとともに、それらを効果的に実装することを考えなければいけない。そのためには「アプリ指向」ではなく「データ指向」な開発方針を取り入れる必要がある。現在開発中の「受注生産システム」から「製造指示」をとりあげて説明しよう。

 まず、製造指示まわりのデータモデルを確認しよう。製造指示(JT010)を完遂させるためには、仕様明細(JT020)、工程明細(JT030)、材料明細(JT040)といった関連情報を管理する必要がある。それらのデータは、製造指示が追加される際に各種のマスターにもとづいてセットアップされる。

製造指示まわりのデータモデル
20150101_1

 製造指示のステータス(製造状況)遷移を見よう。新規登録すると「未発行」として追加され、指示書を発行すると「発行済」になる。さらに、材料出庫報告がなされると「材料出庫済」になり、完成報告で「製造完了」になる(まだあるが省略する)。ステータス毎の制約をいくつか挙げよう。

1.「材料出庫済」でないと完成報告できない
2.「製造完了」であれば、材料出荷報告できない
3.「製造完了」であれば、工程明細を変更できない

 これらの制約は、製造原価(実勢原価)を製品の在庫金額に確実に反映させるためのものだ。材料明細上には出庫時に決定される出庫単価と出庫数があって、"材料原価"の算定基礎となる。工程明細上には加工レートがあって"加工費"の算定基礎となる。完成報告した時点で、これらにもとづいて集計された製造原価が上乗せされた形で製品の在庫金額が計上される。したがって、完成報告以降のタイミングでの材料明細や工程明細の修正は制限されなければいけない(制限されつつも、完成報告した後でそれらの明細を修正するための手順も確保されている必要がある)。

 問題は、これらの込み入った制約をどのように実装するかである。ありがちなのは、関係するアプリにこれらの制約をバラバラに配置するやり方だが、これは下策である。上記のような制約は、データモデリングの段階で、テーブル毎にまとまった形で構想される。つまりそれらは「テーブルに関数従属する仕様要素」であって、本来ならばそのまとまりのまま、テーブル側に一元的に配置されるべきなのだ。

 その実践例を見よう。次の図は「製造指示テーブル」の拡張定義である「テーブルスクリプト」の一覧である。拙作の開発基盤(XEAD Driver)において、テーブルに従属するロジックはこのような形でテーブル定義に組み込まれる。

テーブル定義に含まれるスクリプト定義の一覧
20150101_2

 テーブルスクリプトは一見すると、DBMSの固有機能である「トリガー」や「ストアドプロシージャ」に似ているが、大きな違いがある。プロシージャやトリガーは、あくまでもアプリと連動する別プログラムとして動作する。いっぽうテーブルスクリプトは、アプリの実行時点でプログラム域を共用した形で統合されるゆえに、より柔軟にアプリの振舞いを制御できる。DBMSを切り替えても作り変える必要がないという利点もある。

 コーディング例を見よう。次のコードは図中の「仮想フィールドの設定」のスクリプト定義に含まれるものだ。「製造状況(ステータス)」は物理的な実体を持たない仮想フィールドで、各種の日付がブランクかどうかで値(value)が決まる。この導出ロジックをテーブル定義に組み込むだけで、製造指示テーブルを操作するすべてのアプリに適用されるのである。

////////////////////
// ステータスの設定 //
////////////////////
JT010_製造状況.value = '未発行';
if (JT010_発行日.value != '') {
  JT010_製造状況.value = '発行済';
}
if (JT010_材料出庫日.value != '') {
  JT010_製造状況.value = '材料出庫済';
}
if (JT010_製造完了日.value != '') {
  JT010_製造状況.value = '製造完了';
}

 別の例を見よう。「更新時の各種設定と妥当性検査」のスクリプト定義は次のようなコードを含む。フィールドの編集可能性や妥当性検査や省略値が設定されているのだが、特定のアプリだけに適用したい仕様なので、アプリのIDで条件付けされている。

////////////////////////////////////
// 材料出庫エントリー(JF042)での設定 //
////////////////////////////////////
if (instance.functionID == 'JF042') {

  //////////////////
  // 編集不可設定 //
  //////////////////
  JT010_製造指示数.editable = false;

  //////////////////////
  // 完成済ならばエラー //
  //////////////////////
  if (JT010_製造状況.value == '完成済') {
    JT010_製造指示№.error = '...(エラーメッセージ)';
  } else {

    ///////////////////////
    // 出庫日の初期値設定 //
    ///////////////////////
    if (JT010_出庫日.value =='') {
      JT010_出庫日.value = session.today;
    }
  }
}

 これらのコードがアプリ側ではなく、テーブル側に置かれている点にあらためて注意してほしい。これが、データの扱いに関する仕様をデータ定義そのものに組み込むという「データ指向開発」の眼目である。結果的に各アプリは「ありきたりでうすっぺらな定義要素」に退縮する。アプリの保守にもっともコストがかかることを考えれば、この開発方針の妥当性がよくわかると思う。

 データ指向開発を、このような開発基盤ではなく、JavaやRubyといったプログラミング言語を用いて実践するやり方もある。しかし対象を業務システムに限れば、私にはそれが合理的とは思えない。プログラミングに頼っていては、自由度が高すぎるゆえに開発方針を貫けない怖れがあるからだ。別の言い方をすれば、業務システムはより高級な記述様式で扱える「素朴」なソフトウエアであって、オブジェクト指向言語で扱うやり方では大げさ過ぎるからだ。その種の言語は、上述したような開発基盤を開発するためにこそ用いればよい。

 気の利いた開発基盤は、ある種の自由を制限しつつ、システムのあり方を効果的に誘導してくれる。このときの問題は「制限されている自由」の中身である。カオスをもたらすスジの悪い自由が制限されるべきで、創造性を発揮するための基礎となる自由が制限されてはいけない。

 それが成功しているかどうかは、個別に実感してもらう他にない。少なくとも私は上述の開発基盤を利用し始めてから、以前よりもゴキゲンに開発できるようになったと日々実感している。設計から実装までが「データ指向」の一気通貫で、その気分を一言で言えば「ひとりでぜんぶやれる全能感」である。オメデタイ話ではあるが、お正月ということでご容赦を。

|

« 「だるいコーディング」を駆逐した後に残る仕事 | トップページ | アプリの類型における処理テーブルの形式化 »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: データ指向設計・開発の実践:

« 「だるいコーディング」を駆逐した後に残る仕事 | トップページ | アプリの類型における処理テーブルの形式化 »