Het CQRS-patroon: de voor- en nadelen van een scheiding
Command Query Responsibility Segregation (CQRS) is een architecturaal patroon waarin je het schrijfmodel rigoureus scheidt van het leesmodel. Dankzij de splitsing van deze verantwoordelijkheden ben je onder meer vrij om te beslissen of je deze lees- en schrijffunctionaliteiten al dan niet in dezelfde database wenst onder te brengen. Maar kiezen voor CQRS heeft nog meer implicaties. Scheiden of niet? Intracto maakt de balans op.
Het meest gangbare patroon voor interactie met data verloopt volgens het CRUD-principe. Hierbij wordt gewerkt met één model waarbij records kunnen aangemaakt (create), uitgelezen (read), aangepast (update) of verwijderd (delete) worden.
De laatste jaren werden gebruikers van applicaties echter steeds veeleisender. Applicaties moeten razendsnel werken en zoekopdrachten worden verondersteld vliegensvlug een resultaat op te leveren. De aandacht voor een uitstekende gebruikerservaring nam zienderogen toe.
De afhandeling van gedetailleerde queries en validatieregels maakt de zaken echter een stuk complexer. Het conventionele CRUD-model wordt dan omslachtig om te implementeren en te onderhouden. Hier kan CQRS mogelijk soelaas bieden. Maar is zo’n CQRS-patroon ook geschikt voor jouw project? We houden de voor- en nadelen even onder loep.
Lezen en schrijven
Naarmate de vereisten complexer worden, kan het nuttig zijn om van het CRUD-model af te stappen. Misschien willen we de informatie in een andere structuur kunnen uitlezen dan in de structuur waarin deze wordt weggeschreven?
Bij het uitlezen van de data is het misschien nodig dat de verschillende resultaten samengevoegd worden of dat we informatie vanuit verschillende locaties willen combineren. In het CRUD-model kunnen zulke query’s zeer complex worden. Aan de schrijfkant willen we eventueel bepaalde validatieregels inbouwen.
CQRS splitst het conventionele CRUD-model op in 2 verschillende modellen. Namelijk het Command-model en het Query-model.
Commands hebben als enig doel een actie uit te voeren. Deze commands kunnen bijvoorbeeld verantwoordelijk zijn voor het aanmaken, bewerken of verwijderen van data. In de CQRS-architectuur kunnen commands geen resultaat terugsturen. Query’s kunnen dan weer enkel gegevens lezen en teruggeven zonder deze te wijzigen.
Stel: een gebruiker bekijkt een webpagina die tot stand is gekomen via het query-model. Als hij een aanpassing uitvoert, zal deze aanpassing via het command-model verwerkt worden. De aanpassing wordt dan gecommuniceerd met het query model die het bijgewerkte resultaat weergeeft aan de gebruiker.
CQRS kan in vele variaties voorkomen. De twee modellen kunnen dezelfde database delen, waardoor deze database als we ware fungeert als communicator tussen de modellen. Ook kan er gewerkt worden met afzonderlijke databases. In dat geval fungeert de query database als een real-time Reportage Database.
Voordelen
CQRS vergemakkelijkt het verdelen van werk. Door het scheiden van lees- en schrijf-flows kunnen grotere development teams de applicatie beter beheren.
CQRS maakt onderhoud en bug fixing een stuk eenvoudiger.
CQRS maakt een geoptimaliseerd database model mogelijk. Een van de grootste voordelen is ongetwijfeld de mogelijkheid om de leeszijde te optimaliseren en daardoor de query prestaties aanzienlijk te verbeteren.
CQRS zorgt voor meer vrijheid om de gegevensweergave te finetunen zonder de algemene prestaties negatief te beïnvloeden. De schrijfzijde moet geen rekening houden met de leeszijde, wat een optimaler gebruik van database resources bewerkstelligt.
CQRS verbetert de security. Door het scheiden van de schrijf- en leesbewerkingen is het makkelijker om te bepalen welke entiteiten toegang hebben tot bepaalde datasets en wie de machtiging heeft om gegevens te schrijven of te wijzigen.
Nadelen
CQRS zorg helaas ook voor extra complexiteit. Hoewel het opsplitsen van lezen en schrijven in afzonderlijke modellen logisch lijkt, wordt het ontwerp van de applicatie zelf complexer.
CQRS verhoogt de kans op inconsistenties. Het gevaar bestaat dat het leesmodel niet up-to-date gehouden wordt. Dit wordt vaak opgelost door gebruik te maken van Event Sourcing.
Zoals elk patroon is CQRS nuttig in sommige situaties, maar in andere dan weer niet. Het CRUD model blijft zeker geschikt voor heel wat toepassingen. Je kunt CQRS eventueel ook enkel toepassen op een specifiek onderdeel binnen de applicatie.
Als je te maken krijgt met complexe queries of prestatieproblemen in een applicatie die niet geschikt is voor CQRS, kun je nog steeds een Reportage Database gebruiken. Deze Reportage Database wordt dan enkel gebruikt om de meest veeleisende vragen op te vangen. ElasticSearch kan hiervoor bijvoorbeeld gebruikt worden.
Combinaties
Je kunt CQRS ook combineren met andere architecturale patronen. Zo werkt CQRS goed samen met event-based programmeermodellen. In dat geval communiceren de verschillende services met elkaar via events. Dit staat toe dat deze services het voordeel kunnen ervaren van Event Sourcing.
In veel situaties komt de meeste logica kijken bij het bewerken van je data. Het kan zinvol zijn om Eager Read Derivation te gebruiken om het query-model te vereenvoudigen.
Als het schrijfmodel events genereert voor alle updates, kun je het leesmodel structureren als Event Posters. Zo kunnen er Memory Images gegenereerd worden, wat bepaalde database interacties onnodig maakt.
Ten slotte is CQRS ook geschikt voor complexe domeinen die eveneens baat kunnen hebben bij Domain-Driven Design.