vækst af microservice vedtagelse har medført en genopblussen i popularitet af nogle tidligere-overset software design mønstre. Mange af disse mønstre er blevet udvundet fra Eric Evans ‘ Domain Driven Design, En bog, der handler lige så meget om teamstruktur, som det handler om programmelarkitektur.
og af disse mønstre er den afgrænsede kontekst måske den vigtigste at forstå. Som ingeniører er vi kommet til at betragte den afgrænsede kontekst som et designmønster for programmelarkitektur. Men det er fordi vi har valgt det lidt fra dets oprindelige brug. Som brugt af Evans er den afgrænsede kontekst lige så meget et organisatorisk mønster som det er teknisk.
derfor er jeg kommet for at se det afgrænsede Kontekstmønster som en lynchpin i forståelsen af mikroservices. Ikke kun hvordan man bygger dem, men virkelig hvorfor vi bygger dem i første omgang, og hvordan de kan gøre vores organisationer mere succesrige. Hvis vi forstår, hvad afgrænsede sammenhænge er – hvis vi vedtager den afgrænsede Kontekstindstilling både teknisk og organisatorisk — så kan vi virkelig få succes med at opbygge vores mikroservices arkitektur.
hvorfor flytte til microservices?
for at begynde, lad os udføre en lille øvelse. Stil dig selv dette spørgsmål: Hvorfor bygger vi mikroservices i første omgang?
Tag et øjeblik til at tænke over det. Hvad er de fordele, der først kommer til at tænke på? Hvad er de største problemer, vi skal håbe på at løse? Skriv nogle svar ned, bare for at holde dig ærlig.
…
har du dit svar? God. Læs det tilbage til dig selv. Har du ramt de tekniske standardfordele? Kontinuerlig levering, skalerbarhed, polyglot miljøer, containere og skyer, og alle de gode ting? Stor.
men inkluderede dit øverste svar noget om at gøre det muligt for din organisation at fungere mere effektivt? Det burde det. Fordi opbygning af mikroservices ikke handler om at realisere tekniske fordele. Det handler virkelig om at opnå organisatoriske fordele. Alt andet er en implementeringsdetalje.
Monoliths = koblet kode og koblede hold
efterhånden som vores monolitter bliver større og større, begynder produktiviteten at aftage. Der er mindst to hovedårsager til det.
at sætte bremserne på vores hastighed
for det første bidrager hvert ingeniørteam til en kæmpe kodebase. Som sådan står hold over for en stadigt voksende sandsynlighed for, at deres kode vil være i konflikt med andres kode. For at hjælpe med at afbøde de potentielle problemer, dette kan medføre, indfører vi procedurer — kode fryser, KVALITETSTESTPERIODER, frigør tog osv. – det er bogstaveligt talt designet til at bremse vores produktivitet.
selvfølgelig forhindrer disse procedurer funktioner og forbedringer i at blive implementeret rettidigt. De skaber også kaos på ingeniørers evne til at fokusere på deres teams prioriteter. Hvis der findes en fejl i en testperiode, det ansvarlige team skal kontekstskift og fokusere på at løse denne fejl. Hvis der findes en alvorlig fejl i produktionen, holdet skal ikke kun rette fejlen, men også hoppe gennem bøjler for at få den implementeret af det næste frigivelsestog.
vagt bliver en boondoggle. Hvis noget går galt med vores monolit, skal nogen være tilgængelige — dag eller nat — for at løse problemet. Men hvem? Store organisationer med store monolitter står generelt over for to valg:
- et hændelsesledelsesteam, hvis eneste, triste, triste job i organisationen er at reagere på problemer forårsaget af andre ingeniørers kode og finde ud af, hvordan man løser dem.
- en roterende vagtplan, hvor hver uge tildeles en vilkårlig ingeniør det triste, triste job med at blive ansvarlig for at løse problemer, der sandsynligvis er forårsaget af kode skrevet af en anden ingeniør, i et andet ingeniørteam.
(Mis)organisering af vores teams
Monoliths rod med vores organisationer på endnu en måde. Hele vores organisation arbejder på det samme, store produkt. Men vi er stadig nødt til at opdele organisationen i håndterbare teams. Så vi har en tendens til at se på funktionelle roller for at finde teamgrænser:
desværre begrænser denne form for organisationsstruktur samarbejdsarbejde. I stedet for at arbejde sammen om at løse det sande problem ved hånden (f. eks. hvordan designer, bygger og vedligeholder vi funktionen?) medlemmer af de forskellige funktionelle områder fokuserer simpelthen på deres egen del og kaster metaforisk deres arbejde over hegnet, når de er færdige. Potentialet for samarbejde og synergi — hvor den samlede kvalitet af holdets indsats er meget mere end summen af de enkelte teammedlemmer — går tabt.
det er også fyldt med flaskehalse. Når vi organiserer vores teams efter funktionsområde, vil vi naturligvis have forkert justering i prioriteterne. Lad os sige, at produktledelsesteamet besluttede, at vores monoliths købsproces skal moderniseres. De planlægger tid med designteamet for at sammensætte nogle mocks. På et tidspunkt vil mocks være færdige og afleveret til frontend-teamet for at implementere. Selvfølgelig vil frontend-teamet have brug for API ‘ er, der skal implementeres af backend-teamet, så de blokeres, indtil det er afsluttet. Når backend-teamet prioriterer sit arbejde med de nye checkout-tjenester, finder det ud af, at det har brug for hjælp fra Databaseadministrationsteamet (dba). Hvilket selvfølgelig har sine egne prioriteter. Så backend-teamet blokeres, indtil en DBA frigøres.
på en måde virker denne organisationsstruktur lidt som en dårligt designet, alt for koblet programarkitektur… gør det ikke?
Microservices = afkoblet kode, afkoblede teams
derimod muliggør en microservices-arkitektur teamautonomi. Det bliver meget lettere at danne hold, der er selvstændige, der arbejder effektivt sammen, og som ikke konstant blokeres af afhængigheder af andre hold.
Teams kan tage fuldt ejerskab over deres arbejde, fra design til udvikling til implementering. Hvert medlem deler ansvaret for at nå deres holds mål, så de bliver incitamenterede til at deltage i mere end bare “deres del”. Jeg har arbejdet med teams, hvor produktledere, designere, front-end, back-end og mobile ingeniører er kommet sammen for at designe produktfunktioner, hvilket giver langt bedre resultater, end en person kunne have opnået.
holdet får ansvar for sine egne artefakter, når de er indsat i produktionen. Dette fører generelt til kode af højere kvalitet, der er lettere at fejlfinde. Hvorfor det? I modsætning til med en monolit har hold en tendens til at have et holistisk syn på de mikroservices, de ejer. Så det er meget lettere for teamet at forudse problemer, at tilføje god logning og målinger til fejlfinding af problemer, når de opstår, og at gøre korrekt brug af modstandsdygtighedsmønstre (f.eks.
desuden, da hold har en fuld følelse af ejerskab over deres arbejde, bliver deres tjenester sunde og kører i produktion mindre om en mareridtsagtig udgivelsesplan og mere om at pleje deres oprettelse.
endelig arbejder holdene mod det samme mål på samme tidslinje. Det betyder ikke mere at blokere en person, da de venter på, at nogen i et andet funktionelt område frigør sig.
vi skal være bevidste om autonomi
men vi får ikke disse fordele gratis ved blot at bryde vores monolit i mikroservices. Lad os se på vores første, naive visning af en mikroservices-arkitektur:
Hvis vi er som de fleste ingeniører, er vores oprindelige ide om en mikroservicearkitektur, ja, en flok mikroservices. Hver udsætter en slags API (hvile, måske) for at tillade enhver anden tjeneste at læse fra den og skrive til den.
når vi får erfaring, lærer vi, at ikke alle mikroservices tjener det samme formål — eller i det mindste burde de ikke. Og derfor, ligesom vores monolit var blevet arrangeret i lag, så arrangerer vi vores mikroservices: