Mener monolitter kan være bedre enn mikro­tjenester

- Mikrotjenester blir ofte mer kompliserte, skriver Pål Bøckmann, som har prøvd begge deler på samme produkt.

Pål Bøckmann har tatt et produkt fra monolitt til mikrotjenester, og synes begge løsninger har sine fordeler og ulemper. 📸: Alv
Pål Bøckmann har tatt et produkt fra monolitt til mikrotjenester, og synes begge løsninger har sine fordeler og ulemper. 📸: Alv Vis mer

Mikrotjenester er noe man har hørt mye om på konferanser og forum i en stund nå, men sett bort ifra den tekniske løsningen; hvordan passer dette egentlig inn i et reelt prosjekt, og hvilke hensyn må man ta?

Ved å ta utgangspunkt i et produkt jeg har vært med å utvikle, skal jeg forklare hva som er positivt med mikrotjenester, hva som er utfordrende og hvorfor det ikke nødvendigvis alltid er det riktige valget.

Da Alv startet i fjor tok vi en avgjørelse på å lage vårt eget timeføringssystem, AlvTime, fordi vi ikke var fornøyd med hyllevaren vi fant. AlvTime har siden utviklet seg til å bli et slags ankerpunkt og sentrum i vår faglige kultur og utvikling.

Vi valgte relativt tidlig å gå for en mikrotjeneste-arkitektur på grunn av et par sentrale punkter i filosofien vår som jeg vil gå inn på litt senere i artikkelen.

Først og fremst vil jeg utdype et par fordeler og ulemper med både monolitter og mikrotjenester.

«Da utviklingen av timeføring-systemet startet, var det kun én utvikler som jobbet på det.»

Fordeler med monolitter

Da utviklingen av timeføringssystemet startet, var det kun én utvikler som jobbet på det, og det ble da mest naturlig å lage én kodebase bestående av en .NET backend og React frontend, basert på en standardmal med både front- og backend publisert på samme server og alt i ett og samme GIT-repository. Dette ble gjort for å få et fungerende timeføringssystem opp å gå så fort som mulig.

Monolitter som dette kan være svært praktisk når man er få mennesker som jobber sammen, eller hvis det sjeldent gjøres endringer. Andre fordeler med monolitter er at man kan lett omstrukturere dem, da det er lett å flytte koden rundt. Det er lett å debugge, samt introdusere nye attributter, da man lett kan følge flyten av objekter fra en side av applikasjonen, til en annen.

Opptil en viss størrelse er de oversiktlige og relativt lette å ha med å gjøre, men det har noen begrensninger.

Med all koden i én kodebase tar det lenger tid å bygge koden og kjøre tester. Det gjør det tidkrevende og tungvint å slippe nye endringer og mye koordinering må fort til. Når man i tillegg får mange folk som jobber på den samme kodebasen, kan man fort ende opp med spagetti-kode hvis man ikke er forsiktig.

Dette er stort sett ikke noe man trenger å ta hensyn til i små team, og i hvert fall ikke på et prosjekt som AlvTime, som er mer som et hobbyprosjekt vi jobber på innimellom oppdragene. Dette fordi det er lettere å kommunisere seg imellom når man er få personer, i tillegg til at endringer skjer sjeldent.

Likevel valgte vi å gå over til mikrotjenester. Hvorfor det, egentlig?

Fordeler med mikrotjenester

Etter hvert som det ble ansatt flere utviklere med ulik kompetanse, besluttet vi å dele opp den opprinnelige monolitten i flere mikrotjenester. Mikrotjenester har et par fordeler over monolitter. Blant annet gir de raskere testing og raskere release.

Et av grunnprinsippene i AlvTime-prosjektet er at det i tillegg til å være et system vi faktisk bruker, skal være et prosjekt som bidrar til faglig utvikling. Det skal være en slags lekeplass, hvor folk skal kunne prøve ut ny teknologi og få erfaring og trening i systemutvikling. For at dette skal fungere, må det være lav terskel for å bidra. Hvis det er en stor og uoversiktlig kodeklump, hvor det tar lang tid å rulle ut nye endringer, vil bøygen være stor for å sette seg ned og kode.

«Vi har gått fra å ha en monolitt bygd i .NET og React, til å ha mikrotjenester utviklet i .NET, React, Vue, Typescript og Python.»

Som følge av denne tankegangen, har vi gått fra å ha en monolitt bygd i .NET og React, til å ha mikrotjenester utviklet i .NET, React, Vue, Typescript og Python.

For oss var det et åpenbart valg å gå for mikrotjenester for å gjøre det enklest mulig for noen å prøve ut et nytt språk, en ny teknologi, eller om de rett og slett bare vil lage sin egen app, som kan integreres mot en av de andre appene vi har fra før.

Dette er en løsning som er riktig for oss nettopp fordi vi vil det skal være enkelt for folk å teste ut det de skulle ønske. For et prosjekt med en mer fastsatt teknologi-stack vil ikke dette nødvendigvis være like viktig.

Noen andre store fordeler man får ved å bruke mikrotjenester, er at det er lettere å gjøre endringer internt i en tjeneste, da tjenestene har klart definert og begrenset output og input. Videre er en av de tingene jeg er mest fan av, at man kan skrive om og velge teknologier innad i en tjeneste uavhengig av de andre, slik at hvert team kan spille på sine styrker og interesser, uten at det trenger å påvirke andre.

Starte som monolitt

Ved å starte AlvTime som en monolitt, fikk vi en liten fordel litt på slump.

Det finnes flere gode argumenter for at det lønner seg å starte med å utvikle en monolitt, for så å bryte den opp i mikrotjenester senere. På denne måten får man en god oversikt over hvordan applikasjonen vil se ut i sin helhet og det vil være lettere å dele den opp i logiske deler.

Refaktorering mellom forskjellige tjenester vil være en god del mer krevende enn det vil være i en monolitt. Derfor er det mye gevinst å hente i å sette gode grenser mellom ulike kontekster og tjenester så tidlig som mulig.

Det er dog noen fallgruver her også.

Dersom monolitten ikke har noen klare grenser og ulike ansvarsområder og funksjonaliteter flyter over i hverandre, vil det være problematisk å dele det opp i definerte mikrotjenester. Det er derfor viktig å lage moduler i monolitten som senere kan enkelt splittes ut.

DevOps i mikrotjenester

Mikrotjenester blir ofte en del mer komplisert enn monolitter, da man har flere deler i bevegelse. Spesielt kan DevOps-delen bli uoversiktlig, med mange forskjellige pipelines, til mange forskjellige miljøer.

«Spesielt kan DevOps-delen bli uoversiktlig, med mange forskjellige pipelines, til mange forskjellige miljøer.»

Selv om mikrotjenester ofte har en større grad av kompleksitet sammenlignet med monolitter, er det spesielt én ting som blir enklere, nemlig skalering.

Med mikrotjenester kan man velge å skalere opp kun de tjenestene som har stor belastning og skalere ned de som ikke brukes noe særlig. Hvis det hele i tillegg orkestreres av en Kubernetes-klynge, kan den automatisk allokere ressurser til der de trengs mest og visse deler av løsningen kan skaleres opp og ned etter behov.

Å operere med kontainer-tjenester som Docker og Kubernetes gjør en del for å forenkle prosessen med å utvikle mikrotjenester. Foruten å gjøre skalering enklere, blir faren for nedetid mindre når alt er delt opp i mindre, uavhengige deler. Dersom en av mikrotjenestene går ned, vil en Kubernetes-klynge kunne spinne opp en erstatning ekstremt raskt.

Fordelen med mindre nedetid gjelder også selv om man ikke bruker konteinere, fordi selv om en mikrotjeneste går ned vil fortsatt de resterende tjenestene fortsette å fungere.

Er mikrotjenester alltid løsningen?

Alt er ikke alltid bare fryd og gammen med mikrotjenester.

En ting som kan være spesielt utfordrende, er logging og monitorering. For en monolitt kan det være nok å gå gjennom én enkelt logg, i motsetning til 4-5 ulike logger, for 4-5 ulike mikrotjenester. Det gjør det ekstra viktig med gode feilmeldinger og logging for å finne ut akkurat hvor i hvilken mikrotjeneste noe har gått galt når det gjør det.

Det samme gjelder for monitorering. Dette blir spesielt viktig når man får mange mikrotjenester, da man er veldig avhengig av å finne ut hvilke tjenester som bruker mer eller mindre ressurser enn forventet, eller å finne tjenester som bruker lenger tid enn forventet på et kall.

Dette kan bli ganske vanskelig å finne ut av dersom man ikke har satt opp automatisert monitorering, med gode dashboards.

Mikrotjenester har også utfordringen med at man får mange tjenester man skal forholde seg til og det setter derfor krav til at disse er logisk satt opp og at de bare gjør sin jobb og ikke noe uventet. Det er også viktig at man har konvensjoner, slik at alle lett kan gå inn i en ny mikrotjeneste og begynne å kode på samme måte som man har gjort i de andre tjenestene.

Punktene over, kombinert med at mikrotjenester som oftest brukes sammen med en kontainertjeneste, gjør at det ikke er noe tvil om at oppsett og infrastruktur krever litt mer innsats og kunnskap sammenlignet med monolitter.

«Dessverre er ikke alt svart-hvitt, med to streker under svaret.»

Konklusjon

Det er åpenbart mange hensyn og avgjørelser å ta i alle deler av et systemutviklingsprosjekt og hvordan man strukturerer opp tjenestene sine er kanskje et av de viktigste og første valgene man tar.

Mikrotjenester er veldig i vinden for tiden og det vil absolutt være det beste valget for mange prosjekter, spesielt store prosjekter med mange kokker hvor endringer skjer raskt og ofte.

Dessverre er ikke alt svart-hvitt, med to streker under svaret. Både monolitter og mikrotjenester kommer med hvert sitt sett av fordeler og ulemper.

Forhåpentligvis kan denne teksten være et godt utgangspunkt til en diskusjon om hvorvidt du skal gå for en monolitt eller mikrotjenester.