Analysera ett program och identifiera uppdelningsgränser

Slutförd

För att kunna flytta programmet till en mikrotjänstarkitektur behöver Fabrikam utvärdera det nuvarande programmet och fastställa omfattningen och avgränsningen för respektive mikrotjänst. För den här utvärderingen kommer de att använda det domändrivna designramverket (DDD). Låt oss se hur de tillämpar detta på sitt program.

Kommentar

Den här artikeln visar inte en fullständig eller omfattande domänanalys. Vi har avsiktligt förkortat det här exemplet för att illustrera huvudpunkterna. Mer information om DDD finns i avsnittet "Läs mer" i sammanfattningen i slutet av den här modulen.

Vad är domändriven design?

DDD är en metod för systemdesign som ursprungligen introducerades av Erik Evans i boken Domain-Driven Design: Tackling Complexity in the Heart of Software från 2005. Den här metoden omfattar tre huvudelement:

  • Fokusera på kärndomänen och domänlogiken.
  • Strukturera designen baserat på en modell av domänen.
  • Driv ett iterativt samarbete mellan de tekniska teamen och affärsintressenterna för att ständigt förbättra systemet.

DDD tillhandahåller ett ramverk som kan ge dig det mesta av vägen till en uppsättning väldesignade mikrotjänster. Det har två distinkta faser, strategiska och taktiska. I strategisk DDD definierar du systemets storskaliga struktur. Strategisk DDD hjälper till att säkerställa att arkitekturen behåller fokuset på affärsfunktioner. Taktisk DDD ger en uppsättning designmönster som du kan använda för att skapa domänmodellen. Dessa mönster inkluderar entiteter, aggregat och domäntjänster. De här taktiska mönstren hjälper dig att designa mikrotjänster som är löst kopplade och sammanhängande.

Diagram of the steps for domain-driven design.

Under den strategiska DDD-fasen beskriver du företagsdomä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 är vi intresserade av mönstren för entiteter och aggregat. När vi använder de här mönstren kan vi identifiera naturliga avgränsningar för tjänsterna i vårt program. En allmän princip är att en mikrotjänst inte bör vara mindre än ett aggregat och inte större än en avgränsad kontext.

På hög nivå kan du dela in processen i fyra steg:

  1. Analysera affärsdomänen så att du förstår kraven på programmets funktioner. Resultatet av det här steget är en informell beskrivning av domänen som kan förfinas till en mer formell uppsättning domänmodeller.
  2. Definiera de avgränsade kontexterna för domänen. Varje avgränsad kontext innehåller en domänmodell som representerar en viss underdomän i det större programmet.
  3. I en avgränsad kontext använder du taktiska DDD-mönster för att definiera entiteter, aggregat och domäntjänster.
  4. Identifiera mikrotjänsterna i programmet med hjälp av resultatet från föregående steg.

Vi tar en närmare titt på vad som händer i vart och ett av dessa steg.

Analysera företagsdomänen

DDD börjar med att modellera affärsdomänen och skapa en domänmodell. Domänmodellen är en abstrakt modell för företagsdomänen. Den analyserar och organiserar domänkunskap, och utgör ett gemensamt språk för utvecklare och domänexperter.

Börja med att beskriva alla företagsfunktioner och deras kopplingar. Den här analysen är ett samarbete som involverar domänexperter, programvaruarkitekter och andra intressenter. Du behöver inte använda någon särskild formalitet. Skissa ett diagram eller rita ut det på en whiteboard.

När du fyller i diagrammet börjar du kanske hitta urskiljbara underdomäner. Vilka funktioner är nära relaterade? Vilka funktioner utgör kärnan i verksamheten, och vilka tillhandahåller mer kringliggande tjänster? Hur ser beroendegrafen ut? Under den här inledande fasen är du inte intresserad av tekniker eller implementering. Dock bör du notera var programmet kommer att behöva integreras med externa system som CRM, betalningsbearbetning eller fakturering.

Diagram of the business domain.

Definiera avgränsade kontexter

Domänmodellen innehåller representationer av verkliga saker som användare, drönare och paket. Men det betyder inte att alla delar av systemet behöver använda samma representationer för samma saker.

Undersystem som hanterar reparationer av drönare och prediktiv analys måste till exempel representera många fysiska egenskaper hos drönarna. Det här kan handla om underhållshistorik, körsträcka, ålder, modellnummer och prestandainformation. När vi ska schemalägga en leverans behöver vi dock inte tänka på de här sakerna. Undersystemet för schemaläggning behöver bara veta om en drönare är tillgänglig samt beräknad tid för upphämtning och leverans.

Om vi försöker skapa en enda modell för båda dessa undersystem är det mer komplext än vi behöver. Det blir även svårare för modellen att utvecklas med tiden, eftersom eventuella ändringar måste fungera för flera team som arbetar med separata undersystem. Det är ofta bättre att utforma separata modeller som representerar samma verkliga entitet (i det här fallet en drönare) i två olika kontexter. Varje modell innehåller bara de funktioner och attribut som är relevanta i just den modellens kontext.

Den här metoden är den metod där DDD-begreppet avgränsade kontexter spelar in. En avgränsad kontext är helt enkelt den avgränsning i en domän där en viss domänmodell gäller. När vi tittar på föregående diagram kan vi gruppera funktionerna baserat på om de delar samma domänmodell.

Diagram of the bounded contexts for the drone application.

Definiera entiteter, aggregat och tjänster

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 är vi intresserade av mönstren för entiteter och aggregat. När vi använder de här mönstren kan vi identifiera naturliga avgränsningar för tjänsterna i vårt program. En allmän princip är att en mikrotjänst inte bör vara mindre än ett aggregat och inte större än en avgränsad kontext.

Det finns flera mönster för taktisk DDD att överväga:

  • Entiteter: En entitet är ett objekt med en unik identitet som bevaras över tid. I ett bankprogram är exempelvis kunder och konton entiteter.
  • Värdeobjekt: Ett värdeobjekt har ingen identitet. Värdena för dess attribut definierar det och det är oföränderligt. Vanliga exempel på värdeobjekt är färger, datum, tider och valutavärden.
  • Aggregeringar: En aggregering definierar en konsekvensgräns runt en eller flera entiteter. 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?
  • Domän- och programtjänster: I DDD-terminologi är en tjänst ett objekt som implementerar viss logik utan att ha något tillstånd. Evans skiljer mellan domäntjänster, som kapslar in domänlogik, och programtjänster som tillhandahåller tekniska funktioner. Programtjänster omfattar vanligtvis tekniska funktioner som användarautentisering eller att skicka ett SMS. Domäntjänster används ofta till att modellera beteenden som omfattar flera entiteter.
  • Domänhändelser: Domänhändelser kan användas för att meddela andra delar av systemet när något händer. Som namnet antyder bör domänhändelser innebära något inom domänen. ”En post har infogats i en tabell” är till exempel inte en domänhändelse. ”En leverans avbröts” är en domänhändelse. Domänhändelser är särskilt relevanta i en arkitektur för mikrotjänster. Eftersom mikrotjänster är distribuerade och inte delar datalager ger domänhändelser ett sätt för mikrotjänster att koordinera med varandra.

Diagram of the drone domain model.

I Fabrikams system identifierade utvecklingsteamet följande entiteter:

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

De fyra första entiteterna, leverans, paket, drönare och konto, är aggregat som representerar avgränsningar för transaktionell konsekvens. Bekräftelser och meddelanden är underordnade entiteter till leveranser. Taggar är underordnade entiteter till paket.

Värdeobjekten i den här designen är Location (plats), ETA (beräknad tid), PackageWeight (paketvikt) och PackageSize (paketstorlek).

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, till exempel att den är i luften eller att den har landat.
  • Leveransentiteten skickar DeliveryTracking-händelser när leveransstatusen ändras. Statusarna är DeliveryCreated (leverans skapad), DeliveryRescheduled (leverans ombokad), DeliveryHeadedToDropoff (leverans på väg till avlämning) och DeliveryCompleted (leverans slutförd).

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. Utvecklings teamet lade till två domäntjänster i designen. En Scheduler samordnar stegen. En övervakare övervakar statusen för varje steg för att identifiera om några steg misslyckades eller tidsgränsen överskrids.

Identifiera mikrotjänster

Nu är vi redo att gå från domänmodell till programdesign. Här är en metod som du kan använda för att få ut mikrotjänster från domänmodellen.

  1. Börja med en avgränsad kontext. I allmänhet bör funktionerna i en mikrotjänst inte omfatta mer än en begränsad kontext. Per definition markerar en avgränsad kontext gränsen för en viss domänmodell. Om mikrotjänsten blandar olika domänmodeller är det ett tecken på att du kan behöva förfina domänanalysen.
  2. Titta sedan på aggregaten i domänmodellen. Aggregat är ofta bra kandidater för mikrotjänster. En väl utformad aggregat visar många av egenskaperna hos en väl utformad mikrotjänst:
    • Aggregat bygger på affärskrav snarare än tekniska frågor som dataåtkomst eller meddelanden.
    • Aggregat bör ha hög funktionell sammanhållning.
    • Aggregat är gränser för beständighet.
    • Aggregat bör vara löst kopplade.
  3. Domäntjänster är också bra kandidater för mikrotjänster. Domäntjänster är tillståndslösa åtgärder som omfattar flera aggregat. Ett vanligt exempel är ett arbetsflöde som inbegriper flera mikrotjänster. Senare ser vi ett exempel på en domäntjänst i drone delivery-programmet.
  4. Överväg slutligen icke-funktionella krav. Titta på faktorer såsom teamstorlek, datatyper, tekniker samt krav för skalbarhet, tillgänglighet och säkerhet. Dessa faktorer kan leda till att du ytterligare delar upp en mikrotjänst i två (eller flera) mindre tjänster, eller att göra det motsatta och kombinera flera mikrotjänster till en.

Det är viktigt att vara pragmatisk och komma ihåg att domändriven design är en iterativ process. Om du är osäker ska du börja med mer generella mikrotjänster. Det är enklare att dela upp en mikrotjänst i två mindre tjänster än att omstrukturera funktioner i flera befintliga mikrotjänster.

Diagram of the microservices.

Använd domändriven design för drönarprogrammet

För Fabrikams program finns alla dessa tjänster i sina befintliga monolitiska program. När de har identifierat var de kan dela upp sitt program i mikrotjänster börjar de med pakettjänsten.

Pakettjänsten har för närvarande ett fokuserat utvecklingsteam som uppvisar prestandaproblem relaterade till skalbarhet och är en bra kandidat för att påbörja nedbrytningen av deras program.