Übersetzung des Artikels für Studierende des Kurses im Bildungsprojekt OTUS.
Sie sollten ein Monorepo wählen, da das Verhalten, das es in Ihren Teams fördert, Transparenz und kollektive Verantwortung ist, insbesondere mit dem Wachstum der Teams. In jedem Fall müssen Sie in die Werkzeuge investieren, aber es ist immer besser, wenn das Standardverhalten das Verhalten ist, das Sie in Ihren Teams sehen möchten.
Warum sprechen wir darüber?
Matt Klein hat einen Artikel geschrieben (Anm. des Übersetzers: Die Übersetzung auf Habré ). Ich mag Matt, ich denke, er ist sehr schlau, und Sie sollten seine Sichtweise lesen. Zunächst veröffentlichte er eine Umfrage auf Twitter:
Übersetzung:
An diesem Neujahrstag werde ich argumentieren, wie absurd Monorepos sind. Das Jahr 2019 hat unauffällig begonnen. In diesem Sinne schlage ich Ihnen eine Umfrage vor. Wer sind die großen Fans? Befürworter:
— Monorepo
— Rust
— Falsche Umfrage / sowohl als auch
Meine Antwort war: „Ich bin buchstäblich diese beiden Personen.“ Anstatt darüber zu sprechen, wie toll Rust ist, lasst uns besprechen, warum ich denke, dass er sich bezüglich Monorepos irrt. Ein wenig zu mir: Ich bin CTO bei Chef Software. Wir haben etwa 100 Ingenieure, einen Codebestand von etwa 11–12 Jahren und 4 Hauptprodukte. Ein Teil dieses Codes befindet sich in einem Poly-Repository (meine Ausgangsposition), der andere Teil in einem Monorepository (meine aktuelle Position).
Bevor ich beginne: Jedes Argument, das ich hier bringe, wird auf Repositories beider Arten angewendet. Meiner Meinung nach gibt es keine technischen Gründe, warum Sie die eine oder andere Art von Repository wählen sollten. Sie können jeden Ansatz zum Laufen bringen. Ich freue mich darauf, darüber zu sprechen, aber ich interessiere mich nicht für künstliche technische Gründe, die dafür sprechen, dass das eine das andere übertrifft.
Ich stimme der ersten Hälfte von Matts Standpunkt zu:
Denn in großem Maßstab wird ein Monorepository all die gleichen Probleme lösen, die auch ein Polyrepository behandelt, gleichzeitig aber zu einer stärkeren Kohärenz Ihres Codes anregen und enorme Anstrengungen zur Skalierbarkeit Ihres Versionskontrollsystems erfordern.
Sie werden die gleichen Probleme lösen müssen, egal ob Sie sich für ein Monorepository oder ein Polyrepository entscheiden. Wie veröffentlichen Sie Releases? Welche Strategie haben Sie für Updates? Rückwärtskompatibilität? Kreuzabhängigkeiten zwischen Projekten? Welche Architekturstile sind akzeptabel? Wie verwalten Sie Ihre Build- und Testinfrastruktur? Die Liste ist endlos. Und Sie werden diese Herausforderungen alle bewältigen müssen, während Sie wachsen. Kostenlose Dinge gibt es nicht.
Ich denke, dass Matt's Argument die Ansichten widerspiegelt, die viele Ingenieure (und Manager), die ich respektiere, teilen. Dies geschieht aus der Perspektive eines Ingenieurs, der an einer Komponente arbeitet, oder eines Teams, das an einer Komponente arbeitet. Man hört dann Dinge wie:
- Die Codebasis ist schwerfällig – ich brauche nicht all diesen Ballast.
- Es ist schwieriger zu testen, da ich all diesen Kram überprüfen muss, den ich nicht brauche.
- Es ist schwieriger, mit externen Abhängigkeiten zu arbeiten.
- Ich brauche meine eigenen virtuellen Versionsverwaltungssysteme.
Zweifellos sind all diese Punkte gerechtfertigt. Das gilt in beiden Fällen – in meinem Monorepository habe ich meinen Kram, zusätzlich zu dem, der für den Build benötigt wird... Vielleicht brauche ich noch mehr Kram. Daher erstelle ich "einfach" Werkzeuge, die ein Checkout des gesamten Projekts durchführen. Oder ich erstelle ein gefälschtes Monorepository mit Submodulen. Wir könnten den ganzen Tag darüber diskutieren. Aber ich denke, dass Matts Argument die Hauptursache übersieht, für die ich ziemlich stark für Monorepositories plädiere:
Es fördert die Kommunikation und zeigt Probleme auf.
Wenn wir Repositories teilen, schaffen wir de facto ein Problem der Koordination und Transparenz. Dies entspricht der Art und Weise, wie wir über Teams denken (insbesondere wie individuelle Mitglieder über sie denken): Wir sind verantwortlich für eine bestimmte Komponente. Wir arbeiten in relativer Isolation. Die Grenzen sind auf mein Team und die Komponente(n) festgelegt, an denen wir arbeiten.
Mit der Komplexität der Architektur kann ein Team sie nicht mehr alleine verwalten. Nur sehr wenige Ingenieure haben das gesamte System im Kopf. Angenommen, Sie verwalten die gemeinsame Komponente A, die von den Teams B, C und D genutzt wird. Das Team A refaktoriert, verbessert die API und ändert die interne Implementierung. Infolgedessen sind die Änderungen nicht abwärtskompatibel. Welchen Rat würden Sie geben?
- Finden Sie alle Stellen, an denen die alte API verwendet wird.
- Gibt es Orte, an denen die neue API nicht verwendet werden kann?
- Können Sie andere Komponenten anpassen und testen, um sicherzustellen, dass sie nicht kaputtgehen?
- Können diese Teams Ihre Änderungen jetzt überprüfen?
Bitte beachten Sie, dass diese Fragen nicht vom Typ des Repositories abhängen. Sie müssen die Teams B, C und D finden. Sie müssen mit ihnen sprechen, um deren Zeitrahmen und Prioritäten zu verstehen. Wir hoffen jedenfalls, dass Sie das tun werden.
Tatsächlich möchten das die meisten nicht machen. Es ist weitaus weniger spannend, als einfach die verdammte API zu reparieren. Das Ganze ist menschlich und kompliziert. In einem Polirepository können Sie einfach Änderungen vornehmen, zur Überprüfung an die Personen weitergeben, die an diesem Baustein arbeiten (wahrscheinlich nicht an B, C oder D), und dann weitermachen. Teams B, C und D können vorerst bei ihrer aktuellen Version bleiben. Sie werden aktualisieren, sobald sie Ihr Genie erkennen!
Im Monorepo verschiebt sich die Verantwortung standardmäßig. Team A ändert seine Komponente und wenn es nicht vorsichtig ist, bricht es sofort B, C und D. Das führt dazu, dass B, C und D vor der Tür von A stehen und sich wundern, warum Team A den Build kaputt gemacht hat. Das bringt A bei, dass sie meine obige Liste nicht ignorieren können. Sie müssen darüber sprechen, was sie vorhaben. Können B, C und D agieren? Was ist, wenn B und C können, aber D eng mit den Nebeneffekten des alten Algorithmus verbunden war?
Dann müssen wir darüber sprechen, wie wir aus dieser Situation herauskommen:
- Unterstützung mehrerer interner APIs, während der alte Algorithmus als veraltet markiert wird, bis D ihn nicht mehr verwenden kann.
- Unterstützung mehrerer Versionen von Releases, eine mit der alten Schnittstelle, eine mit der neuen.
- Verschiebung der Release-Veränderungen von A, bis B, C und D diese gleichzeitig akzeptieren können.
Angenommen, wir haben 1 oder mehrere APIs ausgewählt. In diesem Fall haben wir zwei Codeabschnitte. Den alten und den neuen. Das ist in bestimmten Situationen recht praktisch. Wir geben den alten Code zurück, kennzeichnen ihn als veraltet (deprecated) und stimmen mit Team D einen Zeitplan für seine Entfernung ab. Im Wesentlichen gilt das Gleiche für Poly- und Monorepositories.
Für die Veröffentlichung mehrerer Versionen benötigen wir einen Branch. Derzeit haben wir zwei Komponenten – A1 und A2. Die Teams B und C nutzen A2, während D A1 verwendet. Es ist erforderlich, dass jede Komponente bereit für die Veröffentlichung ist, da möglicherweise Sicherheitsupdates und Fehlerbehebungen erforderlich sind, bevor D weitermachen kann. In unserem Polirepository können wir dies in einem langlebigen Branch verstecken, der gut funktioniert. Im Monorepository erstellen wir den Code zwangsläufig in einem neuen Modul. Team D wird dennoch Änderungen an der "alten" Komponente vornehmen müssen. Jeder kann die Kosten sehen, die wir hier tragen – unser Code hat sich nun verdoppelt, und alle Fehlerbehebungen, die auf A1 und A2 angewendet werden, müssen für beide gelten. Mit dem Branch-Ansatz im Polirepository bleibt dies durch Cherry-Picking verborgen. Wir betrachten die Kosten als geringer, da es dort keine Duplizierung gibt. Aus praktischer Sicht sind die Kosten jedoch gleich: Sie werden zwei, im Wesentlichen identische, Codebasen entwickeln, veröffentlichen und unterstützen, bis Sie eine von ihnen entfernen können. Der Unterschied besteht darin, dass bei dem Monorepository dieser Schmerz direkt sichtbar ist. Das ist noch schlimmer, und das ist gut.
Schließlich sind wir beim dritten Punkt angekommen: Die Verzögerung des Releases. Es ist möglich, dass die Änderungen von Team A das Leben von Team A verbessern. Wichtig, aber nicht dringend. Können wir einfach warten? In unserem Repositories fördern wir dies zur Festschreibung des Artefakts. Natürlich sprechen wir darüber mit Team D. Bleibt einfach bei der alten Version, bis ihr nachkommt! Das spielt mit den Ängsten. Team A arbeitet weiter an seinem Konzept und ignoriert, dass Team D eine zunehmend veraltete Version verwendet (das ist das Problem von Team D, sie sind naiv). In der Zwischenzeit spricht Team D schlecht über die fahrlässige Haltung von Team A gegenüber der Stabilität des Codes, falls sie überhaupt darüber sprechen. Monate vergehen. Schließlich entscheidet sich Team D, die Möglichkeit eines Updates zu prüfen, doch die Änderungen in Team A haben sich nur vergrößert. Team A kann sich kaum erinnern, wann und wie sie Team D gestört haben. Das Update wird schmerzhafter und dauert länger. Was es weiter nach unten auf der Prioritätenliste schiebt. Bis zu dem Tag, an dem wir ein Sicherheitsproblem in Team A haben, was uns zwingt, einen Branch zu machen. Team A muss in der Zeit zurückreisen, den Moment finden, als Team D stabil war, das Problem dort beheben und es für den Release vorbereiten. Das ist de facto die Wahl, die Menschen treffen, und sie ist sichergestellt die schlechteste. Es scheint, dass es sowohl für Team A als auch für Team D gut ist, solange wir einander ignorieren können.
In einem Monorepo ist das dritte - wirklich keine Option. Sie sind gezwungen, die Situation auf eine von zwei Arten zu bewältigen. Sie müssen die Kosten von zwei Release-Branches betrachten. Lernen Sie, sich vor Änderungen zu schützen, die die Abwärtskompatibilität brechen. Aber das Wichtigste ist: Sie werden nicht um ein schwieriges Gespräch herumkommen.
Meiner Erfahrung nach, wenn Teams größer werden, gibt es keine Möglichkeit mehr, das gesamte System im Kopf zu halten, und das ist der wichtigste Teil. Sie müssen die Sichtbarkeit von Konflikten im System verbessern. Sie müssen aktiv daran arbeiten, die Teams dazu zu bringen, ihre Blicke von ihren eigenen Komponenten abzuwenden und die Arbeiten anderer Teams und ihrer Benutzer zu betrachten.
Ja, Sie können Werkzeuge erstellen, die versuchen, Probleme mit Poly-Repositories zu lösen. Doch meine Erfahrungen mit Continuous Delivery und Automatisierung in großen Unternehmen zeigen mir Folgendes: Das Standardverhalten ohne den Einsatz zusätzlicher Werkzeuge ist das Verhalten, das Sie erwarten sollten. Das Standardverhalten eines Poly-Repositories besteht in der Isolation; das ist der ganze Sinn. Das Standardverhalten eines Mono-Repositories dagegen ist gemeinsame Verantwortung und Transparenz; das ist der ganze Sinn. In beiden Fällen werde ich ein Werkzeug erstellen, das es ermöglicht, die Ecken abzurunden. Als Führungskraft werde ich jedes Mal ein Mono-Repository wählen, weil die Werkzeuge die Kultur unterstützen sollten, die ich fördern möchte, und diese Kultur entsteht aus kleinen Entscheidungen und der täglichen Arbeit des Teams.
Nur registrierte Benutzer können an der Umfrage teilnehmen. Sind Sie an Contour interessiert?
Wer sind die größeren Fanatiker? Befürworter:
Monorepo
Rust
Falsche Umfrage / sowohl als auch
33 Nutzer haben abgestimmt. 13 Nutzer haben sich enthalten.
Quelle: habr.com
