Sono io CQRS?

Decisamente l’acronimo CQRS ultimamente è una delle buzzwords più in voga del momento e talvolta ci si scatenano dietro guerre di religione. In sostanza si parla di CQRS quando noi utilizziamo due modelli differenti, uno dedicato alla modifica dei dati (la parte di Commanding) ed uno dedicato alla lettura dei dati (la parte di query).

Di base CQRS non è nemmeno un pattern, ma piuttosto una organizzazione architetturale che può essere declinata in tanti modi differenti, soprattutto in base alle necessità del progetto corrente (leggi requisiti). Approcciare un problema direttamente con CQRS+EVENT SOURCING+BLABLABLA senza che effettivamente ci sia necessità è la strada migliore per “farsi male”, piuttosto è necessario capire perché nasce CQRS, che problemi risolve e come posso declinarlo in strutture esistenti ed in nuovi progetti.

Se si lavora con NHibernate e si cerca di realizzare un Domain Model prima o poi ci si scontrerà sicuramente con un aumentata complessità dei nostri modelli, cosa che ci porta ad avere domini troppo anemici per soddisfare la necessità di fare delle particolari query, oppure faticare molto nell’esprimere le query tramite il nostro ORM preferito. Il sintomo tipico è, iniziare a scervellarsi su una nuova query perché il modello non è adatto a soddisfare una nuova interrogazione che si rende necessaria perché è stata introdotta una nuova UI utente che deve mostrare XYZ all’utente. Uno dei problemi in questi scenari è LINQ, perchè se da una parte sembra la manna dal cielo, perchè permette di esprimere Query sul nostro modello, in realtà potrebbe essere considerato il male allo stato puro, perchè vi costringe a modellare il dominio affinché sia interrogabile. Il rischio insito di LINQ è quello infatti di avere domini fortemente anemici e che comunque debbono esporre molto del loro stato Affinché possano essere interrogati.

Se vi ritrovate in questi problemi allora molto probabilmente CQRS fa per voi, vediamo quindi come poterlo implementare in maniera semplice, forse impropria, ma per ottenere dei vantaggi senza dover sconvolgere architetture precedenti.

Se nel nostro programma usiamo ad esempio NHibernate per persistere i nostri oggetti di dominio o EF, è possibile fare delle semplici VIEW affinché sia possibile avere delle visualizzazione in sola lettura dei dati che interessano. Si fa una VIEW per ogni UI o in generale per ogni formato di dato che volete mostrare all’utente e questo permette di avere flessibilità di design nel proprio dominio, dato che non deve più essere usato per “leggere” dati. Potete ora mettere tutte le proprietà private, (tanto le letture vengono fatte con un datareader su una VIEW :)). Se usate un Db NoSql come RavenDb o Mongo potete sempre creare degli indici che vi permetteranno di avere visioni differenti sulle vostre entità. Dove non arrivate con una view potete usare una stored, la cosa importante è la separazione tra operazioni che modificano lo stato (fatte con il dominio) e lettura dei dati (fatte attraverso il QueryModel, ovvero viste e stored). I vantaggi di questo approccio sono

  • è semplice, non vi richiede di introdurre nulla di complesso
  • I QueryModel sono sempre sincroni, ovvero quando eseguite un comando subito tutti QueryModel sono aggiornati

D’altra parte questa struttura non è completamente flessibile perché esiste un forte accoppiamento tra lo stato delle classi di dominio ed i QueryModel. Questo comporta che ogni volta che un oggetto di dominio viene rifattorizzato rischiate di riscrivere View e Stored che lo usano, però comunque le modifiche si fermerebbero li.

Di base però questo approccio è comunque CQRS e vi porterà molti vantaggi, primo tra tutti la semplificazione del codice, dato che solamente le chiamate verso il WriteModel utilizzeranno ORM, Validatori, etc etc, mentre tutte le chiamate al QueryModel saranno molto semplici. Un vantaggio tra tutti? Praticamente la scomparsa dei Dto, se avete Sql Server, una volta create viste e stored potete tranquillamente usare un Dataset che vi fate generare dal designer ed utilizzare tutte le funzionalità di binding della vostra UI. Se usate NHibernate in un progetto WPF non avete più il problema di capire “quanto a lungo deve vivere una ISession” e i problemi del lazy load usato durante il binding, semplicemente la ISession viene usata solamente quando si esegue un Comando e vive per la durata dell’esecuzione del comando stesso, per tutto il resto potete leggere con una normale SqlConnection.

Se poi un purista dice che questo non è CQRS, possiamo chiamarlo in altro modo, il concetto è che usare più modelli per soddisfare esigenze differenti (Oggetti per le modifiche e Viste e stored per le letture) è spesso un approccio vincente, poi lo possiamo chiamare come ci pare :).

Gian Maria.

Comments are closed.