Delen via


Tactische DDD gebruiken om microservices te ontwerpen

Azure Migrate

DDD (Domain-Driven Design) is tegen het idee om één uniform model voor het hele systeem te hebben. In plaats daarvan moedigt het aan het systeem te verdelen in gebonden contexten, elk met een eigen model. Tijdens de strategische fase van DDD wijst u het bedrijfsdomein toe en definieert u gebonden contexten voor uw domeinmodellen.

Tijdens de tactische DDD definieert u uw domeinmodellen nauwkeuriger. De tactische patronen worden toegepast binnen één contextgrens. In een microservicesarchitectuur, waarbij elke gebonden context een microservicekandidaat is, zijn de entiteits- en aggregatiespatronen van belang. Het toepassen van deze patronen helpt bij het identificeren van natuurlijke grenzen voor de services in uw toepassing. Zie Microservicegrenzen identificeren voor meer informatie. Als algemeen principe mag een microservice niet kleiner zijn dan een aggregaties en niet groter zijn dan een gebonden context.

In dit artikel worden de tactische patronen beoordeeld en vervolgens toegepast op de context Verzending gebonden in de Drone Delivery-toepassing.

Overzicht van de tactische patronen

In deze sectie vindt u een kort overzicht van de tactische DDD-patronen. Als u bekend bent met DDD, kunt u deze overslaan. Deze patronen worden gedetailleerder beschreven in hoofdstukken 5 en 6 van het boek van Eric Evans, en in Implementeren Domain-Driven Design by Vaughn Vernon.

Diagram van tactische patronen in DDD.

Entiteiten. Een entiteit is een object met een unieke identiteit dat in de loop van de tijd blijft bestaan. Bij een banktoepassing zijn klanten en rekeningen bijvoorbeeld entiteiten.

  • Een entiteit heeft een unieke id in het systeem, die kan worden gebruikt om de entiteit op te zoeken of op te halen. Dat betekent niet dat de id altijd rechtstreeks aan gebruikers wordt blootgesteld. Dit kan een GUID of een primaire sleutel in een database zijn.

  • Een identiteit kan meerdere gebonden contexten omvatten en kan langer duren dan de levensduur van de toepassing. Bankrekeningnummers of door de overheid uitgegeven id's zijn bijvoorbeeld niet gekoppeld aan een specifieke toepassing.

  • De kenmerken van een entiteit kunnen na verloop van tijd worden gewijzigd. De naam of het adres van een persoon kan bijvoorbeeld veranderen, maar ze blijven hetzelfde.

Waardeobjecten. Een waardeobject heeft geen identiteit. Deze wordt alleen gedefinieerd door de waarden van de kenmerken. Waardeobjecten kunnen onveranderbaar zijn. Als u een waardeobject wilt bijwerken, wordt er een nieuw exemplaar gemaakt om de oude te vervangen. Waardeobjecten kunnen methoden bevatten die domeinlogica inkapselen, maar deze methoden mogen geen neveneffecten produceren of de status van het object wijzigen. Veelvoorkomende voorbeelden van waardeobjecten zijn kleuren, datums en tijden en valutawaarden.

Aggregaties. Een aggregatie geeft een consistentiegrens rond een of meer entiteiten aan. Precies één entiteit in een aggregaties is de hoofdmap. Opzoeken wordt uitgevoerd met behulp van de id van de hoofdentiteit. Alle andere entiteiten in de aggregaties zijn onderliggende elementen van de hoofdmap en waarnaar wordt verwezen door de aanwijzers uit de hoofdmap te volgen.

Het doel van een aggregatie is om transactionele invarianten te modelleren. In het echt bestaan er complexe relaties tussen dingen. Klanten maken orders, orders bevatten producten, producten hebben leveranciers, enzovoort. Als verschillende verwante objecten in de toepassing worden gewijzigd, hoe wordt dan de consistentie gegarandeerd? Hoe houden we invarianten bij en zien we erop toe?

Traditionele toepassingen hebben vaak databasetransacties gebruikt om consistentie af te dwingen. In een gedistribueerde toepassing is dat echter vaak niet haalbaar. Een enkele zakelijke transactie kan meerdere gegevensarchieven omvatten, of langlopend zijn, of er kunnen services van derden bij betrokken zijn. Uiteindelijk is het aan de toepassing, niet aan de gegevenslaag, om de invarianten af te dwingen die vereist zijn voor het domein. Dat is wat aggregaties zijn bedoeld om te modelleren.

Notitie

Een aggregaties kunnen bestaan uit één entiteit, zonder onderliggende entiteiten. Wat het een aggregatie maakt, is de transactionele grens.

Domein- en toepassingsservices. in DDD-terminologie is een service een object waarmee logica zonder enige status wordt geïmplementeerd. Evans maakt onderscheid tussen domeinservices, die domeinlogica inkapselen en toepassingsservices, die technische functionaliteit bieden, zoals gebruikersverificatie of het verzenden van een sms-bericht. Domeinservices worden vaak gebruikt om gedrag voor meerdere entiteiten te modelleren.

Notitie

De term service is overbelast in softwareontwikkeling. De definitie die hier wordt gebruikt, is niet rechtstreeks gerelateerd aan microservices.

Domein gebeurtenissen. Domeinevenementen kunnen andere onderdelen van het systeem waarschuwen wanneer er iets gebeurt. Zoals de naam al aangeeft, moeten domeinevenementen iets zinvols in het domein vertegenwoordigen. 'Een record is bijvoorbeeld ingevoegd in een tabel' is geen domeingebeurtenis. 'Een levering is geannuleerd' is een domeingebeurtenis. Domeinevenementen zijn vooral belangrijk in een microservicesarchitectuur. Omdat microservices worden gedistribueerd en geen gegevensarchieven delen, maken domeingebeurtenissen coördinatie mogelijk tussen services. Zie Interservice-communicatie voor meer informatie over asynchrone berichten.

Er zijn enkele andere DDD-patronen die hier niet worden behandeld, waaronder factory's, opslagplaatsen en modules. Deze patronen kunnen handig zijn wanneer u een microservice implementeert, maar ze zijn minder relevant wanneer u de grenzen tussen microservices ontwerpt.

Dronelevering: De patronen toepassen

We beginnen met de scenario's die de context met betrekking tot verzending moet verwerken.

  • Een klant kan een drone aanvragen om goederen op te halen bij een bedrijf dat is geregistreerd bij de droneleveringsservice.
  • De afzender genereert een tag (streepjescode of RFID) die op het pakket moet worden geplaatst.
  • Een drone haalt een pakket op van de bronlocatie naar de doellocatie.
  • Wanneer een klant een levering plant, biedt het systeem een ETA op basis van routegegevens, weersomstandigheden en historische gegevens.
  • Wanneer de drone onderweg is, kan een gebruiker de huidige locatie en de nieuwste ETA volgen.
  • Totdat een drone het pakket heeft opgehaald, kan de klant een levering annuleren.
  • De klant wordt op de hoogte gesteld wanneer de levering is voltooid.
  • De afzender kan een bevestiging van de bezorging aanvragen bij de klant, in de vorm van een handtekening of vingerafdruk.
  • Gebruikers kunnen de geschiedenis van een voltooide levering opzoeken.

In deze scenario's heeft het ontwikkelteam de volgende entiteiten geïdentificeerd.

  • Levering
  • Pakket
  • Drone
  • Rekening
  • Bevestiging
  • Melding
  • Etiket

De eerste vier, Levering, Pakket, Drone en Account, zijn allemaal aggregaties die transactionele consistentiegrenzen vertegenwoordigen. Bevestigingen en Meldingen zijn onderliggende entiteiten van Leveringen, en Tags zijn onderliggende entiteiten van Pakketten.

De waardeobjecten in dit ontwerp omvatten Locatie, ETA, PackageWeight en PackageSize.

Ter illustratie ziet u hier een UML-diagram van de aggregaties Levering. U ziet dat het verwijzingen bevat naar andere aggregaties, waaronder Account, Pakket en Drone.

UML-diagram van de aggregaties levering.

Er zijn twee domeingebeurtenissen:

  • Als een drone onderweg is, worden vanuit de entiteit Dronestatus gebeurtenissen verzonden om de locatie en status van de drone te beschrijven (Onderweg, Geland).

  • Vanuit de entiteit Levering worden steeds LeveringVolgen-gebeurtenissen verzonden wanneer de fase van een levering verandert. De DeliveryTracking-gebeurtenissen omvatten DeliveryCreated, DeliveryRescheduled, DeliveryHeadedToDropoff en DeliveryCompleted.

Zoals u ziet, worden met deze gebeurtenissen zinvolle zaken binnen het domeinmodel beschreven. Er wordt iets beschreven over het domein en dat is niet gebonden aan een bepaalde computertaalconstructie.

Het ontwikkelteam heeft nog een functionaliteitsgebied geïdentificeerd, en dat past niet naadloos in een van de entiteiten die tot nu toe zijn beschreven. Ergens in het systeem moeten alle stappen van het plannen of bijwerken van een levering worden gecoördineerd. Daarom heeft het ontwikkelteam twee domeinservices toegevoegd aan het ontwerp: een Scheduler die de stappen coördineert en een Supervisor die de status van elke stap bewaakt om te detecteren of er een time-out is opgetreden bij eventuele stappen. Deze benadering is een variant van het Scheduler Agent Supervisor-patroon.

Diagram van het herziene domeinmodel.

Volgende stappen

De volgende stap is het definiëren van de grenzen voor elke microservice.