Commands return Domain Models, and Queries return DTOs.
In realtà, i comandi dovrebbero produrre effetti collaterali e idealmente non restituire nulla (che in alcuni casi non è pratico). Le query non dovrebbero avere effetti collaterali e restituire alcuni dati. Questo è tutto prima che i DTO inseriscano l'immagine.
Le DTO vengono quindi introdotte essenzialmente per "raggruppare le chiamate remote multiple in una singola chiamata" per motivi di prestazioni ( vedi il post di Fowler ). Una struttura di oggetti relativamente complessa viene appiattita in un singolo oggetto serializzato per il trasferimento. Ciò significa che i DTO sono ciò che ottiene passato al codice dell'infrastruttura che implementa i comandi e le query al limite dell'applicazione. Ora, per controllare le dipendenze tra i livelli, è importante sapere quale layer possiede cosa (non dove gli oggetti sono memorizzati , ma quale layer definisce e ha ownership di tipi specifici). Lo stesso vale per i DTO. Quindi, qualunque sia il livello più esterno (pur essendo logicamente parte della vostra applicazione), e sta chiamando (e quindi dipende direttamente) sulle librerie / framework usati per accedere alla risorsa remota, sarà quello che possiede i DTO.
P.S. A proposito, notare che l'idea alla base di CQRS è quella di rappresentare il dominio in due modi diversi basati sui modelli di accesso, cioè di avere due modelli di dominio - un modello di query e un modello di comando. E questi faranno uso di diversi set di DTO. Ma in entrambi i casi, un layer esterno, proprietario di DTO, riceverà una richiesta (comando o query) da un livello interno (livello superiore), insieme a qualche input (forse un oggetto dominio, forse solo un semplice set di parametri). In caso di query, sebbene inizialmente si traducano in DTO, il codice nel livello interno che ha invocato la query non otterrà i dati come DTO (perché non "vede" i tipi di DTO); invece, nello scenario più generale, il livello esterno tradurrà i DTO in oggetti di dominio e li restituirà.
Salvo tutto ciò che è veramente necessario è mostrare i dati sullo schermo, nel qual caso il livello esterno può bypassare quelli interni e andare direttamente al componente di presentazione ( che può fare senza violare la struttura delle dipendenze, se accade all'interno dello stesso "anello" - un livello visto in architettura pulita / a cipolla / esagonale). In effetti, la vista stessa può ignorare anche i livelli più interni durante l'emissione della query. E puoi eliminare completamente il modello di query se non c'è abbastanza comportamento utile da garantirne uno. Ciò che rimane può essere un componente che gestisce la responsabilità dell'interrogazione, ma non è un modello completo rappresentato da un numero di oggetti interagenti. Ciò consente quindi di ridurre la quantità di traduzioni da DTO a altre rappresentazioni o di evitarle completamente. Quindi ottieni questa immagine:
P.P.S.Giustoperridurreilpotenzialediconfusione:
IDTOsono,insensostretto,sullechiamateremote.Tuttavia,avoltelepersoneusanounapprocciosimilequandotrasmettonodatilocalmente,tralivelli,echiamanoquestiDTO(cheèdiscutibilmentediscutibiledelsignificatodeltermine),maquestapraticadovrebbeessereusataconparsimoniaebuonagiustificazione,comescrivereemantenereilcodiceciòchesitraducetralerappresentazionièundolore.Vedi questo articolo per maggiori informazioni. Nello stesso articolo, Martin Fowler fornisce un esempio di uno scenario in cui vale la pena considerare questo approccio (concentrarsi maggiormente su perché e meno sul dove):
One case where it is useful to use something like a DTO [in a local context] is when you have a significant mismatch between the model in your presentation layer and the underlying domain model. In this case it makes sense to make presentation specific facade/gateway that maps from the domain model and presents an interface that's convenient for the presentation.