Wat zijn microservices?

Microservices zijn een manier om software op te delen in zelfstandige services met ieder een duidelijke verantwoordelijkheid. Een service bevat idealiter zijn eigen domeinlogica, beheert zijn eigen data en kan onafhankelijk van andere services worden ontwikkeld en gedeployed.

Voor mij zijn microservices alleen waardevol als die opsplitsing ook daadwerkelijk iets oplost.

Het aantal services zegt daarom weinig over de kwaliteit van een architectuur. Een systeem met twintig services kan nog steeds sterk gekoppeld zijn, terwijl een goed opgebouwde monolith juist heel overzichtelijk en schaalbaar kan zijn.

Hoe kijk ik naar microservices?

Ik zie microservices niet als het standaard einddoel van een backend-architectuur.

De belangrijkste vraag is voor mij eerst: waar liggen de verantwoordelijkheden binnen het systeem?

Pas wanneer die grenzen duidelijk zijn, kun je bepalen of het technisch en organisatorisch logisch is om onderdelen fysiek van elkaar los te trekken.

Een microservice moet wat mij betreft zelfstandig genoeg zijn om een eigen reden van bestaan te hebben. Wanneer twee services continu dezelfde data nodig hebben, voortdurend synchroon met elkaar communiceren en eigenlijk alleen samen kunnen worden aangepast, dan zijn het waarschijnlijk geen goede servicegrenzen.

Dan heb je vooral een distributed monolith gebouwd.

Wanneer is het goed om iets af te splitsen?

Ik kijk vooral naar de onafhankelijkheid van een onderdeel.

Afsplitsen wordt interessant wanneer een domein:

  • Een duidelijke eigen verantwoordelijkheid heeft

  • Onafhankelijk moet kunnen deployen

  • Andere schaalbaarheidseisen heeft

  • Een eigen lifecycle heeft

  • Eigen data en businessregels beheert

  • Door een afzonderlijk team beheerd kan worden

  • Niet voor iedere actie afhankelijk is van andere services

Een goed voorbeeld is wanneer één onderdeel van een platform veel meer verkeer verwerkt dan de rest. Wanneer dat onderdeel zelfstandig kan functioneren, kan een aparte service ervoor zorgen dat je alleen dat gedeelte hoeft te schalen.

Ook organisatorische grenzen zijn belangrijk. Als verschillende teams verantwoordelijk zijn voor verschillende domeinen, kunnen microservices technisch eigenaarschap ondersteunen.

Maar een teamgrens alleen is voor mij geen reden om software direct op te splitsen. De domeingrens moet technisch ook logisch zijn.

Wanneer blijf ik liever bij een monolith?

Een monolith heeft naar mijn mening onterecht een slechte naam gekregen.

Voor veel applicaties is een goed gestructureerde monolith juist de simpelste en meest duurzame oplossing.

Wanneer een applicatie nog relatief klein is, het domein sterk samenhangt of één team verantwoordelijk is voor het geheel, levert opsplitsen vaak meer complexiteit op dan waarde.

Je introduceert namelijk direct nieuwe problemen:

  • Netwerkcommunicatie

  • Distributed transactions

  • Eventual Consistency

  • Monitoring over meerdere services

  • Complexere deployments

  • Versiebeheer tussen interfaces

  • Meer infrastructuur

  • Complexere lokale ontwikkeling

Als daar geen duidelijke technische of organisatorische reden tegenover staat, zou ik die complexiteit niet toevoegen.

Ik begin daarom liever met duidelijke modules binnen één applicatie dan met meerdere losse services.

Een modular monolith kan veel van dezelfde domeingrenzen afdwingen zonder direct de operationele kosten van een distributed systeem te introduceren.

Eerst logisch scheiden, daarna fysiek scheiden

Dit is voor mij een belangrijk principe.

Voordat ik een onderdeel technisch als microservice zou afscheiden, wil ik eerst kunnen aantonen dat het logisch zelfstandig kan functioneren.

Dat betekent dat de grens tussen domeinen eerst duidelijk moet zijn in de software zelf.

Als twee modules binnen dezelfde applicatie al niet netjes van elkaar gescheiden kunnen worden, gaat een netwerkverbinding tussen diezelfde onderdelen het probleem niet oplossen.

Je maakt de afstand alleen groter.

Een goede modular monolith kan daarom ook een uitstekend vertrekpunt zijn richting microservices. Wanneer een module later voldoende zelfstandig wordt, kan deze relatief gecontroleerd worden afgesplitst.

Microservices brengen ook nieuwe complexiteit

Een microservice-architectuur verplaatst complexiteit.

Een lokale method call wordt bijvoorbeeld een netwerkrequest of event. Een database-transactie kan veranderen in een gedistribueerd proces. Een simpele stacktrace wordt observability over meerdere services.

Daarom vind ik dat je bij iedere opsplitsing moet kunnen uitleggen welke complexiteit je verwijdert en welke complexiteit je ervoor terugkrijgt.

Distributed systems vragen namelijk om andere keuzes rondom betrouwbaarheid, consistency en foutafhandeling.

Mijn ervaring met microservices, event-driven architecturen, Kafka, Redis Streams en consistency patterns heeft mij juist kritischer gemaakt op wanneer die architectuur nodig is.

Mijn uitgangspunt

Ik kies niet tussen een monolith en microservices op basis van voorkeur voor een architectuurstijl.

Ik kijk naar het probleem.

Als een monolith de gewenste schaalbaarheid, onderhoudbaarheid en ontwikkelsnelheid kan bieden, zou ik hem monolithisch houden.

Als delen van het systeem daadwerkelijk onafhankelijk moeten kunnen bewegen, dan wordt afsplitsen interessant.

Voor mij is een goede architectuur daarom niet degene met de meeste services, maar degene waarbij de grenzen logisch zijn en de complexiteit bewust is gekozen.

Veelgestelde vragen die ik krijg over Microservices

Wanneer zou jij een microservice afsplitsen?

Wanneer een onderdeel een duidelijke eigen verantwoordelijkheid heeft en ook technisch voldoende onafhankelijk kan functioneren. Alleen code kleiner maken vind ik geen goede reden.

Is een monolith slecht?

Nee. Een goed gestructureerde monolith kan juist eenvoudiger, goedkoper en beter onderhoudbaar zijn dan een onnodig complexe microservice-architectuur.

Begin je direct met microservices?

Meestal niet. Ik zou eerst duidelijke domeinen en modules creëren. Wanneer daar later natuurlijke servicegrenzen uit ontstaan, kun je gecontroleerd afsplitsen.

Wanneer heb je een distributed monolith?

Wanneer services technisch losstaan, maar functioneel nog volledig afhankelijk van elkaar zijn. Je hebt dan wel alle complexiteit van microservices, maar nauwelijks de voordelen.

Wat is voor jou het belangrijkste bij microservices?

Goede grenzen. Technologie komt daarna. Als de verantwoordelijkheden verkeerd verdeeld zijn, gaat Kafka, Kubernetes of welk framework dan ook dat niet voor je oplossen.