- Microservices vereisen een zorgvuldige opzet van services, data, veerkracht en contracten om in een productieomgeving te kunnen functioneren.
- Kubernetes/OpenShift, CI/CD en GitOps maken de automatisering van grootschalige implementaties, schaling en beheer mogelijk.
- Zero Trust-beveiliging, robuust configuratiebeheer en observability met OpenTelemetry vormen de pijlers van het platform.
- De organisatie van het productteam en gedistribueerd bestuur zijn net zo belangrijk als de gekozen technologie.
Het implementeren van een microservices-architectuur in de praktijk gaat niet alleen over het opsplitsen van een monolithische applicatie in kleinere onderdelen; het vereist een heroverweging van infrastructuur, teams, processen, data, beveiliging en operationele aspecten . Wanneer het systeem van theorie naar een productieomgeving overgaat, ontstaan er problemen met betrekking tot service discovery, afspraken tussen teams, CI/CD, observability, veerkracht en schaalbaarheid. Als deze problemen niet goed worden aangepakt, kunnen ze microservices veranderen in een gedistribueerde chaos.
Het goede nieuws is dat we tegenwoordig beschikken over een schat aan ervaring van organisaties zoals Netflix, Amazon, Google en andere grote bedrijven die honderden microservices in productie draaien . Voortbouwend op deze lessen, in combinatie met best practices in bedrijfsomgevingen met Kubernetes en OpenShift, kunnen we een zeer robuuste aanpak ontwikkelen voor het ontwerpen, implementeren en beheren van microservices op grote schaal, zonder de controle te verliezen.
Waarom microservices in productie nemen (en wanneer is het niet de moeite waard)?
Een goed ontworpen microservices-architectuur stelt je in staat om te werken met kleine, autonome en multidisciplinaire teams die de volledige verantwoordelijkheid dragen voor een service. Elk team opereert binnen een duidelijk afgebakende context, kan frequent implementeren en neemt de volledige verantwoordelijkheid voor zijn service op zich. Dit verkort de ontwikkeltijd en versnelt de levering van nieuwe functionaliteiten.
Een ander belangrijk voordeel is de onafhankelijke schaalbaarheid per service . U hoeft niet de hele applicatie te overdimensioneren als alleen de catalogus, de checkout of de openbare API pieken in het verkeer ondervindt. U kunt elke microservice horizontaal of verticaal aanpassen aan het belastingpatroon, de kosten van elke functionaliteit nauwkeurig meten en de beschikbaarheid behouden, zelfs als een specifiek onderdeel een piek in het gebruik ervaart.
De manier waarop deze services worden verpakt en geïmplementeerd, maakt continue implementatie met een laag risico mogelijk . Door elke microservice onafhankelijk uit te brengen, wordt het testen van nieuwe ideeën en het terugdraaien van problematische versies veel eenvoudiger: canary-implementaties, blue/green rollbacks en geautomatiseerde rollbacks verlagen de kosten van mislukking en bieden ruimte voor experimenten.
Vanuit technologisch oogpunt bieden microservices de vrijheid om voor elke service de juiste programmeertalen, frameworks en databases te kiezen . Niet alle behoeften passen in dezelfde technologiestack: je kunt bijvoorbeeld zakelijke services in .NET of Java hebben, dataverwerking in Scala/Spark, gespecialiseerde services in Python of F#, of AI-microservices in R. Deze gecontroleerde diversiteit stelt je in staat om voor elk geval de juiste tool te gebruiken, zonder de hele applicatie te dwingen tot een algehele technologische verschuiving.
Bovendien maakt het opsplitsen van het systeem in kleine, goed gedefinieerde onderdelen het hergebruik van functionaliteiten als bouwstenen mogelijk . Een microservice die aanvankelijk is ontwikkeld als onderdeel van een grotere functionaliteit, kan later worden hergebruikt als afhankelijkheid van andere onderdelen van het systeem zonder de logica te hoeven herschrijven. En omdat de services geïsoleerd zijn, leidt een storing in een ervan meestal tot gedeeltelijke systeemverslechtering en niet tot een volledige systeemuitval, mits er vanaf het begin rekening is gehouden met redundantie.
Architectuur- en serviceontwerp

Om microservices goed te laten functioneren in een productieomgeving, is het essentieel om te beginnen met een zorgvuldig ontwerp van de servicegrenzen en -verantwoordelijkheden . In de praktijk begint dit meestal met het identificeren van grofkorrelige services binnen de bestaande monolithische applicatie: grote functionele gebieden of bedrijfsdomeinen (bijv. bestellingen, catalogus, gebruikers, facturering) die al een zekere logische scheiding kennen.
Beginnend met deze grote bouwstenen, omvat het proces het verfijnen van het ontwerp om fijnmazige microservices te verkrijgen die werken met een samenhangende dataset , hun eigen model beheren en precies weten wat ze van andere services moeten lezen of naar andere services moeten schrijven. Dit proces is doorgaans gebaseerd op concepten van domain-driven design (DDD) en bounded contexts, waardoor wordt voorkomen dat een microservice een "mini-monoliet" wordt.
De API's die deze services beschikbaar stellen, moeten goed gedefinieerde en stabiele contracten hebben . Dit impliceert rigoureuze documentatie (REST met OpenAPI, gRPC met .proto-bestanden, enz.), expliciete versiebeheer, het waar mogelijk behouden van achterwaartse compatibiliteit en het automatiseren van contractvalidatie om ingrijpende wijzigingen te detecteren voordat ze in productie worden genomen.
In omgevingen met tientallen of honderden services is het cruciaal om al in de ontwerpfase veerkrachtpatronen te integreren, zodat het systeem is voorbereid op gedeeltelijke storingen . Patronen zoals circuit breakers, retries with backoff, goed gedefinieerde timeouts, bulkheads en backpressure helpen voorkomen dat de uitval van één service de rest platlegt. Chaos engineering tools zoals ChaosMonkey of Gremlin zijn nuttig om in de praktijk te testen hoe het platform zich gedraagt onder gesimuleerde storingen.
Veel complexe systemen combineren relatief eenvoudige CRUD-services met meer geavanceerde services die inspelen op veranderende bedrijfsregels. Niet alle microservices vereisen een complexe interne architectuur : sommige kunnen eenvoudige HTTP-controllers zijn met basisgegevenstoegang, terwijl andere, zoals order- of facturatieservices, gebruik kunnen maken van geavanceerdere patronen (DDD, CQRS, domeingebeurtenissen, enz.).
Productie-infrastructuur: cloud, containers en Kubernetes/OpenShift
De praktijk wijst uit dat microservices veel beter presteren wanneer ze worden ingezet op cloudinfrastructuur met containers en orchestratie dan op geïsoleerde virtuele machines. Platforms zoals Kubernetes en OpenShift bieden de benodigde basisfunctionaliteit om services als containers te verpakken, te schalen, te updaten, de belasting te verdelen en hoge beschikbaarheid te garanderen.
Doorgaans wordt elke microservice verpakt in een containerimage op basis van een bedrijfsbrede basisimage (bijvoorbeeld OpenJDK 21 voor Java-services) die wordt beheerd door het infrastructuurteam. Deze basisimage wordt up-to-date gehouden met beveiligingspatches en wanneer een nieuwe versie wordt uitgebracht, zijn de ontwikkelteams verantwoordelijk voor het opnieuw compileren en implementeren van hun services in de bijbehorende omgevingen.
In Kubernetes/OpenShift is de basisimplementatie-eenheid de pod, die een of meer containers bevat . Een microservice komt doorgaans overeen met een pod-type en wordt geïmplementeerd met behulp van resources zoals Deployments (voor stateless services) of StatefulSets (wanneer er een bijbehorende state is). Vanaf het begin wordt een minimum aantal replica's per omgeving gedefinieerd, zodat test-, pre-productie- en productieomgevingen beschikbaarheidsniveaus hebben die passen bij hun kritikaliteit.
Automatische schaling wordt geïmplementeerd met behulp van HorizontalPodAutoscaler (HPA) , die het aantal replica's aanpast op basis van statistieken zoals CPU, geheugen of andere aangepaste statistieken. Het platform moet ook anti-affiniteitsregels voor pods configureren om replica's van dezelfde service over verschillende knooppunten te verdelen, zodat een storing op één knooppunt niet alle instanties platlegt.
Wat verticale dimensionering betreft, worden resources.requests en resources.limits gebruikt om het bereik van CPU en geheugen te definiëren dat een pod kan verbruiken. Bijvoorbeeld door minimaal 100 MB CPU en 256 MB geheugen te reserveren, en respectievelijk maximaal 500 MB en 2 GB toe te staan voor een Java-service, waarbij de JVM (Xms, Xmx, Xss) wordt aangepast om de resources van de container optimaal te benutten.
Statusbeheer: stateless en stateful microservices
De meeste zakelijke microservices zijn ontworpen als stateless services . Dit betekent dat de pod geen informatie opslaat die na een herstart behouden moet blijven; de status wordt opgeslagen in externe databases, berichtenwachtrijen of andere opslagmedia. Deze aanpak maakt dynamische horizontale schaling en probleemloze implementaties mogelijk, omdat elke replica elk verzoek kan afhandelen.
Er zijn echter scenario's waarin er geen alternatief is dan stateful microservices te ondersteunen met persistente volumes . Dit is het geval voor sommige databases, gedistribueerde bestandssystemen of componenten die lokale data moeten bewaren. Deze pods worden doorgaans geïmplementeerd met StatefulSets, gekoppeld aan PersistentVolumes met behulp van PersistentVolumeClaims, en schalen verticaal in plaats van horizontaal.
Wanneer een microservice permanente opslag nodig heeft, wordt een PersistentVolumeClaim (PVC) aangevraagd met de gewenste grootte, toegangsmodus en beoogde gebruik . Het operationsteam voorziet deze vervolgens in de juiste configuratie volgens het platformbeleid. Deze PVC wordt opgenomen in het implementatiemanifest en gekoppeld aan de pod, zodat de service permanent gegevens kan lezen en schrijven.
Hoewel stateful modellen in specifieke gevallen noodzakelijk kunnen zijn, is de algemene aanbeveling om zoveel mogelijk services stateless te houden . Dit vereenvoudigt de implementatie, schaalbaarheid, veerkracht en het herstel na rampen, en vermindert de operationele complexiteit in omgevingen met veel microservices.
Datadecentralisatie en servicesoevereiniteit
In traditionele infrastructuren is het gebruikelijk om databases en opslag te centraliseren om de efficiëntie te maximaliseren. Bij microservices staat deze aanpak echter haaks op de autonomie en ontkoppeling van teams . Als veel services hetzelfde relationele schema delen, kan elke structurele wijziging meerdere teams blokkeren en onbedoeld de compatibiliteit verbreken.
Daarom is het aanbevolen dat elke microservice zijn eigen datamodel en database beheert , hoewel die database in een ontwikkelomgeving als een container binnen het cluster draait om de implementatie te vereenvoudigen. In een productieomgeving worden doorgaans cloud-managed instances of andere databaseservers met hoge beschikbaarheid gebruikt, waarbij altijd een duidelijke eigendomsgrens wordt gehandhaafd.
Dit betekent niet dat er geen data-integratie is; het betekent dat de consistentie tussen services wordt beheerd met behulp van gebeurtenissen en asynchrone berichtenuitwisseling , waarbij uiteindelijke consistentie wordt geaccepteerd wanneer dat redelijk is. Het is gebruikelijk om gebeurtenisbussen (RabbitMQ, Azure Service Bus, Kafka, enz.) te gebruiken om statuswijzigingen tussen microservices door te geven, waardoor de sterke afhankelijkheid van één enkele database wordt verminderd.
Het cloudplatform maakt het voor teams eenvoudig om voor elke service het optimale databasetype te kiezen (relationeel, document, key-value, tijdreeks, enz.), zonder één specifieke technologie op te leggen. De sleutel is dat bij het ontwerp rekening wordt gehouden met de mogelijkheid om schema's en structuren te migreren zonder contracten met andere services te verbreken, en dat databeslissingen worden genomen in lijn met de domeingrenzen van elke microservice.
Gedistribueerd bestuur, teams en organisatie
Overstappen op microservices zonder de organisatiestructuur te veranderen, is vragen om problemen. In plaats van de klassieke functionele silo's van netwerken, systemen, databases, ontwikkeling en operations , wordt een structuur gebaseerd op productteams aangemoedigd, waarin profielen van ontwikkeling, QA, DevOps en, waar van toepassing, business- of data-analisten worden samengebracht.
Elk team is verantwoordelijk voor een of meer microservices binnen hetzelfde functionele domein en verzorgt zowel de ontwikkeling als het beheer (je bouwt het, je voert het uit) . Dit betekent dat het team zijn CI/CD-pipelines beheert, samenwerkt met de infrastructuur voor specifieke behoeften en deelneemt aan monitoring en incidentafhandeling. De infrastructuur en het cloudplatform zijn gericht op het leveren van gemeenschappelijke en gestandaardiseerde services.
Om te voorkomen dat dit gedistribueerde bestuur in anarchie ontaardt, is het cruciaal om lichtgewicht standaarden en gedeelde catalogi te definiëren : goedgekeurde basisimages, implementatiepatronen, naamgevingsconventies voor namespaces en services, API-richtlijnen, Dockerfile- en Kustomize-sjablonen, enzovoort. Deze richtlijnen dienen als "vangrails" die teams richting geven zonder hun besluitvormingsvermogen te belemmeren.
In veel bedrijfsomgevingen worden aparte namespaces gebruikt voor elk project of domein , met ten minste één per omgeving (ontwikkeling, pre-productie, productie). Een groot project kan zijn microservices over meerdere namespaces verdelen, mits de interne communicatie correct is geconfigureerd en de beveiligingsregels worden nageleefd.
CI/CD, automatisering en het GitOps-model
Wanneer een architectuur uit tientallen of honderden microservices bestaat, is de enige manier om ze operationeel te houden, fors te investeren in end-to-end automatisering . Dit omvat consistente CI/CD-pipelines, declaratieve implementatiedefinities, geautomatiseerd testen en automatische terugdraaimechanismen.
Een typische continue integratie- en leveringspipeline (CIDD) omvat het compileren van code, het uitvoeren van tests, het analyseren van de kwaliteit met tools zoals SonarQube , het bouwen van de containerimage op basis van het Dockerfile van het bedrijf en het bijwerken van de implementatiemanifesten. Vervolgens past een systeem zoals ArgoCD of een vergelijkbaar systeem de wijzigingen toe op het cluster met behulp van een GitOps-aanpak.
Elke microservice-repository bevat doorgaans een gestandaardiseerd Dockerfile, een pipeline-configuratiebestand (bijv. ci.json) , eigenschappen voor kwaliteitsanalyse en een implementatiemap met Kubernetes-definities (Kustomize of Helm), gescheiden per omgeving. De webhooks van de repository activeren de pipeline wanneer gebeurtenissen zoals het pushen van tags of merge-verzoeken plaatsvinden.
Het GitOps-patroon stelt de Git-repository vast als de bron van waarheid voor infrastructuur en implementatie . Manifesten voor implementaties, services, ConfigMaps, PVC's, SealedSecrets en andere resources worden daar geverifieerd, en specifieke tools zorgen voor de synchronisatie van de clusterstatus met wat in Git is gedefinieerd. Dit biedt traceerbaarheid, maakt het mogelijk om pull requests te beoordelen en zorgt voor eenvoudige terugdraaimogelijkheden.
Instellingen, geheimen en beveiliging
In een volwaardig microservicesplatform is configuratiebeheer gebaseerd op ConfigMaps voor niet-gevoelige parameters en Secrets voor vertrouwelijke informatie . Elke microservice heeft doorgaans zijn eigen omgevingsspecifieke ConfigMap, waarin eigenschappen zoals URL's van afhankelijke services, functionaliteitsvlaggen en afstemmingsparameters worden opgeslagen.
Geheimen (referenties, sleutels, tokens, certificaten) worden beheerd volgens strikte beveiligingsrichtlijnen . In minder kritieke omgevingen kan het acceptabel zijn om ze in platte tekst te bewaren en te laten beheren door het ontwikkelteam, maar in pre-productie- en productieomgevingen wordt aanbevolen om ze te versleutelen met behulp van tools zoals Sealed Secrets of specifieke externe cloudgebaseerde beheersystemen.
Wanneer een geheim gedeeld moet worden tussen meerdere services (bijvoorbeeld OTEL Collector-referenties of een gemeenschappelijke sleutelopslag ), kan het gecentraliseerd worden in een configuratierepository per namespace. Projecten die die namespace delen, coördineren de updates ervan wanneer nodig, waardoor ze controle behouden over wie deze resources kan lezen of wijzigen.
Wat betreft communicatiebeveiliging is het dominante patroon Zero Trust : niets wordt als vanzelfsprekend beschouwd, simpelweg omdat het verkeer "intern" is. Alle aanroepen tussen services, zowel intern als extern, moeten worden geauthenticeerd en geautoriseerd, idealiter met mTLS, JWT-tokens of andere gelijkwaardige mechanismen. Microservices delegeren de beveiliging niet blindelings aan de API Manager of het netwerk; ze voeren ook hun eigen controles uit.
Communicatie tussen microservices, API's en berichtenverkeer.
In een volwaardige microservices-architectuur is de communicatielaag opgedeeld in verschillende cases. Voor verkeer van clients (browsers, mobiele apps, externe partijen) naar de back-end worden gepubliceerde API's gebruikt die beheerd worden door een API Manager . Deze API's zijn doorgaans RESTful (vaak met OpenAPI) of, in sommige gevallen, gRPC, beschikbaar gesteld via een gateway.
Aanroepen tussen microservices die zich in dezelfde namespace bevinden, of zelfs tussen meerdere namespaces binnen hetzelfde project, worden doorgaans afgehandeld door interne Kubernetes-services met interne DNS . Deze aanroepen omzeilen de openbare API Manager, maar voldoen wel aan de beveiligings-, authenticatie- en autorisatieregels. Voor dergelijke scenario's kan een service mesh of interne gateways die gemeenschappelijke regels afdwingen, worden gebruikt.
Wanneer microservices tot verschillende functionele domeinen of projecten behoren , wordt communicatie op organisatieniveau als "openbaar" beschouwd. In dergelijke gevallen is het gebruikelijk om een API Manager of een interoperabiliteitsbus te gebruiken, waar contracten, quota, beveiliging, versiebeheer en auditing worden beheerd, waardoor directe koppeling tussen onafhankelijke clusters of namespaces wordt voorkomen.
Wat betreft integratie met legacy- of externe systemen, die mogelijk niet altijd moderne API's beschikbaar stellen, wordt vaak gebruikgemaakt van specifieke connectors via een interoperabiliteitsbus . Op deze manier spreken microservices een gemeenschappelijke taal (bijvoorbeeld gebeurtenissen of interne REST API's), en de connector verzorgt de vertaling van en naar het legacy-systeem, altijd met verbeterde beveiliging.
Naast synchrone communicatie speelt asynchrone berichtgeving een belangrijke rol . Het wordt gebruikt om processen te ontkoppelen, pieken op te vangen, zakelijke gebeurtenissen tussen services te verspreiden en de veerkracht te verbeteren. Elke gebeurtenis heeft doorgaans een goed gedefinieerd en versiebeheerd schema, met trackingmechanismen om storingen tussen producenten en consumenten te voorkomen naarmate de gebeurtenissen zich ontwikkelen.
Observeerbaarheid, OTEL-collector en werking
In een systeem dat uit veel microservices bestaat, is het diagnosticeren van een probleem zonder goede observability vrijwel onmogelijk. Daarom worden metrics, gecentraliseerde logging en gedistribueerde traces vanaf de ontwerpfase geïntegreerd , waardoor inzicht wordt verkregen in wat er gebeurt op zowel service- als platformniveau.
Een centraal onderdeel van dit schema is de OpenTelemetry Collector (OTEL Collector) , die in de namespace of centraal wordt geïmplementeerd om metrics, logs en traces van alle componenten te verzamelen. Microservices hoeven alleen te weten dat ze hun telemetrie naar de Collector moeten sturen; de Collector stuurt deze vervolgens door naar de observatiesystemen (Prometheus, Grafana, Jaeger, Elastic, enz.) zonder dat de service de details hoeft te kennen.
Voor de infrastructuurlaag worden collectors en exporters op node-niveau gebruikt om CPU-, geheugen-, schijf-, netwerk- en loggegevens van de pods te verzamelen en deze respectievelijk naar Prometheus en Elasticsearch te sturen. Tools zoals Grafana en Kibana worden gebruikt om deze informatie te visualiseren, dashboards te bouwen en waarschuwingen te definiëren met slimme drempelwaarden en bijbehorende runbooks.
Wanneer een project zeer specifieke verwerking van zijn meetwaarden of traceringen vereist, kan het een eigen instantie van OTEL Collector in zijn namespace implementeren, mits er operationele goedkeuring is en het productieonderhoudsmodel duidelijk is.
Teststrategie, contracten en lokale ontwikkelingservaring
Het testen van een gedistribueerde microservices-architectuur vereist een geavanceerdere teststrategie dan het testen van een monolithische applicatie. Unit-tests blijven essentieel, maar contracttests (voor API's en gebeurtenissen), integratietests tussen services en end-to-end-tests die complete processen doorlopen, worden steeds belangrijker.
Om compatibiliteitsproblemen te voorkomen, worden technieken zoals consumentgerichte contracttesten gebruikt , waarbij klanten de API-verwachtingen definiëren en serviceproviders daaraan voldoen. Elke contractwijziging wordt geautomatiseerd getest binnen de CI-pipelines, waardoor implementaties die problemen veroorzaken voor bekende gebruikers worden voorkomen.
Wanneer het aantal services de honderd overschrijdt, wordt het onpraktisch om het hele systeem lokaal te repliceren. Daarom is de ontwikkeling afhankelijk van simulaties van afhankelijke services of tunneling naar externe omgevingen . Ontwikkelaars lanceren doorgaans slechts een subset van microservices en simuleren de rest met mocks, fakes of simulators, of leiden bepaalde aanroepen om naar een gedeelde integratieomgeving.
End-to-end testen is steeds vaker gebaseerd op tijdelijke omgevingen of "previews" die worden gecreëerd vanuit feature branches. Deze omgevingen vormen een geïsoleerde omgeving met de services die relevant zijn voor de betreffende functionaliteit. Dit minimaliseert wrijving tussen teams, vermindert het "het werkt op mijn machine"-effect en detecteert integratieproblemen voordat duurdere omgevingen zoals pre-productie worden bereikt.
Implementatiepatronen voor microservices in productieomgevingen
Naast Kubernetes zijn er verschillende implementatiepatronen voor microservices in productie die het waard zijn om te kennen, omdat ze verschillende scenario's op het gebied van isolatie, kosten en volwassenheid aanpakken . Een van de oudste patronen is het gebruik van meerdere service-instanties per host, waarbij een enkele fysieke of virtuele host meerdere instanties van verschillende services draait, meestal op een gedeelde applicatieserver.
Bij het per-VM-service-instance -patroon wordt elke service verpakt als een VM-image (bijvoorbeeld een EC2 AMI) en draait deze op een eigen instantie. Dit biedt een sterke isolatie, maar gaat ten koste van een hoger resourceverbruik en langere opstarttijden. Tools zoals Packer of oplossingen van cloudproviders maken het eenvoudig om productiegereedde VM-images te genereren.
Het meest gangbare patroon is tegenwoordig de service-instantie per container , waarbij elke microservice wordt gebouwd als een containerimage en geïmplementeerd op een orchestrator (Kubernetes, OpenShift, enz.). Containers zijn lichter dan virtuele machines, starten zeer snel op en stellen je in staat om alles wat nodig is voor de service te bundelen, waardoor implementaties worden vereenvoudigd en automatisch schalen mogelijk wordt.
Tot slot zijn serverloze benaderingen, zoals AWS Lambda , populair geworden. Deze pakketten bevatten functies die reageren op HTTP-verzoeken of gebeurtenissen van andere services (S3, DynamoDB, wachtrijen, enz.), waarbij gebruikers alleen betalen voor wat ze gebruiken. Dit patroon is met name geschikt voor zeer kleine microservices of kortstondige, gebeurtenisgestuurde taken, hoewel het extra aandachtspunten met zich meebrengt met betrekking tot observeerbaarheid, cold starts en uitvoeringslimieten.
In de praktijk kiezen veel organisaties uiteindelijk voor een hybride ecosysteem: het kernonderdeel van het systeem draait op containers en orchestrators, terwijl bepaalde hulpcomponenten worden geïmplementeerd als serverloze functies of als gespecialiseerde virtuele machines, altijd met duidelijke interfaces en goed gedefinieerde protocollen om ze in het geheel te integreren.
Als het erop aankomt dit alles in productie te nemen, is het niet alleen de gekozen technologie die het verschil maakt, maar ook een architectuur die bestand is tegen fouten, schaalbaar is waar nodig, automatisch wordt geïmplementeerd en observeerbaar is . Met productgerichte teams, goed beheerde contracten, gedecentraliseerde data en een robuust cloudplatform, veranderen microservices van een belofte in een effectieve en duurzame manier om complexe applicaties jarenlang te ontwikkelen.