サービスが指し示すもの

ソフトウェア開発の文脈で語られるサービスはクライアントのために何かを行うオブジェクトのことをさすことが多い。

ドメイン駆動設計で取り上げるサービスは大きく分けて二つある

上記の区分けをしっかりとするために前者をドメインサービス、後者をアプリケーションサービスと呼ぶ。

ドメインサービスとは

値オブジェクトやエンティティなどのドメインオブジェクトにはふるまいが記述される。

例えば、ユーザー名に利用できる文字数や利用できる文字列の種類に制限がある場合は、その知識はユーザー名の値オブジェクトに記述されるべき。

だが、システムを開発する際に、値オブジェクトやエンティティに記述すると不自然になってしまうふるまいが存在する。ドメインサービスはそういった不自然さを解消するためのオブジェクト。

不自然なふるまいとは

現実世界では同姓同名は起こりえるが、システムにおいてはユーザー名の重複を許可しないということはありえる。ユーザー名を重複しないというのはドメインのルールであり、ドメインのふるまいとして定義すべきもの。ただ、このふるまいをユーザーオブジェクトのエンティティに記述すると不自然になる。

(例)重複確認のふるまいをUserクラスに追加

class User {
	private UserId $id;
	private UserName $name;
	
	public function __construct(UserId $id, UserName $name)
	{
		if (
			$id === null ||
			$name === null
		) throw new ErrorException('引数がnullです。');
	
		$this->id = $id;
		$this->name = $name;
	}
	
	public function getId()
	{
		return $this->id->getUserId();
	}

	public function exists(User $user)
	{
		// 重複を確認するコード
	}
}

上記のオブジェクトを確認した際は問題ないように見えるが、これは不自然さを生み出すコードです。実際に重複確認を行うメソッドを使ってみるとわかる

(例)重複確認を行うメソッドを利用する

$userId = new UserId(1);
$userName = new UserName('takumi');
$user = new User($userId, $userName);

// 生成したオブジェクト自身に問い合わせることになる
$duplicateCheckResult = $user->exists($user);

重複を確認する振る舞いはUserクラスに定義されているので重複の有無を自身に対して問い合わせる必要がある。これは多くの開発者を悩ませる不自然のコード。自身が重複しているかの結果が真なのか偽なのかどちらを返せばいいのかわからない。