Warum ist TROCKEN wichtig?


81

Ganz einfach, warum sollte ich Code schreiben wollen, der für alle Fälle und skalierbare Daten funktioniert, wenn ich den gleichen Vorgang nur ein paar Mal mit ein paar kleinen Änderungen wiederholen muss?

Es ist unwahrscheinlich, dass ich das bald wieder ändern muss.

Es sieht aus wie viel weniger Arbeit, um einfach zu gehen ...

function doStuff1(){/*.a.*/}
function doStuff2(){/*.b.*/}
function doStuff3(){/*.c.*/}

Und wenn ich jemals etwas hinzufügen muss ...

function doStuff4(){/*.d.*/}

Und wenn ich es entfernen muss, entferne ich es.

Es ist schwieriger herauszufinden, wie ich all diese in ein einfaches Muster umwandeln kann, in das ich einfach Daten einspeisen und alle Fälle bearbeiten kann, und eine Reihe von Änderungen vornehmen kann, von denen ich nicht glaube, dass ich sie jemals haben werde machen.

Warum trocken sein, wenn es so aussieht, als würde ein schnelles Ausschneiden und Einfügen so viel weniger Arbeit bedeuten?


11
denn trocken ist noch schneller, wenn man es richtig macht, auch wenn man einen Fehler in a gemacht hat. das wirkt sich auf alle anderen aus
Daniel Little

97
"Es ist unwahrscheinlich, dass ich das bald wieder ändern muss" - Sie können hoffen, aber höchstwahrscheinlich machen Sie hier einen Fehler. Und wenn Sie diesen Code erneut bearbeiten, aber nicht so bald, wird dies die Situation nur verschlimmern. Du wirst vergessen, wo Duplikate sind, und Duplikate werden subtile, aber tückische Diskrepanzen entwickeln. "Schreiben Sie, als ob die Person, die Ihren Code verwaltet, ein gefährlicher Verrückter ist, der weiß, wo Sie leben", um die Klassiker zu zitieren.
9000,

14
Ich denke, Sie können es so ziemlich zusammenfassen: Ein einzelner Punkt der Veränderung ist einfacher zu pflegen.
Falcon

17
Wenn Sie dies nicht selbst beantworten können, müssen Sie eine realere Erfahrung in Bezug auf Entwicklung und Wartung sammeln.
David Heffernan

15
@ Wayne Ich fühlte eine große Störung in der Quelle, als ob Millionen von Programmierern plötzlich vor Angst aufschreien würden.
Inkognito

Antworten:


121

Wenn Sie sich wiederholen, können Sie Wartbarkeitsprobleme erstellen. Wenn doStuff1-3 alle ähnlich strukturierten Code haben und Sie ein Problem in einem beheben, können Sie leicht vergessen, das Problem an anderen Stellen zu beheben. Wenn Sie einen neuen Fall hinzufügen müssen, können Sie einfach verschiedene Parameter an eine Funktion übergeben, anstatt sie überall einzufügen.

Allerdings wird DRY von geschickten Programmierern oft als extrem empfunden. Um sich nicht zu wiederholen, müssen Sie manchmal Abstraktionen erstellen, die so stumpf sind, dass Ihre Teamkollegen ihnen nicht folgen können. Manchmal ist die Struktur zweier Dinge nur vage ähnlich, aber unterschiedlich genug. Wenn doStuff1-4 so unterschiedlich sind, dass Sie durch das Umgestalten nicht wiederholt werden, unnatürlichen Code schreiben oder clevere Codierungs-Backflips ausführen müssen, durch die Ihr Team Sie anstarrt, ist es möglicherweise in Ordnung, sich selbst zu wiederholen. Ich habe mich nach hinten gebeugt, um mich nicht ein paarmal unnatürlich zu wiederholen, und das Endprodukt bereut.

Ich bin immer auf der Seite von DRY und wiederhole mich in seltenen Fällen, wenn ich der Meinung bin, dass die Vorteile der Lesbarkeit das Risiko wert sind, dass jemand vergisst, einen Fehler an mehreren Stellen zu beheben.

Wenn Sie diesen Rat berücksichtigen, klingt es wie in Ihrem Fall

Wiederholen Sie den Vorgang einige Male mit ein paar kleinen Änderungen

Ich würde auf jeden Fall hart arbeiten, um mich in Ihrem Fall nicht zu wiederholen. Unter der Annahme minimaler "Optimierungen" können sie mit unterschiedlichen Parametern behandelt werden, die sich auf das Verhalten auswirken, oder sie können abhängig gemacht werden, um unterschiedliche Unteraufgaben auszuführen.

Warum trocken sein, wenn es so aussieht, als würde ein schnelles Ausschneiden und Einfügen so viel weniger Arbeit bedeuten?

Berühmte letzte Worte. Sie werden es bereuen zu denken, dass, wenn ein Junior-Ingenieur eine Aufgabe bearbeitet, korrigiert oder umgestaltet und nicht einmal merkt, dass die anderen vorhanden sind. Es kommt zur Heiterkeit. Meistens tritt kein Sodbrennen auf. Jede Codezeile kostet mehr. Wie viele Codepfade müssen Sie mit so vielen wiederholten Funktionen testen? Bei einer Funktion müssen Sie nur einen Hauptpfad mit ein paar Verhaltensänderungen testen. Wenn Sie kopieren, müssen Sie jedes doStuff separat testen. Es besteht die Möglichkeit, dass Sie eine verpassen und ein Kunde möglicherweise einen unerwünschten Fehler hat und Sie möglicherweise einige unerwünschte E-Mails in Ihrem Posteingang haben.


2
Ähm, um ganz klar zu sein, ich schlage nicht vor, trocken ist schlecht, diese Frage ist eher von Teufelsanwälten. Ich bin wirklich auf der Suche nach einer logischen Antwort, die ich mit Leuten verknüpfen kann, die denken, dass Ausschneiden + Einfügen + Code optimieren in Ordnung ist.
Inkognito

2
Abgesehen davon gefällt mir Ihre Antwort am besten, da sie beide Fehler in DRY abdeckt: Nicht belästigen und über Bord gehen sowie Auswirkungen erklären. - Zum einen geht es darum, die Lesbarkeit für Fehler zu opfern. Ich würde argumentieren, dass sich wiederholender Code aus dem gleichen Grund weniger lesbar ist, aus dem Sie darauf hinweisen, dass es leicht ist, den Überblick zu verlieren.
Inkognito

16
Ich möchte eine einfache Falle von DRY unterstreichen: ähnlichen Code zusammengeführt. Wenn Sie zwei Anwendungsfälle, die funktionell unabhängig sind , aber passieren sehr ähnlichen Code haben, ist es leicht zu verschmelzen die beiden , weil DRY gut ist . Wenn man sich weiterentwickeln muss, hat man leider oft die unangenehme Aufgabe, die Funktion noch einmal aufzuteilen , dann alle Aufrufstellen durchzugehen und genau zu überlegen, welche hier aufgerufen werden sollen ... Beispiel: LLVM-Strukturtypisierung (alle ähnlichen Typen werden zu einem zusammengeführt) macht es nahezu unmöglich, den IR-Code wieder dem Originalcode zuzuordnen.
Matthieu M.

1
Bingo. Wenn zwei oder mehr Codeteile geändert werden und die Änderungen für alle Teile immer gleich sind, sollten sie zusammengeführt werden. Jedes Stück, das sich auf eine andere Art und Weise ändern muss, sollte nicht zusammengeführt werden. Wenn sich der Code nie ändern wird, spielt es keine Rolle, ob er zusammengeführt wird oder nicht. Die Frage, ob Änderungen gesperrt oder getrennt werden sollen, ist viel wichtiger als die Größe des betreffenden Codes.
Supercat

1
@MatthieuM das ist ein bisschen ein unfaires Beispiel. LLVM wendet strukturelle Typisierung als Optimierung an . Das heißt, die LLVM-Leute haben beschlossen, den Preis für schwer verständliche IR für die Leistungsvorteile zu zahlen. DRY ist normalerweise ein Problem der Wartbarkeit, aber in diesem Fall war es eindeutig eine bewusste Entscheidung, die Wartbarkeit zu verringern.
Benjamin Hodgson

47

Weil DRY später weniger Arbeit sein wird.


DRY: (Wiederholen Sie sich nicht)

Eine Funktion, die ein Argument übernimmt.

def log(arg):
    print(arg)

C & P: (Kopieren & Einfügen)

26 Gazillionen Funktionen tun im Wesentlichen das Gleiche, jedoch mit einem Unterschied von 2 Zeichen.

def logA():
    print('a')

def logB():
    print('b')

...ad infinitum...

Wie wäre es, wenn wir unseren Druck aktualisieren, um genau anzugeben, was gedruckt wird?

TROCKEN:

def log(arg):
    print(arg + "Printed from process foo")

Getan.

C & P:

Sie müssen zurückgehen und jede einzelne Funktion ändern .


Was denkst du wäre einfacher zu debuggen?


10
Außerdem müssen Sie so viele ähnliche Testsuiten schreiben, wie Sie über doppelte Funktionen verfügen.
9000,

Sie haben das Konzept hinreichend illustriert, aber in der Praxis würde niemand das tun, was Sie mit den Gazillion-Funktionen beschrieben haben, nicht auf diese Weise.
Robert Harvey

@Robert Ich würde nicht hoffen! Ich habe eine sehr einfache Aufgabe ausgewählt, um zu versuchen, das Konzept besser zu veranschaulichen und warum es eine gute Sache sein kann.
John

11
@ Robert - haben Sie einen der Artikel auf thedailywtf.com gelesen ;) - es gibt einige da draußen, die genau das tun würden
HorusKol

1
@ 9000 Nicht, wenn Sie keine
Testsuiten

16

Denn auf Ihr Beispiel angewendet:

  • + Lesbarkeit

    Weniger Code führt häufig zu weniger Rauschen . (nicht immer...)

  • + Flexibilität

    Wenn Sie jemals das Verhalten der ändern mussten, doStuffXmöchten Sie sich selbst oder denjenigen töten, der es geschrieben hat.

  • + Erweiterbarkeit

    Wenn Sie die einzelnen Teile in eine Datenstruktur Ihrer Wahl extrahiert und dann einfach mit einem generischen Aufruf darüber iteriert hätten doStuff, könnten Sie genauso gut eine Zeile in Ihre Datenstruktur einfügen, in der Sie einen neuen Eintrag wünschen, oder eine Zeile entfernen und Wenn Sie das Verhalten ändern, müssen Sie es nur bearbeiten doStuff. Einfacher zu warten .

  • + Kosteneffizienz

    weniger Code bedeutet hier:

    • => weniger Entwicklung => geringere Kosten
    • => geringere Fehlerwahrscheinlichkeit => geringere Supportzeit => geringere Kosten
  • + (mögliche) gemanagte Optimierung

    Abhängig von der Sprache hat der Compiler / Interpreter möglicherweise eine größere Chance festzustellen, dass generic doStuffimmer die fast identischen Dinge ausführt, die oftmals ein Aufruf nach dem anderen ausführt , und dies einbinden oder versuchen könnte, es zu optimieren . Wäre wohl nicht für X-Variationen von doStuffX.

  • + Prüfung und Qualität

    Testen ist einfacher: es doStuffmuss getestet werden, und das war's. Naja, nicht genau, aber das deckt schon mehr ab . Lediglich die IO-Erwartungen variieren und müssen unter verschiedenen Bedingungen getestet werden, aber es ist immer noch viel einfacher zu testen und besser zu warten als alle Variationen von doStuffX.

Insgesamt bedeutet dies einen wartbareren Code und eine verbesserte Entwicklungseffizienz für Ihr Team, und es ist eine von vielen bewährten Methoden , die Sie bei der Erstellung robusterer und zuverlässigerer Software unterstützen.


13

Da alle anderen großartige Arbeit geleistet haben, um die Wartbarkeitsprobleme mit doppeltem Code zu erklären, sage ich Folgendes:

Viel Programmieren erfordert, dass Sie über die Zukunft nachdenken, nicht nur über die unmittelbare Gegenwart. Sie haben Recht, dass das Kopieren und Einfügen jetzt einfacher ist, aber die Aussage, dass ich das wahrscheinlich nicht bald wieder bearbeiten muss " zeigt, dass Sie nicht richtig denken. Ja, Sie könnten sich ein bisschen Zeit mit einem kaufen schnelles und schmutziges Kopieren / Einfügen, aber damit zeigen Sie, dass Sie nicht über Ihr unmittelbares Problem hinausblicken und über das Morgen nachdenken können. Sind Sie sicher, dass Sie diesen Code niemals erneut aufrufen müssen? Wissen Sie, dass es solche gibt Können Sie zu 100% garantieren, dass Sie es nicht erneut aufrufen müssen, wenn Ihre nächsten Funktionen implementiert werden müssen? Dies sind Probleme für morgen und müssen berücksichtigt werden, wenn Sie heute entwerfen.

Natürlich kann es vorkommen, dass Kopieren / Einfügen erforderlich ist. Als UI-Entwickler habe ich festgestellt, dass ich manchmal gegen das DRY-Prinzip verstoßen muss. Es ist zum Kotzen, ich erschaudere jedes Mal, wenn es passiert, und zum Glück ist es selten. Aber es kommt vor .

Der Unterschied besteht darin, dass Sie bei einer Verletzung von DRY einen sehr zwingenden Grund haben sollten, und die Aussage, es sei schwieriger, herauszufinden, wie man all diese in ein einfaches Muster umwandelt, ist nicht wirklich eines von ihnen. Es sei denn, Sie befinden sich in einer massiven Zeitkrise und Ihr Chef schreit, um in den nächsten Stunden etwas zu besorgen, oder Sie verlieren Ihren Job. Ich halte dies nicht für eine gültige Begründung.

Verstehen Sie das nicht falsch: Ich versuche nicht, Sie zu strafen oder zu bestrafen, sondern Sie dazu zu bringen, zu erkennen, wo Ihre Mentalität falsch ist. Programmierer investieren in zukünftige Faulheit; DRY ist ein Weg, dies zu erreichen. Die Arbeit, die Sie heute zur Lösung eines schwierigen Konstruktionsproblems leisten, wird sich morgen auszahlen.


Ich bin mir nicht sicher, ob ich mit einem Chef einverstanden bin, der sagt, dass "erledigen oder entlassen werden" ein guter Grund ist, DRY zu verletzen. Technische Schulden, wann hast du Zeit, es richtig zu machen, ist es wirklich zeitsparend, etc?
Inkognito

1
@Incognito, ich habe versucht, ein bisschen ironisch zu sein :)
Bedwyr

7

Es ist unwahrscheinlich, dass ich das bald wieder ändern muss.

Wenn dies wirklich der Fall ist, können Sie möglicherweise damit durchkommen, aber in den meisten Fällen werden Sie an Code arbeiten, der gewartet werden muss. Das bedeutet, die Funktionalität zu erweitern, Fehler zu beheben und andere Verbesserungen vorzunehmen. Wenn Sie kleine Variationen desselben Codes an 10 verschiedenen Stellen haben und eines Tages zu diesem Code zurückkehren und eine Änderung vornehmen müssen, haben Sie jetzt die fehleranfällige Aufgabe, die gleiche Änderung an 10 verschiedenen Stellen vorzunehmen (Sorry, there waren 11 Plätze, du hast einen vergessen und jetzt hast du einen Fehler).

Wenn Sie verallgemeinern können, welches Problem Sie lösen möchten, können Sie Ihren Code einfacher erweitern und beheben, wenn Fehler auftauchen.


Coole Antwort, aber auch wenn ich damit durchkommen könnte, was ist mit dem armen Trottel, der es hinter mir lassen kann? ;).
Inkognito

Siehe: "Meistens arbeiten Sie an Code, der gewartet werden muss" :)
Alex

Selbst dann ist es nur dann der Fall, wenn das, was Sie kopieren und einfügen, zu 100% fehlerfrei ist. Und es ist nicht, und hör auf zu denken, es könnte sein.
Dan Ray

Ich gebe zu, dass ich in der Vergangenheit Sachen kopiert und eingefügt habe, aber nie für etwas, das ich länger als einen Tag behalten würde. Manchmal braucht man nur ein schnelles und schmutziges Einweg-Skript.
Alex

6

Wie ich in der Antwort auf eine andere Frage ausgeführt habe, gehe ich folgendermaßen vor:

  1. Wenn ich zum ersten Mal ein bestimmtes Problem löse, erledige ich es einfach.
  2. Beim zweiten Mal (dh wenn ich ein ähnliches Problem löse) denke ich: hm, vielleicht wiederhole ich mich selbst, aber ich werde mich erst einmal um das schnelle Kopieren und Einfügen bemühen.
  3. Das dritte Mal denke ich: hm, ich wiederhole mich -> mach es allgemein!

Dh bis zu 2 gewinnt ein anderes Prinzip (YAGNI) über DRY. Aber ab 3 (oder 4, wenn ich wirklich faul bin!) Scheine ich es zu brauchen und folge DRY.

Aktualisieren

Einige weitere Ideen aus meiner jüngsten Erfahrung. Ich musste zwei Komponenten A und B, die von einem anderen Team entwickelt wurden, in unser Produkt anpassen / integrieren. Erstens: Die beiden Komponenten A und B sind sich sehr ähnlich, so dass ich schon beunruhigt war, dass sie eine etwas andere Architektur hatten. Zweitens: Ich musste sie anpassen, damit ich froh gewesen wäre, Unterklassen zu verwenden und nur das zu überschreiben, was ich wirklich brauchte.

Also habe ich begonnen, diese beiden Komponenten (von denen jede aus ungefähr 8 C ++ - Klassen besteht) umzugestalten: Ich wollte eine gemeinsame Architektur für A und B haben und dann die Features hinzufügen, die wir benötigen, indem ich Unterklassen definiere. Auf diese Weise wären unsere beiden neuen Komponenten A 'und B' von den vorhandenen abgeleitet worden.

Nachdem ich zwei Wochen lang versucht hatte, aus dem vorhandenen Code eine gemeinsame und gut definierte Struktur zu machen, und während unserer täglichen Besprechungen erklären musste, dass ich wenig Fortschritte machte, weil der ursprüngliche Code zu unordentlich war, sprach ich mit meinem Chef. Wir stellten fest, dass wir nicht mehr als diese beiden neuen Komponenten A 'und B' benötigen würden (es würden nicht vier oder sechs von ihnen geben, nur diese beiden).

Ok, sei es so: Ich habe eine umfangreiche Kopie und Umbenennung der Klassen von A und B durchgeführt und angefangen, die Kopie des Codes anzupassen. Ich habe es in zwei weiteren Wochen zum Laufen gebracht (mache noch ein paar Fehlerbehebungen).

Vorteile: Wir haben die Funktionalität fast fertig und wenn wir alle Fehler behoben haben, sind wir fertig. Wir haben alle Umbauten und Tests von A und B eingespart.

Nachteile: Vor zwei Wochen hat das andere Team eine andere Komponente C geändert, die von A und B verwendet wird. Sie haben A und B angepasst, aber A 'und B' waren ebenfalls defekt und wir mussten sie selbst ändern. Dies führte zu einem neuen Fehler, den wir beheben mussten. Diese zusätzliche Arbeit wäre wahrscheinlich unnötig gewesen, wenn A 'und B' den größten Teil ihres Codes mit A und B geteilt hätten.

Also: Code-Vervielfältigung ist immer gefährlich. Ich denke, es geht immer darum, Kompromisse zu finden, und oft ist es nicht einfach.


5

Nur zur Klarstellung, da ich dies in keiner der anderen Antworten finde:

DRY ist ein Prinzip der Softwareentwicklung, das darauf abzielt, die Wiederholung von Informationen aller Art zu reduzieren .

Jedes Wissen muss eine einzige, eindeutige und maßgebliche Repräsentation innerhalb eines Systems haben.

Das von Andy Hunt und Dave Thomas erwähnte DRY-Prinzip beschränkt sich nicht nur darauf, die Vervielfältigung von Code zu verhindern. Es befürwortet auch die Codegenerierung und alle Automatisierungsprozesse. Ironischerweise könnten die Ergebnisse der Codegenerierung sogar doppelter Code sein ...

Der Grund, warum dies so ist, wurde bereits in den anderen Antworten ausführlich erläutert, aber der Kommentar von Falcon fasst es meiner Meinung nach gut genug zusammen:

Ein einzelner Änderungspunkt ist einfacher zu warten.


Oh wow, ich dachte, das Etikett enthält Daten. Ich werde da ein paar Infos reinstecken.
Inkognito

3

Es gibt so etwas wie zu viel TROCKEN. In diesem Fall können sich zwei Konzepte, die zu einem bestimmten Zeitpunkt als ähnlich genug erscheinen, um Factoring-Code (1) zu rechtfertigen, später als so unterschiedlich herausstellen, dass sie separate Implementierungen verdienen.

Mit anderen Worten, DRY und lose Kopplung stehen manchmal in Konflikt. Wenn Sie erwarten, dass doStuff1 und Freunde bei jeder neuen Version der Software voneinander abweichen, ist es in Ordnung, ihren Code zu duplizieren.

Nach meiner Erfahrung kann es schwierig sein, zu beurteilen, wohin Ihre Software in Zukunft führen wird, und aus diesem Grund ist DRY häufig eine sichere Wahl.

Übermäßig "getrockneter" Code weist normalerweise einen komplexen Steuerungsfluss und zu viele Parameter auf. Was ursprünglich eine einfache Funktion war, wurde später erweitert, um eine neue Funktionalität zu unterstützen, die durch einen zusätzlichen Parameter gesteuert wird. Nach zwei oder drei Iterationen kann die Funktion nicht mehr gewartet werden. Beheben Sie einen Fehler, der in einer Einstellung auftritt, und führen Sie neue Fehler in anderen Einstellungen ein.

Es ist verständlich, dass die Codequalität mit der Entwicklung des Codes häufig abnimmt, aber ich habe Fälle gesehen, in denen eine Mehrparameterfunktion mit Wenn-Dann-Sonst-Spaghetti im Körper das Ergebnis eines wohlmeinenden, aber schlecht durchgeführten Umgestaltungsaufwands war.

(1) Ich verwende das Wort "Code", aber dies gilt auch für das Design.


Es wäre hilfreich, ein Beispiel für "zu viel Trockenheit" anzugeben, da dies das weniger sichtbare Ende des Spektrums ist.
Inkognito

@Incognito: Ich habe meine Antwort bearbeitet. Kein konkretes Beispiel, aber hoffentlich ist klar genug, was ich meinte.
Joh

2

Ich muss die Probleme mit DRY in der relationalen Datenbankwelt erwähnen. Datenbanken sind so konzipiert, dass sie mit satzbasierter Logik und durch sargable Abfragen schnell und gut funktionieren. DRY-Prinzipien führen häufig dazu, dass der Entwickler nicht-Sargable-Abfragen schreibt oder Row-by-Agonizing-Row-Logik verwendet, um vorhandenen Code in mehreren Situationen zu nutzen. DRY- und Leistungsoptimierung sind oft uneinheitlich, und in der Datenbankwelt ist die Leistung in der Regel weitaus kritischer als die Wartbarkeit. Dies bedeutet nicht, dass Sie DRY-Prinzipien überhaupt nicht verwenden sollten, sondern dass Sie sich darüber im Klaren sein sollten, wie sich dies auf die allgemeine Verwendbarkeit der Datenbank auswirkt. Anwendungsentwickler denken zuerst an DRY und dann an die Leistung. Datenbankentwickler denken zuerst an Datenintegrität, dann an die Leistung und dann an die Sicherheit der Daten (Leistung und Sicherheit können in einigen Systemen die Plätze tauschen).

Im Allgemeinen ist mir aufgefallen, dass je mehr Abstraktionsebenen Sie in Datenbankabfragen einfügen, desto langsamer werden sie. Ich möchte nicht sagen, dass ich nicht wollte, dass die Leute, die die Datenbankprogramme selbst entwerfen, es den Entwicklern ermöglichen, DRY zu verwenden, ohne die Leistung der Datenbank zu beeinträchtigen, aber ich entwerfe keine Datenbanksoftware auf dieser Ebene Vielleicht ist der Konflikt zwischen Abstraktion und Leistung in der Datenbank schwieriger zu lösen, als ich vermute. Wir müssen jedoch mit den Systemen arbeiten, wie sie derzeit gebaut werden. Wir können eine bessere Implementierung der DRY-Prinzipien in zukünftigen Releases fordern, die nicht auch die Leistung beeinträchtigen (und im Laufe der Jahre besser geworden sind, aber immer noch problematisch sind). In der Zwischenzeit müssen wir jedoch überlegen, ob DRY der richtige Schritt für diese Datenbank ist in diesem Moment.

Oft sind es jedoch genau die Funktionen, mit denen Sie sicherstellen möchten, dass das DRY-Prinzip erfüllt wird, die der Datenbank enorme Probleme bereiten. Ich sage nicht, niemals DRY zu verwenden, aber übertreibe es nicht.

Beispiele für das, wovon ich spreche. Einmal im Monat müssen Sie eine Million Datensätze importieren. Datensätze können bereits manuell über die Benutzeroberfläche hinzugefügt werden, indem ein gespeicherter Prozess aufgerufen wird. Da dieser Proc für den Import einzelner Datensätze konzipiert wurde, wird jeweils nur ein Datensatz hinzugefügt. Wenn Sie DRY verwenden, um zu vermeiden, dass sich der Einfügecode an zwei Stellen befindet, schreiben Sie einen Cursor, um den proc wiederholt aufzurufen, anstatt die benötigten satzbasierten Importe zu schreiben. Die Zeit für den Import beträgt zwischen 30 Minuten und 18 Stunden. In diesem Fall besteht der richtige Weg, sich an DRY zu halten, darin, den Prozess für die Verarbeitung mehrerer Datensatzimporte zu korrigieren. Leider ist es oft unmöglich oder sehr schwierig, ein Array an einen Proc zu senden (abhängig vom DB-Back-End), und durch Ändern des Proc kommt es zum Absturz der Anwendung.

Skalarfunktionen und Funktionen mit Tabellenwerten werden auch zum Implementieren von DRY-Prinzipien verwendet. Sie können wiederum die Leistung erheblich beeinträchtigen, insbesondere wenn Sie sie so verwenden müssen, dass die Indizes nicht nützlich sind.

Views sind auch gut für die Implementierung von DRY. Wenn Sie DRY jedoch mithilfe von Ansichten implementieren, die Ansichten aufrufen, die andere Ansichten aufrufen, gelangen Sie schnell zu dem Punkt, an dem die Abfragen unter Last eine Zeitüberschreitung aufweisen. Tatsächlich müssen Sie möglicherweise Datensätze mit Millionen von Datensätzen generieren, wenn Sie am Ende nur drei benötigen. Daher kann eine einstufige Ansicht einer komplexen Gruppe von Verknüpfungen zur Implementierung von DRY ausgezeichnet sein (ich habe eine, die wir verwenden, um sicherzustellen, dass alle Finanzberichte denselben Basissatz von Tabellen und Berechnungen für bestimmte Dinge verwenden), und zwar auf mehr als zwei Ebenen und Sie müssen berücksichtigen, ob Sie eine Leistungsstörung erstellen.


1

Die wichtigsten Punkte meiner Antwort sind oben nicht aufgeführt, und so geht es weiter. Sieh DRY in der Regel nicht so sehr anetwas machen. Es mag so formuliert sein, aber es kann wirklich einen ganz anderen und positiven Zweck erfüllen. Es ist ein Signal, anzuhalten, nachzudenken und eine bessere Antwort zu finden. Ich muss nach Möglichkeiten suchen, um eine bessere Lösung zu finden. Es ist die gute Seite eines schlechten Geruchs in meinem Code, der mich dazu veranlasst, mein Design zu überdenken, und mich dazu bringt, es viel besser zu machen. DRY handelt nicht nur von einer kleinen Syntaxverletzung. Es fordert mich heraus, zu modularisieren. Es fordert mich heraus, zu komponieren. Es signalisiert Wiederholungen, die mich daran erinnern, über die Verwendung von Vorlagen und die Codegenerierung anstelle von roher Gewalt und Ignoranz nachzudenken. Es hilft mir herauszufinden, dass ich etwas Zeit finden sollte, um meine Automatisierung zu automatisieren. Es führt Sie zu einem sparsamen Lebensstil! Es hilft dir, mehr Zeit mit cooleren neuen Sachen zu verbringen, als mit nervigen alten, langweiligen Details. Und es gibt Ihnen gute Manieren, guten Atem und einen gesunden Lebensstil! Na ja, vielleicht bin ich ein bisschen in die Irre gegangen ....


DRY hat sehr unterschiedliche Auswirkungen auf mich. Wenn dies jedoch die Auswirkungen auf Sie sind, gefällt mir die Philosophie, dass etwas "ein Signal ist, anzuhalten, nachzudenken und eine bessere Antwort zu finden", und die Herausforderung.
n611x007

1

Ich habe ein altes Legacy-Projekt, bei dem einige der früheren Entwickler sich überhaupt nicht für DRY interessierten. So war die gesamte Codebasis mit Hilfsmethoden wie GetSystemTimeAsString (), LogToFile () und vielen anderen Dingen überfüllt. Einige Methoden wurden leicht an spezielle Bedürfnisse angepasst, aber die meisten waren nur Kopieren und Einfügen.

Leider hatten einige der Methoden subtile Fehler wie char array, die in einigen Fällen nicht lang genug waren und unsichere Dinge wie strcpy () usw. verwendeten.

Es war also eine echte PITA, alle Codefragmente zu finden, zu harmonisieren und die Fehler zu beheben. Und wir harmonisieren und reparieren immer noch Dinge.

Sie wissen nie, ob Sie bei Ihrer ersten Methode einen Fehler gemacht haben und ihn dann mehrmals beheben müssen, weil Sie ihn nur kopiert haben. Und wenn Sie einige der Methoden später verwenden möchten, woher wissen Sie, welche der 5 Methoden in der Codebasis für Ihren Fall jetzt die richtige ist? Also einfach kopieren, anpassen und schon geht es wieder los ...



1

Die Phraseologie "Wiederhole dich nicht" ist etwas zu simpel. Wichtig ist: "Vermeiden Sie, dass ein Teil der potenziell veränderlichen Informationen an zwei unabhängigen Orten eingekapselt wird ."

Wenn ein Programm Widgets verarbeiten soll, die jeweils drei Woozles enthalten und viele Schleifen des Formulars enthalten

for (i=0; i<3; i++)
  thisWidget.processWoozle(i);

Die Erwartung, dass die Widgets drei Woozles enthalten, würde dann in jeder dieser Schleifen gekapselt, und die Aktualisierung des Codes, um eine beliebige andere Anzahl von Woozles pro Widget aufzunehmen, könnte schwierig sein. Im Gegensatz dazu, wenn man sagen würde

#define WOOZLES_PER_WIDGET 3

und jede Schleife wurde neu geschrieben

for (i=0; i<WOOZLES_PER_WIDGET; i++) ...

Ein solches Design könnte es sehr einfach machen, die Anzahl der Woozles pro Widget zu ändern.

Es ist jedoch wichtig zu beachten, dass es zwar wünschenswert ist, Informationen wie die Anzahl der Woozles pro Widget auf einen einzigen Punkt zu konsolidieren, dies jedoch nicht immer praktikabel ist. Manchmal kann es notwendig sein, Logik fest zu codieren, die nur dann funktioniert, wenn die Dinge eine bestimmte Größe haben. Wenn zum Beispiel jede Woozle einen Wert hat und man den mit einem bestimmten Widget verknüpften Median finden möchte, kann es möglich sein, die Werte zu sortieren und den mittleren zu nehmen, und ein solcher Ansatz würde mit einer beliebigen Anzahl von Woozles außer Logik funktionieren Diese Methode wurde speziell für das Ermitteln des Medians von drei Elementen von Hand geschrieben und kann erheblich schneller sein.

Während eine WOOZLES_PER_WIDGET-Konstante den Code lesbarer machen kann, sollte sie kommentiert werden, um zu verdeutlichen, dass ihr Wert nicht geändert werden kann, ohne andere Anpassungen an der Programmlogik vorzunehmen. In diesem Fall würden die Logik, die für drei Elemente fest codiert ist, und die Konstante WOOZLES_PER_WIDGET beide die Informationen duplizieren, "jedes Widget hat drei Woozles", aber die Vorteile einer solchen Duplizierung (höhere Ausführungsgeschwindigkeit) könnten die Kosten überwiegen.


0

Während ich den anderen Postern tatsächlich zustimme, sind alle Kommentare zur Wartbarkeit usw. gültig.

Ich möchte der Debatte eine kleine Gegenstimme hinzufügen.

  • Es ist nur für Programmierer wichtig. Die Leute, die Ihre Löhne zahlen, könnten sich nicht weniger interessieren, solange die Software UAT besteht.
  • In Bezug auf die Wichtigkeit liegt es weit unter den Punkten, wie die richtigen Anforderungen zu erhalten, den Projektsponsoren zuzuhören und pünktlich zu liefern.

Da diese Seite für "Programmierer" ist, ist es sicher zu sagen, dass sich die Frage an den "Standpunkt der Programmierer" richtet. Ihre Aussagen zu Lohnzahlern, UAT und Rang sind natürlich gültig, aber für diese spezielle Frage nicht relevant.
ozz

1
Ich stimme überhaupt nicht zu. Gutes Management versteht die Prinzipien und warum sie gemacht werden, wenn es im Detail erklärt wird. Dies sollte ein ernsthaftes, eingehendes Gespräch sein, nicht 5 Minuten vorbeischauen.
Michael Durrant

2
Ihr zweiter Aufzählungspunkt ist völlig korrekt.
Jim G.

1
@Ozz, Stolz auf dein Handwerk ist wichtig, auch wenn es für einen guten Programmierer notwendig ist, aber vielleicht sollte der "Standpunkt des Programmierers" ein gewisses Maß an Sorge um die "Kundenzufriedenheit" beinhalten.
James Anderson

0

<tl;dr>

Ich konnte nicht alle wiederholten Antworten lesen, daher habe ich möglicherweise etwas verpasst (und werde es selbst wiederholen <= sehen, was ich hier getan habe?).

Hier ist die Liste von Dingen, die großartig sind, um das Duplizieren von Code zu verhindern!

  1. Einfacher zu testen: Sie müssen nur eine 'Kopie' des Codes testen.
  2. Einfacher zu beheben: Sie müssen den Fehler nur in einer 'Kopie' des Codes finden und ihn einmal beheben.
  3. Einfacher zu aktualisieren (wie oben): Erforderliche Änderungen können häufig durch Ändern des Codes an sehr wenigen Stellen vorgenommen werden, da Sie sich die Zeit genommen haben, den Code ordnungsgemäß wiederzuverwenden, und nicht dieselben Zeilen an Hunderten oder Tausenden von verschiedenen Stellen in der Quelle kopiert haben.
  4. Einfacher wiederzuverwenden: Wenn (nicht an wenigen Stellen dupliziert) und in allgemeinen Methoden mit passendem Namen aufbewahrt wird, ist es einfach, sie zu finden und zu verwenden, anstatt eigene Methoden zu schreiben.
  5. Einfacher zu lesen: duplizierter Code ist schwer zu lesen, weil er unnötig ausführlich ist. Es enthält viele Zeilen, die nicht Teil der Logik und der spezifischen beabsichtigten Funktionalität sind (z. B. allgemeine Befehle zum Einrichten der Bühne für die auszuführende Aktion oder allgemeine einfache wiederholte Aufgaben, die an vielen Stellen benötigt werden). Durch sauberen Code werden die Logik und die Funktionalität hervorgehoben, da keine Wiederholung den Code-Raum verschmutzt.
  6. Einfacher zu debuggen, da (1) und (5).
  7. Spart Zeit und Geld und macht in Zukunft noch mehr Spaß. speziell besser robuster Code erstellen. Dies ist die Quintessenz und es ist eine Zusammenfassung von so ziemlich allem oben Genannten. Wenn viele Benutzer dieselbe Funktion verwenden doFoo1(a, b), ist die Wahrscheinlichkeit größer, dass viele der ärgerlichen Fehler und Randfälle aufgedeckt und behoben werden. Wenn jeder den Code kopiert und erstellt doFoo2(specialA)... doFuu2^n(a, b, c)dann dupliziert er die Probleme doFoo1und erstellt konkret viel mehr Arbeit.

</tl;dr>

Lange Version:

Das Problem bei der Codeduplizierung besteht darin, dass sie "exponentiell wächst" (mit anderen Worten, sie wächst schnell), weil Sie beim Duplizieren von Code anderen unwissentlich die Erlaubnis erteilen (zum einen sind Sie nicht mehr in der Lage, sie zu beurteilen) und Sie ermutigen sie, dasselbe zu tun. Sie machen es auch schwieriger, dies nicht zu tun, da es schwieriger ist, nützlichen Code zu erkennen und wiederzuverwenden, wenn die Quelle viele verwirrende redundante Wiederholungen enthält. Vor allem, wenn der Code noch nicht in eine entsprechend benannte Funktion extrahiert wurde. Wenn Sie also auf ein allgemeines, einfach zu lösendes Problem stoßen, werden Sie wahrscheinlich selbst einen Teil des Codes schreiben, der das Problem löst. Und Sie werden wahrscheinlich nicht nach einigen Randfällen suchen und mehr fehlerhaften, nicht getesteten Code hinzufügen.

Eine andere Sache ist, dass dies für einen Anfänger wie ein Problem klingen mag, das nur große Unternehmen betrifft, aber ich fand, dass es winzige Startups nur sehr stark beeinträchtigt (wie in 10.000 Zeilen duplizierten serverseitigen Codes). Es ist ein Geisteszustand. Sie sollten DRY nicht nur beherrschen, sondern sich auch bemühen, andere zu ermutigen, dasselbe zu tun. denn sonst wirst du dich dazu verurteilen, den Code zumeist zu duplizieren. Wenn die DRY-Mittel zur Verfügung stehen und durchgesetzt werden, ist es viel einfacher, sie anzuwenden. Wenn es viel duplizierten Code gibt, ist es viel einfacher, Lösungen zum Kopieren und Einfügen anzuwenden.

Dinge, die ich bei der Code-Duplizierung als schädlich empfinde:

  1. Ist diese Funktion verwendbar? Nehmen wir an, Sie finden eine Funktion, die genau das tut (oder zu tun scheint, was Sie brauchen), woher wissen Sie, ob sie überhaupt richtig funktionieren soll oder ob es sich nur um Code handelt, der dupliziert und verworfen wurde.
  2. Redundanter Code. Manchmal duplizieren Leute Code, verwenden ihn und vergessen ihn (sie können ihn in Zukunft immer wieder duplizieren). Irgendwann entfernt jemand die Aufrufe der duplizierten Funktion an einigen Stellen, um sie umzugestalten, aber die nicht verwendete Funktion bleibt auch dann erhalten, wenn sie nicht aktiv verwendet wird.
  3. Schwer zu finden, wonach Sie suchen. Duplizierter Code nimmt Platz ein und macht das Auffinden nützlicher und benötigter Dinge (mithilfe von Tools wie grep) zu einer schwierigeren Aufgabe, als es sein muss, da Sie Dutzende oder Tausende von Ergebnissen erhalten, für die Sie nur eine Handvoll hätten haben sollen.
  4. (Wurde bereits erwähnt): Schwer zu pflegen, aber auch schwer für Wartungs- und Regressionszwecke zu verwenden. Wenn Testcode dupliziert und nicht richtig in Funktionen extrahiert wird, duplizieren andere ihn. Wird sich jemand die Mühe machen, eine benutzerfreundliche, einfach zu lesende API zu schreiben, um die Lebensqualität zu verbessern? Nach meiner Erfahrung gibt es oft etwas, das die Leute für dringlicher halten, bis es außer Kontrolle gerät.
  5. Codeduplizierung ist schwieriger zu lesen, da sie den Code ausführlich macht, wo er nicht sein muss, an Orten, an denen die Ausführlichkeit keine Informationen über die beabsichtigte Funktionalität hinzufügt: zum Beispiel generische Methodenaufrufe, die [immer und immer wieder] verwendet werden Legen Sie den Grundstein für mehrere Arten von beabsichtigter Funktionalität, und erschweren Sie es, dass diese tatsächliche Funktionalität herausspringt.
  6. Dies wurde viel erwähnt. Wenn der Code falsch ist, muss ein armer Freund oder eine arme Frau jede Verwendung dieses Codes suchen und ändern. Wenn zum Beispiel jemand einen unsicheren SQL-Injection-Aufruf von mysql_query an sehr wenigen Stellen in einer organisierten Klasse verwendet, wo er benötigt wird, wäre es einfach, ihn zu beheben und stattdessen PHP PDO zu verwenden, aber wenn er ihn an mehr als tausend Stellen verwendet und den Aufruf kopiert Außerdem muss der Code, um ihn zu reparieren, praktisch ausgelagert werden oder manchmal gefährlicher, und von Grund auf neu geschrieben werden.
  7. Das Kopieren von Code ist eine schlechte Angewohnheit. Wenn Sie etwas üben, wird es langsam zu einer zweiten Natur und wirkt sich auf die Menschen in Ihrer Umgebung aus. Junior Entwickler sehen, wie du es tust und tun es auch. Sie sollten üben, was Sie predigen, und sich angewöhnen, das Richtige zu tun. Sie lernen mehr. Das Schreiben von nicht dupliziertem Code ist schwieriger und herausfordernder. Es ist eine lohnende Angewohnheit.

Letzte Anmerkungen zur Verhinderung übereifriger Codeduplizierung und Zusammenfassung:

Dies wurde auch schon früher gesagt, aber manchmal führt das Vermeiden von Duplikaten dazu, dass Sie sich "nach hinten beugen" und Dinge tun, die zu raffiniert (oder unwichtig) sind, als dass andere sie verstehen könnten. Das Schreiben von nicht lesbarem Code (oder, wie wir es scherzhaft nennen, „Jobbewahrungscode“) ist ein Problem an sich, auch wenn die Vermeidung von Code-Duplikaten keine Rolle spielt. Ich bin jedoch der Meinung, dass es viel einfacher ist, Code-Duplikationen zu vermeiden, wenn die richtige Infrastruktur und die richtigen Best Practices von Anfang an eingesetzt werden. Oftmals kann man es vermeiden, unintuitive Dinge zu tun Du machst es von Anfang an richtig.

Was macht man richtig? Nun, das ist eine schwer zu beantwortende Frage, aber eine Sache ist, zu definieren, welche Methoden für das Projekt benötigt werden und zu sehen, was bereits von anderen (außerhalb und innerhalb des Unternehmens) implementiert wurde, und dies, wenn möglich, wiederzuverwenden. Dokumentieren Sie alles, was Sie zur Codebasis hinzufügen, und versuchen Sie, sie allgemeiner zu gestalten, als es sein muss, aber das war's. Übertreiben Sie Designmuster nicht, um den Code flexibel zu machen, wo er nicht sein muss.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.