La serie sul pattern architetturale Command Query Responsibility Segregation (CQRS) prosegue con questa seconda parte in cui parleremo dei vantaggi che CQRS può garantire e dei casi in cui è realmente conveniente applicarlo. Nei prossimi numeri, proseguiremo con la presentazione del pattern, mostrando anche degli esempi pratici.
Nel precedente articolo [2] sono stati introdotti i concetti base del pattern Command Query Responsibilty Segregation (CQRS). In questo secondo articolo analizziamo i casi in cui è consigliabile l’adozione di tale pattern e quali vantaggi se ne possono trarre.
Vantaggi legati a CQRS
CQRS è particolarmente indicato nel design e nell’implementazione di web applications che:
- sono incentrate sulla logica di business piuttosto che sulla particolare tecnologia impiegata;
- possono crescere molto e necessitano di diventare in grado di gestire problemi sempre più complessi senza un corrispondente significativo aumento dei costi di sviluppo;
- devono adeguarsi a rapidi cambiamenti dei requisiti di business;
- devono integrarsi in modo efficiente con altri software e sistemi;
- devono gestire un numero elevato di utenti;
- possono beneficiare di risorse in cloud computing;
- devono essere altamente scalabili.
Non la panacea a tutti i mali, ma la soluzione per alcuni problemi
Ovviamente CQRS non è la soluzione universale a tutti i problemi (nel prossimo paragrafo vedremo quali sono i casi in cui è vantaggioso utilizzarlo) ma, grazie alle sue caratteristiche, fornisce un ottimo approccio per risolvere in maniera efficiente i problemi più frustranti che affliggono il delivery delle web applications:
- colli di bottiglia nelle prestazioni e scalabilità;
- risoluzione e prevenzione di conflitti di concorrenza;
- complessità nel design, sviluppo e manutenzione;
- data staleness.
Come si vede, si tratta di alcune aree importanti che impattano notevolmente sulla bontà della nostra applicazione, e che, pur non rappresentando la totalità dei problemi, risultano comunque significative per la globale qualità dell’appplicazione.
Quando ricorrere a CQRS
Così come per tutti i pattern architetturali, esistono dei casi in cui CQRS è utile ed altri in cui non ha senso utilizzarlo. Per parecchie web applications il semplice modello CRUD [2] calza perfettamente a pennello e non ha senso utilizzare altri altri pattern che finirebbero più per complicare le cose che per risolvere problemi.
CQRS per porzioni di applicazione
Ci sono molti casi in cui CQRS può essere molto utile se applicato solo a una porzione dell’applicazione. Per essere più precisi ed usare un termine del Domain Driven Design [3], CQRS può essere applicato limitatamente a un Bounded Context [4] e non a tutta l’applicazione nel suo complesso. Un Bounded Context rappresenta una porzione del Domain Model di una applicazione a cui viene applicato un determinato pattern. Definire dei Bounded Contexts è sicuramente una best practice in progetti molto grandi e basati su modelli multipli, soprattutto per mantenere una maggior leggibilità e chiarezza del codice.
CQRS per domini complessi
Applicazioni con domini molto complessi possono sicuramente essere gestite meglio tramite CQRS piuttosto che con un unico modello. In questi casi si ha anche un ulteriore vantaggio nella gestione delle prestazioni dell’applicazione. CQRS porta ad una netta separazione tra i carichi relativi alle operazioni di lettura e quelli relativi alle operazioni di scrittura: in questo modo è possibile scalare indipendentemente le due parti e quindi, nel caso di grossa disparità tra le due, prevedere strategie di ottimizzazione diverse per ciascuna delle due componenti.
Reporting DataBase
Nei casi in cui il dominio non è adatto a CQRS, ma l’applicazione ha necessità di query che aggiungono problemi di complessità o deterioramento delle prestazioni, si può comunque ricorrere all’utilizzo di un Reporting DataBase. Non è raro lavorare su applicazioni che prevedono la generazione di molti report. A tale scopo l’adozione di un domain model può essere di notevole aiuto. Ma i tool e i framework di reportistica esistenti dialogano perfettamente con database SQL e non con i domain model. Come agire allora in questi casi? Innanzitutto bisogna cercare di capire perchè l’applicazione necessita di un notevole numero di report ad hoc. Talvolta questa necessità è dovuta ad una cattiva individuazione dei business requirements. Ma in molti casi (esperienza personale molto frequente) gli utenti finali dell’applicazione hanno una reale necessità di generare tanti report o sono semplicemente “report addicted” e a volte anche talmente smart da riuscire a utilizzare uno strumento di reporting basato su SQL. In questi casi il ricorso a un Reporting Database è un’ottima strategia. Un Reporting Database è un database separato da quello che contiene i dati operativi. I vantaggi che ne derivano sono i seguenti:
- Il database operativo è popolato a partire dal domain model: quindi è possibile ricavare i dati da inserire nel Reporting Database sempre a partire dal Domain Model.
- Il Reporting Database è read-only e quindi non si ha necessità di normalizzarlo.
- La struttura del Reporting Database può essere disegnata in maniera specifica per facilitare la creazione dei report.
- Si possono eseguire refactor del database operativo senza ripercussioni sul Reporting Database.
- Le query eseguite sul Reporting Database non influiscono sulle performance del database operativo.
In una applicazione che usa CQRS si ha un modello separato per tutte le query. Adottando anche un Reporting Database è sempre l’applicazione stessa che esegue la maggior parte delle query, ma scalando quelle più onerose sul Reporting Database.
Errori di gioventù?
Qualcuno obbietta che comunque CQRS è un pattern architetturale piuttosto recente e che al momento non sono molti i progetti che lo adottano in un ambito di produzione: in tal modo, i suoi pro e contro non sono ancora definiti in maniera chiara e precisa. L’osservazione è teoricamente giusta, ma personalmente, in base all’analisi di parecchi sistemi reali già esistenti su cui ho lavorato negli ultimi anni, l’impressione che ne ricavo è che a tanti di questi sistemi (per non dire quasi tutti) un buon refactoring basato su CQRS avrebbe giovato parecchio. Mi conferma questa impressione il lavoro che sto svolgendo attualmente su un progetto la cui architettura prevede, fra le altre cose, CQRS: be’, almeno per la mia esperienza, mi sento di affermare che i principi di CQRS brevemente illustrati in questi primi due articoli trovano riscontro pratico nella realtà.
Altri casi particolari
Un altro caso particolare in cui CQRS è vantaggioso è per i sistemi che devono affrontare problemi come Collaboration e Staleness. Per Collaboration si intendono determinate circostanze in cui più attori (utenti o sistemi) di una applicazione vanno a usare e/o modificare lo stesso set di dati, ciascuno con l’intenzione oppure no di collaborare con gli altri. In questi casi bisogna pensare a regole che indichino chiaramente quali utenti possono eseguire determinati tipi di modifiche e quali modifiche ai dati sono accettabili in alcuni casi piuttosto che in altri. Il termine Staleness invece fa riferimento ai casi in cui, in un ambiente collaborativo, mentre un set di dati viene presentato ad un utente, tale set può subire modifiche da parte di un altro attore (utente o sistema) e quindi le informazioni risultano datate. Questa è una situazione che può capitare non di rado, per esempio in sistemi che, per motivi di performance, fanno uso di cache. È un problema non da poco, poiche’ le decisioni prese dagli utenti in queste situazioni non sono più attendibili essendo esse fondate su informazioni datate. Le architetture standard non forniscono esplicitamente strumenti per trattare questo tipo di problemi non trascurabili, al contrario di CQRS (tramite i Commands e la validation).
CQRS e database NoSQL
Un ulteriore interessante sviluppo in una web application che usa CQRS può essere il seguente: nel caso in cui si utilizzino database separati per commands e queries, considerando che lo schema per le query rispecchia esattamente il view model e non si hanno relazioni tra le classi che lo compongono, non si ha più la necessità di dover avere relazioni tra le tabelle e quindi dover per forza utilizzare un database relazionale per le query. Si hanno quindi tutte le condizioni ideali in cui in alternativa si può quindi utilizzare un database NoSQL [5] [6].
Conclusioni
In questa seconda parte abbiamo completato la panoramica su CQRS. Nei prossimi articoli verrà illustrato in dettaglio il framework Axon, una implementazione Java del pattern in questione e verranno presentati anche degli esempi pratici relativi ad una applicazione reale che usa tale framework.
Riferimenti
[1] Martin Fowler, “CQRS”, 2011
http://martinfowler.com/bliki/CQRS.html
[2] Guglielmo Iozzia, “Command Query Responsibility Segregation pattern I parte: Breve panoramica su CQRS”, Mokabyte 177, ottobre 2012
https://www.mokabyte.it/cms/article.run?permalink=mb177_cqrs-1
[3] La voce “Domain Driven Design definition” su Wikipedia
http://en.wikipedia.org/wiki/Domain-driven_design
[4] Eric Evans, “Domain-Driven Design: Tackling Complexity in the Heart of Software”, Addison-Wesley, 2003
[5] La voce “NoSQL database definition” su Wikipedia
http://en.wikipedia.org/wiki/NoSQL
[6] Elenco di progetti reali basati su database NoSQL