Was sind die schlimmsten Anti-Muster, auf die Sie in Ihrer Karriere als Programmierer gestoßen sind?
Ich beschäftige mich hauptsächlich mit Java, obwohl es wahrscheinlich sprachunabhängig ist.
Ich denke, das Schlimmste ist das, was ich als Haupt-Anti-Muster bezeichne . Es bedeutet ein Programm, das aus einer einzelnen, extrem großen Klasse besteht (manchmal begleitet von zwei kleinen Klassen) und alle Logik enthält. In der Regel mit einer großen Schleife, in der die gesamte Geschäftslogik enthalten ist und manchmal Zehntausende von Codezeilen enthält.
language-agnostic
anti-patterns
стривігор
quelle
quelle
Ich werde eine andere offensichtliche mit "Copy-Pasta" treffen. Kopieren Sie Code, der fast identisch mit dem ist, was Sie möchten, und ändern Sie dann einige Dinge (anstatt ihn in eine Methode zu extrahieren).
Dies ist besonders häufig in einigen Funktions- und API-Testcodes aus den späten 90er Jahren der Fall: Buchstäblich Hunderte (oder sogar Tausende) nahezu identischer Testfälle, die in einige Funktionen unterteilt werden könnten, die 3 oder 4 Parameter annehmen - oder sogar noch besser , etwas datengetriebenes. Mein erster Job außerhalb des College war buchstäblich 8 Monate lang das Umschreiben und Umgestalten von Tausenden von Zeilen mit Nudeln, die veraltete Methoden verwendeten. Als ich fertig war, waren die Testdateien weniger als ein Zehntel ihrer ursprünglichen Größe und weitaus wartbarer (und lesbarer!).
quelle
Ich denke, ich kann viel über Pattern Mania und Lösungen schreiben , die mit viel weniger Aufwand gelöst werden könnten, aber ich möchte lieber auf einen großartigen Artikel verweisen, den ich kürzlich gelesen habe, mit einem fantastischen Beispiel dafür, wie eine einfache Lösung überkompliziert werden kann .
Wie (nicht) man Factorial in Java schreibt oder so, wir setzen eine Factory in Ihren Algorithmus ein
quelle
Goldener Hammer
quelle
Regionen
In C # können Sie einen Codebereich definieren, der in der IDE reduziert werden kann, und ihn so ausblenden, es sei denn, Sie möchten mit diesem Code umgehen. Ich war in einem Projekt (bin gerade dabei), in dem die Regionen Hunderte von Zeilen umfassten (ich wünschte, ich übertreibe) und es gab mehrere Regionen in einer Funktion mit tausend Zeilen (wieder wünschte ich, ich mache Witze).
Auf der anderen Seite hat der Entwickler, der die Region erstellt hat, sehr gute Arbeit geleistet, um bestimmte Funktionen innerhalb einer Region zu identifizieren. So sehr, dass ich eine Extraktionsmethode für die Region durchführen und weitermachen konnte.
Regionen ermutigen Entwickler, ihren Mist in Sichtweite zu "verstecken".
quelle
DoNotUseRegions
.#region SQL Update
macht sie zusammenklappbar, sodass weniger Bildlauf erforderlich ist.Für mich ist das schlechteste Muster Kopieren / Einfügen .
quelle
Nicht überladende Methoden:
Zeigt deutlich, dass der Programmierer das Überladen nicht verstanden hat.
quelle
Schleifenschaltersequenzen
http://en.wikipedia.org/wiki/Loop-switch_sequence
Sie nerven mich bis zum Äußersten und zeigen wirklich, wie unerfahren der Entwickler war
quelle
Softcodierung , dh wenn Programmierer alles daran setzen, Hardcodierung zu vermeiden, und auf der anderen Seite der Skala landen - "hartcodierte" Abhängigkeiten.
quelle
Behalten Sie den Status im Client.
Einmal mit einer Webanwendung gearbeitet, bei der der gesamte Status im Browser beibehalten wurde. (Um eine problemlose Skalierbarkeit zu gewährleisten, wurden alle Ausnahmen ignoriert.)
quelle
Massive Checkins
Ich hasse es, wenn ich sehe, dass ein Entwickler seit über einer Woche nicht mehr eingecheckt hat. Es bedeutet, dass er entweder feststeckt und nicht nach Hilfe gesucht hat oder eine Reihe von Funktionen in einem großen Check-in zusammengefasst hat. (Ich habe das Worst-Case-Szenario ausgelassen, er tut einfach nichts. Das ist leicht zu lösen ... zwei Wörter klingen, als wären Sie eingestellt.)
Wenn Sie einen großen Check-in durchführen, verlieren Sie viele Vorteile von SCM, z. B. die Möglichkeit, einen Änderungssatz mit einer bestimmten Funktion zu verknüpfen. Außerdem müssen Sie wahrscheinlich viel zusammenführen, und das ist nicht unbedingt einfach richtig zu machen.
quelle
Derzeit arbeite ich mit einem Legacy-Code und ich mag die Art und Weise, wie der vorherige Codierer das erste Element einer Liste erhält:
Aber das Schlimmste, was ich in diesem Code gesehen habe, ist das Definieren von Klassen in Inline-JSPs-Seiten, das Schreiben von HTML, CSS und Javascript mit scriptlet und out.println :-(
quelle
Eines der schlimmsten Verhaltensmuster, das ich je gesehen habe, war ein Shop, in dem Code erst nach der Produktion in die Versionskontrolle eingecheckt werden konnte. In Verbindung mit exklusiven Checkouts in VSS führte dies zu einem komplizierten Prozess des Rückgängigmachens von Checkouts, wenn ein Produktionsfehler vor der nächsten Version behoben werden musste, geschweige denn, dass mehr als eine Person eine bestimmte Datei für die kommende Version ändern musste.
Die Tatsache, dass dies eine Abteilungsrichtlinie war, machte es noch schlimmer als der Fall eines einzelnen Entwicklers, der sich so verhält.
quelle
Sperren eines String-Literal
Sehr lange Klassennamen. (in der JRE)
Schlechte Vererbungsstruktur
Eine Ausnahme, die es nicht ist.
Sinnlose und kryptische Fehlerbehandlung
Unnötige Erstellung von Objekten
Eine Ausnahme für andere Zwecke auslösen
Verwenden von Instanzobjekten für statische Methoden.
Synchronisieren in einem nicht endgültigen Feld
Sinnlose Kopie eines konstanten Strings
Sinnloser Aufruf von String.toString ()
Ruft System.gc () auf, um Speicherplatz freizugeben
Setzen Sie die lokale Variable auf null, um Speicherplatz freizugeben
Verwenden von ++ i anstelle von i ++ aus Leistungsgründen (oder einer anderen Mikro-Mikro-Optimierung)
quelle
Code bestreut mit:
oder
ohne zusätzliche Informationen.
quelle
Iterator für Dummies:
Singletono-Fabrik:
if-else-getriebene Entwicklung (auch Open-Close-Prinzip genannt - offen für Modifikationen, geschlossen zum Verständnis):
StringPattern (auch StringObject genannt):
quelle
else if
ist dann aber oft nur der Weg, um Dinge zu erledigen. Ich denke über Saiten nach; Ich kann keinen Schalter benutzen. Die Bedingungen sollten gleich sein, damit es nützlich ist.getInstance
dieselbe Instanz zurückgibt. Eine solche Annahme würde die Einkapselung brechen und ist in der Tat eines der häufigsten Anti-Muster.Es ist nicht so sehr ein Codierungsmuster, sondern ein Verhaltensmuster, aber es ist ziemlich schlecht: Ändern Sie etwas im Code (sagen wir, die Anforderungen haben sich geändert) und optimieren Sie dann alle Komponententests, bis der Code es besteht. Optimieren oder Entfernen des gesamten Testcodes aus der Testmethode, aber Belassen der Methode dort.
Dies ist jedoch mit einem allgemeineren Muster verknüpft, dem That'll Do- Muster. Hier ist eine repräsentative Codezeile dafür:
Es funktioniert schließlich.
quelle
Ich verachte die Inversion der Abstraktion oder die Neuerfindung von Grundelementen auf niedriger Ebene zusätzlich zu Grundelementen auf hoher Ebene. Manchmal wird dies jedoch von schlechten Sprachdesignern verursacht, nicht von schlechten Programmierern. Beispiele:
Verwenden einer einzelnen Methodenklasse ohne Elementvariablen und einer entsprechenden Schnittstelle (implementiert in Form von Tabellen mit Funktionszeigern) anstelle eines Funktionszeigers. Beachten Sie, dass Sie in Sprachen wie Java möglicherweise keine Wahl haben.
In MATLAB und R besteht das Bestehen darauf, dass alles eher ein Vektor / eine Matrix als ein Primitiv ist.
Während wir MATLAB verprügeln, wie wäre es mit der Tatsache, dass es keine ganzen Zahlen hat. Wenn Sie also eine ganze Zahl benötigen, müssen Sie ein Double verwenden.
Rein funktionale Sprachen, in denen Sie Funktionsaufrufe verwenden müssen, um eine Schleife zu schreiben.
quelle
Es wäre definitiv Kopieren / Einfügen, ich habe gesehen, wie viel schlechter Code gemacht wurde, das und Cowboy-Codierung und alles, was daraus resultiert. (Gottklassen, extra große Methoden, schlecht durchdachte Algorithmen usw.)
Und wenn Entwurfsmuster zulässig sind, würde ich sagen: Ein Projekt als eine Reihe von Aktionen aus einem Plan ausführen, ohne eine Entwurfs- oder Domänenanalyse durchzuführen.
quelle
Mehrzweck-Java-Bohne -
Eine Java-Bean mit vielen Variablen, die in verschiedenen Operationen verwendet wird. Jede Operation verwendet eine beliebige Teilmenge der Bean-Variablen und ignoriert die anderen. Ein paar Variablen für den GUI-Status, ein paar Variablen für die Weitergabe zwischen Komponenten, einige, die wahrscheinlich nicht einmal mehr verwendet werden. Die besten Beispiele haben keine Dokumentation, die die Wertschätzung des Musters behindern würde.
Ich kann auch den Geliebten nicht vergessen
quelle
Ein ehemaliger Mitarbeiter hatte die Angewohnheit, Objekte durch Überschreiben ihrer Eigenschaften wiederzuverwenden, anstatt einfach neue zu erstellen. Ich hätte mir nie vorstellen können, wie viele Probleme dies bei der Implementierung neuer Funktionen verursacht hat.
quelle
Etwas, das mir viel Kummer bereitet hat, ist das Muster "Große Karte am Himmel". Eine Karte herumwerfen, anstatt die richtigen Objekte zu verwenden. Sie haben keine Ahnung, welche "Variablen" es enthält, ohne zu debuggen, und Sie wissen nicht, was es enthalten könnte, ohne den Code rückwärts zu verfolgen. Ordnet Strings normalerweise Objekten oder Strings Strings zu, die Sie möglicherweise in Grundelemente analysieren sollen.
quelle
Eines meiner bevorzugten Anti-Patterns für die Entwicklung ist die Verwendung eines Datenbank- "Designs", bei dem einer oder mehreren Tabellen programmgesteuert kontinuierlich zusätzliche Spalten hinzugefügt werden müssen . Dies ist ein Cousin des "Designs", der für jede Instanz einer Entität eine neue Tabelle erstellt. Beide stoßen unweigerlich auf Einschränkungen des Datenbankservers, aber normalerweise erst, wenn das System schon seit einiger Zeit in Produktion ist.
quelle
Ich denke, eines der schlimmsten Anti-Patterns, die ich je gesehen habe, ist die Verwendung einer Datenbanktabelle als temporärer Speicher anstelle des Computerspeichers.
Die Problemdomäne ist proprietär, was es mir nicht erlaubt, sie zu erklären, aber es ist nicht notwendig, das Grundproblem zu verstehen. Dies war eine in Java geschriebene GUI-Anwendung mit einer Backend-Datenbank. Es sollte bestimmte Eingabedaten übernehmen, bearbeiten und dann die verarbeiteten Daten in die Datenbank übertragen.
Unser Projekt hat einen ziemlich komplizierten Algorithmus, der Zwischenwerte für die spätere Verarbeitung speichert. Anstatt die temporären Objekte in ... Objekte zu kapseln, wurde eine Datenbanktabelle wie "t_object" erstellt. Jedes Mal, wenn ein Wert berechnet wurde, wurde er dieser Tabelle hinzugefügt. Nachdem der Algorithmus seine Arbeit beendet hat, wählt er alle Zwischenwerte aus und verarbeitet sie alle in einem großen Map-Objekt. Nachdem die gesamte Verarbeitung abgeschlossen war, wurden die verbleibenden Werte, die zum Speichern markiert wurden, zum realen Datenbankschema hinzugefügt und die temporären Einträge in der Tabelle "t_object" wurden verworfen.
Die Tabelle wurde auch wie eine eindeutige Liste verwendet, Daten konnten nur einmal existieren. Dies wäre vielleicht ein anständiges Merkmal des Entwurfs gewesen, wenn wir Einschränkungen für die Tabelle implementiert hätten, aber am Ende haben wir die gesamte Tabelle durchlaufen, um festzustellen, ob die Daten vorhanden waren oder nicht. (Nein, wir haben nicht einmal Abfragen verwendet, die where-Klauseln mit CONTAINS verwendet haben.)
Einige der Probleme, auf die wir aufgrund dieses Designs gestoßen sind, waren speziell das Debuggen. Die Anwendung wurde für Pipeline-Daten erstellt, sodass mehrere GUIs vorhanden sind, die die Daten vorverarbeiten, bevor sie zu diesem Algorithmus gelangen. Der Debugging-Prozess bestand darin, einen Testfall zu verarbeiten und dann direkt nach Abschluss des obigen Abschnitts anzuhalten. Dann würden wir die Datenbank abfragen, um zu sehen, welche Daten in dieser Tabelle enthalten waren.
Ein weiteres Problem, das wir festgestellt haben, war, dass Daten nicht ordnungsgemäß aus dieser temporären Tabelle gelöscht wurden, was in Zukunft die Ausführung beeinträchtigen würde. Wir haben festgestellt, dass dies darauf zurückzuführen ist, dass Ausnahmen nicht ordnungsgemäß behandelt wurden und die Anwendung daher nicht ordnungsgemäß beendet wurde und die Daten in der Tabelle, über die sie die Kontrolle hatte, nicht gelöscht wurden.
Wenn wir Basic Object-Oriented Design verwendet und alles im Speicher behalten hätten, wären diese oben genannten Probleme niemals aufgetreten. Erstens wäre das Debuggen einfach gewesen, da wir leicht Haltepunkte in der Anwendung einrichten und dann den Speicher im Stapel und im Heap untersuchen könnten. Zweitens wäre der Java-Speicher bei einem abnormalen Beenden der Anwendung auf natürliche Weise bereinigt worden, ohne sich Gedanken über das Löschen aus der Datenbank machen zu müssen.
HINWEIS: Ich sage nicht, dass dieses Muster von Natur aus schlecht ist, aber in diesem Beispiel fand ich es unnötig, wenn grundlegende OO-Prinzipien ausgereicht hätten.
Ich bin mir nicht sicher, wie dieses Anti-Muster heißen soll, da dies das erste Mal ist, dass ich so etwas gesehen habe. Gibt es gute Namen für dieses Muster?
quelle
Cart-Before-The-Horse - auch bekannt als YouMightNeedIt
Beispielsweise:
quelle
IMO ist das schlimmste Anti-Pattern, das ich je gesehen habe, das Anti-Pattern "Wir brauchen keine stinkenden Muster": Die Idee, dass Design-Patterns Zeitverschwendung sind und Sie Code schneller schreiben können, indem Sie ihn einfach zusammenfügen und kopieren / nach Bedarf einfügen.
Lobende Erwähnung verdient Code, der ein Objekt aus der Datenbank mit dem alten VB6-Stil lädt:
an sich kein wirkliches Anti-Muster, zeigt aber, dass es nicht möglich ist, die richtige Architektur auszunutzen und Bedenken zu trennen.
Auch solche Dinge:
quelle