Dove si inseriscono queste query in una buona architettura?

Aug 17 2020

Ho pensato a un problema per un po 'e non mi sento davvero di aver capito come affrontarlo.

Sto cercando di lavorare con DDD il più possibile, ma alcuni scenari di presentazione non si adattano perfettamente a questo in termini di prestazioni.

Diciamo che abbiamo un sistema per le auto a noleggio, e lì abbiamo una vista che dovrebbe mostrare tutte le auto e il numero di volte in cui sono state noleggiate.

In un mondo DDD immagino che avrei un deposito per le mie auto a noleggio e un deposito per i "noleggi". Immagino anche che potrebbe esserci un servizio che gestisce l'interazione tra di loro, la creazione di accordi, ecc.

Ma quando si tratta di presentare la vista con le auto a noleggio e il numero di noleggi, non sono davvero sicuro di dove metterlo. Poiché i requisiti sono molto specifici per questa vista, immagino che la versione più performante sarebbe quella di avere una sorta di oggetto "RentalCarsOverview" restituito dal repository. Ma questo "inquinerebbe" i repository con query molto specifiche per la vista.

Quindi mi chiedo se qualcuno ha affrontato gli stessi problemi e come è stato risolto? Ho esaminato CQRS per separare questo, utilizzando query per questo tipo di visualizzazioni e il mio modello di dominio per gli aggiornamenti. è un buon approccio?

Inoltre, sarebbe "ok" avere solo SQL grezzo in questi gestori di query o si astratterebbero anche questi con un repository sottostante?

Risposte

3 VoiceOfUnreason Aug 17 2020 at 19:44

Al giorno d'oggi, la solita risposta è che i percorsi del codice della tua query aggireranno il "modello di dominio" e funzioneranno direttamente con le copie delle tue informazioni.

L'argomento qui è che una query non modifica le informazioni memorizzate nel modello di dominio, e quindi non beneficiamo di una serie di cerimonie che inseriscono tali informazioni in oggetti di dominio solo per rimuoverle di nuovo.

Ad esempio, se tutte le tue informazioni sono archiviate nello stesso database relazionale, è molto probabile che tu interroghi il database e trasformi le informazioni nei set di risultati nella forma corretta e le rispedisca al client.

Quando le informazioni necessarie per rispondere alla query sono distribuite su più sistemi, allora c'è più lavoro su misura per generare il report. Quando il tempo necessario per generare il rapporto supera i tuoi obiettivi di latenza, allora inizi a esaminare i progetti in cui puoi memorizzare nella cache le parti costose del rapporto. In alcuni casi, ciò significa che l'intero rapporto viene memorizzato nella cache.

2 RikD Aug 17 2020 at 17:07

CQRS e DDD sono una combinazione perfetta.

I comandi passano attraverso i tuoi repository e i modelli DDD. Le query possono essere SQL non elaborate o un ORM leggero, con modelli separati specifici per ciascuna vista.

L'architettura del tuo sistema in questo modo ti offre un modo solido per gestire regole aziendali complesse, con le migliori prestazioni possibili per le letture.

2 CarmineIngaldi Aug 17 2020 at 19:38

Cominciamo a sottolineare che avere query intelligenti è un odore di codice DDD. La maggior parte delle volte, tutto ciò che devi fare è farlo

  • recupera un aggregato in base al suo ID (parlando RESTful: GET /users/xyz)
  • recuperare tutti gli aggregati con una data radice ( /users?page=0&limit=10)
  • recuperare un sottoinsieme di aggregati con un semplice filtro (parlando RESTful: GET /users?username_startsWith=johnd&page=0&limit=10 )

Le applicazioni complesse devono fare cose complesse, chiare, quindi potresti finire per dover costruire proiezioni dal tuo aggregato. Ovviamente, il tuo aggregato non dovrebbe avere la minima idea di cosa sia una proiezione, ma lì puoi trovare tutti i dati necessari per costruirli, perché stai progettando il tuo dominio non solo per essere costantemente mutato, ma anche per essere osservato

Questo è un approccio ragionevole anche senza introdurre concetti CQRS. La maggior parte delle nostre applicazioni sono applicazioni CRUD + alcune regole di convalida del dominio. Se incontri parole come " panoramica " " report " " statistiche " " sommario " " cronologia " solo poche volte in requisiti/storie/codice, sai che puoi gestirle semplicemente caricando aggregati in memoria tramite query specifiche, chiamando alcune aggregazioni metodo (conteggi, somme, medie) e fare la mappatura rispetto a qualche proiezione DTO

Quando i suddetti casi sono importanti nel tuo progetto, quando il caricamento di aggregati per recuperare solo alcune informazioni di aggregazione è un enorme onere per il tuo sistema, quindi sì, stai incontrando uno dei due casi d'uso in cui CQRS è utile

Fornirai al tuo aggregato (vale a dire, l'aggregato lato scrittura) la possibilità di attivare eventi di dominio ogni volta che è stata commessa una notevole mutazione di stato

Costruirai un modulo diverso in cui avrai repository e gestori di eventi specifici per la proiezione (nel tuo caso qualcosa come onEvent(CarRentedOutEvt evt) ) per aggiornare e salvare le tue proiezioni.

Avrai (di nuovo in modo riposante) un'API di amministrazione GET /rents/overview che si comporterà in modo molto stupido. Tutta la complessità viene scaricata al momento dell'aggiornamento

Merrion Sep 08 2020 at 17:48

È consentito avere più di un modello di lettura e, in questo caso, un modello di lettura "Reporting" denormalizzato che sottoscrive solo gli eventi necessari per aggiornarsi quando riceve un evento "affittato".