勉強日記

チラ裏

PoEAA ch9 Domain Model

martinfowler.com


An object model of the domain that incorporates both behavior and data.

  • ビジネスロジックは非常に複雑になりうる
  • オブジェクトのネットワークでこれを表現する
    • 各オブジェクトが意味のある「個」を表現する
      • 大きいものでは「企業」から
      • 小さいものでは「注文」まで

How It Works

  • オブジェクトでビジネス領域をモデリングドメイン層をつくる
    • ビジネス領域のデータを模す
    • ビジネスルールをとらえる
    • データと処理とを組み合わせる
  • DBのスキーマと似ることがしばしば
  • とはいえ違いも多い
    • 「一対多」の集約
    • 関連のネットワーク
    • 継承
  • Domain Modelの2つのスタイル
    • シンプル
      • DBのスキーマに似てる
      • Active Recordを採用してもいい
        • Domain Modelオブジェクトにpersistメソッドとかが生えてるやつ
    • リッチ
      • DBのスキーマとは異なる見た目になる
      • OOらしいことする
        • 継承
        • Strategy Pattern
        • ほかGoFのやついろいろ
        • 小さなオブジェクトを相互に結合させネットワークを形成する
      • 複雑なドメインロジックを表現できる
      • DBとのマッピングが大変
        • データソース層にはData Mapperが必要
  • ビジネスロジックはしょっちゅう変わる
  • ドメイン層で大事なこと
    • 変更容易性
      • 【補】依存性を反転させると、実装クラスを変更しても呼び出し側が壊れない
      • 【補】リスコフの置換原則に基づいて、実装クラスをすげ替えられる
    • ビルド容易性
      • 【補】インタフェースに依存させ、実装クラスを分離することで、呼び出し側の再コンパイルを回避する
    • テスト容易性
      • 【補】インタフェースに依存させ、モックをDIして単体テストする
  • 他層との結合を最小に(疎結合に)
  • 最も単純な系: ユーザが1人だけのアプリケーション
    • オブジェクトグラフを単一のファイルから読み出して、全部メモリに載せることができる
      • 【補】エッジとかノードとかの「グラフ」
    • デスクトップアプリケーションならこれでいい
  • 多層アーキテクチャのIS(?)アプリケーションではそうはいかない
    • 【推測】inter system もしくは inter serverかな
    • オブジェクト多すぎ
    • すべてのオブジェクトをメモリに載せるわけにはいかない
      • メモリ消費しすぎる
      • 時間かかる
  • OOデータベースが輝くところ
    • オブジェクトをメモリとディスクの間で直接的にやりとりできる
  • OOデータベースを使わない場合、メモリ-ディスク間のオブジェクトのやりとりを自前で取り回さないといけない
    • セッションに絡む、必要なオブジェクトグラフを読み出す
  • サーバ間で同一のオブジェクトグラフが必要な場合
    • サーバのステートをどこかに保存する必要がある
  • ドメインオブジェクト肥大化問題について
    • 特定のユースケース固有の振る舞いの責務は誰が持つ
      • Domain Model?
      • もっと上の層?(usage-specific class)
  • usage-specific classの問題点
    • コードの多重化を引き起こしやすい
      • Domain Modelから離れた場所に実装されるので、すでにあるものを見つけづらい
    • 多重化したが最後
      • 複雑化
      • 一貫性を失う
  • Domain Modelの肥大化のほうがマシ
    • 肥大化自体そうそう起きない
    • 起きたとして、コードの多重化よりも見つけやすく修正しやすい
  • usage-specific classは切り出さないほうがいい
    • それでDomain Modelが肥大化してしまったら、そのとき考えれば良い

Java Implementation

  • J2EEでDomain Modelを開発するとなると、議論は白熱する
  • J2EEの入門本「Entity Beans使え」
  • バージョン2.0時点では問題がある
  • リッチなDomain Modelを作る上で大きな制約がある
    • CMP: Container Managed Persistenceの制限
      • 簡素なO/Rマッパー
      • Entity Beansは、CMPと一緒に使うと力を発揮する
      • リッチなDomain Modelを作るのはきつい
    • Entity Beansはre-entrantであるべきではない
      • 【補】循環参照のこと
      • OOPのアドバンテージ損なう
        • 【補】Strategy Patternとか書く時困るよね
  • Domain ModelでEntity Beansを使用する場合はローカルインタフェース使え
    • Domain Modelを作る上ではfine-grainedなインタフェースが要請される
    • Entity Beansはリモートアクセス可能
    • fine-grainedなインタフェースでリモートアクセスすると深刻なパフォーマンス劣化をもたらしうる
  • ビルドやテストに時間がかかる・テスト大変
    • コンテナとDBを接続する必要があるため
  • じゃあどうする
  • POJO: Plain Old Java ObjectをEJBコンテナでくるむ
    • 「普通のオブジェクト」
    • 利点
      • POJOで作ったDomain Modelは組み合わせやすい
      • ビルド速い
      • EJBコンテナから切り離して実行・テストできる
      • EJB非依存
        • (だからベンダは使ってほしくないだろう)
        • Domain Modelについて考えるときにEJBを考慮に入れたくない
  • ドメインロジックの複雑性がほどほどならEntity Beansでうまくいくだろう
    • 1 beanクラス1テーブルくらいの単純さ
  • 複雑ならPOJO + Data Mapper使え
    • OOPのパターンをいろいろ使ったリッチなDomain Modelが必要

When to Use It

  • ドメインロジックが複雑なとき
    • ビジネスルールが絶えず変化する
      • バリデーション
      • 計算
      • 導出
        • 【補】導出: 面積=幅x高さ とかそういうやつ
    • 「nullチェックと総和計算」程度ならTransaction Scriptがいいだろう
  • チームがOOPにどれくらい慣れ親しんでいるかも重要
    • 一度慣れればTransaction Scriptに戻りたくなくなる
  • 著者はドメイン層にDomain Modelを採用したら、データソース層にはまずData Mapperを検討する
  • Service Layerを追加することで別個のAPIをもたせることもできる
    • しないこともできる

Further Reading

  • OO設計
    • Larman
  • Domain Modelの例
    • Fowler AP
    • Hay
  • conceptual thinking about objects
    • Martin and Odell
  • デザパタ
  • DDD
    • Evans

Example: Revenue Recognition (Java)

  • コード略(pp.120-123)
  • Strategy Patternとか使って条件分岐自体をなくせるよ
  • 新しい収益認識方法が追加されたら、同じインタフェースをもつ新しいクラスを追加するだけでいい