CQRS & de bijkomende architectuur

 
09 maart 2010

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”.

Base-CQS-CQRS

Figuur 1: Geen patroon, CQS en CQRS naast elkaar uitgezet.

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.

Figuur 2: Event Sourcing, plus het gebruik als application state middels een Event Store

Figuur 2: Event Sourcing, plus gebruik als application state via Event Store

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.

Figuur 4: de Hexagonal Architecture zoals beschreven door Alistair Cockburn

Figuur 3: de Hexagonal Architecture zoals beschreven door Alistair Cockburn

Figuur 4: Hexagonal Architecture in detail, met gebruikelijke structuur

Figuur 4: Hexagonal Architecture in detail, met gebruikelijke structuur

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 3: de architectuur die nu verondersteld wordt als de term CQRS gebruikt wordt.

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 7: Circular Architecture: een duidelijke naam?

Figuur 6: Circular Architecture: een duidelijke naam?


Werken met ?
Kijk dan bij onze mogelijkheden voor starters en/of ervaren IT'ers.


Categorieën: Architectuur, Development

Tags: , , , ,


Reacties (2)

  • @Anatoly

    Bedankt voor je reactie! Het was wel een heel verhaal en dat zonder paragrafen. Was daardoor niet makkelijk te volgen, maar ik heb mijn best gedaan :-)
    Ik doe mijn reactie even puntsgewijs:

    – CQRS is denk ik inderdaad geen architectuur, maar een patroon.
    – Er komt vaak wel een boel bij kijken om het patroon in werkende vorm te krijgen
    – Je kunt erover twisten of je dat een architectuur of configuratie noemt
    – Feit is wel dat het tezamen een alternatief vormt voor een layered architecture
    – En dat het als geheel nog geen naam heeft en vaak met CQRS verward wordt.

    Geplaatst op 10 maart 2010 om 21:52 Permalink

  • Anatoly Zimakov schreef:

    Het is inderdaad van belang dat de CQRS aanpak een duidelijke definitie krijgt. Als ik de huidge staat van zaken rond deze aanpak bekijk, merk ik dat het voor de meesten geen probleem is om de principes van de aanpak te begrijpen. Wat wel lastig blijkt te zijn is om de CQRS aanpak naast bestaande concepten (zoals gelaagde architectuur) te plaatsen. Persoonlijk vind ik het ook twijfelachtig dat de CQRS aanpak als een afzonderlijke type van het software architectuur beschouwd kan worden.
    Implementaties van de CQRS aanpak hebben duidelijke scheiding tussen de bekende lagen (presentation, business, persistentie), omdat de verantwoordelijkheden die op deze lagen opgelegd zijn (volgens het concept van gelaagde architecuren), blijven in de CQRS gewoon bestaan: presentatie ‘praat’ met gebruiker, business (domain) bevat logica en persistentie zorgt voor interacties met de database. Ok, in de CQRS aanpak worden deze lagen niet duidelijk genoemd, maar het gaat vooral om het feit dat er op basis van de bovengenoemde verantwoordelijkheden de scheiding tussen componenten in het systeem bestaat. Op het eerste gezicht lijkt het ook dat de CQRS aanpak regels van communicatie tussen lagen overschijdt, o.a. omdat de client (onderdeel van de presentatie) rechtsreeks de reporting (onderdeeel van de persistentie) kan aanroepen. Het feit dat dit gebeurt wilt niet zeggen dat er geen andere abstratielagen tussen de client en de reporting kunnen bestaan. Naarmate de grootte en de complexiteit van het systeem stijgen, zullen deze lagen hoogstwaarscijnlijk verschijnen. Maar er is een hoop dat het nooit heel complex wordt, aangezien de reporting voor het uitlezen van gegevens geoptimaliseerd is. Als mogelijke abstractie voor het ophalen van gegevens vanuit de reporting kan men een soort van Table Module design pattern toepassen. Normaal gesproken hoort deze pattern in de business laag thuis. Maar aangezien in de CQRS aanpak de verantwoordelijkheid voor het uitvoeren van de business logica al verdeeld is, zal de implementatie van zo’n Table Module alleen de functionaliteit van het ophalen van gegevens bevatten. Als je dan de implementatie van het systeem als geheel bekijkt, zie je dat de structuur van het systeem nog steeds aan de belangrijkste eisen van de gelaagde architectuur blijft voldoen: duidelijke verdeling van verantwoordelijkheden en de eisen in betrekking tot communicatie tussen de lagen. Het verschil met een standard implementatie van de gelaagde architectuur zal dan zijn dat het op de CQRS aanpak gebaseerd systeem een duidelijk scheiding tussen de business logica en het ophalen van gegevens zal hebben. Waar je in standaard implementatie de keuze tussen Table Module en Domain Module zou maken, kan je in het CQRS systeem de principes van beide design patterns toepassen. Je krijgt dan de implementatie van Table Module met getters en setters maar zonder business logica (in reporting), en implementatie van Domain Model met business logica maar zonder getters en setters (in Business). En dit alles als gevolg van de scheiding tussen Commands en Queries.
    Concluderend, in mijn ogen bevindt de CQRS aanpak zich in hele andere dimensie dan andere concepten (architecturen) die de regels van het verdelen van verantwoordelijkheden vastleggen.

    P.S. De bovengenoemde design patters heb ik maar als voorbeeld erbijbetrokken om de uitleg te verduidelijken. En niet omdat ik vind dat ze perse toegepast moeten worden. De vraag over de betere implementaties blijft nog lang open.

    Geplaatst op 10 maart 2010 om 16:41 Permalink

Trackback & Pingback (1)

  1. Van Command Query Responsibility Segregation | Dialogues Technology op 11 april 2011 at 15:10

    […] (Command Query Responsibility Segregation) by Rick van der Arend. A Dutch version is available too: CQRS & de bijkomende architectuur. This post not only introduces the principles of CQRS, but motivates them too, e.g. it is argued […]