# Cyclomatische complexiteit: deployment-risico-signaal

URL: https://upstreamapi.com/nl/journal/cyclomatische-complexiteit-deployment-risico
Type: blog
Locale: nl
Published: 2026-07-25
Updated: 2026-07-25

---

> Cyclomatische complexiteit telt codepaden. Statische drempels op 10 werken niet omdat zij niet voorspellen welke paden in productie falen. Complexiteitsdelta bepaalt rollout-risico.

## Cyclomatische complexiteit: van code-review regel naar deployment-risico-signaal

Cyclomatische complexiteit telt het aantal onafhankelijke paden door een functie. NIST stelt de veiligheidslimiet op 10 per functie, en de meeste teams handhaven iets dergelijks in hun CI pipeline. Wat dat getal je niet vertelt, is welke van die paden daadwerkelijk zal worden traversed door de canary die je zo meteen naar 5% van jouw productieverkeer gaat sturen, en in die kloof beginnen de meeste rollout-incidenten echt. Behandel cyclomatische complexiteit als een deployment-risico-input, niet als een linting-regel, en het getal begint echt zijn waarde te bewijzen.

## Wat cyclomatische complexiteit werkelijk meet

McCabes metric is een grafiektelwerk: knopen, edges, verbonden componenten. Elke `if`, `for`, `while`, `case` en boolean-operator voegt een pad toe. Een functie met complexiteit 25 heeft minstens 25 lineair onafhankelijke paden erdoorheen. Dat is geen mening, het is basis-path-testing-wiskunde, en het stelt een ondergrens voor hoeveel testgevallen je nodig hebt om de functie eenmalig volledig te dekken. [Sourcegraph's analyse](https://sourcegraph.com/blog/cyclomatic-complexity-what-it-is-and-how-to-reduce-it) beschrijft de volledige drempels: 1-10 laag risico, 11-20 matig, 21-50 hoog, 50+ is het "we moeten erover praten" niveau.

De meeste teams halen die ondergrens niet. Coverage-tools rapporteren line coverage, niet path coverage, dus een functie kan 90% coverage tonen terwijl de helft van haar branches nooit in CI wordt uitgevoerd. Dat is het deel dat niemand op de PR-template zet, en het is de reden waarom "tests slagen" en "dit is veilig om te shippen" twee verschillende beweringen zijn die worden behandeld als één.

We hebben genoeg post-mortems gelezen om het patroon te herkennen: de incident-review bevat altijd een regel voor error-budget-verbruik en een regel voor detectietijd. Het bevat bijna nooit een regel voor hoe complex de veranderde functie er voor de diff uit zag. Dat is een gat in de administratie, niet alleen in de tooling.

![Close-up van handen die een code diff met geneste inspringing op een laptopscherm beoordelen](https://fdzlnqpwsaniezitwiuw.supabase.co/storage/v1/object/public/cms-media/upstreamapi/2026-07/91e851-inline1.webp)

## Waarom een plat complexiteitsgetal de werkelijke blast radius verbergt

Hier is het deel dat elk complexiteit-dashboard fout doet: twee functies kunnen dezelfde cyclomatische-complexiteit-score posten en totaal verschillende risico's dragen. Een 20-branch switch-statement die naar goed-geteste handlers dispatched is niet dezelfde soort dier als een functie met vier aparte nesten van geneste voorwaarden verspreid over 80 regels, elk drie levels diep. [CodeScene noemt die tweede vorm een "bumpy road,"](https://codescene.com/blog/bumpy-road-code-complexity-in-context/) en de naam is nauwkeurig. Het is de nestingdiepte, niet het ruwe aantal branches, die de werkgeheugencapaciteit belast en het edge case verbergt dat niemand dacht te testen.

Dit is voor ons specifiek van belang omdat een canary niet faalt op gemiddelde complexiteit. Het faalt op die ene bumpy functie die in deze diff is aangeraakt, om 2 uur 's nachts, onder belasting die niemand load-testte. In de post-mortems die we hebben beoordeeld met platform-teams, herhaalt het patroon zich: de root-cause-functie heeft bijna nooit de hoogste complexiteitsscore in de repo. Het heeft de hoogste complexiteits-*delta* in de diff die is shipped. Dat is een ander signaal, en bijna niemand instrumenteert het.

Een dashboard dat je vertelt dat de complexiteit van de codebase afneemt, is niet hetzelfde dashboard dat je vertelt dat deze rollout, hier en nu, een functie heeft aangeraakt die zojuist drie nieuwe geneste branches heeft gekregen. De een is een statusrapport dat je eenmaal per kwartaal leest. De ander is een gate die je werkelijk in de deployment-pipeline zou willen, naast de SLO-check, niet begraven in een apart static-analysis-tool dat niemand opent tijdens een incident.

Ring-based en percentage-based rollouts gaan er al van uit dat sommige diffs riskanter zijn dan anderen; dat is het hele premisse van een canary. Wat de meeste pipelines niet doen, is de complexiteitsvorming van de diff zelf laten informeren hoe snel die canary zou moeten verbreden. Het wordt behandeld als een code-review-zorg, daarna vergeten op het moment dat de PR merged.

## De CI gate die iedereen op 10 zet, en waarom het niet echt helpt

Het standaardadvies, beperk cyclomatische complexiteit tot 10 en laat de build boven die drempel falen, is de "skip" stap die bijna elke engineerings-blog aanbeveelt en bijna niemand valideert tegen werkelijke incident-data. Het is niet verkeerd, precies. Het is onvolledig op een manier die teams doet geloven dat ze het risico hebben afgehandeld terwijl ze het meestal gewoon hebben verplaatst.

Twee foutmodi, beide algemeen bij teams waarmee we hebben gesproken:

- 
**Het getal gamen.** Extract Method is het leerboekoplossing, en het werkt: cyclomatische complexiteit per functie daalt. Maar als de extractie niet echt het aantal beslissingen vermindert, gewoon over drie functies in plaats van één verplaatst, is de systeemcomplexiteit onveranderd. De gate wordt groen. De blast radius krimpt niet, het wordt gewoon moeilijker om in een enkele diff-view te zien.

- 
**De vorm negeren.** Een platte drempel behandelt een 12-branch dispatcher en een 12-path bumpy road als even riskant. Ze zijn het niet. De dispatcher is waarschijnlijk prima; het is mechanische routing. De bumpy road is waar je volgende rollback woont, omdat degene die het beoordeelde, stopte met het bijhouden van toestand drie nesten diep.

AI-coderingagenten maken dit erger voordat het beter wordt. Devin en gelijkaardige autonome agenten shippen PR's snel, en "snel" betekent vaak een branch toevoegen in plaats van die refactoren die al daar is. Dat is het pad van minste weerstand voor een model dat optimaliseert voor een slaagde testsuite, niet voor de cognitieve belasting van een reviewer. Als uw team AI-authored diffs in volume merged, is complexiteitsdelta per PR een metriek die u op het dashboard wilt voordat het een incident-review-bevinding wordt, niet erna.

![Twee engineers die een branching-stroomschema op een glazen whiteboard getekend beoordelen](https://fdzlnqpwsaniezitwiuw.supabase.co/storage/v1/object/public/cms-media/upstreamapi/2026-07/4479b1-inline2.webp)

## Wat de complexiteitsdelta je werkelijk over testinglast vertelt bij rollout

Vergeet even het absolute getal. Het getal dat incident-risico voorspelt, is de verandering in complexiteit die door een enkele diff wordt ingevoerd, kruisgecontroleerd met of de tests die die diff aanraken daadwerkelijk groeiden om ernaar te matchen.

Een functie die van complexiteit 8 naar 19 in één PR gaat, heeft volgens de basis-path-testing-wiskunde hierboven ruwweg zijn vereiste minimum-aantal-tests verdubbeld. Als de PR twee tests toevoegde, heb je een coverage-gat shipped dat wordt vermomd als een slagende CI-run. Dat gat verschijnt niet totdat de canary het 5% verkeersgedeelte raakt dat de ongeteste branch exerceert, en tegen die tijd is het een incident, geen code-review-opmerking die onopgelost in een PR-thread zit.

Dit is de instrumentatie-kloof die de AI Pilot van upstreamapi aanpakt aan de rollout-kant: gate de canary-percentage en hold-tijd op de complexiteitsdelta van de shipped diff, kruisgecontroleerd met zijn testdelta, niet alleen op de downstream-error-rate SLO. Een error-rate SLO vertelt je dat iets al is gebroken. Een complexiteitsdelta-gate vertelt je dat de diff meer kans had om iets te breken voordat het live-verkeer serveert, wat het enige moment is waarop die informatie nog actionabel is.

`// Vereenvoudigde canary-gate: langzaam verbreden op laag-risico-diffs, vasthouden op hoog-risico
function canaryStep(diff: DiffMetrics): CanaryDecision {
  const complexityRisk = diff.complexityDelta / Math.max(diff.testDelta, 1);

  if (complexityRisk > 3 && diff.slo.errorBudgetBurn > 0.1) {
    return { action: "hold", trafficPct: diff.currentTrafficPct };
  }
  if (complexityRisk > 3) {
    return { action: "extend_bake_time", bakeMinutes: 45 };
  }
  return { action: "advance", trafficPct: diff.currentTrafficPct + 10 };
}`
## Zijn onderzoekers het hierover eens?
Nee, en dat verdient duidelijk te worden gezegd. Sommig practitioneronderzoek duwt hard terug op cyclomatische complexiteit als een defect-voorspeller helemaal niet, stellende dat teams die optimaliseren voor een lager getal de complexiteit gewoon ergens minder zichtbaar verplaatsen. GetDX's kritiek maakt deze zaak en wijst teams in plaats daarvan naar developer-experience-metrieken. We denken niet dat dat argument de metriek doodt; we denken dat het de metriek doodt wanneer gebruikt alleen, als een statische repo-brede score, losgekoppeld van de diff en de rollout waaraan het is vastgehecht.

## Hoe je daadwerkelijk een canary op complexiteit zou gaten, niet alleen op error rate

Drie dingen, in volgorde van hoeveel wrijving ze aan een PR toevoegen:

- 
**Bereken complexiteitsdelta per diff, niet per repo.** Repo-brede gemiddelden verbergen de ene functie die er deze week toe doet. Delta per PR is goedkoop om te berekenen in de meeste static-analysis tools, en het is het getal dat correlatie heeft met wat werkelijk in de volgende 48 uur stukgaat.

- 
**Kruisreferentie tegen testdelta, niet testtelling.** Een functie met 40 tests en een complexiteitsstijging van 8 naar 19 met nul nieuwe tests is een groter risico dan een gloednieuwe functie met complexiteit 15 en matching coverage vanaf dag één.

- 
**Voer de ratio in rollout-pacing in, niet alleen merge-goedkeuring.** Een high-complexity-delta diff hoeft niet geblokkeerd te worden bij review; veel legitiem complexe domeinlogica (state machines, protocolparsers) zal altijd hoog scoren. Het heeft een langzamere canary en een kortere error-budget-teugel nodig, wat een rollout-beslissing is, geen code-review-beslissing.

Schrijf de runbook-entry voordat de rollout plaatsvindt, niet nadat de pagina crash. Als de on-call engineer die het incident-kanaal om 3 uur 's nachts opent de reden waarom een "schone" PR net het error-budget heeft verbrand moet achterhalen, faalde de documentatie voordat de code faalde. Een eenregels-opmerking in het deploy-log ("complexity delta 11, test delta 1, held at 20%") kost niets om te schrijven en bespaart de eerste vijftien minuten van elke incident-review die volgt.

![Serverdoorgangscorridor 's nachts met status-LED's en een eenzame engineer die wegloopt terwijl hij een tablet vasthoudt](https://fdzlnqpwsaniezitwiuw.supabase.co/storage/v1/object/public/cms-media/upstreamapi/2026-07/a58df0-inline3.webp)

## Is het het waard om bij te houden, of gewoon nog een dashboard-getal?

Volledig afhankelijk van waar je het aan vasthecht. Cyclomatische complexiteit als een repo-gezondheidstrend is meestal decoratie: fijn voor een kwartaalslide, nutteloos om 2 uur 's nachts. Cyclomatische complexiteit als per-diff delta, ingevoed in canary-pacing en kruisgecontroleerd tegen testgroei, is een van de goedkopere leading indicators die we hebben gevonden voor "deze rollout gaat iemand bellen."

De post-mortem zal vragen hoe het SLO-budget eruitzag voordat de rollback. In toenemende mate vragen de onze ook hoe de complexiteitsdelta eruitzag op de diff die is shipped. Het is het waard om die vraag aan je eigen runbook toe te voegen voordat de incident je forceert het gesprek, niet tijdens de retro wanneer het antwoord een schouderophaal is en een belofte om "betere tests volgende keer" toe te voegen.

## FAQ

### Wat is cyclomatische complexiteit precies?

Cyclomatische complexiteit is een metriek die het aantal onafhankelijke codepaden door een functie telt. Deze metriek gebruikt de basis-path-testing theorie: een functie met CC 25 vereist minimaal 25 testgevallen voor volledige paddeking. Elke control flow statement (if, for, while, case, boolean operator) voegt één toe aan de score.

### Waarom werkt de standaard CI-gate op 10 niet?

Een statische drempel op 10 is onvolledig omdat: (1) hij niet onderscheid maakt tussen soorten complexiteit (een dispatcher is veiliger dan geneste voorwaarden), (2) teams geven gamen door Extract Method zonder werkelijk aantal beslissingen te verminderen, en (3) hij geen rekening houdt met testgroei of deployment-context.

### Wat is een 'bumpy road' functie?

Een bumpy road is een functie met dezelfde complexiteitsscore als een dispatcher, maar waarvan de beslissingen verspreid zijn over meerdere niveaus nesting. Dit patroon is veel riskanter omdat het werkgeheugen van reviewers belast en edge cases verbergt. CodeScene analyseert dit patroon in detail.

### Hoe moet je complexiteitsdelta gebruiken in je rollout?

Bereken de verandering in complexiteit per diff en vergelijk dit met testgroei. Een diff met complexiteitsdelta 11 en testdelta 1 is riskant en verdient een langzamer canary-rollout met frequenter monitoring. Dit is informatie voor de deployment-pipeline, niet alleen voor code review.

### Hoe verhouden AI-codeagents zich tot cyclomatische complexiteit?

Autonome agenten zoals Devin voegen vaak branches toe in plaats van refactoring, waardoor complexiteitsdelta per PR sneller groeit dan bij human-authored code. Dit leidt tot meer onderteste code in productie, dus teams zouden complexiteitsdelta monitoren als ze AI-assisted development gebruiken.

### Wat is het verschil tussen CC-gating op code-review versus rollout?

Code-review gating (CI-build fail op CC>10) is preventief maar onvolledig. Rollout-gating met complexiteitsdelta is operationeel: het telt code werkelijk falen in productie. Beide zijn nodig, maar rollout-signalling is dichterbij waar risico werkelijk materialiseert.

### Hoe meet je testdelta precies?

Testdelta is het aantal nieuwe test cases of test lines toegevoegd per PR. Een diff met complexiteitsdelta 11 maar testdelta 1 geeft risico-ratio van 11:1, dus meer werk voor canary-pacing. Tools zoals Codescene en static-analysis platforms kunnen dit automatisch berekenen.

### Kunnen teams Extract Method gebruiken zonder risico?

Extract Method vermindert CC-scores per functie, maar als het werkelijk aantal beslissingen in het systeem hetzelfde blijft, is het risico ongewijzigd. Teams moeten validators gebruiken die de echte reductie controleren, niet alleen de CI-gate groen zien.