Let's imagine I have a Groups and Users and when user wants to join a
group, I'm calling groupsService.AddUserToGroup(group, user) method.
In DDD I should do group.JoinUser(user), which looks pretty good.
Ma DDD ti incoraggia anche a utilizzare servizi (stateless) per eseguire attività, se l'attività in corso è troppo complessa o non si adatta a un modello di entità. Va bene avere servizi nel livello dominio. Ma i servizi nel livello dominio dovrebbero includere solo la logica aziendale. Le attività esterne e la logica dell'applicazione (come l'invio di una e-mail), d'altra parte, dovrebbero utilizzare il servizio di dominio nel livello dell'applicazione, in cui è possibile disporre ad esempio di un servizio (applicazione) separato.
The problem appears if I there are some validation rules for adding a
user ...
Le regole di convalida appartengono al modello di dominio! Dovrebbero essere incapsulati all'interno degli oggetti del dominio (entità ecc.).
... or some external tasks need to be started when user is added to
the group. Having these tasks will lead to the entity having external
dependencies.
Anche se non so che tipo di attività esterna stai parlando, presumo che sia qualcosa come inviare un'e-mail, ecc. Ma questo non fa realmente parte del tuo modello di dominio. Dovrebbe vivere nel livello di applicazione e rimanere lì imho. Puoi avere un servizio nel tuo livello applicativo che opera su servizi e entità di dominio per eseguire tali compiti.
But the fact that an Entity depends on some external services/classes
doesn't seem so good and "natural" to me.
È innaturale e non dovrebbe accadere. L'entità non dovrebbe sapere di cose che non sono di sua competenza. I servizi dovrebbero essere utilizzati per orchestrare le interazioni tra entità.
What's the proper way to deal with this in DDD?
Nel tuo caso, la relazione dovrebbe probabilmente essere bidirezionale. Se l'utente si unisce al gruppo o al gruppo, l'utente dipende dal tuo dominio. L'utente si unisce al gruppo? O l'utente è stato aggiunto a un gruppo? Come funziona nel tuo dominio?
Ad ogni modo, hai una relazione bidirezionale e puoi quindi determinare la quantità di gruppi a cui l'utente appartiene già all'interno dell'aggregato utente. Se si passa l'utente al gruppo o il gruppo all'utente è tecnicamente banale una volta determinata la classe responsabile.
La convalida dovrebbe quindi essere eseguita dall'entità. Il tutto è chiamato da un servizio del livello applicazione che può anche fare cose tecniche, come l'invio di email ecc.
Tuttavia, se la logica di validazione è davvero complessa, un servizio di dominio potrebbe essere una soluzione migliore. In tal caso, incapsula le regole aziendali e quindi chiamalo dal livello applicazione.