Verstoß gegen das DRY-Prinzip

10

Ich bin sicher, dass es irgendwo einen Namen für dieses Anti-Muster gibt; Ich bin jedoch nicht genug mit der Anti-Muster-Literatur vertraut, um sie zu kennen.

Stellen Sie sich das folgende Szenario vor:

or0ist eine Mitgliedsfunktion in einer Klasse. Ob gut oder schlecht, es hängt stark von Variablen der Klassenmitglieder ab. Programmierer A kommt und benötigt Funktionen wie, or0aber anstatt aufzurufen or0, kopiert Programmierer A die gesamte Klasse und benennt sie um. Ich vermute, dass sie nicht anruft, or0weil es, wie gesagt, für seine Funktionalität stark von Mitgliedsvariablen abhängt. Oder vielleicht ist sie eine Junior-Programmiererin und weiß nicht, wie sie es von einem anderen Code aus aufrufen soll. Also jetzt haben wir or0und c0(c für Kopie). Ich kann Programmierer A für diesen Ansatz nicht vollständig bemängeln - wir alle haben enge Fristen und hacken Code, um die Arbeit zu erledigen.

Mehrere Programmierer warten, or0so dass es jetzt Version ist orN. c0ist jetzt Version cN. Leider or0schienen sich die meisten Programmierer, die die Klasse enthielten , überhaupt nicht bewusst zu c0sein - was eines der stärksten Argumente ist, die ich mir für die Weisheit des DRY-Prinzips vorstellen kann. Möglicherweise wurde der Code auch unabhängig gepflegt c. So oder so scheint es, dass or0und c0unabhängig voneinander gehalten wurden. Und, Freude und Glück, es tritt ein Fehler auf cN, der nicht auftritt orN.

Ich habe also ein paar Fragen:

1.) Gibt es einen Namen für dieses Anti-Muster? Ich habe das so oft gesehen, dass es mir schwer fällt zu glauben, dass dies kein benanntes Anti-Muster ist.

2.) Ich sehe einige Alternativen:

a.) Fix orN, um einen Parameter zu übernehmen, der die Werte aller benötigten Mitgliedsvariablen angibt. Ändern Sie dann cN, um orNalle erforderlichen Parameter aufzurufen, die übergeben wurden.

b.) Versuchen Sie, Fixes manuell von orNbis zu portieren cN. (Wohlgemerkt, ich möchte das nicht tun, aber es ist eine realistische Möglichkeit.)

c.) Wiederholen, orNum noch cNeinmal, yuck, aber ich liste es der Vollständigkeit halber auf.

d.) Versuchen Sie herauszufinden, wo ein cNDefekt vorliegt, und reparieren Sie ihn dann unabhängig davon orN.

Alternative a scheint auf lange Sicht die beste Lösung zu sein, aber ich bezweifle, dass der Kunde mich diese implementieren lässt. Niemals Zeit oder Geld, um die Dinge richtig zu reparieren, sondern immer Zeit und Geld, um das gleiche Problem 40 oder 50 Mal zu beheben, oder?

Kann jemand andere Ansätze vorschlagen, die ich möglicherweise nicht in Betracht gezogen habe?

Onorio Catenacci
quelle
"Gibt es einen Namen für dieses Anti-Muster?" Das "verletzend-trockene" Anti-Muster? :) IMHO hast du es so ziemlich selbst beantwortet.
Steven Jeuris
Nennen Sie es vielleicht "The Dry Violator"?
FrustratedWithFormsDesigner
2
Ich nenne es: DRY Bumping.
AJC
5
Codierung kopieren und einfügen?
Tylermac
Es wird das Muster "zu viele Köche verderben die Brühe" genannt.
Doc Brown

Antworten:

18
  1. es heißt nur doppelter Code - ich kenne keine ausgefallenen Namen mehr dafür. Die langfristigen Folgen sind wie von Ihnen beschrieben und schlimmer.

  2. Natürlich ist die Beseitigung der Duplizierung die ideale Option, wenn dies nur möglich ist. Es kann viel Zeit in Anspruch nehmen (in einem kürzlich in unserem Legacy-Projekt durchgeführten Fall wurden mehrere Methoden in mehr als 20 Unterklassen in einer Klassenhierarchie dupliziert, von denen viele im Laufe der Jahre ihre eigenen geringfügigen Unterschiede / Erweiterungen evolutionär vergrößert hatten Ich etwa 1,5 Jahre durch sukzessives Schreiben und Umgestalten von Unit-Tests, um alle Überschneidungen zu beseitigen. Ausdauer hat sich jedoch gelohnt.

    In einem solchen Fall benötigen Sie möglicherweise noch eine oder mehrere der anderen Optionen als vorübergehende Korrekturen, selbst wenn Sie sich dazu entschließen, die Duplizierung zu beseitigen. Welche davon besser ist, hängt jedoch von vielen Faktoren ab, und ohne mehr Kontext raten wir nur.

    Viele kleine Verbesserungen können auf lange Sicht einen großen Unterschied machen. Sie benötigen auch nicht unbedingt die ausdrückliche Genehmigung des Kunden für diese - ein kleines Refactoring jedes Mal, wenn Sie diese Klasse berühren, um einen Fehler zu beheben oder eine Funktion zu implementieren, kann im Laufe der Zeit viel bewirken. Nehmen Sie einfach etwas mehr Zeit für das Refactoring in Ihre Aufgabenschätzungen auf. Es ist genau wie bei der Standardwartung, die Software langfristig funktionsfähig zu halten.

Péter Török
quelle
3
+1, nicht nur für die Erwähnung von doppeltem Code, sondern auch für den bloßen Aufwand, der mit Ihrer Geschichte des Code-Refactorings verbunden ist. : D
Andreas Johansson
9

Es gibt einen Verweis auf das WET- Muster (We Enjoy Typing), aber ich weiß nicht, ob es sich um einen Standardnamen handelt.

... Die Softwarelizenzierung ist eine bemerkenswerte Ausnahme von der DRY-Praxis (Don't Repeat Yourself). Der Softwarelizenzierungscode sollte so WET (We Enjoy Typing - das Gegenteil von DRY) wie möglich sein.

Wenn Sie Ihre Lizenzierungslogik an einem Ort isolieren, getrennt von anderen Bedenken, erleichtern Sie die Änderung Ihrer Software erheblich, um die Lizenzierung insgesamt zu deaktivieren. Es ist viel besser, die Lizenzierungslogik in der gesamten Anwendung viele Male zu wiederholen, vorzugsweise so, dass sie während einer einzelnen Ausführung der Software mehrmals ausgeführt wird.

Wir empfehlen beispielsweise, dass Sie während der Installation, beim Start der Anwendung und bei jedem Zugriff auf wichtige Funktionen eine Lizenzprüfung durchführen. Überprüfen Sie die Lizenz während des Startvorgangs nicht einmal und geben Sie diesen Wert weiter. Replizieren Sie stattdessen die Lizenzprüfung in jedem Bereich. Es ist unpraktisch, aber weitaus besser als ein Produkt herauszubringen, das leicht zu knacken ist ...

Jeremy-George
quelle
3
WET kann bedeuten: Schreiben Sie alles zweimal
StuperUser
1
@ SuperUser Ich habe das gestern auf der Tageszeitung entdeckt ...
Jeremy-George
3

Wenn ich dich richtig verstehe, ist in der Klasse zu viel los. Dadurch entstehen Methoden, die nicht dem Prinzip der Einzelverantwortung folgen . Dies führt zu Code, der verschoben werden muss, wobei Teile genommen werden, während andere weggelassen werden. Dies könnte auch viele Mitglieder schaffen.

Sie sollten auch die Eingabehilfen-Modifikatoren überprüfen. Stellen Sie sicher, dass die Dinge, die öffentlich sind, tatsächlich öffentlich sein sollten. Der Verbraucher muss nicht über jedes kleine Mitglied Bescheid wissen ... verwenden Sie die Kapselung.

Dies erfordert einen Refactor. Es scheint auch, dass Code ohne Vorabentwurf geschrieben wird. Schauen Sie sich die testgetriebene Entwicklung an. Schreiben Sie den Code so, wie er aufgerufen werden soll, anstatt den Code aufzurufen, wie auch immer er implementiert ist. In TDD finden Sie einige Hinweise zur Ausführung der Aufgabe.

P.Brian.Mackey
quelle
3

Wenn Sie Code kopieren, führen Sie eine technische Schuld der doppelten Wartung ein, genauer gesagt: Codeduplizierung .

Normalerweise wird dies durch Refactoring behoben. Insbesondere leiten Sie alle Aufrufe an eine neue Funktion (oder eine neue Methode in einer neuen Klasse) um, die den gemeinsamen Code enthält. Der einfachste Weg, um zu beginnen, besteht darin, den gesamten kopierten Code zu entfernen und zu sehen, welche Unterbrechungen Sie beheben, indem Sie die Aufrufe an den allgemeinen Code umleiten.

Es kann schwierig sein, Ihren Kunden dazu zu bringen, dem Refactor-Code zuzustimmen, da es schwierig ist, eine nicht-technische Person davon zu überzeugen, eine technische Schuld zu beheben. Wenn Sie das nächste Mal Zeitschätzungen vornehmen, geben Sie einfach die Zeit an, die erforderlich ist, um Ihre Schätzungen zu überarbeiten . In den meisten Fällen gehen Kunden davon aus, dass Sie den Code während der Korrektur bereinigen.

Spoike
quelle
1

Klingt für mich nach Spaghetti-Code . Die beste Lösung ist ein Refactor / Rewrite.

Ein abwertender Begriff für Quellcode mit einer komplexen und verworrenen Kontrollstruktur, insbesondere einer, die viele GOTOs, Ausnahmen, Threads oder andere "unstrukturierte" Verzweigungskonstrukte verwendet. Es wird so genannt, weil der Programmablauf konzeptionell wie eine Schüssel Spaghetti ist, dh verdreht und verwirrt ...

http://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Spaghetti.jpg/175px-Spaghetti.jpg

Tom Squires
quelle
-1 Refactor und Rewrite sind zwei sehr unterschiedliche Optionen. Totale Umschreibungen, das Wegwerfen von Software, sind niemals eine gute Idee. joelonsoftware.com/articles/fog0000000069.html
P.Brian.Mackey
1
Spaghetti-Code ist IMO ein viel allgemeinerer und lockerer Begriff. Obwohl ein solcher Code häufig Duplikate enthält, können Sie Spaghetti-Code ohne Duplizierung sowie stark duplizierten, aber keinen Spaghetti-Code verwenden.
Péter Török
@ P.Brian.Mackey Ich habe nie gesagt, dass Refactor und Rewrite dasselbe sind. OP sollte entscheiden, welche verwendet werden soll.
Tom Squires
2
Ich war nie ein Fan dieses Artikels. Ich stimme zu, dass das Umschreiben im angeführten Beispiel eine schlechte Idee war, aber nur weil es in diesem Fall eine schlechte Idee war, heißt das nicht, dass es immer eine schlechte Idee ist. Wird das Umschreiben für den Anfang weitere Fortschritte blockieren? Wenn ja, ist das schlecht; wenn nicht, dann ist das bei weitem nicht so schlimm.
Schockieren
@jhocking - Ich glaube, der Sinn der No-Rewrite-Richtlinie besteht nicht darin, den Fortschritt in anderen Programmen zu blockieren, sondern im Laufe der Zeit echte Korrekturen zu verlieren. Dieses magische "if (goldenNugget> 22)" löst, obwohl es schlecht benannt ist, immer noch ein spezifisches Problem, das ohne stunden- oder tagelange Forschung möglicherweise nicht zu identifizieren ist. Nun sollten stattdessen dieselben Daten genommen und verbessert werden. Das ist ein Refaktor. Es rauszuwerfen und zu sagen "Wir machen es beim nächsten Mal richtig" ist Zeitverschwendung. Der gleiche Grund, bereits gelöste Probleme zu lösen, ist Zeitverschwendung. Das Hinzufügen von gutem Code zu schlechten erhöht die Verschuldung
P.Brian.Mackey
0

Sie sagen, Sie können A nicht vollständig beschuldigen - aber das Kopieren einer Klasse auf diese Weise ist eigentlich unverzeihlich. Es ist ein massiver Fehler in Ihrem Codeüberprüfungsprozess. Es ist möglicherweise der massivste Fehler, da überhaupt keine Codeüberprüfung durchgeführt wurde.

WENN Sie jemals denken, dass Sie schrecklichen Code produzieren müssen, um eine Frist einzuhalten, sollte die absolut höchste Prioritätsanforderung für die Veröffentlichung danach darin bestehen, den schrecklichen Code JETZT zu reparieren. Ihr Problem ist also weg.

Das DRY-Prinzip gilt für Situationen, die nicht ganz perfekt sind und verbessert werden können. Das Duplizieren einer Klasse ist ein völlig neues Kaliber. Ich würde es zuerst "duplizierter Code" nennen, und im Laufe der Zeit wird es sich in den schlimmsten aller Zeitverschwender verwandeln, "divergierenden duplizierten Code": mehrere Kopien desselben Codes, die fast, aber nicht ganz identisch sind, und niemand weiß, ob Die Unterschiede sind beabsichtigt, Zufall oder Fehler.

gnasher729
quelle
-3

Fast ein Jahrzehnt zu spät zu dieser Party, aber der Name dieses Anti-Musters ist Divergent Change , wo mehrere Klassen Kopien desselben Verhaltens enthalten, aber wenn Zeit und Wartung fortschreiten und einige Klassen vergessen werden, weichen diese Verhaltensweisen voneinander ab.

Abhängig davon, was das gemeinsame Verhalten ist und wie es geteilt wird, könnte es stattdessen als Shotgun Surgery bezeichnet werden. Der Unterschied besteht darin, dass hier ein einzelnes logisches Merkmal von vielen Klassen bereitgestellt wird und nicht von einem einzelnen.

doOOooonkeyKoooOOOooong
quelle
1
Das sieht nicht gleich aus. Abweichende Änderung ist, wenn viele Änderungen an derselben Klasse vorgenommen werden. Das OP beschreibt die Codeduplizierung. Schrotflintenchirurgie ist auch nicht dasselbe. Shotgun Surgery beschreibt die gleiche Änderung, die an mehreren verschiedenen Klassen vorgenommen wurde.
Robert Harvey