De waarde van domain-driven design in complexe IT-landschappen

Complexe IT-landschappen hebben hun eigen zwaartekracht. Modellen uit verschillende systemen trekken aan elkaar, definities verschuiven, en teams die langs elkaar heen praten versnellen misverstanden. Ik heb eens een betaalplatform gezien waar “settlement” voor finance iets anders betekende dan voor de engineers van de betalingsgateway, met als gevolg twee data pipelines, drie reconciliatiejobs en maandelijks handwerk in spreadsheets. De software werkte, maar elk nieuw land of elke nieuwe betaalmethode kostte weken. Domain-driven design, kortweg DDD, is vooral waardevol in zulke omgevingen waar begripsverwarring en integratiefrictie de echte bottlenecks vormen, niet de technologie.

DDD is niet een verzameling patronen die je klakkeloos toepast. Het is een manier van werken die de kern van het domein naar voren haalt, met taal en grenzen als belangrijkste instrumenten. Wie daar serieus mee aan de slag gaat, merkt dat gesprekken verbeteren, wijzigingskosten dalen en teams autonoomer worden. Niet door magie, maar door expliciete keuzes die het juiste soort complexiteit omarmen en het verkeerde soort afknijpen.

Waarom taal het belangrijkste integratiesubstraat is

De ubiquituous language, de gedeelde taal van business en techniek, lijkt zo voor de hand liggend dat veel teams haar overslaan. Totdat de productie-incidents zich opstapelen omdat “actieve klant” in CRM iemand met een e‑mailopt-in betekent, terwijl in facturatie iemand bedoeld wordt met een openstaand contract. Het gaat zelden om semantiek voor de semantiek. Het gaat om eenduidigheid die aan code, data en interfaces kleeft.

Een goede gedeelde taal ontstaat niet in een wiki. Ze ontstaat in gesprekken, scenario’s, voorbeelden aan het whiteboard en terugkoppeling naar de code. Als de taal leeft, zie je het direct terug in:

  • methodenamen die leesbaar en precies zijn,
  • events die een begrijpelijk verhaal vertellen,
  • rapporten die geen voetnoten vol uitleg vereisen.

In een workshop bij een retailer over retouren bleek “retour” verschillende subcases te omvatten die in practice totaal andere regels vroegen: defect, herroepingsrecht, en coulance. Door die woorden afzonderlijk te benoemen en te modelleren, verdween een reeks if-statements en nam de doorlooptijd voor lastige retouren met ongeveer 30 procent af. Vaak is dit de eerste winst van DDD: misverstanden voorkomen die je anders met technologie probeert te dichten.

Bounded contexts als ruggengraat van de architectuur

Waar de taal divergeert, hoort de software te splitsen. Een bounded context definieert zo’n grens. Binnen een context gelden consistente definities en modellen. Tussen contexten praat je via expliciete contracten. Dat klinkt abstract, maar in de praktijk is het het verschil tussen één mega-API met 140 endpoints en vijf heldere services die elk een deel van het domein bezitten, elk met een eigen ritme van verandering.

In payment, een klassiek complex domein, zie je vaak contexten als Onboarding, Risk, Authorization, Settlement en Disputes. Elk van die contexten heeft een eigen tempo en prioriteit. Risk wil bijvoorbeeld snel experimenteren met nieuwe signalen, terwijl Settlement gebaat is bij strikte stabiliteit en auditeerbaarheid. Door die grenzen te respecteren, stop je met het afstemmen van elke deploy op het traagste onderdeel en kunnen teams binnen hun domein versnellen. In organisaties met DevOps & Cloud Services op orde, versterkt dit elkaar: een context krijgt infrastructuur die past bij het doel, zoals sterk geconfigureerde audit-logging voor Settlement en event streaming met feature flags voor Risk.

Een context map maakt afhankelijkheden zichtbaar. Hierin leg je uit welke context leidend is, waar vertalingen plaatsvinden en welk integratiepatroon gekozen is. Anti-corruption layers bewaken dat begrippen niet stiekem mee verschuiven. Published language, bijvoorbeeld een gestandaardiseerd eventformaat voor “InvoiceFinalized”, zorgt dat nieuwe afnemers niet telkens opnieuw “uitvinden” wat een factuur is. Zo’n kaart fungeert als mentale wegenkaart bij onboarding van nieuwe mensen en als referentie bij discussies over teamgrenzen. Het is ook een uitstekend instrument tijdens Digital Transformation trajecten, waar reorganisaties en systeemvervanging hand in hand gaan.

Tactiek met beleid: aggregates, value objects en domain events

DDD biedt tactische bouwstenen, maar de valkuil is overdreven ijver. Niet elk veld moet een value object worden en niet elk clickje rechtvaardigt een event. Toch zien we in complexe landschappen dat een paar weloverwogen keuzes onevenredig veel opleveren.

Een aggregate bewaakt invariante regels in één consistentietransactie. In e‑commerce is Order een voor de hand liggend aggregate, maar Payment vaak niet, omdat betalingen asynchroon verlopen en meerdere externe partijen raken. Het is een kunst om de grenzen klein te houden, zodat je gelijktijdigheid en schaalbaarheid niet hindert, terwijl je wel de zakelijke regels kunt afdwingen. Value objects maken ongeldige toestanden onmogelijk, bijvoorbeeld een Money type met muntsoort en afgeronde precisie. Domain events vertellen het verhaal van het systeem naar buiten toe en vormen de brandstof voor projecties en rapportages zonder de core logica te vervuilen.

Een harde les uit productieomgevingen: events die geen echte zakelijke betekenis dragen, slijten in het landschap als zand. Ze zijn moeilijk te versioneren en worden zelden goed gedocumenteerd. Een klein team dat een event “UserUpdated” publiceert om UI-state te synchroniseren, kan onbedoeld een data-afhankelijkheid creëren voor vijf andere teams. Beter is om te spreken in termen van “PhoneNumberVerified” of “AddressChangedForShipping”, wat afnemers helpt de intentie te begrijpen en robuuste koppelingen te bouwen. Combineer dat met bewuste schema-evolutie en versiebeheer, bijvoorbeeld via schema registry tooling, en je eventlog blijft waardevol in plaats van ballast.

Checklist voor goed aggregate-ontwerp:

  • Beperk de aggregate tot regels die gelijktijdig consistent moeten zijn, niet tot alles wat “bij elkaar hoort”.
  • Modelleer intenties als commands en resultaten als events, zodat use cases scherp blijven.
  • Gebruik value objects voor ondelbare concepten met valideerbare invarianten, zoals Money of Percentage.
  • Maak referenties naar andere aggregates via identifiers, niet als objectgrafen in geheugen.
  • Meet hotspots in productie en heroverweeg grenzen als lock-contention of wachttijden oplopen.

Van ontdekking naar levering: hoe DDD het deliverypad verkort

DDD versnelt niet omdat er minder code geschreven wordt, maar omdat je minder verkeerde code schrijft. Een event storming duurt bij ons vaak zes tot acht uur, verspreid over twee dagen. Met post-its en markers lopen we door het scenario van order tot bezorging, of van lead tot contract, en vangen we domeinregels, uitzonderingen en externe afhankelijkheden. Na zo’n sessie is er zelden nog discussie over basisterminologie. In de weken erna zie je dat stories scherper worden geschreven, testgevallen rijker zijn, en architectuurkeuzes beter te verdedigen.

In een logistieke context heeft deze aanpak het aantal rollback-deploys teruggebracht van gemiddeld twee per maand naar eens per kwartaal, gemeten over een jaar. Niet omdat er minder bugs waren, maar omdat de soort bugs veranderde. Minder misinterpretaties van regelgeving, meer klassieke codefouten die makkelijker te testen zijn. In Software Development is dat een wezenlijk verschil: de eerste categorie vraagt weken van herontwerp, de tweede categorie is te vangen met testdiscipline en CI.

Data en rapportage zonder het domein te verfrommelen

Systeemgrenzen zijn vaak helder, tot de rapportagevraag komt. “Kunnen we volgende week omzet per regio én per marketingkanaal zien, gecorrigeerd voor retouren?” Zonder DDD eindig je al snel met een rapportagedatabase die impliciete bedrijfslogica bevat. Met DDD verschuif je die logica naar expliciete read modellen die gevoed worden door domeinevents of dedicated queries. CQRS helpt hier: schrijfmodellen blijven zuiver, leesmodellen zijn geoptimaliseerd voor vragen die in de praktijk leven.

Trade-offs zijn onvermijdelijk. Eventual consistency betekent dat een dashboard soms 1 tot 2 minuten achterloopt. In finance of risk kan dat geen probleem zijn, maar in real‑time fraudedetectie is die vertraging onwenselijk. Dan kies je voor streaming met lage latency en aangepaste SLA’s. Je bouwt idempotente consumers en je accepteert dat sommige events corrigeren of compenseren. In data lake of data mesh omgevingen werkt dit alleen als het eventcontract een first-class citizen is. Data teams moeten toegang hebben tot betekenisvolle, versioneerbare events, niet tot losse tabellen met ongedocumenteerde velden.

Legacy, brownfield en het strangler patroon

De meeste organisaties beginnen niet op een maagdelijk groen veld. Bestaande monolieten bevatten jaren aan domeinkennis en edge cases, vaak zonder expliciete taal. Hier helpt het strangler patroon: waarde stap voor stap uit de monoliet trekken langs natuurlijke contextgrenzen. Het is een chirurgische operatie, geen sloop.

Stapsgewijze aanpak voor brownfield-migratie:

  • Identificeer een bounded context met een duidelijke klantwaarde, beperkte externe afhankelijkheden en meetbare pijn, bijvoorbeeld “Pricing”.
  • Snijd het leespad eerst los met een read model of proxy, zodat je risico’s verkleint en het team de domeintaal scherpt.
  • Zet een anti-corruption layer neer die de oude taal vertaalt naar de nieuwe, en log afwijkingen expliciet.
  • Verplaats schrijfoperaties gefaseerd, begin met zelden gebruikte paden om te leren, daarna de hotspots.
  • Ontkoppel de database pas als je functionele divergensie zichtbaar en getest is, niet op basis van een deadline.

In een verzekeringscase hebben we zo in zes maanden het claimsproces opgesplitst. Eerst het read‑gedeelte losgetrokken om realtime statusweergave aan klanten te verbeteren. Daarna de intake en triage migreren met nieuwe regels per product. De oude kern bleef draaien voor uitbetalingen tot de reconciliatie stabiel was. Resultaat: klanttevredenheid plus 12 punten in NPS, wachttijden terug van dagen naar uren, en geen big bang weekend.

DevOps & Cloud Services als enabler, niet als doel

DDD komt pas tot leven als teams autonoom kunnen bouwen, uitrollen en monitoren binnen hun context. Cloudplatforms helpen, mits ze capabilities bieden die het domeindenken ondersteunen:

  • self‑service provisioning voor data stores per context, zodat teams geen schema’s delen uit gemak;
  • managed messaging met schema‑registry, versies en retentiebeleid, zodat events evolueren zonder breuk;
  • observability per context met traces die business events volgen, niet alleen technische spans;
  • deploystrategieën zoals canary en blue‑green, afgestemd op het risicoprofiel van de context.

GitOps versterkt dit door infrastructuur en applicatie als één geheel te beheren. Een Settlement‑team met strikte compliance kan change approval formaliseren via pull requests en policy as code, terwijl een Risk‑team snellere iteraties draait. Het platform faciliteert, het domein dicteert. Die asymmetrie is geen rommeligheid, maar een reflectie van de werkelijkheid.

Nearshore AI Development inbedden in het domein

AI‑teams die aan de zijkant experimenteren leveren vaak indrukwekkende demo’s die moeilijk te operationaliseren zijn. Door AI‑ontwikkeling te verankeren in bounded contexts voorkom je dat features verzanden in proof‑of‑concepts. Een nearshore team dat bijvoorbeeld werkt aan demand forecasting hoort in de Supply Planning context, met toegang tot juist die events, definities en kwaliteitsmetingen. Data contracten krijgen zo tanden: als “StockReplenished” zijn semantiek verandert, zien IT personeel uit Egypte modellen het direct, met expliciete versies en compatibiliteitsafspraken.

Let op een paar valkuilen. AI‑modellen hebben de neiging contextgrenzen te negeren, omdat ze signalen uit meerdere domeinen combineren. Dat kan, maar borg de scheiding in de output. Een churn‑risicoscore is prima, zolang het domein dat de score consumeert de beslisregels blijft bezitten. Model drift vraagt monitoring op business KPI’s per context, niet enkel op abstracte metrics. Iteratiesnelheid groeit als nearshore teams dezelfde ubiquitous language spreken en deelnemen aan event storming, niet als ze “aan de overkant” features toegestuurd krijgen.

IT Recruitment: huur op domeinscherpte, niet alleen op tools

DDD heeft consequenties voor hoe je mensen zoekt en teams samenstelt. Een uitstekende engineer zonder domeininteresse brengt je minder ver dan een goede engineer die scherp luistert, doorvraagt en taal verfijnt. In IT Recruitment helpt het om profielen te beschrijven aan de hand van domeinverantwoordelijkheid en contextgrenzen in plaats van lijstjes frameworks. Een vacature voor “Engineer, Disputes domain” zegt meer dan “Senior Java developer”.

Tijdens interviews gebruiken we liefst echte domeinscenario’s. Niet “hoe sorteer je een array,” maar “hoe zou je chargebacks modelleren, welke invarianten gelden en wat betekent dat voor consistentie?” Pairing met een domain expert van de business levert vaak het scherpste beeld. Kandidaten die de moed hebben om definities te betwisten, passen goed bij DDD‑teams. En wie kan uitleggen waarom iets niet als microservice moet, laat volwassen oordeel zien.

Organisatie en teamgrenzen die modelleren wat je echt doet

Conway’s law laat zich zelden negeren. Als teamgrenzen haaks staan op bounded contexts, sluipen integraties terug de code in. Teams die elk “een laag” beheren, bijvoorbeeld een back‑end team, een front‑end team en een data team, missen vaak de domeinfocus om zelfstandig te leveren. Team Topologies biedt nuttige namen: stream‑aligned teams per context, een platformteam dat gemeenschappelijke capabilities levert, en waar nodig een complicated subsystem team voor specialistische componenten zoals pricing engines of cryptografie.

Maak afhankelijkheden expliciet. Als Pricing de leidende context is voor kortingen, dan bepaalt dat team de public interface en releasecadans. Afnemers doen verzoeken, geen commits. Service Level Objectives horen business‑gedreven te zijn: “90 procent van price quotes binnen 50 milliseconden” zegt iets, “CPU onder 70 procent” niet. Daarmee stuur je op waarde in plaats van bezetting.

Meten is weten, maar meet het juiste

Veel teams sturen op generieke metriek zoals code coverage en story points. Die zijn oké als hygiene, maar zeggen weinig over domaineducatie en doorstroom. Beter is te meten per context:

  • cycle time van idee tot productie, uitgesplitst naar type wijziging, bijvoorbeeld regelwijziging versus UI‑wijziging;
  • deploymentfrequentie en change failure rate per context, bij voorkeur in DORA‑termen;
  • defecten die domeinregels raken, bijvoorbeeld verkeerde berekeningen of foute statussen, als afzonderlijke categorie;
  • tijd tot begrip, gemeten door onboarding‑surveys van nieuwe teamleden na 30 en 60 dagen, specifiek over taal en model;
  • support load per context, om te zien waar de pijn zit.

Deze cijfers geven richting. Als cycle time voor rule changes oploopt terwijl voor simpele UI‑wijzigingen daalt, is je taal of je aggregategrens vermoedelijk niet scherp genoeg, of ontbreekt tooling om regels veilig te wijzigen.

Misverstanden en valkuilen

DDD wordt weleens gelijkgesteld aan microservices. Het omgekeerde is dichter bij de waarheid: zonder duidelijke bounded contexts worden microservices het digitale equivalent van los zand. Een tweede misvatting is dat DDD altijd zwaar is. In simpele administratieve apps, met weinig verandering en beperkte domeinlogica, is een rechtlijnige CRUD‑aanpak prima. Je hoeft niet elk formulier tot aggregate te verheffen.

Over‑modelleren is een reëel risico. Ontwikkelaars houden van mooie objecten en zuivere relaties, maar het leven is rommelig. Soms is een simpele mappinglaag naar een externe API voldoende en verdient een scenario geen rijk model. Houd de feedbacklus kort: production telemetry, stakeholderdemo’s en data‑checks moeten je model voeden, niet je esthetisch gevoel. En wees alert op Big Design Up Front. DDD is iteratief. Een context map die vandaag klopt, Front En Developer moet over drie maanden misschien weer bijgesteld.

Een beknopte case: verzekeraar met claimschaos

Bij een middelgrote verzekeraar zagen we een wachttijd van gemiddeld 9 dagen tussen claimindiening en eerste inhoudelijke reactie. Er waren vier systemen betrokken, elk met een eigen “claimstatus”. Escalaties liepen via e‑mail. Het management wilde “een nieuw claimsysteem”. In plaats daarvan begonnen we met een event storming van claim tot uitbetaling. We brachten drie heldere contexten aan: Intake, Assessment en Payout.

Intake kreeg taal en regels rond volledigheid en fraude‑signalen. Assessment bepaalde de dekkingsbeslissing met productafhankelijke regels, Payout borgde audit en compliance. Tussen Intake en Assessment kwam een published event “ClaimReadyForAssessment” met expliciet schema. We bouwden een read App Ontwikkelen Kosten model voor klanten en medewerkers met statusinformatie die uit alle drie contexten kwam, maar zonder dat één context de anderen hoefde te kennen.

In drie maanden draaide Intake los van de rest in productie. Het read model gaf realtime inzicht, waardoor veel statusmails wegvielen. Assessment volgde twee maanden later, met canary releases per productlijn. Payout bleef vier maanden langer in de monoliet vanwege auditvereisten. Resultaten na 9 maanden: gemiddelde wachttijd omlaag naar 36 uur, 40 procent minder calls naar het contactcenter, en een daling van 30 procent in “onzachte” escalaties. De codebase groeide niet noemenswaardig, maar de verdeling veranderde. Minder conditionele spaghetti, meer expliciete events. De teams rapporteerden bovendien een kortere doorlooptijd voor regelwijzigingen, van gemiddeld 15 naar 6 dagen.

Wanneer DDD juist doorslaggevend is

DDD voegt de meeste waarde toe wanneer:

  • je domein rijk is aan regels, uitzonderingen en veranderende wetgeving;
  • integratie met externe partijen cruciaal is en de semantiek van berichten al jaren omstreden is;
  • meerdere teams tegelijk aan aangrenzende onderdelen werken en elkaar nu ophouden;
  • rapportage en analytics worden belemmerd door ambiguïteit over definities.

Koppel dit aan een volwassen DevOps‑omgeving en je hebt een vliegwiel. Teams bouwen waar ze over gaan, zien eerder waar semantiek schuurt en vangen problemen op in design, niet in incidentmanagement.

Praktisch beginnen zonder de boel op zijn kop te zetten

Kies een klein, zichtbaar domein met echte pijn. Organiseer een event storming met mensen die het werk doen en mensen die de knoppen hebben. Leg de taal vast in code, niet alleen in Confluence. Waak voor generieke frameworks die je taal verstoppen. Publiceer één of twee betekenisvolle events met versiebeheer en observeer wie ze consumeert. Richt monitoring in die business events volgt, zoals “OrderPaid” of “ClaimApproved”, en koppel metrics aan doelen die ertoe doen.

Betrek nearshore teams in dezelfde ritmes en rituelen, zodat je geen taalbreuk over de grens creëert. Laat IT Recruitment sturen op domeinaffiniteit en leervermogen. En laat je platformteam vooral dingen bouwen die de contexten versterken: eenvoud in provisioning, goede observability, betrouwbare messaging. Technologie is het podium. Het stuk dat je speelt is het domein. Als dat klopt, wordt complexe software weer maakbaar.