ひがやすを技術ブログ

電通国際情報サービスのプログラマ

Separation of Hotspotその2

リッチなドメインモデルのアンチパターンの1つとして、「ホットスポットを考慮せずに関連のあるデータと振る舞いを1つのクラスに詰め込んだもの」があります。
このパターンは、変更による影響を受けやすいので、変更の多いシステムには、向いていません。逆に変更のほとんど無いシステムなら、これで十分(最善かどうかは今回のテーマではないので言及しません)だと思います。
これに対する改善案として、

  1. ホットスポットをStrategyパターンで切り替えられるようにする。
  2. ホットスポットアスペクトで組み込む。
  3. ホットスポットを別のLogicクラスに切り出す。ドメインオブジェクトには、ホットスポットは存在しない。

などが考えられます。
1,2は、利用者側から見た場合、これまでのドメインモデルと同じように見えます。3は、ホットスポットが完全にドメインオブジェクトから切り離されているためpoorなモデルに見えるかもしれません。
ホットスポットの実装という点では、1,2,3ともあまり変わりません。別のホットスポットを実装したクラスから、ドメインオブジェクトの公開されたメソッドを通じて処理を行うからです。利用者側の使い方は異なりますけど。
1は、PofEAAでも出てくる方法ですが、StrategyオブジェクトをDIする方式が現状確立されていません。ドメインオブジェクトを作成するのは、今のところO/Rマッパーの役割であることが多いと思いますが、O/Rマッパーが作成するオブジェクトにDIするための有力な方式は、今のところ無いためです。手作りはかなり大変。実装が大変なので、実際には、最初からすべてのユーザの要件に関するメソッドをStrategyにすることはせず、変更があったときにはじめて、Strategyにするという方法もありますが、OCPに違反してしまいます。
ちなみに、PofEAAに出てくるStrategyパターンを使ったドメインモデルのメリットですが、Strategyパターンだったら別にトランザクションスクリプトでも使えるジャンと思ったり。
2は、アスペクトを静的に組み込む、あるいは、クラスのロード時に組み込む方式のAOPなら、今でも十分に可能ですが、アドバイスホットスポットを実装するときに、引数や戻り値の型が失われてしまうのと、ぱっとみ何が起きているのか分からないのと、テストがしにくいのが難点です。
3は、現状のDIの仕組みを使えば簡単に実現できます。問題は、カプセル化が壊れたように見えること。でも、これまで、エンティティというクラスだけだったのが、エンティティ + エンティティロジックの2つをセットで用いるようにするんですよというのが、カプセル化を壊すことになるのかどうか、この辺は、好みに左右される部分が大きいと思います。ただ、1,2はカプセル化にこだわるあまり、実装をかなり難しくしている気がします。
3は、ファウラーのパターンには当てはまりにくいと思いますが、あえて言うならテーブルモジュールかな。
確定ではないのですが、1のためのDIをKuinaでサポートする予定。ドメインオブジェクトに対するアスペクトも。
私は、ドメインモデルがすべてのシステムにおいて向かないとは思っていません。向いているシステムはもちろんありますが、要員などの問題により適用しにくいとアーキテクト的な立場からは思っています。ただし、この問題は、今回のテーマとは異なるので、この辺で止めときます。