ドメインモデルでサマリー帳票を作成

日報や月報などの明細データをサマリーしたレポートを作成することは業務アプリケーションでは多い。このようなデータ集計が中心の処理をドメインモデルでどのように扱えばよいか考えてみたい。


ずは、元になるシナリオということで、目標とする帳票イメージおよび、対象のドメインモデルとデータベースを想定。

帳票は在庫サマリーとして在庫と出庫、入庫予定を商品ごとに集計して一覧表示するようなものにした。なお、在庫レベルとしてA,B,C,Dに評価する。この評価ルールはバリエーションがいろいろある。

ベースのドメインモデルはこんな感じ。普通の倉庫の在庫管理を簡略化したもの。

いつものようにドメインモデルからERを生成。DOAで作成したものとそんなにかわらないと思っている。



れから上記の帳票をどのように作成するかを考えていくわけだが、まずはトランザクションスクリプトで作成する場合はどのようにするかを考えてみる。こんな感じかな。

1.商品の一覧を取得する
2.全ての商品をループ
2.1.在庫テーブルを該当商品コードで検索し総在庫数を取得
2.2.入庫予定テーブルを該当商品コードで検索し入庫予定数を取得
2.3.出庫予定テーブルを該当商品コードで検索し入庫予定数を取得
2.4.予定在庫数を計算
2.5.品目テーブルを該当商品コードで検索し安全在庫を取得
2.6.在庫レベルを評価

もっと上手くできる方法がいくつもあると思うが、ありがちな実装としてあげてみた。



ドメインモデルではどのようにするか、まず考え付く方法として、ナイーブなOO的?に全てのデータを読み込んで行う方法が考えられる。しかし、これはデータ量が増えるとパフォーマンスがでないなどの無理が出てくる。どうにかして、1件1件の明細ではなく集約したデータを取り扱う必要がある。そこで考え付くのが、商品ごとの総在庫数、入庫予定数、出庫予定数を属性としてもつ在庫サマリークラスの導入である。総在庫数などの属性をデータベースの検索処理であかじめ導出してしまう方法にすれば、全てのデータを読み込むのではなく集約されたデータのみ取り扱うことになる。でもこれって、ドメインモデルでないじゃないかと思うかもしれないが、在庫サマリークラスの利用自体は普通のドメインモデル内で利用できるので反則技ではない。もちろん、実装にはカスタムのDataMapper(データベースからドメインモデルに変換する処理本体)で頑張る必要になる。

ちなみに、このDataMapperをカスタム化する際に商品ごとに検索して総数を取得するのではなく、商品コードのGROUPBYで1度に全ての商品の総数をもとめキャッシュするようにすればパフォーマンスを向上することもできる。上記のトランザクションスクリプトの実装よりもデータアクセス効率が良いと思うがどうだろうか?
もちろん、トランザクションスクリプトもチューニングすれば同じようなレベルにもっていけると思うが、その場合コードの複雑さはどのようになるかも合わせて考えてもらいたい。



らにもう少し応用していきたいので、在庫サマリーに日ごとの在庫予定を合わせて表示したいような要求が追加された場合のシナリオを考えてみたい。入庫・出庫を予定日を考慮する必要があるということである。
トランザクションスクリプトではこのレベルで案外複雑になってくる。少なくとも元のコードの大幅な書き直しになる。
ドメインモデルも在庫サマリーだけでは取り扱いが若干複雑になってくるので、入庫予定IN在庫サマリー・出庫予定IN在庫サマリー・在庫IN在庫サマリーなどのロールクラスを導入して責務を分解する。これで1クラスあたりの複雑さが小さくなる。(最初からこのレベルにしておくほうが良いかな)

ちなみに、入庫予定IN在庫サマリーのDataMapperで商品・予定日ごとにGROUPBY検索するようなデータアクセスの最適化ももちろん可能である。

ということで、サマリー帳票をドメインモデルで作成する場合はサマリークラスを導入しDataMapperを最適化することでパフォーマンスを保つようにする。