Una piccola osservazione, quindi una risposta provvisoria.
Use eventual consistency between aggregate's boundaries (before asking whose job it is)
Questa è la progettazione aggregata per definizione . Potremmo discutere se questa è una decisione buona o cattiva, ma l'aggregato in Domain-Driven Design è una "unità di coerenza". Questo non vuol dire che questo è "il modo giusto di fare le cose", solo che, quando parliamo di aggregati, questo principio è in qualche modo implicito.
If I'm not mistaken, one of DDD's reasons for being is avoiding spaghetti code, where business logic is scattered all around on, most of times, a fat service layer. Are you not scattering business logic when you use eventual consistency?
DDD non esiste per evitare il codice spaghetti, ma per fornire un modo sensato di progettare il codice in luoghi in cui si hanno frequenti evoluzioni (a causa della complessità intrinseca del dominio - il codice viene modificato perché le persone imparano - o ai domini in rapida evoluzione - codice è cambiato perché siamo in competizione con nuove idee). Tuttavia ... gli spaghetti si intromettono quando si spinge per cambiamenti frequenti. ; -)
"Scattering business logic" di per sé non è una buona o una cattiva cosa, finché non prendi in considerazione contesti limitati e scopi diversi che il software potrebbe servire. Se la logica di business appartiene a diversi contesti limitati, allora va bene se non si trova nello stesso posto. Ad esempio, in CQRS / ES, la logica di coordinamento viene spesso inserita in ProcessManager, reagendo agli eventi di dominio esterni.
Is there any other way to represent the business ubiquitous language other than having a rich domain model? Can't the language be expressed in a fatter service layer?
Un altro piccolo chiarimento è necessario: non esiste una cosa come "il linguaggio aziendale onnipresente" . Ci sono molte lingue con scopi diversi. Possono essere resi ubiquitari e coerenti solo entro i confini di un Contesto Limitato, dove saranno espressi bene ... ovunque (questa è l'ubiquità), dai Test di Accettazione alle etichette dell'interfaccia utente ai nomi dei campi del database.
La necessità di un livello di servizio più grasso spesso deriva da un'idea sbagliata di cosa sia un modello. Se il modello è principalmente comportamentale, il suo comportamento viene disaccoppiato da ciò che gli utenti devono vedere. Tuttavia, questo disaccoppiamento non è distribuito in modo uniforme: alcune parti del sistema sembreranno CRUD, mentre in altre parti la distanza tra ciò che il software sta facendo e ciò che un utente deve vedere potrebbe essere abbastanza strong da richiedere modelli distinti.
Concentrarsi su ciò che gli utenti devono vedere porta invariabilmente a modelli sovrapposti: cose con lo stesso nome che i diversi utenti usano in modi diversi. Questo perché i dati hanno lo stesso aspetto, forzando la condivisione promiscua. Quando i dati sono promiscui, il posto ovvio per mettere la logica è il livello di servizio. Ma il problema è a monte di questo.