F Fakt Artikel

Refactoring ist kein Heldentum

Ein informationstheoretisches Argument, dass jede wachsende Codebasis unordentlich wird — und warum Aufräumen ein Rhythmus ist, keine Rettungsaktion.

Jede Codebasis, die wächst, wird unordentlich. Das ist kein Mangel an Disziplin. Es folgt daraus, wie Information funktioniert.

Die meisten Teams behandeln diese Unordnung wie ein moralisches Versagen. Sie legen „Tech-Debt“-Tickets an, die im Backlog verrotten. Sie planen „Refactoring-Sprints“, als wäre Aufräumen ein besonderes Ereignis, für das man eine Erlaubnis braucht. Und sie feiern die Entwicklerin oder den Entwickler, die sich endlich des Chaos annehmen, als Helden.

Diese Sicht ist falsch. Und die Informationstheorie erklärt seit 1948, warum.

1. Die Informationstheorie erklärt es längst

Eine Codebasis ist ein Kompressionsverfahren. Die Ordnerstruktur, die Klassengrenzen, die Schnittstellen zwischen Modulen: Sie bilden eine Kodierung, die die Beschreibungslänge Ihres Systems minimiert. Passt die Kodierung zum Inhalt, finden Sie jedes Konzept mit wenigen Schritten. Die kognitiven Kosten sind gering.

Shannon hat gezeigt, dass der beste Code auf die Statistik der Daten zugeschnitten ist, für die er gebaut wurde. Daten, die er nie gesehen hat, kann er nicht vorwegnehmen. Könnten Sie künftige Features perfekt vorhersagen, trügen diese Features keinerlei Information — sie wären nicht neu.

Daraus folgt: Jedes neue Feature, das echte Information trägt, verletzt die bestehende Kodierung bis zu einem gewissen Grad. Die Struktur wurde für das Bisherige entworfen. Das Neue passt nicht perfekt hinein. Die Beschreibungslänge wächst.

Das ist kein Versagen Ihrer Architektur. Es ist Informationstheorie am Werk.

2. Der Kipppunkt lässt sich berechnen

Das Prinzip der minimalen Beschreibungslänge (Minimum Description Length, Rissanen 1978) fasst den Kipppunkt so:

Umbauen, wenn L(code | current) > L(code | new) + C(refactor)

Dabei ist L die Beschreibungslänge — die kognitiven Kosten, den Code unter einer bestimmten Ordnung zu verstehen — und C sind die Kosten des Umbaus.

Ein konkretes Beispiel: die Datei, die den Zustand Ihrer Anwendung verwaltet. Sie beginnt aufgeräumt — der Anmeldezustand, ein paar Aktionen, ein Reducer. Im nächsten Sprint kommt der Warenkorb dazu. Dann die Benachrichtigungseinstellungen. Dann eine Echtzeit-Synchronisation. Jede Ergänzung ist klein und logisch — „ist ja alles Zustand, gehört hierher“. Sechs Monate später hat die Datei 1.200 Zeilen, und vier Domänen, die nichts miteinander zu tun haben, teilen sich einen einzigen Reducer. Wer die Warenkorb-Logik ändern will, scrollt an Anmeldung und Benachrichtigungen vorbei. Ein Fehler in der Synchronisation schickt Sie durch alle vier Bereiche, weil ihre Zustände ineinander verwoben sind.

Stellen Sie sich nun vor, Sie teilen die Datei entlang der Domänengrenzen: vier Dateien mit jeweils rund 300 Zeilen, jede für ihren eigenen Teil des Zustands zuständig. Das Aufteilen kostet tatsächlich etwas — Imports neu verdrahten, Tests anpassen, ein Nachmittag konzentrierter Arbeit. Doch danach berührt jede künftige Änderung nur noch einen Bereich, braucht nur ein mentales Modell und beschädigt nur selten etwas außerhalb ihrer Grenze.

Die Formel sagt: Bauen Sie um, sobald die laufenden Kosten, sich durch das Chaos zu bewegen, die einmaligen Kosten des Aufräumens übersteigen. Dort, wo sich beide kreuzen, liegt der Kipppunkt.

Der Kipppunkt: ab hier ist Umbauen günstiger als Weitermachen.Kipppunkt: hier umbauenWeiterbauenUmbauen ist günstigerFeatures seit dem letzten UmbauKognitive Kosten
  • Bisherige Struktur
  • Nach dem Umbau, samt seinen Kosten C
Der Kipppunkt: ab hier ist Umbauen günstiger als Weitermachen.

Die Softwaretechnik misst Näherungen für L seit Jahrzehnten: zyklomatische Komplexität (McCabe, 1976), Halstead-Volumen, Kopplungsmetriken (Yourdon & Constantine, 1979). Und die Neurowissenschaft beginnt, die biologische Seite zu messen: Eine fMRT-Studie fand, dass der Umfang des Textes die Aufmerksamkeit bindet und die Größe des Vokabulars das Arbeitsgedächtnis belastet — während klassische Komplexitätsmetriken nur einen Teil dessen erklären, was Code schwer macht (Peitek et al., ICSE 2021, ausgezeichnet als Distinguished Paper). Das menschliche Arbeitsgedächtnis fasst etwa vier unabhängige Einheiten (Cowan, 2001).

Wir haben eine zusammengesetzte Formel gebaut, die diese Signale vereint:

S(file) = 0.40 · (LOC / 400) · (avg_cc / baseline_cc)
        + 0.25 · (1 − cohesion)
        + 0.20 · (concerns / 4)
        + 0.15 · (imports / median)

Dabei gilt:

400
ist das empirische Fenster, in dem Code-Reviews wirksam bleiben, in Codezeilen
avg_cc / baseline_cc
ist der Dämpfer der zyklomatischen Komplexität — die durchschnittliche zyklomatische Komplexität je Funktion, geteilt durch den Median der Codebasis. Einfacher Standardcode (cc ≈ 1) dämpft das Größensignal; tief verschachtelte Logik (cc ≫ Basiswert) verstärkt es
cohesion
ist die semantische Ähnlichkeit zwischen Codeabschnitten (0–1, gemessen über Embeddings)
4
ist die Grenze des Arbeitsgedächtnisses in Einheiten (Cowan, 2001)
imports / median
setzt die Zahl der Abhängigkeiten ins Verhältnis zur übrigen Codebasis
0,60
0,13
0,25
0,38
= 1,36
Schwelle 1,50
  • Dateigröße (600 / 400) = 0,60
  • Geringe Kohäsion (1 − 0,48) = 0,13
  • Belange (5 / 4) = 0,25
  • Abhängigkeiten (20 / 8) = 0,38

Unter der Schwelle: weiterbauen

Aufschlüsselung des Scores für eine Datei mit 600 Zeilen, fünf Belangen und geringer Kohäsion.

Die Gewichte sind unsere heuristische Lesart dieser Forschung, keine dort gemessenen Werte: Die Größe wiegt am meisten (0,40), gefolgt davon, wie viele voneinander unabhängige Dinge eine Datei tut (Kohäsion: 0,25, Belange: 0,20), und schließlich die Kopplung an fremde Module (0,15).

Der Faktor der zyklomatischen Komplexität wirkt als Dämpfer auf den Größenterm, nicht als eigenes Gewicht. Eine 600-Zeilen-Datei aus lauter gleichförmigen Vierzeilern hat ein cc nahe 1 — der Dämpfer schrumpft ihren Größenbeitrag, und die Formel bewertet sie zu Recht als harmlos. Eine 400-Zeilen-Datei mit tief verzweigten Bedingungen liegt deutlich über dem Basiswert — der Dämpfer verstärkt das Größensignal und meldet die Datei, obwohl ihre Zeilenzahl moderat wirkt. Die Größe sagt Ihnen, wie viel Code es gibt. Die zyklomatische Komplexität sagt Ihnen, wie schwer jede Zeile zu durchdenken ist. Der Dämpfer verbindet beides zu einem Maß für kognitives Gewicht.

Die Kohäsion ist der zweite tragende Term. Ohne sie kann die Formel eine große Datei, die eine Sache tut, nicht von einer großen Datei unterscheiden, die fünfzehn tut. Kohäsion und cc-Dämpfer erfüllen unterschiedliche Zwecke: Die Kohäsion trennt „viele Belange“ von „einem Belang“, das cc trennt „komplexe Logik“ von „einfacher Wiederholung“.

3. Der Test an der Wirklichkeit

Wir haben die Formel auf unsere eigene produktive Codebasis angewendet: 947 Quelldateien in sechs Microservices.

In einem Aufräumzyklus kurz zuvor hatten wir acht Service-Dateien aufgeteilt, die zu groß geworden waren — jede zwischen 810 und 1.431 Zeilen. Ohne Planung, ohne „Refactoring-Sprint“. Wir spürten die Reibung und räumten auf. Reine Strukturumbauten: keine Änderung an der Logik, nur ein Aufteilen entlang von Nähten, die im Code bereits sichtbar waren. Die Tests liefen unverändert durch — ein gutes Zeichen, dass es Umzüge in der Struktur waren, keine Änderungen im Verhalten.

Als wir diese acht Dateien nachträglich mit der Formel bewerteten, lagen alle über dem Kipppunkt. Die Formel traf genau die Aufteilungen, die wir aus dem Gefühl heraus schon vorgenommen hatten.

Der Scan der gesamten Codebasis ergab 17 Dateien über der Schwelle. Acht davon waren die gerade aufgeteilten. Neun waren neue Kandidaten, die uns noch nicht aufgefallen waren — Dateien, in denen sich die Kosten aufbauten, ohne schon so weh zu tun, dass wir gehandelt hätten.

Danach setzten wir die Formel vorausschauend ein: Der nächste Scan meldete zehn Dateien über der Schwelle. Wir haben alle bearbeitet. Acht Aufteilungen waren echte Gewinne — sie legten doppelte Logik offen, vermischte Lese- und Schreibbelange und verwobene Domänen. Zwei waren Fehlalarme: Verteiler aus Standardcode, in denen jede Methode eine gleichförmige Weiterleitung von vier Zeilen war. Die Formel bewertete sie wegen der Zahl der Imports und Belange hoch, doch es gab keine echte Komplexität zu reduzieren. Acht hilfreiche Meldungen von zehn bei einem vorausschauenden Scan, ohne dass die Formel für diese Runde angepasst worden war.

Bei den Fehlalarmen versagten zwei Schutzmechanismen zugleich. Erstens fehlten Kohäsionsdaten: Die Embedding-Pipeline hatte Ergebnisse stillschweigend abgeschnitten, sodass diese Dateien mit einem pauschalen Malus für niedrige Kohäsion bewertet wurden statt mit ihrer tatsächlichen, hohen Kohäsion. Zweitens der cc-Dämpfer: Die Verteiler hatten eine zyklomatische Komplexität nahe 1 je Funktion — triviale, geradlinige Weiterleitungen. Mit vollständigen Kohäsionsdaten und dem cc-Dämpfer hätten beide Dateien deutlich unter der Schwelle gelegen. Die Kohäsion erkennt „groß, aber gleichförmig“. Der cc-Dämpfer erkennt „groß, aber einfach“. Zusammen sollten sie die Klasse von Fehlalarmen beseitigen, bei denen eine Datei groß, aber harmlos ist.

Eine Formel mit unvollständigen Eingaben kann falsche Sicherheit geben. Sie fand trotzdem neun Kandidaten, die unser Bauchgefühl komplett übersehen hatte, aber Metriken versagen lautlos. Prüfen Sie die Pipeline, nicht nur die Mathematik.

Die Verteilung der Scores hat die Form, die der Zyklus erwarten lässt: eine rechtsschiefe Kurve, mit dem Großteil der Dateien in einem gesunden Bereich und einem dünnen Ausläufer von Dateien, in denen sich Entropie ansammelt.

Nach jeder Aufteilung haben die Dateien im Schnitt etwa 250–420 Zeilen.04008001.2001.6001.431297A×51.169292B×41.099375C×3994259D×4877302E×3831416F×2810405G×2842421H×2
  • Vor der Aufteilung, eine Datei
  • Nach der Aufteilung, Schnitt je Datei
  • Kognitives Fenster 250–420
  • Beobachtete Schwelle, etwa 800 Zeilen
Nach jeder Aufteilung haben die Dateien im Schnitt etwa 250–420 Zeilen. ×n: in wie viele Dateien jede aufgeteilt wurde.

Nach dem Aufteilen pendelten sich die Dateigrößen bei etwa 250–420 Zeilen je Datei im Schnitt ein — einem Bereich, in dem eine Datei meist einen einzigen Belang trägt und gut im Kopf zu behalten ist. Wir lesen das nicht als Stilfrage, sondern als den Punkt, an dem die Beschreibungslänge am kleinsten wird: klein genug, um sie zu verstehen, groß genug, um für sich zu stehen.

4. Probieren Sie es selbst: FastAPI

Um zu zeigen, dass die Formel auch jenseits unserer eigenen Codebasis funktioniert, haben wir sie auf FastAPI angewendet — ein bekanntes, gut gepflegtes Python-Framework. Ohne Feinabstimmung, ohne besondere Konfiguration. Einfach:

python entropy.py fastapi/ --cohesion auto

Der Schalter --cohesion auto berechnet die semantische Kohäsion lokal, mit Embeddings von ollama — ohne API-Schlüssel, ohne Cloud, nur auf Ihrem Rechner. Das Skript zerlegt jede Datei in logische Abschnitte, bettet sie ein und misst, wie ähnlich sich die Abschnitte sind. Hohe Ähnlichkeit deutet auf einen Belang. Geringe Ähnlichkeit deutet auf vermischte Belange.

Ergebnis: 24 Dateien analysiert, 7 über der Schwelle zum Aufteilen.

ScoreDateiZeilenCCKohäsion
15,02applications.py4.03611,90,63
10,74routing.py4.3747,60,59
9,36param_functions.py2.32313,30,71
3,05dependencies/utils.py9636,80,53
2,70openapi/utils.py58211,20,53

Die drei obersten Dateien sind genau die Art, für die die Formel gemacht ist: Tausende Zeilen, hohe zyklomatische Komplexität und mittlere bis geringe Kohäsion. Allein applications.py umfasst 4.036 Zeilen mit 41 unterscheidbaren Abschnitten — die Datei trägt den gesamten Lebenszyklus der Anwendung, die Registrierung der Routen, den Middleware-Stack und die OpenAPI-Erzeugung. routing.py ist mit 4.374 Zeilen sogar noch länger. Das ist kein schlechter Code — FastAPI ist ein sorgfältig gebautes Projekt. Aber Entropie sammelt sich in jeder Codebasis an, und diese Dateien haben den Kipppunkt überschritten, ab dem Aufteilen die kognitiven Kosten senken würde.

Ebenso richtig stuft die Formel die kleinen Dateien niedrig ein. concurrency.py (37 Zeilen, Kohäsion 1,0) und exception_handlers.py (28 Zeilen, Kohäsion 1,0) liegen nahe null — kleine, fokussierte Dateien, die keine Aufmerksamkeit brauchen.

Sie können das in wenigen Minuten nachvollziehen:

curl -O \
  https://raw.githubusercontent.com/HeinrichvH/articles/main/building-with-ai/01-entropy-cycle/entropy.py
git clone https://github.com/fastapi/fastapi
ollama pull nomic-embed-text
python entropy.py fastapi/fastapi --cohesion auto --all

5. KI ändert das Tempo, nicht den Zyklus

Es gibt eine Besonderheit der KI-gestützten Entwicklung, die zu wenig Beachtung findet.

KI erzeugt Code schnell. Eine Pair-Programming-Sitzung mit einem Sprachmodell liefert mehr Zeilen pro Stunde als Handarbeit. Dateien wachsen schneller. Features landen schneller. Entropie sammelt sich schneller an.

Aber KI kann auch 800 Zeilen ohne Reibung lesen. Sie scrollt nicht. Sie ermüdet nicht. Deshalb kommt das Schmerzsignal — der Moment, in dem Sie spüren, dass eine Datei zu groß ist — später, als es sollte. Der Mensch bleibt der Engpass beim Verstehen, doch die KI verdeckt das Symptom, weil sie die Navigation unsichtbar übernimmt.

Beim Debuggen zeigt sich der Preis. Auch dabei kann KI helfen — Hypothesen vorschlagen, Logs lesen, Korrekturen entwerfen. Aber Sie müssen sie steuern. Sie müssen entscheiden, welcher Hypothese Sie folgen, welchen Teil des Zustands Sie untersuchen und wo die eigentliche Grenze des Problems liegt. Dieses Steuern setzt voraus, dass Sie den Code verstehen. Je weniger Sie die Struktur durchschauen, desto schlechter werden Ihre Fragen und desto mehr Runden verschwenden Sie auf der falschen Spur. KI verstärkt Ihr Verständnis — sie ersetzt es nicht.

So entsteht eine Lücke: Der theoretische Kipppunkt, ab dem Umbauen günstiger ist, liegt vielleicht bei 500 Zeilen, aber Sie spüren ihn erst bei 800, weil Ihr KI-Partner die kognitive Last für Sie getragen hat. Wenn Sie es bemerken, zahlen Sie schon seit 300 Zeilen drauf.

Sie müssen schneller atmen, weil Sie schneller laufen.

Der Entropiezyklus ändert sich mit KI nicht. Die Physik bleibt dieselbe. Aber das Tempo muss steigen. Und auf Ihr Bauchgefühl können Sie sich dabei nicht verlassen, weil die KI das Signal dämpft. Sie brauchen eine Formel.

6. Die Schwelle ist keine Zeilenzahl

Daraus ergibt sich eine wichtige Feinheit: Die Schwelle ist keine Zeilenzahl. Nehmen Sie die Datei aus der Aufschlüsselung und lassen Sie sie auf 800 Zeilen wachsen, die Größe, bei der wir Aufteilungen beginnen sahen. Mit ihren fünf Belangen, geringer Kohäsion und zwanzig Importen kommt sie nun auf etwa 1,6, über der Schwelle: aufteilen.

Geben Sie denselben 800 Zeilen einen einzigen Belang, hohe Kohäsion und acht Importe, so viele wie im Median — alle Methoden dienen einem Zweck, alle Logik fließt in eine Richtung —, und sie kommen auf etwa 1,0, weit darunter. Diese Datei sollte nicht aufgeteilt werden: Sie würden nur Zusammenhänge zerstreuen, die zusammengehören, und danach vier Dateien öffnen, um ein einziges Konzept zu verstehen.

Deshalb steht die Kohäsion in der Formel und nicht nur die Zeilenzahl. Der Kipppunkt ist das Gleichgewicht zwischen zwei Kosten:

Zu spät aufteilen

Scrollen, Überlastung, irrelevanten Kontext im Kopf behalten

Zu früh aufteilen

zerstreuter Kontext, Springen zwischen Dateien für ein einziges Konzept

Die Formel misst beide Kräfte. Der Score steigt, wenn eine Datei groß und zusammenhanglos ist. Er bleibt niedrig, wenn eine Datei groß, aber fokussiert ist. Die Größe ist das stärkste Signal, aber nicht das einzige.

7. Warum verfrühte Abstraktion scheitert

Derselbe Rahmen erklärt auch, warum Over-Engineering scheitert. Verfrühte Abstraktion ist der Versuch, eine Kodierung für Information zu bauen, die Sie noch gar nicht haben. Nach dem MDL-Prinzip ist eine Kodierung, die für hypothetische künftige Daten optimiert ist, für die tatsächlichen heutigen Daten meist schlechter als eine einfache, direkte Kodierung. Sie zahlen die Komplexität jetzt und bekommen keinen Kompressionsgewinn, bis die vorhergesagten Daten eintreffen — falls sie es je tun.

Der Rhythmus

Wachstum schafft Unordnung. Aufräumen löst sie auf. Das sind keine Gegenkräfte. Es sind zwei Hälften desselben Zyklus. Wie das Atmen.

Atemzug 4 von 5 · Aufräumen: Ein Fünftel bleibt als Struktur Kern 54 Unordnung 150

Wer sich gegen die Unordnung stemmt — nichts Unfertiges ausliefern will —, wächst nie. Er steckt seine Kraft in Abstraktionsschichten für Probleme, die er gar nicht hat.

Wer sich gegen das Aufräumen stemmt — Refactoring für Verschwendung hält —, lässt die Unordnung wuchern. Belange sickern über Dateigrenzen, Abhängigkeiten werden unausgesprochen, und irgendwann verlangt jede Änderung, das ganze System zu verstehen, weil kein einzelnes Teil mehr für sich steht.

Der Entropiezyklus ist keine Philosophie. Er ist das, was die Informationstheorie für Systeme erwarten lässt, die echte Arbeit leisten.

Entropie ist nicht Ihr Feind. Sie ist der Beweis, dass Ihr System lebt.

Die einzige Frage ist, ob Sie einen Rhythmus haben, mit ihr umzugehen.

Die hier beschriebene Formel steht als quelloffenes Python-Skript bereit, entropy.py, und funktioniert mit jeder Codebasis — Python, JS/TS, Go, Rust, Java, C# und mehr. Die wissenschaftlichen Quellen: Shannon (1948), Rissanen (1978), McCabe (1976), Halstead (1977), Cowan (2001), Peitek et al. (2021), Sturtevant (2013, MIT).

Spüren Sie die Reibung in Ihren Systemen?

Wir helfen Teams, ihren Rhythmus zwischen Wachsen und Aufräumen zu finden — vereinbaren Sie gern einen Termin mit uns.

Bleiben Sie auf dem Laufenden

Gelegentliche Notizen zu Agenten, Software und dazu, wie wir bei Aquiilo entwickeln. Kein Spam, jederzeit abbestellbar.

Mit dem Abonnieren stimmen Sie zu, dass wir Ihnen unseren Newsletter senden dürfen. Sie können sich mit einem Klick aus jeder E-Mail abmelden.

War das hilfreich?