Zyklomatische Komplexität: Der Wert 10 und was er nicht sagt
Zusammenfassung
Zyklomatische Komplexität zählt die Pfade durch eine Funktion: jeder `if`, `case`, `&&` erhöht die Komplexität. Der berühmte Richtwert von 10 stammt von NIST (1996), aber die Werkzeuge vertrauen auf 20-25. Das Wichtigste: Ein Score von 10 sagt nichts über die echte Lesbarkeit aus, eine flache `switch`-Anweisung mit 10 Fällen ist einfach zu verstehen, eine dreifach verschachtelte `if`-Struktur mit Score 6 ist Terror. Messe vor Du gellst, wende 10-15 als Warnung an, aber richte Deine Gating-Strategie auf die Onboarding-Zeit von neuen Engineers aus, nicht auf eine Zahl.
Zyklomatische Komplexität zählt die Zahl der unabhängigen Pfade durch eine Funktion. Eine Funktion ohne Verzweigungen hat einen Score von 1. Ein if hinzufügen? Dann 2. Ein switch mit vier Fällen? Der Score springt auf 6. Die Zahl sagt Dir, wie viele Testfälle Du brauchst, um jeden Pfad abzudecken, und wie lange es dauert, bis jemand anderes die Funktion im Kopf halten kann.
Das ist die ganze Metrik. Es kommt darauf an, was Teams damit anfangen und wo sie es falsch machen.
Was zyklomatische Komplexität wirklich zählt
McCabe definierte das 1976 als Kanten minus Knoten plus zwei. Graphentheorie. In der Praxis brauchst Du das nicht. Zähle die Verzweigungspunkte: if, else if, case, while, for, catch, &&, ||, Ternäre Operatoren. Addiere 1. Das ist der Score.
def preis(bestellung):
if bestellung.ist_vip: # +1
if bestellung.betrag > 100: # +1
return bestellung.betrag * 0.8
return bestellung.betrag * 0.9
elif bestellung.hat_gutschein: # +1
return bestellung.betrag * 0.95
return bestellung.betragDiese Funktion hat einen Score von 4. Nicht hoch. Aber bereits drei Ebenen von Verzweigungen für eine Funktion, die mit "Rabatt anwenden" begann. Das ist das Muster, das es zu bemerken gilt: Komplexität schleicht sich mit jedem elif ein, und niemand spielt den Bösewicht.
Woher kommt der Richtwert von 10 (und warum sind sich die Werkzeuge uneinig)
Die Zahl, die alle zitieren, ist 10. Sie stammt aus der NIST-Publikation 500-235, wo McCabe und Watson schrieben, dass Grenzen über 10 für Teams mit erfahrenem Personal, formalem Design und umfassender Testplanung reserviert sein sollten. Mit anderen Worten: 10 ist der Standard, kein Gesetz.
Die Werkzeuge einigen sich nicht auf einen Grenzwert, und das ist wichtig zu wissen, bevor Du ein Gate konfigurierst:
NIST SP 500-235: 10
ESLint
complexity-Regel: 20Microsoft CA1502: 25
Steve McConnell, Code Complete: 0–5 in Ordnung, 6–10 beobachten, 10+ überarbeiten
Carnegie-Mellon-Referenzbereiche: 1–10 einfach, 11–20 schwerer zu testen, 20+ schwer zu verstehen, 50+ wartungsunfähig
Vier Quellen, vier Zahlen. Falls Dein CI-Gate bei 10 ausfällt und Dein Teamkollege sein Nebenproject bei 25 gatet, keiner von Euch irrt sich. Ihr misst nur gegen verschiedene Risikotoleranzen. Microsofts eigene Dokumentation geht auf die NIST-Begründung detaillierter ein, falls Du die Quelle und nicht die Zusammenfassung möchtest.
Was wir tatsächlich setzen würden: 10–15 als Warnlinie für neuen Code, 20 als Punkt, wo ein PR einen zweiten Blick bekommen sollte, 50 als harter Stopp. Unter 10? Verbringe keine Review-Zeit damit, darüber zu diskutieren.
Die Falle: Ein guter Score heißt nicht, dass die Funktion lesbar ist
Hier verbrennen sich Teams. Eine Funktion kann 6 zählen und wirklich schwer zu lesen sein, und eine Funktion kann 14 zählen und trivial sein.
Nimm eine flache switch mit zehn Fällen, jeder gibt eine Konstante zurück. Das ist eine Komplexität von 10, und die meisten Engineers lesen sie in fünfzehn Sekunden, weil das Muster offensichtlich ist: eine Sache rein, eine Sache raus, kein Zustand zwischen den Verzweigungen. Jetzt nimm eine Funktion mit drei verschachtelten if-Blöcken und eine Schleife, die eine gemeinsame Variable mutiert. Das könnte 6 zählen, und es dauert einen Senior-Engineer fünf Minuten zum Durchtracing, weil Du den ganzen Call Stack im Kopf halten musst, um zu wissen, welche Verzweigung Du eigentlich nimmst.
Zyklomatische Komplexität misst Pfade. Sie misst nicht die Verschachtelungstiefe, den Variablenumfang oder wie weit eine Bedingung und ihre Wirkung in der Datei auseinanderliegen. Zwei Funktionen mit dem gleichen Score können völlig verschiedene Lektüre sein.
Wir haben Teams sehen, die "unter 10" als Proxy für "reviewbar" behandeln, einen PR durchschieben, weil das Linter grün war, und dann zuschauen, wie ein Junior-Engineer drei Wochen später einen Nachmittag in dieser Funktion verliert. Der Score passte. Das Lesen wurde nicht einfacher.
Zyklomatische Komplexität vs. Kognitive Komplexität: Zwei verschiedene Fragen
SonarSource führte die Kognitive Komplexität 2017 speziell ein, um diese Lücke zu schließen. Zyklomatische Komplexität beantwortet "Wie viele Pfade hat diese Funktion." Kognitive Komplexität beantwortet "Wie schwer ist diese Funktion, im Kopf zu halten", und das tut sie, indem sie Verschachtelungstiefe stärker als Flachstruktur bestraft.
Eine switch-Anweisung bewegt den kognitiven Score kaum. Drei Ebenen tiefer verschachtelte if in einer Schleife bewegen ihn schnell, weil jede zusätzliche Verschachtelungsebene die mentale Belastung der vorherigen verstärkt. SonarSource' eigene Beschreibung erklärt die Scoring-Regeln, falls Du sie selbst implementieren möchtest, und die meisten Linter, die Zyklomatische Komplexität unterstützen, unterstützen jetzt auch Kognitive Komplexität als separate zweite Regel.
Überspringe Kognitive Komplexität, wenn Dein Team klein genug ist, dass jeder bereits weiß, wo die unordentlichen Funktionen sind. Schalte sie ein, sobald Du mehr als zwei Personen hast, die den Code, den sie reviewen, nicht geschrieben haben, denn das ist genau die Lücke, für die sie entworfen wurde.

Was AI-Code-Review-Tools mit dieser Zahl anfangen (und was sie verpassen)
GitHub Copilot Code Review, CodeRabbit, Qodo und Greptile zeigen alle in irgendeiner Form Komplexitätssignale in einem PR. Einige kennzeichnen eine Funktion, die einen Schwellenwert überschritten hat. Einige fassen zusammen "dieser PR erhöht die Komplexität in drei Dateien." Kaum einer sagt Dir, warum das für die Person wichtig ist, die die Datei sechs Monate später ohne Kontext öffnet.
Das ist die echte Lücke. Eine Komplexitätswarnung in einem PR ist eine Zahl in einem Kommentar. Sie sagt einem Reviewer nicht, ob der hinzugefügte Zweig dorthin gehört, ob er Logik drei Dateien über dupliziert, oder ob die richtige Abhilfe eine Guard-Klausel ist oder ein vollständiger Extract-Methode-Pass. Die KI-Werkzeuge sind gut beim Zählen. Sie sind noch nicht gut beim Erklären der Form des Durcheinanders.
Was diese Lücke praktisch schließt, ist, die Zahl mit einer Frage zu verbinden, die ein Mensch noch antworten muss: Macht diese Funktion eine Sache oder drei Dinge in if-Anweisungen? Kein Linter beantwortet das für Dich. Es sagt Dir nur, wo Du hinschauen sollst.
Warum das bei einer 100K-LOC-Base mehr zählt als bei einem Side Project
Auf einer Codebasis, die Du allein geschrieben hast, ist Komplexität ein Speicherproblem, das Du bereits gelöst hast. Du kennst die zehn kniffligen Funktionen beim Namen, Du weißt, warum sie knifflig sind, und Du umgehst sie ohne zu denken. Das ist nicht die Situation, in der sich die meisten dieses Publikums befinden.
Auf einem gemeinsamen Repo mit fünf bis fünfzig Engineers hält niemand die ganze Karte. Eine Funktion mit Score 22, die der Originalautor vollkommen verstand, wird sechs Monate später zu einer Funktion, die ein anderer Engineer von Grund auf rekonstruieren muss, normalerweise unter Druck. Du hast das schon getan: Nach dem Funktionsnamen greifen, Ctrl+F durch die Datei, git blame auf verdächtige Zeilen, dann jemanden anschreiben, der das Team vor acht Monaten verlassen hat.
Hier wird auch die Komplexitätszahl mit der Suche interaktiv. Eine High-Complexity-Funktion ist schwerer korrekt zusammenzufassen, was bedeutet, dass es für einen Teamkollegen oder ein Code-Search-Tool schwerer ist, sie korrekt in einem Satz zu beschreiben. Frage "Was macht diese Funktion" zu einer Complexity-4-Funktion und Du bekommst eine klare Antwort. Stelle die gleiche Frage zu einer Complexity-22-Funktion mit vier verschachtelten Verzweigungen und die ehrliche Antwort ist "Es hängt ab, welcher Pfad den Dich interessiert." Diese Mehrdeutigkeit ist genau das, was einen neu eingestellten Engineer am ersten Tag verlangsamt, und deshalb lohnt es sich, Komplexität auf Repo-Ebene zu verfolgen, nicht nur als Lint-Warnung pro PR.
Die echten Kosten, die niemand in die Metrik steckt: Onboarding-Zeit
Hier ist der Teil, der nicht auf einem Dashboard erscheint. Ein Junior-Engineer, der zu einem Team kommt, erlebt nicht "Zyklomatische Komplexität von 23." Sie erleben: Ich habe diese Datei geöffnet, ich weiß nicht, welche Verzweigung läuft wann, und ich lese seit vierzig Minuten.
Wir haben das über ein paar Onboarding-Zyklen loose gemessen: Funktionen mit einem Komplexitätsscore über 15 kosteten neue Hires ungefähr drei bis vier Mal länger, um in einer Walkthrough korrekt zu erklären als Funktionen mit Score unter 8. Nicht, weil die High-Complexity-Funktionen mehr taten, sondern weil das Tracing, welche Verzweigung unter welcher Bedingung feuert, echte, sequenzielle Lesezeit braucht, und niemand liest eine verschachtelte Bedingung beim ersten Durchgang korrekt überflogen.
Hier verdient die Metrik ihre Sporen bei Teams, die oft einarbeiten. Es ist wirklich keine Code-Quality-Zahl. Es ist ein Proxy für "wie viele Minuten wird es die nächste Person kosten, die es nicht geschrieben hat." Verfolge es so und die Schwellenwert-Diskussion wird viel weniger abstrakt.

Wie Du es gimmst, ohne Dein Team zu bremsen
Mess, bevor Du gellst. Wähle einen:
Python:
radon cc -a -s .zeigt jede Funktion mit einer Buchstabennote;radon cc -n c .filtert zu C-Note und schlechter.JavaScript / TypeScript: ESLint
complexity-Regel, gesetzt mit['warn', { max: 15 }]zum Starten.Go:
gocyclo, zeige es auf ein Package und es druckt jede Funktion über einem Schwellenwert.Java / C#: SonarQube oder PMD, normalerweise bereits in CI verdrahtet, wenn Dein Team einen verwendet.
Führe es einmal über das ganze Repo aus, bevor Du Durchsetzung einschaltest. Du bekommst eine Baseline und wahrscheinlich ein paar Funktionen im 40+-Bereich, die älter sind als jeder momentan im Team. Sperre den Build auf diesen Funktionen nicht rückwirkend; das lehrt Leute nur, den Linter zu umgehen.
Gate neuen Code bei 10–15. Kennzeichne alles, das 20 überschreitet, für einen zweiten Reviewer, nicht um automatisch abgelehnt zu werden; einige dieser Funktionen, wie die flache switch, sind in Ordnung. Behandele alles über 50 als ein Technical-Debt-Ticket, nicht als ein Kommentar zu jemandes PR.

Das Limit hält nur, wenn die Toolchain es jedes Mal auf die gleiche Weise erzwingt. Eine Regel, die einmal für einen Deadline umgangen wird, wird für immer umgangen.
Jagst Du den Score oder die Funktion?
Ein Team, das hart bei 10 gellt und flache, langweilige, leicht zu lesende Funktionen shipped, ist in guter Form. Ein Team, das hart bei 10 gellt und anfängt, Funktionen in vier kleinere Funktionen zu spalten, die sich gegenseitig auf eine Weise aufrufen, die niemand ohne drei Tabs geöffnet tracing kann, hat die Zahl besser und den Codebase schlimmer gemacht.
Zyklomatische Komplexität ist ein Rauchwarnmelder, kein Feuerlöscher. Sie sagt Dir, wo Du hinschauen sollst. Sie sagt Dir nicht, was zu tun ist, sobald Du dort bist, und die Zahl als das Ziel statt der Lesbarkeit zu behandeln, für die sie ein Proxy sein soll, ist wie Teams mit einem grünen Dashboard und einem Repo enden, bei dem es immer noch drei Wochen dauert, bis sich ein neuer Hire nützlich anfühlt.