CQRS & de bijkomende architectuur

In mijn vorige blogpost deed ik in de voetnoten een voorstel om de architectuur die vaak meekomt met het patroon CQRS anders te noemen. Ik dacht aan een “Circular Architecture” om hem duidelijk te contrasteren met een “Layered Architecture”. Na een korte discussie met Greg Young en Alistair Cockburn hierover besloot ik om het idee nog eens even goed onder de loep te nemen. Zij claimden allebei dat de “Hexagonal Architecture” van Alistair Cockburn deze architectuur al voldoende beschreef. Dat zette me wel aan het denken, aangezien ik het oordeel van beide zeer respecteer. Eerst enkele definities waar ik vanuit ga

Command-Query Responsibility Segragation (CQRS) – de ontwerpstijl (patroon) waarbij commands en queries onderscheiden worden en ook gescheiden worden over twee verschillende interfaces. De term wordt ook gebruikt voor de applicatie-architectuur die er vaak bij komt, maar zoals Greg Young zelf betoogt in de blogpost “CQRS and Event Sourcing”, is CQRS zelf een vrij eenvoudig patroon en geen architectuur. Het is een uitbreiding op een eerder patroon dat benoemd is door Bertrand Meyer als “Command-Query Separation”.

In de bovenstaande figuur zien we achtereenvolgens 1) een referentie situatie, waarin een implementatie een interface implementeert waarin geen commands en queries onderscheiden worden, 2) Command-Query Separation als patroon, waarin een interface zowel commands als queries bevat en 3) Command-Query Responsibility Segragation, waarin commands en queries over twee verschillende interfaces verdeeld worden.

Event Sourcing – in essentie is dit de naam die gebruikt wordt voor het patroon dat elke verandering in de toestand (state) van een applicatie vastgelegd wordt in een event en dat deze event objecten opgeslagen worden in volgorde van optreden, gedurende dezelfde periode als dat de application state behouden blijft. Zie ook de Bliki over Event Sourcing.

Dit combineer ik hierbij meteen met het gebruik van deze stream aan events als leidende drager van de application state. Hiervoor moet het mogelijk zijn om de events nogmaals ‘af te spelen’ om weer in de laatste toestand (state) te geraken na een applicatie stop/start. Hiervoor is in de architectuur die Greg Young voorstelt als implementatie achter het CQRS patroon gebruik gemaakt van een event store, die in samenwerking met de Aggregate Roots binnen het domein beide functionaliteiten ondersteunt.

Hexagonal Architecture (ook wel Ports and Adapters Architecture) – deze architectuur beschrijft een applicatie als een (domein-) model dat onwetend is van zijn omgeving en dus alleen ‘met zichzelf bezig is’. Alle communicatie met de buitenwereld gebeurt via adapters, die via een bepaald protocol als het ware een poort open zetten naar de buitenwereld. Binnen Sogyo kennen we dit ook wel als het satellietmodel of het zonnebloemmodel, maar waar de Hexagonal Architecture de ‘Application’ in het midden zet, zetten we in het satellietmodel expliciet het Domeinmodel in het midden. Zie hier een afbeelding die ik overgenomen heb uit de beschrijving van Alistair Cockburn van deze architectuur.

Karakteristieke elementen uit deze architectuur zijn het feit dat de ‘Applicatie’ niets van de buitenwereld weet en dat adapters de vertaling heen-en-weer met de buitenwereld verzorgen. Belangrijk detail, zoals je ook in bovenstaande afbeelding kunt zien, is dat de database die gebruikt wordt voor persistentie ook buiten de applicatie valt. In die zin is het dus anders dan de Layered Architecture, die alle elementen in een standaard applicatie boven elkaar plaatst. Verder zien we een scheiding vermeld worden tussen user-side API en een data-side API, wat wel enige overeenkomst vertoond met de scheiding tussen commands en events zoals die in het domeinmodel benoemd worden in het geval van event sourcing. Queries gaan echter wel naar de ‘applicatie’.

De architectuur die vaak bij CQRS gebruikt en verondersteld wordt
De bovenstaande  patronen, in combinatie met het gebruik van een Database die een datamodel bevat dat toegespitst is op uitlezen (querying) is een inmiddels vaker beschreven applicatie architectuur. Elk van de elementen erin is niet nieuw, maar in totaal is het een oplossing voor de problemen die ontstaan als het domein model direct gebruikt wordt voor uitlezen (querying). Door deze functionaliteit volledig aan de read-zijde te houden en te implementeren door middel van een database, is het mogelijk om het domeinmodel vrij van getters en setters te houden (uitlezen is niet noodzakelijk) en een event store te gebruiken als leidende opslag van applicatie toestand (application state) zonder performance problemen. Zie hieronder een afbeelding met alle elementen samen.

Figuur 5: de architectuur die nu verondersteld wordt als de term CQRS gebruikt wordt.

In deze architectuur zien we de volgende elementen:

– Scheiding van commands en queries over twee interfaces (CQRS)
– Een domeinmodel dat alleen commands ontvangt en events uitstuurt (opgooit)
– Het opslaan van deze events op volgorde (Event Sourcing)
– Het restoren van het domeinmodel op basis van de events via de Event Store
– Het bijwerken van de Read Database door Event Handlers (EH)
– De Task-Based User Interface die gevoed wordt met queries op de read database en commands uitstuurt

Gezamelijk vormen deze elementen een alternatief voor de overbekende Layered Architecture, waarvan de basisvorm bestaat uit de lagen User Interface, Business Layer en Persistentie. Binnen deze architectuur gaan zowel commands en queries door deze drie lagen heen, waardoor de business layer geschikt moet zijn voor zowel commands als queries en er vaak een sterke koppeling is tussen het domeinmodel en het onderliggende datamodel in de persistentie, omdat deze voor alles met elkaar te maken hebben.

Is de bovenstaande architectuur te beschrijven met de naam Hexagonal Architecture?
Volgens mij zou deze naam niet alle elementen vatten die we er normaal gesproken onder verstaan. De onderstaande onderdelen missen volgens mij namelijk dan nog:

1. De HA beschrijft niet een strikte scheiding tussen commands en queries (maar er wordt wel een aanzet in die richting gegeven)
2. De HA beschrijft niet het gebruik van een read database met een geoptimaliseerd read model voor alle queries
3. De HA beschrijft niet het gebruik van een event store als leidende opslag van de applicatietoestand

De ontbrekende elementen en patronen zouden prima als toevoeging op een Hexagonale architectuur gezien kunnen worden, ze sluiten elkaar op geen enkele wijze uit. Echter, met de naam Hexagonal Architecture denk ik alleen aan het gedeelte rond het domeinmodel. Het beschrijft de standaard architectuur die we hierboven zien dus niet volledig.

Conclusie
Of de configuratie van op zich al bekende elementen bij elkaar een architectuur genoemd kan worden is nog niet duidelijk geworden. Volgens mij is het wel duidelijk dat de naam ‘Hexagonal Architecture’ nog niet volledig de lading dekt. Tegelijkertijd wordt de hierboven beschrijven standaard CQRS architectuur wel vaak beschreven als met het heeft over CQRS. Terwijl CQRS an sich een eenvoudiger patroon is. Volgens mij worden deze met elkaar verward, omdat er nog geen naam is voor deze Architectuur/configuratie die een direct bruikbaar alternatief is voor de welbekende ‘Layered Architecture’. Kunnen we de bovenstaande architectuur daarom niet voortaan “Circular Architecture” noemen?

Figuur 6: Circular Architecture: een duidelijke naam?