ドメインモデル
Martin Fowlerの『Patterns of Enterprise Application Architecture 』(PofEAA)において、ドメイン層のロジックの実装パターンとして、トランザクションスクリプト、テーブルモジュールと並んで挙げられている。
テーブルモジュールは今では見かけないので、現代では「トランザクションスクリプトかドメインモデルか」で比較されることが多い。が、それぞれの定義はハッキリとはしていない。
比較に使われている論点
PofEAAのトランザクションスクリプトとドメインモデルのコード例を見ると幾つかの比較論点がある。
ロジックを実装する場所
A: SQLに書く
B: 性能に問題ない範囲ではインメモリで処理する
データソース層へのアクセス
A: ドメインロジックのどこで書くかは特に気にしない。
B: できるだけ処理の端っこに寄せる。ドメインロジックの中心部分はデータソース層に依存しないように書く
ロジックの構造化
A: しない
B: 振る舞いを構造化し、必要に応じてStrategyパターンなどを使う
これらの論点はどれもトランザクションスクリプトでもドメインモデルパターンでも選択しうるものであるにもかかわらず、PofEAAではトランザクションスクリプトのコード例は"A"で、ドメインモデルパターンのコード例では"B"で書かれているので、話がわかりづらくなっているように見える。
結局はドメインオブジェクトを作るかどうか、で区別されているように見える。
モデル
PofEAAで比較に使われている収益認識の例を元に考える。
収益認識は売上をいつ帳簿に記載するかに関するものである。コーヒーを販売した場合、コーヒーを渡し、代金を受け取り、その瞬間にお金を帳簿に記載するが、多くのケースではこれが複雑になる。例えば、一括払いの年間契約サービスの商品の場合、一年間にわたってサービス提供されるので、月ごとにその料金の1/12を計上するというやり方が考えられる。ここでは、ワードプロセッサ、データベース、スプレッドシートの三種類の製品を販売する会社を想定する。ルールに従って、ワードプロセッサの契約を結ぶとすぐにすべての収益を計上できる。スプレッドシートの場合、今日1/3、60日後に1/3、90日後に1/3を計上できる。データベースの場合、今日1/3、30日後に1/3、60日後に1/3を計上できる。
トランザクションスクリプトであろうが、ドメインモデルパターンであろうが、ドメインの存在を認識していることが暗黙の前提なので、まずドメインに存在するデータと振る舞いを書き出してみる(表記方法はドメイン記述ミニ言語に準ずる)。 code:Model
// PofEAAのコード例から忠実にデータと振る舞いを実装パラダイムに依存しない形でモデルを書き起こす
data 収益認識 = Money AND 計上日
data 契約 = 契約番号
AND 商品
AND 売上
AND 契約日
AND 収益認識[]
data 商品 = 商品名
AND 計上方法
data 計上方法 = 一括計上 OR 三分割計上
data 三分割計上 = 2回目計上日 AND 3回目計上日
data 売上 = Money
behavior とある日での収益認識総額を計算する = 契約 AND 日付 -> Money
behavior 収益認識を計算する = 契約 -> 収益認識[]
behavior 一括計上の収益認識を計算する = 契約 -> 収益認識[]
behavior 三分割計上の収益認識を計算する = 契約 AND 2回目計上日 AND 3回目計上日 -> 収益認識
本質的複雑さに関する議論
このモデルの実装を考える前に、以下のような議論がそもそもありうる。
契約が収益認識をもつ構造だが、関心事として契約と収益認識(売上計上)は別の方が認知負荷は減るのではないか?
契約が収益認識をもつ構造のせいで、とある日での収益認識総額を計算する"ために"契約"をINPUTとしているが、ある契約に関連する"収益認識"の一覧だけをINPUTにすれば計算可能なのではないか? (スタンプ結合があることを示唆)
同様に"収益認識を計算する"ために"契約"をINPUTとしているが、計上方法は"商品"だけで決まらないものが出てくるかもしれないので、素直に"計上方法"と"売上"、"契約日"をINPUTにした方が良いのではないか?