Serviceとは?
- ドメイン固有のタスクを果たす状態を持たない操作
- ユビキタス言語に従っている
- ある操作が、AggregateやValue Objectのメソッドではないと感じられるなら、それをServiceとして作るといい
Domain Serviceじゃないもの
- サービス指向アーキテクチャ
- メッセージ指向ミドルウェア
- Application Service(これはDomain Serviceのクライアントになる)
- 粒度が大きいもの (coarse-graind)
- リモート実行可能なもの (remote-capable)
- 重量級のもの (heavyweight)
- トランザクション操作を持つもの (transactional operation)
Domain Serviceであるもの
ドメイン上の重要な処理や変形操作。
すでにあるEntityやValue Objectに収まらない操作。
- 重要なビジネス上の処理を行うもの
- ドメインオブジェクトを他のドメインオブジェクトに変形するもの
- 2つ以上のドメインオブジェクトを入力に受け取って値(Value)を計算するもの
Domain Serviceの過剰使用
Domain Serviceの過剰使用はドメインモデル欠乏症(Anemic Domain Model)になる。
なぜサービスが必要なのかをよく考えること:
「このふるまいは単純にEntityに置けないか?」
もし理由が
- それがEntityの単一責務(Single Responsibility)に違反するから
- クライアントが複雑になるから
- ドメイン固有の知識がクライアントに流出するから
等なら、答えは「Serviceを作るべき」。
Entityにあるstatic methodはServiceになるフラグ。
Service実装のいろは
- ServiceはSeparated Interfaceにするといい
- インターフェイスはDomain Layerの中に定義する
- そしてたったひとつの操作を持つようにする
- 技術的な実装はInfrastructure Layerの中に作るといいかもしれない
- 実装クラス名前はその実装の特性を表現したものにする(単に-ImplやDefault-ではなく)
- 実装はユビキタス言語を明示的(explicit)に表現する!
Separated Interfaceにすべきとき、そうでもないとき
すべきとき
- Serviceに複数の実装がある(ポリモーフィックになっている)
- 技術的な実装がある(暗号化技術やInfrastructure LayerのRepositoryに依存するなど)
- Serviceのインスタンス化の方法を隠蔽したいとき
そうでもないとき
Separated Interfaceはいつも必要というわけではない。普通にクラスをDomain Layerに作るだけで十分なときもある。
- Serviceのポリモーフィックが不要なとき
- ドメイン固有の操作しか含まない場合
- Dependency InjectionやService FactoryがServiceのインスタンス化の方法を隠蔽しているとき。
もし実装クラスが、インターフェイス名に-ImplやDefault-のような接辞をつけているだけなら、それはSeparated Interfaceが不要という合図。
サービスをテストする
Serviceをどう使うかデモンストレーションになるような、模範的なテストを提供すること。