Domeinanalyse gebruiken om microservices te modelleren

Een van de grootste uitdagingen van microservices is het definiëren van de grenzen van afzonderlijke services. De algemene regel is dat een service 'één ding' moet doen, maar om die regel in de praktijk te brengen, moet u zorgvuldig nadenken. Er is geen mechanisch proces dat het "juiste" ontwerp zal produceren. U moet goed nadenken over uw bedrijfsdomein, vereisten en doelstellingen. Anders kunt u eindigen met een willekeurig ontwerp dat enkele ongewenste kenmerken vertoont, zoals verborgen afhankelijkheden tussen services, een nauwe koppeling of slecht ontworpen interfaces. In dit artikel wordt een domeingestuurde benadering voor het ontwerpen van microservices beschreven.

In dit artikel wordt een droneleveringsservice als actief voorbeeld gebruikt. Meer informatie over het scenario en de bijbehorende referentie-implementatie vindt u hier.

Introductie

Microservices moeten worden ontworpen rond zakelijke mogelijkheden, niet op horizontale lagen zoals gegevenstoegang of berichten. Bovendien moeten ze een losse koppeling en een hoge functionele samenhang hebben. Microservices zijn losjes gekoppeld als u één service kunt wijzigen zonder dat andere services tegelijkertijd moeten worden bijgewerkt. Een microservice is samenhangend als deze één goed gedefinieerd doel heeft, zoals het beheren van gebruikersaccounts of het bijhouden van de bezorgingsgeschiedenis. Een service moet domeinkennis inkapselen en die kennis van clients abstraheren. Een klant moet bijvoorbeeld een drone kunnen plannen zonder de details van het planningsalgoritmen te kennen of te weten hoe de dronevloot wordt beheerd.

Domain-Driven Design (DDD) biedt een framework waarmee u bijna helemaal tot een set goed ontworpen microservices kunt komen. DDD bestaat uit twee verschillende fasen: de strategische en de tactische. In strategische DDD definieert u de grootschalige structuur van het systeem. Met strategische DDD kunt u uw architectuur gericht houden op zakelijke mogelijkheden. Tactische DDD biedt een set ontwerppatronen waarmee u het domeinmodel kunt maken. Deze patronen bestaan onder meer uit entiteiten, aggregaties en domeinservices. Met deze tactische patronen kunt u microservices ontwerpen die losjes gekoppeld en samenhangend zijn.

Diagram van een DDD-proces (Domain-Driven Design)

In dit artikel en in het volgende artikel doorloopt u de volgende stappen en past u deze toe op de droneleveringstoepassing:

  1. Begin met het analyseren van het bedrijfsdomein om inzicht te krijgen in de functionele vereisten van de toepassing. De uitvoer van deze stap is een informele beschrijving van het domein, die kan worden verfijnd tot een formelere set domeinmodellen.

  2. Definieer vervolgens de contextgrenzen van het domein. Elke contextgrens bevat een domeinmodel dat een bepaald subdomein van de grotere toepassing vertegenwoordigt.

  3. Pas binnen een contextgrens tactische DDD-patronen toe om entiteiten, aggregaties en domeinservices te definiëren.

  4. Gebruik de resultaten van de vorige stap om de microservices in uw toepassing te identificeren.

In dit artikel behandelen we de eerste drie stappen, die voornamelijk betrekking hebben op DDD. In het volgende artikel identificeren we de microservices. Het is echter belangrijk om te onthouden dat DDD een iteratief, doorlopend proces is. Servicegrenzen zijn niet in steen gefixt. Naarmate een toepassing zich ontwikkelt, kunt u besluiten om een service op te splitsen in verschillende kleinere services.

Notitie

In dit artikel wordt geen volledige en uitgebreide domeinanalyse getoond. We hebben het voorbeeld bewust kort gehouden om de belangrijkste punten te illustreren. Voor meer achtergrondinformatie over DDD raden we Domain-Driven Design van Eric Evans aan, het boek waarin hij de term heeft geïntroduceerd. Een ander goed naslagwerk is Implementing Domain-Driven Design van Vaughn Vernon.

Scenario: Levering per drone

Fabrikam, Inc. begint met een service voor het leveren van pakketjes per drone. Het bedrijf beheert een hele vloot van drones. Bedrijven registreren zich bij de service en gebruikers kunnen dan een aanvraag indienen om pakketjes door een drone te laten ophalen. Wanneer een klant een datum en tijd opgeeft waarop het pakketje moet worden opgehaald, wordt er een drone toegewezen en de gebruiker op de hoogte gesteld van de geschatte levertijd. Terwijl de levering wordt uitgevoerd, kan de klant de locatie van de drone zien, met een doorlopend bijgewerkte verwachte aankomsttijd.

Voor dit scenario is een tamelijk gecompliceerd domein een vereiste. Een aantal van de problemen die het bedrijf ondervindt, is het plannen van de drone-inzet, het traceren van pakketjes, het beheren van gebruikersaccounts, en het opslaan en analyseren van historische gegevens. Bovendien wil Fabrikam zijn toepassingen sneller op de markt kunnen afzetten en met een hogere frequentie, waarbij nieuwe functionaliteit en mogelijkheden worden toegevoegd. De toepassing moet op cloudschaal werken en een hoge serviceniveaudoelstelling hebben. Fabrikam verwacht ook dat de verschillende onderdelen van het systeem volledig verschillende vereisten hebben voor wat betreft gegevensopslag en het uitvoeren van query's. Op basis van al deze overwegingen kiest Fabrikam ervoor een microservicearchitectuur te gebruiken voor de toepassing Drone Delivery.

Het domein analyseren

Het gebruik van een DDD-benadering helpt u bij het ontwerpen van microservices, zodat elke service een natuurlijke aanvulling vormt op een functionele bedrijfsvereiste. Het kan u helpen om de val te voorkomen dat organisatiegrenzen of technologische keuzes uw ontwerp bepalen.

Voordat u code schrijft, hebt u een vogelvlucht nodig van het systeem dat u maakt. DDD begint met het modelleren van het bedrijfsdomein en het maken van een domeinmodel. Het domeinmodel is een abstract model van het bedrijfsdomein. Het biedt afgeleide en georganiseerde domeinkennis en een gemeenschappelijke taal voor ontwikkelaars en domeinexperts.

Begin met het in kaart brengen van alle bedrijfsfuncties en de verbindingen ervan. Dit wordt waarschijnlijk een gezamenlijke inspanning van domeinexperts, softwarearchitecten en andere belanghebbenden. U hoeft geen specifieke vorm te gebruiken. Schets een diagram of teken op een whiteboard.

U kunt beginnen met het identificeren van afzonderlijke subdomeinen als u het diagram gaat invullen. Welke functies zijn nauw verwant? Welke functies behoren tot de kernactiviteiten van het bedrijf en welke bieden aanvullende services? Wat is de afhankelijkheidsgrafiek? In deze eerste fase hoeft u zich niet te bekommeren om technologieën of implementatiedetails. Let wel op de plaats waar de toepassing moet worden geïntegreerd met externe systemen, zoals CRM of systemen voor betalingsverwerking of facturering.

Voorbeeld: Toepassing voor dronebezorging

Na een eerste domeinanalyse kwam het Fabrikam-team met een ruwe schets die het Drone Delivery-domein weergeeft.

Diagram van het domein Drone Delivery

  • Verzending wordt in het midden van het diagram geplaatst, omdat het de kern van het bedrijf is. Al het andere in het diagram bestaat om deze functionaliteit in te schakelen.
  • Dronebeheer is ook de kern van het bedrijf. Functionaliteit die nauw verwant is aan dronebeheer omvat dronereparatie en het gebruik van voorspellende analyse om te voorspellen wanneer drones onderhoud en onderhoud nodig hebben.
  • ETA-analyse biedt tijdschattingen voor ophalen en bezorgen.
  • Met transport van derden kan de toepassing alternatieve transportmethoden plannen als een pakket niet volledig per drone kan worden verzonden.
  • Drone sharing is een mogelijke uitbreiding van de core business. Het bedrijf heeft mogelijk overtollige dronecapaciteit tijdens bepaalde uren en kan drones verhuren die anders inactief zouden zijn. Deze functie komt niet voor in de eerste release.
  • Videobewaking is een ander gebied waarop het bedrijf zich later kan uitbreiden.
  • Gebruikersaccounts, Facturering en Callcenter zijn subdomeinen die ondersteuning bieden voor de kernactiviteiten.

U ziet dat we op dit punt in het proces nog geen beslissingen hebben genomen over de implementatie of technologieën. Sommige subsystemen kunnen externe softwaresystemen of services van derden omvatten. Toch moet de toepassing communiceren met deze systemen en services, dus het is belangrijk om ze op te nemen in het domeinmodel.

Notitie

Wanneer een toepassing afhankelijk is van een extern systeem, bestaat het risico dat het gegevensschema of de API van het externe systeem in uw toepassing lekt, waardoor uiteindelijk het architectuurontwerp wordt aangetast. Dit geldt met name voor oudere systemen die mogelijk geen moderne best practices volgen en ingewikkelde gegevensschema's of verouderde API's kunnen gebruiken. In dat geval is het belangrijk om een goed gedefinieerde grens te hebben tussen deze externe systemen en de toepassing. Overweeg het patroon Strangler Fig of het anti-corruptielaagpatroon voor dit doel te gebruiken.

Contextgrenzen definiëren

Het domeinmodel zal representaties van echte dingen in de wereld bevatten, zoals gebruikers, drones en pakketten. Dat betekent echter niet dat in elk deel van het systeem dezelfde representaties voor dezelfde dingen moeten worden gebruikt.

Subsystemen die bijvoorbeeld dronereparatie en voorspellende analyse verwerken, moeten veel fysieke kenmerken van drones vertegenwoordigen, zoals hun onderhoudsgeschiedenis, kilometerstand, leeftijd, modelnummer, prestatiekenmerken, enzovoort. Als we een levering plannen, zijn dat soort zaken echter niet van belang. In het subsysteem voor planning hoeft alleen bekend te zijn of een drone beschikbaar is en wat de verwachte ophaal- en levertijd zijn.

Als we zouden proberen één model voor beide subsystemen te maken, zou dat model onnodig ingewikkeld zijn. Het zou ook lastiger zijn om het model in de loop van de tijd verder te ontwikkelen omdat elke wijziging zou moeten voldoen aan de wensen van meerdere teams die aan afzonderlijke subsystemen werken. Daarom is het vaak beter om afzonderlijke modellen te ontwerpen voor dezelfde werkelijke entiteit (in dit geval een drone) in twee verschillende contexten. Elk model bevat alleen de functies en kenmerken die relevant zijn binnen de specifieke context.

Hier komt het DDD-concept van begrensde contexten om de hoek kijken. Een contextgrens is gewoonweg de grens binnen een domein waarop een bepaald domeinmodel van toepassing is. De functies in het vorige diagram kunnen we groeperen op basis van aanwezigheid ervan in één domeinmodel.

Diagram van contextgrenzen

Contextgrenzen zijn niet noodzakelijkerwijs van elkaar geïsoleerd. In dit diagram vertegenwoordigen de ononderbroken lijnen die de begrensde contexten verbinden plaatsen waar twee begrensde contexten met elkaar communiceren. Verzending is bijvoorbeeld afhankelijk van gebruikersaccounts om informatie over klanten te krijgen en van Drone Management om drones uit de vloot te plannen.

In het boek Domain Driven Design beschrijft Eric Evans verschillende patronen voor het handhaven van de integriteit van een domeinmodel wanneer het communiceert met een andere gebonden context. Een van de belangrijkste principes van microservices is dat services communiceren via goed gedefinieerde API's. Deze benadering komt overeen met twee patronen die Evans Open Host Service en Published Language aanroept. Het idee van Open Host Service is dat een subsysteem een formeel protocol (API) definieert voor andere subsystemen om ermee te communiceren. Gepubliceerde taal breidt dit idee uit door de API te publiceren in een vorm die andere teams kunnen gebruiken om clients te schrijven. In het artikel API's ontwerpen voor microservices bespreken we het gebruik van OpenAPI-specificatie (voorheen bekend als Swagger) voor het definiëren van taalagnostische interfacebeschrijvingen voor REST API's, uitgedrukt in JSON- of YAML-indeling.

Voor de rest van deze reis richten we ons op de context Verzendingsgrens.

Volgende stappen

Nadat u een domeinanalyse hebt voltooid, is de volgende stap het toepassen van tactische DDD om uw domeinmodellen nauwkeuriger te definiëren.