Viel zu viele Kommentare???
-
Original erstellt von <Stift>:
**Den habe ich gerade gefunden. Ist das nicht ein bisschen übertrieben mit den
Kommentaren?
**Ist doch super Dokumentiert.
Ich hab' schon Teile gesehen, da war noch viel
mehr Kommentar drin - ohne dass es zu viel war!Inhaltlich sollte das aber überarbeitet werden! Anpassen nach Copy/Paste
-
Ich habe mir schon vor Jahren angewöhnt, jede Methode am Kopf ausführlich und (für mich) genormt zu dokumentieren. Ich habe mal eine Stringklasse geschrieben und die immer wieder erweitert. Wenn ich hierzu keine Dokumentation gemacht hätte (im Source und als seperates Word-Dokument), würd ich ständig mit der Nase im alten Source hängen und kucken, was da tatsächlich passiert.
Hier mal eine Kostprobe einer etwas komplexeren Methode:
UBYTE __fastcall TStringMachine::CompEx(STRP strpFirst, STRP strpSecond, BOOL blCaseSensitive, ULONG lFSize, ULONG lSSize, ULONG lFPos, ULONG lSPos) { /***[FUNKTION 0032h]********************************************************* ANMERKUNG ------------------------------------------------------------------- Stark erweiterte Version von Comp: vergleicht zwei Strings miteinander, wobei es sich bei jedem String um einen STRP, STRZP oder SHANDLE handeln kann. Auch Teilstrings können miteinander verglichen werden. Die Stringgrößen können gleich oder unterschiedlich sein. Als zusätzli-ches Feature kann angegeben werden, ob Groß/Kleinschreibung berücksichtigt werden soll oder nicht. AUFRUF ---------------------------------------------------------------------- STRP strpFirst {1 bis X + [CPT_SHANDLE]} STRP strpSecond {1 bis X + [CPT_SHANDLE]} Zeiger auf den ersten String, der mit dem zweiten String verglichen werden soll. Handelt es sich bei dem String um einen SHANDLE, so ist das Flag CPT_SHANDLE zu setzen (über Makro SM_STRING(x) möglich). Handelt es sich um einen STRP, so muß die Größe des Strings zwingend in lFSize bzw. lSSize angegeben werden. HINWEIS: die Stringtypen von strpFirst und strpSecond dürfen voneinander abweichen! BOOL blCaseSensitive {FALSE, TRUE} [STANDARD: FALSE] Wird FALSE (Standardwert) angegeben, wird keine Unterscheidung bei Groß/ Kleinbuchstaben vorgenommen. Dabei werden auch die deutschen Umlaute (ä, ö, ü) korrekt umgesetzt! Wird hingegen FALSE angegeben, so wird jedes Zeichen mit seinem Zeichencode (Grundlage bildet dabei der ANSI-Zeichencode) bewertet. ULONG lFSize {0 bis SM_MAXSIZE} [STANDARD: NULL] ULONG lSSize {0 bis SM_MAXSIZE} [STANDARD: NULL] Hier kann die Größe des Strings in strpFirst bzw. strpSecond in Bytes angegeben werden. Handelt es sich bei strpFirst bzw. strpSecond um einen STRP, muß die Größe zwingend angegeben werden, andernfalls ist die Angabe optional. Wird NULL (Standardwert) angegeben, bestimmt die Methode die Stringgröße selbst (bei STRZP bis zu einem abschließenden Nullbyte; bei SHANDLE bis zum Stringende). Bei einem SHANDLE wird lFSize bzw. lSSize maximiert! ULONG lFPos {0 bis X} [STANDARD: NULL] ULONG lSPos {0 bis X} [STANDARD: NULL] Diese Parameter geben an, ab welchem Offset mit dem Vergleich begonnen werden soll. Der Wert wird auf die Adresse in strpFirst bzw. strpSecond aufaddiert. Ein Wert von NULL besagt, daß beim ersten Zeichen begonnen werden soll, ein Wert von 1 bezieht sich auf die zweite Zeichenposition und so weiter. Der Offset macht hauptsächlich bei SHANDLEs Sinn, weil damit (ggf. in Verbindung mit lFSize bzw. lSSize) Teilstrings definiert werden können, ohne diese vorher extrahieren zu müssen. RÜCKGABE -------------------------------------------------------------------- UBYTE {Fehler: NULL, Erfolg: siehe nachfolgende Auflistung} Konnten beide Strings miteinander verglichen werden, wird das Testergebnis mitgeteilt. Wurden unzulässige Parameter angegeben, wird lediglich NULL zurückgeliefert. Das Ergebnis ist stets als Vergleich von strpFirst mit strpSecond zu sehen. Sind alle Zeichen von strpFirst in strpSecond enthalten, wird SMC_EQUAL zurückgeliefert. Ist mindestens ein Zeichen unterschiedlich, wird SMC_UNEQUAL zurückgegeben. Sind alle Zeichen von strpFirst in strpSecond enthalten, aber sind beide Strings unterschiedlich groß, wird neben SMC_EQUAL auch SMC_GREATER (strpFirst > strpSecond) oder SMC_LESS (strpFirst < strpSecond) zurückgegeben. Sind beide String unterschiedlich, wird SMC_UNEQUAL zurückgegeben und die Aussage, ob der String in strpFirst bei einer Sortierung größer (SMC_GREATER) oder kleiner (SMC_LESS) ist. Beispiele: strpFirst = "Test" strpSecond = "Testzweck" Ergebnis: SMC_EQUAL|SMC_LESS, weil strpFirst kleiner als strpSecond ist, aber alle Zeichen von strpFirst in strpSecond vorkommen. strpFirst = "Testzweck" strpSecond = "Test" Ergebnis: SMC_UNEQUAL|SMC_GREATER, weil strpFirst größer als strpSecond ist und nicht alle Zeichen von strpFirst in strpSecond vorkommen. strpFirst = "Test" strpSecond = "Test" Ergebnis: SMC_EQUAL, weil alle Zeichen von strpFirst in strpSecond vorkommen und beide Strings exakt gleich groß sind. strpFirst = "ABCD" strpSecond = "FGD" Ergebnis: SMC_UNEQUAL|SMC_LESS, weil strpFirst nicht in strpSecond vorkommt und bei einer Sortierung vor strpSecond angesiedelt ist. ****************************************************************************/
Die Formatierug sieht hier vermutlich etwas blöd aus, ist aber auch auf 76 Zeichen/Zeile ausgelegt.
Es kostet zwar eine gewisse Disziplin, aber es rentiert sich, wenn man die Sachen später wiederverwenden will und das ist ja heutzutage nicht unwichtig.
Wenn ich neue Klassen bilde, schreib ich meist ein Word-Dokumentationsfile dazu und dokumentiere erstmal alle öffentlichen Methoden und Eigenschaften. Dann erst wieder codiert. Interne Methoden dokumentiere ich allerdings nur im Source.
Beruflich würde ich natürlich alles komplett dokumentieren, aber für privat reichts sicherlich ausAußerdem denkt man durch diese Vorgehensweise erstmal ein bissel nach und codiert erst dann, so daß man sich viele Neuprogrammierungen sparen kann.
Kann ich also nur empfehlen. Die Doku oben find ich übrigens nach dem ersten Augenschein auch nicht schlecht, wenn man sicher auch noch ausführlicher sein könnte....
-
Original erstellt von JFK:
Hier mal eine Kostprobe einer etwas komplexeren MethodeDas kann ja wohl unmöglich dein Ernst sein...:)
-
wieso nicht?
-
Der ist besonders gut:
/* Wird FALSE (Standardwert) angegeben, wird keine Unterscheidung bei Groß/ Kleinbuchstaben vorgenommen. Dabei werden auch die deutschen Umlaute (ä, ö, ü) korrekt umgesetzt! Wird hingegen FALSE angegeben, so wird jedes Zeichen mit seinem Zeichencode (Grundlage bildet dabei der ANSI-Zeichencode) bewertet. */
Warum das nicht dein Ernst sein kann? Aus mehreren Gründen:
1. Eine so ausführliche Dokumentation gehört nicht in den Code. Im Code soll knapp und präzise beschrieben sein, wie man die Funktion aufruft oder was sie macht. Einen Parameter wie CaseSensitive zu dokumentieren, ist nicht wirklich sinnvoll. Der ist selbsterklärend. Der Hinweis mit den Umlauten gehört in die externe Doku.
2. Wenn der Rückgabewert so klar und einfach über Flags definiert ist, reicht es die möglichen Flags kurz aufzulisten. Normalerweise sollte der Name schon aussagekräftig genug sein, sodass man gar nicht mehr in die Doku schauen muss.
3. Beispiele gehören nicht in Kommentare. Schon gar nicht so viele.btw:
Wie war das nochmal mit dem Präfix?
-
Also da muß ich wiedersprechen. Wer bitteschön sagt mir, daß ich im Source zu einer Methode keine 10, 20 oder 100 Zeilen Kommentar reinschreiben kann? Wie ich bereits schrieb, ist die Funktionsbeschreibung aus der zugehörigen Dokumentation übernommen (natürlich nur die Texte, die Darstellung in der Doku sieht ein bissel anders aus).
Außerdem hab ich mir ein Tool geschrieben, welches in der Lage ist, die Kommentare zu einer Methode auf Knopfdruck anzuzeigen. Das kann die Dokumentation oftmals ersetzen, wenn bekannt ist, wie die Klasse zu bedienen ist bzw. wie die Schnittstelle zu bedienen ist.
Hat man mehrere Klassen und für jede eine Dokumentation (am Besten dann gleich ausgedruckt), ist man nämlich nur noch am rumblättern und wird irgendwann von einer Leitz-Ordner-Lawine erschlagen.
Zum CaseSensitive: wer sagt Dir denn, daß es "normal" ist, die deutschen Umlaute zu berücksichtigen? Wenn ich alles, was ich als normal empfinde, annehmen würde, dann hätte ich einige Probleme.
Was die Beispiele anbelangt, so gilt das oben gesagte. Manchmal sind 3 Beispiele besser als gar keines.
Das ist übrigens nur ein Beispiel einer Methode gewesen. Andere Methoden können durchaus kürzer sein.
Abgesehen davon ist das halt meine Methode, meinen Source zu dokumentieren und es war ja nur ein Vorschlag, wie ich das handhabe. Ich bin überzeugt, daß das die wenigsten so machen, aber das is nich mein Problem, weil ich deren Code nicht in meinen Programmen habe....
Noch ein Letztes zu dem Präfix: an so einer Diskussion beteilige ich mich nicht (mehr). Jeder sollte seinen Stil haben und ihn beibehalten, wenn er sich für ihn als nützlich herausgestellt hat. Arbeiten mehrere Leute zusammen, bietet es sich natürlich an, sich auf eine Vorgehensweise zu einigen. Allerdings halte ich am Präfix fest, weil ich das extrem sinnvoll finde und mich längst daran gewöhnt habe. Dadurch komme ich auch gar nich erst auf die Idee, einem strpPtr einen iValue zuzuweisen.
-
Ich würde auch so lange Doku´s in den Code schreiben. Obwohl die Parameter / Funktionsnamen für sich sprechen sollten.
Mit Doxygen eine Docu draus machen, und passt!
Meine Header docs sehen so aus:
//! Returns how much files matching the mask /*! Files returned in sOutFile You need to free the struct with IPacker::FreeFileStruct( SPackFile **sPackFile ) */ virtual unsigned int FindFiles( SPackFile **sOutFile, const char *_chMask ) = 0; //! Free´s the file struct - allocated in FindFiles virtual void FreeFileStruct( SPackFile **sPackFile ) = 0; //! Returns the compression level /*! 1 is low compression and the best speed 9 is the best 0 is no compression */ virtual int GetCompressionLevel() = 0;
Und im Source:
bool CPacker::CompressRam( char **_chCompressed, int &_iCompresedSize, char *_chData, int _iSize ) { PUSH_TREE( "CompressRam", "CPacker" ); // Allocate memory for the compressed data *_chCompressed = new char[ _iSize * 2 + 100 ];// char[ _iSize + 100 ]; _iCompresedSize = _iSize + 100; // Compress if( PrintError( compress2( (unsigned char*)*_chCompressed, (unsigned long*)&_iCompresedSize, (const Bytef*)_chData, _iSize, iCompressionLevel ) ) ) { delete [] *_chCompressed; POP_TREE(); return false; } POP_TREE(); // Done successful return true; }
Ist jetzt nur kleines Beispiel, aber wer versuch nach 1 Jahr den Code wieder zu lesen, dankt es sich sebst, wenn er viel Docu geschrieben hat.
Lieber zuviel Docu als zu wenig! Wenn man ohne sie auskommt, dann ists auch gut. Man muß sie ja nicht lesen
-
@ SnorreDev: Ich dachte, man soll keine Unterstriche bei Variablennamen voranstellen!? Habe ich da etwas falsch verstanden?
Da ist eine typische von mir geschriebene und dokumentierte Javaklasse
:
[java]
package myMath.function.distribution;import myMath.function.*;
public class Gaussian extends Distribution
{
private Function gaussian;public Gaussian (int dimensions, float standardDeviation)
{
Function normalizer = new ConstFunction ((float)(standardDeviation*
standardDeviation*2.0*Math.PI));
normalizer = new PowerFunction (normalizer,
new ConstFunction (-0.5f*(float)dimensions));
Function [] tempFunctions = new Function [dimensions];
for (int i = 0 ; i < dimensions ; ++i)
{
tempFunctions[i] = new PowerFunction (new Variable(i),
new ConstFunction(2.0f));
}
Function exponent = new AddFunction (tempFunctions);
exponent = new MultiplyFunction (new ConstFunction (-1.0f),exponent);
exponent = new DivideFunction (exponent,
new ConstFunction (2.0f*standardDeviation*standardDeviation));
gaussian = new MultiplyFunction (normalizer,new ExpFunction(exponent));
}public float getValue(float[] variables)
{
return gaussian.getValue(variables);
}protected Function getDerivative(int variable)
{
return gaussian.derive(variable);
}public Function simplify()
{
return gaussian.simplify();
}public String toString ()
{
return gaussian.toString();
}
}[/code]
...ich finde, die Doku reicht vollkommen aus. Ich sehe keine Stelle, wo mehr Doku mehr Lesbarkeit bringt, die jemand benötigt, der die Klasse benutzt.BTW: Was mir beim ersten Code noch auffällt:
Mir ist nicht ganz klar, ob der Schreiber davon ausgeht, ob der, der den Code liest Deutsch spricht, oder ob er Englisch spricht.
Wenn er Deutsch sprechen soll: Warum sind die Variablennamen auf Englisch?
Wenn er Englisch sprechen soll: Warum ist die Doku auf Deutsch?[ Dieser Beitrag wurde am 05.07.2003 um 07:46 Uhr von Gregor editiert. ]
-
also für mich ist das das krasse Gegenbeispiel zu meinem. Um zu wissen, was die Methode leistet, muß ich mir erstmal den Code ankucken. Bei den reinen Zugriffsmethoden mag das ja noch angehen.
Aber selbst da tut eine kurze Info Not, WAS denn da eigentlich zurückkommt und welche Wertbereiche da möglich sind.
Wenn ich 50 Klassen verwenden muß und hab keinerlei Anhaltspunkte, was das passiert, dann bin ich als Programmierer aber wirklich arm dran, wenn ich mich durch alle Methoden durchwühlen muß, bis ich die richtige Gefunden hab.
Meiner Meinung nach extrem kurzsichtig gedacht.... oder Du bist so ein Genie, daß du schneller den Code im Kopf in eine Programmdoku umsetzt, also 4 Sätze zu lesen.... Ist aber eher zu bezweifeln.
-
Original erstellt von JFK:
**
Wenn ich 50 Klassen verwenden muß und hab keinerlei Anhaltspunkte, was das passiert, dann bin ich als Programmierer aber wirklich arm dran, wenn ich mich durch alle Methoden durchwühlen muß, bis ich die richtige Gefunden hab.Meiner Meinung nach extrem kurzsichtig gedacht.... oder Du bist so ein Genie, daß du schneller den Code im Kopf in eine Programmdoku umsetzt, also 4 Sätze zu lesen.... Ist aber eher zu bezweifeln.**
Dann bin ich vermutlich ein Genie, da ich mich auch nach Monaten noch ohne Probleme in meinem Programm zurechtfinde. Das besteht momentan aus 185 Klassen mit ähnlicher Kommentierung. Zugegeben: Hin und wieder steht auch ne Zeile Kommentar drin.
IMHO ist es klar, was die Methoden machen. Wenn da eine Methode getDerivative steht, dann bringt mir ein Kommentar in der Form "Returns the derivative" auch nichts. Wenn man seinen Methoden natürlich Namen, wie "bmc_ioctl" gibt, dann kommt man nach 2 Wochen nicht mehr ohne weiteres dadrauf, was die Methode macht. Da braucht man dann schon Kommentare.
-
vielleicht kommst Du auch mal in die Lage, etwas zu programmieren, daß Du fachlich nicht so verstehst, oder mit dem Du Dich programmtechnisch nicht so auskennst.
Ich habe bei uns in der Firma mehr als genug Beispiele, wo man alte Programme pflegen muß und immer wieder Stellen findet, die man erstmal in die Fachlichkeit zurückinterpretieren muß. Da wär ich mit Deinem Beispiel schnell am Ende und leider gibt und gab es auch bei uns viele Leute, die es ähnlich wie Du halten, weil es ihnen ja klar ist, was sie machen. Aber wehe, sie wechseln ihre Zuständigkeiten, kündigen, gehen in Rente oder kriegen nix mehr auf die Reihe...
Aber wie gesagt. Ich kann nur aus meiner Sicht schildern, wie ich es für mich persönlich ok finde. Ich programmiere auch nicht erst seit vorgestern und jeder macht seine eigenen Erfahrungen.
-
Original erstellt von JFK:
vielleicht kommst Du auch mal in die Lage, etwas zu programmieren, daß Du fachlich nicht so verstehst,Wenn du dich fachlich nicht in dem Gebiet auskennst, helfen auch keine Kommentare. Die brauchen schließlich auch eine Basis, auf der sie aufsetzen.
-
Natürlich tun sie das. Aber meistens kommt man eher von der fachlichen Seite zum Programm und nicht umgekehrt. Weil die fachliche Sache kann ich jemanden relativ schnell grundlegend erklären. Ein Programm hingegen nicht. Außerdem kann jemand, der sich fachlich auskennt, aber das Programm nicht kennt, viel schneller verstehen, um was es da gerade gehen soll.
Ich glaube, daß war auch generell der Grundgedanke von Kommentaren...
Insofern hab ich zu dem Thema jetzt genug geschrieben. Will hier ja niemanden missionieren. Jeder soll sich sein Himmel- oder Höllenreich selber schreiben...
-
Gregor - stell dir mal vor, du fängst in einer Firma an. Du kriegst ein begonnenes GP System vor die Nase gesetzt. ( GP = Genetic Programming )
Du sollst es erweitern, oder Teile ändern.Wenn das Ding nicht richtig Kommentiert ist, bist du ein armes Schwein. Mit Glück ist vielleicht noch die Person da, die den Code geschrieben hat, mit Pech, hat er gekündigt oder ähnliches, und du stehst als armes Würstchen vor X Klassen, die unkommentiert sind.
Du wirst ihn Verfluchen. Wenn´s kommentiert ist, findest du dich viel schneller zurecht
-
Real Programmers don't comment their code. If it was hard to write, it should be hard to understand.