it-swarm.com.de

Was ist der beste Weg, um eine große Datei umzugestalten?

Ich arbeite derzeit an einem größeren Projekt, das leider einige Dateien enthält, in denen Richtlinien zur Softwarequalität nicht immer befolgt wurden. Dies schließt große Dateien (lesen Sie 2000-4000 Zeilen) ein, die eindeutig mehrere unterschiedliche Funktionen enthalten.

Jetzt möchte ich diese großen Dateien in mehrere kleine umgestalten. Das Problem ist, dass mehrere Personen (ich eingeschlossen) in verschiedenen Zweigen an diesen Dateien arbeiten, da sie so groß sind. Ich kann mich also nicht wirklich von der Entwicklung und dem Refactor abheben, da das Zusammenführen dieser Refactorings mit den Veränderungen anderer Menschen schwierig wird.

Wir könnten natürlich verlangen, dass jeder wieder zusammenführt, um die Dateien zu entwickeln, "einzufrieren" (d. H. Niemandem mehr zu erlauben, sie zu bearbeiten), umzugestalten und dann "freizugeben". Dies ist jedoch auch nicht wirklich gut, da hierfür jeder seine Arbeit an diesen Dateien einstellen muss, bis das Refactoring abgeschlossen ist.

Gibt es also eine Möglichkeit zur Umgestaltung, muss niemand anderes aufhören zu arbeiten (zu lange) oder seine Feature-Zweige wieder zusammenführen, um sich zu entwickeln?

42
Hoff

Sie haben richtig verstanden, dass dies weniger ein technisches als ein soziales Problem ist: Wenn Sie übermäßige Zusammenführungskonflikte vermeiden möchten, muss das Team so zusammenarbeiten, dass diese Konflikte vermieden werden.

Dies ist Teil eines größeren Problems mit Git, da das Verzweigen sehr einfach ist, das Zusammenführen jedoch noch viel Aufwand erfordern kann. Entwicklungsteams neigen dazu, viele Zweige zu starten, und sind dann überrascht, dass das Zusammenführen schwierig ist, möglicherweise weil sie versuchen, den Git Flow zu emulieren, ohne dessen Kontext zu verstehen.

Die allgemeine Regel für schnelle und einfache Zusammenführungen besteht darin, zu verhindern, dass sich große Unterschiede ansammeln, insbesondere, dass Feature-Zweige sehr kurzlebig sein sollten (Stunden oder Tage, nicht Monate). Ein Entwicklungsteam, das in der Lage ist, seine Änderungen schnell zu integrieren, sieht weniger Zusammenführungskonflikte. Wenn ein Code noch nicht produktionsbereit ist, kann er möglicherweise integriert, aber über ein Feature-Flag deaktiviert werden. Sobald der Code in Ihren Hauptzweig integriert wurde, ist er für die Art von Refactoring zugänglich, die Sie durchführen möchten.

Das könnte zu viel für Ihr unmittelbares Problem sein. Es kann jedoch möglich sein, Kollegen zu bitten, ihre Änderungen, die sich auf diese Datei auswirken, bis zum Ende der Woche zusammenzuführen, damit Sie das Refactoring durchführen können. Wenn sie länger warten, müssen sie sich selbst mit den Zusammenführungskonflikten befassen. Das ist nicht unmöglich, es ist nur vermeidbare Arbeit.

Möglicherweise möchten Sie auch verhindern, dass große Teile des abhängigen Codes beschädigt werden, und nur API-kompatible Änderungen vornehmen. Wenn Sie beispielsweise einige Funktionen in ein separates Modul extrahieren möchten:

  1. Extrahieren Sie die Funktionalität in ein separates Modul.
  2. Ändern Sie die alten Funktionen, um ihre Aufrufe an die neue API weiterzuleiten.
  3. Im Laufe der Zeit portabhängiger Code zur neuen API.
  4. Schließlich können Sie die alten Funktionen löschen.
  5. (Wiederholen Sie diesen Vorgang für die nächsten Funktionen.)

Dieser mehrstufige Prozess kann viele Zusammenführungskonflikte vermeiden. Insbesondere kommt es nur dann zu Konflikten, wenn jemand anderes auch die von Ihnen extrahierte Funktionalität ändert. Die Kosten dieses Ansatzes sind, dass er viel langsamer ist als das gleichzeitige Ändern aller Elemente, und dass Sie vorübergehend zwei doppelte APIs haben. Dies ist nicht so schlimm, bis etwas Dringendes dieses Refactoring unterbricht, die Vervielfältigung vergessen oder priorisiert wird und Sie am Ende eine Menge technischer Schulden haben.

Letztendlich erfordert jede Lösung jedoch, dass Sie sich mit Ihrem Team abstimmen.

42
amon

Führen Sie das Refactoring in kleineren Schritten durch. Angenommen, Ihre große Datei hat den Namen Foo:

  1. Fügen Sie eine neue leere Datei Bar hinzu und übergeben Sie sie an "trunk".

  2. Suchen Sie einen kleinen Teil des Codes in Foo, der nach Bar verschoben werden kann. Wenden Sie den Umzug an, aktualisieren Sie ihn vom Trunk, erstellen und testen Sie den Code und legen Sie ihn auf "Trunk" fest.

  3. Wiederholen Sie Schritt 2, bis Foo und Bar gleich groß sind (oder welche Größe Sie bevorzugen).

Auf diese Weise erhalten Ihre Teamkollegen beim nächsten Aktualisieren ihrer Zweige aus dem Trunk Ihre Änderungen in "kleinen Portionen" und können sie einzeln zusammenführen. Dies ist viel einfacher, als eine vollständige Aufteilung in einem Schritt zusammenführen zu müssen. Das Gleiche gilt, wenn in Schritt 2 ein Zusammenführungskonflikt auftritt, weil jemand anderes die Amtsleitung dazwischen aktualisiert hat.

Dadurch werden Zusammenführungskonflikte oder die Notwendigkeit einer manuellen Lösung nicht beseitigt, aber jeder Konflikt wird auf einen kleinen Codebereich beschränkt, der viel einfacher zu handhaben ist.

Und natürlich - kommunizieren Sie das Refactoring im Team. Informieren Sie Ihre Kollegen darüber, was Sie tun, damit sie wissen, warum sie mit Zusammenführungskonflikten für die jeweilige Datei rechnen müssen.

30
Doc Brown

Sie denken daran, die Datei als atomare Operation aufzuteilen, aber Sie können zwischenzeitliche Änderungen vornehmen. Die Datei wurde im Laufe der Zeit allmählich riesig, sie kann im Laufe der Zeit allmählich klein werden.

Wählen Sie ein Teil aus, das sich seit langem nicht mehr ändern musste (git blame kann dabei helfen) und spaltet das zuerst ab. Lassen Sie diese Änderung in allen Zweigen zusammenführen und wählen Sie dann den nächst einfacheren Teil aus, der aufgeteilt werden soll. Vielleicht ist sogar das Teilen eines Teils ein zu großer Schritt, und Sie sollten zuerst einige Änderungen in der großen Datei vornehmen.

Wenn sich die Leute nicht häufig wieder zusammenschließen, um sich zu entwickeln, sollten Sie dies fördern. Nutzen Sie nach dem Zusammenführen diese Gelegenheit, um die Teile, die sie gerade geändert haben, abzuspalten. Oder bitten Sie sie, die Abspaltung im Rahmen der Überprüfung der Pull-Anforderung vorzunehmen.

Die Idee ist, sich langsam Ihrem Ziel zu nähern. Es wird sich so anfühlen, als ob der Fortschritt langsam ist, aber dann werden Sie plötzlich feststellen, dass Ihr Code viel besser ist. Das Drehen eines Ozeandampfers dauert lange.

18
Karl Bielefeldt

Ich werde eine andere als die normale Lösung für dieses Problem vorschlagen.

Verwenden Sie dies als Teamcode-Ereignis. Lassen Sie alle ihren Code einchecken, der dies kann, und helfen Sie dann anderen, die noch mit der Datei arbeiten. Wenn alle relevanten Personen ihren Code eingecheckt haben, suchen Sie sich einen Konferenzraum mit einem Projektor und arbeiten Sie zusammen, um Dinge in neue Dateien zu verschieben.

Möglicherweise möchten Sie eine bestimmte Zeitspanne festlegen, damit es nicht zu einer Woche voller Argumente kommt, deren Ende nicht abzusehen ist. Stattdessen kann dies sogar eine wöchentliche 1-2-stündige Veranstaltung sein, bis Sie alle sehen, wie es sein muss. Möglicherweise benötigen Sie nur 1-2 Stunden, um die Datei zu überarbeiten. Sie werden es wahrscheinlich erst wissen, wenn Sie es versuchen.

Dies hat den Vorteil, dass sich alle beim Refactoring auf derselben Seite befinden (kein Wortspiel beabsichtigt), aber es kann Ihnen auch helfen, Fehler zu vermeiden und bei Bedarf Eingaben von anderen zu möglichen Methodengruppierungen zu erhalten, die beibehalten werden müssen.

Wenn Sie dies tun, kann dies als integrierte Codeüberprüfung angesehen werden, wenn Sie so etwas tun. Auf diese Weise kann die entsprechende Anzahl von Entwicklern Ihren Code abmelden, sobald Sie ihn eingecheckt und für ihre Überprüfung bereit haben. Vielleicht möchten Sie immer noch, dass sie den Code auf etwas überprüfen, das Sie verpasst haben, aber es trägt wesentlich dazu bei, dass der Überprüfungsprozess kürzer ist.

Dies funktioniert möglicherweise nicht in allen Situationen, Teams oder Unternehmen, da die Arbeit nicht so verteilt ist, dass dies problemlos möglich ist. Es kann auch (fälschlicherweise) als Missbrauch der Entwicklungszeit ausgelegt werden. Dieser Gruppencode muss sowohl vom Manager als auch vom Refactor selbst übernommen werden.

Um diese Idee an Ihren Manager zu verkaufen, erwähnen Sie das Code-Überprüfungsbit sowie alle, die von Anfang an wissen, wo sich die Dinge befinden. Es kann sich lohnen, zu verhindern, dass Entwickler Zeit verlieren, wenn sie einen Host mit neuen Dateien durchsuchen. Außerdem ist es normalerweise eine gute Sache, zu verhindern, dass Entwickler darüber informiert werden, wo Dinge gelandet sind oder "vollständig fehlen". (Je weniger die Kernschmelzen, desto besser, IMO.)

Sobald Sie eine Datei auf diese Weise überarbeitet haben, können Sie möglicherweise leichter die Genehmigung für weitere Refaktoren erhalten, wenn dies erfolgreich und nützlich war.

Wie auch immer Sie sich für Ihren Refactor entscheiden, viel Glück!

9
computercarguy

Um dieses Problem zu beheben, müssen Sie sich bei den anderen Teams einkaufen, da Sie versuchen, eine gemeinsam genutzte Ressource (den Code selbst) zu ändern. Abgesehen davon denke ich, dass es eine Möglichkeit gibt, von riesigen monolithischen Dateien wegzuwandern, ohne die Menschen zu stören.

Ich würde auch empfehlen nicht auf alle großen Dateien gleichzeitig abzielen es sei denn, die Anzahl der großen Dateien wächst zusätzlich zu den Größen der einzelnen Dateien unkontrolliert.

Das Refactoring großer Dateien wie diese führt häufig zu unerwarteten Problemen. Der erste Schritt besteht darin, zu verhindern, dass die großen Dateien zusätzliche Funktionen ansammeln über das hinaus, was derzeit im Master oder in Entwicklungszweigen vorhanden ist.

Ich denke, der beste Weg, dies zu tun, sind Commit-Hooks, die bestimmte Ergänzungen zu den großen Dateien standardmäßig blockieren, aber mit einem magischen Kommentar in der Commit-Nachricht wie @bigfileok Oder so etwas außer Kraft gesetzt werden können. Es ist wichtig, die Richtlinie auf eine Weise außer Kraft setzen zu können, die schmerzlos, aber nachverfolgbar ist. Idealerweise sollten Sie in der Lage sein, den Commit-Hook lokal auszuführen und es sollte Ihnen sagen, wie Sie diesen bestimmten Fehler in der Fehlermeldung selbst überschreiben können. Dies ist auch nur meine Präferenz, aber nicht erkannte magische Kommentare oder magische Kommentare, die Fehler unterdrücken, die nicht tatsächlich ausgelöst in der Festschreibungsnachricht eine Warnung oder ein Fehler für die Festschreibungszeit sein sollten, damit Sie nicht versehentlich trainieren Menschen, um die Haken zu unterdrücken, unabhängig davon, ob sie müssen oder nicht.

Der Commit-Hook kann nach neuen Klassen suchen oder andere statische Analysen durchführen (Ad-hoc oder nicht). Sie können auch einfach eine Zeilen- oder Zeichenanzahl auswählen, die 10% größer ist als die aktuelle Datei, und sagen, dass die große Datei nicht über das neue Limit hinaus wachsen kann. Sie können auch einzelne Commits ablehnen, bei denen die große Datei um zu viele Zeilen oder zu viele Zeichen oder w/e vergrößert wird.

Sobald die große Datei keine neuen Funktionen mehr ansammelt, können Sie sie einzeln umgestalten (und gleichzeitig die durch die Commit-Hooks erzwungenen Schwellenwerte verringern, um zu verhindern, dass sie erneut wächst).

Schließlich sind die großen Dateien so klein, dass die Commit-Hooks vollständig entfernt werden können.

4
Gregory Nisbet