Brian Kernighans Rat zum guten Geschmack zeigt, wie lesbarer Code Zeit spart, Fehler reduziert und Teams schneller vorankommen lässt als clevere Tricks.

Brian Kernighans Name taucht dort auf, wo viele Entwickler ihn verwenden, ohne groß darüber nachzudenken: klassische Unix‑Werkzeuge, das C‑Ökosystem und Jahrzehnte an Texten, die Menschen beibrachten, Programme klar zu erklären. Ob du The C Programming Language (mit Dennis Ritchie), The Unix Programming Environment oder seine Essays und Vorträge kennst — der gemeinsame Nenner ist das Beharren auf einfachen Ideen, sauber ausgedrückt.
Kernighans beste Ratschläge hängen nicht von C‑Syntax oder Unix‑Konventionen ab. Es geht darum, wie Menschen lesen: Wir suchen nach Struktur, verlassen uns auf Benennungen, schließen auf Absicht und geraten ins Straucheln, wenn Code Bedeutung hinter Tricks versteckt. Deshalb ist „Geschmack" in Sachen Lesbarkeit auch dann wichtig, wenn du TypeScript, Python, Go, Java oder Rust schreibst.
Sprachen ändern sich. Tooling verbessert sich. Teams liefern unter Zeitdruck Features, und der Großteil des Codes wird von jemand anderem gewartet als dem ursprünglichen Autor (oft dem zukünftigen Ich). Klarheit ist der Multiplikator, der all das überlebbar macht.
Dies ist keine Hommage an „Hero Coding“ oder ein Aufruf, alte Regeln auswendig zu lernen. Es ist ein praktischer Leitfaden zu Gewohnheiten, die Alltags‑Code leichter handhabbar machen:
Kernighans Einfluss ist wichtig, weil er auf ein einfaches, teamfreundliches Ziel hinweist: schreibe Code, der kommuniziert. Wenn Code wie eine klare Erklärung zu lesen ist, verbringst du weniger Zeit mit Entschlüsseln und mehr Zeit mit Verbessern.
„Guter Geschmack“ in lesbarem Code ist keine Frage persönlicher Vorlieben, schicker Muster oder die Lösung in möglichst wenigen Zeilen zu quetschen. Es ist die Gewohnheit, die einfachste, klare Option zu wählen, die zuverlässig Absicht vermittelt.
Eine Lösung mit gutem Geschmack beantwortet die Grundfrage für den nächsten Leser: Was versucht dieser Code zu tun, und warum wird er so implementiert? Wenn diese Antwort mentale Verrenkungen, versteckte Annahmen oder das Entschlüsseln cleverer Tricks erfordert, kostet der Code das Team Zeit.
Die meisten Codes werden viel häufiger gelesen als geschrieben. „Guter Geschmack“ betrachtet Lesen als die primäre Aktivität:
Deshalb ist Lesbarkeit nicht nur Ästhetik (Einrückung, Zeilenbreite oder ob du snake_case magst). Diese Dinge helfen, aber „guter Geschmack“ dreht sich hauptsächlich darum, das Denken zu erleichtern: klare Namen, offensichtlicher Kontrollfluss und vorhersehbare Struktur.
Ein häufiger Fehler ist, Kürze statt Klarheit zu optimieren. Manchmal ist der klarste Code etwas länger, weil er die Schritte explizit macht.
Zum Beispiel im Vergleich:
Die zweite Variante fügt vielleicht Zeilen hinzu, reduziert aber die kognitive Last, um die Korrektheit zu überprüfen. Fehler sind leichter zu isolieren und Änderungen sicherer anzuwenden.
Guter Geschmack heißt zu wissen, wann man aufhört, eine Lösung mit Cleverness „zu verbessern“, und stattdessen die Absicht deutlich macht. Wenn ein Kollege den Code versteht, ohne dich um eine Führung zu bitten, hast du gut gewählt.
Cleverer Code fühlt sich im Moment oft wie ein Gewinn an: weniger Zeilen, ein netter Trick, ein „Wow“ im Diff. In einem echten Team wird diese Cleverness zu einer wiederkehrenden Rechnung — bezahlt in Einarbeitungszeit, Review‑Zeit und Zögern, jedes Mal wenn jemand den Code anfassen muss.
Onboarding verlangsamt sich. Neue Kollegen müssen nicht nur das Produkt lernen; sie müssen auch deinen privaten Dialekt von Abkürzungen verstehen. Wenn das Verstehen einer Funktion das Entschlüsseln cleverer Operatoren oder impliziter Konventionen erfordert, werden Leute Änderungen vermeiden — oder sie mit Angst vornehmen.
Reviews werden länger und weniger verlässlich. Reviewer investieren Energie darin zu beweisen, dass der Trick korrekt ist, statt zu beurteilen, ob das Verhalten der Absicht entspricht. Clevere Lösungen sind schwerer mental zu simulieren, sodass Reviewer Edge‑Cases übersehen, die in einer geradlinigen Version aufgefallen wären.
Cleverness häuft sich an bei:
Ein paar Wiederholungstäter:
17, 0.618, -1), die Regeln kodieren, die sich niemand merken kann.\u0026\u0026 / ||‑Tricks), die darauf bauen, dass Leser subtile Evaluationsregeln kennen.Kernighans Punkt über „Geschmack“ zeigt sich hier: Klarheit heißt nicht, mehr zu schreiben; es heißt, Absicht offensichtlich zu machen. Wenn eine „clevere“ Version heute 20 Sekunden spart, aber jeden zukünftigen Leser 20 Minuten kostet, ist sie nicht klug — sie ist teuer.
Kernighans „Geschmack“ zeigt sich häufig in kleinen, wiederholbaren Entscheidungen. Du brauchst keinen großen Rewrite, um Code leichter handhabbar zu machen — winzige Klarheitsgewinne summieren sich jedes Mal, wenn jemand eine Datei scannt, nach einem Verhalten sucht oder unter Zeitdruck einen Bug behebt.
Ein guter Name reduziert die Notwendigkeit für Kommentare und macht Fehler schwerer zu verbergen.
Strebe nach absichtserklärenden Namen, die zur Sprache deines Teams passen:
invoiceTotalCents statt sum.Wenn ein Name dich zum Dekodieren zwingt, erfüllt er nicht seine Aufgabe.
Die meiste Lektüre ist ein Überfliegen. Konsistente Whitespaces und Struktur helfen dem Auge, zu finden, was wichtig ist: Funktionsgrenzen, Bedingungen und den „happy path“.
Einige praktische Gewohnheiten:
Wenn die Logik knifflig wird, verbessert sich die Lesbarkeit meist, indem Entscheidungen explizit gemacht werden.
Vergleiche diese beiden Stile:
// Harder to scan
if (user \u0026\u0026 user.active \u0026\u0026 !user.isBanned \u0026\u0026 (role === 'admin' || role === 'owner')) {
allow();
}
// Clearer
if (!user) return deny('missing user');
if (!user.active) return deny('inactive');
if (user.isBanned) return deny('banned');
if (role !== 'admin' \u0026\u0026 role !== 'owner') return deny('insufficient role');
allow();
Die zweite Version ist länger, liest sich aber wie eine Checkliste — und lässt sich leichter erweitern, ohne Fehler einzuführen.
Das sind „kleine" Entscheidungen, aber die tägliche Handwerkskunst wartbarer Software: ehrliche Namen, Formatierung, die den Leser führt, und ein Kontrollfluss, der keine mentalen Verrenkungen verlangt.
Kernighans Klarheitsstil zeigt sich am stärksten in der Art, wie du Arbeit in Funktionen und Module aufteilst. Ein Leser sollte die Struktur überfliegen können, erraten, was jedes Stück macht, und größtenteils richtig liegen, bevor er ins Detail geht.
Ziele auf Funktionen, die genau eine Sache auf einer bestimmten „Zoomstufe" tun. Wenn eine Funktion Validierung, Geschäftslogik, Formatierung und I/O mischt, muss der Leser mehrere Fäden im Kopf behalten.
Ein schneller Test: Schreibst du Kommentare wie „// jetzt X machen“ innerhalb einer Funktion, ist X oft ein guter Kandidat für eine separate Funktion mit klarem Namen.
Lange Parameterlisten sind eine versteckte Komplexitätssteuer: jeder Aufruf wird zu einer Mini‑Konfigurationsdatei.
Wenn mehrere Parameter immer zusammen auftauchen, gruppiere sie sinnvoll. Options‑Objekte (oder kleine Datenstrukturen) können Aufrufstellen selbsterklärend machen — vorausgesetzt, du hältst die Gruppe kohärent und schiebst nicht alles in eine „misc“‑Tasche.
Außerdem: Bevorzuge das Übergeben von Domänenkonzepten statt Primitiven. UserId ist besser als string, und DateRange ist besser als (start, end), wenn diese Werte Regeln haben.
Module sind ein Versprechen: „Alles, was du für dieses Konzept brauchst, ist hier, der Rest ist woanders.“ Halte Module klein genug, dass du ihren Zweck im Kopf behalten kannst, und gestalte Grenzen so, dass Seiteneffekte minimiert werden.
Praktische Gewohnheiten, die helfen:
Wenn Shared State nötig ist, nenne ihn ehrlich und dokumentiere die Invarianten. Klarheit bedeutet nicht, Komplexität zu vermeiden — sie heißt, sie dort zu platzieren, wo Leser sie erwarten. Mehr dazu, wie man diese Grenzen bei Änderungen beibehält, siehe /blog/refactoring-as-a-habit.
Kernighans „Geschmack“ zeigt sich darin, wie du kommentierst: Ziel ist nicht, jede Zeile anzumerken, sondern zukünftige Verwirrung zu reduzieren. Der beste Kommentar verhindert eine falsche Annahme — besonders, wenn der Code korrekt, aber überraschend ist.
Ein Kommentar, der den Code nur wiederholt („i erhöht sich“) fügt nur Rauschen hinzu und lehrt Leser, Kommentare zu ignorieren. Nützliche Kommentare erklären Absicht, Kompromisse oder Einschränkungen, die aus der Syntax nicht ersichtlich sind.
# Bad: sagt, was der Code bereits sagt
retry_count += 1
# Good: erklärt, warum das Retry begrenzt ist
retry_count += 1 # Vermeidet Sperren durch wiederholte Fehlschläge
Wenn du versucht bist, „was"‑Kommentare zu schreiben, ist das oft ein Zeichen, dass der Code klarer sein sollte (bessere Namen, kleinere Funktion, einfacherer Kontrollfluss). Lass den Code die Fakten tragen; Kommentare tragen die Begründung.
Nichts untergräbt Vertrauen schneller als ein veralteter Kommentar. Wenn ein Kommentar optional ist, driftet er mit der Zeit; wenn er falsch ist, wird er zur aktiven Fehlerquelle.
Eine praktische Gewohnheit: Behandle Kommentar‑Updates als Teil der Änderung, nicht als „nice to have“. In Reviews ist es fair zu fragen: Passt dieser Kommentar noch zum Verhalten? Wenn nicht, aktualisiere ihn oder entferne ihn. „Kein Kommentar“ ist besser als „falscher Kommentar“.
Inline‑Kommentare sind für lokale Überraschungen. Breitere Hinweise gehören in Docstrings, READMEs oder Entwicklernotizen — besonders für:
Eine gute Docstring sagt, wie eine Funktion korrekt zu benutzen ist und welche Fehler zu erwarten sind, ohne die Implementierung zu erzählen. Eine kurze /docs‑ oder /README‑Notiz kann die „Warum‑wir‑es‑so‑gemacht‑haben"‑Geschichte festhalten, sodass sie Refactors überdauert.
Der stille Gewinn: weniger Kommentare, aber jeder verdient seinen Platz.
Die meisten Codes sehen auf dem Happy Path „in Ordnung“ aus. Der wirkliche Geschmackstest ist, was passiert, wenn Eingaben fehlen, Services timeouts erzeugen oder ein Nutzer etwas Unerwartetes macht. Unter Stress versteckt cleverer Code die Wahrheit. Klarer Code macht Fehler offensichtlich — und handhabbar.
Fehlermeldungen sind Teil deines Produkts und deines Debugging‑Workflows. Schreib sie so, als wäre die nächste Person müde und im Bereitschaftsdienst.
Enthält:
Wenn du Logging hast, ergänze strukturierten Kontext (wie requestId, userId oder invoiceId), damit die Meldung ohne langes Graben handlungsfähig ist.
Die Versuchung besteht darin, „alles“ mit einem cleveren Einzeiler oder einem generischen Catch‑All zu handhaben. Guter Geschmack ist, die wenigen Edge‑Cases auszuwählen, die wichtig sind, und sie sichtbar zu machen.
Beispielsweise liest sich ein expliziter Branch für „leere Eingabe“ oder „nicht gefunden“ oft besser als eine Transformationskette, die irgendwo implizit null produziert. Wenn ein Spezialfall wichtig ist, benenne ihn und setze ihn nach vorne.
Das Mischen von Rückgabeformen (manchmal ein Objekt, manchmal ein String, manchmal false) zwingt Leser, einen mentalen Entscheidungsbaum zu pflegen. Bevorzuge Muster, die konsistent bleiben:
Klare Fehlerbehandlung reduziert Überraschungen — und Überraschungen sind die Quelle von Bugs und nächtlichen Pages.
Klarheit dreht sich nicht nur um das, was du beim Schreiben gemeint hast. Es geht darum, was die nächste Person erwartet, wenn sie eine Datei um 16:55 Uhr öffnet. Konsistenz verwandelt „Code lesen“ in Mustererkennung — weniger Überraschungen, weniger Missverständnisse, weniger Debatten, die jeden Sprint wieder auftauchen.
Ein guter Team‑Style‑Guide ist kurz, spezifisch und pragmatisch. Er versucht nicht, jede Präferenz zu kodifizieren; er klärt wiederkehrende Fragen: Namenskonventionen, Dateistruktur, Fehler‑Handling‑Muster und was „done" für Tests bedeutet.
Der wirkliche Wert ist sozial: Er verhindert, dass dieselbe Diskussion bei jedem neuen Pull Request neu beginnt. Wenn etwas dokumentiert ist, verschieben sich Reviews von „Ich mag X“ zu „Wir haben uns für X entschieden (und hier ist warum)“. Halte den Guide lebendig und leicht auffindbar — viele Teams pinnen ihn ins Repo (z. B. /docs/style-guide.md), sodass er nah am Code ist.
Setze Formatter und Linter für messbare, langweilige Regeln ein:
Das befreit Menschen, sich auf Bedeutung zu konzentrieren: Namensgebung, API‑Form, Edge‑Cases und ob der Code der Absicht entspricht.
Manuelle Regeln bleiben wichtig, wenn sie Designentscheidungen beschreiben — z. B. „Bevorzuge Early Returns, um Verschachtelung zu reduzieren“ oder „Ein öffentlicher Einstiegspunkt pro Modul“. Tools können das nicht vollständig beurteilen.
Manchmal ist Komplexität gerechtfertigt: enge Performance‑Budgets, Embedded‑Beschränkungen, knifflige Concurrency oder plattformspezifisches Verhalten. Die Vereinbarung sollte lauten: Ausnahmen sind erlaubt, aber explizit.
Ein einfacher Standard hilft: dokumentiere den Trade‑off in einem kurzen Kommentar, füge ein Micro‑Benchmark oder eine Messung hinzu, wenn Performance als Grund angegeben wird, und isoliere den komplexen Code hinter einer klaren Schnittstelle, sodass der Rest des Codebases lesbar bleibt.
Ein guter Code‑Review sollte sich mehr wie eine kurze, fokussierte Lektion in „gutem Geschmack“ anfühlen als wie eine Inspektion. Kernighans Punkt ist nicht, dass cleverer Code böse ist — sondern dass Cleverness teuer wird, wenn andere damit leben müssen. Reviews sind der Ort, an dem Teams diesen Trade‑off sichtbar machen und bewusst Klarheit wählen können.
Beginne mit der Frage: „Kann ein Kollege das in einem Durchgang verstehen?“ Das heißt meist, zuerst auf Benennung, Struktur, Tests und Verhalten zu schauen, bevor man sich Mikro‑Optimierungen widmet.
Wenn der Code korrekt, aber schwer lesbar ist, behandle Lesbarkeit als echten Fehler. Schlage vor, Variablen so umzubenennen, dass sie Absicht widerspiegeln, lange Funktionen zu splitten, Kontrollfluss zu vereinfachen oder einen kleinen Test hinzuzufügen, der das erwartete Verhalten demonstriert. Ein Review, das „es funktioniert, aber ich weiß nicht warum“ abfängt, verhindert Wochen zukünftiger Verwirrung.
Eine praktische Prüfreihenfolge, die sich bewährt hat:
Reviews eskalieren, wenn Feedback als Punktevergabe verstanden wird. Statt „Warum hast du das so gemacht?“ versuche:
Fragen laden zur Zusammenarbeit ein und bringen oft Zwänge ans Licht, die du nicht kanntest. Vorschläge zeigen Richtung ohne Kompetenz zu unterstellen. So verbreitet sich Geschmack im Team.
Wenn du konsistente Lesbarkeit willst, verlass dich nicht auf die Laune des Reviewers. Füge ein paar „Klarheitschecks“ in deine Review‑Vorlage und die Definition of Done ein. Kurz und konkret:
Mit der Zeit verwandelt das Reviews vom Stilpolicing in Unterricht über Urteilsvermögen — genau die tägliche Disziplin, für die Kernighan plädierte.
LLM‑Tools können schnell lauffähigen Code erzeugen, aber „funktioniert" ist nicht die Messlatte, auf die Kernighan hinwies — kommuniziert ist es. Wenn dein Team mit einer Vibe‑Coding‑Arbeitsweise arbeitet (z. B. Features über Chat generieren und den Code iterativ anpassen), lohnt es sich, Lesbarkeit als erstklassiges Akzeptanzkriterium zu behandeln.
Auf Plattformen wie Koder.ai, wo du React‑Frontends, Go‑Backends und Flutter‑Mobile‑Apps aus einem Chatprompt generieren kannst (und anschließend den Quellcode exportierst), gelten dieselben geschmacksgetriebenen Gewohnheiten:
Geschwindigkeit ist am wertvollsten, wenn das Ergebnis für Menschen leicht zu prüfen, zu warten und zu erweitern ist.
Klarheit ist kein Zustand, den man einmal erreicht. Code bleibt nur lesbar, wenn du ihn immer wieder in Richtung klarer Sprache nudgest, während sich Anforderungen ändern. Kernighans Haltung passt hierher: bevorzuge stetige, verständliche Verbesserungen statt heroischer Rewrites oder „cleverer" Einzeiler, die heute beeindrucken und nächsten Monat verwirren.
Das sicherste Refactoring ist langweilig: winzige Änderungen, die das Verhalten identisch halten. Wenn du Tests hast, führe sie nach jedem Schritt aus. Wenn nicht, schreibe einige fokussierte Checks rund um den Bereich, den du anfasst — betrachte sie als temporäre Schutznetze, damit du Struktur verbessern kannst, ohne Angst zu haben.
Ein praktischer Rhythmus:
Kleine Commits machen Reviews einfacher: Kollegen können die Absicht beurteilen, statt nach Nebenwirkungen zu suchen.
Du musst nicht bei jedem Touchpoint alle „cleveren“ Konstrukte auf einmal entfernen. Wenn du Code für ein Feature oder einen Bugfix anfasst, tausche clevere Abkürzungen gegen geradlinige Äquivalente:
So gewinnt Klarheit in echten Teams: ein verbesserter Hotspot nach dem anderen, genau dort, wo Menschen ohnehin arbeiten.
Nicht jede Aufräumarbeit ist dringend. Eine nützliche Regel: Refactore jetzt, wenn der Code aktiv verändert wird, häufig missverstanden wird oder wahrscheinlich Bugs verursacht. Plane später, wenn er stabil und isoliert ist.
Mache Refactoring‑Schulden sichtbar: hinterlasse ein kurzes TODO mit Kontext oder erstelle ein Ticket, das den Schmerz beschreibt („schwer neue Zahlungsmethoden hinzuzufügen; Funktion macht 5 Aufgaben“). So entscheidest du bewusst — statt dass verwirrender Code stillschweigend zur dauerhaften Belastung wird.
Wenn du willst, dass „guter Geschmack" regelmäßig sichtbar wird, mach es den Leuten einfach, ihn zu praktizieren. Hier eine leichte Checkliste, die du in Planung, Coding und Review wiederverwenden kannst — kurz genug, um sie zu merken, spezifisch genug, um etwas zu tun.
Vorher: process(data) macht Validierung, Parsen, Speichern und Logging an einer Stelle.
Nachher: Aufteilen in validateInput, parseOrder, saveOrder, logResult. Die Hauptfunktion wird zur lesbaren Gliederung.
Vorher: if not valid then return false fünfmal wiederholt.
Nachher: Eine upfront Guard‑Sektion (oder eine Validierungsfunktion), die eine klare Liste von Problemen zurückgibt.
Vorher: x, tmp, flag2, doThing().
Nachher: retryCount, draftInvoice, isEligibleForRefund, sendReminderEmail().
Vorher: Eine Schleife mit drei in der Mitte versteckten Spezialfällen.
Nachher: Spezialfälle zuerst behandeln (oder Helfer extrahieren), dann die einfache Schleife ausführen.
Wählt eine Verbesserung für diese Woche: „keine neuen Abkürzungen“, „happy path zuerst“, „pro PR einen Helper extrahieren“ oder „jede Fehlermeldung enthält nächste Schritte“. Verfolgt sie sieben Tage, und behaltet, was das Lesen tatsächlich erleichtert.
Kernighans Einfluss betrifft weniger C selbst als eine dauerhafte Erkenntnis: Code ist ein Kommunikationsmedium.
Sprachen und Frameworks ändern sich, aber Teams brauchen weiterhin Code, der sich leicht überfliegen, durchdenken, prüfen und debuggen lässt — besonders Monate später und unter Zeitdruck.
„Guter Geschmack“ bedeutet konsequent die einfachste klare Option zu wählen, die die Absicht vermittelt.
Ein nützlicher Test: Kann ein Kollege beantworten „Was macht das und warum wurde es so gemacht?“ ohne Tricks zu entschlüsseln oder sich auf versteckte Annahmen zu verlassen?
Weil Code viel häufiger gelesen als geschrieben wird.
Für Leser zu optimieren reduziert Einarbeitungszeit, Review‑Reibung und das Risiko fehlerhafter Änderungen — besonders wenn der Wartende „das zukünftige Ich“ mit weniger Kontext ist.
Die „Cleverness‑Steuer“ äußert sich in:
Wenn die clevere Version heute Sekunden spart, aber bei jeder Berührung Minuten kostet, ist das ein Nettoverlust.
Häufige Problemquellen sind:
Solche Muster verbergen Zwischenzustände und lassen Edge‑Cases leichter im Review übersehen.
Wenn es die kognitive Belastung senkt.
Explizite Schritte mit benannten Variablen (z. B. validate → normalize → compute) machen Korrektheit leichter überprüfbar, vereinfachen Debugging und erleichtern künftige Änderungen — selbst wenn ein paar Zeilen dazukommen.
Strebe an für:
invoiceTotalCents statt sum)Wenn du einen Namen dekodieren musst, erfüllt er seine Aufgabe nicht; er sollte die Notwendigkeit zusätzlicher Kommentare verringern.
Bevorzuge einfache, explizite Verzweigungen und halte den „happy path“ sichtbar.
Hilfreiche Taktiken:
Kommentiere das Warum, nicht das Was.
Gute Kommentare erklären Absicht, Kompromisse oder nicht offensichtliche Invarianten. Vermeide das Nacherzählen offensichtlichen Codes und behandle Kommentar‑Updates als Teil der Änderung — veraltete Kommentare sind schlimmer als keine.
Nutze Tools für mechanische Regeln (Formatierung, Imports, einfache Fußfallen) und lass Menschen über Bedeutung urteilen.
Ein schlanker Style‑Guide reduziert wiederkehrende Diskussionen (Namenskonventionen, Struktur, Fehlerbehandlung). Wenn Ausnahmen für Performance nötig sind, dokumentiere den Trade‑off und isoliere die Komplexität hinter einer klaren Schnittstelle.