In questo articolo presentiamo una panoramica introduttiva all’argomento CQRS. Il pattern architetturale Command Query Responsibility Segregation (CQRS), di cui sempre più si stanno apprezzando i vantaggi e le possibilità. CQRS parte da un’idea apparentemente semplice, ma è capace di profondo impatto sul modo in cui progettiamo e sviluppiamo le nostre applicazioni. Cominciamo con una introduzione panoramica su CQRS, per poi dedicarci nei prossimi numeri alla concretizzazione nel modo Java.
Introduzione
Command Query Responsibility Segregation (CQRS) è un pattern concettualmente molto semplice, ma che può condurre verso profondi e interessanti sviluppi nel design di sistemi informativi. In questo primo articolo verranno spiegati i concetti fondamentali, senza alcun riferimento a una tecnologia particolare (a differenza dei prossimi articoli, in cui si concretizzeranno i concetti teorici relativamente al mondo Java).
Una nuova idea di web application
L’idea tradizionale che le persone (siano essi utilizzatori finali o progettisti o sviluppatori) hanno di web application è quello di considerarla sostanzialmente come un datastore CRUD. Lo schema mentale è quello di una struttura di record in cui è possibile crearli, leggerli, aggiornarli ed eliminarli (Create, Read, Update, Delete). Nel caso più semplice quindi, le interazioni sono tutte di memorizzazione e recupero di record.
Mano a mano che i business requirements di un progetto diventano sempre più sofisticati, ci si allontana progressivamente da tale modello. Spesso si ha la necessità di mostrare i dati in maniera diversa dalla semplice struttura prevista per i record, per esempio raggruppare più record in uno solo oppure creare record virtuali combinando dati provenienti da fonti diverse. Per quanto riguarda l’update, invece, spesso è necessario introdurre delle regole di validazione che consentono di salvare solo determinate combinazioni di dati oppure dedurre quelli da salvare da quelli visualizzati (che possono essere diversi). Quando si presentano questi casi ci si trova di fronte a rappresentazioni multiple delle stesse informazioni.
Gli utenti quindi interagiscono con diversi modi di presentare le informazioni del sistema, mentre invece gli analisti/sviluppatori costruiscono il proprio modello concettuale (Domain Model) che descrive le varie entità che fanno parte di un sistema e le relazioni che intercorrono fra di loro. E normalmente anche la parte di persistenza si avvicina quanto più possibile al modello concettuale.
Figura 1 – Lo schema descrittivo di una applicazione web 3-tier basata su un’architettura “classica” CRUD.
Una struttura avente strati multipli di presentazione dei dati può sembrare piuttosto complicata, ma a livello più basso esiste comunque una singola rappresentazione concettuale che funge da punto di integrazione fra tutte le diverse presentazioni.
Un paradigma diverso: separare aggiornamento e visualizzazione
L’architettura presentata da Martin Fowler [1] e denominata, appunto Command Query Responsibility Segregation si basa su un concetto apparentemente semplice: il cambiamento che CQRS introduce è quello di dividere il modello concettuale in modelli separati per l’aggiornamento e la visualizzazione, a cui ci si riferisce, rispettivamente, con i nomi di Command e Query. Tali nomi sono derivati dal concetto di Command Query Separation, termine coniato da Bertrand Mayer [2]. L’idea di base di questo concetto è quella di dividere i metodi di un oggetto in due categorie nettamente separate:
- Queries: a questa categoria appartengono i metodi che restituiscono un risultato e non cambiano lo stato osservabile del sistema (non introducono quindi side effects).
- Commands: in questa categoria ricadono quelli che cambiano lo stato del sistema, ma non restituiscono un valore di ritorno.
Il motivo di questa separazione è che per molti problemi, in particolare nei casi con domini più complessi, l’utilizzo di un unico modello concettuale per commands and queries fa aumentare le complicazioni e contemporaneamente diminuire i vantaggi.
Modelli separati in concreto
Per modelli separati intendiamo object models diversi, che possono essere eseguiti in processi logici differenti e anche su hardware separati. Nell’ambito di una web application questa situazione si traduce nel seguente modo: il rendering di una pagina web richiesta da un utente coinvolge il query model, mentre invece una operazione di modifica di dati coinvolge il command model e il risultato viene successivamente comunicato al query model, il quale provvede a renderizzare la pagina coerentemente al cambiamento di stato. I due modelli possono condividere lo stesso database: in questo caso esso funge da mezzo di comunicazione fra i due. Oppure ciascuno dei due modelli può usare un proprio database: e in questo caso invece bisogna implementare anche un meccanismo di comunicazione tra i due modelli. I due modelli non devono per forza essere costituiti da oggetti diversi: possono avere anche gli stessi oggetti ma con differenti interfacce lato query e lato command. Ma la definizione pura di CQRS prevede modelli nettamente separati.
Figura 2 – Raffigurazione concettuale d’insieme di una applicazione web 3-tier basata sul pattern architetturale CQRS.
Relazione tra CQRS ed altri pattern architetturali
Abbiamo visto in breve i concetti base di CQRS: un’idea dagli effetti decisivi sulla progettazione delle web application può in effetti anche basarsi su principi sostanzialmente semplici. Ma in che modo questa piccola “rivoluzione” si integra con quello che già c’è? In realtà, Command Query Responsibility Segregation si sposa perfettamente ad altri pattern architetturali.
Task-Based User Interfaces
Quanto più ci si allontana dal modello a rappresentazione singola dei dati con cui si interagisce tramite CRUD, tanto più facile risulta orientarsi verso l’implementazione di task-based user interfaces [3].
Event Sourcing
L’interazione con il command model inevitabilmente conduce all’Event Sourcing (ES). ES è un pattern architetturale che permette di rappresentare gli oggetti come una sequenza di eventi che si è verificata nel tempo e che li ha portati ad essere nel loro stato attuale. Tutti i cambiamenti di stato dell’applicazione vengono quindi conservati ed è quindi sempre possibile recuperarli e ricostruire la storia passata degli oggetti ed eventualmente usarla come base per adattare automaticamente uno stato a far fronte a cambiamenti retroattivi.
Eager Read Derivation
In molti casi la maggior parte di domain logic è necessaria in fase di update: quindi ha senso ricorrere al concetto di Eager Read Derivation [4] per semplificare il query model. Questo aspetto verrà approfondito nel prossimo articolo.
Domain Driven Design
CQRS è particolarmente adatto ai domini complessi, soprattutto quelli che traggono beneficio anche dall’adozione di un approccio di tipo Domain-Driven Design [5] [6].
Conclusioni
Questa prima parte della serie è stata dedicata a una brevissima panoramica su CQRS, presentandone i concetti base. Come abbiamo visto, non si tratta di nulla di straordinario sul piano concettuale, eppure questo pattern architetturale presenta numerosi vantaggi. Dopo questo primo, veloce approccio con CQRS, nel prossimo articolo andremo più a fondo sull’argomento vedendo in quale ambiti l’adozione di questo pattern architetturale può essere realmente vantaggiosa ed entrando anche nel concreto delle implementazioni possibili con Java.
Riferimenti
[1] Martin Fowler, “CQRS”, 2011
http://martinfowler.com/bliki/CQRS.html
[2] Bertrand Meyer, “Object-Oriented Software Construction (2nd Edition)”, Prentice Hall, 2000
[3] Charles Rich, “Goal/Task-Based User Interfaces”
http://web.cs.wpi.edu/~rich/courses/cs525u-s09/lectures/1-task.pdf
[4] Martin Fowler, “EagerReadDerivation”, 2009
http://martinfowler.com/bliki/EagerReadDerivation.html
[5] Pagina Wikipedia di definizione del Domain Driven Design
http://en.wikipedia.org/wiki/Domain-driven_design
[6] Eric Evans, “Domain-Driven Design: Tackling Complexity in the Heart of Software”, Addison-Wesley, 2003
Guglielmo Iozzia si è Laureato nel 1999 in Ingegneria Elettronica (indirizzo Biomedico) presso l‘Università di Bologna. Ha progettato e realizzato un software diagnostico per la predizione dell‘andamento della pressione intracranica in pazienti in terapia intensiva neurochirurgica. Frequenta il mondo Java dall‘inizio del 2000. Dopo numerose esperienze presso un‘azienda di Bologna del settore IT (fino all‘aprile del 2006), e per qualche mese in una analoga società di Roma, ha scelto la libera professione, lavorando per RAI Net fino ai primi mesi del 2008. In seguito è diventato Senior IT Consultant per la FAO (Food and Agriculture Organization of the United Nations). In ambito FAO ha dedicato quasi tutto il 2012 al progetto GRMS (Global Resources Management System) in qualità di "Web Services and cross-environmental integration specialist". Da luglio 2013 si è trasferito a Dublino, dove ricopre il ruolo di SVT Automation Engineer per IBM Ireland.