cqrs pattern

in Architetture Software, Informatica

CQRS e Event Sourcing in C#

Reading Time: 2 minutes

Per persistere lo stato di un oggetto all’interno di un sistema, la tipica operazione che viene eseguita è quella di salvarlo all’interno di un database. Un’altra possibile soluzione è quella di utilizzare sempre un database ma invece di memorizzare lo stato, memorizzare tutti gli eventi che lo anno portato a quello stato. In pratica si memorizza la sequenza di eventi che lo hanno portato allo stato finale. Ogni singolo evento è, nella pratica, un Domain Event. In un qualsiasi momento è possibile risalire allo stato di un oggetto, estraendo la sequenza di Domain Event ricalcolando lo stato a partire dagli eventi. Apparentemente questo approccio può sembrare particolamente complicato da implementare ma consente di ottimizzare le operazioni di scrittura evitando l’introduzione di deadlock.

A differenza del modello tradizionale, non viene aggiornato un singolo record nel database (per aggiornare ad esempio il valore di una variabile) ma viene aggiunto un nuovo record con l’evento che ha introdotto il cambio di stato. In questo modo si evitano problemi di concorrenza nella scrittura e soprattutto il deadlock. Dal momento che all’interno del database vengono memorizzate solo le catene di eventi, questo approccio viene chiamato Event Store. E’ possibile implementare un Event Store custom, oppure utilizzare una soluzione esistente come questa.

Lo strato di persistenza dei dati di un Event Store non è legato ad una particolare tecnologia database, trattandosi di fatto di accodamenti dei dati. Inoltre, rappresentando l’unico punto di scrittura dei Domain Event viene garantita la transazionalità delle operazioni.

Introduzione a CQRS

Spesso, nell’approccio tradizionale dello sviluppo software viene utilizzato un unico modello dati, creando modelli univoci per l’accesso ai dati. Non sempre questo tipo di approccio può essere utilizzato e, soprattutto, è quello ottimizzato per l’applicazione. Inoltre, analizzando le performance di accesso ai dati spesso ci si rende conto che il numero di operazioni in lettura è nettamente superiore a quelle in scrittura (o viceversa).

In queste condizioni ci viene in aiuto CQRS (Command Query Responsability Segregation) che consente di separare in maniera netta le operazioni di scrittura (command) dei dati da quelle di lettura (query) su database.

L’utilizzo di due modelli separati per la lettura e la scrittura, molto spesso, consente di ottimizzare le performance e progettare in maniera specifica ogni singolo componente. Inoltre, la separazione delle funzionalità di lettura e scrittura permette utilizzare tecnologie differenti per scrivere ed accedere ai dati: ad esempio, utilizzare un database relazione per operazioni di scrittura e NOSQL per operazioni di lettura. Ovviamente, la base dati deve essere sincronizzata, utilizzando un meccanismo che potrebbe anche non essere in real-time.

La possibilità di utilizzare tecnologie differenti per operazioni di scrittura e lettura, consente di ottenere un sistema in grado di scalare in maniera molto più specifica: potrebbe essere necessario aumentare le risorse di sistema per le operazioni di lettura e diminuire le risorse per le operazioni di lettura. Utilizzando tecnologie differenti in base alle operazioni eseguite, è anche determinare e dimensionare in maniera più preciso il costo dei servizi da utilizzare.

Per le operazioni di sincronizzazione dei dati nel Domain Driven Design, utilizza i Domain Event: le operazioni di sincronizzazione devono essere analizzati in maniera precisa, perchè molto spesso viene persa la caratteristica transazionale delle operazioni. L’esecuzione di operazioni in modalità transazionale non è garantita dal momento che esistono :

  • almeno un gestore di eventi (es. RabbitMQ)
  • almeno un database (es. SqlServer)

L’utilizzo di un Event Store e di CQRS consente di creare applicazioni mantenendo separata la parte di lettura dei dati da quella della persistenza.