CQRS && Validatie && Business Rules

 
04 maart 2010

Validatie en business rules binnen een CQRS architectuur [1][2] blijven onderwerpen die vragen oproepen voor degenen die er voor het eerst van horen. Drie specifieke vragen worden daarover vaak  gesteld: hoe werkt de validatie van commands, hoe kun je business rules afdwingen over grote collections (state) en hoe werkt het afdwingen van business rules over aggregates heen? Hopelijk kan ik een aantal lezers helpen met mijn drie antwoorden daarop. Eerst de vragen

  • Als commands asynchroon afgehandeld gaan worden, hoe kan ik dan de validatie op de server doen en het de gebruiker melden dat deze validatie faalde?
  • Hoe dwingen we business rules af die afhankelijk is van state die heel groot kan worden. Bekendste voorbeeld: een gebruiker moet een unieke gebruikersnaam hebben.
  • Als aggregates volledig gescheiden zijn, hoe dwingen we dan business rules af die over meerdere aggregates heen gaan?

Ik wilde hier mijn ideeën over delen, aangezien ik denk dat deze vragen goed te beantwoorden zijn. In een hernieuwde poging om een korte post te schrijven, hier mijn drie antwoorden:

  • Maak declaratief valideerbare commands. Valideer op de client. Niet-valide commands negeer je. Zie ook [3]
  • Sla deze state in eerste instantie in-memory op in een onderdeel van de aggregate die de scope vertegenwoordigt (zie ook [4] voor een uitleg waarom er altijd zo’n scope is). Optimaliseer door de state buiten het geheugen te bewaren wanneer noodzakelijk. Gebruik maken van de read database is een extra optimalisatie.
  • Dat kan niet. Althans, niet in de vorm van invariants, die gelden namelijk alleen binnen aggregates. Mogelijke oplossingsrichtingen: voeg de aggregates samen als ze onlosmakelijk verbonden blijken, kijk of je niet een aggregate mist die specifiek deze invariant afdwingt en ga anders uit van het gebruikelijke scenario en los uitzonderingen op met compensating actions.

Om het kort te houden, is deze post van allerlei extra uitleg ontdaan. Ik kan me voorstellen dat er nog vragen overblijven, die hoor ik dan ook graag.


[1] Zie deze post van Mark Nijhof (engels) voor een mooie beschrijving van wat ik bedoel met “CQRS architectuur”
[2] Greg Young zegt zelf ook CQRS geen architectuur te vinden. Die komt er wel vaak bij, maar heeft nog geen naam. Voorstel: “Circular Architecture”?
[3] Die is aardig uitgelegd in deze post van Udi Dahan (engels). Zoek op “Commands and validation”.
[4] Hier is een mooie uitleg over te vinden in een post van Jérémie Chassaing.


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


Categorieën: Architectuur, Development

Tags: , , ,


Reacties (2)

  • @Jilles

    Punt 1: ok. :-) Betekent dus ook dat je weet dat je van het domein geen validatie-fouten meer terug kunt krijgen, dat is erg prettig en maakt asynchrone communicatie tussen de UI en het domein een stuk haalbaarder.

    Punt 2: Nou, nee, dat is sowieso het idee als je het domein weer ‘up’ wilt krijgen uit persistentie in het geval van Event sourcing. Snapshots zijn hier een optimalisatie voor. Wat ik bedoel is dat je de data die je nodig hebt voor het afdwingen van business rules (zoals het hebben van een unieke username) in je domein kunt opslaan. Wanneer nodig kun je gaan optimaliseren door deze uit het geheugen te houden en pas op te vragen wanneer deze nodig is.

    Punt 3: Ik zou zelf zover willen gaan om te te zegggen dat het hier om de definitie van een aggregate gaat: datgene dat bij elkaar hoort en waarover consistent en continue afgedwongen business rules gelden. Zulke regels heten ook wel invariants.

    Geplaatst op 08 maart 2010 om 11:46 Permalink

  • Jilles van Oossanen schreef:

    Hallo Rick,

    Lekker duidelijke post op deze manier. Kort maar krachtig! Met de bijgeleverde links is het echter toch een mooi volledig stuk.

    Punt 1: Ben ik het helemaal mee eens. Heb namelijk eindelijk de presentatie van Greg Young bekeken waarin hij het redelijk helder uitlegd. Raad mensen het ook zeker aan om die te bekijken wanneer ze meer willen weten van CQRS.

    Punt 2: Dat betekent dus dat je bij een restart/reboot je event-source moet terugspoelen om weer te komen tot de laatst bekende state? Blijft een mooie theorie, misschien interessant om dat een keer uit te werken en het in de praktijk uit te proberen.

    Punt 3: Samenvoegen lijkt me sowieso een goede oplossing. Het lijkt me sowieso dat alles binnen een aggregate met elkaar verbonden is en moet zijn. Wanneer er entities in een aggregate niks met elkaar te maken of verschillende entiteiten in verschillende aggregates zijn met elkaar verbonden, dan heb je je aggregates fout opgesteld. Op deze manier kan je nog steeds wel interactie hebben tussen verschillende aggregates, maar deze moeten dan van dusdanige aard zijn dat ze met behulp van events afgehandeld kunnen worden.

    Geplaatst op 08 maart 2010 om 9:42 Permalink