DDD messaging architectures
Van 25 t/m 28 juni 2019 was JDriven met twee collega's aanwezig bij een vier daagse workshop van Mathias Verraes getiteld DDD for Messaging Architectures. De workshop had een opzet waarbij de aanwezigen zelf onderwerpen op de agenda konden zetten. Aangezien Sander en ik bezig zijn met een project dat typisch in een message driven context leeft en waarbij er rondom het team buzzwords rondvliegen zoals DDD, Kafka, Event Sourcing (ES), Event Storming en CQRS, besloten wij die onderwerpen aan te dragen. We waren reeds enigszins bekend met de begrippen, maar zochten specifiek naar hulp met twee vragen:
- Hoe ga je in CQRS + ES om met externe events, w.w.z. gebeurtenissen die elders hebben plaatsgevonden en als feiten worden medegedeeld aan jouw systeem?
- Hoe verschijnt CQRS + ES in code die is opgezet volgens hexagonal architecture (ports & adapters)?
Leidraad voor de workshop was een casus van Mathias over een car sharing service. Middels Event Storming werd in een paar dagen tijd het e.e.a. duidelijk gemaakt:
- Het belang van een ubiquitous language en het vermogen van betrokkenen om scherp te zijn op woordkeus en lichaamstaal.
- Het belang van voldoende tijd en aandacht voor het uitvragen van de domain expert om inzichten te verzamelen in de problem space (divergeren)
- Het identificeren van events, constraints en commands
- Het temporeel modelleren van events, commands en constraints om van een beoogd resultaat terug te redeneren naar wat er voor nodig is en zo een flow inzichtelijk te maken.
- De paradigm shift die je moet ervaren om niet direct in CRUD en structurele modellen te denken.
- De noodzaak om regelmatig in en uit te zoomen om overzicht en afhankelijkheden in kaart te brengen.
- Inzicht in Bounded Contexts en Aggregates van het probleemdomein
- Event Storming vereist veel fysieke ruimte, vereist actieve deelname door iedereen, en vereist veel aandacht. Het is een intensief proces dat makkelijk meer dagen in beslag kan nemen.
Met voldoende inzicht was het bruggetje te maken naar de solution space: het vertalen van het domein model naar een oplossing die daarbij past. De middelen die hiertoe werden aangereikt waren met name CQRS en Event Sourcing, vergezeld met caveats aangaande transactions en concurrency. Binnen CQRS werd de Process Manager, ook wel Saga, genoemd als onderdeel dat externe events kan opvangen en vertalen naar nieuwe commands voor het write model van CQRS. Alhoewel we met meer ontzag en aandacht de design kant zullen aanvliegen met de inzichten die Mathias wist over te brengen, werden we in dit opzicht echter enigszins teleurgesteld.
De workshop leidde niet tot een beter begrip van hoe zo'n design nou concreet - al was het maar een voorbeeld - tot een implementatie kan leiden. Het gebruik van een process manager voor externe events, of het uitsturen van eigen events, m.a.w. de interactie tussen bounded contexts geïmplementeerd middels verschillende systemen, is geen sinecure. Maar er was geen voorbeeld implementatie. Hoe aggregates, entities, event store, commands en projections in CQRS + ES typisch te combineren zijn met hexagonal architecture, blijft iets voor onszelf om uit te zoeken. Mathias merkte op dat Kafka niet voor event sourcing is bedoeld (een mening die je wel meer tegenkomt, maar die Confluent zelf bijv. niet deelt) maar wel een rol kan spelen als broker in een message driven architectuur, maar hoe deze tools en begrippen samen kunnen komen in een architectuur is iets wat wij zelf naderhand zijn gaan uitzoeken.
We zijn sinds de workshop vlijtig aan de gang gegaan met event storming en merken dankzij bovengenoemde inzichten dat het een middel is geworden waar we regelmatig naar grijpen tussen coding en backlog refinements. Voor de implementatie laten we ons helpen door het Axon framework dat een aantal CQRS+ES primitives aanlevert. Het inpassen in hexagonal architecture en het gebruik van een saga om externe events op te vangen blijft daarbij een uitdaging die ons regelmatig terug naar de tekentafel leidt en ons doet afvragen: wat willen we bereiken, hoe dragen de events die we kennen hieraan bij, en waar begint en eindigt de verantwoordelijkheid van onze bounded context en aggregates?
Meer hierover in een komend blog, waarin we ingaan op CQRS + ES in combinatie met Axon, Kafka en hexagonal architecture.
Jasper en Sander