Geringe Auswirkung beim Refactoring und Bereinigen von Code, während auf Anforderungen gewartet wird

17

Ich habe eine vorhandene Codebasis für ein Produkt geerbt, das verwerflich schlampig ist. Das grundlegende Design ist absolut unzureichend, was ich leider nur wenig ohne einen kompletten Refaktor tun kann (HOHE Kopplung, NIEDRIGE Kohäsion, zügellose Vervielfältigung von Code, keine technische Designdokumentation, Integrationstests anstelle von Komponententests). Das Produkt hat eine lange Geschichte, ein hohes Risiko für kritische "Cash-Cow" -Kunden mit minimaler Risikobereitschaft, technische Schulden, die die Griechen erröten lassen, eine SEHR große Codebasis und Komplexität sowie eine kampferprobte defätistische Herangehensweise des Teams an Bugs mir.

Das alte Team sprang in eine andere Division, um die Möglichkeit zu haben, ein anderes Projekt zu ruinieren. Es kommt sehr selten vor, dass ich im Gegensatz zu einem Projektmanagement-Fehler einen Projektfehler mit technischer Inkompetenz erleide, aber dies ist in der Tat einer dieser Fälle.

Im Moment bin ich alleine, aber ich habe viel Zeit, Entscheidungsfreiheit und zukünftige Richtung und die Fähigkeit, ein Team von Grund auf neu aufzubauen, um mir zu helfen.

Meine Frage ist es, eine Meinung zum Thema „Low Impact Refactoring“ für ein Projekt wie dieses zu sammeln, wenn Sie in der Phase des Sammelns der funktionalen Anforderungen etwas Zeit haben. Es gibt Tausende von Compiler-Warnungen, fast alle davon nicht verwendete Importe, ungelesene lokale Variablen, fehlende Typprüfung und unsichere Umwandlungen. Die Code-Formatierung ist so unleserlich und schlampig, dass es aussieht, als ob der Programmierer an der Parkinson-Krankheit leidet und nicht kontrollieren kann, wie oft die Leertaste in einer bestimmten Zeile gedrückt wurde. Weitere Datenbank- und Dateiressourcen werden normalerweise geöffnet und niemals sicher geschlossen. Sinnlose Methodenargumente, doppelte Methoden, die dasselbe tun, usw.

Während ich auf die Anforderungen für die nächste Funktion warte, habe ich im Laufe der Zeit Dinge mit geringen Auswirkungen und geringem Risiko gesäubert und mich gefragt, ob ich meine Zeit verschwende oder das Richtige tue. Was ist, wenn die neue Funktion das Herausreißen von Code bedeutet, für den ich früher Zeit aufgewendet habe? Ich werde einen agilen Ansatz verfolgen und ich verstehe, dass dies akzeptabel und normal ist, um mich während der agilen Entwicklung ständig zu verändern.

Können Sie sich positive oder negative Auswirkungen vorstellen, wenn ich dies tue, die Sie hinzufügen möchten?

maple_shaft
quelle
1
Retten, was es wert ist, gerettet zu werden, den Rest umschreiben ...
SF.
"Es kommt sehr selten vor, dass ein Projektfehler aufgrund technischer Inkompetenz auftritt, im Gegensatz zu einem Projektmanagementfehler. [...]" Wie wahr das ist, +1.
Gregory Higley

Antworten:

22

Zunächst möchte ich darauf hinweisen, dass Unit-Tests keinen Ersatz für Integrationstests darstellen. Die beiden müssen nebeneinander existieren. Seien Sie dankbar, dass Sie Integrationstests absolviert haben. Andernfalls könnte eine Ihrer kleinen Umgestaltungen dazu führen, dass eine der Cash-Kühe mit geringer Toleranz auf Sie losgeht.

Ich würde anfangen, an den Compiler-Warnungen und nicht verwendeten Variablen und Importen zu arbeiten. Holen Sie sich zuerst einen sauberen Build. Beginnen Sie dann, Komponententests zu schreiben, um das aktuelle Verhalten zu dokumentieren, und starten Sie dann das eigentliche Refactoring.

Ich kann keine negativen Auswirkungen sehen. Sie werden viel tieferes Verständnis für die Codebasis erlangen, was bei größeren Refactorings hilfreich sein wird. Es ist fast immer vorzuziehen, umzugestalten, als umzuschreiben, da Sie während der Umgestaltung immer noch ein funktionierendes Produkt haben, während Sie es während der Umgestaltung nicht tun. Und am Ende muss der Verkauf des Produkts Ihr Gehalt bezahlen.

Sobald die Anforderungen eingehen, würde ich den sogenannten Spotlight-Ansatz verwenden. Führen Sie das übliche agile Verfahren aus (priorisieren Sie, schneiden Sie dann eine kleine Platte für eine Iteration ab und arbeiten Sie das durch) und lassen Sie viel Zeit für Code-Verbesserungen. Dann überarbeiten Sie doch, wo Sie arbeiten. Mit der Zeit wird dies weite Bereiche der Codebasis abdecken, ohne dass Sie jemals in Bereiche vordringen müssen, in denen Sie Schwierigkeiten haben würden, die Verwaltung zu rechtfertigen, warum Sie an diesem Teil des Codes arbeiten.

wolfgangsz
quelle
Ich mag diese Antwort wirklich. Ich brauche ein tieferes Verständnis für die Codebasis und die Cash Cows, die mein Gehalt bezahlen und es uns ermöglichen, für andere Kunden an besseren neuen Projekten zu arbeiten, bei denen ich die Möglichkeit bekomme, von vorne anzufangen und es von Anfang an zu tun.
maple_shaft
10

Das Schreiben von Komponententests kann eine wertvollere Zeit sein: Es gibt Ihnen Einblicke in die aktuelle Funktionsweise der Codebasis. Wenn Sie sich dafür entscheiden, mit dem zu beginnen, was Sie haben, anstatt alles von Grund auf neu zu schreiben, verfügen Sie über eine solide Basis Änderungen vornehmen, ohne zu viel Risiko einzugehen. Es besteht die Möglichkeit, dass Sie beim Schreiben von Komponententests auch Änderungen an der Codebasis vornehmen, um eine testbare Form zu erhalten. diese sind gut, denn unit-testable bedeutet meist auch modular, gekapselt und meist unabhängig vom externen zustand. Und vor allem sind gut geschriebene Komponententests von unschätzbarem Wert für die technische Dokumentation. Wenn Unit-Tests vorhanden sind, können Sie beurteilen, was die aktuelle Codebasis kann und was nicht, anstatt wilde Vermutungen anzustellen oder Dinge für den Fall neu zu schreiben.

tdammers
quelle
2
Fangen Sie dann mit den einfachen an und arbeiten Sie sich nach oben?
Tdammers
2
Nach meiner Erfahrung ist dies immer das Problem - Code wie dieser wird niemals geschrieben, um Tests zu ermöglichen, und Sie werden am Ende große Umgestaltungen vornehmen müssen, wenn Sie den Code nicht direkt umschreiben, um überhaupt Unit-Tests zu ermöglichen .
Wayne Molina
2
Wenn der Code nicht für Tests entwickelt wurde, ist das umso mehr ein Grund, Tests durchzuführen - aber sicher. Lesen Sie Michael Feathers 'Buch "Effektiv mit Legacy-Code arbeiten". Es enthält Rezepte, um nicht testbaren Code testbar zu machen.
Joe White
1
Genau; Wenn es meiner Erfahrung nach keine Tests gibt, müssten Sie zunächst ein umfangreiches Refactoring starten, um es für die Tests vorzubereiten. Dies führt zu mehr Zeitverschwendung beim Refactoring, was das Schreiben von Tests erschwert dann ist es umso schwieriger, überhaupt etwas umzugestalten.
Wayne Molina
1
Es braucht etwas Erfahrung und ein gutes Urteilsvermögen. Nicht alles kann (oder sollte) Unit-Test-fähig gemacht werden.
Tdammers
1

Vermischen von Antworten - Mein Gedanke wäre, Tests und Aufräumarbeiten zu vermischen - vielleicht 50/50? Wenn Sie in einem Bereich arbeiten, in dem ein TDD-Ansatz verwendet wird, richten Sie die erforderlichen Tests ein, um sicherzustellen, dass die Tests für Einheit und Integration den Anforderungen entsprechen, und beginnen Sie dann mit der Fehlerbehebung. Mach weiter, wie es die Zeit erlaubt.

Es bedeutet wahrscheinlich, dass Sie nicht so viel Fortschritt machen, aber es bedeutet, dass Sie zumindest in einigen Bereichen eine schön stabile Codebasis und eine gute Ausgangsbasis haben.

Meine Bauchreaktion war anfangs: "Kann es wirklich weh tun, kaputten Code zu bereinigen?" (aka, Compiler-Fehler), aber dann erinnerte ich mich an Zeiten, in denen die Behebung des Problems in einigen wirklich seltsamen Fällen tatsächlich die Funktionalität beeinträchtigte, weil anstelle eines aussterbenden Threads Speicher an schlechten Stellen belassen wurde - im Grunde maskierte eine schlechte Unterbrechung einen noch schlimmeren Fehler. Es kann buchstäblich eine Büchse der Pandora voller unangenehmer Überraschungen sein.

Angesichts dessen, dass Sie dies tun, während Sie auf weitere Anforderungen warten, denke ich, dass alles, was Sie tun können, um das Chaos zu diagnostizieren, zu Ihrer langfristigen Gesundheit beiträgt.

bethlakshmi
quelle