Welche Dinge läuten beim Betrachten von Code sofort Alarmglocken? [geschlossen]

98

Ich habe vor ein paar Wochen an einer Veranstaltung zum Thema Software-Handwerk teilgenommen, und einer der Kommentare lautete: "Ich bin sicher, wir alle erkennen schlechten Code, wenn wir ihn sehen."

Diese Art von Dingen beunruhigt mich immer, da es diese Binsenweisheit gibt, die jeder für einen überdurchschnittlichen Fahrer hält. Obwohl ich denke, dass ich schlechten Code erkennen kann, würde ich gerne mehr darüber erfahren, was andere Leute als Codegerüche betrachten, da dies in den Blogs der Leute selten und nur in einer Handvoll Büchern ausführlich besprochen wird. Insbesondere finde ich es interessant, etwas zu hören, das in einer Sprache nach Code riecht, aber nicht in einer anderen.

Ich beginne mit einem einfachen:

Code in der Quellcodeverwaltung mit einem hohen Anteil an auskommentiertem Code - warum ist er dort? sollte es gelöscht werden? ist es eine halbfertige Arbeit? Vielleicht hätte es nicht auskommentiert werden sollen und wurde nur gemacht, wenn jemand etwas ausprobierte? Persönlich finde ich solche Dinge wirklich ärgerlich, auch wenn es hier und da nur die eine oder andere Zeile ist, aber wenn Sie große Blöcke sehen, die mit dem Rest des Codes durchsetzt sind, ist das völlig inakzeptabel. Dies ist normalerweise auch ein Hinweis darauf, dass der Rest des Codes wahrscheinlich ebenfalls von zweifelhafter Qualität ist.

FinnNk
quelle
61
Manchmal stoße ich auf Leute, die Code auskommentieren, einchecken und sagen: "Vielleicht brauche ich ihn in Zukunft wieder - wenn ich ihn jetzt entferne, verliere ich ihn." Ich muss mit "Er, ... aber dafür ist die Quellcodeverwaltung" kontern.
Talonx
6
Manchmal, besonders beim Optimieren, ist es praktisch, den alten Code als Kommentar zu hinterlassen, damit Sie wissen, was der obskure optimierte Code ersetzt. Denken Sie daran, einen 3-Zeilen-Swap mit Temp zu belassen, wenn Sie ihn durch einen einzeiligen Twiddling-Swap ersetzen. (Obwohl ich keine Notwendigkeit sehe, einen einzeiligen Tausch zu verwenden - NIEMALS, es sei denn, die Programmgröße ist von entscheidender Bedeutung.)
Chris Cudmore
4
Ich pflege / räume den Code auf, der von einem unserer Ingenieure geschrieben wurde, der einige nützliche Dinge codiert hat, aber zugibt, dass er kein Programmierer ist. Während ich Dinge zusammenführe, werde ich seinen alten Code auskommentieren und dann später die Änderungen durchgehen und ihm zeigen, wie ich seinen durch etwas Kleineres / Effizienteres / Leichteres ersetzt habe. Danach entferne ich diese Blöcke und checke sie ein. Den alten Code zu haben, hat Vorteile, weil er sieht, wie Dinge einfacher gemacht werden können und ich mich daran erinnere, warum ich Dinge geändert habe, als wir gesprochen haben.
der Blechmann
8
Ich lasse Dinge, die für 1 Festschreibung "verwendet" werden könnten. Wenn die Dinge dann nicht zusammenbrechen oder eine Notwendigkeit nicht gefunden wird, wird sie beim nächsten Festschreiben entfernt.
Paul Nathan
24
Hmm. printf("%c", 7)In der Regel läutet Alarmglocken für mich. ;)

Antworten:

128
/* Fuck this error */

In der Regel in einem Quatschblock gefunden try..catch, neigt es dazu, meine Aufmerksamkeit zu erregen. Genau so gut wie /* Not sure what this does, but removing it breaks the build */.

Noch ein paar Dinge:

  • Mehrere verschachtelte komplexe ifAnweisungen
  • Try-Catch-Blöcke, mit denen regelmäßig ein logischer Ablauf ermittelt wird
  • Funktionen mit generischen Namen process, data, change, rework,modify
  • Sechs oder sieben verschiedene Aussteifungsstile in 100 Zeilen

Eine habe ich gerade gefunden:

/* Stupid database */
$conn = null;
while(!$conn) {
    $conn = mysql_connect("localhost", "root", "[pass removed]");
}
/* Finally! */
echo("Connected successfully.");

Richtig, weil es der richtige Weg ist, Ihre MySQL-Verbindungen brachial zu erzwingen. Es stellte sich heraus, dass die Datenbank Probleme mit der Anzahl der Verbindungen hatte, so dass das Zeitlimit konstant blieb. Anstatt dies zu debuggen, versuchten sie es einfach immer wieder, bis es funktionierte.

Josh K
quelle
19
Wenn ich das nur 6 mal verbessern könnte! Alles gute Beispiele. Ich mag auch arrogante / lustige Kommentare nicht (besonders wenn sie das Fluchen beinhalten) - es könnte ein wenig amüsant sein, wenn man sie zum ersten Mal liest, aber sehr alt wird (und daher sehr schnell ablenkt).
FinnNk
5
Ich mag Ihr Beispiel, obwohl ich sagen würde, dass in einem bestimmten Kontext mehrere verschachtelte Anweisungen unvermeidbar sind. Mit viel Geschäftslogik kann der Code ein bisschen verwirrend sein. Wenn das Geschäft selbst jedoch zunächst verwirrend ist, wäre es zur Vereinfachung des Codes weniger genau, den Prozess zu modellieren. Wie Einstein sagte: "Die Dinge sollten so einfach wie möglich und nicht ein bisschen einfacher sein."
Morgan Herlocker
2
@Prof Plum - Welches Beispiel können Sie geben? Normalerweise besteht die Alternative zu mehrfach geschachtelten ifs darin, sie in (viele) Methoden aufzuteilen. Nachwuchsentwickler neigen dazu, dies zu vermeiden, als wäre es weniger wünschenswert als das Wenn. aber normalerweise sagen sie, wenn sie gedrückt werden "wenn es in weniger Zeilen getan wird". Es braucht jemanden, der Vertrauen in OOP hat, um einzusteigen und ihn daran zu erinnern, dass weniger Zeilen! = Besserer Code.
STW
2
@STW Das ist ein guter Punkt, aber ich würde sagen, dass es darauf ankommt, wie tief die Verschachtelung ist. Ich würde mit Sicherheit zustimmen, dass mehr als drei Nester oft umgestaltet werden müssen, weil es ziemlich haarig wird. Insurance Quoting ist jedoch ein gutes Beispiel, bei dem Multi-Nesting die reale Welt recht gut abbilden kann. Mit Ausnahmen von bestimmten Tarifen / Prämien wird im Handbuch buchstäblich so etwas wie "Wenn dies eine Immobilie ist und wenn sie einen Mindesttarif unter 5,6 hat und wenn sie sich in NC befindet und wenn sie ein Boot auf dem Gelände hat, dann tue dies und." eine solche." mit vielen anderen Optionen.
Morgan Herlocker
4
@josh, wenn "sie" Kollegen sind, dann würde ich darüber nachdenken, warum Sie nicht "wir" gesagt haben ...
104

Die wichtigste rote Fahne für mich sind duplizierte Codeblöcke, da sie zeigen, dass die Person entweder die Programmiergrundlagen nicht versteht oder zu ängstlich war, um die richtigen Änderungen an einer vorhandenen Codebasis vorzunehmen.

Ich habe auch das Fehlen von Kommentaren als rote Fahne gewertet, aber nachdem ich in letzter Zeit eine Menge sehr guten Codes ohne Kommentare bearbeitet habe, habe ich das zurückgenommen.

Ben Hughes
quelle
1
+1: Ich habe einen Code von einem Kollegen gesehen, der sich selbst als Linux-Experte angepriesen hat und der eine einfache Loop-Anwendung als eine einzige lange Funktion geschrieben hat, das Ganze immer und immer wieder in main (). Huch.
KFro
4
@KFro, das ist Loop-Unrolling. Das machen Compiler die ganze Zeit :) SEHR effizient!
3
@Thorbjorn: Manchmal muss man dem Compiler ein wenig helfen; Immerhin bist du der kluge Mensch und er ist nur ein dummer Computer.
Yatima2975
3
Ein weiterer Grund, den ich gesehen habe: Der Berater wurde dafür bezahlt, das Feature so schnell wie möglich zu implementieren (deshalb fehlen natürlich auch Tests und Dokumentation). Kopieren / Einfügen ist schneller als überlegen, wie man es richtig macht.
LennyProgrammers
4
Das Vermeiden von Code-Duplikaten kann eine Obsession sein. In einer Sprache wie C ++ ist es nicht immer so einfach, die unterschiedlichen Teile herauszufiltern, und dennoch verfügt sie über robusten und effizienten Code. Manchmal ist ein bisschen Ausschneiden und Einfügen die praktischere Option. Auch das Optimierungsprinzip kann angewendet werden - durch Ausschneiden und Einfügen erhalten Sie eine schnelle und einfache Lösung, die Sie bei Bedarf später überarbeiten können. Möglicherweise sparen Sie sich Wartungsprobleme für später, aber Sie wissen sicher, dass Sie Verzögerungen im Moment vermeiden.
Steve314
74

Code, der zeigt, wie schlau der Programmierer ist, obwohl er keinen echten Mehrwert bietet:

x ^= y ^= x ^= y;
Rei Miyasaka
quelle
12
Wow, das ist sooo viel lesbarer alsswap(x, y);
JBRWilkinson
8
wenn x und y - Zeiger sind, und diese Zuordnung erfolgt über eine reasonble Länge der Zeit, es solide bricht konservative Müllsammler wie Boehm GC.
SingleNegationElimination
12
Übrigens ist dieser Code in C und C ++ wegen mehrfacher Änderungen ohne dazwischenliegenden Sequenzpunkt undefiniert.
Fredoverflow
9
Das einzige, was mir in den Sinn kam, waren Emoticons:^_^
Darien
62
  • 20.000 (übertriebene) Zeilenfunktionen. Jede Funktion, die mehr als ein paar Bildschirme benötigt, muss neu faktorisiert werden.

  • In die gleiche Richtung gehen Klassendateien, die scheinbar ewig dauern. Es gibt wahrscheinlich einige Konzepte, die in Klassen abstrahiert werden könnten, um den Zweck und die Funktion der ursprünglichen Klasse zu klären, und wahrscheinlich, wo sie verwendet wird, es sei denn, es handelt sich ausschließlich um interne Methoden.

  • Nicht beschreibende, nicht triviale Variablen oder zu viele triviale, nicht beschreibende Variablen. Diese machen es zu einem Rätsel, was tatsächlich passiert.

Dominique McDonnell
quelle
9
Ich neige dazu, Funktionen auf 1 Bildschirm zu beschränken, wann immer dies möglich ist.
Matt DiTrolio
20
1 Bildschirm ist sogar eine Strecke. Nach ungefähr 10 Zeilen fühle ich mich schmutzig.
Bryan Rowe
54
Okay, ich werde eine möglicherweise unpopuläre Meinung äußern. Ich sage, es ist Code-Geruch, Funktionen zu schreiben, die atomare Top-to-Bottom-Prozesse sind, die in separate Funktionen unterteilt sind, weil der Entwickler an einigen "Funktionen festhält, die kurz sein sollten". Funktionen sollten entlang der FUNKTIONALEN Linien getrennt werden, nicht nur, weil sie eine mythische "richtige Größe" haben sollten. Deshalb heißen sie FUNCTIONS.
Dan Ray
7
@ Dan, Funktionen sollten nicht kurz sein, um kurz zu sein, aber es gibt nur so viele Informationen, die Sie gleichzeitig in Ihrem Kopf halten können. Vielleicht habe ich ein kleines Gehirn, da für mich diese Grenze ein paar Bildschirme ist :). Das Aufteilen von Funktionen in mehrere Funktionen, wenn diese zu testen beginnen, ist erforderlich, um Fehler zu vermeiden. Auf der einen Seite bietet es eine Kapselung, damit Sie auf einer höheren Ebene denken können, und auf der anderen Seite verbirgt es das, was gerade passiert, so dass es schwieriger ist, herauszufinden, wie die Funktion funktioniert. Ich denke, dass die Aufteilung der Funktionen durchgeführt werden sollte, um die Lesbarkeit zu verbessern, und nicht um eine „perfekte Länge“ zu erreichen.
Dominique McDonnell
6
@Dominic, @Péter, ich denke, wir drei sagen eigentlich dasselbe. Wenn es einen guten Grund gibt, Code in eine kleinere Funktion zu zerlegen, bin ich dafür. Was ich ablehne, ist Kürze aus Gründen der Kürze im Funktionsdesign. Sie wissen, ein Call-Stack, der dreimal länger ist als nötig, aber zumindest diese Funktionen sind kurz. Ich würde lieber eine umfangreiche Funktion debuggen, die eine Sache gut und klar macht, als den Ausführungspfad durch ein Dutzend verketteter Funktionen zu verfolgen, die jeweils nur von der vorherigen aufgerufen werden.
Dan Ray
61
{ Let it Leak, people have good enough computers to cope these days }

Was noch schlimmer ist, ist das aus einer kommerziellen Bibliothek!

Wirklich ethisch
quelle
32
Dies läutet nicht Alarmglocken. Es tritt dich praktisch zwischen die Beine.
Steven Evers
15
Tochter ist methsüchtig. Wen kümmert es, zumindest wird sie nicht fettleibig. :: Seufzer ::
Evan Plaice
17
Wenn ich in Schwierigkeiten gerate, kommt Mutter Buntu zu mir. Wenn du Worte der Weisheit sprichst, lass es auslaufen. LASSEN SIE ES LECKEN .. LASSEN SIE ES LECKEN. LASS ES LECKEN oh LASS ES LECKEN. Wenn es nur einmal leckt, ist es kein leaaaaaak. (Wenn Sie so weit gelesen haben, +1). Ich muss wirklich über ein Decaf nachdenken.
Tim Post
13
"Als sich die Frist schnell nähert, sind LECKS alles, was ich sehen kann, irgendwo flüstert jemand: 'Write in C ...... eeeeee !!!'"
Chiurox
9
Es waren einmal zwei Betriebssysteme. Einer ist durchgesickert und abgestürzt, wenn er länger als 49 Tage lief, der andere war perfekt und würde für immer laufen. Eine wurde 1995 zu einer großen Fanmesse ins Leben gerufen und von Millionen von Menschen genutzt - die andere wurde nie ausgeliefert, weil sie immer noch überprüft, ob sie fehlerfrei ist. Es gibt einen Unterschied zwischen Philosophie und Technik.
Martin Beckett
53

Kommentare, die so ausführlich sind, dass ein englischer Compiler zwar perfekt kompiliert und ausgeführt werden kann, jedoch nichts beschreibt, was der Code nicht beschreibt.

//Copy the value of y to temp.
temp = y;
//Copy the value of x to y.
y = x;
//Copy the value of temp to x.
x = temp;

Bei Kommentaren zu Code, der hätte entfernt werden können, wurden einige grundlegende Richtlinien eingehalten:

//Set the age of the user to 13.
a = 13;
Rei Miyasaka
quelle
15
Es gibt, es heißt COBOL :-)
Gaius
26
Der zweite Fall ist nicht der schlimmste. Das Schlimmste ist: / * Setzen Sie das Alter des Benutzers auf 13 * / a = 18;
PhiLho
4
@PhiLho - nein, noch schlimmer ist es, wenn das /von dem */fehlt, so dass der gesamte Code bis zum Ende des nächsten */ignoriert wird. Glücklicherweise macht das Hervorheben von Syntax solche Dinge heutzutage selten.
Steve314
3
aNoch schlimmer für user_age? "Ja wirklich?"
Glasnt
2
Ich pflegte bei einem früheren Arbeitgeber einen Kodex als Standarddokument, von dem ein Abschnitt einen angemessenen Kommentar enthielt. Mein Lieblingsbeispiel war von MSDN:i = i + 1; //increment i
Michael Itzoe
42

Code, der beim Kompilieren Warnungen ausgibt.

Rei Miyasaka
quelle
1
Es gibt einen Kandidaten für das Hinzufügen der Compileroption "Alle Warnungen als Fehler" zum Makefile / Projekt.
JBRWilkinson
3
Ich denke, das könnte nützlich sein, wenn Sie in einem Projekt mit mehreren Personen arbeiten, denen Sie einfach nicht vertrauen. Wenn ich jedoch an einem Projekt teilnehmen würde, in dem diese Option festgelegt ist, würde ich mir selbst Sorgen darüber machen, wie fähig der andere ist Programmierer sind.
Rei Miyasaka
1
Ich bin damit nicht einverstanden. Einige Compiler-Warnungen (wie der Vergleich zwischen signierten und nicht signierten Werten , wenn Sie wissen, dass beide Werte nicht signiert sind, auch wenn die Typen unterschiedlich sind) werden Code mit unnötigen Umwandlungen vorgezogen. Wenn ich Code mit einer tragbaren Ganzzahl mit Vorzeichen reduziere, die von einer Funktion nur geändert wird , wenn die Ganzzahl einen vorzeichenlosen Wert hat, werde ich das tun.
Tim Post
13
Ich würde meinen Code lieber mit einem fast überflüssigen (unsigned int)überladen, als meine Warn- / Fehlerlisten mit harmlosen Warnungen zu überladen. Ich würde es hassen, wenn die Warnliste ein blinder Fleck würde. Es ist auch viel mehr ein PITA zu anderen Menschen zu erklären , warum Sie eine Warnung zu ignorieren sind , als es zu erklären ist , warum Sie eine Besetzung von natürlichen tun intszu unsigned ints.
Rei Miyasaka
Gelegentlich müssen Sie mit einer API arbeiten, die Fehler ausgibt, egal was Sie tun. Klassische Beispiele sind, wo die API in Bezug auf Dinge definiert ist, die durch das Design beschädigt wurden (einige alte ioctl () -Konstanten waren so, und manchmal bestehen OS-Entwickler darauf, den falschen Typ in ihren Headern zu verwenden) oder wo sie etwas ohne veraltet haben Hinterlasse einen guten Ersatz (danke, Apple).
Donal Fellows
36

Funktioniert mit Zahlen im Namen, anstatt beschreibende Namen zu haben , wie:

void doSomething()
{
}

void doSomething2()
{
}

Bitte lassen Sie die Funktionsnamen etwas bedeuten! Wenn doSomething und doSomething2 ähnliche Aktionen ausführen, verwenden Sie Funktionsnamen, die die Unterschiede unterscheiden. Wenn doSomething2 ein Ausbruch aus der Funktionalität von doSomething ist, nennen Sie es für seine Funktionalität.

Wonko the Sane
quelle
Ebenso @Parm für SQL
Dave
2
+1 - Enter mshtml- es bricht mir die Augen :(
Kyle Rozendo
3
Die Ausnahme wäre GUI-Code. Zum Beispiel, wenn ein Schneckenpostformular zwei Adressen hatte; address1 und address2 sind sinnvoller als address und alternateAddress. Auch unechte Etiketten, die nur statisch sind, sind eine sinnvolle Ausnahme.
Evan Plaice
@Evan - fair genug, obwohl ich mehr in der Funktionalität unterschied.
Wonko the Sane
1
+1 - Ich habe sogar gesehen, dass dies als Pseudoversionskontrollmethode verwendet wird.
EZ Hart
36

Magic Numbers oder Magic Strings.

   if (accountBalance>200) { sendInvoice(...); }

   salesPrice *= 0.9;   //apply discount    

   if (invoiceStatus=="Overdue") { reportToCreditAgency(); }
JohnFx
quelle
4
Nicht wirklich so schlimm mit den zweiten beiden, zumindest wird der Rabatt erklärt und die "Überfälligkeit" ist intuitiv. Die 200, auf der anderen Seite ...
Tarka
9
@Slokun - Intuitiv geht es nicht so sehr um Wartbarkeit und Fragilität. Überlegen Sie beispielsweise, was passiert, wenn sich der Rabattbetrag ändert und 0,9 an sechs verschiedenen Stellen fest programmiert ist. Die Verwendung von Zeichenfolgen anstelle von Konstanten / Aufzählungen ist in Sprachen mit Zeichenfolgen, bei denen zwischen Groß- und Kleinschreibung unterschieden wird, problematisch.
JohnFx
+1 Ich habe gerade viel zu viel Zeit mit dem Debuggen eines Problems verbracht, das durch eine Zeile 'timeout = 15;' verursacht wurde. in einem Programm begraben.
Aubreyrhodes
Ich denke, der letzte ist manchmal in Ordnung, je nachdem, woher diese Daten für RechnungStatus stammen. Wenn es nur von einer öffentlichen API stammt, die JSON zurückgibt, das gerade dekodiert wurde, ist es wahrscheinlich in Ordnung, mit einer fest kodierten String-Konstante zu vergleichen. Stimmen Sie jedoch zu, dass "200" und "0.9" nur magische Konstanten sind und nicht auf diese Weise hart codiert werden sollten. Selbst wenn sie nur an dieser einen Stelle verwendet werden, ist die Wartung einfacher, wenn Sie sie in einem Konfigurationsabschnitt separat definieren, anstatt sie in den Logikcode einzufügen. Und wenn sie an mehreren Orten eingesetzt werden, wird die Wartung viel einfacher.
Ben Lee
36
  • Vielleicht nicht das schlechteste, zeigt aber deutlich die Implementierungsstufe:

    if(something == true) 
  • Wenn eine Sprache eine for-Schleife oder ein Iteratorkonstrukt hat, zeigt die Verwendung einer while-Schleife auch, wie gut die Implementierer die Sprache verstehen:

    count = 0; 
    while(count < items.size()){
       do stuff
       count ++; 
    }
    
    for(i = 0; i < items.size(); i++){
      do stuff 
    }
    //Sure this is not terrible but use the language the way it was meant to be used.
  • Schlechte Rechtschreibung / Grammatik in Dokumentation / Kommentaren frisst bei mir fast so viel wie Code selbst. Der Grund dafür ist, dass Code für Menschen zum Lesen und für Maschinen zum Ausführen gedacht war. Aus diesem Grund verwenden wir Hochsprachen, wenn es schwierig ist, Ihre Dokumentation zu verarbeiten, kann ich mir eine negative Meinung über die Codebasis bilden, ohne sie anzusehen.

Chris
quelle
29

Das, was mir sofort auffällt, ist die Häufigkeit tief verschachtelter Codeblöcke (if's, while's usw.). Wenn Code häufig mehr als zwei oder drei Ebenen tief ist, deutet dies auf ein Design- / Logikproblem hin. Und wenn es 8 Nester tief geht, gibt es einen verdammt guten Grund, warum es nicht zerbrochen werden sollte.

GroßmeisterB
quelle
6
Ich weiß, dass einige Leute gelernt haben, dass jede Methode nur eine returnAussage haben sollte, aber wenn es 6+ Ebenen von Wenn / Dann-Verschachtelung verursacht, denke ich, dass es weit mehr schadet als nützt.
Darien
28

Wenn ich ein Studentenprogramm benote, kann ich das manchmal in einem "Blink" -Moment feststellen. Dies sind die unmittelbaren Hinweise:

  • Schlechte oder inkonsistente Formatierung
  • Mehr als zwei Leerzeilen hintereinander
  • Nicht standardmäßige oder inkonsistente Namenskonventionen
  • Wiederholter Code, je wörtlicher die Wiederholungen sind, desto stärker ist die Warnung
  • Was ein einfacher Code sein sollte, ist übermäßig kompliziert (z. B. das Überprüfen der Argumente, die auf verschlungene Weise an main übergeben werden).

Selten sind meine ersten Eindrücke falsch, und diese Warnglocken stimmen in etwa 95% der Fälle . Für eine Ausnahme verwendete ein Student, der neu in der Sprache war, einen Stil aus einer anderen Programmiersprache. Das Nachlesen ihres Stils in der anderen Sprache löste die Alarmglocken für mich und der Student erhielt dann die volle Anerkennung. Aber solche Ausnahmen sind selten.

Wenn ich fortgeschritteneren Code betrachte, sind dies meine anderen Warnungen:

  • Das Vorhandensein vieler Java-Klassen, die nur "Strukturen" zum Speichern von Daten sind. Es spielt keine Rolle, ob die Felder öffentlich oder privat sind und Getter / Setter verwenden, es ist dennoch nicht wahrscheinlich, dass sie Teil eines gut durchdachten Designs sind.
  • Klassen mit schlechten Namen, z. B. nur ein Namespace, und der Code besteht nicht wirklich aus einem Guss
  • Verweis auf Entwurfsmuster, die nicht einmal im Code verwendet werden
  • Leere Ausnahmebehandlungsroutinen ohne Erklärung
  • Wenn ich den Code in Eclipse aufrufe, wird der Code von Hunderten von gelben "Warnungen" angezeigt, die hauptsächlich auf nicht verwendete Importe oder Variablen zurückzuführen sind

In Bezug auf den Stil sehe ich im Allgemeinen nicht gerne:

  • Javadoc-Kommentare, die nur den Code wiedergeben

Dies sind nur Hinweise auf fehlerhaften Code. Manchmal ist das, was nach schlechtem Code aussieht, wirklich nicht der Fall, weil Sie die Absichten des Programmierers nicht kennen. Zum Beispiel mag es einen guten Grund dafür geben, dass etwas übermäßig komplex erscheint - es mag eine andere Überlegung gegeben haben.

Macneil
quelle
Ich verstehe nicht, wie es ein schwerwiegender Fehler ist, den Stil einer Sprache in einer anderen zu verwenden (2, 4, 8 Leerzeichen pro Gedankenstrich ...). Wenn der Schüler wenig anderes zu tun hat, ist es nichts Falsches, wenn er selbstbeständig ist. Als Grader sehen Sie eine Milliarde Programme und befinden sich damit am anderen Ende dieses Spektrums. Dies ist jedoch kein Grund, einen anderen (aber konsistenten) Stil vollständig zu verwerfen.
Nick T
18
Ich sehe nichts falsches an Klassen, die einfach Daten aggregieren - also Strukturen. Das sind Data Transfer Objects (DTOs), mit denen Code viel besser lesbar gemacht werden kann als beispielsweise, indem 20 Parameter an eine Methode übergeben werden.
Nemi
1
Ihr Kommentar zu structs ist genau richtig. Es ist in Ordnung, wenn die Daten in ihrer ursprünglichsten Form vorliegen und in keiner Weise geändert werden. In 95% der Fälle sollten Sie jedoch einige Funktionen in der Klasse haben, um die Daten zu formatieren / zu verarbeiten. Ich habe mich gerade an einen Teil meines Codes erinnert, der im Wesentlichen dieses Muster verwendet und verbessert werden sollte.
DisgruntledGoat
2
+1 für inkonsistenten Stil und zusätzliche Zeilenumbrüche (Ich habe zufällige Einrückungen, keine Einrückungen, zufällige und sich ändernde Namenskonventionen und mehr gesehen - und das im Produktionscode!). Wenn Sie sich nicht einmal die Mühe machen können, was können Sie dann noch tun?
Dean Harding
1
Ich suche nach der Deklarationszeile einer Methode, die relativ zum Körper zu weit eingerückt ist. Dies ist ein Zeichen, das sie aus einer anderen Datei kopieren und einfügen.
Barry Brown
25

Persönlicher Liebling / Haustier-Ärger: IDE-generierte Namen, die festgeschrieben werden. Wenn TextBox1 eine wichtige und wichtige Variable in Ihrem System ist, steht eine weitere Überprüfung des Codes an.

Wyatt Barnett
quelle
25

Völlig unbenutzte Variablen , insbesondere wenn die Variable einen ähnlichen Namen wie die verwendeten Variablennamen hat.

Kreuz
quelle
21

Viele Leute haben erwähnt:

//TODO: [something not implemented]

Ich wünschte, das Zeug wäre implementiert, aber sie machten sich wenigstens eine Notiz. Was ich für schlimmer halte, ist:

//TODO: [something that is already implemented]

Todos sind wertlos und verwirrend, wenn Sie sich nie die Mühe machen, sie zu entfernen!

Morgan Herlocker
quelle
1
Ich habe gerade die Übung absolviert, einen Bericht über alle TODOs in unserem Release-Produkt sowie einen Plan für deren Entsorgung zu erstellen. Fast die Hälfte erwies sich als veraltet.
AShelly
1
-1 TODO-Kommentare werden in MS Visual Studio verwendet, um Teile des Projekts zu verfolgen, die noch bearbeitet werden müssen. Die IDE führt eine Liste, in der die TODOs nachverfolgt werden, sodass Sie leicht darauf klicken und direkt zu der Zeile gelangen können, in der sich das TODO befindet. Ich würde es vorziehen, TODOs explizit zu platzieren, um zu sehen, welche Arbeit noch zu erledigen ist. Siehe dotnetperls.com/todo .
Evan Plaice
3
@Evan Plaice: Wow, du meinst die VS IDE erkennt, wenn du etwas implementiert hast und entfernt den //TODOKommentar? Genial!
JBRWilkinson
4
@Prof Plum Warum nicht einfach eine Richtlinie erstellen, in der die für ein TODO verantwortliche Person ihren Namen in den Kommentar einfügt. Auf diese Weise, wenn es ein paar Reste gibt
Evan Plaice
3
Besser planen als // TODO , verwenden Sie Ihren Bug-Tracker, dafür ist er da!
SingleNegationElimination
20

Eine Methode, bei der ich nach unten scrollen muss, um alles zu lesen.

BradB
quelle
14
Hmm .. das hängt davon ab, was implementiert wird. Es wäre nicht unangemessen, wenn dies bei der Implementierung einiger komplizierter Algorithmen der Fall wäre, da diese so definiert sind. Wenn die meisten Methoden so sind, ist das natürlich eine rote Fahne.
Billy ONeal
9
Als Pauschalaussage bin ich nicht einverstanden, dass die Verschwendung von Zeit, die ständig umgestaltet wird, damit alles zu dieser Art von selbst auferlegter Regel passt, die Gesamtkosten des Projekts erhöht.
Anonymous Type
1
Ich bin nicht einverstanden, dass diese Regel die Gesamtkosten eines Projekts erhöhen kann, aber ich denke, dass dies subjektiv ist, da es von den Entwicklern abhängen würde. Wenn Sie sich bei der Entwicklung an das allgemeine Prinzip der "Trennung von Bedenken" halten, wäre das Umrechnen weniger eine Aufgabe, wenn Sie sich dafür entscheiden würden. Zu überlegen ist, wie viel es drei Jahre später kosten würde, wenn Entwickler, die das ursprüngliche Projekt nicht programmiert haben, versuchen, eine Reihe von Methoden mit mehr als 300 Codezeilen zu reparieren? Wie viel kostet das?
BradB
18
Es ärgert mich mehr, nach rechts zu scrollen, als nach unten zu scrollen. Whitespace ist "frei".
Wonko the Sane
4
Ich möchte lieber scrollen, als die gesamte Datei (oder mehrere Dateien) überspringen zu müssen, um herauszufinden, was der Code tut.
TMN
20

Verknüpfungen in Methodennamen:

public void addEmployeeAndUpdatePayrate(...) 


public int getSalaryOrHourlyPay(int Employee) ....

Klarstellung: Der Grund, warum diese Alarmglocken läuten, ist, dass sie anzeigt, dass die Methode wahrscheinlich gegen das Prinzip der einmaligen Verantwortung verstößt .

JohnFx
quelle
Hmmm ... wenn der Funktionsname genau definiert, was die Funktion tut, bin ich anderer Meinung. Wenn die Methode zwei getrennte Dinge ausführt, die besser zu trennen wären, kann ich je nach Kontext zustimmen.
Wonko the Sane
2
Das ist der Punkt. Die Konjunktion impliziert, dass es sehr wahrscheinlich mehr als eine Sache tut. Bei der Frage ist es nur etwas, das mein Bewusstsein weckt, dass etwas falsch sein könnte.
JohnFx
3
Was ist nun, wenn Sie einen Mitarbeiter hinzufügen und seinen Lohn an mehreren Stellen aktualisieren müssen? Wenn diese Methode zwei Methodenaufrufe ( addEmployee(); updatePayrate();) enthält, ist das meines Erachtens kein Problem.
Matt Grande
13

Offensichtlich GPL-Quellcode in ein kommerzielles Closed-Source-Programm einbinden.

Dies stellt nicht nur ein unmittelbares rechtliches Problem dar, sondern weist meiner Erfahrung nach in der Regel auch auf Unachtsamkeit oder Unbesorgtheit hin, die sich auch an anderen Stellen im Code widerspiegeln.

Bob Murphy
quelle
6
Während Ihr Punkt ausgezeichnet ist, ist Ihr Ton unnötig.
JBRWilkinson
@ JBRWilkinson: Danke, du hast recht. Ich entschuldige mich bei allen.
Bob Murphy
Ich denke, Ihre Überschrift muss neu geschrieben werden. Sowohl das statische als auch das dynamische Verknüpfen mit dem GPL-Quellcode verstößt gegen die GPL ...
Gavin Coates
Gute Argumente. Ich habe den gesamten Beitrag umgeschrieben. Dank an alle.
Bob Murphy
9

Sprachunabhängig:

  • TODO: not implemented
  • int function(...) { return -1; } (das gleiche wie "nicht implementiert")
  • Eine Ausnahme aus einem nicht außergewöhnlichen Grund auslösen.
  • Missbrauch oder inkonsistente Verwendung 0, -1oder nullals Ausnahmerückgabewert.
  • Behauptungen ohne überzeugenden Kommentar, warum sie niemals scheitern sollten.

Sprachspezifisch (C ++):

  • C ++ - Makros in Kleinbuchstaben.
  • Statische oder globale C ++ - Variablen.
  • Nicht initialisierte oder nicht verwendete Variablen.
  • Alles array new, was anscheinend nicht RAII-sicher ist.
  • Jede Verwendung von Arrays oder Zeigern, die anscheinend nicht sicher sind. Dies beinhaltet printf.
  • Beliebige Verwendung des nicht initialisierten Teils eines Arrays.

Microsoft C ++ spezifisch:

  • Alle Bezeichnernamen, die mit einem Makro kollidieren, das bereits in einer der Microsoft SDK-Headerdateien definiert ist.
  • Im Allgemeinen ist jede Verwendung der Win32-API eine große Quelle für Alarmglocken. Lassen Sie MSDN immer geöffnet und prüfen Sie die Argumente / Rückgabewertdefinitionen, wenn Sie Zweifel haben. (Bearbeitet)

C ++ / OOP-spezifisch:

  • Vererbung der Implementierung (konkrete Klasse), bei der die übergeordnete Klasse sowohl über virtuelle als auch über nicht virtuelle Methoden verfügt, ohne dass eine klare konzeptionelle Unterscheidung zwischen dem, was virtuell sein sollte / nicht sein sollte, vorliegt.
falsch
quelle
18
// TODO: Kommentiere diese Antwort
johnc
8
Ich vermute, "language agnostic" bedeutet jetzt "C / C ++ / Java"?
Inaimathi
+1 "Wirf eine Ausnahme aus einem nicht außergewöhnlichen Grund" konnte nicht mehr zustimmen!
billy.bob
2
@Inaimathi - TODO-Kommentare, Funktionsstubs, Ausnahmebedingungsmissbrauch, Verwechslung von Null / Null / Leer-Semantik und sinnlose Vernunftsprüfungen gehören zu allen Imperativ- / OOP-Sprachen und zu einem gewissen Grad zu allen Programmiersprachen im Allgemeinen.
Rei Miyasaka
Ich glaube, dass C-Präprozessor-Makros in Kleinbuchstaben in Ordnung sind, aber nur, wenn sie ihre Argumente nur einmal auswerten und nur eine einzige Anweisung ergeben.
Joe D
8

Bizarrer Einrückungsstil.

Es gibt einige sehr beliebte Stile, und die Leute werden diese Debatte mit ins Grab nehmen. Aber manchmal sehe ich jemanden, der einen wirklich seltenen oder sogar einen einheimischen Einrückungsstil verwendet. Dies ist ein Zeichen dafür, dass sie wahrscheinlich mit niemand anderem als sich selbst codiert haben.

Ken
quelle
2
oder einfach ein Zeichen dafür, dass es sich um ein hochgeschätztes individualistisches Talent handelt, das sich nicht im Netz homogonisierter Codierungspraktiken verfangen hat, die in keiner Weise mit "Best Practices" zusammenhängen.
Anonymous Type
1
Ich hoffe du bist sarkastisch. Wenn jemand so ungewöhnlich codiert, sollte dies Alarmglocken auslösen. Sie können so künstlerisch sein, wie sie wollen, aber immer noch ... Alarmglocken.
Ken
2
Es gibt einen etwas ungewöhnlichen Stil (ich glaube, er heißt Utrecht-Stil), den ich sehr nützlich finde, obwohl er außerhalb von Haskell / ML / F # extrem ungewöhnlich ist. Scrollen Sie nach unten zu "Modul Shapes": learnyouahaskell.com/making-our-own-types-and-typeclasses . Das Schöne an diesem Stil ist, dass Sie das Trennzeichen in der vorhergehenden Zeile nicht ändern müssen, um ein neues hinzuzufügen - was ich oft vergesse.
Rei Miyasaka
@ReiMiyasaka Sieben Jahre zu spät, aber ... Utrecht-Stil ärgert mich wirklich. Ich glaube, dass es ein Fehler in der Haskell-Spezifikation ist, vertikal organisierten Listen keine andere "Layoutregel" aufzuerlegen. Auf diese Weise kann der Parser einen neuen Listeneintrag erkennen, indem er nur die Einrückung überprüft. Auf diese Weise ordnet jeder Benutzer seine Listen trotzdem an.
Ryan Reich
@ RyanReich Seltsam, sieben Jahre später, und ich mag es immer noch. Ich stimme jedoch zu; Bei aller syntaktischen Ungeschicklichkeit und bei allen Fehlern ermöglicht F # auch, dass Elemente nur durch eine neue Zeile und Einrückung (in den meisten Fällen) abgegrenzt werden, was für einen aufgeräumten Code sorgt.
Rei Miyasaka
8

Verwenden Sie viele Textblöcke anstelle von Aufzählungen oder global definierten Variablen.

Nicht gut:

if (itemType == "Student") { ... }

Besser:

private enum itemTypeEnum {
  Student,
  Teacher
}
if (itemType == itemTypeEnum.Student.ToString()) { ... }

Beste:

private itemTypeEnum itemType;
...
if (itemType == itemTypeEnum.Student) { ... }
Yaakov Ellis
quelle
Oder am besten: Verwende Polymorphismus.
Lstor
8

Schwach eingegebene Parameter oder Rückgabewerte für Methoden.

public DataTable GetEmployees() {...}

public DateTime getHireDate(DataTable EmployeeInfo) {...}

public void FireEmployee(Object EmployeeObjectOrEmployeeID) {...}
JohnFx
quelle
2
+1: Ich muss mit einigen "REST" -Webdiensten arbeiten, die alles als Pseudo-HTML-Tabellen zurückgeben, auch wenn Sie Dinge übergeben, die einen klaren syntaktischen Fehler darstellen. Nicht genehmigt? Vollständigen Müll eingeben? Server überlastet? 200 (plus eine Nachricht in einem schrecklichen Format in einer Tabelle mit einer Spalte und einer Zeile). AAaaaaaaaargh!
Donal Fellows
7
  • Mehrere ternäre Operatoren reihen sich aneinander, sodass sie nicht wie ein if...elseBlock aussehen, sondern zu einem if...else if...[...]...elseBlock werden
  • Lange Variablennamen ohne Unterstriche oder camelCasing. Beispiel aus einem Code, den ich aufgerufen habe:$lesseeloginaccountservice
  • Hunderte von Codezeilen in einer Datei, mit wenigen bis keinen Kommentaren, und der Code ist sehr unübersichtlich
  • Zu komplizierte ifAussagen. Beispiel aus dem Code: auf if (!($lessee_obj instanceof Lessee && $lessee_obj != NULL))den ich heruntergebastelt habeif ($lessee_obj == null)
Tarka
quelle
7

Code-Geruch: Best Practices nicht befolgen

Diese Art von Dingen beunruhigt mich immer, da es diese Binsenweisheit gibt, die jeder für einen überdurchschnittlichen Fahrer hält.

Hier ist ein Blitz für Sie: 50% der Weltbevölkerung sind unterdurchschnittlich intelligent. Okay, einige Leute hätten genau die durchschnittliche Intelligenz, aber lassen Sie uns nicht wählerisch werden. Eine der Nebenwirkungen von Dummheit ist, dass Sie Ihre eigene Dummheit nicht erkennen können! Wenn Sie diese Aussagen kombinieren, sieht es nicht so gut aus.

Welche Dinge läuten beim Betrachten von Code sofort Alarmglocken?

Es wurden viele gute Dinge erwähnt, und im Allgemeinen scheint es ein Codegeruch zu sein, wenn Best Practices nicht befolgt werden.

Best Practices werden in der Regel nicht zufällig erfunden und sind häufig aus einem bestimmten Grund vorhanden. Oft kann es subjektiv sein, aber meiner Erfahrung nach sind sie meist gerechtfertigt. Das Befolgen von Best Practices sollte kein Problem sein, und wenn Sie sich fragen, warum sie so sind, recherchieren Sie sie, anstatt sie zu ignorieren und / oder sich darüber zu beschweren - vielleicht ist es gerechtfertigt, vielleicht nicht.

Ein Beispiel für eine bewährte Methode ist die Verwendung von Curlies für jeden if-Block, auch wenn dieser nur eine Zeile enthält:

if (something) {
    // whatever
}

Sie denken vielleicht nicht, dass es notwendig ist, aber ich habe kürzlich gelesen, dass es eine Hauptquelle für Fehler ist. Die Verwendung von eckigen Klammern wurde auch im Zusammenhang mit dem Stapelüberlauf erörtert. Die Überprüfung, ob if-Anweisungen eckige Klammern enthalten, ist auch in PMD , einem statischen Codeanalysator für Java, eine Regel .

Denken Sie daran: "Weil es sich um bewährte Methoden handelt" ist keine akzeptable Antwort auf die Frage "Warum machen Sie das?" Wenn Sie nicht artikulieren können, warum etwas ein bewährtes Verfahren ist, dann ist es kein bewährtes Verfahren, sondern ein Aberglaube.

Vetle
quelle
2
Das mag pedantisch sein, aber ich denke, es ist wichtig, welchen Durchschnitt Sie wählen. Soweit ich weiß, liegen 50% der Weltbevölkerung unter dem Median der Intelligenz (per Definition). Andere Mittelwerte funktionieren jedoch nicht auf die gleiche Weise. Nehmen Sie zum Beispiel die Bevölkerung (1, 1, 1, 5), die ein arithmetisches Mittel von 2 hat.
Flamingpenguin
ähm, Sie haben den Beitrag "Was für Aberglauben-Programmierer-haben" zitiert, in dem ein Benutzer eine kühne Aussage über geschweifte Klammern ohne Quelle machte. Ich sehe das nicht als gutes Beispiel für Best Practices.
Evan Plaice
@Evan: Ja, du hast recht. Ich habe ein bisschen mehr hinzugefügt, hoffe das hilft.
Vetle
4
Die Kehrseite davon sind Leute, die sich sklavisch an "Best Practices" halten, ohne sich kritisch darüber Gedanken zu machen, warum etwas eine "Best Practice" ist. Aus diesem Grund lehne ich den Begriff "Best Practice" sehr ab, da er für manche Menschen eine Ausrede ist, nicht mehr nachzudenken und der Herde zu folgen. "Weil es Best Practice ist" ist keine akzeptable Antwort auf die Frage "Warum machst du das?" Wenn Sie nicht artikulieren können, warum etwas ein bewährtes Verfahren ist, dann ist es kein bewährtes Verfahren, sondern ein Aberglaube.
Dan Dyer
Sehr guter Kommentar, Dan! Ich habe die beiden letzten Zeilen zur Antwort hinzugefügt.
Vetle
6

Kommentare, die besagen: "Das liegt daran, dass das Design des Froz-Subsystems völlig durcheinander ist."

Das geht über einen ganzen Absatz.

Sie erklären, dass der folgende Refactor passieren muss.

Aber habe es nicht getan.

Jetzt wurde ihnen vielleicht gesagt, dass sie es von ihrem Chef zu der Zeit aus Zeit- oder Kompetenzgründen nicht ändern konnten, aber vielleicht lag es daran, dass die Leute kleinlich waren.

Wenn ein Vorgesetzter das für zufällig hält. Der Programmierer kann kein Refactoring durchführen, dann sollte der Supervisor dies tun.

Wie dem auch sei, ich weiß, dass der Code von einem geteilten Team mit möglicher Machtpolitik geschrieben wurde, und sie haben die Entwürfe von gegabelten Subsystemen nicht überarbeitet.

Wahre Geschichte. Das könnte dir geschehen.

Tim Williscroft
quelle
6

Kann jemand an ein Beispiel denken, in dem Code legitimerweise auf eine Datei durch absoluten Pfad verweisen sollte?

Rei Miyasaka
quelle
1
XML-Schemas zählen?
Nick T
1
Systemkonfigurationsdateien. Sollte normalerweise durch ./configure gesetzt werden, aber auch das benötigt irgendwo einen Standardwert.
Eswald
4
/dev/nullund freunden geht es gut Aber selbst /bin/bashsolche Dinge sind verdächtig - was ist, wenn Sie ein verrücktes System sind, das es gibt /usr/bin/bash?
Tom Anderson
1
Der von JAX-WS-Tools (mindestens JBossWS und Metro) generierte Webdienst-Client-Code enthält einen festverdrahteten absoluten Pfad zur WSDL-Datei (zweimal!). Welches ist wahrscheinlich etwas wild unpassendes wie /home/tom/dev/randomhacking/thing.wsdl. Es ist kriminell verrückt, dass dies ein Standardverhalten ist.
Tom Anderson
4
about /dev/null: Ich habe die Gewohnheit, bei der Entwicklung auf Windows Apps und Bibliotheken unterzuhalten c:\dev. Irgendwie nullwird immer automatisch ein Ordner in diesem Ordner erstellt. Ich schwöre, ich habe keine Ahnung, wer das tut. (Einer meiner Lieblingsfehler / Features)
Sean Patrick Floyd
6

Allgemeine Ausnahmen:

try {

 ...

} catch {
}

oder

try {

 ...

} catch (Exception ex) {
}

Überbeanspruchung der Region

In der Regel bedeutet die Verwendung zu vieler Regionen, dass Ihre Klassen zu groß sind. Es ist eine Warnflagge, die signalisiert, dass ich mich eingehender mit diesem Code befassen sollte.

Erik van Brakel
quelle
Das Abfangen von allgemeinen Ausnahmen ist nur dann ein Problem, wenn Sie sie erneut werfen, ohne etwas zu tun. Wirklich für die meisten Dinge würde eine Ausnahmeklasse ausreichen. Ich neige dazu, Laufzeitfehler zu verwenden.
CashCow
+1 für das Beispiel "Ausnahme abfangen und wegwerfen". Wenn Sie nichts mit der Ausnahme tun, fangen Sie es nicht. Zumindest loggen Sie es. Geben Sie zumindest einen Kommentar ein, der erklärt, warum es in Ordnung ist, alle Ausnahmen abzufangen und an diesem Punkt im Code fortzufahren.
EZ Hart
5

Klassennamenskonventionen, die ein schlechtes Verständnis der Abstraktion zeigen, die sie erstellen möchten. Oder das definiert überhaupt keine Abstraktion.

Ein extremes Beispiel Datafällt mir in einer VB-Klasse ein, die ich einmal gesehen habe und die über 30.000 Zeilen lang war ... in der ersten Datei. Es war eine Teilklasse, die in mindestens ein halbes Dutzend andere Dateien aufgeteilt war. Die meisten Methoden waren Wrapper um gespeicherte Procs mit Namen wie FindXByYWithZ().

Selbst mit weniger dramatischen Beispielen bin ich sicher, dass wir alle die Logik in eine schlecht konzipierte Klasse "geworfen" haben, indem wir ihr einen ganz allgemeinen Titel gegeben haben und es später bereut haben.

Bryan M.
quelle
5

Funktionen, die grundlegende Funktionen der Sprache neu implementieren. Wenn Sie beispielsweise jemals eine "getStringLength ()" - Methode in JavaScript anstelle eines Aufrufs der ".length" -Eigenschaft eines Strings sehen, wissen Sie, dass Sie in Schwierigkeiten sind.

Ameise
quelle
5
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...

Natürlich ohne jegliche Dokumentation und die gelegentlich verschachtelten #defines

Sven
quelle
Ich habe gestern genau dieses "Muster" gesehen ... im Produktionscode ... und noch schlimmer ... im C ++ - Produktionscode: - /
Oliver Weiler