it-swarm.com.de

Pflegen Sie Hunderte von benutzerdefinierten Zweigen über dem Hauptzweig

Derzeit haben wir einen Hauptzweig für unsere PHP -Anwendung in einem gemeinsam genutzten Repository. Wir haben mehr als 500 Clients, die Abonnenten unserer Software sind, von denen die meisten für verschiedene Zwecke angepasst werden können separater Zweig. Die Anpassung kann ein anderer Textfeldname, eine völlig neue Funktion oder ein neues Modul oder neue Tabellen/Spalten in der Datenbank sein.

Die Herausforderung besteht darin, dass wir bei der Pflege dieser Hunderte von benutzerdefinierten Zweigen und der Verteilung an Kunden von Zeit zu Zeit neue Funktionen bereitstellen und unseren Hauptzweig aktualisieren. Wir möchten die Änderungen des Hauptzweigs auf die benutzerdefinierten Zweige übertragen, um sie zu aktualisieren sie auf die neueste Version.

Leider führt dies häufig zu vielen Konflikten im benutzerdefinierten Code, und wir verbringen viele Stunden damit, jeden einzelnen Zweig zu durchlaufen, um alle Konflikte zu lösen. Dies ist sehr ineffizient, und wir haben festgestellt, dass Fehler bei der Lösung dieser Konflikte keine Seltenheit sind.

Ich suche nach einer effizienteren Möglichkeit, unsere Kundenfreigabezweige mit dem Hauptzweig auf dem neuesten Stand zu halten, was zu weniger Aufwand beim Zusammenführen führt.

145
Fernando Tan

Sie missbrauchen Zweige völlig! Die Anpassung sollte durch Flexibilität in Ihrer Anwendung und nicht durch Flexibilität in Ihrer Versionskontrolle erfolgen (die, wie Sie festgestellt haben, nicht für diese Art der Verwendung vorgesehen ist).

Stellen Sie beispielsweise sicher, dass Textfeldbezeichnungen aus einer Textdatei stammen und nicht fest in Ihre Anwendung codiert werden (so funktioniert die Internationalisierung). Wenn einige Kunden unterschiedliche Funktionen haben, erstellen Sie Ihre Anwendung modular mit strengen internen Grenzen, die von strengen und stabilen APIs bestimmt werden, damit Funktionen nach Bedarf eingebunden werden können.

Die Kerninfrastruktur und alle gemeinsam genutzten Funktionen müssen dann nur noch gespeichert, gewartet und getestet werden einmal.

Sie sollten dies von Anfang an getan haben. Wenn Sie bereits fünfhundert Produktvarianten (!) Haben, wird die Behebung dieses Problems eine große Aufgabe sein… aber nicht mehr als die laufende Wartung.

500 Kunden zu haben ist ein schönes Problem. Wenn Sie die Zeit im Voraus verbracht hätten, um dieses Problem mit Filialen zu vermeiden, könnten Sie möglicherweise nie lange genug im Handel bleiben, um Kunden zu gewinnen.

Erstens hoffe ich, dass Sie Ihren Kunden genug in Rechnung stellen, um ALLE die Kosten für die Wartung ihrer benutzerdefinierten Versionen zu decken. Ich gehe davon aus, dass Kunden neue Versionen erwarten, ohne dafür bezahlen zu müssen, dass ihre Anpassungen erneut vorgenommen werden. Ich würde damit beginnen, alle Dateien zu finden, die in 95% Ihrer Filialen gleich sind. Diese 95% sind der stabile Teil Ihrer Anwendung.

Suchen Sie dann alle Dateien, deren Zeilen sich nur in wenigen Zeilen unterscheiden. Versuchen Sie, ein Konfigurationssystem einzuführen, damit diese Unterschiede beseitigt werden können. Anstatt beispielsweise Hunderte von Dateien mit unterschiedlichen Textfeldbezeichnungen zu haben, haben Sie 1 Konfigurationsdatei, die jede Textbezeichnung überschreiben kann. (Dies muss nicht auf einmal erfolgen. Machen Sie einfach eine Textfeldbezeichnung konfigurierbar, wenn ein Client sie zum ersten Mal ändern möchte.)

Gehen Sie dann mit dem Strategiemuster, der Abhängigkeitsinjektion usw. zu den schwierigeren Themen über.

Erwägen Sie, json in der Datenbank zu speichern, anstatt Spalten für die eigenen Felder des Clients hinzuzufügen. Dies kann für Sie funktionieren, wenn Sie diese Felder nicht mit SQL durchsuchen müssen.

Jedes Mal, wenn Sie eine Datei in einen Zweig einchecken, MÜSSEN Sie sie mit main unterscheiden und jede einzelne Änderung, einschließlich Leerzeichen, begründen. Viele Änderungen werden nicht benötigt und können vor dem Einchecken entfernt werden. Dies kann nur darauf zurückzuführen sein, dass ein Entwickler in seinem Editor unterschiedliche Einstellungen für die Formatierung des Codes vorgenommen hat.

Sie möchten zunächst von 500 Zweigen mit vielen unterschiedlichen Dateien zu den meisten Zweigen mit nur wenigen unterschiedlichen Dateien wechseln. Während du noch genug Geld verdienst, um zu leben.

Möglicherweise haben Sie in vielen Jahren noch 500 Filialen, aber wenn diese viel einfacher zu verwalten sind, haben Sie gewonnen.


Basierend auf dem Kommentar von br3w5:

  • Sie können jede Klasse belegen, die sich zwischen den Clients unterscheidet
  • Erstellen Sie eine "xxx_baseclass", die alle Methoden definiert, die in der Klasse von außerhalb aufgerufen werden
  • Benennen Sie die Klasse so um, dass xxx xxx_clientName heißt (als Unterklasse von xxx_baseclass).
  • Verwenden Sie die Abhängigkeitsinjektion, damit für jeden Client die richtige Version der Klasse verwendet wird
  • Und nun zu dem cleveren Einblick, den sich br3w5 ausgedacht hat! Verwenden Sie ein statisches Code-Analyse-Tool, um den jetzt duplizierten Code zu finden und in die Basisklasse usw. Zu verschieben

Führen Sie die obigen Schritte erst aus, nachdem Sie das einfache Korn erhalten haben, und verfolgen Sie es zuerst mit einigen Klassen.

93
Ian

Stellen Sie in Zukunft den Joel-Test Fragen in Ihrem Interview. Es ist wahrscheinlicher, dass Sie nicht in ein Zugunglück geraten.


Dies ist ein, ah, wie sollen wir sagen ... wirklich wirklich schlechtes Problem zu haben. Der "Zinssatz" für diese technische Verschuldung wird sehr, sehr hoch sein. Es ist möglicherweise nicht wiederherstellbar ...

Wie integriert sind diese benutzerdefinierten Änderungen in den "Kern"? Können Sie sie zu einer eigenen Bibliothek machen und einen einzelnen "Kern" haben und jeder bestimmte Kunde ein eigenes "Add-On" haben?

Oder sind das alles sehr kleine Konfigurationen?

Ich denke, die Lösung ist eine Kombination aus:

  • Ändern aller fest codierten Änderungen in konfigurationsbasierte Elemente. In diesem Fall hat jeder die gleiche Kernanwendung, aber Benutzer (oder Sie) schalten die Funktionen ein/aus, legen nach Bedarf Namen usw. fest
  • Verschieben von "kundenspezifischen" Funktionen/Modulen in separate Projekte. Anstatt ein "Projekt" zu haben, haben Sie ein "Kernprojekt" mit Modulen, die Sie einfach hinzufügen/entfernen können. Alternativ können Sie diese Konfigurationsoptionen auch vornehmen.

Beides wird nicht trivial sein, als wären Sie mit mehr als 500 Kunden hier gelandet. Wahrscheinlich haben Sie hier keinen wirklichen Unterschied gemacht. Ich gehe davon aus, dass Ihre Änderungen bei der Trennung eine sehr zeitaufwändige Aufgabe sein werden.

Ich vermute auch, dass Sie erhebliche Probleme haben werden, Ihren gesamten kundenspezifischen Code einfach zu trennen und zu kategorisieren.

Wenn die meisten Ihrer Änderungen spezifisch Wortlautunterschiede sind, empfehle ich, Fragen wie this zur Sprachlokalisierung zu lesen. Unabhängig davon, ob Sie mehrere Sprachen vollständig oder nur eine Teilmenge verwenden, ist die Lösung dieselbe. This ist speziell PHP und Lokalisierung.

39
enderland

Dies ist eines der schlimmsten Anti-Patterns, die Sie mit einem VCS treffen können.

Der richtige Ansatz besteht darin, den benutzerdefinierten Code in einen konfigurationsgesteuerten Code umzuwandeln. Anschließend kann jeder Kunde seine eigene Konfiguration haben, die entweder in einer Konfigurationsdatei oder in einer Datenbank oder einem anderen Speicherort fest codiert ist. Sie können ganze Funktionen aktivieren oder deaktivieren, das Aussehen der Antworten anpassen usw.

Auf diese Weise können Sie eine Hauptniederlassung mit Ihrem Produktionscode behalten.

17
Daenyth

Der Zweck von Zweigen besteht darin, einen möglichen Entwicklungsweg zu erkunden, ohne das Risiko einzugehen, die Stabilität des Hauptzweigs zu beeinträchtigen. Sie sollten schließlich zu einem geeigneten Zeitpunkt wieder zusammengeführt oder verworfen werden, wenn sie zu einer Sackgasse führen. Was Sie haben, sind nicht so viele Zweige, sondern vielmehr 500 Gabeln desselben Projekts, und der Versuch, die wichtigen Änderungssätze auf alle anzuwenden, ist ein Sisyphus Aufgabe.

Stattdessen sollten Sie Ihren Kerncode in einem eigenen Repository mit den erforderlichen Einstiegspunkten haben, um das Verhalten durch Konfiguration zu ändern und das Verhalten gemäß invertierte Abhängigkeiten einzufügen.

Die verschiedenen Setups, die Sie für Clients haben, können sich dann entweder lediglich durch einen extern konfigurierten Status (z. B. eine Datenbank) unterscheiden oder bei Bedarf als separate Repositorys ausgeführt werden, die den Kern als Submodul hinzufügen.

13
back2dos

Alle wichtigen Dinge wurden hier durch gute Antworten vorgeschlagen. Ich möchte meine fünf Pence als Prozessvorschlag hinzufügen.

Ich möchte vorschlagen, dass Sie dieses Problem langfristig oder mittelfristig lösen und Ihre Richtlinien zur Entwicklung von Code übernehmen. Versuchen Sie, ein flexibles Lernteam zu werden. Wenn jemand 500 Repos haben darf, anstatt die Software konfigurierbar zu machen, ist es Zeit, sich zu fragen, wie Sie bisher gearbeitet haben und was Sie von nun an tun werden.

Was bedeutet:

  1. Klären Sie die Verantwortlichkeiten für das Änderungsmanagement: Wenn ein Kunde einige Anpassungen benötigt, wer verkauft sie, wer erlaubt sie und wer entscheidet, wie der Code verwendet wird verändert sein? Wo müssen die Schrauben gedreht werden, wenn einige Dinge geändert werden müssen?
  2. Klären Sie die Rolle, wer in Ihrem Team darf neue Repos erstellen, und wer ist es nicht.
  3. Stellen Sie sicher, dass jeder in Ihrem Team die Notwendigkeit von Mustern erkennt, die Flexibilität für Software ermöglichen.
  4. Klären Sie Ihr Management-Tool: Woher wissen Sie schnell, welcher Kunde welche Code-Adoptionen hat? Ich weiß, eine "Liste von 500" klingt nervig, aber hier ist eine "emotionale Ökonomie", wenn Sie wollen. Wenn Sie die Änderungen des Kunden nicht in einer kurzen Zeit erkennen können, fühlen Sie sich noch verlorener und gezeichneter, als müssten Sie eine Liste erstellen. Verwenden Sie diese Liste dann, um die Funktionen so zu gruppieren, wie Ihnen die Antworten anderer Personen hier gezeigt haben:
    • gruppenkunden nach kleinen/großen Änderungen
    • gruppieren nach themenbezogenen Änderungen
    • gruppieren nach Änderungen, die leicht zusammenzuführen sind, und Änderungen, die schwer zusammenzuführen sind
    • finde Gruppen mit gleichen Änderungen, die an mehreren Repos vorgenommen wurden (oh ja, es wird einige geben).
    • vielleicht das Wichtigste, um mit Ihrem Manager/Investor zu sprechen: Gruppieren nach teuer Änderungen und billig Änderungen.

Dies soll in keiner Weise zu einer schlechten Druckatmosphäre in Ihrem Team führen. Ich schlage eher vor, dass Sie diese Punkte zuerst für sich selbst klären und, wo immer Sie die Unterstützung spüren, diese gemeinsam mit Ihrem Team organisieren. Laden Sie freundliche Leute an den Tisch ein, um all Ihre Erfahrungen zu verbessern.

Versuchen Sie dann, ein langfristiges Zeitfenster einzurichten, in dem Sie dieses Ding auf einer kleinen Flamme kochen. Vorschlag: Versuchen Sie, jede Woche mindestens zwei Repos zusammenzuführen, und so entfernen Sie mindestens eines. Möglicherweise lernen Sie, dass Sie häufig mehr als zwei Zweige zusammenführen können, wenn Sie Routine und Kontrolle erhalten. Auf diese Weise können Sie in einem Jahr die schlechtesten (teuersten?) Filialen bearbeiten und in zwei Jahren dieses Problem reduzieren, um eine deutlich bessere Software zu erhalten. Aber erwarten Sie nicht mehr, denn am Ende wird niemand "Zeit" dafür haben, aber Sie sind derjenige, der dies nicht länger zulässt, da Sie der Software-Architekt sind.

So würde ich versuchen, damit umzugehen, wenn ich in Ihrer Position wäre. Ich weiß jedoch nicht, wie Ihr Team solche Dinge akzeptieren wird, wie die Software dies wirklich zulässt, wie Sie unterstützt werden und was Sie noch lernen müssen. Sie sind der Software-Architekt - machen Sie es einfach :-)

7
peter_the_oak

Nehmen wir im Gegensatz zu allen Neinsagern an, dass es sich um ein echtes Geschäftsbedürfnis handelt.

(Lieferbar ist beispielsweise Quellcode, Kunden stammen aus derselben Branche und daher miteinander und Ihr Geschäftsmodell verspricht, ihre Geheimnisse geheim zu halten)

Nehmen wir außerdem an, dass Ihr Unternehmen über die Tools verfügt, um alle Niederlassungen zu verwalten. Dies ist entweder Personal (sagen wir 100 Entwickler, das sich der Zusammenführung widmet, unter der Annahme einer Verzögerung von 5 Tagen oder 10 Entwicklern unter der Annahme 50-tägige Release-Verzögerung ist in Ordnung) oder solch ein fantastisches automatisiertes Testen, dass automatisierte Zusammenführungen in beiden Zweigen sowohl auf Kernspezifikation als auch Erweiterungsspezifikation getestet werden Daher erfordern nur Änderungen, die nicht "sauber" zusammengeführt werden, menschliches Eingreifen. Wenn Ihre Kunden nicht nur für Anpassungen, sondern auch für deren Wartung bezahlen, kann dies ein gültiges Geschäftsmodell sein.

Meine (und Neinsager-) Frage lautet: Haben Sie eine engagierte Person, die für die Lieferung an jeden Kunden verantwortlich ist? Wenn Sie beispielsweise ein Unternehmen mit 10.000 Mitarbeitern sind, kann dies der Fall sein.

Dies kann von Plugin-Architektur in einigen Fällen erledigt werden. Nehmen wir an, Ihr Kern ist Trunk, Plugins können in Trunk oder Zweigen gespeichert werden, und die Konfiguration für jeden Kunden ist entweder eine Datei mit einem eindeutigen Namen oder wird im Kunden gespeichert Ast.

Plugins können zur Laufzeit geladen oder zur Kompilierungszeit integriert werden.

Wirklich viele Projekte werden so durchgeführt, grundsätzlich gilt immer noch das gleiche Problem - einfache Kernänderungen sind trivial zu integrieren, Konfliktänderungen müssen entweder rückgängig gemacht werden oder Änderungen an vielen Plugins sind erforderlich.

Es gibt Fälle, in denen Plugins nicht gut genug sind. In diesem Fall müssen so viele Interna des Kerns angepasst werden, dass die Anzahl der Plugin-Schnittstellen zu groß wird, um verarbeitet zu werden.

Im Idealfall wird dies von aspektorientierte Programmierung erledigt, wobei Trunk der Kerncode ist und Zweige Aspekte sind (dh zusätzlicher Code und Anweisungen zum Verbinden von Extras mit dem Kern).

In einem einfachen Beispiel können Sie angeben, dass benutzerdefiniertes foo vor oder nach dem Kern klass.foo Ausgeführt wird oder dass es ihn ersetzt oder umschließt und die Eingabe oder Ausgabe ändern kann.

Dafür gibt es eine Menge Bibliotheken, aber das Problem der Zusammenführungskonflikte verschwindet nicht - saubere Zusammenführungen werden von AOP behandelt und Konflikte erfordern immer noch menschliches Eingreifen.

Schließlich muss sich ein solches Geschäft wirklich mit Filialwartung befassen, nämlich ist das kundenspezifische Merkmal X so häufig, dass es billiger ist, es in den Kern zu verschieben, obwohl nicht alle Kunden dafür bezahlen?

5
Dima Tisnek

Sie lösen die Grundursache der Krankheit nicht, indem Sie das Symptom betrachten. Die Verwendung eines "Code-Management" -Ansatzes ist symptomatisch, löst jedoch langfristig keine Probleme für Sie. Die Hauptursache ist das Fehlen gut verwalteter Produktfunktionen, -funktionen sowie deren Erweiterungen und Variationen.

Ihr 'benutzerdefinierter' Code stellt nur Erweiterungen der Produktmerkmale und -funktionen und Datenfeld Änderungen bei anderen dar.

Wie umfangreich die benutzerdefinierten Funktionen sind, wie unterschiedlich, wie kontextbezogen ähnlich oder nicht, trägt wesentlich zur „Bereinigung“ der Codebasis Ihres Produkts bei.

Mehr als nur Code und Version, hier kommt Produktmanagement, Produktarchitektur und Datenarchitektur ins Spiel. Ernsthaft.

Denn letztendlich ist der Code nichts anderes als Ihr Angebot von Geschäfts- und Produktfunktionen/-diensten für Ihre Kunden. Dafür wird Ihr Unternehmen bezahlt.

Um dies besser in den Griff zu bekommen, muss dies vom Standpunkt der Fähigkeiten und nicht vom Standpunkt des Codes aus erfolgen.

Sie, Ihr Unternehmen und Ihr Produkt können nicht für jeden alles sein. Jetzt, da Sie eine anständige Umsatzbasis von 500 Kunden haben, ist es Zeit, das zu produzieren, was Sie beabsichtigen.

Und wenn Sie mehrere Dinge anbieten, ist es sinnvoll, Ihre Produktfunktionen auf organisierte Weise zu modularisieren.

Wie breit und tief werden Ihre Produkte sein? Andernfalls führt dies zu Problemen mit der Servicequalität und zu Produktverdünnung und -fragmentierung.

Werden Sie ein CRM oder ERP oder Auftragsabwicklung/Versand oder Microsoft Excel sein?

Ihre vorhandenen Erweiterungen müssen aufgerollt und harmonisiert werden, so wie ein großer Software-Major zieht und zusammenführt Produkte, die von einem Startup erworben wurden.

Sie benötigen eine starke Produktmanagement- und Datenarchitektur Personenkarte für Folgendes:

  • Hauptzweig, seine Produktfähigkeiten und Funktionsbasis
  • Benutzerdefinierte Erweiterungsfunktionen, -typen und -varianten
  • Bedeutung und Variation von "benutzerdefinierten Feldern"

..Um eine Roadmap für die Assimilation und Harmonisierung all dieser losen Produktfäden/-zweige im großen Kontext Ihrer Kernanwendung zu erstellen.

PS: Verbinde dich mit mir, ich kenne eine Person, die dir helfen kann, das zu beheben :)

3
Alex S