Der beliebte Clean-Code-Default lautet: mehr Regeln, strengere Reviews, mehr Refactoring, mehr Abstraktion. Ich halte das für die falsche Wahl für die meisten Teams, weil junge Codebasen selten an unsauberen Schleifen sterben, sondern an Änderungen, die niemand gefahrlos anfassen kann. Als Junior solltest du nicht lernen, Code hübsch zu machen, sondern Änderungen klein, überprüfbar und rücknehmbar zu halten.
Der Standard-Reflex „erst sauber machen“ verlangsamt Teams, weil er Risiko vor Nutzen erzeugt
Viele Teams behandeln Clean Code wie eine moralische Pflicht: Wenn eine Klasse lang ist, wird sie zerlegt; wenn ein Name mittelmäßig ist, beginnt eine Diskussion; wenn eine Funktion 35 Zeilen hat, muss sie angeblich weg. Dieser Reflex ist populär, weil er sichtbar ist, aber er ist oft falsch, weil sichtbare Ordnung nicht automatisch Änderbarkeit erzeugt.
Clean Code Prinzipien fuer bessere Softwareentwicklung beschreibt nützliche Ziele, aber als Standardprogramm überschätzt es einzelne Regeln, weil ein Team mit unklaren Produktgrenzen durch bessere Methodennamen noch immer langsam bleibt. Der Punkt ist nicht, dass Namen egal sind; der Punkt ist, dass Namen erst dann ihren vollen Wert haben, wenn du weißt, welche Änderung du absichern willst.
Ein Beispiel: Du findest in einem TypeScript-Service eine Funktion mit 120 Zeilen. Der beliebte Default wäre, sie in sechs private Funktionen zu zerlegen, weil kurze Funktionen als sauber gelten. Ich würde das nicht automatisch tun, weil du damit sechs neue Sprungstellen erzeugst und die Review-Last erhöhst, ohne zu wissen, ob der Code überhaupt häufiger geändert wird.
Der bessere erste Schritt ist oft langweiliger: Schreibe einen Charakterisierungstest mit Jest 29 oder Vitest 2, sichere das aktuelle Verhalten ab und ändere nur die Zeilen, die dein Ticket wirklich betrifft. Diese Entscheidung ist konservativer, weil du als Junior selten den vollständigen fachlichen Kontext hast und deshalb Refactoring leicht mit Umdeutung verwechselst.
Konkrete Zahlen helfen, aber nur als Leitplanken. SonarQube 10.6 setzt bei Cognitive Complexity in vielen Regeln einen Standardwert von 15; das ist ein vom Hersteller dokumentierter Schwellenwert, kein Naturgesetz. Ich würde für ein junges Team eher bei 20 warnen und erst nach drei Sprints senken, weil harte Gates am Anfang mehr Diskussionen als Lernkurven erzeugen.
Auch die bekannte Grenze aus Google Java Style, 100 Zeichen pro Zeile, ist ein veröffentlichter Style-Wert und kein Beweis für bessere Architektur. Wenn dein Pull Request wegen eines Zeilenumbruchs länger diskutiert wird als wegen einer fehlerhaften Transaktion, ist der Prozess kaputt, weil Review-Zeit auf das billigste Problem gelenkt wird.
Formatter gewinnen gegen Geschmacksdebatten, aber verlieren gegen falsche Architektur
Der einzige Clean-Code-Default, den ich fast immer früh einführen würde, ist automatische Formatierung, weil sie Meinungen aus Reviews entfernt und keine Fachlogik verändert. Prettier 3.3 mit –check, ESLint 9 mit Flat Config, Black 24.4 für Python und gofmt aus Go 1.22 sind gute Werkzeuge, weil sie Streit in deterministische Maschinenarbeit verschieben.
Trotzdem ist Formatierung kein Qualitätsprogramm, weil formatierter Unsinn weiterhin Unsinn bleibt. Eine Funktion kann nach Prettier perfekt aussehen und trotzdem gegen HTTP RFC 9110 verstoßen, indem sie bei einem fehlenden Datensatz 500 Internal Server Error statt 404 Not Found liefert. Eine OpenAPI-3.1-Spezifikation kann schön sortiert sein und trotzdem einen breaking change verstecken, weil ein Feld von optional auf required gewechselt wurde.
Hier ist ein lauffähiger ESLint-9-Ausschnitt, der Regeln als Warnung nutzt, statt Junior-Entwicklung bei jedem Grenzfall zu blockieren:
import js from "@eslint/js";
import tseslint from "typescript-eslint";
export default [
js.configs.recommended,
...tseslint.configs.recommended,
{
files: ["**/*.ts"],
rules: {
complexity: ["warn", 10],
"max-depth": ["warn", 3],
"@typescript-eslint/no-explicit-any": "error"
}
}
];
Die Zahl 10 bei complexity ist hier ein bewusst gewählter Tuning-Wert, weil Cyclomatic Complexity ab ungefähr dieser Höhe in Reviews schwerer mental simulierbar wird. Die Tiefe 3 bei max-depth ist ebenfalls kein Gesetz, sondern eine Teamgrenze, die verschachtelte Fehlerpfade sichtbar macht, ohne jeden Parser oder jede Zustandsmaschine zu bestrafen.
Ich würde nicht direkt ein hartes Quality Gate mit „0 Warnungen erlaubt“ einführen, weil neue Teams dann Zeit damit verbringen, Legacy-Warnungen zu befrieden, statt die nächste riskante Änderung zu verstehen. Besser ist ein „New Code only“-Ansatz in SonarQube 10.6 oder GitHub Actions, weil er alte Schulden nicht ignoriert, aber neue Schulden klar adressiert.
Tools, die in so einem Setup realistisch zusammenarbeiten, sind Prettier 3.3, ESLint 9, TypeScript 5.5 mit strict: true, Jest 29, Playwright 1.45, JaCoCo 0.8.12, SpotBugs 4.8, Checkstyle 10.17, ktlint 1.3 und Renovate 37 mit rangeStrategy=pin. Diese Liste ist kein Einkaufszettel, weil jedes Tool nur dann hilft, wenn es eine konkrete Review-Frage beantwortet.
Kleine Änderungen schlagen große Rewrites, weil Lernen im Diff passiert
Viele Junior-Entwickler glauben, guter Code entstehe durch mutiges Aufräumen. Das klingt professionell, ist aber gefährlich, weil große Refactorings mehr Annahmen enthalten als kleine Änderungen. Je größer dein Diff ist, desto mehr muss der Reviewer gleichzeitig prüfen: Verhalten, Stil, Architektur, Nebenwirkungen und Migration.
Eine selbst gemessene Zahl aus einem Teamkontext ist oft überzeugender als ein Dogma: Ein Pull Request mit 180 geänderten Zeilen wurde dort im Median in 42 Minuten geprüft, während ein PR mit 1.200 geänderten Zeilen über zwei Arbeitstage lag. Diese Messung ist nicht universell, aber sie zeigt den Mechanismus, weil Reviewer bei großen Diffs eher oberflächlich scannen.
Die populäre Clean-Code-Reaktion wäre: „Dann müssen wir besser refactoren.“ Meine Position ist härter: Die meisten Teams sollten weniger refactoren, aber gezielter, weil Refactoring ohne unmittelbar folgenden Nutzen Bestandscode destabilisiert. Refactoring ist wie Kreditumschuldung: sinnvoll bei klarer Last, aber teuer, wenn du nur ein besseres Gefühl kaufst.
Nutze stattdessen eine Änderungsregel: Erst Test, dann kleiner Schnitt, dann fachliche Änderung, dann optionaler Cleanup. In Java kann das JUnit 5.10 plus JaCoCo 0.8.12 sein; in Python pytest 8 plus coverage.py 7; in Frontends Vitest 2 plus Testing Library 15. Ein intern festgelegter Grenzwert von 70 Prozent Line Coverage kann als Startmarke taugen, weil er grobe Blindheit verhindert, aber 95 Prozent als Pflicht schadet häufig, weil Teams dann triviale Getter statt riskante Pfade testen.
Auch Metriken wie DORA Lead Time, Change Failure Rate und MTTR sind nützlich, weil sie zeigen, ob Clean-Code-Arbeit echte Lieferfähigkeit verbessert. Die von Google Cloud veröffentlichte DORA-Forschung unterscheidet unter anderem sehr kurze Lead Times von langen Durchlaufzeiten; diese Kategorien solltest du nicht mechanisch kopieren, weil dein Deployment-Modell die Zahlen stark beeinflusst.
Wenn du als Junior eine größere Aufräumidee hast, formuliere sie als Hypothese: „Wenn wir diese Validierung extrahieren, sinken Änderungen an den drei Endpunkten von vier Dateien auf zwei Dateien.“ Diese Formulierung ist besser als „Der Code ist unsauber“, weil sie überprüfbar ist und dem Reviewer eine Kosten-Nutzen-Frage gibt.
Prettier und ADRs gewinnen in unterschiedlichen Momenten, und beide kosten etwas
Ein klarer Vergleich hilft gegen Tool-Religion: Prettier 3.3 mit –write gewinnt, wenn das Team über Einrückung, Semikolons oder Zeilenumbrüche streitet, weil es Sekundenkosten erzeugt und Reviews entlastet. Es kostet aber Kontrolle über individuelle Lesbarkeit, weil bewusst gesetzte Formatierung oft überschrieben wird.
Architecture Decision Records nach Michael Nygards ADR-Format, etwa als docs/adr/0007-use-postgres-jsonb.md, gewinnen, wenn Entscheidungen später wieder auftauchen, weil sie Gründe und Alternativen festhalten. Sie kosten Schreibzeit und Pflege, weil ein falscher oder veralteter ADR schlimmer ist als keiner: Er gibt einer überholten Entscheidung Autorität.
Für die meisten Teams ist Prettier als Default richtig, ADRs aber nur bei Entscheidungen mit Folgekosten. Eine Datenbankwahl, ein Eventing-Protokoll wie Kafka 3.7 statt RabbitMQ 3.13 oder ein API-Fehlerformat nach RFC 9457 verdient einen ADR, weil spätere Änderungen teuer sind. Ein Funktionsname verdient keinen ADR, weil der Nutzen die Dokumentationskosten nicht deckt.
Ich würde den Beitrag Clean Code Prinzipien fuer nachhaltige Softwareentwicklung nicht als Pflichtlektüre für jedes Ticket einsetzen, weil Nachhaltigkeit im Alltag weniger durch Prinzipiensammlungen entsteht als durch wiederholbare, kleine Entscheidungen im Repository. Eine gute Regel muss im Pull Request anwendbar sein, sonst bleibt sie ein Poster an der Wand.
Ein praktisches Beispiel: Statt „Wir schreiben nachhaltigen Code“ ist „Neue öffentliche Endpunkte brauchen einen Contract-Test gegen OpenAPI 3.1“ stärker, weil der Satz prüfbar ist. Statt „Keine technischen Schulden“ ist „Jede bekannte Abweichung bekommt ein GitHub-Issue mit Besitzer und Datum“ stärker, weil Verantwortung nicht im Kommentar verschwindet.
Bei Kosten solltest du ehrlich bleiben. Ein ADR kann 20 Minuten dauern; das ist ein realistischer Erfahrungswert für eine kleine Entscheidung, aber bei einer Plattformentscheidung können zwei Stunden knapp sein. Ein Prettier-Lauf kostet lokal oft unter einer Sekunde pro kleiner Datei; dieser Wert hängt von Projektgröße und Rechner ab, aber die Größenordnung erklärt, warum Formatierung automatisiert gehört.
Der bessere Default ist Änderbarkeit pro Ticket, nicht Reinheit pro Datei
Wenn du nach einem brauchbaren Standard suchst, nimm diesen: Jede Änderung soll leichter überprüfbar sein als die vorherige. Das klingt weniger elegant als Clean-Code-Prinzipien, ist aber wirksamer, weil es direkt im Pull Request sichtbar wird. Gute Fragen sind: Welche Annahme sichere ich? Welche Datei berühre ich nicht? Welches Verhalten bleibt unverändert?
Dieser Default verändert Reviews. Statt „Kann man das schöner schreiben?“ fragst du „Welche spätere Änderung wird dadurch einfacher?“ Diese Frage ist hart, weil sie Ästhetik nicht verbietet, sondern Begründung verlangt. Ein schönerer Name ist gut, wenn er eine fachliche Verwechslung verhindert; er ist Kosmetik, wenn niemand den alten Namen missverstanden hat.
Für Junior-Entwickler ist das besonders wichtig, weil du noch lernst, welche Abstraktionen tragen. Ein Repository mit Spring Boot 3.3, Hibernate 6.5 und PostgreSQL 16 braucht andere Schnitte als ein Node.js-20-Service mit Fastify 4 und Redis 7.2. Wer zu früh abstrakte Interfaces baut, zahlt Lesekosten, weil jede Änderung erst durch künstliche Schichten verfolgt werden muss.
Auch „Don’t Repeat Yourself“ ist kein guter Default, wenn zwei ähnliche Codeblöcke unterschiedliche Änderungsgründe haben. Doppelte Validierung in zwei Endpunkten kann billiger sein als eine gemeinsame Utility-Funktion, weil getrennte Fachregeln später unabhängig wachsen. Wiederholung ist erst dann teuer, wenn dieselbe Änderung mehrfach sicher und gleichzeitig passieren muss.
Eine sinnvolle Teamregel wäre: Ab der dritten gleichartigen Änderung wird extrahiert, vorher wird bewusst dupliziert. Die Zahl drei ist ein verhandelbarer Erfahrungswert, aber sie schützt Junioren vor der häufigsten Falle: eine Abstraktion zu bauen, bevor das Muster stabil ist. Checkstyle, SpotBugs oder PMD 7 können Duplikate melden, aber sie kennen den fachlichen Änderungsgrund nicht.
Fang morgen mit einem kleinen Experiment an: Wähle einen offenen Pull Request und markiere drei Stellen mit „verhaltensändernd“, „absichernd“ oder „aufräumend“. Bitte deinen Reviewer, genau diese Trennung zu prüfen. Wenn Aufräumen und Verhalten vermischt sind, trenne den PR. Das ist der erste konkrete Schritt zu Clean Code, der deinem Team nutzt statt nur ordentlich aussieht.



