Was stimmt nicht mit Kommentaren, die komplexen Code erklären?

236

Viele Leute behaupten, "Kommentare sollten erklären, warum, aber nicht wie". Andere sagen, "Code sollte sich selbst dokumentieren" und Kommentare sollten knapp sein. Robert C. Martin behauptet, dass (in meinen eigenen Worten umformuliert) Kommentare häufig "Entschuldigungen für schlecht geschriebenen Code" sind.

Meine Frage lautet wie folgt:

Was ist falsch daran, einen komplexen Algorithmus oder ein langes und verschlungenes Stück Code mit einem beschreibenden Kommentar zu erklären?

Auf diese Weise müssen andere Entwickler (einschließlich Sie selbst) nicht den gesamten Algorithmus Zeile für Zeile lesen, um herauszufinden, was er tut, sondern können einfach den benutzerfreundlichen beschreibenden Kommentar lesen, den Sie im Klartext geschrieben haben.

Englisch ist so konzipiert, dass es von Menschen leicht verstanden werden kann. Java, Ruby oder Perl wurden jedoch entwickelt, um die Lesbarkeit von Menschen und die Lesbarkeit von Computern in Einklang zu bringen und so die Lesbarkeit des Textes zu beeinträchtigen. Ein Mensch kann ein Stück Englisch viel schneller verstehen als ein Stück Code mit der gleichen Bedeutung (solange die Operation nicht trivial ist).

Fügen Sie nach dem Schreiben eines komplexen Codeteils in einer teilweise für Menschen lesbaren Programmiersprache einen beschreibenden und präzisen Kommentar hinzu, der die Funktionsweise des Codes in freundlichem und verständlichem Englisch erklärt.

Einige werden sagen "Code sollte nicht schwer zu verstehen sein", "Funktionen klein machen", "beschreibende Namen verwenden", "Spaghetti-Code nicht schreiben".

Aber wir alle wissen, dass das nicht ausreicht. Dies sind nur Richtlinien - wichtige und nützliche -, aber sie ändern nichts an der Tatsache, dass einige Algorithmen komplex sind. Und sind deshalb schwer zu verstehen, wenn man sie Zeile für Zeile liest.

Ist es wirklich so schlecht, einen komplexen Algorithmus mit ein paar Zeilen Kommentaren zur allgemeinen Funktionsweise zu erklären? Was ist falsch daran, komplizierten Code mit einem Kommentar zu erklären?

Aviv Cohn
quelle
14
Wenn es so verworren ist, versuchen Sie, es in kleinere Teile umzugestalten.
Vaughan Hilts
151
In der Theorie gibt es keinen Unterschied zwischen Theorie und Praxis. In der Praxis gibt es.
Scott Leadley
5
@mattnz: Direkter gesagt, wenn Sie den Kommentar schreiben, stecken Sie in dem Problem, das dieser Code löst. Bei Ihrem nächsten Besuch werden Sie mit diesem Problem weniger vertraut sein .
Steve Jessop
26
"Was" die Funktion oder Methode tut, sollte aus ihrem Namen ersichtlich sein. Wie es funktioniert, geht aus seinem Code hervor. Warum es so gemacht wird, welche impliziten Annahmen verwendet wurden, welche Papiere man lesen muss, um den Algorithmus zu verstehen, etc. - sollte in Kommentaren stehen.
SK-logic
11
Ich bin der Meinung, dass viele der folgenden Antworten Ihre Frage absichtlich falsch interpretieren. Es ist nichts Falsches daran, deinen Code zu kommentieren. Wenn Sie das Gefühl haben, einen erläuternden Kommentar schreiben zu müssen, müssen Sie dies tun.
Tony Ennis

Antworten:

408

In den Begriffen des Laien:

  • Es ist nichts Falsches an den Kommentaren an sich. Was falsch ist, ist das Schreiben von Code, der diese Art von Kommentaren benötigt, oder die Annahme, dass es in Ordnung ist, verschachtelten Code zu schreiben, solange Sie ihn im Klartext erklären.
  • Kommentare werden nicht automatisch aktualisiert, wenn Sie den Code ändern. Das ist der Grund, warum Kommentare häufig nicht mit dem Code synchronisiert sind.
  • Kommentare erleichtern das Testen von Code nicht.
  • Entschuldigung ist nicht schlecht. Was Sie getan haben, für das Sie sich entschuldigen müssen (das Schreiben von Code, der nicht leicht zu verstehen ist), ist schlecht.
  • Ein Programmierer, der in der Lage ist, einfachen Code zu schreiben, um ein komplexes Problem zu lösen, ist besser als einer, der komplexen Code schreibt und dann einen langen Kommentar schreibt, der erklärt, was sein Code tut.

Endeffekt:

Sich selbst zu erklären ist gut, es ist besser, es nicht zu brauchen.

Tulains Córdova
quelle
91
Es ist häufig unmöglich zu rechtfertigen, dass das Geld des Arbeitgebers für das Umschreiben des Codes selbsterklärender ist, wenn ein guter Kommentar die Arbeit in viel kürzerer Zeit erledigen kann. Ein pflichtbewusster Programmierer muss jedes Mal sein Urteilsvermögen einsetzen.
Aecolley
34
@aecolley Es ist noch besser, zunächst selbsterklärenden Code zu schreiben.
Tulains Córdova
127
Manchmal ist selbsterklärender Code nicht effizient genug, um ein Problem mit der heutigen HW & SW zu lösen. Und Geschäftslogik ist notorisch ... verdreht. Die Teilmenge der Probleme mit eleganten Softwarelösungen ist erheblich kleiner als die Menge der Probleme, deren Lösung wirtschaftlich sinnvoll ist.
Scott Leadley
62
@rwong: Umgekehrt finde ich es oft so, dass ich mehr Kommentare in die Geschäftslogik schreibe, weil es wichtig ist, genau zu zeigen, wie der Code mit den angegebenen Anforderungen übereinstimmt: "Dies ist die Zeile, die verhindert, dass wir alle für Drahtbetrug im Abschnitt Was auch immer ins Gefängnis kommen das Strafgesetzbuch ". Wenn es sich nur um einen Algorithmus handelt, kann ein Programmierer den Zweck bei Bedarf von Grund auf ermitteln. Für die Geschäftslogik benötigen Sie einen Anwalt und den Mandanten zur selben Zeit im selben Raum. Möglicherweise ist mein "gesunder Menschenverstand" in einer anderen Domäne als der eines durchschnittlichen App-Programmierers ;-)
Steve Jessop
29
@ user61852 Abgesehen davon, dass das, was für Sie selbsterklärend ist, der gerade diesen Code geschrieben hat und die letzte $ -Periode damit verbracht hat, für Sie, die ihn in fünf Jahren warten oder bearbeiten müssen, möglicherweise nicht selbsterklärend ist, geschweige denn alles Mögliche Leute, die Sie nicht sind, die es vielleicht ansehen müssen. "Selbsterklärend" ist ein nebulöser heiliger Gral von Definitionen.
Shadur
110

Es gibt verschiedene Gründe, warum Code kompliziert oder verwirrend ist. Die häufigsten Gründe lassen sich am besten beheben, indem Sie den Code überarbeiten, um ihn weniger verwirrend zu machen, und keine Kommentare hinzufügen.

Es gibt jedoch Fälle, in denen ein ausgewählter Kommentar die beste Wahl ist.

  • Wenn es der Algorithmus selbst ist, der kompliziert und verwirrend ist, und nicht nur seine Implementierung - die Art, die in mathematischen Fachzeitschriften geschrieben wird und immer als Mbogos Algorithmus bezeichnet wird -, dann setzen Sie einen Kommentar ganz am Anfang der Implementierung so etwas wie "Dies ist Mbogos Algorithmus zum Auffrischen von Widgets, der ursprünglich hier beschrieben wurde: [URL of Paper]. Diese Implementierung enthält Verfeinerungen von Alice und Carol [URL eines anderen Papiers]." Versuchen Sie nicht, detaillierter darauf einzugehen. Wenn jemand mehr Details benötigt, muss er wahrscheinlich die gesamte Zeitung lesen.

  • Wenn Sie etwas, das als eine oder zwei Zeilen in einer speziellen Notation geschrieben werden kann, zu einem großen Globus imperativen Codes erweitert haben, ist es eine gute Möglichkeit, diese eine oder zwei Zeilen in einen Kommentar über der Funktion einzufügen sagen dem Leser , was es soll tun. Dies ist eine Ausnahme vom Argument "Aber was ist, wenn der Kommentar nicht mehr mit dem Code synchron ist?", Da die spezialisierte Notation wahrscheinlich viel einfacher zu finden ist als der Code. (Wenn Sie eine Spezifikation stattdessen in Englisch verfasst haben, ist dies umgekehrt.) Ein gutes Beispiel ist hier: https://dxr.mozilla.org/mozilla-central/source/layout/style/nsCSSScanner.cpp#1057 ...

    /**
     * Scan a unicode-range token.  These match the regular expression
     *
     *     u\+[0-9a-f?]{1,6}(-[0-9a-f]{1,6})?
     *
     * However, some such tokens are "invalid".  There are three valid forms:
     *
     *     u+[0-9a-f]{x}              1 <= x <= 6
     *     u+[0-9a-f]{x}\?{y}         1 <= x+y <= 6
     *     u+[0-9a-f]{x}-[0-9a-f]{y}  1 <= x <= 6, 1 <= y <= 6
    
  • Wenn der Code insgesamt unkompliziert ist, aber ein oder zwei Dinge enthält, die übermäßig verwickelt, unnötig oder einfach falsch aussehen , aber aus Gründen so sein müssen, setzen Sie einen Kommentar direkt über das verdächtig aussehende Bit, in das Sie geben die Gründe an . Hier ist ein einfaches Beispiel, in dem nur erklärt werden muss, warum eine Konstante einen bestimmten Wert hat.

    /* s1*s2 <= SIZE_MAX if s1 < K and s2 < K, where K = sqrt(SIZE_MAX+1) */
    const size_t MUL_NO_OVERFLOW = ((size_t)1) << (sizeof(size_t) * 4);
    if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
        nmemb > 0 && SIZE_MAX / nmemb < size)
      abort();
    
zwol
quelle
25
Das ist eine Empörung, 4sollte sein CHAR_BIT / 2;-)
Steve Jessop
@SteveJessop: Würde irgendetwas eine Implementierung ausschließen, bei CHAR_BITSder 16 und sizeof (size_t) 2 waren, aber der Maximalwert von size_t z. B. 2 ^ 20 [size_t mit 12 Füllbits] war?
Supercat
2
@supercat Ich sehe nichts , was offensichtlich , dass in C99 entgegensteht, was bedeutet , dass beispielsweise ist technisch falsch. Es stammt aus einer (leicht modifizierten) Version von OpenBSD reallocarray, und OpenBSD glaubt im Allgemeinen nicht daran, auf Möglichkeiten einzugehen, die in ihrer ABI nicht vorkommen.
zwol
3
@Zack: Wenn der Code auf POSIX-Annahmen basiert, kann die Verwendung von CHAR_BITS den Eindruck erwecken, dass der Code mit anderen Werten als 8
funktioniert
2
@Zack: Damit unsignierte Typen mit exakter Breite nützlich sind, müsste ihre Semantik unabhängig von der Größe von definiert werden int. Wie es gegeben ist, hängt uint32_t x,y,z;die Bedeutung von (x-y) > zvon der Größe von ab int. Eine Sprache, die für das Schreiben von robustem Code entwickelt wurde, sollte es Programmierern ermöglichen, zwischen einem Typ zu unterscheiden, bei dem zu erwarten ist, dass Berechnungen den Bereich des Typs überschreiten, und einem, bei dem Berechnungen, bei denen der Bereich des Typs überschritten werden, stillschweigend umbrochen werden sollen Es wird nicht erwartet, dass die Reichweite des Typs überschritten wird, aber ...
Supercat
61

Was ist also falsch daran, komplizierten Code mit einem Kommentar zu erklären?

Es geht nicht um richtig oder falsch, sondern um die "Best Practice", wie im Wikipedia-Artikel definiert :

Eine Best Practice ist eine Methode oder Technik, die durchweg bessere Ergebnisse erzielt als mit anderen Mitteln und die als Benchmark verwendet wird.

Die beste Vorgehensweise besteht darin, zuerst den Code zu verbessern und Englisch zu verwenden, wenn dies nicht möglich ist.

Es ist kein Gesetz, aber es ist weitaus üblicher, kommentierten Code zu finden, der umgestaltet werden muss, als umgestalteten Code, der Kommentare erfordert.

FMJaguar
quelle
42
+1 für "Es ist viel häufiger, kommentierten Code zu finden, der umgestaltet werden muss, als umgestalteten Code, der Kommentare erfordert"
Brandon
7
Okay, aber wie oft ist dieser Kommentar: //This code seriously needs a refactor
Erik Reppen
2
Selbstverständlich ist jede sogenannte Best Practice, die nicht durch eine strenge wissenschaftliche Studie untermauert wird, nur eine Meinung.
Blrfl
54

Es wird ein Tag kommen, an dem Ihr schöner, perfekt gestalteter, gut strukturierter und lesbarer Code nicht mehr funktioniert. Oder es wird nicht gut genug funktionieren. Oder es entsteht ein Sonderfall, in dem es nicht funktioniert und angepasst werden muss.

An diesem Punkt müssen Sie etwas tun, das die Dinge ändert, damit es richtig funktioniert. Insbesondere bei Leistungsproblemen, aber auch häufig in Szenarien, in denen sich eine der von Ihnen verwendeten Bibliotheken, APIs, Webdienste, Gems oder Betriebssysteme nicht wie erwartet verhält, können Sie Vorschläge machen, bei denen dies nicht der Fall ist notwendigerweise unelegant, aber kontraintuitiv oder nicht offensichtlich.

Wenn Sie keine Kommentare haben, um zu erklären, warum Sie diesen Ansatz gewählt haben, besteht eine sehr gute Chance, dass sich in Zukunft jemand (und möglicherweise sogar Sie) den Code ansieht und prüft, wie er "behoben" werden kann Etwas lesbareres und eleganteres, das versehentlich Ihre Korrektur rückgängig macht, weil es nicht wie eine Korrektur aussieht.

Wenn jeder immer perfekten Code geschrieben hätte, wäre es offensichtlich, dass Code, der unvollständig aussieht, um eine knifflige Intervention aus der realen Welt herumarbeitet, aber so funktionieren die Dinge nicht. Die meisten Programmierer schreiben oft verwirrenden oder etwas verworrenen Code. Wenn wir dem begegnen, ist es eine natürliche Neigung, ihn aufzuräumen. Ich schwöre, meine Vergangenheit ist ein wirklicher Idiot, wenn ich alten Code lese, den ich geschrieben habe.

Daher sehe ich Kommentare nicht als Entschuldigung für schlechten Code, sondern als Erklärung dafür, warum Sie das Offensichtliche nicht getan haben. Mit // The standard approach doesn't work against the 64 bit version of the Frobosticate Librarykönnen zukünftige Entwickler, einschließlich Ihres zukünftigen Selbst, auf diesen Teil des Codes achten und ihn mit dieser Bibliothek testen. Sicher, Sie können die Kommentare auch in Ihre Versionskontroll-Commits einfügen, aber die Leute werden sich diese erst ansehen, nachdem etwas schief gelaufen ist. Sie lesen Codekommentare, wenn sie den Code ändern.

Leute, die uns sagen, dass wir immer theoretisch perfekten Code schreiben sollten, sind nicht immer Leute mit viel Erfahrung im Programmieren in realen Umgebungen. Manchmal müssen Sie Code schreiben, der eine bestimmte Leistung erbringt, manchmal müssen Sie mit fehlerhaften Systemen zusammenarbeiten. Das bedeutet nicht, dass Sie dies nicht auf elegante und gut geschriebene Weise tun können, aber nicht offensichtliche Lösungen bedürfen einer Erklärung.

Wenn ich Code für Hobbyprojekte schreibe, von denen ich weiß, dass niemand sie jemals lesen wird, kommentiere ich immer noch Teile, die ich verwirrend finde - zum Beispiel beinhaltet jede 3D-Geometrie Mathematik, mit der ich nicht ganz zuhause bin -, weil ich weiß, wann ich zurückkomme In sechs Monaten werde ich völlig vergessen haben, wie man dieses Zeug macht. Das ist keine Entschuldigung für schlechten Code, sondern eine Anerkennung einer persönlichen Einschränkung. Alles, was ich tun würde, wenn ich es unkommentiert lassen würde, wäre, mir in Zukunft mehr Arbeit zu schaffen. Ich möchte nicht, dass mein zukünftiges Ich etwas unnötig neu lernen muss, wenn ich es jetzt vermeiden kann. Welchen möglichen Wert hätte das?

Glenatron
quelle
5
@Christian ist das? Die erste Zeile bezieht sich sicherlich auf diese Aussage, aber darüber hinaus ist sie, so wie ich sie verstehe, etwas weiter gefasst.
Glenatron
9
"Ich schwöre, meine Vergangenheit ist ein wirklicher Idiot, wenn ich alten Code lese, den ich geschrieben habe." Nach vier Jahren Entwicklungskarriere stelle ich fest, dass dies immer dann der Fall ist, wenn ich etwas über 6 Monate betrachte.
Ken
6
In vielen Fällen beziehen sich die informativsten und nützlichsten historischen Informationen auf Dinge, die erwogen, aber dagegen entschieden werden. In vielen Fällen wählt jemand Ansatz X für etwas und ein anderer Ansatz Y scheint besser zu sein. In einigen dieser Fälle wird Y "fast" besser funktionieren als X, es treten jedoch einige unüberwindbare Probleme auf. Wenn Y aufgrund dieser Probleme vermieden wurde, kann dieses Wissen dazu beitragen, dass andere ihre Zeit nicht mit erfolglosen Versuchen verschwenden, Ansatz Y umzusetzen.
supercat
4
Von Tag zu Tag verwende ich auch Kommentare in Arbeit - sie sind auf lange Sicht nicht da, aber es kann nützlich sein, eine Notiz oder einen kurzen Abschnitt einzutragen, um mich daran zu erinnern, was ich als Nächstes tun werde Erinnerung am Morgen.
Glenatron
1
@Lilienthal, ich glaube nicht , dass im letzten Absatz ist beschränkt auf persönliche Projekte, er sagte : „... ich noch Teile Kommentar, den ich verwirrend finden.“
Wildcard
29

Die Notwendigkeit von Kommentaren ist umgekehrt proportional zur Abstraktionsebene des Codes.

Zum Beispiel ist Assemblersprache für die meisten praktischen Zwecke ohne Kommentare unverständlich. Hier ist ein Auszug aus einem kleinen Programm, das Terme der Fibonacci-Reihe berechnet und ausgibt :

main:   
; initializes the two numbers and the counter.  Note that this assumes
; that the counter and num1 and num2 areas are contiguous!
;
    mov ax,'00'                     ; initialize to all ASCII zeroes
    mov di,counter                  ; including the counter
    mov cx,digits+cntDigits/2       ; two bytes at a time
    cld                             ; initialize from low to high memory
    rep stosw                       ; write the data
    inc ax                          ; make sure ASCII zero is in al
    mov [num1 + digits - 1],al      ; last digit is one
    mov [num2 + digits - 1],al      ; 
    mov [counter + cntDigits - 1],al

    jmp .bottom         ; done with initialization, so begin

.top
    ; add num1 to num2
    mov di,num1+digits-1
    mov si,num2+digits-1
    mov cx,digits       ; 
    call    AddNumbers  ; num2 += num1
    mov bp,num2         ;
    call    PrintLine   ;
    dec dword [term]    ; decrement loop counter
    jz  .done           ;

    ; add num2 to num1
    mov di,num2+digits-1
    mov si,num1+digits-1
    mov cx,digits       ;
    call    AddNumbers  ; num1 += num2
.bottom
    mov bp,num1         ;
    call    PrintLine   ;
    dec dword [term]    ; decrement loop counter
    jnz .top            ;
.done
    call    CRLF        ; finish off with CRLF
    mov ax,4c00h        ; terminate
    int 21h             ;

Selbst mit Kommentaren kann es ziemlich kompliziert sein, zu grocken.

Modernes Beispiel: Regexe sind oft sehr niedrige Abstraktionskonstrukte (Kleinbuchstaben, Nummer 0, 1, 2, neue Zeilen usw.). Sie benötigen wahrscheinlich Kommentare in Form von Mustern (Bob Martin, IIRC, erkennt dies an). Hier ist ein regulärer Ausdruck, der (meiner Meinung nach) mit HTTP- (S) und FTP-URLs übereinstimmen sollte:

^(((ht|f)tp(s?))\://)?(www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu|gov|m
+il|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(/($|[a-zA-Z0-9\.
+\,\;\?\'\\\+&amp;%\$#\=~_\-]+))*$

Während die Sprachen die Abstraktionshierarchie verbessern, kann der Programmierer evokative Abstraktionen (Variablennamen, Funktionsnamen, Klassennamen, Modulnamen, Schnittstellen, Rückrufe usw.) verwenden, um eine integrierte Dokumentation bereitzustellen. Es ist faul, dies zu vernachlässigen und Kommentare zu verwenden, um darüber zu schreiben, ein schlechter Dienst für den Betreuer und respektlos gegenüber ihm.

Ich denke dabei an Numerical Recipes in C übersetzt meist wörtlich zu Numerical Recipes in C ++ , die ich schließen , begann als Numerical Recipes (in FORTAN), mit allen Variablen a, aa, b, c, cc, usw. durch jede Version beibehalten. Die Algorithmen mögen korrekt gewesen sein, aber sie haben die Abstraktionen der bereitgestellten Sprachen nicht ausgenutzt. Und sie machen mich fertig. Auszug aus einem Artikel von Dr. Dobbs - Fast Fourier Transform :

void four1(double* data, unsigned long nn)
{
    unsigned long n, mmax, m, j, istep, i;
    double wtemp, wr, wpr, wpi, wi, theta;
    double tempr, tempi;

    // reverse-binary reindexing
    n = nn<<1;
    j=1;
    for (i=1; i<n; i+=2) {
        if (j>i) {
            swap(data[j-1], data[i-1]);
            swap(data[j], data[i]);
        }
        m = nn;
        while (m>=2 && j>m) {
            j -= m;
            m >>= 1;
        }
        j += m;
    };

    // here begins the Danielson-Lanczos section
    mmax=2;
    while (n>mmax) {
        istep = mmax<<1;
        theta = -(2*M_PI/mmax);
        wtemp = sin(0.5*theta);
        wpr = -2.0*wtemp*wtemp;
        wpi = sin(theta);
        wr = 1.0;
        wi = 0.0;
        for (m=1; m < mmax; m += 2) {
            for (i=m; i <= n; i += istep) {
                j=i+mmax;
                tempr = wr*data[j-1] - wi*data[j];
                tempi = wr * data[j] + wi*data[j-1];

                data[j-1] = data[i-1] - tempr;
                data[j] = data[i] - tempi;
                data[i-1] += tempr;
                data[i] += tempi;
            }
            wtemp=wr;
            wr += wr*wpr - wi*wpi;
            wi += wi*wpr + wtemp*wpi;
        }
        mmax=istep;
    }
}

Als Sonderfall zur Abstraktion verfügt jede Sprache über Redewendungen / kanonische Codefragmente für bestimmte allgemeine Aufgaben (Löschen einer dynamischen verknüpften Liste in C). Unabhängig davon, wie sie aussehen, sollten sie nicht dokumentiert werden. Programmierer sollten diese Redewendungen lernen, da sie inoffiziell Teil der Sprache sind.

Also das Mitnehmen: Nicht-idiomatischer Code, der aus einfachen Bausteinen besteht, die nicht vermieden werden können, benötigt Kommentare. Und das ist WAAAAY weniger notwendig, als es passiert.

Kristian H
quelle
1
Niemand sollte wirklich eine Zeile wie diese in Assembler - Sprache schreiben: dec dword [term] ; decrement loop counter. Auf der anderen Seite fehlt in Ihrem Assembler-Beispiel ein Kommentar vor jedem "Code-Absatz", in dem erläutert wird, was der nächste Codeblock tut. In diesem Fall entspricht der Kommentar normalerweise einer einzelnen Zeile im Pseudocode, z. B. ;clear the screengefolgt von den 7 Zeilen, die zum Löschen des Bildschirms tatsächlich erforderlich sind.
Scott Whitlock
1
Ja, es gibt einige unnötige Kommentare im Assembly-Beispiel, aber um fair zu sein, es ist ziemlich repräsentativ für den "guten" Assembly-Stil. Selbst mit einem ein- oder zweizeiligen Absatzprolog wäre der Code wirklich schwer zu befolgen. Ich habe das ASM-Beispiel besser verstanden als das FFT-Beispiel. Ich habe in der Grundschule eine FFT in C ++ programmiert und es sah nicht so aus, aber dann haben wir die STL, Iteratoren, Funktoren und eine ganze Reihe von Methodenaufrufen verwendet. Nicht so schnell wie die monolithische Funktion, aber viel einfacher zu lesen. Ich werde versuchen, es dem NRinC ++ - Beispiel gegenüberzustellen.
Kristian H
Meinten Sie ^(((ht|f)tps?)\:\/\/)?(www\.)*[a-zA-Z0-9\-\.]+\.(com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(\/($|[a-zA-Z0-9\.\,\;\?\'\\\+&%\$#\=~_\-]+))*$? Achten Sie auf numerische Adressen.
Izabera
Mehr oder weniger mein Punkt: Einige Dinge, die aus sehr einfachen Abstraktionen aufgebaut sind, sind nicht einfach zu lesen oder zu überprüfen. Kommentare (und, um nicht zu weit vom Kurs abzukommen, TESTS) können nützlich sein und sind kein Nachteil. Gleichzeitig erschwert die Nichtverwendung verfügbarer Abstraktionen auf höherer Ebene (: alpha:: num: wo verfügbar) das Verständnis, selbst bei guten Kommentaren, als die Verwendung der Abstraktionen auf höherer Ebene.
Kristian H
3
+1: "The need for comments is inversely proportional to the abstraction level of the code." Fasst so ziemlich alles genau dort zusammen.
Gerrat
21

Ich glaube nicht, dass an Kommentaren im Code etwas falsch ist. Die Idee, dass Kommentare meiner Meinung nach irgendwie schlecht sind , ist darauf zurückzuführen, dass einige Programmierer die Dinge zu weit gehen. Es gibt in dieser Branche eine Menge Bandwagoning, insbesondere in Richtung extremer Ansichten. Irgendwo auf dem Weg wurde kommentierter Code zu schlechtem Code und ich bin mir nicht sicher warum.

Kommentare haben Probleme - Sie müssen sie auf dem neuesten Stand halten, wenn Sie den Code aktualisieren, auf den sie verweisen, was viel zu selten vorkommt. Ein Wiki oder ähnliches ist eine geeignetere Ressource für eine gründliche Dokumentation Ihres Codes. Ihr Code sollte lesbar sein, ohne dass Kommentare erforderlich sind. In Versionskontroll- oder Revisionsnotizen sollten Sie die von Ihnen vorgenommenen Codeänderungen beschreiben.

Keiner der oben genannten Punkte macht jedoch die Verwendung von Kommentaren ungültig. Wir leben nicht in einer idealen Welt. Wenn eine der oben genannten Situationen aus irgendeinem Grund fehlschlägt, hätte ich lieber einige Kommentare , auf die ich zurückgreifen könnte.

Roy
quelle
18

Ich denke, du liest ein bisschen zu viel in dem, was er sagt. Ihre Beschwerde besteht aus zwei Teilen:

Was ist falsch daran, (1) einen komplexen Algorithmus oder (2) ein langes und verschlungenes Stück Code mit einem beschreibenden Kommentar zu erklären?

(1) ist unvermeidlich. Ich glaube nicht, dass Martin dir widersprechen würde. Wenn Sie so etwas wie die schnelle Quadratwurzel schreiben , brauchen Sie einige Kommentare, auch wenn es sich nur um "böses Fließkomma-Bit-Level-Hacking" handelt. Abgesehen von etwas Einfachem wie einer DFS- oder Binärsuche ist es unwahrscheinlich, dass die Person, die Ihren Code liest, Erfahrung mit diesem Algorithmus hat. Daher sollte in den Kommentaren zumindest erwähnt werden, was es ist.

Der meiste Code ist jedoch nicht (1). In den seltensten Fällen werden Sie eine Software schreiben, die nichts anderes als handgerollte Mutex-Implementierungen, obskure lineare Algebraoperationen mit unzureichender Bibliotheksunterstützung und neuartige Algorithmen ist, die nur der Forschungsgruppe Ihres Unternehmens bekannt sind. Der meiste Code besteht aus Bibliotheks- / Framework- / API-Aufrufen, E / A, Boilerplate und Komponententests.

Über diese Art von Code spricht Martin. Und er beantwortet Ihre Frage mit dem Zitat von Kernighan und Plaugher am Anfang des Kapitels:

Kommentieren Sie keinen schlechten Code - schreiben Sie ihn neu.

Wenn Sie lange, verschlungene Abschnitte in Ihrem Code haben, ist es Ihnen nicht gelungen, Ihren Code sauber zu halten . Die beste Lösung für dieses Problem ist nicht, einen absatzlangen Kommentar oben in die Datei zu schreiben, um zukünftigen Entwicklern zu helfen, sich darin zurechtzufinden. Die beste Lösung ist, es neu zu schreiben.

Und genau das sagt Martin:

Die ordnungsgemäße Verwendung von Kommentaren dient dazu, unser Versagen, sich im Code auszudrücken, auszugleichen. Kommentare sind immer Fehler. Wir müssen sie haben, weil wir nicht immer herausfinden können, wie wir uns ohne sie ausdrücken können, aber ihr Gebrauch ist kein Grund zum Feiern.

Das ist dein (2). Martin stimmt zu, dass langer, verschachtelter Code Kommentare benötigt - aber er gibt dem Programmierer, der ihn geschrieben hat, die Schuld für diesen Code, nicht irgendeine nebulöse Vorstellung, dass "wir alle wissen, dass das nicht genug ist". Er argumentiert, dass:

Klarer und aussagekräftiger Code mit wenigen Kommentaren ist unübersichtlichem und komplexem Code mit vielen Kommentaren weit überlegen. Anstatt deine Zeit damit zu verbringen, die Kommentare zu schreiben, die das Chaos erklären, das du angerichtet hast, solltest du es damit verbringen, dieses Chaos zu beseitigen.

Patrick Collins
quelle
3
Wenn ein Entwickler, mit dem ich zusammengearbeitet habe, einfach "Evil Floating Point Bit Level Hacking" schrieb, um den schnellen Quadratwurzel-Algorithmus zu erklären, würden sie von mir angesprochen werden. Solange sie einen Hinweis auf etwas Nützlicheres enthielten, würde ich mich trotzdem freuen.
Michael Anderson
8
Ich bin in einer Hinsicht anderer Meinung - ein Kommentar, der erklärt, wie etwas Schlimmes funktioniert, ist viel schneller. Angesichts eines Codes, der wahrscheinlich nicht mehr angerührt wird (der meiste Code, denke ich), ist ein Kommentar eine bessere Geschäftslösung als ein umfangreiches Refactoring, das häufig Fehler einführt (da ein Fix, der den Fehler beseitigt, auf den man sich verlassen kann, immer noch ein Fehler ist). Eine perfekte Welt von perfekt verständlichem Code steht uns nicht zur Verfügung.
gbjbaanb
2
@trysis haha, ja, aber in einer Welt, in der die Programmierer verantwortlich sind und keine Geschäftsleute, werden sie niemals ausliefern, da sie eine ständig überarbeitete Codebasis für immer vergolden, auf der vergeblichen Suche nach Perfektion.
Gbjbaanb
4
@PatrickCollins Bei fast allem, was ich im Internet lese, geht es darum, es gleich beim ersten Mal richtig zu machen. Fast niemand möchte Artikel über das Reparieren von Unordnung schreiben! Physiker sagen "eine perfekte Kugel gegeben ..." Comp.Scientists sagen "eine grüne Wiese Entwicklung gegeben ..."
gbjbaanb
2
Die beste Lösung ist es, es in unendlicher Zeit umzuschreiben. aber angesichts der Codebasis eines anderen, der typischen Unternehmensfristen und der Realität; Manchmal ist es am besten, einen Kommentar abzugeben, einen TODO: Refactor hinzuzufügen und diesen Refactor in die nächste Version zu übernehmen. und dieses Update, das gestern gemacht werden musste, ist jetzt erledigt. Die Sache bei all diesen idealistischen Gesprächen über das reine Refactoring ist, dass es nicht erklärt, wie die Dinge am Arbeitsplatz wirklich funktionieren. Manchmal gibt es höhere Prioritäten und bald genug Fristen, die die Behebung von altem Code mit schlechter Qualität verhindern. Ist einfach so.
hsanders
8

Was ist falsch daran, einen komplexen Algorithmus oder ein langes und verschlungenes Stück Code mit einem beschreibenden Kommentar zu erklären?

Nichts als solches. Das Dokumentieren Ihrer Arbeit ist eine gute Praxis.

Das heißt, Sie haben hier eine falsche Dichotomie: Schreiben von sauberem Code vs. Schreiben von dokumentiertem Code - die beiden sind nicht gegensätzlich.

Sie sollten sich darauf konzentrieren, komplexen Code zu vereinfachen und in einfacheren Code zu abstrahieren, anstatt zu denken, "komplexer Code ist in Ordnung, solange er kommentiert ist".

Im Idealfall sollte Ihr Code einfach und dokumentiert sein.

Auf diese Weise müssen andere Entwickler (einschließlich Sie selbst) nicht den gesamten Algorithmus Zeile für Zeile lesen, um herauszufinden, was er tut, sondern können einfach den benutzerfreundlichen beschreibenden Kommentar lesen, den Sie im Klartext geschrieben haben.

Wahr. Aus diesem Grund sollten alle Ihre öffentlichen API-Algorithmen in der Dokumentation erläutert werden.

Fügen Sie nach dem Schreiben eines komplexen Codeteils in einer teilweise für Menschen lesbaren Programmiersprache einen beschreibenden und präzisen Kommentar hinzu, der die Funktionsweise des Codes in freundlichem und verständlichem Englisch erklärt.

Idealerweise sollten Sie nach dem Schreiben eines komplexen Code Folgendes tun (keine vollständige Liste):

  • halte es für einen Entwurf (dh plane es neu zu schreiben)
  • Formalisieren Sie die Algorithmus-Einstiegspunkte / Schnittstellen / Rollen / usw. (analysieren und optimieren Sie die Schnittstelle, formalisieren Sie Abstraktionen, dokumentieren Sie Vorbedingungen, Nachbedingungen und Nebenwirkungen und dokumentieren Sie Fehlerfälle).
  • schreiben Sie Tests
  • Aufräumen und Refactor

Keiner dieser Schritte ist trivial (dh jeder kann einige Stunden dauern) und die Belohnungen dafür sind nicht unmittelbar. Daher werden diese Schritte (fast) immer beeinträchtigt (von Entwicklern, Managern, Terminen, Markteinschränkungen / anderen realen Bedingungen, mangelnder Erfahrung usw.).

[...] einige Algorithmen sind komplex. Und sind deshalb schwer zu verstehen, wenn man sie Zeile für Zeile liest.

Sie sollten sich niemals darauf verlassen müssen, die Implementierung zu lesen, um herauszufinden, was eine API tut. Wenn Sie dies tun, implementieren Sie Client-Code basierend auf der Implementierung (anstelle der Schnittstelle) und das bedeutet, dass Ihre Modulkopplung bereits zum Teufel ist. Sie führen möglicherweise undokumentierte Abhängigkeiten mit jeder neuen Codezeile ein, die Sie schreiben, und sind fügte bereits technische Schulden hinzu.

Ist es wirklich so schlecht, einen komplexen Algorithmus mit ein paar Zeilen Kommentaren zur allgemeinen Funktionsweise zu erklären?

Nein, das ist gut. Es reicht jedoch nicht aus, ein paar Kommentarzeilen hinzuzufügen.

Was ist falsch daran, komplizierten Code mit einem Kommentar zu erklären?

Die Tatsache, dass Sie keinen komplizierten Code haben sollten, wenn dies vermieden werden kann.

Um komplizierten Code zu vermeiden, müssen Sie Ihre Schnittstellen formalisieren, ~ 8 Mal mehr für das API-Design als für die Implementierung ausgeben (Stepanov schlug vor, mindestens das 10-fache für die Schnittstelle im Vergleich zur Implementierung auszugeben) und ein Projekt mit dem entsprechenden Wissen entwickeln Sie erstellen ein Projekt und schreiben nicht nur einen Algorithmus.

Ein Projekt umfasst API-Dokumentation, Funktionsdokumentation, Code- / Qualitätsmessungen, Projektmanagement usw. Bei keinem dieser Prozesse handelt es sich um einmalige, schnell auszuführende Schritte (alle benötigen Zeit, erfordern Voraussicht und Planung, und alle erfordern, dass Sie regelmäßig zu ihnen zurückkehren und sie mit Details überarbeiten / vervollständigen).

utnapistim
quelle
3
"Sie sollten sich niemals darauf verlassen müssen, die Implementierung zu lesen, um herauszufinden, was eine API tut." Manchmal wird dies von einem Upstream verursacht, zu dessen Verwendung Sie sich verpflichtet haben. Ich hatte ein besonders unbefriedigendes Projekt, das mit Kommentaren der Form "Der folgende hässliche Heath Robinson-Code existiert, weil simpleAPI () auf dieser Hardware trotz der Behauptungen des Herstellers nicht richtig funktioniert" übersät war.
PJC50
6

Anstatt dass andere Entwickler (einschließlich Sie selbst) den gesamten Algorithmus Zeile für Zeile lesen müssen, um herauszufinden, was er tut, können sie einfach den freundlichen beschreibenden Kommentar lesen, den Sie in einfachem Englisch geschrieben haben.

Ich würde dies als leichten Missbrauch von "Kommentaren" betrachten. Wenn der Programmierer etwas anstelle des gesamten Algorithmus lesen möchte , ist dies die Funktionsdokumentation. OK, die Funktionsdokumentation wird möglicherweise tatsächlich in Kommentaren in der Quelle angezeigt (möglicherweise zum Extrahieren mit Doc-Tools). Syntaktisch handelt es sich jedoch um einen Kommentar für Ihren Compiler. Sie sollten sie jedoch für unterschiedliche Zwecke betrachten. Ich denke nicht, dass "Kommentare sollten knapp sein" notwendigerweise "Dokumentation sollte knapp sein" oder sogar "Copyright-Vermerke sollten knapp sein" bedeutet!

Kommentare in der Funktion sind für jemanden lesbar , ebenso wie der Code. Wenn Ihr Code einige schwer verständliche Zeilen enthält und Sie diese nicht leicht verständlich machen können, ist ein Kommentar für den Leser hilfreich, um ihn als Platzhalter für diese Zeilen zu verwenden. Dies kann sehr nützlich sein, wenn der Leser nur versucht, das Wesentliche herauszufinden, aber es gibt ein paar Probleme:

  • Kommentare sind nicht unbedingt wahr, wohingegen der Code das tut, was er tut. Der Leser nimmt Ihr Wort dafür und das ist nicht ideal.
  • Der Leser versteht den Code selbst noch nicht. Bis er später darauf zurückkommt, ist er immer noch nicht qualifiziert, ihn zu ändern oder wiederzuverwenden. In welchem ​​Fall lesen sie es?

Es gibt Ausnahmen, aber die meisten Leser müssen den Code selbst verstehen. Kommentare sollten geschrieben werden, um dies zu unterstützen, und nicht, um es zu ersetzen. Aus diesem Grund wird empfohlen, dass in den Kommentaren angegeben wird, warum Sie es tun. Ein Leser, der die Motivation für die nächsten Codezeilen kennt, hat eine bessere Chance zu sehen, was er tut und wie.

Steve Jessop
quelle
5
Ein nützlicher Ort für Kommentare: Im wissenschaftlichen Code können Berechnungen häufig recht komplex sein und viele Variablen enthalten. Für den Programmierer ist es sinnvoll, die Variablennamen kurz zu halten, damit Sie sich die Mathematik und nicht die Namen ansehen können. Aber das macht es dem Leser wirklich schwer zu verstehen. Eine kurze Beschreibung der Vorgänge (oder besser ein Verweis auf die Gleichung in einem Zeitschriftenartikel oder ähnlichem) kann also sehr hilfreich sein.
Naught101
1
@ naught101: ja, vor allem, da in dem Artikel, auf den Sie sich beziehen, wahrscheinlich auch Variablennamen mit einem Buchstaben verwendet wurden. In der Regel ist es einfacher zu erkennen, dass der Code tatsächlich dem Papier folgt, wenn Sie dieselben Namen verwenden. Dies steht jedoch im Widerspruch zu dem Ziel, dass der Code selbsterklärend ist (dies wird stattdessen durch das Papier erklärt ). In diesem Fall ersetzt ein Kommentar, in dem jeder Name definiert ist und sagt, was er tatsächlich bedeutet, sinnvolle Namen.
Steve Jessop
1
Wenn ich nach etwas Bestimmtem im Code suche (wo wird dieser spezielle Fall behandelt?), Möchte ich keine Absätze des Codes lesen und verstehen, nur um herauszufinden, dass es schließlich nicht der richtige Ort ist. Ich brauche Kommentare, die in einer einzigen Zeile zusammenfassen, was der nächste Absatz tut. Auf diese Weise finde ich schnell die Teile des Codes, die mit meinem Problem zusammenhängen, und überspringe uninteressante Details.
Florian F
1
@FlorianF: Die traditionelle Antwort ist, dass Variablen- und Funktionsnamen ungefähr angeben sollten, worum es im Code geht, und Sie daher über Dinge hinwegsehen können, bei denen es sicherlich nicht um das geht, wonach Sie suchen. Ich stimme Ihnen zu, dass dies nicht immer gelingt, aber ich stimme nicht so stark zu, dass ich denke, dass der gesamte Code kommentiert werden muss, um die Suche oder das Überfliegen zu erleichtern. Aber Sie haben Recht, das ist ein Fall, in dem jemand Ihren Code liest (oder so) und ihn zu Recht nicht verstehen muss.
Steve Jessop
2
@Snowman Leute könnten das mit Variablennamen machen. Ich habe Code gesehen, in dem die Variable listOfApples eine Liste von Bananen enthielt. Jemand kopierte den Code, der die Liste der Äpfel verarbeitete, und passte ihn für Bananen an, ohne sich die Mühe zu machen, die Variablennamen zu ändern.
Florian F
5

Oft müssen wir komplizierte Dinge tun. Es ist sicherlich richtig, sie für das zukünftige Verständnis zu dokumentieren. Manchmal ist der richtige Ort für diese Dokumentation im Code, wo die Dokumentation mit dem Code auf dem neuesten Stand gehalten werden kann. Es lohnt sich aber auf jeden Fall, eine separate Dokumentation zu betrachten. Dies kann auch einfacher für andere Personen sein, einschließlich Diagrammen, Farbbildern und so weiter. Dann ist der Kommentar einfach:

// This code implements the algorithm described in requirements document 239.

oder auch nur

void doPRD239Algorithm() { ...

Sicherlich sind die Leute mit den Funktionen MatchStringKnuthMorrisPrattoder encryptAESoder zufrieden partitionBSP. Weitere undurchsichtige Namen sollten in einem Kommentar erläutert werden. Sie können auch bibliografische Daten und einen Link zu einem Artikel hinzufügen, aus dem Sie einen Algorithmus implementiert haben.

Wenn ein Algorithmus komplex und neuartig und nicht offensichtlich ist, ist er auf jeden Fall ein Dokument wert, auch wenn er nur für den internen Unternehmensumlauf bestimmt ist. Überprüfen Sie das Dokument in der Quellcodeverwaltung, wenn Sie befürchten, dass es verloren geht.

Es gibt eine andere Kategorie von Code, die weniger algorithmisch als bürokratisch ist. Sie müssen Parameter für ein anderes System einrichten oder mit den Fehlern eines anderen zusammenarbeiten:

/* Configure the beam controller and turn on the laser.
The sequence is timing-critical and this code must run with interrupts disabled.
Note that the constant 0xef45ab87 differs from the vendor documentation; the vendor
is wrong in this case.
Some of these operations write the same value multiple times. Do not attempt
to optimise this code by removing seemingly redundant operations.
*/
pjc50
quelle
2
Ich würde dagegen argumentieren, Funktionen / Methoden nach ihrem internen Algorithmus zu benennen. Meistens sollte die verwendete Methode ein internes Problem sein. Dokumentieren Sie auf jeden Fall die Spitze Ihrer Funktion mit der verwendeten Methode, aber nennen Sie sie nicht so doPRD239Algorithm, dass sie mir Aufschluss gibt Nichts über die Funktion, ohne den Algorithmus nachschlagen zu müssen. Der Grund MatchStringKnuthMorrisPrattund die encryptAESArbeit besteht darin, dass sie mit einer Beschreibung ihrer Arbeit beginnen und anschließend die Methodik beschreiben.
Scragar
5

Ich vergesse, wo ich es gelesen habe, aber es gibt eine scharfe und klare Linie zwischen dem, was in Ihrem Code erscheinen soll und dem, was als Kommentar erscheinen soll.

Ich glaube, Sie sollten Ihre Absicht kommentieren, nicht Ihren Algorithmus . Ich kommentiere, was du vorhast, nicht was du tust .

Zum Beispiel:

// The getter.
public <V> V get(final K key, Class<V> type) {
  // Has it run yet?
  Future<Object> f = multitons.get(key);
  if (f == null) {
    // No! Make the task that runs it.
    FutureTask<Object> ft = new FutureTask<Object>(
            new Callable() {

              public Object call() throws Exception {
                // Only do the create when called to do so.
                return key.create();
              }

            });
    // Only put if not there.
    f = multitons.putIfAbsent(key, ft);
    if (f == null) {
      // We replaced null so we successfully put. We were first!
      f = ft;
      // Initiate the task.
      ft.run();
    }
  }
  try {
    /**
     * If code gets here and hangs due to f.status = 0 (FutureTask.NEW)
     * then you are trying to get from your Multiton in your creator.
     *
     * Cannot check for that without unnecessarily complex code.
     *
     * Perhaps could use get with timeout.
     */
    // Cast here to force the right type.
    return (V) f.get();
  } catch (Exception ex) {
    // Hide exceptions without discarding them.
    throw Throwables.asRuntimeException(ex);
  }
}

Hier gibt es keinen Versuch zu erklären , was jeder Schritt durchführt, alle heißt es ist , was es soll tun.

PS: Ich habe die Quelle gefunden, auf die ich mich bezog - Coding Horror: Code sagt Ihnen wie, Kommentare sagen Ihnen warum

OldCurmudgeon
quelle
8
Der erste Kommentar: Ist es schon gelaufen? Was ist noch gelaufen? Gleiches gilt für die anderen Kommentare. Für jemanden, der nicht weiß, was der Code tut, ist dies nutzlos.
gnasher729
1
@ gnasher729 - Aus dem Kontext herausgenommen, ist fast jeder Kommentar nutzlos. Dieser Code demonstriert das Hinzufügen von Kommentaren, die auf Absichten hinweisen , anstatt zu beschreiben . Es tut mir leid, dass es nichts für Sie tut.
OldCurmudgeon
2
Ein Betreuer dieses Codes hat keinen Kontext. Es ist nicht besonders schwierig herauszufinden, was der Code bewirkt, aber die Kommentare helfen nicht weiter. Wenn Sie Kommentare schreiben, nehmen Sie sich Zeit und konzentrieren Sie sich beim Schreiben.
gnasher729
Übrigens: Der Kommentar " Wurde es noch ausgeführt" bezieht sich auf " Wurde es ausgeführt"Future und gibt an, dass get()durch eine anschließende Überprüfung festgestellt wird, nullob das FutureProgramm bereits ausgeführt wurde. Dabei wird die Absicht und nicht der Prozess korrekt dokumentiert .
OldCurmudgeon
1
@OldCurmudgeon: Ihre Antwort ist nah genug an dem, was ich dachte, dass ich nur diesen Kommentar als Beispiel für Ihren Punkt hinzufügen werde. Während ein Kommentar nicht benötigt wird, um sauberen Code zu erklären, ist ein Kommentar gut, um zu erklären, warum das Codieren auf eine Weise anders gemacht wurde. Nach meiner begrenzten Erfahrung sind Kommentare oft nützlich, um die Besonderheiten des Datensatzes zu erklären, an dem der Code arbeitet, oder die Geschäftsregeln, die der Code durchsetzen soll. Das Kommentieren von Code, der hinzugefügt wird, um einen Fehler zu beheben, ist ein gutes Beispiel, wenn dieser Fehler aufgetreten ist, weil eine Annahme über die Daten falsch war.
Randall Stewart
4

Aber wir alle wissen, dass das nicht ausreicht.

"Ja wirklich?" Seit wann?

Gut gestalteter Code mit guten Namen ist in den allermeisten Fällen mehr als ausreichend. Die Argumente gegen die Verwendung von Kommentaren sind bekannt und dokumentiert (wie Sie sich beziehen).

Aber das sind Richtlinien (wie alles andere). In dem seltenen Fall (meiner Erfahrung nach etwa alle zwei Jahre), in dem sich die Situation verschlechtert, wenn sie (aufgrund von Leistungs- oder Kohäsionsanforderungen) in kleinere lesbare Funktionen umgewandelt wird, geben Sie einen ausführlichen Kommentar ein, in dem Sie erklären, was die Sache eigentlich ist tun (und warum Sie Best Practices verletzen).

Telastyn
quelle
7
Ich weiß, dass es nicht genug ist.
Florian F
2
Seit wann? Anscheinend kennen Sie bereits die Antwort darauf. "Gut gestalteter Code mit guten Namen ist in den allermeisten Fällen mehr als ausreichend ." Es ist also wahrscheinlich nicht genug in einer Minderheit von Fällen, genau das, was der Fragesteller fragt.
Ellesedil
3
Ich versuche immer, den Code anderer Leute zu entschlüsseln, von denen ich wünschte, sie hätten alle zwei Jahre mehrmals Kommentare hinzugefügt.
Ogre Psalm33
@ OgrePsalm33 - Haben sie kleine Methoden und verwenden sie gute Namen? Ungeachtet der Kommentare ist fehlerhafter Code fehlerhaft.
Telastyn
2
@Telastyn Leider sind bei der Arbeit mit großem Code "kleine" Methoden und "gute" Namen für jeden Entwickler subjektiv (dies ist auch ein guter Kommentar). Ein Entwickler, der 7 Jahre lang Flarbigans Code für einen grafischen Verarbeitungsalgorithmus schreibt, kann ihm und ähnlichen Entwicklern etwas klares schreiben, wäre aber für den neuen Mann, der in den letzten 4 Jahren den Perbian Grid Infrastructure Code entwickelt hat, kryptisch. Dann, zwei Wochen später, kündigt der Flarbigan-Experte.
Ogre Psalm33
2

Der Hauptzweck von Code besteht darin, einem Computer zu befehlen, etwas zu tun. Ein guter Kommentar ist also niemals ein Ersatz für guten Code, da Kommentare nicht ausgeführt werden können.

Abgesehen davon sind Kommentare in der Quelle eine Form der Dokumentation für andere Programmierer (einschließlich Sie selbst). Wenn es sich bei den Kommentaren um abstraktere Themen handelt, als der Code bei jedem Schritt tut, sind Sie besser als der Durchschnitt. Diese Abstraktionsstufe hängt vom verwendeten Tool ab. Kommentare, die Assembler-Routinen beigefügt sind, weisen im Allgemeinen eine niedrigere "Abstraktionsstufe" auf als beispielsweise diese APL A←0⋄A⊣{2⊤⍵:1+3×⍵⋄⍵÷2}⍣{⍺=A+←1}⎕. Ich denke, das wäre wahrscheinlich einen Kommentar über das Problem wert, das es lösen soll, hmmm?

Scott Leadley
quelle
2

Wenn der Code trivial ist, benötigt er keinen erklärenden Kommentar. Wenn der Code nicht trivial ist, ist der erläuternde Kommentar höchstwahrscheinlich auch nicht trivial.

Das Problem mit nicht-trivialer natürlicher Sprache ist, dass viele von uns nicht sehr gut darin sind, sie zu lesen oder zu schreiben. Ich bin mir sicher, dass Ihre schriftlichen Kommunikationsfähigkeiten ausgezeichnet sind, aber dennoch kann jemand mit einem geringeren Verständnis der geschriebenen Sprache Ihre Worte missverstehen.

Wenn Sie sich sehr bemühen, eine natürliche Sprache zu schreiben, die nicht falsch interpretiert werden kann, erhalten Sie so etwas wie ein juristisches Dokument (und wie wir alle wissen, sind diese Dokumente ausführlicher und schwer zu verstehen als Code).

Code sollte die prägnanteste Beschreibung Ihrer Logik sein, und es sollte nicht viel Debatte über die Bedeutung Ihres Codes geben, da Ihr Compiler und Ihre Plattform das letzte Wort haben.

Persönlich würde ich nicht sagen, dass Sie niemals einen Kommentar schreiben sollten. Nur, dass Sie sich überlegen sollten, warum Ihr Code einen Kommentar benötigt und wie Sie dies beheben können. Dies scheint ein häufiges Thema bei den Antworten zu sein.

Martin
quelle
Genau das, was ich gedacht habe, als ich mit der Aussage "Ein Mensch kann ein Stück Englisch viel schneller verstehen als ein Stück Code mit der gleichen Bedeutung (solange die Operation nicht trivial ist)" nicht einverstanden war immer weniger mehrdeutig und prägnanter.
Stephenbayer
0

Ein Punkt, der noch nicht erwähnt wurde, ist, dass es manchmal hilfreich sein kann, genau zu kommentieren, was ein Codeteil tut, wenn eine Sprache eine bestimmte Syntax für mehrere Zwecke verwendet. Angenommen, alle Variablen sind vom Typ float:

f1 = (float)(f2+f3); // Force result to be rounded to single precision
f4 = f1-f2;

Die Wirkung der explizit ein Gießens floatzu floatist das Ergebnis zu zwingen, mit einfacher Genauigkeit gerundet werden; Der Kommentar kann also so gesehen werden, als würde er einfach sagen, was der Code tut. Vergleichen Sie andererseits diesen Code mit:

thing.someFloatProperty = (float)(f2*0.1); // Divide by ten

Hier besteht der Zweck des Casts darin, zu verhindern, dass der Compiler auf die effizienteste Art und Weise quäkt (f2 / 10).

Ohne diesen Kommentar könnte jemand, der den vorherigen Code überprüft hat, der Meinung sein, dass die Besetzung fälschlicherweise hinzugefügt wurde, um zu verhindern, dass der Compiler quietscht, und dass sie nicht benötigt wird. Tatsächlich dient die Besetzung dem Zweck, genau das zu tun, was die Sprachspezifikation angibt: Das Ergebnis der Berechnung muss auf eine Genauigkeit gerundet werden, selbst bei Maschinen, bei denen das Runden teurer wäre als das Ergebnis auf einer höheren Genauigkeit zu halten. Angesichts der Tatsache, dass eine Besetzung von floateine Reihe von unterschiedlichen Bedeutungen und Zwecken haben kann, kann das Festlegen, welche Bedeutung in einem bestimmten Szenario beabsichtigt ist, dazu beitragen, klar zu machen, dass die tatsächliche Bedeutung mit der Absicht übereinstimmt.

Superkatze
quelle
Ich bin mir nicht sicher, ob J. Random Programmer beim Betrachten des zweiten Beispiels erkennt, dass die Konstante aus gutem Grund mit 0.1 geschrieben ist, anstatt dass der ursprüngliche Programmierer vergessen hat, ein 'f' einzugeben.
David K
Insbesondere beim Debuggen wird niemals davon ausgegangen, dass etwas aus einem guten Grund getan wurde.
gnasher729
@DavidK: Der Zweck meines zweiten Beispielcodes bestand darin, ihn dem ersten Codeteil gegenüberzustellen. Im zweiten Teil des Codes ist es wahrscheinlich die Absicht des Programmierers someFloatProperty, die genaueste Darstellung dessen zu haben , f2/10was er kann; Der Hauptzweck der zweiten Besetzung besteht also darin, den Code einfach kompilieren zu lassen . Im ersten Beispiel wird die Umwandlung jedoch eindeutig nicht für den normalen Zweck (Ändern eines Kompilierungstyps in einen anderen) benötigt, da die Operanden bereits vorhanden sind float. Der Kommentar dient deutlich zu machen , dass die Besetzung ist für einen sekundären Zweck benötigt werden (Rundung).
Supercat
Ich stimme dem Gedanken zu, dass Sie (float)im zweiten Beispiel keine Kommentare zu der Besetzung abgeben müssen. Die Frage ist nach der wörtlichen Konstante 0.1. Sie haben (im nächsten Absatz des Textes) erklärt, warum wir schreiben würden 0.1: "Es ist genauer als das Multiplizieren mit 0,1f." Ich schlage vor, dass das die Wörter sind, die im Kommentar sein sollten.
David K
@DavidK: Ich würde auf jeden Fall den Kommentar einfügen, wenn ich wüsste, dass 0,1 f inakzeptabel ungenau ist, und würde 0,1 f verwenden, wenn ich wüsste, dass der Präzisionsverlust akzeptabel ist und 0,1 f tatsächlich wesentlich schneller als 0,1 ist . Wenn ich nicht weiß, dass eines dieser Dinge zutrifft, würde ich es vorziehen, doublefür Konstanten oder Zwischenberechnungen zu verwenden, deren Wert möglicherweise nicht darstellbar ist float[obwohl in Sprachen, die ärgerliche, explizite Double-to-Float-Casts und Faulheit erfordern] kann sein, floatKonstanten nicht für die Geschwindigkeit zu verwenden, sondern um Ärger zu minimieren.
Supercat
-1

Kommentare, die erklären, was der Code tut, sind eine Form der Vervielfältigung. Wenn Sie den Code ändern und dann vergessen, die Kommentare zu aktualisieren, kann dies zu Verwirrung führen. Ich sage nicht, benutze sie nicht, sondern benutze sie nur mit Bedacht. Ich abonniere die Maxime von Onkel Bob: "Nur kommentieren, was der Code nicht sagen kann".

murungu
quelle