De CQRS aanpak, hoe doet men dat?

 
09 maart 2010

Geschreven door Anatoly Zimakov
In samenwerking met Rick van der Arend en Jilles van Oossanen

Zoals al in onze vorige blogpost over de CQRS aanpak aangegeven was, hebben wij op basis van de door Erik Rozendaal ontwikkelde framework een voorbeeldapplicatie gebouwd om meer gevoel voor deze aanpak te krijgen. Aan de hand van onze eerste ervaringen met de CQRS aanpak hebben wij toen een aantal regels opgesteld welke in de vorige post ook al vermeld zijn. Hoewel deze regels de belangrijkste principes van de CQRS aanpak redelijk goed beschreven, hebben wij ons afgevraagd in hoeverre implementaties van deze aanpak kunnen verschillen. Met andere woorden: wat zijn de manieren om een CQRS-framework te bouwen dat aan de genoemde regels voldoet? Wat leggen deze regels vast en wat kun je zelf bepalen als je een CQRS-framework ontwikkelt?

Om deze vragen te kunnen beantwoorden hadden wij nog een CQRS  framework nodig om de implementatie daarvan met de implementatie van het framework van Erik Rozendaal te kunnen vergelijken. Wij hebben hiervoor het Axon CQRS-framework uitgekozen. Wij hebben beide frameworks naast elkaar gezet en zijn tot de volgende conclusies gekomen:

Het framework van Erik Rozendaal Het Axon framework
Het framework is als voorbeeld van een CQRS-implementatie gebouwd en is nooit bedoeld als productie systeem. Axon is een open source project. Hoewel het framework nog redelijk jong is, zijn er al een aantal kleine releases geweest. Op het moment van het schrijven van deze blogpost (03/2010) was versie 0.4 de nieuwste release van dit framework.
Geen documentatie. Er is een reference guide  voor iedere versie van het Axon-framework beschikbaar.
Het framework is op maat gemaakt en moet al snel aangepast worden om aan de eisen van de omgeving te voldoen waarin het framework toegepast zal worden. Axon-framework is redelijk generiek geïmplementeerd en bevat  features die afhankelijk van de omstandigheden gebruikt kunnen worden.
Het framework heeft een synchrone bus waarop berichten gezet kunnen worden. De event-bus van het Axon-framework kan de berichten zowel synchroon als asynchroon afhandelen.
De bus is niet op afstand te benaderen. Als je de bus niet wilt aanpassen maar events die door je applicatie afgevuurd worden van buitenaf wil kunnen ontvangen, kan je voor ieder event die voor de buitenwereld interessant is een event handler bouwen welke deze events naar een openbare bus of queue stuurt. Axon-framework maakt gebruik van Spring Integration om zijn eventbus voor de buitenwereld beschikbaar te stellen. Het framework bevat een aparte library waarin deze functionaliteit geïmplementeerd wordt.
Om ervoor te zorgen dat events die uit het domain van je applicatie komen, afgehandeld worden, moet ergens bekend zijn welke event handlers bij welke events horen. In het framework ligt deze verantwoordelijkheid bij de bus. De bus is dan ook diegene die deze event handlers aanroept als hij de bijbehorende events ontvangt. In het Axon-framework worden event handlers door middel van annotations aan events gekoppeld.
Een event handler in het framework is een subklasse van AbstractHandler<T> waarin T de type event aanwijst. In het Axon-framework kunnen methodes als event handlers geannoteerd worden waardoor het mogelijk is om meerdere event handlers in een klasse samen te voegen.
In het framework worden zowel commands als events via de bus verstuurd. Met andere woorden: de bus maakt geen onderscheid tussen commands, events en desbetreffende handlers. Het verschil is er alleen maar in benaming, want ook command handlers zijn ‘de kinderen’ van de  AbstractHandler<T> klasse. Voor Axon-framework is het woord ‘command’ een abstract begrip, want er zijn geen klassen of andere componenten die commands representeren. Deze zouden door de ontwikkelaar zelf gedefinieerd kunnen worden. De bovenstaande betekent ook dat er geen commands op de bus te vinden zijn. Command handlers kunnen dan rechtstreeks vanuit de front-end van de applicatie aangeroepen worden.
Het framework kent één soort event. Alle events moeten de subtype van Event klasse zijn. Dan pas komen ze in aanmerking voor de event sourcing. Wat het Axon-framework wel kent en het framework van Erik Rozendaal niet, is het onderscheid tussen verschillende soorten events, zoals Domain-, Application- en System- events. Meer over deze soorten events kan in de reference guide gevonden worden.
Events worden ge(de)-serialiseerd met Xstream en opgeslagen in de database. Standaard maakt het framework gebruik van dezelfde database als de applicatie zelf. Dit betekent dat event sourcing en reporting in één database plaats vindt. Axon maakt ook gebruik van Xstream voor (de-)serialisatie, maar vervolgens worden ze naar bestanden weggeschreven.

Zoals al uit deze vergelijking geconcludeerd kan worden, heeft Axon een aantal voordelen ten opzichte van het framework van Erik Rozendaal. En dat is ook niet gek, omdat het Axon framework continue in ontwikkeling is en het framework van Erik Rozendaal een voorbeeldimplementatie is. Het is ook niet ons hoofddoel geweest om het beste CQRS-framework te vinden. Wij richtten ons vooral op de manieren waarop de CQRS geïmplementeerd kan worden. Daarmee willen we een wat concreter beeld te vormen van de belangrijkste instrumenten en implementatie principes waarmee men een event-driven omgeving  (in dit geval CQRS omgeving)  kan opzetten.

Hoewel het framework van Erik Rozendaal voor de productie omgeving niet bedoeld is, kan het framework als een voorbeeld gebruikt worden om te begrijpen hoe het CQRS principe in de  gebruikt kan worden. Bovendien kan het framework handig zijn als men een eigen CQRS framework wil bouwen. Hoewel de implementaties sterk van elkaar kunnen verschillen, zijn het steeds dezelfde problemen die op ene of de andere manier door het framework opgelost moeten worden. Voorbeeld: events moeten door handlers afgehandeld worden.  De mapping tussen events en handlers moet dus ergens gespecificeerd worden. Zoals wij al in de bovenstaande tabel hebben gezien, kan dit in de event bus gedaan worden. Of, zoals in het Axon-framework gedaan is, kunnen custom annotations gedefinieerd worden, waarmee men handlers aan kan duiden.

Wat het Axon framework betreft, lijkt dit framework interessant om in de productie toegepast te worden. Het framework biedt voor ontwikkelaars een zekere mate van flexibiliteit in de manier waarop het CQRS principe geïmplementeerd kan worden. Ontwikkelaars kunnen optioneel gebruik maken van Event Sourcing of van Spring Integration library. Dit laatste zorgt ervoor dat de op het Axon framework gebaseerde applicaties met het buitenwereld kunnen communiceren. Onze volgende stap in het onderzoek is om de communicatie van het Axon-framework met het buitenwereld te bestuderen en een proof-of-concept te maken waarmee de werking van deze communicatie aangetoond kan worden.

Concluderend, nu wij de verschillende implementaties van de CQRS aanpak hebben gezien, proberen we richtlijnen te bepalen voor het toepassen van deze aanpak in de praktijk. Wanneer heeft men deze aanpak nodig? Welk invloed kunnen bepaalde eisen vanuit de business domein hebben op de manier waarop een of een ander aspect van de CQRS aanpak geïmplementeerd wordt? Denk hier bijvoorbeeld aan het uitvoeren van verschillende soorten validaties op het domein, het in consistente staat houden van gegevens in verschillende componenten van het systeem of het toepassen van event sourcing. Dit zijn de vragen die wij ons stellen om een concreter beeld te vormen van de toepassingsgebieden van de CQRS aanpak en van de speelruimte die wij als ontwikkelaars binnen deze aanpak krijgen om de doelen te realiseren.


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


Categorieën: Development


Reactie

  • @Anatoly

    Leuk om te zien hoe het uiteindelijk geworden is. Toch een mooie vergelijking, die aangeeft waar er verschillende keuzes gemaakt worden. Misschien nog maar eens een nieuw framework toevoegen aan de vergelijking als we weer een nieuwe implementatie onder handen hebben genomen. Misschien die van Mark Nijhof?

    Geplaatst op 11 maart 2010 om 8:19 Permalink