Använda domänanalys för att modellera 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 omsätta 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, dina 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.

I den här artikeln används 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änkunskaper och abstrahera dessa kunskaper 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.

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 dig att se till att arkitekturens fokus handlar om affärsfunktionerna. Taktisk DDD ger en uppsättning designmönster som du kan använda för att skapa domänmodellen. Dessa mönster kan vara 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.

Anteckning

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 en drönare för att hämta varuleveranser. 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

Med hjälp av 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 av affärsdomä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 affärsfunktioner 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: Drönarleveransprogram

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

Diagram över domänen drone delivery

  • 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 kommer inte att finnas 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.

Anteckning

När ett program är beroende av ett externt system finns det en risk att det externa systemets dataschema eller API läcker in 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. Det betyder inte att alla delar av systemet måste 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 den specifika kontexten.

Det är här DDD-begreppet avgränsade kontexter kommer till användning. 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 begränsade kontexter

Begrä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. Leveransen är till exempel beroende av användarkonton för att få information om kunder och 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 som ska 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 (kallades tidigare 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 leveransbundna 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.