Dela via


Använda taktisk DDD för att utforma mikrotjänster

Azure Migrate

Domändriven design (DDD) motsätter sig tanken på att ha en enda enhetlig modell för hela systemet. I stället uppmuntrar det till att dela upp systemet i avgränsade kontexter, var och en med sin egen modell. Under den strategiska fasen av DDD mappar du ut affärsdomänen och definierar avgränsade kontexter för dina domänmodeller.

Taktisk DDD är när du definierar domänmodeller med mer precision. De taktiska mönstren används inom en enda, avgränsad kontext. I en mikrotjänstarkitektur, där varje begränsad kontext är en mikrotjänstkandidat, är entitets- och aggregerade mönster av betydelse. Genom att använda dessa mönster kan du identifiera naturliga gränser för tjänsterna i ditt program. Mer information finns i Identifiera gränser för mikrotjänster. Som en allmän princip bör en mikrotjänst inte vara mindre än en aggregering och inte större än en begränsad kontext.

Den här artikeln granskar de taktiska mönstren och tillämpar dem sedan på den leveransavgränsade kontexten i drone delivery-programmet.

Översikt över taktiska mönster

Det här avsnittet innehåller en kort sammanfattning av de taktiska DDD-mönstren. Om du är bekant med DDD kan du välja att hoppa över det. Dessa mönster beskrivs mer detaljerat i kapitel 5 och 6 i Eric Evans bok, och i Implementering Domain-Driven Design av Vaughn Vernon.

Diagram över taktiska mönster i DDD.

Entiteter. En entitet är ett objekt med en unik identitet som består över tid. I ett bankprogram skulle exempelvis kunder och konton vara entiteter.

  • En entitet har en unik identifierare i systemet, som kan användas för att söka efter eller hämta entiteten. Det betyder inte att identifieraren alltid exponeras direkt för användare. Det kan vara ett GUID eller en primärnyckel i en databas.

  • En identitet kan sträcka sig över flera avgränsade kontexter och kan finnas kvar längre än programmets livslängd. Till exempel är bankkontonummer eller myndighets-utfärdade ID:t inte knutna till ett specifikt program.

  • Attributen för en entitet kan ändras över tid. En persons namn eller adress kan till exempel ändras, men de förblir samma person.

Värdeobjekt. Ett värdeobjekt har ingen identitet. Den definieras endast av värdena för dess attribut. Värdeobjekt är oföränderliga. För att uppdatera ett värdeobjekt skapas en ny instans för att ersätta den gamla. Värdeobjekt kan innehålla metoder som kapslar in domänlogik, men dessa metoder får inte ge biverkningar eller ändra objektets tillstånd. Vanliga exempel på värdeobjekt är färger, datum och tider samt valutavärden.

Aggregeringar. Ett aggregat definierar en konsekvensavgränsning runt en eller flera entiteter. Exakt en entitet i en aggregering är roten. Sökningen görs med rotentitetens identifierare. Andra entiteter i aggregeringen är underordnade roten och refereras genom att följa pekare från roten.

Syftet med ett aggregat är att modellera transaktionella invarianter. Verkliga saker har komplexa relationsnät. Kunder skapar beställningar, beställningar innehåller produkter, produkter har leverantörer och så vidare. Hur garanterar programmet konsekvens om det ändrar flera relaterade objekt? Hur håller vi reda på invarianter och framtvingar dem?

Traditionella program har ofta använt databastransaktioner för att framtvinga konsekvens. I ett distribuerat program är det dock ofta inte möjligt. En enskild affärstransaktion kan omfatta flera datalager, eller vara tidskrävande eller omfatta tjänster från tredje part. I slutändan är det upp till programmet, inte datalagret, att framtvinga de invarianter som krävs för domänen. Det är vad aggregeringar är avsedda att modellera.

Kommentar

En aggregering kan bestå av en enda entitet, utan underordnade entiteter. Det som gör det till en aggregering är transaktionsgränsen.

Domän- och programtjänster. I DDD-termer än en tjänst ett objekt som implementerar viss logik utan att bibehålla något särskilt tillstånd. Evans skiljer mellan domäntjänster, som kapslar in domänlogik, och programtjänster som tillhandahåller tekniska funktioner, till exempel användarautentisering eller att skicka ett SMS. Domäntjänster används ofta till att modellera beteenden som omfattar flera entiteter.

Kommentar

Termen tjänst är överbelastad i programvaruutveckling. Definitionen som används här är inte direkt relaterad till mikrotjänster.

Domänhändelser. Domänhändelser kan meddela andra delar av systemet när något inträffar. Som namnet antyder bör domänhändelser representera något meningsfullt inom domänen. Till exempel är "en post infogades i en tabell" inte en domänhändelse. "En leverans avbröts" är en domänhändelse. Domänhändelser är särskilt viktiga i en arkitektur för mikrotjänster. Eftersom mikrotjänster distribueras och inte delar datalager möjliggör domänhändelser samordning mellan tjänster. Mer information om asynkrona meddelanden finns i Interservice-kommunikation.

Det finns några andra DDD-mönster som inte omfattas här, inklusive fabriker, lagringsplatser och moduler. Dessa mönster kan vara användbara när du implementerar en mikrotjänst, men de är mindre relevanta när du utformar gränserna mellan mikrotjänster.

Drönarleverans: Tillämpa mönstren

Vi börjar med de scenarier som den fraktbundna kontexten måste hantera.

  • En kund kan begära att en drönare hämtar varor från ett företag som är registrerat hos drönarleveranstjänsten.
  • Avsändaren genererar en tagg (streckkod eller RFID) som ska sättas på paketet.
  • En drönare hämtar och levererar ett paket från källplatsen till målplatsen.
  • När en kund schemalägger en leverans tillhandahåller systemet en ETA baserat på väginformation, väderförhållanden och historiska data.
  • När drönaren är i flygning kan en användare spåra den aktuella platsen och den senaste ETA:n.
  • Tills en drönare har hämtat paketet kan kunden avbryta en leverans.
  • Kunden meddelas när leveransen har slutförts.
  • Avsändaren kan begära leveransbekräftelse från kunden i form av en signatur eller ett fingeravtryck.
  • Användare kan söka efter historiken för en slutförd leverans.

Från dessa scenarier identifierade utvecklingsteamet följande entiteter.

  • Leverans
  • Paket
  • Drönare
  • Konto
  • Bekräftelse
  • Meddelande
  • Tagg

De första fyra, Delivery, Package, Drone och Account, är alla aggregeringar som representerar transaktionskonsekvensgränser. Bekräftelser och Meddelanden är underordnade entiteter för Leveranser, och Taggar är underordnade entiteter för Paket.

Värdeobjekten i den här designen är Plats, ETA, PackageWeight och PackageSize.

För att illustrera, här är ett UML-diagram över leveransaggregatet. Observera att den innehåller referenser till andra aggregeringar, inklusive Konto, Paket och Drone.

UML-diagram över leveransaggregatet.

Det finns två domänhändelser:

  • När en drönare är i luften skickar drönarentiteten DroneStatus-händelser som beskriver drönarens plats och status (i luften, landad).

  • Leveransentiteten skickar DeliveryTracking-händelser (Leveransspårning) när leveransstatusen ändras. DeliveryTracking-händelserna inkluderar DeliveryCreated, DeliveryRescheduled, DeliveryHeadedToDropoff och DeliveryCompleted.

Observera att de här händelserna beskriver saker som har en konkret innebörd i domänmodellen. De beskriver något om domänen och är inte bundna till någon viss konstruktion i ett programmeringsspråk.

Utvecklingsteamet identifierade ytterligare ett funktionsområde, som inte passar särskilt bra i någon av de entiteter som beskrivits hittills. Någon del av systemet måste koordinera alla steg som ingår i schemaläggning eller uppdatering av en leverans. Utvecklingsteamet har därför lagt till två domäntjänster i designen: en Scheduler som samordnar stegen och en övervakare som övervakar statusen för varje steg för att identifiera om några steg misslyckades eller tidsgränsen överskrids. Den här metoden är en variant av Scheduler Agent Supervisor-mönstret.

Diagram över den reviderade domänmodellen.

Nästa steg

Nästa steg är att definiera gränserna för varje mikrotjänst.