Refactoring während der Programmierung

9

Wenn ich mit einem Problem konfrontiert werde, insbesondere wenn es von Natur aus kompliziert ist, versuche ich, mir etwas Zeit zu nehmen, um über den Ansatz nachzudenken, den ich zur Lösung des Problems verfolgen werde. Trotzdem denke ich beim Programmieren der Lösung häufig an Details des Problems, das ich verpasst habe, und passe den Code entsprechend an.

Das Ergebnis ist ein Code-Durcheinander, das überarbeitet werden muss.

Ich möchte "umgestalten, während ich gehe", aber obwohl es einfach genug klingt, fällt es mir wirklich schwer, es zu tun. Wenn das Detail, das ich verpasst habe, klein ist, ist es verlockend, ein kleines Update an meinem Design vorzunehmen, anstatt das, was ich bereits geschrieben habe, zu löschen und es so zu schreiben, wie es sein soll.

Es klingt wie eine Frage mit einer offensichtlichen Antwort, aber gibt es irgendwelche Techniken, um "Refactor as you go" besser zu machen? Ich weiß, dass dies ein gutes Prinzip ist, aber ich scheitere immer wieder daran.

Kirby
quelle

Antworten:

17

Wahrscheinlich ist die grundlegende Beobachtung in Fowlers Refactoring-Buch, dass es viel besser ist, Änderungen, die das Codeverhalten beeinflussen, von Änderungen zu trennen, die dies nicht tun. Diejenigen in der letzteren Kategorie nennen wir "Refactoring". Wenn Sie diese Änderungen mischen, bringen Sie sie durcheinander - also nicht. Sie können zwischen Codierungs- und Refactoring-Modus hin und her wechseln, aber nicht beide gleichzeitig ausführen. Denn wenn Sie es versuchen, werden Sie nicht wissen, was Sie falsch gemacht haben.

Wenn Sie versuchen, eine verhaltensmodifizierende Änderung einzuführen, und das Verhalten sich nicht ändert: Sie haben etwas falsch gemacht; Überprüfen Sie es und beheben Sie es. Vielleicht einfach zurückrollen.

Wenn Sie versuchen, ein Refactoring einzuführen, und sich das Verhalten ändert : Sie haben etwas falsch gemacht; Überprüfen Sie es und beheben Sie es. Vielleicht einfach zurückrollen.

Sie können diese einfache Beurteilung nicht vornehmen, wenn Sie beide Änderungen gleichzeitig versuchen. Sie können es auch nicht, wenn Sie keine Unit-Tests haben. Schreibe Ihnen. Und mach eins nach dem anderen.

Carl Manaster
quelle
1
Interessante Ratschläge ... Obwohl, wie alle Ratschläge, nicht 100%. Ich denke, dieser Rat funktioniert gut, wenn Sie einen kleinen Code relativ klein umgestalten. Aber manchmal gehen auch radikale Umgestaltungen, wie das fast vollständige Umschreiben, mit brandneuen Funktionen einher - und es ist effizient, beides gleichzeitig durchzuführen.
Tomas
3
@Tomas: Die Frage war eindeutig "Refactoring as you go", ebenso wie Carls Antwort (+1 von mir). Ein "fast vollständiges Umschreiben" ist kein Refactoring ... es ist ein Umschreiben.
Amos M. Carpenter
1
Nicht nur das Codieren mit Refactoring zu vermischen wird die Dinge durcheinander bringen, sondern auch gleichzeitig verschiedene Refactorings durchführen .
Rangi Lin
6

Folgendes mache ich oft: Hinterlassen Sie sich Notizen als Kommentare oder sogar als auskommentierten Code. Wenn der schlampige Code funktioniert, können Sie ihn jetzt einfach neu organisieren.

Außerdem ist das Refactoring von Natur aus nichts Falsches. Stellen Sie lediglich sicher, dass Sie Möglichkeiten haben, um zu testen, ob Ihr refactored Code keine neuen Fehler verursacht, bevor Sie fortfahren.

Luke Dennis
quelle
einverstanden. Es ist oft einfacher, hässlichen Arbeitscode in schönen Code zu verwandeln, als es von Grund auf neu zu versuchen. Sie müssen nur ehrlich sein und sich die Zeit geben, Ihre Lösung zu reinigen, sobald sie funktioniert.
Bunglestink
2
Achten Sie jedoch darauf, dass Sie nicht zu viel auskommentierten Code hinterlassen, da sonst alles durcheinander gerät. Wenn Sie fehlerhaften Code ersetzt haben, sollten Sie ihn im Allgemeinen einfach löschen. Auch wenn es sich um ein Gruppenprojekt handelt, werden Ihre Mitcodierer Sie im Allgemeinen nicht mögen, wenn Sie auskommentierten Code ohne triftigen Grund festlegen.
user24795
1
Mein Ansatz: Wenn Sie sich nicht sicher sind, was Sie tun, kommentieren Sie den alten Code aus. Geben Sie Ihre Initialen und das Datum an . Wenn Sie auf Dinge stoßen, die mit einem alten Datum nicht mehr relevant zu sein scheinen, löschen Sie sie, insbesondere wenn Ihre Initialen darauf stehen. Wenn Sie alten Code reaktivieren und nicht wissen, warum er deaktiviert wurde, fügen Sie eine gründliche Erklärung hinzu. Wenn jemand (Sie vielleicht) ihn später wieder so einsetzen möchte, wie er war, wissen Sie, dass Sie sich in einer Endlosschleife befinden und weiß, wie man da rauskommt.
RalphChapin
5

Eine weitere gute Faustregel ist, dass jede Methode nur eines tun sollte.

Wenn Sie die Verarbeitung dessen, was Sie implementieren möchten, in kleine diskrete Schritte aufteilen und die Schritte als Methoden codieren, werden Sie feststellen, dass das einzige Refactoring, das Sinn macht, darin besteht, das zu ändern Reihenfolge, in der die Methoden aufgerufen werden, oder um einige Methoden aus dem Ausführungspfad herauszulassen.

Da Ihre Methoden diskret sind, können Sie jede einzelne Methode neu faktorisieren, solange der zurückgegebene Wert dem entspricht, der er sein sollte. Keiner der anderen Codes ist klüger, wenn eine Änderung vorgenommen wurde.

Auf diese Weise können Sie im Laufe der Zeit schrittweise Verbesserungen an Ihrem Code vornehmen, indem Sie hier und da einfach eine Methode optimieren. Die Gesamtlogik ändert sich nicht, nur die Details eines bestimmten Schritts.

Wenn Sie dies von Methoden zu Klassen verfolgen, in denen Ihre Klassen nur ein einzelnes Objekt darstellen oder darstellen, werden Sie feststellen, dass Ihr Refactoring genau wie bei den Methoden nur eine Umbesetzung der Reihenfolge ist, in der Ihre Klassen erstellt und verwendet werden und weniger über das tatsächliche Ändern der Detaillogik.

Sie wissen, dass Sie den Sweet Spot erreicht haben, wenn sich die Programmspezifikation drastisch und plötzlich ändert, aber Sie können fast alle erforderlichen Änderungen vornehmen, indem Sie einfach die Beziehungen zwischen Ihren Objekten ändern - ohne deren interne Implementierung zu ändern! Es fühlt sich an, als würdest du plötzlich Nirvana erlangen!

Viel Glück und möge Ihr ganzer Code fehlerfrei sein!

Rodney

rpbarbati
quelle
3

Unit-Tests des Codes könnten helfen.

Edson Medina
quelle
2

Ist es möglich, dass Sie Schnittstellen so schreiben, als würden Sie ein Problem von oben nach unten lösen, aber dann von unten nach oben implementieren? Wenn ja, dann denke ich, dass dies die logische Nichtübereinstimmung ist, die Ihnen Probleme verursacht.

Basierend auf dem, was Sie beschreiben, ist es möglicherweise besser, das Problem aufzuschlüsseln, damit Sie sich mindestens eine Sache überlegen können, die Sie tun müssen, und dann genau das zu implementieren. Denken Sie an eine andere Sache, die Sie tun müssen, und implementieren Sie genau das. Machen Sie weiter und erstellen Sie Ihre Lösung so, dass Sie zuerst die absoluten Grundlagen schreiben, dann die Bausteine, die darauf liegen, und so weiter nach oben, bis Sie die eigentliche Lösung gefunden haben. Ich neige dazu zu finden, dass die vollständige Lösung, selbst bei schwierigen Problemen, dazu neigt, sich an Sie heranzuschleichen und plötzlich herauszuspringen, wenn Sie einem solchen Ansatz folgen.

Wenn Sie die Zwischenbausteine ​​logisch fokussiert halten und jedes Codesegment absichtlich geschlossen und begrenzt halten, sollte der Umfang des Refactorings, den Sie durchführen müssen, immer gering und isoliert sein.

Tommy
quelle
Das ist was ich tue, denke ich. Ich schreibe oft die Gliederung dessen, was ich tun möchte - wie zum Beispiel im Entwurfsmuster der Vorlagenmethode. Dann implementiere ich diese Methoden. Wenn ich zu den Details komme, stelle ich manchmal fest, dass in der Originalvorlage etwas nicht stimmt.
Kirby
1

... es ist verlockend, ein kleines Update an meinem Design vorzunehmen, anstatt das, was ich bereits geschrieben habe, zu löschen und es so zu schreiben, wie es sein soll .

Nichts soll sein. Das einzig vermeintliche ist das:

  1. Sie tun können , jede , was Sie wollen
  2. Ihre Lebenszeit / Arbeitszeit ist begrenzt und Sie können nur eine begrenzte Anzahl von Dingen erreichen.

Was willst du? Ein abgeschlossenes absolut perfektes Super-Duper-Excellent-Clean-Code-Projekt oder drei abgeschlossene Projekte, nur 70% -Code-Eleganz im Vergleich zum ersteren, aber 3 mal 95% der aus Anwendersicht? Was wird für die Welt, für Ihr Volk, für Ihre Mission nützlicher sein?

Was willst du?

Natürlich könnte es sich auf lange Sicht für den Refactor auszahlen (verkürzt die MTCE-Zeit usw.), aber nur auf lange Sicht. Wir Programmierer sind oft versucht, viel früher als nötig umzugestalten und zu optimieren. Wir überarbeiten häufig einen Code, der nicht weiterentwickelt wird, was Zeitverschwendung bedeutet.

Ich benutze meine eigene goldene Regel von 2-3. Bei der ersten Verwendung eines bestimmten Codes bastle ich ihn so schnell wie möglich. Es lohnt sich fast nie, über eine allgemeinere Verwendung nachzudenken, da Sie noch nicht genügend Informationen darüber haben, welche Anwendungsfälle auftreten könnten. Außerdem wird dieser Teil des Codes möglicherweise nie wieder verwendet. Wenn der Code zum zweiten Mal benötigt wird, versuche ich, den ersten Code allgemeiner zu gestalten, um ihn auch auf diesen Fall anzuwenden, oder ich entscheide mich, ihn zu kopieren (aber das gefällt mir nicht). Bei der dritten Verwendung habe ich das Gefühl, dass ich genügend Informationen habe, um sie umzugestalten, und da dieser Teil des Codes wirklich verwendet zu werden scheint, denke ich, dass es sich auszahlt.

Tomas
quelle
0

Das Ergebnis ist ein Code-Durcheinander, das überarbeitet werden muss.

Blasen Sie das Problem einfach durch, bis Sie es verstanden haben. Machen Sie dann eine neue, korrekte Implementierung, nachdem Sie die Form kennen.

Um Ihre Frage allgemeiner zu beantworten: Erinnern Sie sich daran, dass notwendige Änderungen im Allgemeinen weniger Welligkeit / erneutes Testen verursachen, wenn sie früher als später vorgenommen werden.

Justin
quelle