グループとユーザーがあり、ユーザーがグループに参加したいときに、groupsService.AddUserToGroup(group、user)メソッドを呼び出しているとします。DDDでは、group.JoinUser(user)を実行する必要がありますが、これは非常に適切です。
ただし、DDDでは、手元のタスクが複雑すぎる場合やエンティティモデルに適合しない場合は、(ステートレス)サービスを使用してタスクを実行することもお勧めします。ドメイン層にサービスを配置しても構いません。ただし、ドメイン層のサービスにはビジネスロジックのみを含める必要があります。一方、外部タスクとアプリケーションロジック(電子メールの送信など)では、アプリケーションレイヤーのドメインサービスを使用する必要があります。たとえば、別の(アプリケーション)サービスでラップすることができます。
ユーザーを追加するための検証ルールがある場合、問題が表示されます...
検証ルールはドメインモデルに属します!ドメインオブジェクト(エンティティなど)内にカプセル化する必要があります。
...または、ユーザーがグループに追加されたときにいくつかの外部タスクを開始する必要があります。これらのタスクを持つことにより、エンティティが外部依存関係を持つことになります。
あなたが話している外部タスクの種類はわかりませんが、それはメールの送信などのようなものだと思います。しかし、これは実際にはドメインモデルの一部ではありません。それはアプリケーション層に存在し、私見でそこに保持されるべきです。ドメイン層のサービスとエンティティを操作して、これらのタスクを実行するサービスをアプリケーション層に持つことができます。
しかし、エンティティがいくつかの外部サービス/クラスに依存しているという事実は、私にはそれほど自然で「自然」ではないようです。
それは不自然であり、起こるべきではありません。エンティティは、その責任ではないものについて知るべきではありません。エンティティの相互作用を調整するには、サービスを使用する必要があります。
DDDでこれに対処する適切な方法は何ですか?
あなたの場合、関係はおそらく双方向であるべきです。ユーザーがグループに参加するか、グループがユーザーを取得するかは、ドメインによって異なります。ユーザーはグループに参加していますか?または、ユーザーはグループに追加されますか?ドメインでどのように機能しますか?
とにかく、双方向の関係があるため、ユーザー集計内でユーザーが既に属しているグループの数を決定できます。ユーザーをグループに渡すか、グループをユーザーに渡すかは、責任のあるクラスを決定した後は技術的に簡単です。
検証は、エンティティによって実行される必要があります。全体は、電子メールの送信などの技術的なこともできるアプリケーション層のサービスから呼び出されます。
ただし、検証ロジックが本当に複雑な場合は、ドメインサービスの方が優れたソリューションになる可能性があります。その場合は、そこにビジネスルールをカプセル化し、アプリケーション層から呼び出します。