Wann soll ein Projekt in mehrere Teilprojekte aufgeteilt werden?


30

Ich würde gerne wissen, ob es Sinn macht, das Projekt, an dem ich arbeite, in zwei Repositories anstatt in eines zu unterteilen.

Soweit ich sagen kann:

  • Frontend wird in html + js geschrieben
  • Backend in .net
  • Das Backend ist nicht vom Frontend abhängig und das Frontend ist nicht vom Backend abhängig
  • Das Frontend verwendet eine im Backend implementierte "Restful API".
  • Das Frontend kann auf einem beliebigen statischen http-Server gehostet werden.

Das Repository hat ab sofort folgende Struktur:

Wurzel:

  • Vorderes Ende/*
  • Backend / *

Ich halte es für einen Fehler, beide Projekte im selben Repository zu belassen. Da beide Projekte keine Abhängigkeiten untereinander aufweisen, sollten sie in einzelne Repositorys und bei Bedarf in ein übergeordnetes Repository mit Submodulen gehören.

Mir wurde gesagt, dass es sinnlos ist und wir keinen Nutzen daraus ziehen werden.

Hier sind einige meiner Argumente:

  • Wir haben zwei Module, die nicht voneinander abhängig sind.
  • Langfristig kann es schwierig sein, die Quellhistorie beider Projekte zu haben (versuchen Sie, in der Historie nach etwas im Frontend zu suchen, während Sie die Hälfte der Commits haben, die überhaupt nichts mit dem gesuchten Fehler zu tun haben).
  • Konflikt und Zusammenführung (Dies sollte nicht passieren, aber wenn jemand auf das Backend pusht, werden andere Entwickler gezwungen, Änderungen am Backend zu übernehmen, um Änderungen am Frontend zu pushen.)
  • Ein Entwickler arbeitet möglicherweise nur am Backend, muss aber immer das Frontend ziehen oder umgekehrt.
  • Auf lange Sicht, wenn es Zeit ist, bereitzustellen. In gewisser Weise könnte das Frontend auf mehreren statischen Servern bereitgestellt werden, während ein Backend-Server vorhanden ist. In jedem Fall werden die Benutzer gezwungen sein, entweder das gesamte Backend damit zu klonen oder ein benutzerdefiniertes Skript zu erstellen, um nur das Frontend auf alle Server zu pushen oder das Backend zu entfernen. Es ist einfacher, nur das Frontend oder das Backend zu schieben / ziehen als beide, wenn nur eines benötigt wird.
  • Gegenargument (Eine Person könnte an beiden Projekten arbeiten), Erstellen Sie ein drittes Repo mit Submodul und entwickeln Sie damit. Die Historie wird in einzelnen Modulen getrennt gehalten und Sie können jederzeit Tags erstellen, bei denen die Version des Backends / Frontends wirklich synchron zusammenarbeitet. Wenn beide Frontends / Backends in einem Repo zusammengefasst sind, bedeutet dies nicht, dass sie zusammenarbeiten. Es verschmilzt einfach beide Geschichten zu einem großen Repo.
  • Wenn Sie Frontend / Backend als Submodule verwenden, wird dies einfacher, wenn Sie dem Projekt einen Freiberufler hinzufügen möchten. In einigen Fällen möchten Sie nicht wirklich vollen Zugriff auf die Codebasis gewähren. Ein einziges großes Modul erschwert die Arbeit, wenn Sie einschränken möchten, was "Außenstehende" sehen / bearbeiten können.
  • Fehlerbeschreibung und Fehlerbehebung: Ich habe einen neuen Fehler in das Frontend eingefügt. Dann hat jemand einen Fehler im Backend behoben. Mit einem einzigen Repository wird durch das Zurücksetzen vor dem neuen Fehler auch das Backend zurückgesetzt, was die Behebung erschweren könnte. Ich müsste das Backend in einen anderen Ordner klonen, damit das Backend funktioniert, während ich den Fehler im Frontend behebe ... und dann versuche, die Dinge neu zu ordnen ... Wenn zwei Repositorys vorhanden sind, ist es schmerzlos, den HEAD eines Repos zu verschieben den anderen nicht ändern. Und das Testen mit verschiedenen Versionen des Backends wird schmerzlos sein.

Kann mir jemand mehr Argumente geben, um sie zu überzeugen, oder zumindest sagen, warum es sinnlos (komplizierter) ist, das Projekt in zwei Teilmodule zu unterteilen. Das Projekt ist neu und die Codebasis ist ein paar Tage alt, so dass es nicht zu früh ist, es zu beheben.

Antworten:


23

In meinem Unternehmen verwenden wir für jede Systemkomponente ein eigenes SVN-Repository. Ich kann Ihnen sagen, dass es extrem frustrierend wird. Unser Erstellungsprozess hat so viele Abstraktionsebenen.

Wir machen das mit Java, also haben wir einen schweren Build-Prozess mit Javac-Kompilierung, JibX-Bindungskompilierung, XML-Validierung usw.

Für Ihre Site ist es möglicherweise keine große Sache, wenn Sie es nicht wirklich "bauen" (wie zum Beispiel Vanilla PHP).

Nachteile der Aufteilung eines Produkts in mehrere Repositorys

  1. Build-Verwaltung - Ich kann nicht nur Code auschecken, ein in sich geschlossenes Build-Skript ausführen und ein lauffähiges / installierbares / implementierbares Produkt haben. Ich brauche ein externes Build-System, das mehrere Repos erstellt, mehrere interne Build-Skripte ausführt und dann die Artefakte zusammenstellt.
  2. Änderungsnachverfolgung - Sehen, wer was, wann und warum geändert hat. Wenn eine Fehlerbehebung im Frontend eine Änderung im Backend erfordert, gibt es jetzt zwei unterschiedliche Pfade, auf die ich später zurückgreifen kann.
  3. Administration - Möchten Sie die Anzahl der zu verwaltenden Benutzerkonten, Kennwortrichtlinien usw. wirklich verdoppeln?
  4. Zusammenführen - Neue Funktionen werden wahrscheinlich viel Code ändern. Indem Sie Ihr Projekt in mehrere Repositorys aufteilen, multiplizieren Sie die Anzahl der erforderlichen Zusammenführungen.
  5. Erstellen von Verzweigungen - Um eine Verzweigung zu erstellen, müssen Sie jetzt in jedem Repository eine Verzweigung erstellen.
  6. Tagging - Nach einem erfolgreichen Test Ihres Codes möchten Sie eine Version für die Freigabe taggen. Jetzt müssen Sie mehrere Tags erstellen, eines in jedem Repository.
  7. Schwer etwas zu finden - Vielleicht ist das Frontend / Backend einfach, aber es wird zu einem rutschigen Hang. Wenn Sie genügend Module aufteilen, müssen Entwickler möglicherweise untersuchen, wo sich ein Teil des Codes in der Quellcodeverwaltung befindet.

Mein Fall ist etwas extrem, da unser Produkt auf 14 verschiedene Repos aufgeteilt ist und jedes Repo dann in 4-8 Module unterteilt ist. Wenn ich mich recht erinnere, haben wir ungefähr 80 oder einige "Pakete", die alle einzeln ausgecheckt und dann zusammengestellt werden müssen.

Ihr Fall mit nur Backend / Frontend ist vielleicht weniger kompliziert, aber ich rate trotzdem davon ab.

Extreme Beispiele können überzeugende Argumente für oder gegen so ziemlich alles sein :)

Kriterien würde ich verwenden, um zu entscheiden

Ich würde in Betracht ziehen, ein Produkt in mehrere Quellcode-Repositorys aufzuteilen, nachdem ich die folgenden Faktoren berücksichtigt habe:

  1. Erstellen - Verschmelzen die Ergebnisse der einzelnen Komponenten zu einem Produkt? Wie das Kombinieren von .class-Dateien aus einer Reihe von Komponenten zu einer Reihe von .jar- oder .war-Dateien.
  2. Bereitstellung - Erhalten Sie Komponenten, die zusammen als eine Einheit bereitgestellt werden, oder verschiedene Einheiten, die auf verschiedenen Servern bereitgestellt werden? Beispielsweise werden Datenbankskripte an Ihren DB-Server gesendet, während Javascript an Ihren Webserver gesendet wird.
  3. Co-change - Wechseln sie häufig oder zusammen? In Ihrem Fall können sie separat, aber dennoch häufig geändert werden.
  4. Häufigkeit des Verzweigens / Zusammenführens - wenn alle nur selten in den Stamm einchecken und die Zweige selten sind, können Sie möglicherweise davonkommen. Wenn Sie häufig verzweigen und zusammenführen, kann dies zu einem Albtraum werden.
  5. Agilität - Wenn Sie eine Änderung in kürzester Zeit entwickeln, testen, freigeben und bereitstellen müssen (wahrscheinlich mit SaaS), können Sie dies tun, ohne viel Zeit mit dem Jonglieren von Filialen und Repos zu verbringen?

Ihre Argumente

Ich stimme auch den meisten Ihrer Argumente für diese Aufteilung nicht zu. Ich werde sie nicht alle bestreiten, weil diese lange Antwort noch länger wird, aber einige, die auffallen:

Wir haben zwei Module, die nicht voneinander abhängig sind.

Unsinn. Wenn Sie Ihr Backend wegnehmen, wird Ihr Frontend funktionieren? Das ist was ich dachte.

Langfristig kann es schwierig sein, die Quellhistorie beider Projekte zu haben (versuchen Sie, in der Historie nach etwas im Frontend zu suchen, während Sie die Hälfte der Commits haben, die überhaupt nichts mit dem gesuchten Fehler zu tun haben).

Wenn Ihr Projektstamm in Frontend / und Backend / unterteilt ist, können Sie den Verlauf dieser Hierarchien unabhängig voneinander anzeigen.

Konflikt und Zusammenführung (Dies sollte nicht passieren, aber wenn jemand auf das Backend pusht, werden andere Entwickler gezwungen, Änderungen am Backend zu übernehmen, um Änderungen am Frontend zu pushen.) Ein Entwickler arbeitet möglicherweise nur am Backend, muss jedoch immer das Backend oder auf die andere Weise pushen um.

Das Aufteilen Ihres Projekts in verschiedene Repos löst dies nicht. Ein Frontend-Konflikt und ein Backend-Konflikt führen weiterhin zu 2 Konflikten, unabhängig davon, ob es sich um 1 Repository-mal-2-Konflikte oder 2 Repository-mal-1-Konflikte handelt. Jemand muss sie noch lösen.

Wenn die Sorge besteht, dass 2 Repos bedeuten, dass ein Frontend-Entwickler Frontend-Code zusammenführen kann, während ein Backend-Entwickler Backend-Code zusammenführt, können Sie dies mit einem einzelnen Repository unter Verwendung von SVN tun. SVN kann auf jeder Ebene zusammengeführt werden. Vielleicht ist das ein Trottel oder eine Quecksilberbeschränkung (Sie haben beide markiert, sind sich also nicht sicher, welchen SCM Sie verwenden)?

Auf der anderen Seite

Vor diesem Hintergrund habe ich Fälle gesehen, in denen das Aufteilen eines Projekts in mehrere Module oder Repositorys funktioniert. Ich habe mich sogar einmal für ein bestimmtes Projekt ausgesprochen, bei dem wir Solr in unser Produkt integriert haben. Solr wird natürlich auf separaten Servern ausgeführt und ändert sich nur, wenn sich ein Änderungssatz auf die Suche bezieht (unser Produkt bietet viel mehr als nur die Suche), es gibt einen separaten Erstellungsprozess und es werden keine Code-Artefakte oder Erstellungsartefakte freigegeben.


Moderation in allen Dingen, wie meine Mutter sagte ...
William Payne

Zum Zeitpunkt meines Schreibens schreibe ich das Frontend ohne Backend. Ich emuliere das Backend mit json-Dateien, und ich könnte wahrscheinlich sogar komplett mit indexedDB im Browser emulieren. Das Backend ist also nur ein Server, der Json bedient. Es könnte durch irgendetwas ersetzt werden, solange die empfangenen Daten mit der API übereinstimmen. Beide Projekte verwenden unterschiedliche Build-Systeme. Kurz gesagt, es ist fast so, als hätten Sie eine Website und eine mobile Android-App. Hinzufügen der mobilen Anwendung im Webserver-Repository.
Loïc Faure-Lacroix

Auch wenn es nicht klar war, sind das Backend und das Frontend keine Benutzer- / Administrationsoberflächen. Aber Frontend ist nur eine Ajax-Schnittstelle und Backend dient Json. Benutzer und Rollen werden unterschiedlich behandelt und die Administrationsoberfläche befindet sich im Frontend. Die Idee ist, beide Teile isoliert zu halten und zu verhindern, dass der von Javascript erzeugte HTML-Code den von dem Server erzeugten HTML-Code lädt. Der Server sollte nur json oder xml liefern.
Loïc Faure-Lacroix

1
Dann haben Sie keine Build- oder Bereitstellungsprobleme, sodass dies möglicherweise in Ordnung ist. Wenn Sie jedoch größere Änderungen vornehmen, müssen Sie möglicherweise die API ändern, die sich sowohl auf das Frontend als auch auf das Backend auswirkt. Daher werden Sie zweimal verzweigen, zweimal zusammenführen, zweimal markieren usw. Solange es jedoch nur zweimal bleibt und dies nicht der Fall ist wird nicht zu 3 ... 4 ... 12 ... 20, wahrscheinlich keine schlechte Idee.
Brandon

Selbst wenn sich die API ändert, ist es bei richtiger Versionsverwaltung möglich, Zweigversionen für jedes Frontend zu erstellen, das eine API-Version unterstützt. Das Backend sollte eine gewisse Abwärtskompatibilität aufweisen und die alte API so lange wie möglich funktionsfähig halten.
Loïc Faure-Lacroix

3

Einige Ihrer Argumente sind gültig und andere nicht.

Wir haben zwei Module, die nicht voneinander abhängig sind.

Das ist eigentlich nicht ganz richtig. Sowohl das Front-End als auch das Back-End müssen eine gemeinsame Schnittstelle haben, um kommunizieren zu können (Beschreibung). Das macht es zu einem schwachen Argument, beide in einem gemeinsamen Repository zu haben. Aber nur ein schwaches Argument, da es keinen großen Unterschied macht.

Langfristig kann es schwierig sein, die Quellhistorie beider Projekte zu haben (versuchen Sie, in der Historie nach etwas im Frontend zu suchen, während Sie die Hälfte der Commits haben, die überhaupt nichts mit dem gesuchten Fehler zu tun haben).

Dies ist ein falsches Argument. Wenn Sie nachsehen möchten, wie ein bestimmter Fehler behoben wurde, sehen Sie im Bug-Tracker nach, für den Commit den Fix enthält. Und wenn Sie wissen möchten, wie sich ein bestimmter Code entwickelt hat, sehen Sie sich den Verlauf einer einzelnen Datei (oder höchstens einer Handvoll) an. In beiden Fällen sollten andere Dateien, möglicherweise von anderen Modulen, im Repository keine Komplikationen verursachen.

Konflikt und Zusammenführung (Dies sollte nicht passieren, aber wenn jemand auf das Backend pusht, werden andere Entwickler gezwungen, Änderungen am Backend zu übernehmen, um Änderungen am Frontend zu pushen.)

Dies ist ein falsches Argument. Mir ist kein (halbwegs anständiges) VCS bekannt, bei dem Sie das gesamte Repository synchronisieren müssen, bevor Sie Ihre Änderungen festschreiben / pushen können. Sie müssen höchstens die Ordner synchronisieren, die die geänderten Dateien enthalten (und oft nur die Dateien selbst).

Ein Entwickler arbeitet möglicherweise nur am Backend, muss aber immer das Backend ziehen oder umgekehrt.

Dies ist das gleiche falsche Argument wie das vorherige.

Auf lange Sicht, wenn es Zeit ist, bereitzustellen. In gewisser Weise könnte das Frontend auf mehreren statischen Servern bereitgestellt werden, während ein Backend-Server vorhanden ist. In jedem Fall werden die Benutzer gezwungen sein, entweder das gesamte Backend damit zu klonen oder ein benutzerdefiniertes Skript zu erstellen, um nur das Frontend auf alle Server zu pushen oder das Backend zu entfernen. Es ist einfacher, nur das Frontend oder das Backend zu schieben / ziehen als beide, wenn nur eines benötigt wird.

Je nachdem, wie die Leute sich die Bereitstellung vorstellen, kann dies ein gültiges Argument sein. Wenn die Bereitstellung durch Entpacken einer Zip-Datei / eines Tarbals auf dem Server erfolgt, spielt es keine Rolle, wie Ihre Repositorys organisiert sind. Wenn die Bereitstellung durch Auschecken (eines Teils) eines Repositorys auf dem Server erfolgt, empfiehlt es sich, separate Repositorys für Module zu verwenden, die separat bereitgestellt werden.

Gegenargument (Eine Person könnte an beiden Projekten arbeiten), Erstellen Sie ein drittes Repo mit Submodul und entwickeln Sie damit. Die Historie wird in einzelnen Modulen getrennt gehalten und Sie können jederzeit Tags erstellen, bei denen die Version des Backends / Frontends wirklich synchron zusammenarbeitet. Wenn beide Frontends / Backends in einem Repo zusammengefasst sind, bedeutet dies nicht, dass sie zusammenarbeiten. Es verschmilzt einfach beide Geschichten zu einem großen Repo.

Dies ist ein gültiges Argument, aber es ist nicht so stark.

Wenn Sie Frontend / Backend als Submodule verwenden, wird dies einfacher, wenn Sie dem Projekt einen Freiberufler hinzufügen möchten. In einigen Fällen möchten Sie nicht wirklich vollen Zugriff auf die Codebasis gewähren. Ein einziges großes Modul erschwert die Arbeit, wenn Sie einschränken möchten, was "Außenstehende" sehen / bearbeiten können.

Dies ist ein gültiges Argument.

Fehlerbeschreibung und Fehlerbehebung: Ich habe einen neuen Fehler in das Frontend eingefügt. Dann hat jemand einen Fehler im Backend behoben. Mit einem einzigen Repository wird durch das Zurücksetzen vor dem neuen Fehler auch das Backend zurückgesetzt, was die Behebung erschweren könnte.

Das ist ein falsches Argument, denn es würde bedeuten, dass Sie nach zwei Bugfixes für ein Modul das erste nicht zurücksetzen können. Mit einem halbwegs vernünftigen VCS können Sie fast alle alten Festschreibungen rückgängig machen (obwohl dies häufig bedeutet, dass Sie eine neue Festschreibung durchführen, mit der diese Änderungen rückgängig gemacht werden, manchmal sogar für die oberste Stufe von HEAD).

Ich müsste das Backend in einen anderen Ordner klonen, damit das Backend funktioniert, während ich den Fehler im Frontend behebe ... und dann versuche, die Dinge neu zu ordnen ... Wenn zwei Repositorys vorhanden sind, ist es schmerzlos, den HEAD eines Repos zu verschieben den anderen nicht ändern. Und das Testen mit verschiedenen Versionen des Backends wird schmerzlos sein.

Dies ist eigentlich ein ziemlich gutes Argument. Durch die Verwendung von zwei Repositorys ist es einfacher, die Szenarien zu testen, in denen das bereitgestellte Front-End und Back-End möglicherweise (leicht) nicht mehr synchron sind.


Um ehrlich zu sein, können die meisten falschen Argumente mit Zweigen gelöst werden. Branch für Frontend und Branch für Backend. Master für die Synchronisation. Aber in gewisser Weise ist es komplizierter, mit Filialen umzugehen, als zwei Repos zu haben.
Loïc Faure-Lacroix

1
@Sybiam: Tatsächlich handelt es sich um falsche Argumente, da sie kein Problem hervorheben, das bei der Verwendung eines einzelnen Repositorys auftreten könnte, selbst wenn alle Änderungen nur an trunk / main vorgenommen werden.
Bart van Ingen Schenau

Ich denke, Ihre Kritiken sind gültig. Ich glaube einfach nicht, dass das der Sinn der Frage war.
Sylvanaar

2

Dieser Beitrag ist ein bisschen alt, aber ich möchte dazu beitragen. Während Ihr Back-End nicht wirklich über das Front-End Bescheid weiß, muss das Front-End Anforderungen haben, die mit der API des Back-End übereinstimmen. Wenn Sie Ihr Back-End als REST-API betrachten, können Sie eine Schnittstellendatei definieren, z. B. eine Swagger-YAML-Schnittstelle. Jetzt gibt es wirklich 3 Projekte, die Sie nach Belieben in verschiedene Repos aufteilen können:

  • API-Definition
  • Backend
  • Vorderes Ende

Die API-Definition ist eine Abhängigkeit in den beiden anderen Projekten. Nehmen wir an, Sie haben maven als Abhängigkeits-Injection-Tool verwendet. Dann kommt es darauf an, wie streng Sie die Versionierung durchführen möchten. Sie können die Version des API-Definitionsprojekts jedes Mal aktualisieren, wenn Sie Änderungen vornehmen, um sicherzustellen, dass die Projekte immer in einem kompatiblen Zustand sind, jedoch einen höheren Overhead erfordern, oder Sie können SNAPSHOTS in maven verwenden und die Versionierung erst dann durchführen, wenn Sie dies tun Ich bin mit der Schnittstelle zufrieden, die weniger Overhead erfordert, aber es kann sein, dass Sie häufig Inkompatibilitäten haben. Solange Sie jedoch die API-Definition in Ihrem Front- und Back-End erzwingen, können Sie die Projekte in verschiedene Repositorys aufteilen.

In diesen Problemen geht es eher um das Verwalten von Abhängigkeiten. Selbst wenn die Projekte nicht aufgeteilt sind und sich im selben Repository befinden, ist es ziemlich einfach, die Website in einen Zustand zu versetzen, in dem das Front-End und das Back-End nicht synchron sind. Die einzige Möglichkeit, dies zu stoppen, besteht darin, den Vertrag zwischen beiden zu definieren. Sie möchten dies jedoch auf eine Weise tun, die die Implementierungen von Front-End und Back-End nicht miteinander verbindet, so als würden Sie stattdessen auf eine Schnittstelle programmieren einer Implementierung in der OO-Programmierung.

Um der Kritik, dass dies einen Mehraufwand für die Verwaltung dieser Schnittstellendatei verursacht, vorbeugend begegnen zu können, kann swagger beispielsweise sogar Code-Stubs für verschiedene Programmiersprachen und Frameworks wie JAX-RS erstellen. Sie können also eine Schnittstelle in der von Ihnen gewählten Technologie erstellen und diese Schnittstelle dann implementieren. Es fügt Ihrem Back-End auch eine sehr schöne Dokumentation hinzu, die es den Front-End-Entwicklern erleichtert, ihre Arbeit zu erledigen.

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.