Skip to main content

Roodkapje in UML diagrammen

Een zachte landing en introductie in UML diagrammen*

Roodkapje in het bos

Figuur 1: Roodkapje in het bos (afbeelding gegenereerd met ChatGPT op basis van origineel kunstwerk door IndividualDesign, DeviantArt, 2025).


Dit voorbeeld toont hoe je een verhaal in natuurlijke taal (het sprookje van Roodkapje) kunt vertalen naar formele diagrammen; namelijk UML diagrammen. In die zin is het een prima introductie van (enkele) UML diagrammen voor niet technici om een beeld te krijgen, of beginnende technici.

We splitsen het verhaal op in drie delen om een "God Diagram" te voorkomen. Een God diagram is een anti-pattern (net als een 'God object' dat is). Het opsplitsen is een best practice om 'cognitive load' te voorkomen. Om wel ook het overzicht te geven maak je weer een apart diagram, die de onderlinge verbanden aangeeft. Dit is vergelijkbaar met hoe in C4 er ook verschillende zoomniveaus zijn.

In dit artikel gebruiken we voor de drie fasen van het verhaal een toenemend detailniveau: fase A gebruikt berichten als natuurlijke taal, fase B schakelt over naar methode-aanroepen, en fase C voegt daar loops en een Factory pattern aan toe. Dit is een didactische keuze om verschillende notaties te demonstreren in één artikel. In de praktijk van softwareontwikkeling werk je anders: je houdt alle delen op hetzelfde detailniveau, en voegt aan alle delen tegelijk meer detail toe naarmate je vordert in de Software Development Life Cycle. Tijdens de analyse modelleer je alle fasen met berichten, tijdens het ontwerp alle fasen met methoden, enzovoort.


Er was eens...

Voordat we het verhaal in sequentiediagrammen vertellen, definiëren we eerst de "wereld" van het sprookje in een domeinmodel. Dit is vergelijkbaar met hoe je in software eerst je domeinmodel opstelt voordat je de use cases uitwerkt.

We gebruiken hier een domeinmodel in de stijl van Larman: focus op de entiteiten (concepten) en hun attributen, zonder methodes en zonder expliciete types. Bij twijfel of iets een primitief attribuut is of een eigen entiteit verdient, kies je voor een aparte entiteit. Business-activiteiten (zoals "eet op") mogen als relatie worden weergegeven.

Roodkapje: Domeinmodel (Larman-stijl)

PlantUML broncode voor "Roodkapje: Domeinmodel (Larman-stijl)"
@startuml
!theme plain
title Er was eens... het domeinmodel van Roodkapje

class Roodkapje {
naam
heeftRoodKapje
}

class Moeder {
naam
}

class Oma {
naam
ziek
}

class Wolf {
honger
vermomming
}

class Jager {
naam
}

class Mandje {
inhoud
}

class Huis {
locatie
}

class Steen {
gewicht
}

Moeder --> Roodkapje : is moeder van
Moeder --> Mandje : geeft
Roodkapje --> Mandje : draagt
Roodkapje --> Oma : bezoekt
Oma --> Huis : woont in
Wolf --> Oma : eet op
Wolf --> Roodkapje : eet op
Jager --> Wolf : opent buik van
Jager --> Steen : verzamelt
Wolf --> "0..*" Steen : krijgt in buik

note "Relaties veranderen\ntijdens het verhaal!" as N1

@enduml

Klassendiagram met 8 klasse(n) en 10 relatie(s).

Klassen:

  • Klasse Roodkapje met:
    • publieke attribuut 'naam'
    • publieke attribuut 'heeftRoodKapje'
    • geen methoden
  • Klasse Moeder met:
    • publieke attribuut 'naam'
    • geen methoden
  • Klasse Oma met:
    • publieke attribuut 'naam'
    • publieke attribuut 'ziek'
    • geen methoden
  • Klasse Wolf met:
    • publieke attribuut 'honger'
    • publieke attribuut 'vermomming'
    • geen methoden
  • Klasse Jager met:
    • publieke attribuut 'naam'
    • geen methoden
  • Klasse Mandje met:
    • publieke attribuut 'inhoud'
    • geen methoden
  • Klasse Huis met:
    • publieke attribuut 'locatie'
    • geen methoden
  • Klasse Steen met:
    • publieke attribuut 'gewicht'
    • geen methoden

Relaties:

  • Moeder heeft een associatie-relatie met naam 'is moeder van' met Roodkapje
  • Moeder heeft een associatie-relatie met naam 'geeft' met Mandje
  • Roodkapje heeft een associatie-relatie met naam 'draagt' met Mandje
  • Roodkapje heeft een associatie-relatie met naam 'bezoekt' met Oma
  • Oma heeft een associatie-relatie met naam 'woont in' met Huis
  • Wolf heeft een associatie-relatie met naam 'eet op' met Oma
  • Wolf heeft een associatie-relatie met naam 'eet op' met Roodkapje
  • Jager heeft een associatie-relatie met naam 'opent buik van' met Wolf
  • Jager heeft een associatie-relatie met naam 'verzamelt' met Steen
  • Wolf heeft een associatie-relatie met naam 'krijgt in buik' met Steen, multipliciteit 0..*

Glossary: De entiteiten van het sprookje

EntiteitOmschrijving
RoodkapjeHet meisje met het rode kapje, hoofdpersoon
MoederDe moeder van Roodkapje die haar op pad stuurt
OmaDe grootmoeder die ziek in bed ligt
WolfDe antagonist die Oma en Roodkapje opeet
JagerDe held die Roodkapje en Oma redt
MandjeContainer met eten voor Oma
HuisDe woning van Oma, diep in het bos
SteenObjecten waarmee de Wolf wordt gestraft
Domeinmodellering: abstractie en overerving

In dit beginnersvriendelijke model tonen we alle entiteiten op hetzelfde abstractieniveau. In een meer verfijnd model zouden we opmerken dat Roodkapje en Oma eigenlijk beide instanties van een gemeenschappelijke superklasse Mens (of Person) zouden kunnen zijn. Hetzelfde geldt voor Wolf en mogelijk Jager - beide zijn levende wezens met bepaalde eigenschappen. Dit illustreert een belangrijke les in domeinmodellering: je kunt entiteiten groeperen onder abstractere concepten.

In dit geval hebben we bewust voor een flat structuur gekozen omdat het verhaal meer gaat over wie interacteert met wie dan over hun taxonomische classificatie. De gedetailleerde Fowler-stijl versie in Bijlage A gaat hier dieper op in.

Opmerking over voorbeelden: In een productieomgeving zou de Glossary concrete voorbeelden bevatten, zoals Roodkapje { naam: "Little Red", heeftRoodKapje: true }. Dit helpt ontwikkelaars en domeinexperts om het data format en mogelijke waarden te begrijpen. Voor dit educatieve voorbeeld hebben we die weggelaten om de focus op de relaties tussen entiteiten te houden.

Larman vs. Fowler: twee stijlen van domeinmodelleren

Dit eenvoudige model volgt de Larman-stijl: alleen entiteiten en attributen, geschikt voor de analysefase en communicatie met domeinexperts. In Bijlage A vind je hetzelfde model in de Fowler-stijl: met methodes, types en meer technisch detail, geschikt voor de ontwerpfase.

De keuze tussen beide stijlen hangt af van je doelgroep en de fase in de Software Development Life Cycle. Voor validatie met een domeinexpert (zoals de verteller van het sprookje) is Larman-stijl leesbaarder. Voor een developer die de code gaat schrijven is Fowler-stijl informatiever.


Waarom opsplitsen?

Een groot sequentiediagram met alle interacties wordt snel onoverzichtelijk. Net als bij code geldt het Single Responsibility Principle: elk diagram beschrijft één fase of scenario. Dit maakt de diagrammen:

  • Leesbaar - Elk diagram past op één scherm
  • Onderhoudbaar - Wijzigingen raken alleen het relevante deel
  • Testbaar - Elk deel kan apart geverifieerd worden

Overzichtsdiagram: De drie fasen

Eerst een activity diagram dat de hoofdlijnen van het verhaal toont:

Roodkapje: Overzicht van de drie fasen

PlantUML broncode voor "Roodkapje: Overzicht van de drie fasen"
@startuml
!theme plain
title Roodkapje - Overzicht

start
:Moeder geeft opdracht;
note right: Breng mandje naar oma

partition "A: Reis naar oma" {
:Roodkapje vertrekt;
:Ontmoeting met wolf;
:Wolf rent vooruit;
}

partition "B: Bij oma's huis" {
:Wolf eet oma op;
:Wolf vermomt zich;
:Roodkapje arriveert;
:Wolf eet Roodkapje op;
}

partition "C: De redding" {
:Jager arriveert;
:Jager bevrijdt oma en Roodkapje;
:Wolf wordt gestraft;
}

stop
@enduml

Activiteitendiagram met 3 partities en 11 activiteiten.

Flow:

  • Start
  • Stap. Moeder geeft opdracht
  • Partitie A: Reis naar oma, bestaande uit:
  • Stap. Roodkapje vertrekt
  • Stap. Ontmoeting met wolf
  • Stap. Wolf rent vooruit
  • Einde partitie A.
  • Partitie B: Bij oma's huis, bestaande uit:
  • Stap. Wolf eet oma op
  • Stap. Wolf vermomt zich
  • Stap. Roodkapje arriveert
  • Stap. Wolf eet Roodkapje op
  • Einde partitie B.
  • Partitie C: De redding, bestaande uit:
  • Stap. Jager arriveert
  • Stap. Jager bevrijdt oma en Roodkapje
  • Stap. Wolf wordt gestraft
  • Einde partitie C.
  • Stop

We gebruiken hier een activity diagram voor het overzicht omdat:

  • Het de volgorde van fasen toont (flow)
  • Partities de drie delen duidelijk scheiden
  • Het abstracter is dan een sequence diagram (geen objecten/methodes)

Voor een gedragsbrug tussen dit klasse-/domeinperspectief en de sequentiediagrammen in fase A, B en C, zie Bijlage C: Use case diagram.


Fase A: De reis naar oma

Roodkapje krijgt de opdracht om een mandje naar oma te brengen en ontmoet onderweg de wolf.

Fase A: Reis naar oma

PlantUML broncode voor "Fase A: Reis naar oma"
@startuml
hide footbox
title Fase A: De reis naar oma

autonumber

actor "Moeder" as Moeder
participant "Roodkapje" as RK
participant "Wolf" as Wolf
participant "Oma" as Oma

== Vertrek ==

Moeder -> RK: "Hier lieverd, neem dit mandje\nmet koekjes en wijn"
Moeder -> RK: "Breng dit naar oma,\nen blijf op het pad!"
RK -> RK: "Ik ga op weg"

== Ontmoeting in het bos ==

Wolf -> RK: "Goedendag, waar ga je heen?"
RK --> Wolf: "Naar oma's huis,\ndiep in het bos"
Wolf -> Wolf: "Hmm, ik neem\nde korte weg..."

@enduml

Sequentiediagram met 4 deelnemers: Moeder, Roodkapje, Wolf en Oma.

Interacties:

  1. Moeder roept Roodkapje.Hier lieverd, neem dit mandje\nmet koekjes en wijn() aan
  2. Moeder roept Roodkapje.Breng dit naar oma,\nen blijf op het pad!() aan
  3. Roodkapje roept Roodkapje.Ik ga op weg() aan
  4. Wolf roept Roodkapje.Goedendag, waar ga je heen?() aan
  5. Roodkapje antwoordt Wolf: 'Naar oma's huis,\ndiep in het bos'
  6. Wolf roept Wolf.Hmm, ik neem\nde korte weg...() aan

Toelichting bij fase A: Message Passing

In dit diagram gebruiken we bewust strings als berichten in plaats van methode-aanroepen. Dit sluit aan bij hoe Alan Kay, de bedenker van objectgeoriënteerd programmeren, OO oorspronkelijk bedoelde: objecten die berichten naar elkaar sturen, niet objecten die elkaars methoden aanroepen.

Van message passing naar event-driven architectuur

Dit "message passing" paradigma zie je terug in moderne event-driven microservices. Vergelijk:

AanpakVoorbeeldKoppeling
Message/Event"Klant heeft bestelling afgerond"Loose coupling
Methode/RPCemailService.verstuurBevestiging(klantId, bestelling)Tight coupling

Bij de event-aanpak stuurt de bestelservice alleen een bericht. Een andere service (bijv. EmailBevestigingService) luistert en besluit zelf wat te doen. Bij de RPC-aanpak roept de bestelservice direct een methode aan op de emailservice.

Waarom maakt dit uit?

Stel de mailserver is offline:

  • Event-driven: Een message broker (zoals RabbitMQ of Kafka) bewaart het bericht. Zodra de mailserver weer online is, worden alle wachtende mails alsnog verstuurd. De bestelling gaat gewoon door.
  • RPC: De bestelservice blokkeert. De gebruiker krijgt "Mail werkt even niet, probeer later opnieuw" - terwijl ze gewoon wilden bestellen.

In de volgende fase schakelen we over naar methode-aanroepen, want dat is waar message passing in de praktijk van OO op neerkomt. Maar het is goed om te beseffen dat de intentie van OO dichter bij het eerste ligt.


Fase B: Bij oma's huis

De wolf arriveert als eerste, eet oma op, en vermomt zich. Dan arriveert Roodkapje.

Fase B: Bij oma's huis

PlantUML broncode voor "Fase B: Bij oma's huis"
@startuml
hide footbox
title Fase B: Bij oma's huis

autonumber

participant "Wolf" as Wolf
participant "Oma" as Oma
participant "Roodkapje" as RK

== Wolf arriveert eerst ==

Wolf -> Oma: klop()
Oma --> Wolf: vraagWieDaarIs()
Wolf -> Oma: antwoord("Roodkapje")
Oma -> Oma: openDeur()
Wolf -> Oma: eetOp()
destroy Oma
note right: Oma is opgegeten

Wolf -> Wolf: vermom(alsOma)
Wolf -> Wolf: gaInBed()

== Roodkapje arriveert ==

RK -> Wolf: klop()
Wolf --> RK: nodigBinnen()
RK -> Wolf: vraagOverOgen()
Wolf --> RK: geefAntwoord("zien")
RK -> Wolf: vraagOverOren()
Wolf --> RK: geefAntwoord("horen")
RK -> Wolf: vraagOverMond()
Wolf --> RK: geefAntwoord("opeten!")

Wolf -> RK: eetOp()
destroy RK
note right: Roodkapje is opgegeten

@enduml

Sequentiediagram met 3 deelnemers: Wolf, Oma en Roodkapje.

Interacties:

  1. Wolf roept Oma.klop() aan
  2. Oma antwoordt Wolf: vraagWieDaarIs()
  3. Wolf roept Oma.antwoord("Roodkapje") aan
  4. Oma roept Oma.openDeur() aan
  5. Wolf roept Oma.eetOp() aan
  6. Wolf roept Wolf.vermom(alsOma) aan
  7. Wolf roept Wolf.gaInBed() aan
  8. Roodkapje roept Wolf.klop() aan
  9. Wolf antwoordt Roodkapje: nodigBinnen()
  10. Roodkapje roept Wolf.vraagOverOgen() aan
  11. Wolf antwoordt Roodkapje: geefAntwoord("zien")
  12. Roodkapje roept Wolf.vraagOverOren() aan
  13. Wolf antwoordt Roodkapje: geefAntwoord("horen")
  14. Roodkapje roept Wolf.vraagOverMond() aan
  15. Wolf antwoordt Roodkapje: geefAntwoord("opeten!")
  16. Wolf roept Roodkapje.eetOp() aan

Toelichting bij fase B: Van berichten naar methoden

In dit diagram schakelen we over naar methode-aanroepen. Vergelijk met fase A:

Fase A (berichten)Fase B (methoden)
"Goedendag, waar ga je heen?"vraagWieDaarIs()
"Naar oma's huis"antwoord("Roodkapje")

Beide notaties zijn valide UML. De keuze hangt af van je doel:

  • Berichten (strings): Goed voor communicatie met domeinexperts, leest als een verhaal
  • Methoden: Goed voor developers, toont de technische interface

In de praktijk van OO-programmeren is een methode-aanroep een bericht. Wanneer je wolf.eetOp(oma) schrijft, stuur je het bericht "eetOp" naar het object wolf met oma als parameter. Het object besluit zelf hoe het reageert - dat is encapsulation.

De bekende dialoog als herhalend patroon

De "grote ogen/oren/mond" dialoog toont een interessant patroon:

RK -> Wolf: vraagOverX()
Wolf --> RK: geefAntwoord(doel)

Dit is een request-response patroon dat drie keer herhaald wordt. In code zou je dit kunnen generaliseren:

String[] lichaamsdelen = {"ogen", "oren", "mond"};
String[] doelen = {"zien", "horen", "opeten!"};

for (int i = 0; i < lichaamsdelen.length; i++) {
roodkapje.vraagOver(lichaamsdelen[i]);
wolf.geefAntwoord(doelen[i]);
}

Andere UML-keywords in dit diagram:

  • destroy toont dat een actor "verdwijnt" (opgegeten)
  • Self-calls (vermom, gaInBed) tonen interne acties van de Wolf

Bewust niet refactoren: leesbaar vs. generiek

Je zou de drie vraagOverOgen(), vraagOverOren(), vraagOverMond() methoden kunnen refactoren naar één generieke functie:

void vraagOver(Lichaamsdeel ld)

En Roodkapje zou een zie(Lichaamsdeel): Grootte methode kunnen krijgen. Dan zou je zelfs een OrenFactory en TandenFactory kunnen bedenken, en via dependency injection verschillende groottes oren en tanden toewijzen aan een Aggregate mond van de Wolf respectievelijk Oma. Op basis daarvan had Roodkapje wellicht wat proactiever kunnen reageren in plaats van opgegeten te worden.

Wanneer wel, wanneer niet refactoren?

Dit is een klassiek spanningsveld in software design. Een generieke oplossing is flexibeler, maar minder leesbaar voor domeinexperts. De "rule of three" suggereert: refactor pas als je drie keer dezelfde code hebt. Hier hebben we precies drie vragen - op de grens dus.

Voor een sprookje (en voor communicatie met stakeholders) is de expliciete notatie leesbaarder. Voor een technisch ontwerp zou je wellicht wel generaliseren.

In fase C gaan we juist de andere kant op: we voegen meer detail toe, inclusief een nieuwe klasse die niet in het oorspronkelijke domeinmodel stond.


Fase C: De redding

De jager hoort gesnurk, onderzoekt de situatie en bevrijdt Roodkapje en oma.

Fase C: De redding

PlantUML broncode voor "Fase C: De redding"
@startuml
hide footbox
title Fase C: De redding

autonumber

actor "Jager" as Jager
participant "Wolf" as Wolf
participant "Roodkapje" as RK
participant "Oma" as Oma
participant "StenenFactory" as SF

== Ontdekking ==

Jager -> Jager: hoort(hardGesnurk)
Jager -> Jager: besluit(onderzoeken)
Jager -> Wolf: gaHuisBinnen()

note over Jager, Wolf: Jager ziet Wolf\nmet dikke buik

== Bevrijding ==

Jager -> Wolf: knipBuikOpen()

create RK
Wolf --> RK: <<bevrijd>>
create Oma
Wolf --> Oma: <<bevrijd>>

RK --> Jager: bedank()
Oma --> Jager: bedank()

== Straf: Stenen verzamelen ==

create SF
Jager -> SF: new StenenFactory(bos)

loop totdat Jager.kanNietMeerDragen()
Jager -> SF: zoekSteen()
SF --> Jager: steen
Jager -> Jager: pakOp(steen)
end

== Straf: Wolf vullen ==

Jager -> Wolf: openBuik()
loop voor elke steen in verzameling
Jager -> Wolf: stopSteenInBuik(steen)
end
Jager -> Wolf: naai(buikDicht)

destroy SF

Wolf -> Wolf: probeertTeVluchten()
Wolf -> Wolf: valt(omEnSterft)
destroy Wolf

@enduml

Sequentiediagram met 5 deelnemers: Jager, Wolf, Roodkapje, Oma en StenenFactory.

Interacties:

  1. Jager roept Jager.hoort(hardGesnurk) aan
  2. Jager roept Jager.besluit(onderzoeken) aan
  3. Jager roept Wolf.gaHuisBinnen() aan
  4. Jager roept Wolf.knipBuikOpen() aan
  5. Wolf antwoordt Roodkapje: <>
  6. Wolf antwoordt Oma: <>
  7. Roodkapje antwoordt Jager: bedank()
  8. Oma antwoordt Jager: bedank()
  9. Jager roept StenenFactory.new StenenFactory(bos) aan
  10. Jager roept StenenFactory.zoekSteen() aan
  11. StenenFactory antwoordt Jager: steen
  12. Jager roept Jager.pakOp(steen) aan
  13. Jager roept Wolf.openBuik() aan
  14. Jager roept Wolf.stopSteenInBuik(steen) aan
  15. Jager roept Wolf.naai(buikDicht) aan
  16. Wolf roept Wolf.probeertTeVluchten() aan
  17. Wolf roept Wolf.valt(omEnSterft) aan

Toelichting bij fase C: Meer detail en nieuwe klassen

In dit diagram gaan we de andere kant op dan in fase B: we voegen meer detail toe. Dit illustreert een belangrijk punt over modelleren.

De StenenFactory: een klasse die niet in het domeinmodel stond

De StenenFactory is een nieuwe participant die niet in ons oorspronkelijke domeinmodel voorkomt. Dit is realistisch: tijdens het uitwerken van use cases ontdek je vaak dat je extra klassen nodig hebt.

In Domain-Driven Design zou je dit een Domain Service kunnen noemen - een klasse die gedrag modelleert dat niet natuurlijk bij één entity hoort. Het "zoeken van stenen in het bos" hoort niet bij de Jager, niet bij de Wolf, maar is een apart concept.

De loop-constructie in UML

PlantUML ondersteunt een loop constructie:

loop totdat conditie
... acties ...
end

Dit is equivalent aan een while loop in code:

while (!jager.kanNietMeerDragen()) {
Steen steen = stenenFactory.zoekSteen();
jager.pakOp(steen);
}

Twee loops, twee doelen

We gebruiken twee loops:

  1. Verzamelen: loop totdat Jager.kanNietMeerDragen() - een while-loop met conditie
  2. Vullen: loop voor elke steen in verzameling - een foreach-loop

Dit toont dat je verschillende loop-types kunt modelleren in UML.

Factory pattern

De StenenFactory illustreert het Factory pattern: een object dat verantwoordelijk is voor het creëren van andere objecten. De Jager hoeft niet te weten hoe stenen gevonden worden, alleen dat de factory ze levert.

// De Jager is ontkoppeld van de details van stenen zoeken
StenenFactory factory = new StenenFactory(bos);
Steen steen = factory.zoekSteen();

Andere UML-keywords in dit diagram:

  • create toont dat Roodkapje en Oma "terugkomen", en dat de StenenFactory wordt geïnstantieerd
  • destroy verwijdert de StenenFactory (niet meer nodig) en de Wolf (einde verhaal)
  • loop toont herhalende acties met een conditie

Alternatief: Overzicht als sequence diagram

Als alternatief voor het activity diagram kunnen we ook een high-level sequence diagram maken. Dit is abstracter en toont alleen de hoofdinteracties:

Roodkapje: Overzicht als sequence diagram

PlantUML broncode voor "Roodkapje: Overzicht als sequence diagram"
@startuml
hide footbox
title Roodkapje - Hoofdlijnen

participant "Roodkapje" as RK
participant "Wolf" as Wolf
participant "Oma" as Oma
actor "Jager" as Jager

== A: Reis naar oma ==
RK -> Wolf: ontmoeting in bos
Wolf --> RK: vraagt naar bestemming

== B: Bij oma's huis ==
Wolf -> Oma: eet op
Wolf -> RK: eet op

== C: De redding ==
Jager -> Wolf: opent buik
Jager --> RK: bevrijdt
Jager --> Oma: bevrijdt
RK -> Wolf: straft met stenen

@enduml

Sequentiediagram met 4 deelnemers: Roodkapje, Wolf, Oma en Jager.

Interacties:

  • Roodkapje roept Wolf.ontmoeting in bos() aan
  • Wolf antwoordt Roodkapje: 'vraagt naar bestemming'
  • Wolf roept Oma.eet op() aan
  • Wolf roept Roodkapje.eet op() aan
  • Jager roept Wolf.opent buik() aan
  • Jager antwoordt Roodkapje: bevrijdt
  • Jager antwoordt Oma: bevrijdt
  • Roodkapje roept Wolf.straft met stenen() aan

Wanneer welk diagram?

DiagramGebruik
Activity diagramToont flow en beslissingen, goed voor processtappen
Sequence diagramToont interacties tussen objecten/actoren in tijd

Voor het overzicht werkt het activity diagram beter omdat:

  • Het de fasen als blokken toont (partities)
  • Het geen objecten nodig heeft op dit abstractieniveau
  • De volgorde visueel duidelijker is

Les: Vermijd het "God Diagram"

Net als bij software design willen we geen "God Object" dat alles doet. Een diagram met 50+ interacties is:

  1. Onleesbaar - Te veel om in één keer te bevatten
  2. Ononderhoudbaar - Elke wijziging raakt het hele diagram
  3. Onbruikbaar - Voor screenreaders is zo'n diagram niet toegankelijk te maken

Door het verhaal op te splitsen in A, B en C krijgen we:

  • Elk diagram beschrijft één fase
  • Makkelijk te begrijpen en uit te leggen
  • Beter te vertalen naar toegankelijke beschrijvingen

Dit principe geldt ook voor softwarediagrammen: splits complexe flows op in deelscenario's!


En ze ontwierpen en documenteerden nog lang en gelukkig

We hopen dat dit voorbeeld je laat inzien dat zowel natuurlijke taal als formele diagrammen hun plaats hebben in softwareontwikkeling. Er is geen "beste" notatie - het hangt af van:

De fase in de Software Development Life Cycle (SDLC)

FaseVoorkeurWaarom
RequirementsNatuurlijke taal, User StoriesCommunicatie met stakeholders
AnalyseDomain Stories, Use CasesBegrip van het probleemdomein
OntwerpUML-diagrammen, C4Precieze specificatie voor developers
ImplementatieCode (de ultieme formele taal)Uitvoerbaar door machines
DocumentatieMix van beideAfhankelijk van de doelgroep

De doelgroep

  • Opdrachtgevers en eindgebruikers - Natuurlijke taal, eventueel met Domain Stories
  • Business Analysts - Use Cases, User Stories, acceptatiecriteria
  • Developers - UML-diagrammen, API-specificaties, code
  • Compilers en runtimes - Alleen formele code, geen ambiguïteit toegestaan

Van informeel naar formeel: UML relatietypen

In dit artikel gebruiken we bewust informele UML - eenvoudige lijnen zonder de volledige notatie. Dit sluit aan bij Martin Fowler's concept van "UML as a sketch" (Fowler, 2003): diagrammen als communicatiemiddel, niet als formele blauwdruk. Simon Brown (2019) doet in zijn presentatie "The Lost Art of Software Architecture" zelfs laatdunkend over de klassieke UML-vraag: "Bestaat een auto nog als je de wielen eraf haalt?" - een verwijzing naar het onderscheid tussen aggregatie en compositie.

Toch is het goed om de formele UML-relatietypen te kennen. In het onderwijs Software & Robotics willen we dit als einddoel stellen, onder het motto: "Je kunt de teugels altijd nog laten vieren." Wie de formele notatie kent, kan bewust kiezen voor informeel.

De vier belangrijkste relatietypen

RelatieSymboolBetekenisVoorbeeld
Associatie──────"is dependent on" / "uses"Wolf ── Roodkapje
Aggregatie◇─────"has a" / "contains" (zwak)Mandje ◇── Koekje
Compositie◆─────"consists of" (sterk)Auto ◆── Motor
Implementatie◁·····"implements" / "realizes"MergeSort ◁·· SorteerStrategie
Generalisatie◁─────"is a" / "extends"Wolf ◁── Dier

Het verschil tussen aggregatie en compositie

  • Aggregatie (open diamant ◇): Het deel kan onafhankelijk bestaan van het geheel. Een koekje kan ook buiten het mandje bestaan.
  • Compositie (dichte diamant ◆): Het deel kan niet bestaan zonder het geheel. Een motor bestaat niet los van een auto (in de context van dat domein).
Brown's advies: gebruik een legenda

Simon Brown adviseert om altijd een legenda bij je diagrammen te zetten. Het verschil tussen een open en dichte diamant vergeet je snel, en tijdens overleg met opdrachtgevers of domeinexperts wil je geen tijd verspillen aan notatie-discussies. Een simpele legenda voorkomt verwarring.

Wanneer formeel, wanneer informeel?

ContextAanbeveling
Analysefase met domeinexpertsInformeel - focus op begrip, niet op notatie
Ontwerpfase voor developersFormeel waar het ertoe doet (eigenaarschap, lifecycle)
Code review / documentatieInformeel met legenda - snel te begrijpen
Genereren vanuit codeFormeel - tools kunnen dit automatisch

Het is ook goed om een versie zonder implementatiedetails te maken voor validatie met domeinexperts die minder van ICT weten. De vraag of een mandje "eigenaar" is van koekjes is voor een bakker irrelevant - maar voor een developer die garbage collection moet begrijpen wel.

Verdere verdieping: A short personal history of Continuous Documentation

Dit inzicht is niet nieuw. Enkele klassieke bronnen, chronologisch geordend:

Drie fasen van documentatie: Knowledge Acquisition, Building en Transfer

Figuur 1: Drie fasen van documentatie: Knowledge Acquisition, Building en Transfer (Theunissen, 2022, Figure 8.1).

  • Reeves (1992) schreef het baanbrekende artikel dat stelt dat code het échte ontwerp is, niet de diagrammen. Zijn belangrijkste inzicht: source code is NIET het product, maar het plan ( de uit dit "plan" gecompileerde binary code die runt op hardware is het product).
  • Fowler (2003) introduceerde in "UML Distilled" het concept van "UML as sketch" versus "UML as blueprint" - diagrammen als communicatiemiddel, niet als formele specificatie
  • Brown (2011) introduceerde het C4 model als informele benadering voor software architectuur visualisatie, met nadruk op uit- en inzoomen tussen abstractieniveaus. UML wordt omarmd voor Code-diagrammen op laag niveau, maar ook code zelf behoudt recht van bestaan als ontwerp van de uiteindelijke runnende applicatie
  • Patton (2014) beschreef hoe je User Stories gebruikt om verhalen te vertellen in Agile
  • Mijn collega Theo Theunissen (2022) onderzocht documentatie in continuous software development. Een van zijn meest opvallende conclusies: developers beschrijven in commit messages vaak te veel WAT ze wijzigen en te weinig WAAROM - een analogie met ADR's als log van beslissingen met rationales
  • Van der Wal (2025) schreef voor de minor DevOps een stuk over domeinmodellen: hoe er verschillende versies zijn in de Analyse- vs. Ontwerp-fase, hoe de double diamond techniek uit Design Thinking deze opsplitsing tussen probleemdomein (analyse) en oplossingsdomein (ontwerp) ook al maakte, en hoe je een groot diagram kunt opdelen in verschillende contexten (probleemdomein) respectievelijk subdomeinen (oplossingsdomein) (e.g. de Context mapping pattern uit Domain Driven Design)

Context Mapping voorbeeld met upstream en downstream bounded contexts

Figuur 2: Context Mapping toont relaties tussen bounded contexts in Domain-Driven Design (Brandolini, 2009, Figure 14).

De les van Reeves

Het artikel van Reeves (1992) is bijzonder relevant: hij betoogt dat high-level programmeertalen slechts een stap zijn in een spectrum. De "echte" code is machinetaal - alles daarboven is een vorm van ontwerp. Dit betekent:

  1. Diagrammen zijn ontwerp op hoog abstractieniveau
  2. High-level code (Java, Python, TypeScript) is ontwerp op lager niveau
  3. Machinetaal is de uiteindelijke implementatie

Daarom is het essentieel om te leren hoe je high-level programmeertalen zo schrijft dat ze aansluiten bij het ontwerp. De code moet het verhaal vertellen - net zoals dit sprookje van Roodkapje.

Tot slot

Net als Roodkapje uiteindelijk veilig thuiskwam, hopen wij dat jij na het lezen van dit voorbeeld:

  • Begrijpt wanneer je natuurlijke taal gebruikt en wanneer formele diagrammen
  • Weet hoe je grote verhalen opsplitst in beheersbare delen
  • Inziet dat code óók een vorm van storytelling is
  • Klaar bent om je eigen softwareverhalen te vertellen - toegankelijk voor iedereen

En toen...

"Ze leefden nog lang en gelukkig" is een fijn einde, maar geeft weinig aangrijpingspunten voor een goed verhaal. Wat gebeurt er ná "en ze leefden nog lang en gelukkig"? In software termen: wat gebeurt er ná de eerste release?

Specificeren en valideren: het verhaal gaat door

Het doel van de meeste softwareproducten is de gebruiker gelukkig te maken. Maar hoe weet je of je gebruiker écht gelukkig is? Hier komen specificatie en validatie om de hoek kijken:

ActiviteitVraagMethode
Specificeren"Wat willen we bouwen?"User Stories, Use Cases, Acceptance Criteria
Valideren"Hebben we het goede gebouwd?"User testing, A/B testing, feedback loops
Verifiëren"Hebben we het goed gebouwd?"Unit tests, integration tests, code reviews

Net als bij Roodkapje: het verhaal eindigt niet bij "en ze leefden nog lang en gelukkig". Oma heeft misschien PTSS, de Wolf heeft familie die wraak wil, en Roodkapje overweegt een carrière als jager. Het échte werk begint pas ná de eerste versie.

De rule of three en het hogere waarom

Het Roodkapje-verhaal bevat een klassiek patroon: de rule of three. "Wat grote ogen heb je!" - "Wat grote oren heb je!" - "Wat een grote mond heb je!" Dit lijkt irrelevant detail, maar is juist de punchline die het verhaal memorabel maakt.

Overigens is onze opsplitsing van het sprookje in drie hoofddelen (A, B, C) vrij arbitrair - het zegt meer over de menselijke neiging tot driedeling dan over een strikte analyse van het verhaal. Maar dat is precies het punt: elk willekeurig maar consistent scheidingsmodel draagt al snel bij aan complexiteitsvermindering in systemen en documentatie. Het gaat om het splitsen zelf, niet om de "perfecte" indeling.

Op een hoger niveau raakt dit aan waarom we überhaupt verhalen vertellen: mensen zijn sociale wezens die graag verhalen delen en verbinding zoeken. Software kan dit ondersteunen - of uitbuiten. Social media platforms beloven verbinding, maar houden ons met shorts en lieve kattenvideo's afgeleid van een echt sociaal leven.

Doctorow (2023) noemt dit enshittification: platforms die eerst waarde creëren voor gebruikers, dan voor adverteerders, en uiteindelijk alleen voor zichzelf. Economisch onderzoek (Dubner, 2024) toont dat veel gebruikers zouden betalen om platforms als Facebook te laten verdwijnen. Meer beschouwing op dit ethisch perspectief, in mijn persoonlijke blog: Weg van Facebook.

Het echte einde

"En ze ontwierpen en documenteerden nog lang en gelukkig..."

steeds validerend of hun gebruikers nog steeds gelukkig waren - wetende dat 'lang en gelukkig' geen eindtoestand is, maar een continu proces van luisteren, aanpassen en verbeteren.


Over dit artikel

Dit artikel is geschreven door Bart van der Wal met Claude (Anthropic) als co-auteur. Claude hielp bij het structureren van de inhoud, het genereren van de PlantUML-diagrammen, en het formuleren van de filosofische beschouwingen. Maar ik (Bart) ben eindverantwoordelijk voor de inhoud.

Feedback welkom

eedback over eventuele fouten of onduidelijkheden zeer welkom. Meld issues via GitHub of neem contact op.


Bronnen


Bijlagen

Bijlage A: Gedetailleerd domeinmodel (Fowler-stijl)

In de hoofdtekst gebruikten we een eenvoudig domeinmodel in Larman-stijl. Hieronder hetzelfde model in Fowler-stijl: met methodes, expliciete types en meer technisch detail. Dit is geschikt voor de ontwerpfase en communicatie met developers.

Roodkapje: Domeinmodel (Fowler-stijl)

PlantUML broncode voor "Roodkapje: Domeinmodel (Fowler-stijl)"
@startuml
!theme plain
title Domeinmodel van Roodkapje (Fowler-stijl)

class Roodkapje {
-naam: String = "Roodkapje"
-heeftKapje: boolean = true
+vertrek()
+klop()
+vraag(tekst: String)
+haalStenen(): Steen[]
}

class Moeder {
-naam: String
+geefMandje(inhoud: Object[]): Mandje
+geefOpdracht(tekst: String)
}

class Mandje {
-koekjes: Koekje[]
-wijn: Fles
}

class Wolf {
-honger: boolean = true
-vermomming: String = null
+vraag(tekst: String): String
+bedenktPlan()
+neem(route: Route, bestemming: Locatie)
+vermom(als: Persoon)
+eetOp(slachtoffer: Persoon)
+gaInBed()
}

class Oma {
-naam: String
-ziek: boolean = true
+openDeur()
}

class Jager {
-schaar: Schaar
+hoort(geluid: String)
+besluit(actie: String)
+knipBuikOpen(wolf: Wolf)
+naai(buik: String)
}

class Huis {
-locatie: String = "diep in het bos"
-heeftBed: boolean = true
}

class Steen {
-gewicht: int
}

Moeder --> Roodkapje : is moeder van
Roodkapje --> Mandje : draagt
Oma --> Huis : woont in
Wolf --> Oma : bezoekt
Wolf --> Oma : eet op
Wolf --> Roodkapje : ontmoet
Wolf --> Roodkapje : eet op
Jager --> Wolf : opent buik van
Jager --> "0..*" Steen : stopt in wolf

note "De relaties veranderen\ntijdens het verhaal!" as N1

@enduml

Klassendiagram met 8 klasse(n) en 9 relatie(s).

Klassen:

  • Klasse Roodkapje met:
    • publieke methode 'vertrek', zonder parameters, return type void
    • publieke methode 'klop', zonder parameters, return type void
    • publieke methode 'vraag', met parameter(s) 'tekst' van type String, return type void
    • publieke methode 'haalStenen', zonder parameters, return type Steen[]
    • private attribuut 'naam' van type String = "Roodkapje"
    • private attribuut 'heeftKapje' van type boolean = true
  • Klasse Moeder met:
    • publieke methode 'geefMandje', met parameter(s) 'inhoud' van type Object[], return type Mandje
    • publieke methode 'geefOpdracht', met parameter(s) 'tekst' van type String, return type void
    • private attribuut 'naam' van type String
  • Klasse Mandje met:
    • private attribuut 'koekjes' van type Koekje Array
    • private attribuut 'wijn' van type Fles
    • geen methoden
  • Klasse Wolf met:
    • publieke methode 'vraag', met parameter(s) 'tekst' van type String, return type String
    • publieke methode 'bedenktPlan', zonder parameters, return type void
    • publieke methode 'neem', met parameter(s) 'route' van type Route, 'bestemming' van type Locatie, return type void
    • publieke methode 'vermom', met parameter(s) 'als' van type Persoon, return type void
    • publieke methode 'eetOp', met parameter(s) 'slachtoffer' van type Persoon, return type void
    • publieke methode 'gaInBed', zonder parameters, return type void
    • private attribuut 'honger' van type boolean = true
    • private attribuut 'vermomming' van type String = null
  • Klasse Oma met:
    • publieke methode 'openDeur', zonder parameters, return type void
    • private attribuut 'naam' van type String
    • private attribuut 'ziek' van type boolean = true
  • Klasse Jager met:
    • publieke methode 'hoort', met parameter(s) 'geluid' van type String, return type void
    • publieke methode 'besluit', met parameter(s) 'actie' van type String, return type void
    • publieke methode 'knipBuikOpen', met parameter(s) 'wolf' van type Wolf, return type void
    • publieke methode 'naai', met parameter(s) 'buik' van type String, return type void
    • private attribuut 'schaar' van type Schaar
  • Klasse Huis met:
    • private attribuut 'locatie' van type String = "diep in het bos"
    • private attribuut 'heeftBed' van type boolean = true
    • geen methoden
  • Klasse Steen met:
    • private attribuut 'gewicht' van type int
    • geen methoden

Relaties:

  • Moeder heeft een associatie-relatie met naam 'is moeder van' met Roodkapje
  • Roodkapje heeft een associatie-relatie met naam 'draagt' met Mandje
  • Oma heeft een associatie-relatie met naam 'woont in' met Huis
  • Wolf heeft een associatie-relatie met naam 'bezoekt' met Oma
  • Wolf heeft een associatie-relatie met naam 'eet op' met Oma
  • Wolf heeft een associatie-relatie met naam 'ontmoet' met Roodkapje
  • Wolf heeft een associatie-relatie met naam 'eet op' met Roodkapje
  • Jager heeft een associatie-relatie met naam 'opent buik van' met Wolf
  • Jager heeft een associatie-relatie met naam 'stopt in wolf' met Steen, multipliciteit 0..*

Verschil met Larman-stijl

AspectLarman-stijlFowler-stijl
AttributenAlleen naamNaam + type + default waarde
MethodesGeenVolledig met parameters en return types
DoelAnalysefase, domeinexpertsOntwerpfase, developers
Leesbaar voorIedereenTechnisch publiek

De Fowler-stijl is informatiever maar ook complexer. Kies de stijl die past bij je doelgroep en de fase van je project.


Bijlage B: Het "God Diagram" (anti-pattern)

Anti-pattern

Het onderstaande diagram is een anti-pattern. We tonen het hier expliciet om te demonstreren waarom je dit NIET moet doen. Dit is het diagram-equivalent van de tweede situatie die Hoare (1980) beschrijft:

"There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies."

Een "God Diagram" maken is kiezen voor de tweede optie: zo complex dat je eventuele fouten niet meer ziet. Het belandt op de kast, en lezers nemen aan 'Het zal wel kloppen', of als ze wel een fout vinden, denken ze eerder 'dan zal het hele diagram wel niet kloppen', in plaats van de fout te fixen. Voorgaande twee argumenten zijn natuurlijk voorbeelden van (typical) human fallacy. Daar zouden we aan kunnen werken; maar mijn voorstel is om meteen de 'god diagram' neiging als fallacy aan te merken, en dit niet meer te doen, en zo deze secundaire fallacy te proberen te voorkomen.

ANTI-PATTERN: God Diagram met alle fasen

PlantUML broncode voor "ANTI-PATTERN: God Diagram met alle fasen"
@startuml
hide footbox
title ANTI-PATTERN: Roodkapje - God Diagram\n(Doe dit NIET!)

autonumber

actor "Moeder" as Moeder
participant "Roodkapje" as RK
participant "Wolf" as Wolf
participant "Oma" as Oma
actor "Jager" as Jager

== FASE A: Vertrek ==

Moeder -> RK: geefMandje(koekjes, wijn)
Moeder -> RK: "Breng dit naar oma,\nen blijf op het pad!"
RK -> RK: vertrek()

== FASE A: Ontmoeting in het bos ==

Wolf -> RK: "Goedendag, waar ga je heen?"
RK --> Wolf: "Naar oma's huis\nin het bos"
Wolf -> Wolf: bedenktPlan()
note right: Wolf besluit\nkortere weg te nemen
Wolf -> Wolf: neem(kortsteRoute, omasHuis)

== FASE B: Wolf arriveert eerst ==

Wolf -> Oma: klop()
Oma --> Wolf: "Wie is daar?"
Wolf -> Oma: "Roodkapje met koekjes"
Oma -> Oma: openDeur()
Wolf -> Oma: eetOp()
destroy Oma
note right: Oma is opgegeten

Wolf -> Wolf: vermom(alsOma)
Wolf -> Wolf: gaInBed()

== FASE B: Roodkapje arriveert ==

RK -> Wolf: klop()
Wolf --> RK: "Kom binnen, lieverd"
RK -> Wolf: "Oma, wat heb je\ngrote ogen!"
Wolf --> RK: "Om je beter\nte zien"
RK -> Wolf: "Oma, wat heb je\ngrote oren!"
Wolf --> RK: "Om je beter\nte horen"
RK -> Wolf: "Oma, wat heb je\neen grote mond!"
Wolf --> RK: "Om je beter\nop te eten!"

Wolf -> RK: eetOp()
destroy RK
note right: Roodkapje is opgegeten

== FASE C: Ontdekking ==

Jager -> Jager: hoort(hardGesnurk)
Jager -> Jager: besluit(onderzoeken)
Jager -> Wolf: gaHuisBinnen()

note over Jager, Wolf: Jager ziet Wolf\nmet dikke buik

== FASE C: Bevrijding ==

Jager -> Wolf: knipBuikOpen()

create RK
Wolf --> RK: <<bevrijd>>
create Oma
Wolf --> Oma: <<bevrijd>>

RK --> Jager: "Dank u wel!"
Oma --> Jager: "Dank u wel!"

== FASE C: Straf ==

RK -> RK: haal(stenen)
RK -> Wolf: vulBuik(stenen)
Jager -> Wolf: naai(buikDicht)
Wolf -> Wolf: probeertTeVluchten()
Wolf -> Wolf: valt(omEnSterft)
destroy Wolf

@enduml

Sequentiediagram met 5 deelnemers: Moeder, Roodkapje, Wolf, Oma en Jager.

Interacties:

  1. Moeder roept Roodkapje.geefMandje(koekjes, wijn) aan
  2. Moeder roept Roodkapje.Breng dit naar oma,\nen blijf op het pad!() aan
  3. Roodkapje roept Roodkapje.vertrek() aan
  4. Wolf roept Roodkapje.Goedendag, waar ga je heen?() aan
  5. Roodkapje antwoordt Wolf: 'Naar oma's huis\nin het bos'
  6. Wolf roept Wolf.bedenktPlan() aan
  7. Wolf roept Wolf.neem(kortsteRoute, omasHuis) aan
  8. Wolf roept Oma.klop() aan
  9. Oma antwoordt Wolf: 'Wie is daar?'
  10. Wolf roept Oma.Roodkapje met koekjes() aan
  11. Oma roept Oma.openDeur() aan
  12. Wolf roept Oma.eetOp() aan
  13. Wolf roept Wolf.vermom(alsOma) aan
  14. Wolf roept Wolf.gaInBed() aan
  15. Roodkapje roept Wolf.klop() aan
  16. Wolf antwoordt Roodkapje: 'Kom binnen, lieverd'
  17. Roodkapje roept Wolf.Oma, wat heb je\ngrote ogen!() aan
  18. Wolf antwoordt Roodkapje: 'Om je beter\nte zien'
  19. Roodkapje roept Wolf.Oma, wat heb je\ngrote oren!() aan
  20. Wolf antwoordt Roodkapje: 'Om je beter\nte horen'
  21. Roodkapje roept Wolf.Oma, wat heb je\neen grote mond!() aan
  22. Wolf antwoordt Roodkapje: 'Om je beter\nop te eten!'
  23. Wolf roept Roodkapje.eetOp() aan
  24. Jager roept Jager.hoort(hardGesnurk) aan
  25. Jager roept Jager.besluit(onderzoeken) aan
  26. Jager roept Wolf.gaHuisBinnen() aan
  27. Jager roept Wolf.knipBuikOpen() aan
  28. Wolf antwoordt Roodkapje: <>
  29. Wolf antwoordt Oma: <>
  30. Roodkapje antwoordt Jager: 'Dank u wel!'
  31. Oma antwoordt Jager: 'Dank u wel!'
  32. Roodkapje roept Roodkapje.haal(stenen) aan
  33. Roodkapje roept Wolf.vulBuik(stenen) aan
  34. Jager roept Wolf.naai(buikDicht) aan
  35. Wolf roept Wolf.probeertTeVluchten() aan
  36. Wolf roept Wolf.valt(omEnSterft) aan

Waarom is dit een anti-pattern?

  1. Onleesbaar - Zelfs met een relatief eenvoudig verhaal als Roodkapje is het diagram al overweldigend
  2. Geen focus - Je kunt niet zien waar het over gaat zonder het hele diagram te bestuderen
  3. Moeilijk te onderhouden - Elke wijziging raakt potentieel het hele diagram
  4. Niet toegankelijk - Een screenreader kan hier geen bruikbare beschrijving van genereren
  5. Analysis paralysis - Je verdrinkt in de complexiteit

De oplossing: decompositie

De manier om een groot probleem op te lossen (of een uitgebreid verhaal te vertellen) is door het op te splitsen in deelproblemen en elk deelprobleem apart op te lossen. Niet door in één keer een grote oplossing te maken, want dan verdrink je in complexiteit.

De grootste uitdaging is vaak wel de gehele oplossing uiteindelijk te valideren als compositie van je deeloplossingen. Je hebt het extra probleem dat je de deeloplossingen ook goed op elkaar moet laten aansluiten. Je moet een integratietest hebben of zelfs een end-to-end test, naast unit tests voor je onderdelen.

Software Engineering als Design Science

Software Engineering is een Design Science (DS). Dit anti-pattern illustreert het DS-equivalent van het feit dat een goed/nuttig geheel (systeem) meer is dan enkel de som van zijn delen (elementen). Het splitsen in delen is noodzakelijk, maar de kunst is om die delen zo te ontwerpen dat ze samen een coherent geheel vormen.

Of, zoals we in de inleiding stelden: net als bij C4-diagrammen gebruik je verschillende zoomniveaus. Je hebt een overzicht nodig én gedetailleerde views - maar niet alles in één diagram.


Bijlage C: Use case diagram (koppeling tussen klasse en sequentieperspectief)

Dit use case diagram beschrijft WIE dot WAT en vormt zo een soort 'gedragsbrug' tussen het klasse-/domeinmodel en de sequentiediagrammen hierboven. De use cases beschrijven wat actoren willen bereiken; de sequentiediagrammen tonen hoe die interacties in de tijd verlopen.

Roodkapje: Use case diagram

PlantUML broncode voor "Roodkapje: Use case diagram"
@startuml
left to right direction
title Roodkapje - Use case view

actor Moeder
actor Roodkapje as RK
actor Wolf
actor Oma
actor Jager

rectangle "Verhaalwereld" {
usecase "Breng mandje\nnaar oma" as UC1
usecase "Praat met wolf\nin het bos" as UC2
usecase "Ga oma's huis\nbinnen" as UC3
usecase "Vermom als\noma" as UC4
usecase "Bevrijd\nslachtoffers" as UC5
usecase "Straf de wolf" as UC6
}

Moeder --> UC1
RK --> UC1
RK --> UC2
Wolf --> UC2
RK --> UC3
Wolf --> UC3
Wolf --> UC4
Oma --> UC3
Jager --> UC5
RK --> UC5
Oma --> UC5
RK --> UC6
Jager --> UC6
Wolf --> UC6
@enduml

Sequentiediagram met 5 deelnemers: Moeder, RK, Wolf, Oma en Jager.