Brian Kernighan’s advies over ‘goede smaak’ laat zien hoe leesbare code tijd bespaart, bugs vermindert en echte teams sneller laat werken dan slimme trucs.

De naam Brian Kernighan verschijnt op plekken die veel ontwikkelaars gebruiken zonder erover na te denken: klassieke Unix-tools, het C-ecosysteem en decennia aan schrijven die mensen leerde programma’s duidelijk uit te leggen. Of je nu The C Programming Language (met Dennis Ritchie), The Unix Programming Environment of zijn essays en lezingen kent, de gemeenschappelijke draad is de nadruk op eenvoudige ideeën die helder worden uitgedrukt.
Kernighan’s beste advies hangt niet af van C-syntaxis of Unix-conventies. Het gaat over hoe mensen lezen: we scannen naar structuur, we vertrouwen op naamgeving, we infereren intentie en raken in de war als code betekenis verbergt achter trucs. Daarom doet “smaak” in leesbaarheid er nog steeds toe als je TypeScript, Python, Go, Java of Rust schrijft.
Talen veranderen. Tooling verbetert. Teams leveren nog steeds features onder tijdsdruk, en de meeste code wordt onderhouden door iemand anders dan de oorspronkelijke auteur (vaak het toekomstige jij). Duidelijkheid is de vermenigvuldiger die dat allemaal overleefbaar maakt.
Dit is geen hulde aan “heldencode” of een oproep om ouderwetse regels uit je hoofd te leren. Het is een praktische gids voor gewoonten die dagelijkse code makkelijker maken om mee te werken:
Kernighan’s invloed is belangrijk omdat hij naar een eenvoudig, teamvriendelijk doel wijst: schrijf code die communiceert. Als code leest als een duidelijke uitleg, besteed je minder tijd aan het ontcijferen en meer tijd aan verbeteren.
“Goede smaak” in leesbare code gaat niet over persoonlijke stijl, chique patronen of het comprimeren van een oplossing tot het minste aantal regels. Het is de gewoonte om de simpelste, duidelijke optie te kiezen die betrouwbaar intentie communiceert.
Een oplossing met goede smaak beantwoordt een basale vraag voor de volgende lezer: Wat probeert deze code te doen, en waarom doet hij het zo? Als dat antwoord mentale gymnastiek, verborgen aannames of het ontcijferen van slimme trucs vereist, kost de code het team tijd.
De meeste code wordt veel vaker gelezen dan geschreven. “Goede smaak” behandelt lezen als de primaire activiteit:
Daarom is leesbaarheid niet alleen esthetiek (inspringing, regelbreedte, of of je snake_case gebruikt). Dat helpt, maar “goede smaak” gaat vooral over het makkelijk maken van redeneren: duidelijke namen, voor de hand ligende control flow en voorspelbare structuur.
Een veelgemaakte fout is optimaliseren voor beknoptheid in plaats van duidelijkheid. Soms is de duidelijkste code iets langer omdat de stappen expliciet zijn.
Vergelijk bijvoorbeeld twee benaderingen:
De tweede versie voegt misschien regels toe, maar verlaagt de cognitieve last om correctheid te verifiëren. Het maakt bugs ook makkelijker te isoleren en veranderingen veiliger toe te passen.
Goede smaak is weten wanneer je moet stoppen met het “verbeteren” van een oplossing met slimheid en in plaats daarvan de intentie duidelijk maken. Als een teamgenoot de code kan begrijpen zonder je om een rondleiding te vragen, heb je goed gekozen.
Slimme code voelt vaak als een overwinning op het moment: minder regels, een nette truc, een “wow”-factor in de diff. In een echt team verandert die slimheid in een terugkerende rekening—betaald in inwerktijd, reviewtijd en aarzeling telkens als iemand de code moet aanraken.
Onboarding vertraagt. Nieuwe teamleden moeten niet alleen het product leren; ze moeten ook jouw privé-dialect van shortcuts leren. Als het begrijpen van een functie het ontcijferen van slimme operators of impliciete conventies vereist, vermijden mensen het aanpassen ervan—of ze doen het met angst.
Reviews worden langer en minder betrouwbaar. Reviewers steken energie in het bewijzen dat de truc correct is in plaats van te beoordelen of het gedrag overeenkomt met de intentie. Nog erger: slimme code is moeilijker mentaal te simuleren, dus reviewers missen randgevallen die ze in een eenvoudige versie wel hadden gezien.
Slimheid stapelt zich op tijdens:
Een paar herhalende boosdoeners:
17, 0.618, -1) die regels coderen die niemand kan onthouden.\u0026\u0026 / || trucs) die erop vertrouwen dat lezers subtiele evaluatieregels kennen.Kernighan’s punt over “smaak” verschijnt hier: duidelijkheid gaat niet over meer schrijven; het gaat erom de intentie voor de hand liggend te maken. Als een “slimme” versie vandaag 20 seconden bespaart maar elke toekomstige lezer 20 minuten kost, is het niet slim—het is duur.
Kernighan’s “smaak” verschijnt vaak in kleine, herhaalbare beslissingen. Je hoeft geen grote rewrite te doen om code leefbaarder te maken—kleine duidelijkheidswinst stapelen zich op elke keer dat iemand een bestand scant, naar gedrag zoekt of een bug fixt onder tijdsdruk.
Een goede naam vermindert de noodzaak van comments en maakt fouten moeilijker te verbergen.
Streef naar intentie-openbarende namen die passen bij hoe je team praat:
invoiceTotalCents boven sum.Als een naam je dwingt die te ontcijferen, doet hij het tegenovergestelde van zijn taak.
Lezen is meestal scannen. Consistente witruimte en structuur helpen het oog te vinden wat belangrijk is: functiegrenzen, conditionals en het “happy path”.
Een paar praktische gewoonten:
Wanneer logica lastig wordt, verbetert de leesbaarheid meestal door beslissingen expliciet te maken.
Vergelijk deze twee stijlen:
// 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();
De tweede versie is langer, maar leest als een checklist—en is makkelijker uit te breiden zonder iets te breken.
Dit zijn “kleine” keuzes, maar het is het dagelijkse vakmanschap van onderhoudbare code: namen die eerlijk blijven, opmaak die de lezer leidt en control flow die nooit mentale gymnastiek vereist.
Kernighan’s helderheidsstijl komt het meest naar voren in hoe je werk opsplitst in functies en modules. Een lezer moet in staat zijn om de structuur te scannen, te raden wat elk onderdeel doet en meestal meteen al grotendeels juist zitten voordat hij de details leest.
Streef naar functies die precies één ding doen op één “zoomniveau”. Wanneer een functie validatie, businessregels, opmaak en I/O mengt, moet de lezer meerdere draden in zijn hoofd houden.
Een snelle test: als je comments schrijft zoals “// now do X” binnen een functie, is X vaak een goede kandidaat voor een aparte functie met een duidelijke naam.
Lange parameterlijsten zijn een verborgen complexiteitstaks: elk call site wordt een mini-configuratiebestand.
Als meerdere parameters altijd samen reizen, groepeer ze verstandig. Opties-objecten (of kleine datastructuren) kunnen call sites zelfverklarend maken—als je de groep coherent houdt en voorkomt dat je alles in één “misc” zak stopt.
Geef ook de voorkeur aan het doorgeven van domeinconcepten boven primitieve types. UserId is beter dan string, en DateRange is beter dan (start, end) wanneer die waarden regels hebben.
Modules zijn beloften: “Alles wat je nodig hebt voor dit concept zit hier, en de rest is elders.” Houd modules klein genoeg zodat je hun doel in je hoofd kunt houden en ontwerp grenzen die bijwerkingen minimaliseren.
Praktische gewoonten die helpen:
Wanneer je gedeelde staat nodig hebt, benoem die eerlijk en documenteer de invarianties. Duidelijkheid gaat niet over het vermijden van complexiteit—het gaat over het plaatsen ervan waar lezers het verwachten. Voor meer over het behouden van deze grenzen tijdens wijzigingen, zie /blog/refactoring-as-a-habit.
Kernighan’s “smaak” blijkt uit hoe je commentarieert: het doel is niet om elke regel te annoteren, maar om toekomstige verwarring te verminderen. De beste comment is degene die een verkeerde aanname voorkomt—vooral wanneer de code wel correct is maar verrassend.
Een comment die de code herhaalt (“increment i”) voegt rommel toe en leert lezers comments te negeren. Nuttige comments leggen intentie, afwegingen of beperkingen uit die niet duidelijk uit de syntaxis blijken.
# Bad: says what the code already says
retry_count += 1
# Good: explains why the retry is bounded
retry_count += 1 # Avoids throttling bans on repeated failures
Als je de neiging hebt om “wat”-comments te schrijven, is dat vaak een teken dat de code duidelijker moet (betere namen, kleinere functie, eenvoudigere control flow). Laat de code de feiten dragen; laat comments de redenering dragen.
Niets ondermijnt vertrouwen sneller dan een verouderde comment. Als een comment optioneel is, zal hij na verloop van tijd afdwalen; als hij onjuist is, wordt het een actieve bron van bugs.
Een praktische gewoonte: behandel comment-updates als onderdeel van de verandering, niet als “leuk om te hebben.” Tijdens reviews is het fair om te vragen: Komt deze comment nog overeen met het gedrag? Zo niet, update of verwijder hem. “Geen comment” is beter dan “verkeerde comment.”
Inline-comments zijn voor lokale verrassingen. Breder advies hoort in docstrings, READMEs of ontwikkelaarsnotities—vooral voor:
Een goede docstring vertelt iemand hoe de functie correct te gebruiken en welke fouten te verwachten zijn, zonder de implementatie te vertellen. Een korte /docs of /README-opmerking kan het “waarom we het zo deden”-verhaal vastleggen zodat het refactors overleeft.
De stille winst: minder comments, maar elke comment verdient zijn plek.
De meeste code ziet er “prima” uit op het happy path. De echte test van smaak is wat er gebeurt wanneer inputs ontbreken, services timeouts krijgen of een gebruiker iets onverwachts doet. Onder stress verbergt slimme code vaak de waarheid. Duidelijke code maakt falen zichtbaar—en herstelbaar.
Foutmeldingen zijn onderdeel van je product en je debugworkflow. Schrijf ze alsof de volgende persoon die ze leest moe is en on-call.
Neem op:
Als je logging hebt, voeg gestructureerde context toe (zoals requestId, userId of invoiceId) zodat het bericht actiegericht is zonder in ongerelateerde data te hoeven graven.
Er is de verleiding om “alles af te handelen” met een slimme één-liner of een generieke catch-all. Goede smaak is het kiezen van de paar randgevallen die ertoe doen en ze zichtbaar maken.
Bijvoorbeeld: een expliciete tak voor “lege input” of “niet gevonden” leest vaak beter dan een keten van transformaties die ergens impliciet null produceren. Als een speciale case belangrijk is, noem hem en zet hem vooraan.
Het mixen van returnvormen (soms een object, soms een string, soms false) dwingt lezers een mentale beslisboom te houden. Geef de voorkeur aan patronen die consistent blijven:
Duidelijke foutafhandeling vermindert verrassingen—en verrassingen zijn waar bugs en nachtelijke pages floreren.
Duidelijkheid gaat niet alleen over wat jij bedoelde toen je de code schreef. Het gaat over wat de volgende persoon verwacht te zien als hij om 16:55 een bestand opent. Consistentie verandert “code lezen” in patroonherkenning—minder verrassingen, minder misverstanden, minder discussies die elke sprint terugkomen.
Een goede teamstijlrichtlijn is kort, specifiek en pragmatisch. Hij probeert niet elke voorkeur te coderen; hij legt terugkerende vragen vast: naamgevingsconventies, bestandsstructuur, foutafhandelingspatronen en wat “klaar” betekent voor tests.
De echte waarde is sociaal: het voorkomt dat dezelfde discussie bij elke nieuwe pull request opnieuw begint. Als iets op papier staat, verschuiven reviews van “ik geef de voorkeur aan X” naar “we hebben X afgesproken (en dit is waarom).” Houd het levend en makkelijk te vinden—veel teams pinnen het in de repo (bijvoorbeeld, /docs/style-guide.md) zodat het dicht bij de code staat.
Gebruik formatters en linters voor alles wat meetbaar en saai is:
Dit geeft mensen ruimte om zich te richten op betekenis: naamgeving, API-vorm, randgevallen en of de code overeenkomt met de intentie.
Handmatige regels blijven belangrijk wanneer ze ontwerpkeuzes beschrijven—bijvoorbeeld “geef voorkeur aan early returns om nesting te verminderen” of “één publieke entrypoint per module.” Tools kunnen die niet volledig beoordelen.
Soms is complexiteit gerechtvaardigd: strakke prestatiebudgetten, embedded beperkingen, lastige concurrency of platform-specifiek gedrag. De afspraak moet zijn: uitzonderingen zijn toegestaan, maar expliciet.
Een eenvoudige standaard helpt: documenteer de afweging in een korte comment, voeg een micro-benchmark of meting toe wanneer prestaties worden aangehaald, en isoleer de complexe code achter een duidelijke interface zodat het grootste deel van de codebase leesbaar blijft.
Een goede code review moet minder voelen als inspectie en meer als een korte, gerichte les in “goede smaak.” Kernighan’s punt is niet dat slimme code slecht is—het is dat slimheid duur is wanneer anderen ermee moeten leven. Reviews zijn waar teams die afweging zichtbaar kunnen maken en bewust voor duidelijkheid kiezen.
Begin met de vraag: “Kan een teamgenoot dit in één keer begrijpen?” Dat betekent meestal kijken naar naamgeving, structuur, tests en gedrag voordat je in micro-optimalisaties duikt.
Als de code correct is maar moeilijk te lezen, behandel leesbaarheid als een echte fout. Stel voor variabelen te hernoemen om intentie weer te geven, lange functies op te splitsen, control flow te vereenvoudigen of een kleine test toe te voegen die het verwachte gedrag aantoont. Een review die vangt “dit werkt, maar ik snap niet waarom” voorkomt weken van toekomstige verwarring.
Een praktische volgorde die goed werkt:
Reviews slaan vaak de plank mis als feedback als punten telling wordt gebracht. In plaats van “Waarom zou je dit doen?” probeer:
Vragen nodigen uit tot samenwerking en brengen vaak beperkingen aan het licht die je niet kende. Suggesties geven richting zonder incompetentie te impliceren. Deze toon is hoe “smaak” zich over een team verspreidt.
Als je consistente leesbaarheid wilt, vertrouw dan niet op de bui van de reviewer. Voeg een paar “duidelijkheidschecks” toe aan je reviewtemplate en definitie van klaar. Houd ze kort en specifiek:
Na verloop van tijd verandert dit reviews van politiewerk in het onderwijzen van oordeel—precies de dagelijkse discipline waar Kernighan voor pleitte.
LLM-tools kunnen snel werkende code produceren, maar “werkt” is niet de lat waar Kernighan het over had—communiceert is dat wel. Als je team een vibe-coding workflow gebruikt (bijvoorbeeld features bouwen via chat en itereren op gegenereerde code), is het de moeite waard om leesbaarheid als acceptatiecriterium te behandelen.
Op platforms zoals Koder.ai, waar je React-frontends, Go-backends en Flutter-mobile-apps kunt genereren vanuit een chatprompt (en de broncode daarna kunt exporteren), gelden dezelfde smaakgedreven gewoonten:
Snelheid is het meest waardevol wanneer de output nog steeds makkelijk voor mensen te reviewen, onderhouden en uitbreiden is.
Duidelijkheid is geen eindpunt dat je één keer bereikt. Code blijft leesbaar alleen als je hem voortdurend terugduwt naar gewone taal naarmate eisen veranderen. Kernighan’s gevoeligheid past hier: geef de voorkeur aan gestage, begrijpelijke verbeteringen boven heroïsche rewrites of slimme één-liners die vandaag imponeren en volgende maand verwarren.
De veiligste refactor is saai: kleine wijzigingen die het gedrag identiek houden. Als je tests hebt, run ze na elke stap. Als je ze niet hebt, voeg dan een paar gerichte checks toe rond het gebied waar je aan werkt—zie ze als tijdelijke vangrails zodat je structuur kunt verbeteren zonder angst.
Een praktisch ritme:
Kleine commits maken code review ook makkelijker: teamgenoten kunnen intentie beoordelen, niet naar bijeffecten zoeken.
Je hoeft niet elke “slimme” constructie in één keer te verwijderen. Terwijl je code aanraakt voor een feature of bugfix, ruil je slimme shortcuts in voor eenvoudige equivalenten:
Zo wint duidelijkheid in echte teams: één hotspot tegelijk, precies waar mensen al aan werken.
Niet alle cleanup is urgent. Een nuttige regel: refactor nu wanneer de code actief verandert, vaak verkeerd begrepen wordt of waarschijnlijk bugs veroorzaakt. Plan later wanneer het stabiel en geïsoleerd is.
Maak refactor-debt zichtbaar: laat een korte TODO met context achter, of voeg een ticket toe dat de pijn beschrijft (“moeilijk om nieuwe betaalmethoden toe te voegen; functie doet 5 taken”). Dan kun je er doelbewust over beslissen—in plaats van dat verwarrende code stilletjes de permanente belasting van het team wordt.
Als je wilt dat “goede smaak” consequent zichtbaar is, maak het dan makkelijk om te oefenen. Hier is een lichte checklist die je kunt hergebruiken bij planning, coderen en review—kort genoeg om te onthouden, specifiek genoeg om op te treden.
Voor: process(data) doet validatie, parsen, opslaan en logging op één plek.
Na: Splits in validateInput, parseOrder, saveOrder, logResult. De hoofdfunctie wordt een leesbare outline.
Voor: if not valid then return false herhaald vijf keer.
Na: Eén upfront guardsectie (of één validatiefunctie) die een duidelijke lijst met problemen teruggeeft.
Voor: x, tmp, flag2, doThing().
Na: retryCount, draftInvoice, isEligibleForRefund, sendReminderEmail().
Voor: Een loop met drie special cases verborgen in het midden.
Na: Handel special cases eerst af (of extraheer helpers), en voer dan de eenvoudige loop uit.
Kies één verbetering om deze week te adopteren: “geen nieuwe afkortingen”, “happy path eerst”, “extraheer één helper per PR” of “elke foutmelding bevat een vervolgstap”. Houd het zeven dagen bij en behoud wat daadwerkelijk lezen makkelijker maakte.
Kernighan’s invloed gaat minder over C en meer over een duurzaam principe: code is een communicatiemiddel.
Talen en frameworks veranderen, maar teams hebben nog steeds code nodig die makkelijk te scannen, te begrijpen, te reviewen en te debuggen is—vooral maanden later en onder tijdsdruk.
“Goede smaak” betekent consequent kiezen voor de eenvoudigste duidelijke optie die de intentie communiceert.
Een handige test is: kan een teamgenoot beantwoorden “wat doet dit en waarom is het zo gedaan?” zonder moeilijke trucs te ontcijferen of te steunen op verborgen aannames.
Omdat de meeste code veel vaker gelezen dan geschreven wordt.
Optimaliseren voor lezers vermindert onboardingtijd, reviewwrijving en het risico op foutieve wijzigingen—vooral wanneer de onderhoudende persoon “toekomstig jij” is met minder context.
De “slimheidstaks” komt neer op:
Als de slimme versie nu seconden bespaart maar elke keer minuten kost als er aan gewerkt wordt, is dat netto verlies.
Veelvoorkomende boosdoeners zijn:
Deze patronen verbergen tussenliggende staat en maken het makkelijker om randgevallen in reviews over het hoofd te zien.
Wanneer het de cognitieve last vermindert.
Stappen expliciet maken met benoemde variabelen (bijv. validate → normalize → compute) kan de juistheid makkelijker verifiëren, debuggen vereenvoudigen en toekomstige wijzigingen veiliger maken—zelfs als het een paar regels extra toevoegt.
Streef naar:
invoiceTotalCents in plaats van sum)Als je een naam moet ontcijferen, vervult die zijn taak niet; de naam moet de noodzaak van extra commentaar verminderen.
Geef de voorkeur aan eenvoudige, expliciete branching en houd het “happy path” zichtbaar.
Gebruikpraktijken die meestal helpen:
Commentaar over het waarom, niet het wat.
Goede comments leggen intentie, afwegingen of niet-voor-de-hand-liggende invarianties uit. Vermijd het omschrijven van voor de hand liggende code en beschouw het bijwerken van comments als onderdeel van de verandering—verouderde comments zijn slechter dan geen comments.
Gebruik tools voor mechanische regels (formattering, imports, eenvoudige voetangels) en laat mensen oordelen over betekenis.
Een compacte stijlrichtlijn helpt door terugkerende beslissingen vast te leggen (naamgeving, structuur, foutafhandelingspatronen) zodat reviews over helderheid en gedrag gaan, niet over persoonlijke voorkeur.
Als je uitzonderingen maakt voor prestaties of beperkingen, documenteer de afweging en isoleer complexiteit achter een duidelijke interface.