DDDにおける「サービス」とは結局なんなのかの疑問に答える

## これは何

DDDを勉強したことがある方は、以下の二つの概念を聞いたことがある人が多いと思います。

- ドメインサービス
- アプリケーションサービス

これらの役割について語られることは多いですが、「サービス」という共通する名前がついている理由については語られることは多くありません。
これらの共通の概念についている「サービス」という言葉について説明していきます。

## DDDとは
DDDとは「ドメイン駆動設計」の略称であり、「特定の世界における手続きや概念をドメインモデルとして定義し、そのモデルを用いてアプリケーションを構築する」アプローチです。
DDDについてより詳しく知りたい方は、↓をご一読ください。

https://qiita.com/little_hand_s/items/721afcbc555444663247

## ドメインサービスについて
ドメインサービスとは以下のような特徴を持つオブジェクトのことを指します。

- ドメイン層に基づくビジネスロジックを記述する
- 特定のドメインオブジェクトに属さないビジネスロジックを記述する

ドメインサービスが活用できる例として、以下のようなドメインのモデル設計を考えます。

- エンティティとしてユーザーと銀行口座が定義されている
- 銀行口座には貯金額が記録されている
- ユーザーは口座に入っているお金を送金し合うことができる

これを単純にドメインオブジェクトとして定義してみます。
今回は↓のようなモデル設計をしてみました。

```plantuml
class User {
  getAccount()
}

class Account {
  money()
}

User - Account
```

ここで、「ユーザーは口座に入っているお金を送金し合うことができる」という処理をどうモデリングするか考えます。
送金はユーザーが行うのでしょうか？それなら`User`に`sendMoney()`のようなメソッドを実装すれば良さそうですが、ユーザーはお金自体の送金処理を行うはずはないので、違和感があります。
では、続いて口座にメソッドを実装することを考えます。「口座がお金を送金する」というのもなんだか実態には則していない処理に感じます。

このような場合にドメインサービスは使えます。
ドメインサービスはドメイン層に基づく処理をかける一方で、特定のドメインオブジェクトに属さないビジネスロジックを記述できるため、このようにモデル設計をしてみます。

```plantuml
class User {
  getAccount()
}

class Account {
  money()
}

class AccountService {
  sendMoney(sendAccount, receiveAccount, amount)
}

User - Account
```

このように、ドメインサービスを活用することでモデル設計がうまくできました。

## アプリケーションサービスについて
続いてアプリケーションサービスについて説明します。
アプリケーションサービスは以下のような特徴を持つオブジェクトのことを指します。

- アプリケーション層に基づくユースケースを記述する
- ドメイン知識に基づかない、アプリケーション特有の処理を記述する

ドメインサービスと同じく、アプリケーションサービスを利用する例として、以下のようなユースケースの実現を行います。
なお、今回は前項に記載したドメイン知識を元に例を作りました。

ドメイン知識

- エンティティとしてユーザーと銀行口座が定義されている
- 銀行口座には貯金額が記録されている
- ユーザーは口座に入っているお金を送金し合うことができる

ユースケース

- ユーザーが口座のお金を送金したとき、送金元のユーザーと送金先のユーザーには決済完了のメールが送られる

このようなユースケースの設計を考えます。
今回はメール送信という、アプリケーション特有の処理を実装する必要があるため、アプリケーションサービスを実装します。
メールの送信処理は`call`メソッド内に記述します。


```plantuml
class User {
  getAccount()
}

class Account {
  money()
}

class AccountService {
  sendMoney(sendAccount, receiveAccount, amount)
}

User - Account

class SendMoneyService {
  call(sendAccount, receiveAccount, amount)
}
```

このようにすることで、アプリケーション特有の処理も、ドメイン層に介入せずに実装することができました。



## ドメインサービスとアプリケーションサービスの共通点
ここまででドメインサービスとアプリケーションサービスについて説明してきました。ここから本題に
写っていきたいと思います。


ドメインサービスとアプリケーションサービスはそれぞれ以下のように定義しました。

- ドメインサービス
    - ドメイン層に基づくビジネスロジックを記述する
    - 特定のドメインオブジェクトに属さないビジネスロジックを記述する
- アプリケーションサービス
    - アプリケーション層に基づくユースケースを記述する
    - ドメイン知識に基づかない、アプリケーション特有の処理を記述する

ここで改めて、DDDとはなんなのかについておさらいします。
DDDとは「特定の世界における手続きや概念をドメインモデルとして定義し、そのモデルを用いてアプリケーションを構築する」アプローチです。
つまり、DDDにおけるドメイン層は常に「AがBに〇〇する」というような処理になります。
それは世の中の変化は複数の概念のやりとりか、自己完結によって生じるためです。
ドメインサービスの例としてあげた送金処理は、現実世界では厳密にいうと、銀行員のような他の役割の人がおり、その人がユーザーから送金依頼をもらい、口座からお金を引き出し、送金先のユーザーの口座にお金を入れる、というような処理が行われるはずです。しかしここまで局所的な役割のドメインまでモデル化すると、逆に複雑性が増してしまい、ドメイン知識が膨大な量になってしまいます。
そのため、DDDでは一個の概念として「ドメインサービス」として、リアルの世界の細かいドメイン知識を丸める処理を行います。
アプリケーションサービスも同じような考え方です。アプリケーションにおけるユースケースの処理は一体誰が行っているのでしょうか？それは言葉で表現するならばアプリケーションを開発している組織であり、運営かもしれません。しかしそれをコードとして表現するのは難しいため、「アプリケーションサービス」という形で、運営の存在を丸めています。

## 結局サービスって何
ドメインサービスも、アプリケーションサービスも、現実世界のドメインを丸めているものでした。
つまり、「概念としては存在しているが、実態のないもの」に対してDDDでは「サービス」という名前を使います。

## 最後に
最後までお読みいただきありがとうございました。
Devトークも公開しているので、もし直接話してみたい、と感じていただけた方はぜひDevトークの方も「話したい」を押していただけると嬉しいです！

https://jobs.qiita.com/employers/qiita-inc/dev_talks/27