Onze laatste DeepDive ging over microservices. Wat is een microservices architectuur, en hoe verhoudt het zich met betrekking tot testen en development ten opzichte van een monolith.
Om eerst duidelijk te krijgen wat een microservices architectuur is, hebben we tijdens de deepdive onderstaand schema besproken. Dit is een voorbeeld van een System Under Test (SUT), die direct aangesproken wordt door de klant, maar die wel andere API’s aanroept. Deze SUT is opgedeeld in meerdere microservices MC1, MC2 etc. Indien die microservices dus als aparte miniapplicaties gedeployed worden, vaak ook in hun eigen repo opgeslagen, en apart benaderbaar en testbaar zijn, spreken wij over een microservices architectuur.
We hebben onderzocht wat de voor- en nadelen zijn van microservices. We zijn daarbij ingegaan op de volgende onderwerpen:
Kosten
Microservices kunnen makkelijker per component geschaald worden, zonder dat je het geheel moet opschalen. Daarmee heb je dus geen kosten voor het opschalen van iets wat niet direct nodig is. Al lijkt dit vooral interessant voor grote e-commerce bedrijven.
Doorgaans is het makkelijker om problemen te achterhalen en op te lossen in een microservices architectuur, het is vaak duidelijker waar (in welke microservice) het probleem moet zitten. En makkelijker werk zorgt voor een betere productiviteit en daarmee minder kosten per functionaliteit.
Doordat je kleinere stukken kunt opleveren, kun je een kortere time to market hebben, daarmee kun je dus eerder inkomsten genereren en dus ook meer inkomsten.
Doordat duidelijker is waar iets veranderd is, hoeft er minder/kan er gerichter per keer getest worden, waardoor je een kortere testtijd hebt, en dus minder testkosten.
Testen
In een microservices architectuur hoef je per component minder te testen dan voor de hele SUT. Dus als er alleen een wijziging in één microservice zit, hoef je van de andere microservices niet de microservice specifieke testen uit te voeren, dus test je in totaal minder.
Je kunt makkelijker kleine onderdelen stubben. Een nadeel is dat je meer dingen moet stubben. Elk voordeel heeft zijn nadeel.
Je kunt de verantwoordelijkheden en doelen beter scheiden doordat je meer testlevels hebt. Wie test wat met welk doel in welke omgeving.
Maar er zijn ook zeker nadelen. Als je de hele SUT wilt testen, moet je wel alle losse componenten zien te deployen, met de juiste versies, dit is complexer dan één monolith deployen.
Verder moet je als tester het geheel goed begrijpen en snappen hoe deze microservice past in de architectuur, maar ook hoe deze als losse microservice te gebruiken/ testen is.
Je krijgt op veel meer punten logging, namelijk van elke microservice, voor het debuggen moet je die logging aan elkaar zien te refereren.
CI/CD
Microservices zijn doorgaans klein, en zijn dus sneller te deployen dan de hele SUT. Dus als er maar één of enkele microservices zijn bijgewerkt, hoeft er minder gedeployed te worden.
Teams die aan één of enkele microservices werken, kunnen zo hun eigen onderdeel deployen en testen, zonder het geheel te hoeven kunnen deployen.
Middels Blue/Green deployments kun je makkelijk één of enkele microservices omzetten naar een nieuwe versie zonder dat je de volledige capaciteit van een 2e monolith tijdelijk in gebruik hebt.
Je creëert met een microservices landschap een complex configuratielandschap, en daardoor een grotere kans op o.a. configuratiefouten. Welke microservice zit met welke microservice verbonden.
Contract based testing
Contract based testing is best complex bij een microservices architectuur omdat er veel meer interfaces zijn dan bij een monolith. Zeker als je als team meerdere microservices ontwikkelt, is het voordeel van contract based testing beperkt.
In grote organisaties met veel teams die aan verschillende microservices werken, kan het wel voordeel bieden.
Er lijken vooral theoretische voordelen te zijn. Maar de praktische voordelen lijken wat ver te zoeken.
Test strategie en OTAP mbt microservices.
Theoretisch kun je met minder omgevingen overweg, maar de vraag is hoe het in de praktijk goed uitpakt. Onze ervaring is: allebei kan, meer of juist minder omgevingen.
Chaos monkey kan je ook helpen om te testen of je architectuur er tegen kan als je één microservice onderuit haalt, daarmee test je de onderlinge afhankelijkheid en eventueel aanwezige circuit breakers en retry mechanismes.
Testdata management is anders. Je hebt vaak meer DB’s dan bij een monolith, die allemaal vergelijkbaar gevuld moeten worden voor consistentie tussen de microservices, maar toch ook weer net anders doordat ze maar een subset nodig hebben per stuk.
Tips en tricks:
Aangezien een microservice gezien kan worden als een apart systeem, dat regelmatig ook door andere systemen gebruikt kan worden, dien je te zorgen dat deze microservice al het binnenkomende verkeer controleert, bijvoorbeeld middels een XSD.
Indien je als team meerdere microservices ontwikkelt die samen een SUT vormen waarbij die microservices per stuk niet door derden bruikbaar zijn, dan kun je er voor kiezen om de communicatie onderling niet meer intensief te checken. En dus alleen de microservice met een “externe” input uitgebreide checks te laten doen op binnenkomend verkeer.
Bij systemen (API’s), die onderdeel zijn van een groter landschap, is het verstandig om zogenaamde circuit breakers in te bouwen. Dit om, in geval van issues met één component in de keten, onnodig verkeer te voorkomen. Voor microservices kun je hetzelfde overwegen, al is dat wel best wat werk om het voor alle microservices in te bouwen.
Zorg dat je duidelijke interface specs hebt voor alle interfaces tussen de microservices. Indien je microservices extern bereikbaar zijn, heb je deze nodig voor je “klanten”. En ze zijn ook hard nodig om de testen op te baseren.
Zorg dat je op de extern facing microservices versionering toepast op de API’s. Indien enkele microservices alleen intern met andere microservices van hetzelfde team kunnen communiceren, dan is het niet direct nodig om versionering op die interfaces toe te passen.
Bij een microservices architectuur krijg je er makkelijker een testsoort en bijpassende omgeving bij. De component test kan op één microservice worden uitgevoerd, de systeemtest op alle microservices samen, en zodra je de externe API’s ook gaat koppelen, krijg je de systeem integratie test.
Conclusie
Wij hebben op deze DeepDive weer een boel geleerd. We zijn zeker niet unaniem over wanneer een microservices architectuur nu goed is en wanneer niet. Zoals wel vaker, ‘it depends’.
We hopen dat deze informatie jou kan helpen in jouw keuze en/ of in het testen van een microservices architectuur.
Wil je graag een volgende DeepDive bijwonen, volg ons dan op onze meetup pagina.