Zijn microservices de passende oplossing voor je API-ontwikkeling?

Jeroen van Dijk
Jeroen van Dijk

24 april 2019

Microservices, right fit?

Voor technische oplossingen anno nu worden cloudgedreven microservices gezien als oplossing voor flexibele en schaalbare IT als tegenhanger voor monolieten. Maar klopt dat beeld wel? Want je API die bestaat uit microservices betekent tientallen cloudconnecties met evenzoveel afhankelijkheden en dito complexiteit. Wanneer zijn microservices wel en wanneer zijn microservices niet de juiste oplossing voor je API-ontwikkeling? Dit artikel gaat over de balans tussen beide: Maak kennis met de microlith.

Service Oriented Architecture

Zo’n 10 jaar geleden hadden wij bij Enrise last van een SOA, en dat hadden we zelf veroorzaakt. SOA’s waren toen een populaire oplossing om monolithische applicaties technisch op te knippen. We waren ervan overtuigd dat ons dit zou helpen bij een uitdaging voor een grote klant.

Een Service Oriented Architecture introduceert een laag waarbij er technische scheiding gemaakt wordt tussen entiteiten die geen directe relatie met elkaar hebben. Developers worden daardoor gedwongen goed na te denken over het model, omdat je de services als losse applicaties kon benaderen.

De Service Oriented Architecture die voor ons had moeten werken, veroorzaakte echter meer uitdagingen dan voordelen. De applicatie was technisch makkelijker onderhoudbaar geworden, maar we kregen te maken met vertragingen die de onderhoudbaarheid teniet doen. De vertragingen waren afkomstig van de netwerkverbindingen. Elke service vereist een eigen connectie, maar elke connectie kan even haperen of net iets minder snel zijn dan normaal.

Hadden we wel goed gedaan aan deze keuze, of was een monolith niet een betere oplossing geweest?

Microservices in de cloud

Ongeveer 5 jaar geleden verfijnde het gedachtegoed rondom Service Oriented Architectures door het populairder worden van de DevOps strategie. DevOps, een samentrekking van development en Operations brengt softwareontwikkeling en de operatie (beheer, onderhoud en support) samen. En het werd eenvoudiger om applicaties te publiceren dankzij de opkomst van de cloud. Clouddiensten hebben de wereld van de hosting op zijn kop gezet en maakten het mogelijk om applicaties technisch nog verder op te breken in kleine services; de zogeheten microservices.

De vraag was alleen nog of deze strategie onze technische uitdagingen kon oplossen.

Hoe groot of klein is eigenlijk een microservice?

De term micro creëert verwarring zodra je dit onderwerp met elkaar bespreekt. Er is geen exacte definitie wat een microservice nu wel of niet behelst. Is een microservice wel een ‘micro’-service? Wat is de definitie van micro in de context van een technisch complexe applicatie? Martin Fowler, een evangelist in software design principes, heeft dit als volgt benoemd:

‘Microservices’ is a label, not a description.

Onze visie op microservices

Bij Enrise vinden we dat een microservice functioneel onafhankelijk moet zijn, taal-agnostisch is en volledig geautomatiseerd te testen en uit te leveren is.

Wij denken dan aan API’s die 1 functionaliteit bieden. Maar ook daar is geen definitie op te plakken. Wat is nu 1 functionaliteit? Iedereen heeft daar een verschillende visie op. En ga je dan je applicatie verdelen in 5, 10 of nog meer microservices die samen de oplossing voor je businesscase vormen?

Neem de volgende 6 gedachten mee in je overwegingen voordat je zelf aan de slag gaat met het opzetten van een microservicesarchitectuur voor je API-ontwikkeling.

1. Moving Complexity

Met een microservices-architectuur kun je complexe businesscases mogelijk beter oplossen dan bij een monolithische applicatie. Helaas verschuif je ook direct de complexiteit van eventuele problemen. Daar waar een Dev-team in een monolithische applicatie met een applicatie-debugger vaak eigenhandig tot een volledige oplossing kan komen, is bij een microservices-architectuur meer kennis nodig. Dit omdat eventuele problemen kunnen ontstaan op zowel applicatieniveau, netwerkniveau en/of infrastructuurniveau. En dat brengt bovendien beveiligingsvraagstukken met zich mee.

2. DevOps experience

De verschoven complexiteit toont direct aan waarom DevOps en microservices hand in hand gaan. Bij de keuze voor een monolithische architectuur komt de verantwoordelijkheid van het realiseren van een business case vooral aan op het Dev-team, de developers. Zij realiseren de broncode en kunnen de applicatie daarna vaak volledig overhandigen aan een Ops-team die het beheer van de applicatie op zich kan nemen. Het Dev-team kan zich daarna concentreren op de volgende benodigde aanpassingen.

In het geval van een microservicesarchitectuur bestaat de applicatie uit diverse services die ieder onafhankelijk van elkaar overgedragen worden aan een Ops-team. Bedenk dat daar problemen kunnen ontstaan. Wie lost ze op? Dev, Ops of een dedicated DevOps-team?

3. Fault Tolerance

Of het nu om een monolithische architectuur of microservicesarchitectuur gaat, voor developers is het altijd een goede gewoonte om defensief te programmeren. Redeneren vanuit foutscenario’s en veiligheid zorgt voor een kwalitatief beter werkende applicatie. Op broncodeniveau kan daardoor vaak al meer dan de helft van je code bestaan uit oplossingen om foutscenario’s te voorkomen. En dan ga je als developer ook nog uit dat de code die je schrijft altijd correct geïnterpreteerd- en uitgevoerd wordt door de compiler.

Voeg daar nu eens een microservice aan toe om data op te halen, die communiceert over HTTP en ergens op de wereld op een server draait. Denk je dan dat er minder fouten ontstaan? Het logische antwoord is uiteraard nee. Het voegt namelijk nog meer foutscenario’s toe waartegen je de applicatie resistent moet maken. En dat is dan alleen al het geval als je een microservice of API consumeert!

4. Independent Lifecycle

Aan de serverzijde van een microservice is het leven voor een developer niet veel makkelijker. Tenminste, als je het netjes wil doen. Dat een microservice slechts 1 functionaliteit omvat, betekent niet dat deze functionaliteit zo blijft. Er komen aanvullingen, maar er gaan ook zaken af. Stel nu dat je microservice inmiddels door tientallen, honderden of nog meer gebruikers afgenomen wordt? Dan moet je elke wijziging blijven ondersteunen. Een microservice heeft idealiter een onafhankelijke lifecycle, maar is in zijn succes afhankelijk van gebruikers. Wat is anders het nut van de microservice?

5. Change in Business Requirements

In het leven van mensen zorgt communicatie voor verwarring en problemen. Als mens hebben we dan ook nog nooit software kunnen bouwen die na interpretatie van onze vraag, volledig correct antwoord gaf met de exacte oplossing volgens onze wensen. Ik geloof ook niet dat er iemand is die dit wel kan. Het is wel exact die interpretatie van een vraagstuk waarmee een technische architectuur wordt neergezet die een businesscase omzet in een succes. En als het success dan komt, is de kans groot dat de businesscase daarop aangepast moet worden.

Stel, je hebt te maken met een scenario waarin wijzigingen doorgevoerd moeten worden in onafhankelijke microservices, dan moeten deze allemaal:

  • Onafhankelijk bijgewerkt worden;
  • Gepubliceerd worden;
  • Zowel de oude als nieuwe situatie ondersteunen;
  • De omnderlinge relaties verleggen;
  • En uiteindelijk de ondersteuning voor de oude situatie verwijderen.

Zou je dit in een enkele database hebben bij een monolithische applicatie, dan pas je de relatie aan met een paar code-wijzigingen en op naar de volgende!

Natuurlijk is dit een extreem voorbeeld, maar in de praktijk de normaalste gang van zaken. Eisen en wensen veranderen continu en daar moet je software-architectuur tegen bestand zijn, plus je lokale ontwikkelomgeving.

6. Develop locally

Het laatste aspect wat niet onderschat moet worden bij het inzetten van microservices is de lokale ontwikkelomgeving van een development-team. Je wilt een team zo goed mogelijk in staat stellen om de businesscase op lokaal niveau zo trouw mogelijk na te bootsen, zoals het in productie zal gaan werken.

Tegenwoordig kan dankzij virtualisatie-software een hoop gedaan worden om de productiesituatie na te bootsen, maar een computer heeft natuurlijk niet de ongelimiteerde resources zoals je in de cloud hebt. Microservices laten zich minder goed simuleren.

Exacte aantallen zijn hier niet voor te geven, maar zodra de ontwikkelomgeving tegenwerkt in het effectief realiseren van nieuwe functionaliteiten is je microservicesarchitectuur in gevaar. Een Dev-team wil van nature zo effectief mogelijk werken, tegenwerkingen worden niet getolereerd.

Met de bovenstaande 6 aandachtspunten bij de opzet van een microservicesarchitectuur lijkt de toekomst voor microservices complex, uitdagend of gewoon erg lastig. Toch niet. Met een goede aanpak kun je wel degelijk microservices inzetten in je API-ontwikkeling.

Maak kennis met de microlith

Als microservices op zichzelf niet perse de oplossing zijn voor je architectuur uitdaging, wat kun je dan doen? Wij leerden van het verleden, van zowel de monoliet in een Service Oriented Architecture, alsook de inzet van microservices. We bouwen een monoliet, met de voordelen van microservices: een microlith.

Een microlith laat zich het best vertalen als een Business Logic Layer, ingekort tot BLL. Dat is op zich een monoliet, een centrale unit waar alle waarheid staat; informatie, taken, rechten, tests, validaties, etc. Het is opgedeeld in modules, ondersteund met losse services. Binnen de BLL bepalen vooraf gedefinieerde workflows en validaties of services onderling wijzigingen bij elkaar mogen aanbrengen. Alle onafhankelijke taken in een workflow worden in een wachtrij geplaatst en stap voor stap uitgevoerd. De wachtrij bepaalt welke taken op welk moment worden geopend en doorgezet naar een volgende status. Gaat er iets fout in de workflow, dan gaat een taak altijd eerst terug naar een vorige status voordat het opnieuw zijn weg aflegt. Elke workflow kan taken uitvoeren die gedefinieerd zijn vanuit elke willekeurige module.

Door deze opzet heb je meerdere modulaire eenheden ofwel services, in 1 applicatie. De mate waarin je de eenheden opdeelt bepaal je zelf. Je kunt ze verder opsplitsen tot op het kleinste niveau, microservices zo je wilt. Zo’n microlith is een oplossing voor een onbeheersbare wolk van losse microservices, waarin het steeds lastiger wordt om al die services te blijven onderhouden, in tijd, geld en mankracht.

Waar beginnen? 4 Adviezen.

Als je nu voor de vraag staat welke servicearchitectuur je het best kunt toepassen, onthoud dan deze 4 adviezen:

1. Start Big

Denk groot in de opzet van je systeemarchitectuur. Opbreken in microservices en die onderling koppelen is makkelijker dan microservices samenvoegen tot 1 functionaliteit.

2. Build for failure

Ga altijd uit van het negatieve scenario. Ontwikkel voor de fouten en beperkingen die kunnen ontstaan.

3. Team skills

Heb je mensen voor security? Voor beheer? Voor development? Combineer development en operations door ze te blenden tot een DevOps-team. Je team is bepalend voor het succes van wat ze leveren. Zorg voor de skills, vooral als het gaat om werken met microservices.

4. Question the problem you’re solving

Blijf kritisch. Stel altijd de vraag waarom de oplossing die je maakt ook echt de oplossing is voor een langere termijn, de grotere schaal die je nastreeft en de communicatie-uitdagingen die ermee samenhangen.

Communicatieproblemen oplossen

Uiteindelijk lost een microservicesarchitectuur niet primair technische problemen op. Microservices lossen een samenwerkingsprobleem op. Vooral als je schaalt, met meer mensen werkt en systemen complexer worden, kunnen microservices die communicatie-uitdagingen aan en blijft begrip voor een architectuur beter onder controle!