Warum „Why Not“-Kommentare nötig sind
(buttondown.com)- Kommentare können menschliche Sprache verwenden, die ausdrucksstärker ist als Bezeichner, und eignen sich daher gut dazu, im Code nicht umgesetzte Optionen und verworfene Alternativen festzuhalten
- „comment the why, not the what“ ist ein Ansatz, möglichst viele Informationen in Bezeichner zu packen, doch in letzter Zeit gibt es auch die Tendenz, sogar Gründe in lange Funktionsnamen oder Testnamen zu verlagern
- Im epub-Build von
Logic for Programmerswurde eine langsame Implementierung verwendet, die 16 mathematische Symbole in jedem String nacheinander ersetzt, aber derzeit gibt es nur 25 mathematische Strings, daher ist sie schnell genug - Solche Kommentare zeigen später, wo man etwas ändern muss, wenn die Zahl mathematischer Strings auf Hunderte anwächst und ein Build-Flaschenhals entsteht, und halten fest, dass der langsame Code ein bewusster Trade-off war
- Funktionsnamen oder Tests haften an dem, was der Code tatsächlich tut; deshalb ist negative Information über nicht gewählte Alternativen und nicht getane Dinge schwer selbstdokumentierend auszudrücken
Informationen, die sich in Kommentaren leichter festhalten lassen als im Code
- Code ist eine strukturierte Maschinensprache, Kommentare werden in ausdrucksstarker menschlicher Sprache geschrieben
- „comment the why, not the what“ kann so verstanden werden, dass möglichst viele Informationen in Bezeichner gepackt werden sollen
- Bezeichner sind eher eine begrenzte Form menschlicher Sprache innerhalb des Codes; sie können nicht jedes „what“ ausdrücken, aber oft doch sehr viel
- In letzter Zeit nimmt die Ansicht zu, dass auch das „why“ nicht in Kommentare, sondern in lange Funktionsnamen oder Testfallnamen aufgenommen werden kann
- Selbstdokumentierende Codebases erweitern ihre Dokumentation meist durch zusätzliche Bezeichner
- Als Ausnahme gibt es Fälle, in denen Kommentare in Logging umgewandelt werden, um den Code stärker selbstdokumentierend zu machen
Worum es bei „Why Not“-Kommentaren geht
- Informationen, die sich schwer im Code ausdrücken lassen, sind negative Informationen
- Negative Informationen lenken die Aufmerksamkeit darauf, was im System fehlt und warum bestimmte Alternativen nicht gewählt wurden
- „why not“ erklärt nicht in erster Linie, was der Code tut, sondern welche Optionen der Code nicht verfolgt und warum
Beispiel: Ersetzung mathematischer Symbole im epub
- Im epub-Build von
Logic for Programmerswurden mathematische Schreibweisen wie\\forallaus technischen Gründen nicht in Symbole wie∀umgewandelt - Um das zu beheben, wurde ein Skript geschrieben, das Tokens in mathematischen Strings direkt durch die entsprechenden Unicode-Symbole ersetzt
- Die einfachste Implementierung besteht darin, für jedes der benötigten 16 mathematischen Symbole
string = string.replace(old, new)aufzurufen - Diese Variante durchläuft jeden String 16-mal und ist daher ineffizient, aber ein Ansatz, der alle 16 Ersetzungen in einem Durchlauf erledigt, ist komplexer
- Der Kern des hinterlassenen Kommentars lautet:
- Jeder String wird 16-mal durchlaufen
- Im Buch gibt es derzeit nur 25 mathematische Strings, und die meisten sind kürzer als 5 Zeichen
- Deshalb ist es immer noch schnell genug
- Dieser Kommentar erklärt nicht nur „warum langsamer Code verwendet wird“, sondern auch „warum kein schnellerer Code verwendet wird“
Wegweiser für spätere Leser
- Langsamer Code kann später zum Problem werden, auch wenn er jetzt noch keines verursacht
- Wenn in einer zukünftigen Version von
Logic for Programmersdie Zahl mathematischer Strings auf Hunderte anwächst, könnte dieser Build-Schritt zum Flaschenhals des gesamten Builds werden - Wenn man jetzt einen Wegweiser hinterlässt, ist später sofort klar, welche Stelle angepasst werden muss
- Selbst wenn der Code weiterhin problemlos läuft, bewahrt der Kommentar die Tatsache, dass dem Autor der Trade-off bewusst war
- Wenn man
epub_math_fixer.pyin zwei Jahren erneut öffnet, muss man viel weniger nachforschen, ob der langsame Code auf Unerfahrenheit, Zeitmangel oder einen Fehler zurückging - Ein negativer Kommentar hält fest, dass die langsame Implementierung bekannt war, Alternativen geprüft wurden und bewusst auf Optimierung verzichtet wurde
Warum sich das schwer durch Funktionsnamen und Tests ersetzen lässt
- Ein Funktionsname wie
RunFewerTimesSlowerAndSimplerAlgorithmAfterConsideringTradeOffsist zu lang und erklärt den tatsächlichen Trade-off trotzdem nicht ausreichend - Wenn der Code später optimiert wird, muss dieser Name womöglich an vielen Stellen geändert werden
- Das größere Problem ist, dass ein solcher Name nicht vermittelt, was die Funktion tatsächlich tut, und damit die Selbstbeschreibung des Codes eher schwächt
- Bezeichner wie Funktions- und Variablennamen können nur eine einzige Informationseinheit tragen
- Es ist schwer, in einem einzelnen Bezeichner zugleich „was die Funktion tut“ und „welchen Trade-off sie in Kauf nimmt“ unterzubringen
Negative Informationen lassen sich auch in Tests nur schwer festhalten
- Man könnte einen Test schreiben, der per grep die Mathematikblöcke im Buch zählt und fehlschlägt, wenn es mehr als 80 gibt
- Ein solcher Test prüft jedoch
EpubMathFixerselbst nicht direkt - Innerhalb der Funktion gibt es keinen Punkt, an dem ein solcher Test ansetzen könnte
- Selbstdokumentation haftet am geschriebenen Code und erklärt, was der Code tut
- Negative Informationen betreffen gerade das, was der Code nicht tut, und passen daher grundsätzlich schlecht zum Prinzip der Selbstdokumentation
Die größere Frage
- „Why Not“-Kommentare lassen sich als ein Beispiel für Kontrafaktisches (counterfactual) verstehen
- Es bleibt die Frage, ob sich abstrakte Elemente menschlicher Kommunikation generell selbstdokumentierend ausdrücken lassen
- Ob sich auch Informationen wie Metaphern, Unsicherheit oder ethische Argumente selbstdokumentierend festhalten lassen, bleibt weiterhin offen
1 Kommentare
Meinungen auf Hacker News
Ich erinnere mich an einen Witz, den ich vor ein paar Jahren wohl auf Twitter gesehen habe: „Junior Engineers schreiben Kommentare, die erklären, was der Code tut; Mid-Level Engineers schreiben Kommentare, die erklären, warum der Code das tut; Senior Engineers schreiben Kommentare, die erklären, warum der Code nicht auf eine andere Weise geschrieben wurde“ – so in der Art
Umgekehrt habe ich auch schon recht große Funktionen ohne Kommentare geschrieben, wenn Funktions- und Variablennamen allein die Bedeutung klar machen konnten
Deshalb gewinnt die Seite mit weniger Kommentaren zwar, aber wenn man eine Codebasis ohne Kommentare sieht, muss man selbst nachsehen, ob es sich um ein schön geschliffenes Meisterwerk handelt oder um wackeligen Code von Anfängern
Auch wenn es wie ein kompletter Hack aussieht, ist das manchmal tatsächlich das Beste, was man erreichen kann
Alles, was mir hilfreich erscheint, wenn ich den Code in einem Jahr wieder ansehe, schreibe ich als Kommentar dazu. Meist geht es um das Warum und das Warum nicht; wenn der Code komplex ist, schreibe ich auch kurz das „Was“ auf, um den Ablauf besser sichtbar zu machen
Nicht hilfreich sind Pflichtkommentare. Öffentliche APIs sollten ausreichend dokumentiert sein, aber manche Organisationen erzwingen Kommentare sogar für jede private Funktion, sodass am Ende nur noch der Funktionsname wiederholt wird, weil der Zweck völlig offensichtlich ist. Das ist nicht nur Zeitverschwendung, sondern stumpft gegenüber Kommentaren ab und lehrt einen, sie zu ignorieren
Ich mag auch überflüssige Kommentare nicht, die Tools hinzufügen. Besonders unschön ist es, an jede Schleife
//foroder//tryzu hängenBesser wäre es, Pflicht- und generierte Kommentare zu entfernen und Kommentare in dunklen Themes in eine helle Neonfarbe zu ändern, damit sie auffallen. Wenn es einen Kommentar gibt, sollte das bedeuten, dass er wichtig ist
Wenn man in einem geschäftlichen Umfeld mit engen Zeitplänen ein großes Altsystem pflegt, muss man manchmal seltsame Dinge tun, und dann sollte man erklären, warum
Ein wichtiger Grund gegen Kommentare ist, dass Kommentare ebenfalls Teil des Codes werden und Wartung brauchen. Die meisten lesen Kommentare aber nur, wenn sie feststecken, und Editoren machen Kommentare grau und blass, sodass sie psychologisch fast unsichtbar werden. Deshalb veralten Kommentare leicht
Ich frage mich, ob Kontext für das „zukünftige Ich“ auch in einer gemeinsamen Codebasis nützlich ist, an der viele Entwickler arbeiten, oder ob das eher gut funktioniert, wenn nur wenige am Code arbeiten
Also fügte ich dem bestehenden Kommentar „=> yes!“ hinzu und war meinem früheren Ich dankbar, dass es diese Frage dokumentiert hatte. Bei der Arbeit hinterlasse ich besonders bei Bugfixes häufig ein oder zwei Kommentarzeilen mit einer Ticketnummer über Änderungen, die nicht offensichtlich sind
Das liebste Format unter den Kommentaren, die ich je in Code hinterlassen habe, ist dieses Template: „DEAR MAINTAINER: Dieser Code ist aus [Grund] so. Wenn Sie beim Versuch, ihn zu ‚reparieren‘, feststellen, dass das ein schrecklicher Fehler war, erhöhen Sie bitte als Warnung für die nächste Person den Zähler
total_hours_wasted_here = n“Ich bin nicht der ursprüngliche Autor, habe es aber ein-, zweimal dankbar verwendet, und es war amüsant, Commits mit nur einer Zeile zu sehen, die nur den Zähler erhöhen
Ein erfahrenerer Engineer übernahm die Codebasis und „reparierte“ alles in eine schleifenbasierte Variante. Er wollte mich per E-Mail darüber belehren, warum Rekursion schlecht sei, aber sein Code erfüllte die tatsächlichen Anforderungen nicht vollständig und am Ende baute er im Grunde wieder das nach, was ich mit Rekursion gemacht hatte
Später entschuldigte er sich zwar für einige seiner Aussagen, aber wenn ich ganz oben so einen Kommentar hinterlassen hätte, hätte man die ganze Sache vielleicht vermeiden können
Ich stimme zu, dass der Titel mehrdeutig ist, und genau deshalb habe ich den Artikel gelesen. Persönlich bevorzuge ich insgesamt eher wenige Kommentare, aber die im Text erwähnten erklärenden Kommentare haben eindeutig Wert. Es ist eine gute Erinnerung, zu erklären, warum man etwas so gemacht hat und warum nicht anders
Das gilt besonders für eigenen Code, der auch noch in 5, 10 oder 15 Jahren gewartet werden muss. Kürzlich reviewte ich neuen Code eines Kollegen und dachte: „Warum hat er das so gemacht?“ Zehn Zeilen darüber stand der Grund, warum ich es vor acht Jahren genauso gemacht hatte. Der Kollege hatte die wichtigste Regel der Wartung befolgt: es wie den bestehenden Code aussehen zu lassen
Es ist nur ein Spezialfall eines allgemeineren Prinzips: Kommentiere das, was beim Lesen des Codes überraschend ist.
Wer beim Schreiben von Code im Kopf ständig fragt: „Werde ich diesen Code später verstehen können?“, und jedes Mal instinktiv mit „ja“ antwortet, ist überheblich und liegt oft falsch. Wenn die Antwort „nicht sicher“ lautet, ist die nächste Frage ganz natürlich „warum?“, und die Antwort darauf gehört in den Kommentar.
Manchmal lautet die Antwort: „weil sich Lesende fragen könnten, warum es nicht anders geschrieben wurde“, und das ist der Spezialfall, um den es in diesem Text geht. Manchmal aber auch: „weil nicht klar ist, wie es funktioniert oder warum es korrekt ist“; dann braucht es eine andere Art von Kommentar.
Das passiert vor allem, wenn Strings zugeschnitten werden oder man sich als Zwischenschritt durch ungewöhnliche Datenstrukturen hangelt.
Mit Bezeichnern allein kommt man sehr weit, aber nicht bis ganz ans Ende. Persönlich mag ich es, für öffentliche Methoden sowie Variablen, Felder und Parameter Dokumentationskommentare wie jsdoc/xmldoc zu verlangen.
Gute Methodennamen zu wählen ist wichtig, aber kurz aufzuschreiben, was sie tun, macht es noch klarer und legt insbesondere offensichtliche Schwächen frei. Oft fällt einem in dem Moment, in dem man den ersten Satz schreibt, ein besserer Name ein; und wenn in der Beschreibung „und“ aufzutauchen beginnt, ist das ein Zeichen dafür, dass die Methode zu viel tut und logischer aufgeteilt werden kann.
Bei Eigenschaften denkt man leicht, sie seien so eindeutig, dass keine Dokumentation nötig sei, aber
/** The API key */ string ApiKey;lässt viel zu viel offen. Man weiß nicht, woher dieser Schlüssel kommt, ob er nur intern ist oder mit externen Systemen ausgetauscht wird, ob er Pflicht ist, ob null oder leere Werte möglich sind, ob es eine maximale Länge gibt, was bei einem ungültigen Wert passiert oder ob es weiterführenden Code oder Dokumentation dazu gibt.Für die ursprüngliche Autorin oder den ursprünglichen Autor sind das Informationen, die sich in 1–2 Minuten aufschreiben lassen; für eine neue Person kann es Stunden dauern, sie herauszufinden, wenn sie den Code ändert, verwendet oder Jahre später zur Behebung eines Bugs hinzugezogen wird.
Wenn ich im Code-Review vorhersehen kann, was ein übermäßig pingeliger Reviewer bemängeln wird, schreibe ich oft Kommentare wie „X wurde wegen Y nicht gemacht“. Ziel ist es, lästige Hin-und-her-Diskussionen zu reduzieren.
Für Kommentare wie „Wir laufen 16-mal über jeden String, aber im Buch gibt es bisher nur 25 Formel-Strings und die meisten sind kürzer als 5 Zeichen, also ist es schnell genug“ gibt es auch eine andere Variante:
Man baut ein Debug-Log ein, das auslöst, wenn die Eingabe deutlich größer wird als durch die ursprünglichen Designannahmen vorgesehen. Es vermittelt künftigen Entwicklerinnen und Entwicklern fast dieselbe Botschaft, wird aber früher entdeckt und kann Diagnose- und Debugging-Zeit weiter reduzieren.
In einem idealen Logging- und Observability-System würde man die Zeit aller Komponenten der App messen und häufig Debug-Informationen hinterlassen, aber wer nutzt so ein perfektes System schon wirklich? Wichtiger ist es, gezielt Logs an Stellen einzubauen, an denen die Performance später schlechter werden könnte oder für die keine Zeit zur Optimierung war.
Rückblickend ist das eine offensichtliche Idee, aber bisher lief es eher darauf hinaus, Kommentare an Stellen zu hinterlassen, die man später noch einmal ansehen sollte, und zu hoffen, dass man sich an diese Kommentare erinnert, wenn es schlechter wird.
Egal, was andere sagen: Ich schreibe an vielen Stellen im Code Kommentare und Dokumentationskommentare. Allerdings gehe ich umgekehrt vor: Ich schreibe zuerst grob die Liste der Schritte der Anwendung als Kommentare auf, zerlege dann während der Entwicklung große Schritte in kleinere, lösche ursprüngliche Kommentare oder lasse sie stehen und verfeinere die Kommentare, bis daraus ein nahezu fertiger Algorithmus wird.
Da man normalerweise von außen nach innen codet, schreibe ich während des Aufteilens der Kommentare auch gleich Code dazu. Manchmal code ich auch in einem Rutsch und kommentiere später so ausführlich, dass die meisten es lästig fänden. Ich versehe jede Funktion und jede Variable mit einer Erklärung und schreibe sogar bei der Funktion
deg_to_rad"""Converts degrees to radians."""dazu. Speicherplatz ist billig.Ich weiß, dass die meisten das nicht mögen, aber das ist okay. Wenn es stört, kann man es per Skript entfernen oder im Code Review rausnehmen. Trotzdem macht es mir viel mehr Freude, meinen alten Code zu lesen als fremden Code ohne Kommentare. In Python ist einfacher Boilerplate-Code wie eine Flask-API meist selbstdokumentierend, aber gerade solcher Boilerplate ändert sich oft und bekommt deshalb wichtige Kommentare. In der Branche werden Algorithmen dagegen häufiger komplett neu geschrieben.
Ich werde Kommentare und Dokumentationskommentare auch weiterhin mögen.
Ich mag es, das Gesamtkonzept im Kopf zu entwickeln, und finde es anfangs langsam, verschiedene Designoptionen tatsächlich auszuprobieren. Sobald also eine Designentscheidung feststeht, muss sie unbedingt dokumentiert werden. Andere können schließlich noch nicht in meinen Kopf schauen.
Bei Details erwarte ich, dass sie klarer werden, sobald andere die Konzeptualisierung abgeschlossen haben. Wenn diese Konzeptualisierung aus irgendeinem Grund aber nicht gelingt, kann es schwerer lesbar werden; deshalb feile ich zusätzlich nach, um zumindest eine grundlegende Lesbarkeit zu erhalten.
Kommentare zu aktualisieren ist oft genauso Arbeit wie den Code zu ändern. Deshalb sind Kommentare in der Praxis meist etwas, das darauf wartet, zur Lüge zu werden. Irgendwann laufen Kommentar und Code auseinander, und das kann schlimmer sein als Code ohne Kommentare.
Besser sind automatisierte Tests, die die Absicht zeigen. Tests können im Allgemeinen nicht lügen, denn sonst wären sie nicht gemergt worden. Wenn es eine ordentliche Testsammlung gibt, die zeigt, wie der Code verwendet werden soll, dann möchte ich die sehen: Sie ist erklärend und ihre Wahrheit ist nahezu garantiert.
Das hilft enorm, wenn ich fünf Wochen später wieder draufschauen muss.
Ich folge dem Konzept: „Kommentare sind eine Entschuldigung an mein zukünftiges Ich.“
Wenn Code merkwürdig oder langsam ist oder wenn ich ihn jemandem erklären würde mit „ist ein bisschen unsauber“, hinterlasse ich meist einen Kommentar. Besonders dann, wenn ich etwas schon einmal geändert habe, dokumentiere ich, welche Fälle nicht funktioniert haben oder was behoben wurde.
Mit diesem Maßstab verschwinden unnötige Kommentare ganz von selbst, und meist dokumentiert man nur dann das Warum, wenn es wirklich nötig ist. Wenn man das in der eigenen Codebasis etwa einen Monat lang ausprobiert, bekommt man ein Gefühl dafür.