Clean Code-Kommentare vs. Klassendokumentation

83

Ich habe einige Diskussionen mit meinen neuen Kollegen über das Kommentieren. Wir beide mögen Clean Code , und ich bin völlig in Ordnung mit der Tatsache, dass Inline-Code-Kommentare vermieden werden sollten und dass Klassen- und Methodennamen verwendet werden sollten, um auszudrücken, was sie tun.

Ich bin jedoch ein großer Fan von kleinen Klassenzusammenfassungen, die versuchen, den Zweck der Klasse und die tatsächliche Repräsentation zu erklären, vor allem, um das Prinzip der Einzelverantwortung einfach beizubehalten . Ich bin es auch gewohnt, einzeilige Zusammenfassungen zu Methoden hinzuzufügen, die erklären, was die Methode tun soll. Ein typisches Beispiel ist die einfache Methode

public Product GetById(int productId) {...}

Ich füge die folgende Methodenübersicht hinzu

/// <summary>
/// Retrieves a product by its id, returns null if no product was found.
/// </summary

Ich glaube, dass die Tatsache, dass die Methode null zurückgibt, dokumentiert werden sollte. Ein Entwickler, der eine Methode aufrufen möchte, sollte meinen Code nicht öffnen müssen, um festzustellen, ob die Methode null zurückgibt oder eine Ausnahme auslöst. Manchmal ist es Teil einer Schnittstelle, sodass der Entwickler nicht einmal weiß, welcher zugrunde liegende Code ausgeführt wird?

Meine Kollegen sind jedoch der Meinung, dass diese Art von Kommentaren " Code-Geruch " ist und dass "Kommentare immer Fehler sind" ( Robert C. Martin ).

Gibt es eine Möglichkeit, diese Art von Wissen auszudrücken und zu kommunizieren, ohne Kommentare hinzuzufügen? Da ich ein großer Fan von Robert C. Martin bin, bin ich etwas verwirrt. Stimmen Zusammenfassungen mit Kommentaren überein und scheitern daher immer?

Dies ist keine Frage zu Inline-Kommentaren.

Björn
quelle
38
Robert Martin sagte: "Kommentare sind immer Fehler"? Nun, dann ist er ein Randextremist und sollte mit einer Prise Salz eingenommen werden. (Ja, mir ist bewusst, dass er aus rhetorischen Gründen so schreibt, um seine Botschaft zu vermitteln. Mein Punkt ist, dass Sie es auch tun sollten .)
Kilian Foth
18
Onkel Bobs Bücher sollten mit einem Beutel mit 1
kg
6
Wenn Sie Robert Martin folgen, sollte die Dokumentation für den Nullfall ein Test sein. Das heißt, Sie sollten einen Test haben, der zeigt, in welchem ​​Fall die Methode null zurückgeben kann. Da dies Java ist, wäre alternativ auch eine Annotation @Nullable besser als der Kommentar.
Martin Epsz
15
@ Bjorn Ich besitze eine Kopie von Clean Code und habe sie mehrmals gelesen. Ja, Onkel Bob bevorzugt, dass sich Code selbst dokumentiert, aber es gibt mehrere Beispiele für Kommentare in seinem eigenen Code im Buch . Der Punkt ist, wenn Sie sich gezwungen fühlen, einen Kommentar zu schreiben, versuchen Sie wirklich, den Code zu ändern, anstatt den Kommentar hinzuzufügen, aber lehnen Sie Kommentare nicht vollständig ab (sogar Inline-Kommentare).
6
Die Methode sollte TryGetById heißen und der Kommentar sollte entfernt werden.
USR

Antworten:

116

Wie andere gesagt haben, gibt es einen Unterschied zwischen API-dokumentierenden Kommentaren und Inline-Kommentaren. Aus meiner Sicht besteht der Hauptunterschied darin, dass ein Inline-Kommentar neben dem Code gelesen wird , während ein Dokumentationskommentar neben der Signatur von allem, was Sie kommentieren, gelesen wird .

Vor diesem Hintergrund können wir das gleiche DRY- Prinzip anwenden . Sagt der Kommentar dasselbe wie die Unterschrift? Schauen wir uns Ihr Beispiel an:

Ruft ein Produkt anhand seiner ID ab

Dieser Teil wiederholt nur das, was wir bereits aus dem Namen GetByIdund dem Rückgabetyp ersehen Product. Es wirft auch die Frage auf, was der Unterschied zwischen "Abrufen" und "Abrufen" ist und welche Bedeutung der Unterschied zwischen Code und Kommentar für diese Unterscheidung hat. Es ist also unnötig und etwas verwirrend. Wenn überhaupt, wird es dem eigentlich nützlichen zweiten Teil des Kommentars im Wege stehen:

Gibt null zurück, wenn kein Produkt gefunden wurde.

Ah! Das können wir definitiv nicht aus der Unterschrift ersehen und liefern nützliche Informationen.


Gehen Sie jetzt noch einen Schritt weiter. Wenn Leute über Kommentare sprechen , als Code riecht, ist die Frage nicht , ob der Code , wie es ist braucht einen Kommentar, aber ob der Kommentar zeigt an, dass der Code besser geschrieben werden kann, die Informationen im Kommentar zum Ausdruck bringen. Das ist, was "Codegeruch" bedeutet - es bedeutet nicht "Tu das nicht!", Es bedeutet "Wenn du das tust, könnte es ein Zeichen dafür sein, dass es ein Problem gibt".

Wenn Ihnen Ihre Kollegen sagen, dass dieser Kommentar zu null ein Codegeruch ist, sollten Sie sie einfach fragen: "Okay, wie soll ich das dann ausdrücken?" Wenn sie eine realisierbare Antwort haben, haben Sie etwas gelernt. Wenn nicht, wird es wahrscheinlich ihre Beschwerden töten.


In Bezug auf diesen speziellen Fall ist allgemein bekannt, dass das Null-Problem schwierig ist. Es gibt einen Grund, warum Codebasen mit Schutzklauseln übersät sind, warum Nullprüfungen eine beliebte Voraussetzung für Codeverträge sind, warum die Existenz von Null als "Milliarden-Dollar-Fehler" bezeichnet wurde. Es gibt nicht so viele praktikable Optionen. Eine beliebte Variante in C # ist die Try...Konvention:

public bool TryGetById(int productId, out Product product);

In anderen Sprachen kann es idiomatisch sein, einen Typ (der oft als " Optionaloder" bezeichnet wird Maybe) zu verwenden, um auf ein Ergebnis hinzuweisen, das möglicherweise vorhanden ist oder nicht:

public Optional<Product> GetById(int productId);

In gewisser Weise hat uns diese Anti-Kommentar-Haltung weitergebracht: Wir haben uns zumindest Gedanken darüber gemacht, ob dieser Kommentar einen Geruch darstellt und welche Alternativen für uns existieren könnten.

Ob wir sollten eigentlich diese über die ursprüngliche Signatur bevorzugen ist eine ganz andere Debatte, aber wir haben zumindest Möglichkeiten , durch den Code zum Ausdruck anstatt Kommentare , was passiert , wenn kein Produkt gefunden wird. Sie sollten mit Ihren Kollegen besprechen, welche dieser Optionen ihrer Meinung nach besser sind und warum, und hoffentlich dabei helfen, über pauschale dogmatische Aussagen zu Kommentaren hinauszugehen.

Ben Aaronson
quelle
9
Oder die Linq-Äquivalent von Try..., ...OrDefault, die zurückkehren , default(T)wenn die Klausel zu einem leeren Ergebnis führen würde.
Bart van Nierop
4
Ich freue mich sehr über Ihre Unterscheidung zwischen Inline-Code-Kommentaren und Dokumentationskommentaren sowie den angegebenen Beispielen :)
Rachel
2
Die möglichen Rückgabewerte einer Funktion sollten an ihrer Signatur erkennbar sein. Das TryGetValueMuster ist eine sinnvolle Möglichkeit, dies in C # zu tun, aber die meisten funktionalen Sprachen haben eine bessere Möglichkeit, einen fehlenden Wert darzustellen. Lesen Sie hier mehr
AlexFoxGill
2
@BenAaronson: Wenn eine generische Schnittstelle verwendet werden soll, die Kovarianz unterstützen kann, kann diese entweder T TryGetValue(params, ref bool success)für einen beliebigen Typ T oder T TryGetValue(params), wenn ein Fehler durch Null angezeigt wird , für einen klassenbeschränkten Typ T verwendet werden. Das zurückgegebene TryGetXXMuster boolist jedoch nicht mit der Kovarianz kompatibel.
Supercat
6
In Java 8 können Sie ein zurückgeben, Optional<Product>um anzugeben, dass möglicherweise kein Produkt von der Methode zurückgegeben wird.
Wim Deblauwe
102

Das Robert C. Martin-Zitat wird aus dem Zusammenhang gerissen. Hier ist das Zitat mit etwas mehr Kontext:

Nichts kann so hilfreich sein wie ein gut platzierter Kommentar. Nichts kann ein Modul überladener machen als frivole dogmatische Kommentare. Nichts kann so schädlich sein wie ein alter, schmutziger Kommentar, der Lügen und Fehlinformationen verbreitet.

Kommentare sind nicht wie Schindlers Liste. Sie sind nicht "rein gut". Kommentare sind in der Tat bestenfalls ein notwendiges Übel. Wenn unsere Programmiersprachen ausdrucksstark genug wären oder wir das Talent hätten, diese Sprachen subtil einzusetzen, um unsere Absicht auszudrücken, würden wir kaum Kommentare benötigen - vielleicht gar nicht.

Die ordnungsgemäße Verwendung von Kommentaren soll unser Versäumnis ausgleichen, uns im Code auszudrücken. Beachten Sie, dass ich das Wort Fehler verwendet habe. Ich meinte es. 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.

Wenn Sie sich also in einer Position befinden, in der Sie einen Kommentar schreiben müssen, überlegen Sie, ob es keine Möglichkeit gibt, den Spieß umzudrehen und sich im Code auszudrücken. Jedes Mal, wenn Sie sich in Code ausdrücken, sollten Sie sich auf den Rücken klopfen. Jedes Mal, wenn Sie einen Kommentar schreiben, sollten Sie eine Grimasse ziehen und das Versagen Ihrer Ausdrucksfähigkeit spüren.

( Von hier kopiert , aber das Originalzitat stammt aus Clean Code: A Handbook of Agile Software Craftsmanship. )

Wie dieses Zitat in "Kommentare sind immer Fehler" reduziert wird, ist ein gutes Beispiel dafür, wie manche Leute ein vernünftiges Zitat aus dem Kontext nehmen und es in ein dummes Dogma verwandeln.


API-Dokumentation (wie javadoc) soll die API dokumentieren, damit der Benutzer sie verwenden kann, ohne den Quellcode lesen zu müssen . Also in diesem Fall die Dokumentation sollte erklären , was das Verfahren der Fall ist. Jetzt können Sie argumentieren, dass "Ruft ein Produkt anhand seiner ID ab" überflüssig ist, da dies bereits durch den Methodennamen angegeben ist. Die zurückgegebenen Informationen nullsind jedoch unbedingt zu dokumentieren, da dies in keiner Weise offensichtlich ist.

Wenn Sie die Notwendigkeit des Kommentars vermeiden möchten, müssen Sie das zugrunde liegende Problem (das nullals gültiger Rückgabewert verwendet wird) entfernen , indem Sie die API expliziter gestalten. Beispielsweise könnten Sie eine Art Option<Product>Typ zurückgeben, sodass die Typensignatur selbst klar kommuniziert, was zurückgegeben wird, falls das Produkt nicht gefunden wird.

In jedem Fall ist es jedoch nicht realistisch, eine API nur durch Methodennamen und Typensignaturen vollständig zu dokumentieren. Verwenden Sie doc-comments für zusätzliche nicht offensichtliche Informationen, die der Benutzer kennen sollte. Nehmen wir zum Beispiel die API-Dokumentation aus DateTime.AddMonths()der BCL:

Die AddMonths-Methode berechnet den resultierenden Monat und das resultierende Jahr unter Berücksichtigung der Schaltjahre und der Anzahl der Tage in einem Monat und passt dann den Tag-Teil des resultierenden DateTime-Objekts an. Wenn der resultierende Tag kein gültiger Tag im resultierenden Monat ist, wird der letzte gültige Tag des resultierenden Monats verwendet. Zum Beispiel: 31. März + 1 Monat = 30. April. Der Tageszeitteil des resultierenden DateTime-Objekts bleibt derselbe wie in dieser Instanz.

Es gibt keine Möglichkeit, dies nur mit dem Methodennamen und der Signatur auszudrücken! Natürlich erfordert Ihre Klassendokumentation möglicherweise nicht diese Detailgenauigkeit, sondern ist nur ein Beispiel.


Inline-Kommentare sind auch nicht schlecht.

Schlechte Kommentare sind schlecht. Zum Beispiel Kommentare, die nur erklären, was trivial aus dem Code ersichtlich ist. Das klassische Beispiel ist:

// increment x by one
x++;

Kommentare, die etwas erklären, das durch Umbenennen einer Variablen oder Methode oder durch sonstige Umstrukturierung des Codes verdeutlicht werden könnte, sind ein Codegeruch:

// data1 is the collection of tasks which failed during execution
var data1 = getData1();

Dies sind die Kommentare, gegen die Martin spricht. Der Kommentar ist ein Symptom dafür, dass kein eindeutiger Code geschrieben wurde. In diesem Fall werden selbsterklärende Namen für Variablen und Methoden verwendet. Der Kommentar selbst ist natürlich nicht das Problem, das Problem ist, wir brauchen den Kommentar, um den Code zu verstehen.

Kommentare sollten jedoch verwendet werden, um alles zu erklären, was aus dem Code nicht ersichtlich ist, z. B. warum der Code auf eine bestimmte, nicht offensichtliche Weise geschrieben ist:

// need to reset foo before calling bar due to a bug in the foo component.
foo.reset()
foo.bar();

Kommentare, die erklären, was ein übermäßig verschlungenes Stück Code bewirkt, sind auch ein Geruch, aber die Korrektur besteht nicht darin, Kommentare zu verbieten, die Korrektur ist die Korrektur des Codes! Konvolutierter Code kommt zwar vor (hoffentlich nur vorübergehend bis zu einem Refactor), aber kein gewöhnlicher Entwickler schreibt beim ersten Mal perfekten, sauberen Code. Wenn verschachtelter Code vorkommt, ist es viel besser, einen Kommentar zu schreiben, der erklärt, was er tut, als keinen Kommentar zu schreiben. Dieser Kommentar erleichtert auch die spätere Umgestaltung.

Manchmal ist Code unvermeidlich komplex. Es kann sich um einen komplizierten Algorithmus handeln, oder es kann sich aus Gründen der Leistung um Code handeln, der die Klarheit beeinträchtigt. Auch hier sind Kommentare erforderlich.

JacquesB
quelle
13
Es gibt auch den Fall, dass Ihr Code mit einer Situation fertig wird , die nur kompliziert ist und mit der kein einfacher Code fertig werden kann.
gnasher729
6
Guter Punkt, Gnasher. Dies scheint häufig zu passieren, wenn Sie einen Teil des Codes für die Leistung optimieren müssen.
JacquesB
9
Sogar ein Kommentar in x++kann gut sein, wenn es so etwas wie "Inkrementiere x um eins, umlaufend, wenn es UINT32_MAX ist" ist; Jeder, der die Sprachspezifikation kennt, würde wissen, dass das Inkrementieren eines uint32_tZeilenumbruchs erfolgt, aber ohne den Kommentar weiß man möglicherweise nicht, ob ein solcher Zeilenumbruch ein erwarteter Teil des implementierten Algorithmus war.
Supercat
5
@ l0b0: Ich hoffe du machst Witze!
JacquesB
9
@ l0b0 Es gibt keinen temporären Code. Der Code wird nie überarbeitet, da das Unternehmen mit dem Ergebnis zufrieden war und keine Mittel zur Behebung des Problems genehmigt. In fünf Jahren wird dieser Code einigen Nachwuchsentwicklern angezeigt. Sie verwenden nicht einmal mehr WizBug 4.0, da Sie ihn durch Bugtrocity v9 ersetzt haben. "Bug123" bedeutet für ihn also nichts. Er denkt jetzt, dass dies der dauerhafte Code sein soll, und wird in seiner gesamten Karriere zu einem schrecklichen Entwickler. Denken Sie an die Kinder. Schreibe keinen temporären Code.
corsiKa
36

Es gibt einen Unterschied zwischen dem Kommentieren Ihres Codes und dem Dokumentieren Ihres Codes .

  • Kommentare werden benötigt, um den Code später zu pflegen, dh den Code selbst zu ändern.

    Kommentare können in der Tat als problematisch empfunden werden. Der äußerste Punkt wäre zu sagen, dass sie immer auf ein Problem hinweisen, entweder innerhalb Ihres Codes (Code zu schwer zu verstehen) oder innerhalb der Sprache (Sprache, die nicht expressiv genug sein kann; zum Beispiel könnte die Tatsache, dass die Methode niemals zurückgibt null, ausgedrückt werden durch Code Verträge in C #, aber es gibt keine Möglichkeit, es durch Code in PHP auszudrücken).

  • Die Dokumentation wird benötigt, um die von Ihnen entwickelten Objekte (Klassen, Interfaces) verwenden zu können. Die Zielgruppe ist anders: es ist nicht die Personen, die Ihren Code pflegen wird und es ändern , dass wir hier reden, sondern Menschen , die kaum müssen verwenden es.

    Das Entfernen der Dokumentation, weil der Code klar genug ist, ist verrückt, da die Dokumentation speziell dafür vorgesehen ist, Klassen und Interfaces zu verwenden, ohne Tausende von Codezeilen lesen zu müssen .

Arseni Mourzenko
quelle
Ja, aber zumindest ein Teil von Martins Argument ist, dass bei modernen Entwicklungspraktiken die Tests die Dokumentation und nicht der Code selbst sind. Angenommen, der Code wird mit einem BDD-ähnlichen Testsystem getestet, z. B. Specflow. Die Tests selbst sind eine direkt lesbare Beschreibung des Verhaltens der Methode ("wenn GetById mit der ID eines gültigen Produkts aufgerufen wird, wird eine Datenbank mit Produkten angegeben Das entsprechende Produktobjekt wird zurückgegeben, [...] wenn GetById mit einer ungültigen Produkt-ID aufgerufen wird, dann wird null zurückgegeben "oder so ähnlich).
Jules,
13

Ihr Kollege liest anscheinend Bücher, nimmt das, was er sagt, auf und wendet das Gelernte an, ohne nachzudenken und ohne Rücksicht auf den Kontext.

Ihr Kommentar zur Funktionsweise sollte so sein, dass Sie den Implementierungscode wegwerfen können. Ich lese den Kommentar der Funktion und kann den Ersatz für die Implementierung schreiben, ohne dass etwas schief geht.

Wenn mir der Kommentar nicht sagt, ob eine Ausnahme ausgelöst wird oder ob nil zurückgegeben wird, kann ich das nicht tun. Wenn der Kommentar nicht angibt , ob eine Ausnahme ausgelöst wird oder ob nil zurückgegeben wird, müssen Sie bei jedem Aufruf der Funktion sicherstellen, dass Ihr Code ordnungsgemäß funktioniert, unabhängig davon, ob eine Ausnahme ausgelöst oder nil zurückgegeben wird.

Ihr Kollege liegt also total falsch. Und lesen Sie alle Bücher, aber denken Sie selbst.

PS. Ich habe gesehen, dass Ihre Zeile "manchmal Teil einer Schnittstelle ist, sodass Sie nicht einmal wissen, welcher Code ausgeführt wird." Selbst bei virtuellen Funktionen wissen Sie nicht, welcher Code ausgeführt wird. Schlimmer noch, wenn Sie eine abstrakte Klasse geschrieben haben, gibt es nicht einmal Code! Wenn Sie also eine abstrakte Klasse mit einer abstrakten Funktion haben, sind die Kommentare, die Sie zur abstrakten Funktion hinzufügen, das einzige, woran sich ein Implementierer einer konkreten Klasse orientieren muss. Diese Kommentare sind möglicherweise auch das Einzige, was einen Benutzer der Klasse leiten kann. Wenn Sie beispielsweise nur eine abstrakte Klasse und eine Factory haben, die eine konkrete Implementierung zurückgibt, sehen Sie jedoch niemals einen Quellcode der Implementierung. (Und natürlich sollte ich nicht den Quellcode einer Implementierung betrachten).

gnasher729
quelle
Ich habe Code in 10 Jahren nicht kommentiert. Kommentare sind Blähungen, Müll. Heutzutage gibt es keinen Code für Kommentare. Wir konzentrieren uns auf wohlgeformten und benannten Code, kleine Module, Entkopplung usw. DAS macht Ihren Code lesbar, keine Kommentare. Tests stellen sicher, dass beim Wegwerfen von Code nichts schief geht, keine Kommentare. In Tests erfahren Sie, wie Sie den von Ihnen geschriebenen Code verwenden, wie Sie ihn aufrufen und warum er überhaupt vorhanden ist. Du bist viel zu alt, als dass du etwas über das Testen und Löschen von Code lernen musst, mein Freund.
PositiveGuy
12

Es gibt zwei Arten von Kommentaren, die für Benutzer mit dem Code sichtbar sind und zum Generieren von Dokumentation verwendet werden.

Die Art von Kommentar, auf die sich Onkel Bob bezieht, ist die Art, die nur für Personen mit dem Code sichtbar ist. Was er befürwortet, ist eine Form von TROCKEN . Für eine Person, die sich den Quellcode ansieht, sollte der Quellcode die Dokumentation sein, die sie benötigt. Selbst wenn Leute Zugriff auf den Quellcode haben, sind Kommentare nicht immer schlecht. Manchmal sind Algorithmen kompliziert oder Sie müssen erfassen, warum Sie einen nicht offensichtlichen Ansatz verfolgen, damit andere Ihren Code nicht beschädigen, wenn sie versuchen, einen Fehler zu beheben oder eine neue Funktion hinzuzufügen.

Die Kommentare, die Sie beschreiben, sind API-Dokumentation. Dies sind Dinge, die für Benutzer Ihrer Implementierung sichtbar sind, die jedoch möglicherweise keinen Zugriff auf Ihren Quellcode haben. Selbst wenn sie Zugriff auf Ihren Quellcode haben, arbeiten sie möglicherweise an anderen Modulen und sehen sich Ihren Quellcode nicht an. Diese Leute finden es nützlich, diese Dokumentation in ihrer IDE verfügbar zu haben, während sie ihren Code schreiben.

Thomas Owens
quelle
Ich habe ehrlich gesagt nie daran gedacht, dass DRY sich auf Code + Kommentare bezieht, aber es macht vollkommen Sinn. So ähnlich wie das Beispiel "Inkrement X" in der Antwort von @ JacquesB.
7

Der Wert eines Kommentars wird anhand des Werts der Informationen gemessen, die er liefert, abzüglich des Aufwands, der zum Lesen und / oder Ignorieren erforderlich ist. Also, wenn wir den Kommentar analysieren

/// <summary>
/// Retrieves a product by its id, returns null if no product was found.
/// </summary>

Bei Wert und Kosten sehen wir drei Dinge:

  1. Retrieves a product by its idwiederholt, was der Name der Funktion sagt, so dass die Kosten ohne Wert sind. Es sollte gelöscht werden.

  2. returns null if no product was foundist sehr wertvolle Information. Dies verringert wahrscheinlich die Zeit, die andere Programmierer für die Implementierung der Funktion benötigen. Ich bin mir ziemlich sicher, dass es mehr Lesekosten spart als die Lesekosten, die es selbst verursacht. Es sollte bleiben.

  3. Die Linien

    /// <summary>
    /// </summary>
    

    Tragen Sie keine Informationen. Sie sind reine Kosten für den Leser des Kommentars. Sie können gerechtfertigt sein, wenn Ihr Dokumentationsgenerator sie benötigt, aber in diesem Fall sollten Sie wahrscheinlich über einen anderen Dokumentationsgenerator nachdenken.

    Aus diesem Grund ist die Verwendung von Dokumentationsgeneratoren umstritten: Sie erfordern im Allgemeinen viele zusätzliche Kommentare, die keine Informationen enthalten oder offensichtliche Dinge wiederholen, nur um ein poliertes Dokument zu erhalten.


Eine Beobachtung, die ich in keiner der anderen Antworten gefunden habe:

Auch Kommentare, die zum Verstehen / Verwenden des Codes nicht erforderlich sind, können sehr wertvoll sein. Hier ist ein solches Beispiel:

//XXX: The obvious way to do this would have been ...
//     However, since we need this functionality primarily for ...
//     doing this the non-obvious way of ...
//     gives us the advantage of ...

Wahrscheinlich viel Text, völlig unnötig, um den Code zu verstehen / zu verwenden. Es erklärt jedoch einen Grund, warum der Code so aussieht, wie er aussieht. Es wird die Leute davon abhalten, sich den Code anzuschauen, sich zu fragen, warum es nicht auf die offensichtliche Weise getan wird, und würde anfangen, den Code umzugestalten, bis sie erkennen, warum der Code überhaupt so geschrieben wurde. Und selbst wenn der Leser klug genug ist, nicht direkt zum Refactoring zu springen, muss er erst herausfinden, warum der Code so aussieht, wie er aussieht, bevor er erkennt, dass er am besten so bleibt, wie er ist. Dieser Kommentar könnte buchstäblich Stunden Arbeit sparen. Somit ist der Wert höher als die Kosten.

Ebenso können Kommentare die Absichten eines Codes kommunizieren, anstatt nur, wie es funktioniert. Und sie können das große Bild zeichnen, das normalerweise im kleinsten Detail des Codes selbst verloren geht. Als solches sind Sie zu Recht für Kommentare in der Klasse. Ich schätze Kommentare zu Klassen am meisten, wenn sie die Absicht der Klasse erklären, wie sie mit anderen Klassen interagiert, wie sie verwendet werden soll usw. Leider bin ich kein großer Autor solcher Kommentare ...

cmaster
quelle
2
Wow - ändern Sie Ihren Dokumentgenerator, weil er ein paar zusätzliche Zeilen HTML zum Parsen benötigt? Lass uns nicht.
corsiKa
2
@corsiKa YMMV, aber ich würde einen Dokumentationsgenerator bevorzugen, der die Kosten für Kommentare auf ein Minimum reduziert. Natürlich würde ich auch lieber eine gut geschriebene Header-Datei lesen als eine Doxy-Dokumentation, die nicht mit dem tatsächlichen Code synchron ist. Aber wie gesagt, YMMV.
cmaster
4
Selbst wenn der Name einer Methode ihren Zweck brillant beschreibt, kann es für jemanden, der ihn liest, einfacher sein, diesen Zweck mit den folgenden Vorbehalten in Verbindung zu bringen, wenn er diesen Zweck in natürlicher Sprache wiederholt. Eine Wiederholung dessen, was im Namen beschrieben wird, ist kurz genug, so dass die Kosten auch dann niedrig sind, wenn der Wert niedrig ist. Ich bin daher mit dem ersten Teil Ihres Beitrags nicht einverstanden. +1 jedoch für den zweiten Teil. Die Dokumentation von alternativen Ansätzen, die bewertet und abgelehnt wurden, kann äußerst wertvoll sein, doch wird solchen Informationen selten die gebührende Aufmerksamkeit geschenkt.
Supercat
GetByIdwirft die Frage auf, was id ist und was woher. Der Dokumentationskommentar sollte es der Entwicklungsumgebung ermöglichen, Antworten auf diese Fragen anzuzeigen. Sofern es nicht an anderer Stelle in den Moduldokumentationskommentaren erläutert wird, ist es auch eine Stelle, an der angegeben wird, warum die ID ohnehin abgerufen wird.
Hyde
Kommentare blasen, sauberer Code (selbstbeschreibend), TDD (häufiges Feedback und häufiges Feedback zu Ihrem Design) und Testregeln (geben Ihnen Vertrauen und dokumentieren das Verhalten)! TESTS people TESTS. Ein Niemand hier spricht darüber. wach auf
PositiveGuy
4

Nicht kommentierter Code ist ungültiger Code. Es ist ein weit verbreiteter (wenn nicht universeller) Mythos, dass Code auf die gleiche Weise gelesen werden kann wie beispielsweise Englisch. Es muss interpretiert werden und nur für den einfachsten Code, der Zeit und Mühe kostet. Darüber hinaus hat jeder eine unterschiedliche Fähigkeit, eine bestimmte Sprache zu lesen und zu schreiben. Unterschiede zwischen dem Autor und den Codierungsstilen und -fähigkeiten des Lesers sind starke Hindernisse für eine genaue Interpretation. Es ist auch ein Mythos, dass Sie die Absicht des Autors aus der Implementierung des Codes ableiten können. Nach meiner Erfahrung ist es selten falsch, zusätzliche Kommentare hinzuzufügen.

Robert Martin et al. halte es für einen "schlechten Geruch", da es sein kann, dass der Code geändert wird und die Kommentare nicht. Ich sage, es ist eine gute Sache (genauso wie dem Haushaltsgas ein "schlechter Geruch" beigemischt wird, um den Benutzer auf Undichtigkeiten aufmerksam zu machen). Durch das Lesen von Kommentaren erhalten Sie einen nützlichen Ausgangspunkt für die Interpretation des eigentlichen Codes. Wenn sie übereinstimmen, haben Sie mehr Vertrauen in den Code. Wenn sie sich unterscheiden, haben Sie einen Warngeruch festgestellt und müssen weitere Untersuchungen durchführen. Die Heilung eines "schlechten Geruchs" besteht nicht darin, den Geruch zu beseitigen, sondern das Leck abzudichten.

Vince O'Sullivan
quelle
2
Vorausgesetzt, Sie sind ein intelligenter Autor und der Text ist zum Nutzen eines intelligenten Publikums. Sie ziehen die Linie mit gesundem Menschenverstand. So wie es aussieht, ist das Beispiel natürlich dumm, aber das heißt nicht, dass es keinen sehr guten Grund geben kann, mit einem Kommentar zu verdeutlichen, warum der Code an dieser Stelle ein i ++ enthält.
Vince O'Sullivan
8
i++; // Adjust for leap years.
Vince O'Sullivan
5
"Robert Martin et al. Halten es für einen" schlechten Geruch ", weil möglicherweise der Code geändert wird und die Kommentare nicht." Das ist nur ein Teil des Geruchs. Der schlimmste Grund für den Geruch ist die Idee, dass der Programmierer beschlossen hat, den Code nicht in einer aussagekräftigeren Form zu schreiben, sondern stattdessen das Leck mit einem Kommentar abzudichten. Seine Behauptung ist, dass man im Code selbst (oder ähnlichem) wahrscheinlich eine Methode "adjustForLeapYears ()" haben sollte, anstatt einen Kommentar "// adjust for leap years" zu setzen. Die Dokumentation besteht aus Tests, die die Schaltjahrlogik anwenden.
Eric King
3
Ich würde in Betracht ziehen, einen Methodenaufruf hinzuzufügen, um eine einzelne Codezeile durch einen Kommentar-Overkill zu ersetzen, zumal der Name der Methode selbst nur ein Kommentar ist, der einen Codeteil kennzeichnet und keine Garantie für eine bessere Dokumentationsgenauigkeit gibt. (Wenn diese Zeile an zwei oder mehr Stellen vorkommt, ist die Einführung eines Methodenaufrufs natürlich genau die richtige Lösung.)
Vince O'Sullivan,
1
@Jay Der Grund dafür ist, dass es die Regel ist, Ihre Abstraktionen explizit zu machen (z. B. indem Sie Methoden einführen) . Dies nicht zu tun, weil Sie möglicherweise eine Methode mit einer Zeile haben, ist die Ausnahme. Lassen Sie mich die echte willkürliche Regel umschreiben: "Verwenden Sie die Strukturen Ihrer Programmiersprache (normalerweise Methoden und Klassen), um Abstraktionen einzuführen, es sei denn, die Implementierung dieser Abstraktion kann als eine Codezeile ausgedrückt werden. Geben Sie in diesem Fall die Abstraktion in natürlicher Sprache durch Hinzufügen an ein Kommentar."
Eric
3

In einigen Sprachen (z. B. F #) kann der gesamte Kommentar / die gesamte Dokumentation tatsächlich in der Methodensignatur ausgedrückt werden. Dies liegt daran, dass in F # null im Allgemeinen kein zulässiger Wert ist, es sei denn, dies ist ausdrücklich zulässig.

Was in F # (und auch in mehreren anderen funktionalen Sprachen) üblich ist, ist, dass Sie anstelle von null einen Optionstyp verwenden, Option<T>der entweder Noneoder sein kann Some(T). Die Sprache würde dies dann verstehen und Sie dazu zwingen (oder Sie warnen, wenn Sie dies nicht tun), in beiden Fällen übereinzustimmen, wenn Sie versuchen, es zu verwenden.

So könnten Sie beispielsweise in F # eine Signatur haben, die so aussieht

val GetProductById: int -> Option<Product>

Und dann wäre dies eine Funktion, die einen Parameter (ein int) annimmt und dann entweder ein Produkt oder den Wert None zurückgibt.

Und dann könnten Sie es so benutzen

let product = GetProduct 42
match product with
| None -> printfn "No product found!"
| Some p -> DoThingWithProduct p

Und Sie würden Compiler-Warnungen erhalten, wenn Sie nicht beide möglichen Fälle übereinstimmen. Es gibt also keine Möglichkeit, dort Nullreferenzausnahmen zu erhalten (es sei denn, Sie ignorieren natürlich die Compiler-Warnungen), und Sie wissen alles, was Sie brauchen, indem Sie sich nur die Funktionssignatur ansehen.

Dies setzt natürlich voraus, dass Ihre Sprache so gestaltet ist - was bei vielen gängigen Sprachen wie C #, Java, C ++ usw. nicht der Fall ist. Dies ist in Ihrer aktuellen Situation möglicherweise nicht hilfreich. Aber es ist (hoffentlich) schön zu wissen, dass es Sprachen gibt, mit denen Sie diese Art von Informationen statisch schreiben können, ohne auf Kommentare usw. zurückgreifen zu müssen :)

wasatz
quelle
1

Hier gibt es einige ausgezeichnete Antworten und ich möchte nicht wiederholen, was sie sagen. Aber lassen Sie mich ein paar Kommentare hinzufügen. (Kein Wortspiel beabsichtigt.)

Es gibt viele Aussagen, die kluge Leute machen - über Softwareentwicklung und viele andere Themen, nehme ich an -, die sehr gute Ratschläge sind, wenn sie im Kontext verstanden werden, aber die dumme Leute nicht aus dem Kontext nehmen oder in unangemessenen Situationen anwenden oder anwenden lächerliche Extreme.

Die Idee, dass Code selbstdokumentierend sein sollte, ist eine solche hervorragende Idee. Im wirklichen Leben gibt es jedoch Grenzen für die praktische Anwendbarkeit dieser Idee.

Ein Haken ist, dass die Sprache möglicherweise keine Funktionen bietet, mit denen dokumentiert werden kann, was klar und präzise dokumentiert werden muss. Wenn sich die Computersprachen verbessern, wird dies immer weniger zum Problem. Aber ich denke nicht, dass es vollständig verschwunden ist. In den Tagen, in denen ich in Assembler schrieb, war es sehr sinnvoll, einen Kommentar wie "Gesamtpreis = Preis für nicht steuerpflichtige Artikel plus Preis für steuerpflichtige Artikel plus Preis für steuerpflichtige Artikel * Steuersatz" einzufügen. Es war nicht unbedingt offensichtlich, was sich zu einem bestimmten Zeitpunkt in einem Register befand. Es dauerte viele Schritte, um eine einfache Operation durchzuführen. Aber wenn Sie in einer modernen Sprache schreiben, wäre ein solcher Kommentar nur eine Neuformulierung einer Codezeile.

Ich ärgere mich immer, wenn ich Kommentare wie "x = x + 7; // addiere 7 zu x" sehe. Wie, wow, danke, wenn ich vergessen hätte, was ein Pluszeichen bedeutet, das sehr hilfreich gewesen sein könnte. Wo ich wirklich verwirrt sein könnte, ist zu wissen, was "x" ist oder warum es erforderlich war, zu diesem bestimmten Zeitpunkt eine 7 hinzuzufügen. Dieser Code kann sich selbst dokumentieren, indem Sie "x" einen aussagekräftigeren Namen geben und statt 7 eine symbolische Konstante verwenden. Wenn Sie beispielsweise "total_price = total_price + MEMBERSHIP_FEE;" geschrieben haben, ist ein Kommentar wahrscheinlich überhaupt nicht erforderlich .

Es klingt gut zu sagen, dass ein Funktionsname genau sagen sollte, was eine Funktion tut, damit zusätzliche Kommentare überflüssig werden. Ich habe gute Erinnerungen an die Zeit, als ich eine Funktion schrieb, die überprüfte, ob eine Artikelnummer in unserer Datenbank war. Die Artikeltabelle gab entweder wahr oder falsch zurück und ich nannte sie "ValidateItemNumber". Schien wie ein anständiger Name. Dann kam jemand anderes und änderte diese Funktion, um auch eine Bestellung für den Artikel zu erstellen und die Datenbank zu aktualisieren, änderte aber nie den Namen. Jetzt war der Name sehr irreführend. Es hörte sich an, als ob es eine kleine Sache getan hätte, obwohl es wirklich viel mehr getan hätte. Später nahm jemand sogar den Teil über die Validierung der Artikelnummer heraus und tat das woanders, änderte aber trotzdem den Namen nicht. Also, obwohl die Funktion jetzt nichts mit der Validierung von Artikelnummern zu tun hatte,

In der Praxis ist es jedoch häufig unmöglich, dass ein Funktionsname die Funktion vollständig beschreibt, ohne dass der Name der Funktion so lang ist wie der Code, aus dem diese Funktion besteht. Sagt uns der Name genau, welche Validierungen für alle Parameter durchgeführt werden? Was passiert unter Ausnahmebedingungen? Alle möglichen Unklarheiten darlegen? Irgendwann würde der Name so lang werden, dass er nur noch verwirrend wird. Ich würde String BuildFullName (String Vorname, String Nachname) als anständige Funktionssignatur akzeptieren. Auch wenn dies nicht aussagt, ob der Name "first last" oder "last, first" oder eine andere Variation ist, was passiert, wenn einer oder beide Teile des Namens leer sind, wenn die kombinierte Länge und begrenzt werden was es tut, wenn das überschritten wird,

Jay
quelle