ドメインサービスとは
値オブジェクトやエンティティのふるまいとして定義すると違和感が生じるものを別のオブジェクトとして定義するもの
ソフトウェアの文脈でのサービスとは何か
クライアントのために何かを行うオブジェクトである。
💡ドメイン駆動設計で取り沙汰されるサービスは大きく分けて2つある
- ドメインのためのサービス
- 本章で解説
- アプリケーションのためのサービス
- 6章で解説
ふるまいとして定義すると違和感(不自然さ)が生じるものとは
値オブジェクトやエンティティにふるまいとして定義して…
- 違和感のないもの
- ユーザ名に文字数制限
- ユーザ名に利用できる文字の種類の制限
- 違和感があるもの
- ユーザ名の重複の制限
- Userクラスに重複を確認するメソッドを定義すると生成したオブジェクト自身に問い合わせをすることになるのが不自然
- 重複確認のための専用のインタンスを用意する方法もユーザを表すオブジェクトなのにユーザではないという不自然さがある
不自然さを解決するためにドメインサービスを定義する
- ドメインサービスは値オブジェクトやエンティティと異なり、自身のふるまいを変更するようなインスタンス特有の状態を持たないオブジェクト。
- 重複確認のメソッドをドメインサービスに定義して使用することで、生成したオブジェクト自身に問い合わせをすることがなくなった。
ドメインサービスには値オブジェクトやエンティティに定義すると不自然なふるまいのみに限定する
- やろうと思えばユーザ名を変更する等の全てのふるまいをドメインサービスに定義できる
- するとエンティティにはゲッターとセッターだけが残ってしまう
- 無口なオブジェクトになってしまいUserクラスからどんなふるまいやルールがあるのか読み取れなくなる
- するとエンティティにはゲッターとセッターだけが残ってしまう
💡上記の状態をドメイン貧血症という
- オブジェクト指向設計のデータとふるまいをまとめるという基本戦略の真逆をいくやってはいけない行為
- ユーザ名を変更するふるまいはUserクラスに定義するべきものでドメインサービスに定義するべきではない
以上の理由から不自然なふるまいのみをドメインサービスに定義して
なるべくドメインサービスに定義するのは避けるべきである
- 迷ったらまずはエンティティや値オブジェクトに定義する
- 変更容易性を担保するためにもコードを一元的に管理することを早々に諦めてはいけない
ユーザ作成処理(例)のデータベースとのやり取りに関してはリポジトリに記述する
- ユーザ作成処理を行った場合に、作成処理のクラスとドメインサービスにデータベースとのやり取りに関して記述すると以下の問題がある
- リレーショナルデータベースからNoSQLに変更になったらユーザ作成処理の本質は変わっていないのにコードの大半は変更しなくではいけなくなる
RDB(リレーショナルデータベース)とは|NoSQLとの違いやメリットを紹介
物流システムの場合のドメインサービス
物流システムでは荷物を拠点から直接配送するのではなく
拠点→配送先近くの拠点→配送という手順を踏んでいる
- 物流拠点には出庫(Ship)と入庫(Receive)のふるまいがある - セットで取り扱われるべき活動である - 出庫していない架空の荷物を入庫はできない - 出庫したまま荷物を放置することもできない - 間違いなくセットで実行する輸送の処理を準備する必要がある - 配送の記録などの操作が全て物流拠点オブジェクトで行われるのは違和感があるし扱いづらい
輸送ドメインサービスを定義する
- 輸送という概念は特定のオブジェクトのふるまいとすると不都合のあるふるまいである
- 物流拠点ではなく輸送を行うドメインサービスとして定義する
- 配送記録などの操作を記述しても違和感がなくなった
ドメインサービスの命名規則
ドメインサービスであることがチームの共通認識になればどれでも良い。