Gibt es Ausnahmefälle, in denen wir doppelten Code akzeptieren können?

57

Ich arbeite an einem Softwareprojekt, in dem wir drei APIs erstellen müssen. Ein für den Heim- Banking - Kanal, eine für die Agentur Kanal und ein dritte für den mobilen Kanal.

Die Agentur-API ist die vollständigste, da sie alle Funktionen bietet. Dann die etwas kleinere Home-API und dann die mobile API.

Die Architekten haben hier eine gemeinsame Ebene erstellt (kanalübergreifende EJB-Services, die von allen APIs gemeinsam genutzt werden). Aber dann sind die APIs anders.

Derzeit gibt es keinen großen Unterschied zwischen den APIs. Das große Team startete mit dem Agentur-Channel und wir passen ihn jetzt für den Home-Channel an. Wir bereichern nur Objekte speziell für unsere Home-App. Ansonsten ist der Code zwischen den APIs zu 95% ähnlich. Die APIs basieren auf Spring MVC und enthalten Controller, Modelle und einige Dienstprogramme.

Grundsätzlich machen die Controller das Mapping von BO zu ChannelObject (es scheint mir nicht der richtige Ort dafür zu sein) und einige zusätzliche Dienstprogramme und Serializer. Alles ist vorerst doppelt vorhanden. Sie sagen, dass der Grund für die Duplizierung ist, dass sie die APIs unabhängig wollen. "Wenn wir morgen ein anderes Verhalten für zu Hause als für die Agentur oder das Handy wollen, werden wir keine Probleme haben !!"

Gibt es einen Fall, in dem wir doppelten Code akzeptieren sollten?

Mohamed Amine Mrad
quelle
22
Und wenn drei Morgen später die Entscheidung fällt, dass sie einen konsistenten Datenzugriff und eine konsistente Darstellung zwischen allen APIs wünschen ... nun ja ... "Kampf!"
Becuzz
26
Doppelter Code ist nicht unbedingt eine schlechte Sache. Das Sprichwort "TROCKEN ist der Feind der Entkopplung" kann nicht genug betont werden. Habe gesagt, dass das Entwerfen für die Zukunft und nicht für jetzt wirklich wirklich eine sehr schlechte Sache ist. Diese Zukunft kommt so gut wie nie zustande. Entwerfen Sie stattdessen eine stark entkoppelte Lösung, die durch gute automatisierte Tests für den aktuellen Bedarf abgedeckt wird. Wenn dann in Zukunft etwas anderes benötigt wird, ist es einfacher, es zu ändern.
David Arno
2
Ich denke, die beiden Fälle, in denen ich das Duplizieren von Code noch nie bereut habe, sind: (a) Der duplizierte Code ist ein sehr kleiner und nicht sehr wichtiger Teil der Gesamtmenge, und (b) ich kopiere Code von einem System, das bereits abstirbt in ein neues System für Langlebigkeit ausgelegt. Es gibt viele andere Fälle, in denen ich bittere Tränen geweint habe, nachdem ich Code gegabelt habe.
Michael Kay
14
Wo ich gearbeitet habe, wurde oft darauf hingewiesen, dass man (oft) einmal duplizieren und das dritte Mal die Gemeinsamkeit abstrahieren sollte. Dadurch entfällt der Zeitgeist für eine frühe, möglicherweise unangemessene Abstraktion, die die Kopplung anstelle des Zusammenhalts erhöht. Wenn zukünftige Anforderungen tatsächlich gut verstanden werden, können natürlich Ausnahmen gemacht werden.
Pieter Geerkens
3
Ein trivialer Fall, in dem doppelter Code akzeptabel sein kann, ist, wenn er automatisch generiert wird
samgak

Antworten:

70

Vervielfältigung kann das Richtige sein, aber nicht aus diesem Grund.

Die Aussage "Wir möchten möglicherweise, dass sich diese drei Stellen in der Codebasis unterschiedlich verhalten, obwohl sie im Moment identisch sind" ist kein guter Grund für eine Duplizierung in großem Maßstab. Dieser Begriff könnte für jedes System gelten und zur Rechtfertigung von Duplikaten herangezogen werden , was offensichtlich nicht zumutbar ist.

Vervielfältigung nur toleriert werden , wenn das Entfernen es wäre insgesamt teurer jetzt aus einem anderen Grunde (kann nicht von einem guten Augenblick, aber da kann man sicher sein , sein - praktisch alles , was in der Programmierung ist ein Kompromiss und nicht als Gesetz).

Für das, was Sie tun, könnte die richtige Lösung beispielsweise darin bestehen, das gerade duplizierte Verhalten in eine Strategie oder ein anderes Muster zu extrahieren, das das Verhalten als Klassen modelliert und dann drei Instanzen derselben Klasse verwendet. Auf diese Weise, wenn Sie tun das Verhalten in einer der drei Stellen ändern möchten, müssen Sie nur eine neue Strategie erstellen und instanziieren , dass an einem Ort. Auf diese Weise müssen Sie nur einige Klassen hinzufügen und den Rest der Codebasis nahezu unberührt lassen.

Kilian Foth
quelle
1
Wenn sich zwei Dinge gleich verhalten, ist das eine Verdoppelung. Obwohl sie sich nicht aus einem bestimmten Grund gleich verhalten, sollten sie nicht zusammengeführt werden. Kann man einen gemeinsamen Teil der Implementierungen extrahieren? Manchmal gibt es Bausteine, die noch nicht abstrahiert sind, wer weiß.
Deduplizierer
32
Als Beispiel hatten wir ein Stück Code, das von drei Teilen unserer Anwendung verwendet wurde, und es war ziemlich schrecklich geschrieben, mit vielen kleinen bedingten Verzweigungen überall, um Ausnahmen für jede dieser drei zu behandeln. Aber , und das war das Wichtige, es wurde zwei Jahre lang intensiv genutzt, ohne dass es zu nennenswerten Fehlern kam. Also , wenn ein vierte Teil der Anwendung benötigte etwas damit zu tun, aber auch hier etwas anders, die Entscheidung, gerade gemacht wurde nicht berührt den fehlerhaften Code, der einwandfrei lief, und kopieren Sie es einfach und erstellen Sie eine besseren geschrieben, flexible Basis für die Zukunft.
KRyan
2
Vervielfältigung ist das Richtige, wenn die Kosten für die Lesbarkeit im Vergleich zu den Wartungskosten, die letztendlich aneinander gebunden sind, zu hoch sind. Ich denke, dass dies in diesem Szenario überhaupt nicht zutrifft und in einem Projekt oft im kleineren Maßstab gesehen wird, nicht so etwas. Selbst dann ist es sehr selten, dass Sie in eine Situation geraten, in der dies jemals der Fall ist. Dies kann passieren, wenn Sie eine verschachtelte Nischen-Duplizierung haben, die Sie zwingen würde, das Muster der Vorlagenmethode oder dergleichen zu verwenden, jedoch an kleinen Stellen. Dies führt normalerweise dazu, dass Code verschleiert wird.
opa
Ein Beispiel , wo Vervielfältigung nützlich ist (und „Entfernen es insgesamt teurer Yould jetzt “) eingegeben wird valdation in Web - Anwendungen: Wir auf dem Client eine erste (möglicherweise vereinfachte) Validierung verwenden , so dass der Benutzer ein unmittelbares Feedback über Probleme bekommt; und dann führen wir dieselbe (oder eine gründlichere) Überprüfung auf dem Server durch, da Clients nicht vertrauenswürdig sind.
Hagen von Eitzen
3
@HagenvonEitzen Das muss aber nicht mal eine Verdoppelung sein, je nach Techstack. Möglicherweise haben Sie beispielsweise die JavaScript-Prüfungseingabe im Browser und anschließend die Java-Prüfung auf dem Server, sodass Sie die Funktionalität dupliziert haben. Wenn Sie jedoch Node.js auf dem Server ausführen, können Sie die gleiche JavaScript-Überprüfung im Browser und auf dem Server verwenden, um die Duplizierung zu vermeiden. Sie wollen immer noch der Code laufen an mehreren Stellen (eine vertrauenswürdigen und nicht vertrauenswürdige Umgebung), aber der Code nicht notwendigerweise dupliziert werden.
Joshua Taylor
87

Sandi Metz, eine renommierte Softwareentwicklerin und Autorin im Ruby-Ökosystem, hat einen großartigen Blogbeitrag und einen Vortrag, in dem sie auch über die Beziehung zwischen Vervielfältigung und Abstraktion spricht. Sie kommt zu folgendem Schluss

Vervielfältigung ist weitaus billiger als die falsche Abstraktion

Und ich stimme ihr vollkommen zu. Lassen Sie mich mehr Kontext zu diesem Zitat geben. Manchmal ist es sehr schwierig, die richtige Abstraktion zu finden. In solchen Fällen ist es verlockend, einfach eine beliebige Abstraktion zu wählen, um Doppelarbeit zu vermeiden. Aber später werden Sie vielleicht feststellen, dass Ihre Abstraktion nicht für alle Fälle gilt. Es ist jedoch kostspielig, alles noch einmal zu ändern und einen anderen Weg zu gehen (für eine weitaus bessere Erklärung sehen Sie sich ihr Gespräch an!).

Ja, für mich gibt es Ausnahmefälle, in denen das Akzeptieren von Duplikaten die richtige Entscheidung ist, insbesondere wenn Sie sich nicht sicher sind, was kommen wird und sich die Anforderungen wahrscheinlich ändern werden. Aus Ihrem Beitrag gehe ich davon aus, dass es derzeit viele Überschneidungen gibt, aber Ihre Kollegen schlagen vor, dass sich dies ändern könnte und nicht beide Anwendungen miteinander gekoppelt werden. Meiner Meinung nach ist dies ein gültiges Argument und kann im Allgemeinen nicht außer Acht gelassen werden.

larsbe
quelle
23
Ah ja, wenn Sie die verallgemeinerten Regeln nicht ableiten können, kann der Versuch, sie zu abstrahieren, nur scheitern. Und wenn die Korrespondenz zufällig ist, kann sie nur von kurzer Dauer sein.
Deduplizierer
5
Es mag teuer sein, eine Abstraktion zu ändern, sobald sie vorhanden ist, aber das Entfernen von Duplikaten, sobald sie vorhanden ist, kann noch schwieriger sein. Dies hängt natürlich stark von der Sprache usw. ab. Moderne stark statische Typsysteme können Ihnen dabei helfen, auch größere Änderungen an einer Abstraktion richtig hinzubekommen. Das Synchronisieren duplizierter Features kann Ihnen jedoch von einem Typsystem nicht viel helfen (da die Duplikate im Typsystem nur unterschiedlich sind). Aber ich nehme an, in dynamischen, entenartigen Sprachen ist es eher umgekehrt. so könnte es für Ruby Sinn machen.
links um ca. 10.8.17 Uhr
34

Wenn die Leute mit den Worten "Wenn morgen" über Design nachdenken , ist dies oft ein großes Warnsignal für mich, besonders wenn das Argument verwendet wird, um eine Entscheidung zu rechtfertigen, die zusätzlichen Arbeitsaufwand beinhaltet, für den niemand wirklich weiß, ob dies jemals der Fall sein wird zahlen sich aus und was schwieriger zu ändern oder rückgängig zu machen ist als die gegenteilige Entscheidung.

Die Vervielfältigung von Code reduziert den Aufwand nur kurzfristig, erhöht jedoch den Wartungsaufwand fast sofort, proportional zur Anzahl der vervielfältigten Codezeilen. Beachten Sie auch, dass es nach dem Duplizieren des Codes schwierig wird, die Duplizierung zu entfernen, wenn sich herausstellt, dass dies die falsche Entscheidung war. Wenn Sie den Code jetzt nicht duplizieren, können Sie die Duplizierung später problemlos einführen, wenn Sie sich an DRY halten war die falsche Entscheidung.

In größeren Organisationen ist es manchmal vorteilhaft, die Unabhängigkeit verschiedener Teams gegenüber dem DRY-Prinzip zu bevorzugen. Wenn das Entfernen der Duplizierung durch Extrahieren der zu 95% gemeinsamen Teile der APIs zwei einer neuen Komponente zu einer Kopplung von zwei ansonsten unabhängigen Teams führt, ist dies möglicherweise nicht die klügste Entscheidung. Wenn Sie jedoch nur über begrenzte Ressourcen verfügen und nur ein Team beide APIs verwaltet, liegt es sicher in ihrem eigenen Interesse, keinen doppelten Aufwand zu betreiben und unnötige Code-Duplikationen zu vermeiden.

Beachten Sie außerdem, dass es einen Unterschied macht, ob "Home" - und "Agency" -APIs ausschließlich von völlig unterschiedlichen Anwendungen verwendet werden oder ob versucht wird, eine Komponente zu schreiben, die auf den APIs aufbaut, die auch in einem "Home" -Kontext verwendet werden können wie in einem "Agentur" -Kontext. In diesem Fall wird die Entwicklung einer solchen Komponente wahrscheinlich viel einfacher, wenn die gemeinsamen Teile der APIs genau identisch sind (was nur garantiert werden kann, wenn die gemeinsamen Teile nicht dupliziert werden).

Wenn sich also herausstellt, dass es wirklich unterschiedliche Subteams gibt, die jeweils für die einzelnen APIs verantwortlich sind, jeweils einen anderen Zeitplan und andere Ressourcen haben, ist es an der Zeit, den Code zu duplizieren, aber nicht "nur für den Fall".

Doc Brown
quelle
3
Noch größeres Warnzeichen als "wenn morgen" ist für mich "Das würde sich nie ändern".
abuzittin gillifirca
@abuzittingillifirca: und was hat das mit der frage oder meiner antwort zu tun?
Doc Brown
1
Ich fordere Ihren ersten Absatz heraus.
abuzittin gillifirca
2
@abuzittingillifirca: Nun, lesen Sie die Frage noch einmal: Es geht darum, mit einem "wenn morgen" Argument zu argumentieren, um eine Entscheidung für die Vervielfältigung zu rechtfertigen, die schwer rückgängig zu machen ist , sodass es für bestimmte Fälle schwieriger ist, die Software tatsächlich zu ändern. Es mag ein wenig eingängig sein, aber der beste Weg, Software für die Zukunft veränderbar zu halten, besteht darin, keine (wahrscheinlich falschen) Annahmen über die Zukunft zu treffen, sondern die Software so klein und solide wie möglich zu halten.
Doc Brown
13

Vervielfältigung, um eine Kopplung zu verhindern . Nehmen wir an, Sie haben zwei große Systeme und zwingen sie, dieselbe Bibliothek zu verwenden. Möglicherweise koppeln Sie den Release-Zyklus beider Systeme. Das mag nicht so schlimm sein, aber sagen wir mal, dass ein System eine Änderung einführen muss. Der andere muss die Änderung analysieren und kann betroffen sein. Manchmal kann es Dinge brechen. Selbst wenn beide Parteien in der Lage sind, die Änderungen zu koordinieren, kann es zu vielen Besprechungen kommen, die Manager, Tests, Abhängigkeiten und das Ende des kleinen autonomen Teams durchlaufen.

Sie zahlen also den Preis für duplizierten Code, um Autonomie und Unabhängigkeit zu erlangen.

Borjab
quelle
Dies ist also eine Verdoppelung zwischen Komponenten, um eine Kopplung zu vermeiden. Aber Sie möchten trotzdem eine Vervielfältigung innerhalb von Komponenten vermeiden, oder?
TemplateRex
Nun ja, Sie möchten doppelten Code minimieren, da dies das Verstehen und Ändern Ihres Codes erleichtert. Denken Sie jedoch daran, dass es gute Antworten mit realisierbaren Ausnahmen gibt. Die richtige Abstraktion, um Doppelarbeit zu vermeiden, ist möglicherweise schwer zu finden.
Borjab