Sollte älterer Code aktualisiert werden, um neuere Sprachkonstrukte zu verwenden, oder sollten veraltete Konstrukte beibehalten werden?


15

Ich möchte einige Verbesserungen an einem noch funktionsfähigen Code vornehmen, der vor langer Zeit geschrieben wurde, bevor die Programmiersprache, in der er geschrieben wurde, an Funktionen zunahm. Theoretisch verwendet das gesamte Projekt die aktuelle Version der Sprache. Dieses spezielle Modul (und in der Tat viele andere Module) ist jedoch immer noch im älteren Dialekt geschrieben.

Sollte ich:

  • Berühren Sie nicht die Teile des Codes, die ich nicht berühren muss, sondern schreiben Sie meinen Patch, indem Sie die neuen Sprachfunktionen verwenden, die das Schreiben des Patches erleichtern, aber in analogen Situationen an keiner anderen Stelle im Modul verwendet werden? (Dies ist die Lösung, die ich intuitiv wählen würde.)
  • Ignorieren Sie die Tatsache, dass Jahre vergangen sind, und spiegeln Sie den Stil wider, der im Rest des Codes beim Schreiben meines Patches verwendet wird, und tun Sie so, als würde ich die gleiche Aufgabe viele Jahre zuvor ausführen? (Diese Lösung würde ich intuitiv für albern halten, aber angesichts der Menge an Aufhebens, die jeder macht, der über „guten Code“ spricht, sollte er auf jeden Fall für Konsistenz sorgen. Vielleicht sollte ich das auch tun.)
  • Das gesamte Modul aktualisieren, um die neueren Sprachkonstrukte und Konventionen zu verwenden? (Dies ist wahrscheinlich die beste Lösung, erfordert jedoch möglicherweise viel Zeit und Energie, die besser für eine andere Aufgabe aufgewendet werden könnten.)

1
@ JerryCoffin Ich werde nicht weiter in Kommentaren streiten: Ich habe auf Meta gepostet, wo wir eine richtige Diskussion führen können.

Antworten:


10

Es ist unmöglich, eine endgültige Antwort auf diese Frage zu geben, da sie zu stark von den Einzelheiten der Situation abhängt.

Konsistenz im Stil der Codebasis ist wichtig, da dies das Verständnis des Codes erleichtert. Dies ist einer der wichtigsten Aspekte der Wartbarkeit.
Sie wären nicht der erste Programmierer, der verflucht wurde, weil er den Code durch das Mischen verschiedener Stile schwer verständlich gemacht hat. Es könnte sogar Sie selbst sein, der in ein paar Jahren den Fluch ausübt.

Andererseits bedeutet die Verwendung neuer Sprachkonstrukte, die beim ersten Schreiben des Codes nicht vorhanden waren, nicht automatisch, dass Sie die Wartbarkeit verringern oder sogar den Stil des Codes verletzen. Dies hängt von den jeweiligen Sprachfunktionen ab, die Sie verwenden möchten, und davon, wie gut das Team sowohl mit dem alten Stil des Codes als auch mit den neuen Funktionen vertraut ist.

Als Beispiel wäre es im Allgemeinen nicht ratsam, funktionale Programmierkonzepte wie map / reduction auf eine Codebasis einzuführen, die vollständig im OO-Stil ist, aber es könnte funktionieren, hier und da eine Lambda-Funktion zu einem Programm hinzuzufügen, das nicht verwendet wurde so etwas schon mal.


1
Ich stimme teilweise nicht zu. Wir sollten dem Open-Close-Prinzip folgen. Deshalb sollten wir versuchen, den neuen Code so weit wie möglich zu isolieren und gleichzeitig den neuen Code mit dem neuesten möglichen Sprachkonstrukt zu schreiben.
Anand Vaidya

3
@AnandVaidya: das ist meiner Meinung nach eine unrealistische Erwartung, da davon ausgegangen wird, dass der alte Code dem OCP folgt oder einfach geändert werden kann, um dem OCP zu folgen, was selten der Fall ist oder einfach den Aufwand nicht wert ist.
Doc Brown

1
Wenn ich ocp sagte, meine ich nicht oops ocp, sondern ocp im Allgemeinen. Das heißt, Sie sollten versuchen, vorhandenen Code so wenig wie möglich zu ändern und Ihren eigenen Code zu isolieren. Das ist sogar mit altem Verfahrenscode möglich. Ich verstehe, dass Spaghetti-Codes nicht auf diese Weise modifiziert werden können, aber für gut gestalteten Code in jedem Paradigma sollte open close leicht anwendbar sein. Möge es oops oder prozedural oder funktional sein.
Anand Vaidya

2
@AnandVaidya: Wenn du nicht OCP meinst, solltest du es nicht so nennen. Ich vermute, was Sie wirklich meinen, ist das, was Feather beim Schreiben von neuem Code in einer Sprout-Methode nennt , sodass man den neuen Codestil auf eine neue, getrennte Methode beschränken kann. Wenn dies möglich und sinnvoll ist, haben Sie Recht, das ist in Ordnung. Leider ist dieser Ansatz nicht immer anwendbar, zumindest nicht, wenn Sie den alten Code DRY behalten möchten.
Doc Brown

@DocBrown: Ich glaube nicht, dass das Open / Closed-Prinzip auf objektorientierte Programmierung beschränkt ist. Sie können Module haben, in denen Sie neue Prozeduren hinzufügen, aber keine vorhandenen ändern, dh Sie behalten die Semantik des vorhandenen Codes bei und schreiben neuen Code, wenn Sie neue Funktionen benötigen.
Giorgio

5

Der Code und sein Aussehen sind weitgehend irrelevant . Was der Code tut, ist wichtig.

Wenn Sie garantieren können , dass das Ändern / Umschreiben des Codes nicht die Funktion des Codes ändert, können Sie den Code nach Herzenslust überarbeiten. Diese "Garantie" ist ein umfassender Satz von Komponententests, die Sie vor und nach Ihren Änderungen ohne erkennbaren Unterschied durchführen können.

Wenn Sie diese Stabilität nicht garantieren können (Sie haben diese Tests nicht), lassen Sie es gut in Ruhe.

Niemand wird Ihnen dafür danken, dass Sie ein Stück geschäftskritischer Software "kaputtgemacht" haben, selbst wenn Sie versucht haben, es "besser" zu machen. "Arbeiten" trumpft mit jedem Mal "besser" auf.

Natürlich gibt es nichts , Sie zu stoppen eine Reihe solcher Tests bei der Schaffung Bereitschaft für eine solche Übung ...


4

Fast alles kann in Bezug auf Kosten und Nutzen analysiert werden, und ich denke, das gilt hier.

Der offensichtliche Vorteil der ersten Option besteht darin, dass sie die Arbeit kurzfristig minimiert und die Wahrscheinlichkeit minimiert, dass etwas kaputt geht, indem der Arbeitscode neu geschrieben wird. Die offensichtlichen Kosten bestehen darin, dass die Codebasis inkonsistent wird. Wenn Sie eine Operation X ausführen, geschieht dies in einigen Teilen des Codes auf eine andere Weise und in einem anderen Teil des Codes auf eine andere Weise.

Beim zweiten Ansatz haben Sie bereits den offensichtlichen Vorteil festgestellt: Konsistenz. Die offensichtlichen Kosten sind, dass Sie Ihren Verstand beugen müssen, um auf eine Weise zu arbeiten, die Sie möglicherweise vor Jahren aufgegeben haben, und der Code bleibt durchweg unlesbar.

Für den dritten Ansatz müssen die offensichtlichen Kosten einfach viel mehr Arbeit leisten. Ein weniger offensichtlicher Preis ist, dass Sie möglicherweise Dinge kaputt machen, die funktionierten. Dies ist besonders wahrscheinlich, wenn (wie so oft) der alte Code unzureichende Tests aufweist, um sicherzustellen, dass er weiterhin ordnungsgemäß funktioniert. Der offensichtliche Vorteil ist, dass Sie (vorausgesetzt, Sie tun es erfolgreich) einen schönen, glänzenden neuen Code haben. Neben der Verwendung neuer Sprachkonstrukte haben Sie die Möglichkeit, die Codebasis zu überarbeiten, was fast immer zu Verbesserungen an sich führt, selbst wenn Sie die Sprache noch genauso verwendeten, wie sie zum Zeitpunkt der Erstellung vorhanden war Arbeit leichter, und es kann durchaus ein großer Gewinn sein.

Ein weiterer wichtiger Punkt: Im Moment scheint es, dass dieses Modul über einen langen Zeitraum hinweg nur minimale Wartung hatte (obwohl das Projekt als Ganzes beibehalten wird). Das deutet darauf hin, dass es ziemlich gut geschrieben und relativ fehlerfrei ist - andernfalls hätte es in der Zwischenzeit wahrscheinlich mehr Wartung erfahren.

Das führt zu einer anderen Frage: Woher stammt die Änderung, die Sie jetzt vornehmen? Wenn Sie einen kleinen Fehler in einem Modul beheben, der die Anforderungen insgesamt noch gut erfüllt, deutet dies darauf hin, dass die Zeit und der Aufwand für die Umgestaltung des gesamten Moduls wahrscheinlich zum größten Teil verschwendet werden - bis sich jemand damit herumschlagen muss Auch hier kann es sein, dass sie sich in etwa an der Position befinden, an der Sie sich gerade befinden. Dabei wird Code beibehalten, der nicht den "modernen" Erwartungen entspricht.

Es ist jedoch auch möglich, dass sich die Anforderungen geändert haben und Sie an dem Code arbeiten, um diese neuen Anforderungen zu erfüllen. In diesem Fall stehen die Chancen gut, dass Ihre ersten Versuche nicht den aktuellen Anforderungen entsprechen. Es besteht auch eine wesentlich größere Wahrscheinlichkeit, dass die Anforderungen einige Überarbeitungsrunden durchlaufen, bevor sie sich wieder stabilisieren. Das bedeutet, dass Sie in (relativ) naher Zukunft mit viel größerer Wahrscheinlichkeit wichtige Arbeiten in diesem Modul ausführen und im Rest des Moduls mit viel größerer Wahrscheinlichkeit Änderungen vornehmen, nicht nur in dem Bereich, den Sie kennen jetzt. In diesem Fall ist es viel wahrscheinlicher, dass die Umgestaltung des gesamten Moduls greifbare, kurzfristige Vorteile mit sich bringt, die die zusätzliche Arbeit rechtfertigen.

Wenn sich die Anforderungen geändert haben, müssen Sie möglicherweise auch prüfen, um welche Art von Änderung es sich handelt und was diese Änderung antreibt. Angenommen, Sie haben Git geändert, um die Verwendung von SHA-1 durch SHA-256 zu ersetzen. Dies ist eine Änderung der Anforderungen, aber der Anwendungsbereich ist klar definiert und recht eng. Sobald Sie SHA-256 ordnungsgemäß gespeichert und verwendet haben, ist es unwahrscheinlich, dass andere Änderungen eintreten, die sich auf den Rest der Codebasis auswirken.

In die andere Richtung tendiert eine Änderung an einer Benutzeroberfläche, selbst wenn sie klein und diskret beginnt, zur Ballonbildung. Das, was als "Ein neues Kontrollkästchen zu diesem Bildschirm hinzufügen" begann, endet also eher wie folgt: "Diese feste Benutzeroberfläche ändern zur Unterstützung von benutzerdefinierten Vorlagen, benutzerdefinierten Feldern, benutzerdefinierten Farbschemata usw. "

Für das erste Beispiel ist es wahrscheinlich am sinnvollsten, Änderungen zu minimieren und auf der Seite der Konsistenz Fehler zu machen. Für letztere zahlt sich ein vollständiges Refactoring viel eher aus.


1

Ich würde für Sie erste Option gehen. Wenn ich codiere, befolge ich die Regel, um den Zustand zu verbessern, in dem er war.

Der neue Code folgt also den bewährten Methoden, aber ich werde keinen Code berühren, der nichts mit den Problemen zu tun hat, an denen ich arbeite. Wenn Sie dies gut machen, sollte Ihr neuer Code besser lesbar und besser wartbar sein als der alte Code. Ich habe festgestellt, dass die Wartbarkeit insgesamt besser wird, denn wenn Sie so weitermachen, ist der Code, den Sie für Ihre Arbeit berühren müssen, immer häufiger der "bessere" Code. Dies führt zu einer schnelleren Problemlösung.


1

Die Antwort hängt , wie so viele andere Dinge auch, davon ab . Wenn die Aktualisierung älterer Konstrukte wichtige Vorteile bietet, wie beispielsweise eine erheblich verbesserte langfristige Wartbarkeit (z. B. Vermeidung von Rückrufaktionen), sollten Sie diese durchführen. Wenn es keinen großen Vorteil gibt, ist Konsistenz wahrscheinlich dein Freund

Darüber hinaus möchten Sie auch vermeiden, zwei Stile in dieselbe Funktion einzubetten, anstatt sie in zwei separaten Funktionen zu vermeiden.

Fazit: Ihre endgültige Entscheidung sollte auf einer Kosten-Nutzen-Analyse Ihres Einzelfalls beruhen.

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.