Artikel top billede

Microservices - næste bølge inden for moderne software-udvikling

Klumme: Microservices er et af de mere lovende arkitekturmønstre for moderne softwareudvikling, som førende tech organisationer som blandt andet Netflix, Google, Facebook, Amazon, Uber, Zalando anvender i omfattende grad. Flere danske virksomheder er også gået i gang rejsen. Her får du forklaringen på, hvad microservices er for en størrelse.

Denne klumme er et debatindlæg og er alene udtryk for skribentens synspunkter.

Microservices er mindre selvstændige applikationer med deres egen logik og database, som løst koblede kommunikerer med hinanden og ofte i event-drevne mønstre.

Lad os tage et eksempel som Netflix – deres applikationsarkitektur er opdelt af mange mindre applikationer (+1000 microservices) som repræsenterer større eller mindre features.

Der findes jo ikke en ”netflix”-backbone som et COTS-produkt, men typisk vil et COTS-produkt (for eksempel ERP, SCM, CRM, eCommerce platforme) ”bundle” features sammen til én stor applikation/kodebase.

Det har nogle åbenlyse fordele, men også en lang række ulemper.

Microservices er forsimplet et arkitekturmønster, som anvender en række centrale principper og som kræver et underliggende infrastrukturelt fundament for reelt at fungere i praksis.

Det er et fundament, som kun indenfor de senere år er blevet muligt med event-platforme som Kafka og RabbitMQ kombineret med cloud native services som docker og kubernetes via Azure, AWS og Google kombineret med CI/CD pipeline-automation.

Dette er dog kun toppen af det teknologiske isbjerg, og det kræver grundige arkitektur forberedelser at vælge den rigtige sammensætning af en hel række centrale teknologier indenf or containers, container orchestration, cloud platforms, API gateways, CI/CD pipeline automation, application monitoring og logging, event platforms etc.

Dette vil blive uddybet i en fremtidig artikel.

Andre har den holdning, at microservice er ”SOA done right” eller i hvert fald at de teknologiske komponenter er på plads til, at man kan udvikle isolerede services som kan kommunikere med hinanden og stadig bevare et arkitekturmæssigt overblik.

Det skal dog siges, at microservices har en meget anden tilgang ift. inter-kommunikation og datamodeller sammenlignet med SOA.

Ordet ”micro” i microservices er i virkeligheden ikke en særlig sigende betegnelse for størrelsen på en applikation eller en service.

Lidt populært sagt kunne man også have kaldt det én capability app, som indikerer, at services/applikationer opdeles i autonome applikationer baseret på specielt en domain business capability opdeling.

Der er mange eksempler i praksis, hvor det viser sig at opdeling efter forretningsdomæner (på feature niveau) giver mindst mulige tværgående afhængigheder mellem services (og dermed de bedste forudsætninger for agile teams!).

Et af flere vigtige design kriterier for, at agile teams kan arbejde så uafhængigt af andre og dermed levere software i en langt større hastighed.

Det er en vigtig detalje som oftest bliver overset, at applikationsarkitekturen har en signifikant impact på ens operating model – f.eks. i Scaled Agile implementeringer.

Et kerne metodeværktøj indenfor microservices er domain-driven design (DDD), som anvendes til at identificere service og de forskellige afhængigheder.

Her er Eric Evans bog faktisk var forud for sin tid. Jeg hælder dog mere til Vernons bog omkring DDD, men begge er must-reads hvis man er interesseret i DDD. Metoden kan dog ligeledes være effektiv i generelt arkitekturarbejde.

Hvilke udfordringer forsøger microservice at være løsningen på?

Microservice er specielt blevet populært set i lyset af følgende punkter:

(1) En langt bedre optimering omkring specielt tre ikke-funktionelle krav – testability, maintainability og deployability. Dette opnås særligt ved at bevare den skarpe opdeling i særskilte applikationer med klare API’er.

(2) Kravet om at levere custom-built software langt mere frekvent til slutbrugere og bevare en høj fleksbilitet til at ændre applikations- og featurearkitekturen løbende parallelt med en forretningsmodel, som løbende også udvikler sig – Amazon og Uber er gode eksempler på dette.

(3) At være på forkant med digital udvikling og muligheden for at anvende nye frameworks og udviklingssprog, som er best-fit til at løse en konkret opgave.

(4) En høj tilgængelighed (availability) og ekstremt skalerbar platform, som muliggør en solid system performance globalt set – Netflix og Amazon som de mest ekstreme eksempler. Men Zalando er også et godt eksempel, som i en årrække forsøgte at optimere deres eCom platforme, hvor de til sidst var nødsaget til at implementere logik på database niveau, som igen gav en række kompleksitetsudfordringer.

(5) At skabe en høj autonomi i større udviklingsteams, så hver capability kan udvikle og deploy i den hastighed, som er krævet for det enkelte forretningsområde. Dette muliggjort uden at have høje omkostninger til tværgående teknisk og forretningsmæssig koordinering – se figur 1. Det er også derfor, at microservice går særdeles godt i spænd med en agil organisering som f.eks. Scaled Agile.

(6) Sikre at nye udviklere relativt nemt kan on-boardes og levere nye features uden at de skal have et omfattende kendskab til én samlet kodebase.

(7) At isolere fejl i en højere grad (fault isolation), så en uhensigtsmæssig handling i én del af applikationen ikke signifikant påvirker en anden del af applikationen (f.eks. SQL låsninger)

Kravet om at levere software-udvikling mere frekvent og bevare fleksibiliteten

Der er en vis tendens til, at større kodebaser har det med (1) at sande til over tid, (2) ikke overholde modulariteten og derved blive komplekse og (3) at vedligeholdelsen bliver vanskelig som igen leder til omfattende test og/eller fejl i produktion.

Selvfølgelig findes der også eksempler på det modsatte - jeg har personligt oplevet kodebaser på flere millioner linjers kode, som var gennemgående modulære og vel opdelte.

God kode praksis handler blandt andet om at skabe modularitet, genbrug og klar adskillelse i kodebaser for at sikre fleksibilitet og transparens når funktionalitet skal ændres og/eller udvides.

Man kan sige, at er ens udviklerproduktivitet stigende (for eksempel i form af genbrug) eller blot stabil i større kodebaser – så har man typisk en god kode praksis.

Men ofte opstår nogle meget centrale klasser eller tabeller (for eksempel lagertransaktionsområder i ERP-systemer), som har afhængigheder på tværs af kodeområder. Meget brede tabeller eller omfattende metoder, som kalder på tværs af moduler, er et godt eksempel på dette.

Dette forværres signifikant i miljøer, hvor man ikke nødvendigvis er klar over end-state i udviklingen eller hvor der har været mange forskellige udviklere inde over samme applikation.

Generelt når kodebaser vokser i bredden og dybden på grund af tilføjelse af flere features stiger kompleksiteten og derved minimeres evnen til at levere ændringer til den pågældende applikation.

Det påvirker også deployment hastigheden negativt, da én ændring i kodebasen kan have gennemgående effekt på den resterende del af kodebasen. Men ser derfor ofte deployments som ikke er særlig frekvente, hvor testen er særdeles vanskelig. Det medfører at deployment er indpakket i en solid mængde governance som igen gør introduktion af nye ændringer rigid.

Dette er i direkte modstrid med behovet for digital transformation og en fleksibel og tilpasningsdygtig arkitektur, hvor nye forretningsbehov nemt kan introduceres. Amazon er de mest progressive og har faktisk konkrete KPIer som måler på deployment til produktion – hvert 11.6 sekund bliver der deployed ny kode til produktion!

Microservice løser dette igennem mere velafgrænsede og signifikant mindre applikationer (deraf micro), hvor applikationsarkitekturen er modelleret omkring services eller business capabilities og kommunikere med hinanden igennem klare APIer.

Målet er at være i stand til at ændre én del af applikationen uden det har ”ripple-effect” igennem alle andre områder.

Det betyder samtidig, at realismen i at automatisere test og deployment bliver mere gældende – eller sagt på en anden måde; det er et krav.

"Eventual consistency" har en pris

Det kommer dog ikke gratis, da det medfører en øget kompleksitet pga. microservice i praksis er et distribueret system.

Eventual consistency bliver pludseligt et seriøst tema.

Pointen er dog, at jo større og mere komplekse systemerne bliver, jo mere bliver denne eventuel consistency opvejet. Se figur for Martin Fowler’s productivity vs. complexity model.

Men netop dette område bør tages meget seriøst, da det er én af de primære udfordringer i microservice, hvor ACID transaktioner (og specielt roll-backs) på tværs af moduler indenfor én applikation er meget simpel.

Det er langt mere komplekst i distribuerede systemer og bør grundigt tages i betragtning når microservice arkitekturen designes og særligt den underliggende integrationsarkitektur og event-styring.

Det er et meget omfattende område at forklare i én artikel, men jeg vil vende tilbage til det i en fremtidig artikel.

Muliggør digital transformation og anvend nye frameworks og udviklingssprog

Udviklingen i frameworks, udviklingssprog og teknologier er i konstant udvikling og giver nogle helt unikke muligheder i digital transformation – og ikke mindst for at tiltrække de bedste udviklere.

For eksempel er der en række scenarier, hvor NoSQL eller ElasticSearch er ekstremt anvendelig eller ift. udviklingssprog er Python særdeles anvendeligt ift. neurale netværk (deep learning).

Problemet er blot at i monolith orientede applikationer vælger man fra starten et udviklingssprog, en database teknologi osv. hvor det på et senere tidspunkt er meget vanskeligt at skifte teknologisk retning.

Derfor findes der også et vælg af applikationer derude, som stadig er bygget på noget som er grænsende til et teknologisk oldfund. Main frames er et eksempel på dette.

I en microservice arkitektur er det muligt at eksperimentere (indenfor rimelighedens grænser selvfølgelig) med nye teknologier og frameworks. Årsagen er simpel; man bygger mindre applikationer, som ikke låser den samlet applikation arkitektur fast til et givent framework.

For eksmpel kan applikationer/services bygges med specifikke formål, således at man ikke er låst til én database teknologi, men som eksempel kan anvende ElasticSearch til fuldtekst queries, SQL til det mere transaktionsorienteret og graph db til hierarki modeller.

Det kan bl.a. ses i figur 3, som viser en forsimpling af en microservice arkitektur for en distributed order management applikation.

Ser vi blot 10 år tilbage, har dette ikke været muligt, men specielt containers (oplagt via docker) samt kubernetes, Red Hat OpenShift, Pivotal Cloud Foundry, Eventuate, Kafka, Prometheus, Netflix spinnaker etc. har lagt grundlaget for at det nu kan realiseres.

Sådan vælger I, om microservice er et godt match

Som med meget andet i livet er microservice ”no free lunch”.

Der er en række specifikke trade-offs ift. distribuerede systemer, som nøje skal overvejes.

Specielt CAP theorem via event-orienteret distribuerede systemer giver en højere initial kompleksitet. Tænk på et eksempel, hvor I opdaterer en følgeseddel i Jeres ERP-system og som en del af denne proces skal der også udføres en anden kørsel.

Det er super simpelt i monolith applikationer, hvor kørsel kan være en efterpostering i samme ”call stack”, men vil være et netværkskald (med de udfordringer det kan give) til en selvstændig applikation – det betyder eventual consistency.

Valget står derfor imellem at bygge én monolith orienteret applikation (eller købe en COTS applikation) versus at bygge en række selvstændige applikationer i en microservice arkitektur. Dog er der god ræsonnement i, at kan man ikke bygge en monolith orienteret applikation som overholder god kodepraksis, så vil man heller ikke være i stand til at bygge en applikation baseret på en microservice arkitektur.

Faktisk vil det give endnu større problemer.

Samtidig er det ofte en god idé at starte ud med at bygge en monolith orienteret applikation og derfra udskille områder når applikationen starter på at løse et nyt domæne. Dette er selvfølgelig hvis man ikke på forhånd kan planlægge arkitekturen via DDD.

Er udgangspunktet en eksisterende applikation vil der være en række andre mønstre som er vigtige (f.eks. ”stranger pattern”).

Men når man skal ud på microservice rejsen bør I vurdere dette ift. en række kriterier, som kan have højere eller mindre betydning i Jeres situation. Men nedenstående er en god guidance til valg af microservice vs. monolith mønstre:

1. Domæne kompleksitet og tværgående afhængighed mellem features.

2. Volume og skaleringskravene – få nu styr på jeres non-functional requirements.

3. Hvor kompleks er den nuværende applikation eller forventningerne til den nye.

4. Geografisk placering og/eller graden af latency.

5. Hvor moden er den interne udviklingsorganisation ift. udviklingspraksis.

6. Hvor bevidst er organisationen omkring ”responsibility” og afhængigheder mellem sub-domæner.

7. Antallet af udviklere som arbejder på den tværgående applikation på samme tid.

8. Er der forskelligheder ift. udviklingshastighed indenfor samme domæne som applikationen skal understøtte.

9. Hvordan er den nuværende udvikler produktivitet – stigende, stagnerede eller faldende.

10. Findes der et udpræget behov for at anvende forskellige udviklingssprog pga. forretningskravene kræver nogle specialiserede løsninger.

Afslutning

Microservice er et felt som er i en hastig udvikling og spænder over en række teknologiske områder og principper som er for omfattende at beskrive i denne introduktionsartikel. Men nogle af de vigtigste er følgende:

1. Infrastruktur, teknologiske platforme og deployment.

2. Refactoring af en eksisterende applikation til microservice mønstre via ”stranger pattern”.

3. Command Query responsibility segregation (CQRS)

4. Message platforme og tilgange (f.eks. dumb pipes, sma.rt end-points).

5. Decomposition metoder (domain-driven design).

6. API Gateways og backends for frontends.

7. Event sourcing.

8. Automatisering indenfor CI/CD pipelines.

9. Monitoring og logging.

10. Agile development og organisering.
Og det skal vi selvfølgelig se nærmere på i en række fremtidige artikler.

Som afslutning - hvis jeg skulle vælge ét teknologisk område, som ville være det allervigtigste ift. microservice implementeringer så er det sandsynligvis integration (populært sagt dumb pipes, smart end-points + en del mere). Det er samtidigt formodentligt uden undtagelse, at alle virksomheder som har stor succes med microservices har en ekstrem forståelse for løst-koblede systemer og de underliggende infrastrukturelle platforme som event-platforme (f.eks. Kafka) samt API gateways osv.

Designes arkitekturen ikke korrekt er risikoen for at få signifikant mere omfattende udfordringer større ved microservice end blot én monolith applikation. Derfor bør arkitekturen ikke undervurderes.

Men designes arkitekturen korrekt og bliver løbende justeret vil det åbne op for nogle helt unikke muligheder i Jeres digitale transformation, som ikke kan opnås på andre måder.

Klummer er læsernes platform på Computerworld til at fortælle de bedste historier, og samtidig er det vores meget populære og meget læste forum for videndeling.

Har du en god historie eller har du specialviden, som du synes trænger til at blive delt?

Læs vores klumme-guidelines og send os din tekst, så kontakter vi dig - måske bliver du en del af vores hurtigt voksende korps af klummeskribenter.