Dela via


Använda domänanalys för att utforma mikrotjänster

En av de största utmaningarna med mikrotjänster är att definiera gränserna för enskilda tjänster. Den allmänna regeln är att en tjänst ska göra "en sak" – men att tillämpa den regeln i praktiken kräver noggrann eftertanke. Det finns ingen mekanisk process som kommer att producera "rätt" design. Du måste tänka djupt på din affärsdomän, krav, arkitekturegenskaper (även kallade icke-funktionella krav) och mål. Annars kan du få en slumpmässig design som uppvisar vissa oönskade egenskaper, till exempel dolda beroenden mellan tjänster, nära koppling eller dåligt utformade gränssnitt. Den här artikeln visar en domändriven metod för att utforma mikrotjänster. Att utvärdera tjänstgränser är ett pågående arbete med att utveckla arbetsbelastningar. Ibland resulterar utvärderingen i omdefinierade definitioner av befintliga gränser som kräver ytterligare programutveckling för att hantera ändringarna.

Den här artikeln använder en tjänst för drönarleverans som ett exempel som körs. Du kan läsa mer om scenariot och motsvarande referensimplementering här.

Introduktion

Mikrotjänster bör utformas kring affärsfunktioner, inte horisontella lager som dataåtkomst eller meddelanden. Dessutom bör de ha lös koppling och hög funktionell sammanhållning. Mikrotjänster är löst kopplade om du kan ändra en tjänst utan att kräva att andra tjänster uppdateras samtidigt. En mikrotjänst är sammanhängande om den har ett enda, väldefinierat syfte, till exempel att hantera användarkonton eller spåra leveranshistorik. En tjänst bör kapsla in domänkunskap och sammanfatta den kunskapen från klienter. En klient bör till exempel kunna schemalägga en drönare utan att känna till information om schemaläggningsalgoritmen eller hur drönarflottan hanteras. Arkitekturegenskaper måste definieras för varje mikrotjänst för att matcha dess domänproblem, i stället för att definieras för hela systemet. En kundinriktad mikrotjänst kan till exempel behöva ha prestanda, tillgänglighet, feltolerans, säkerhet, testbarhet och flexibilitet. En serverdelsmikrotjänst kan bara behöva ha feltolerans och säkerhet. Om mikrotjänster har synkron kommunikation med varandra skapar beroendet mellan dem ofta behovet av att dela samma arkitekturegenskaper.

Med domändriven design (DDD) får du ett ramverk som du kan använda för att få ut det mesta möjliga av en uppsättning väldesignade mikrotjänster. DDD har två distinkta faser, den strategiska och den 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. Dessa taktiska mönster hjälper dig att designa mikrotjänster som är både löst kopplade och sammanhängande.

Diagram över en domändriven designprocess (DDD)

I den här artikeln och i nästa steg går vi igenom följande steg och tillämpar dem på drone delivery-programmet:

  1. Börja med att analysera företagsdomänen för att förstå programmets funktionskrav. 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 sedan domänens avgränsade kontexter . 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. Använd resultaten från föregående steg för att identifiera mikrotjänsterna i ditt program.

I den här artikeln går vi igenom de tre första stegen, som främst handlar om DDD. I nästa artikel ska vi identifiera mikrotjänsterna. Det är dock viktigt att komma ihåg att DDD är en iterativ, pågående process. Tjänstgränser är inte fasta i sten. När ett program utvecklas kan du välja att dela upp en tjänst i flera mindre tjänster.

Kommentar

Den här artikeln visar inte en fullständig eller omfattande domänanalys. Vi höll avsiktligt exemplet kort för att illustrera huvudpunkterna. Om du vill läsa mer om bakgrunden till DDD rekommenderar vi Eric Evans Domain-Driven Design, den bok där begreppet först introducerades. En annan bra referens är Implementing Domain-Driven Design av Vaughn Vernon.

Scenario: Drönarleverans

Fabrikam, Inc. startar en tjänst för drönarleverans. Företaget hanterar en flotta med drönare. Företag registrerar sig för tjänsten och användare kan begära att en drönare hämtar gods för leverans. När en kund schemalägger en hämtning tilldelar ett serverdelsystem en drönare och meddelar användaren en uppskattad leveranstid. När leveransen pågår kan kunden spåra drönarens plats med en ständigt uppdaterad ETA (beräknad ankomst).

Det här scenariot omfattar en relativt komplicerad domän. Några av affärsproblemen är schemaläggning av drönare, spårning av paket, hantering av användarkonton och lagring och analys av historiska data. Fakrikam vill dessutom komma ut på marknaden snabbt och sedan iterera snabbt, och lägga till nya funktioner och möjligheter. Programmet måste drivas i molnskala med höga servicenivåmål. Fabrikam förväntar sig även att olika delar av systemet kommer att ha mycket olika krav på datalagring och frågor. Alla dessa överväganden har gjort att Fabrikam väljer en arkitektur för mikrotjänster för programmet för drönarleverans.

Analysera domänen

Genom att använda en DDD-metod kan du utforma mikrotjänster så att varje tjänst passar perfekt för ett funktionellt affärsbehov. Det kan hjälpa dig att undvika fällan att låta organisationens gränser eller teknikval diktera din design.

Innan du skriver någon kod behöver du en fågelperspektiv över systemet som du skapar. DDD börjar med att modellera företagsdomänen och skapa en domänmodell. Domänmodellen är en abstrakt modell för företagsdomänen. Den analyserar och organiserar domänkunskap samt ger ett gemensamt språk för utvecklare och domänexperter.

Börja med att beskriva alla företagsfunktioner och deras kopplingar. Detta blir troligen ett gemensamt arbete som omfattar domänexperter, programvaruarkitekter och andra intressenter. Du behöver inte använda någon särskild formalitet. Skissa ett diagram eller rita på en whiteboardtavla.

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, till exempel system för CRM, betalningsbearbetning eller fakturering.

Exempel: Program för drönarleverans

Efter en inledande domänanalys kom Fabrikam-teamet fram till en grov skiss som visar domänen Drone Delivery.

Diagram över domänen drönarleverans

  • Frakt placeras i mitten av diagrammet eftersom det är kärnan i verksamheten. Allt annat i diagrammet finns för att aktivera den här funktionen.
  • Drönarhantering är också kärnan i verksamheten. Funktioner som är nära relaterade till drönarhantering inkluderar drönarreparation och användning av förutsägelseanalys för att förutsäga när drönare behöver service och underhåll.
  • ETA-analys ger tidsuppskattningar för upphämtning och leverans.
  • Med transport från tredje part kan programmet schemalägga alternativa transportmetoder om ett paket inte kan levereras helt med drönare.
  • Drönardelning är en möjlig förlängning av kärnverksamheten. Företaget kan ha överskott av drönarkapacitet under vissa timmar och kan hyra ut drönare som annars skulle vara inaktiva. Den här funktionen finns inte i den första versionen.
  • Videoövervakning är ett annat område som företaget kan expandera till senare.
  • Användarkonton, fakturering och callcenter är underdomäner som stöder kärnverksamheten.

Observera att vi i det här läget inte har fattat några beslut om implementering eller teknik. Vissa av undersystemen kan omfatta externa programvarusystem eller tjänster från tredje part. Trots detta måste programmet interagera med dessa system och tjänster, så det är viktigt att inkludera dem i domänmodellen.

Kommentar

När ett program är beroende av ett externt system finns det en risk att det externa systemets dataschema eller API läcker ut i ditt program, vilket i slutändan äventyrar arkitekturdesignen. Detta gäller särskilt äldre system som kanske inte följer moderna metodtips och som kan använda invecklade datascheman eller föråldrade API:er. I så fall är det viktigt att ha en väldefinierad gräns mellan dessa externa system och programmet. Överväg att använda Strangler Fig-mönstret eller mönstret antikorruptionsskikt för detta ändamål.

Definiera avgränsade kontexter

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

Till exempel måste undersystem som hanterar drönarreparation och förutsägelseanalys representera många fysiska egenskaper hos drönare, till exempel deras underhållshistorik, körsträcka, ålder, modellnummer, prestandaegenskaper och så vidare. 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 enskild modell för båda dessa undersystem blir det onödigt komplext. Det skulle även bli svårare för modellen att utvecklas med tiden, eftersom eventuella ändringar måste fungera för flera team som arbetar med separata undersystem. Därför är det 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.

Det är hä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å det föregående diagrammet kan vi gruppera funktioner baserat på huruvida olika funktioner kommer att dela samma enskilda domänmodell.

Diagram över avgränsade kontexter

Avgränsade kontexter är inte nödvändigtvis isolerade från varandra. I det här diagrammet representerar de fasta linjer som ansluter de avgränsade kontexterna platser där två avgränsade kontexter interagerar. Leverans är till exempel beroende av användarkonton för att få information om kunder och på Drönarhantering för att schemalägga drönare från flottan.

I boken Domain Driven Design beskriver Eric Evans flera mönster för att upprätthålla integriteten hos en domänmodell när den interagerar med en annan begränsad kontext. En av huvudprinciperna för mikrotjänster är att tjänster kommunicerar via väldefinierade API:er. Den här metoden motsvarar två mönster som Evans anropar Open Host Service och Published Language. Tanken med Open Host Service är att ett undersystem definierar ett formellt protokoll (API) för andra undersystem att kommunicera med det. Publicerat språk utökar den här idén genom att publicera API:et i ett formulär som andra team kan använda för att skriva klienter. I artikeln Designa API:er för mikrotjänster diskuterar vi att använda OpenAPI Specification (tidigare kallat Swagger) för att definiera språkagnostiska gränssnittsbeskrivningar för REST-API:er, uttryckta i JSON- eller YAML-format.

Under resten av den här resan kommer vi att fokusera på den fraktgränsade kontexten.

Nästa steg

När du har slutfört en domänanalys är nästa steg att tillämpa taktisk DDD för att definiera dina domänmodeller med större precision.