Monorepositories: bitte, muss

Monorepositories: bitte, muss

Übersetzung des Artikels für Kursteilnehmer „DevOps-Praktiken und -Tools“ im OTUS-Bildungsprojekt.

Sie sollten sich für ein Monorepository entscheiden, da das Verhalten, das es in Ihren Teams fördert, Transparenz und gemeinsame Verantwortung fördert, insbesondere wenn Teams wachsen. In jedem Fall müssen Sie in Werkzeuge investieren, aber es ist immer besser, wenn das Standardverhalten das Verhalten ist, das Sie in Ihren Befehlen wünschen.

Warum reden wir darüber?

Matt Klein hat den Artikel geschrieben „Monorepos: Bitte nicht!“  (Anmerkung des Übersetzers: Übersetzung auf Habré „Monorepositorien: bitte nicht“). Ich mag Matt, ich denke, er ist sehr schlau und man sollte seinen Standpunkt lesen. Er hat die Umfrage ursprünglich auf Twitter gepostet:

Monorepositories: bitte, muss

Übersetzung:
An diesem Neujahrstag werde ich darüber diskutieren, wie lächerlich Monorepositories sind. Das Jahr 2019 begann ruhig. In diesem Sinne biete ich Ihnen eine Umfrage an. Wer sind die großen Fanatiker? Unterstützer:
- Monorepo
- Rust
- Falsche Umfrage / beides

Meine Antwort war: „Ich bin buchstäblich beides.“ Anstatt darüber zu sprechen, dass Rust eine Droge ist, schauen wir uns lieber an, warum er meiner Meinung nach in Bezug auf Monorepositorien falsch liegt. Ein bisschen über dich. Ich bin der CTO von Chef Software. Wir haben etwa 100 Ingenieure, eine Codebasis, die etwa 11–12 Jahre zurückreicht, und 4 Hauptprodukte. Ein Teil dieses Codes befindet sich in einem Polyrepository (meine Ausgangsposition), ein anderer Teil in einem Monorepository (meine aktuelle Position).

Bevor ich anfange: Jedes Argument, das ich hier vorbringe, gilt für beide Arten von Repositories. Meiner Meinung nach gibt es keinen technischen Grund, warum Sie einen Repository-Typ einem anderen vorziehen sollten. Sie können jeden Ansatz zum Erfolg führen. Ich rede gerne darüber, aber ich interessiere mich nicht für künstliche technische Gründe, warum das eine dem anderen überlegen ist.

Ich stimme dem ersten Teil von Matts Argument zu:

Denn im Maßstab löst ein Monorepository dieselben Probleme wie ein Polyrepository, zwingt Sie aber gleichzeitig dazu, Ihren Code eng zu koppeln, und erfordert unglaubliche Anstrengungen, um die Skalierbarkeit Ihres Versionskontrollsystems zu erhöhen.

Unabhängig davon, ob Sie sich für ein Monorepository oder ein Polyrepository entscheiden, müssen Sie die gleichen Probleme lösen. Wie veröffentlichen Sie Veröffentlichungen? Wie gehen Sie mit Updates um? Rückwärtskompatibilität? Projektübergreifende Abhängigkeiten? Welche Architekturstile sind akzeptabel? Wie verwalten Sie Ihre Build- und Testinfrastruktur? Die Liste ist endlos. Und Sie werden sie alle lösen, wenn Sie wachsen. Es gibt keinen kostenlosen Käse.

Ich denke, Matts Argumentation ähnelt den Ansichten vieler Ingenieure (und Manager), die ich respektiere. Dies geschieht aus der Perspektive des an der Komponente arbeitenden Ingenieurs oder des an der Komponente arbeitenden Teams. Sie hören Dinge wie:

  • Die Codebasis ist umfangreich – ich brauche diesen ganzen Müll nicht.
  • Es ist schwieriger zu testen, weil ich all diesen Müll testen muss, den ich nicht brauche.
  • Es ist schwieriger, mit externen Abhängigkeiten zu arbeiten.
  • Ich brauche meine eigenen virtuellen Versionskontrollsysteme.

Natürlich sind alle diese Punkte berechtigt. Dies geschieht in beiden Fällen – im Polyrepository habe ich meinen eigenen Müll, zusätzlich zu dem, der für den Build benötigt wird ... Möglicherweise benötige ich auch anderen Müll. Ich erstelle also „einfach“ Tools, die das gesamte Projekt prüfen. Oder ich erstelle ein gefälschtes Monorepository mit Submodulen. Wir könnten hier den ganzen Tag herumlaufen. Aber ich denke, Matts Argument geht am Hauptgrund vorbei, den ich ziemlich stark zugunsten des Monorepositorys umgedreht habe:

Es provoziert Kommunikation und zeigt Probleme auf

Wenn wir Repositories trennen, entsteht de facto ein Koordinations- und Transparenzproblem. Dies entspricht der Art und Weise, wie wir über Teams denken (insbesondere die Art und Weise, wie einzelne Mitglieder über sie denken): Wir sind für eine bestimmte Komponente verantwortlich. Wir arbeiten relativ isoliert. Die Grenzen sind auf mein Team und die Komponente(n) festgelegt, an denen wir arbeiten.

Da die Architektur immer komplexer wird, kann ein Team sie nicht mehr alleine bewältigen. Die wenigsten Ingenieure haben das Gesamtsystem im Kopf. Nehmen wir an, Sie verwalten eine gemeinsam genutzte Komponente A, die von den Teams B, C und D verwendet wird. Team A führt eine Umgestaltung durch, verbessert die API und ändert auch die interne Implementierung. Daher sind die Änderungen nicht abwärtskompatibel. Welchen Rat haben Sie?

  • Finden Sie alle Orte, an denen die alte API verwendet wird.
  • Gibt es Orte, an denen die neue API nicht verwendet werden kann?
  • Können Sie andere Komponenten reparieren und testen, um sicherzustellen, dass sie nicht kaputt gehen?
  • Können diese Teams Ihre Änderungen jetzt testen?

Bitte beachten Sie, dass diese Fragen unabhängig vom Repository-Typ sind. Sie müssen die Teams B, C und D finden. Sie müssen mit ihnen sprechen, die Zeit herausfinden und ihre Prioritäten verstehen. Zumindest hoffen wir, dass Sie es tun werden.

Niemand möchte das wirklich tun. Das macht viel weniger Spaß, als nur die verdammte API zu reparieren. Es ist alles menschlich und chaotisch. In einem Polyrepository können Sie einfach Änderungen vornehmen, sie den Leuten, die an dieser Komponente arbeiten (wahrscheinlich nicht B, C oder D), zur Überprüfung geben und weitermachen. Die Teams B, C und D können vorerst einfach bei ihrer aktuellen Version bleiben. Sie werden erneuert, wenn sie Ihr Genie erkennen!

In einem Monorepository wird die Verantwortung standardmäßig verschoben. Team A wechselt seine Komponente und macht, wenn es nicht aufpasst, sofort B, C und D kaputt. Dies führt dazu, dass B, C und D an der Tür von A auftauchen und sich fragen, warum Team A die Baugruppe kaputt gemacht hat. Dies lehrt A, dass sie meine Liste oben nicht überspringen können. Sie müssen darüber sprechen, was sie tun werden. Können B, C und D sich bewegen? Was wäre, wenn B und C das könnten, D aber eng mit einem Nebeneffekt des Verhaltens des alten Algorithmus verbunden wäre?

Dann müssen wir darüber reden, wie wir aus dieser Situation herauskommen:

  1. Unterstützt mehrere interne APIs und markiert den alten Algorithmus als veraltet, bis D ihn nicht mehr verwenden kann.
  2. Unterstützung für mehrere Release-Versionen, eine mit der alten Schnittstelle, eine mit der neuen.
  3. Verzögern Sie die Veröffentlichung der Änderungen von A, bis B, C und D sie gleichzeitig akzeptieren können.

Nehmen wir an, wir haben 1 oder mehrere APIs ausgewählt. In diesem Fall haben wir zwei Codeteile. Alt und Neu. In manchen Situationen recht praktisch. Wir checken den alten Code wieder ein, markieren ihn als veraltet und vereinbaren mit dem D-Team einen Zeitplan für die Entfernung. Im Wesentlichen identisch für Poly- und Mono-Repositories.

Um mehrere Versionen zu veröffentlichen, benötigen wir einen Zweig. Jetzt haben wir zwei Komponenten – A1 und A2. Die Teams B und C verwenden A2 und D verwendet A1. Wir müssen jede Komponente zur Veröffentlichung bereit haben, da möglicherweise Sicherheitsupdates und andere Fehlerbehebungen erforderlich sind, bevor D voranschreiten kann. In einem Polyrepository können wir dies in einem langlebigen Zweig verstecken, der sich gut anfühlt. In einem Monorepository erzwingen wir die Erstellung des Codes in einem neuen Modul. Team D muss noch Änderungen an der „alten“ Komponente vornehmen. Jeder kann sehen, welche Kosten wir hier zahlen – wir haben jetzt doppelt so viel Code und alle Fehlerbehebungen, die für A1 und A2 gelten, müssen für beide gelten. Beim Branching-Ansatz in einem Polyrepository wird dies hinter Cherry-Pick verborgen. Wir halten die Kosten für geringer, da es keine Duplikate gibt. Aus praktischer Sicht sind die Kosten die gleichen: Sie erstellen, veröffentlichen und pflegen zwei weitgehend identische Codebasen, bis Sie eine davon löschen können. Der Unterschied besteht darin, dass dieser Schmerz bei einem Monorepositorium direkt und sichtbar ist. Das ist noch schlimmer, und das ist gut so.

Schließlich kamen wir zum dritten Punkt. Release-Verzögerung. Es ist möglich, dass von A vorgenommene Änderungen das Leben von Team A verbessern. Wichtig, aber nicht dringend. Können wir es einfach hinauszögern? In einem Polyrepository pushen wir dies, um das Artefakt zu fixieren. Natürlich sagen wir das Team D. Bleiben Sie einfach bei der alten Version, bis Sie auf dem Laufenden sind! Das bereitet Sie darauf vor, den Feigling zu spielen. Team A arbeitet weiter an seiner Komponente und ignoriert dabei die Tatsache, dass Team D eine zunehmend veraltete Version verwendet (das ist das Problem von Team D, sie sind dumm). In der Zwischenzeit spricht Team D schlecht über die nachlässige Haltung von Team A gegenüber der Codestabilität, wenn überhaupt darüber gesprochen wird. Monate vergehen. Schließlich beschließt Team D, die Möglichkeit einer Aktualisierung zu prüfen, aber A hat nur weitere Änderungen. Team A kann sich kaum daran erinnern, wann oder wie es D kaputt gemacht hat. Das Upgrade ist schmerzhafter und wird länger dauern. Dadurch wird es im Prioritätsstapel weiter nach unten geschickt. Bis zu dem Tag, an dem wir in A ein Sicherheitsproblem haben, das uns dazu zwingt, eine Verzweigung zu machen. Team A muss in der Zeit zurückgehen, einen Punkt finden, an dem D stabil war, das Problem dort beheben und es für die Veröffentlichung vorbereiten. Dies ist die faktische Entscheidung, die Menschen treffen, und sie ist bei weitem die schlechteste. Es scheint sowohl für Team A als auch für Team D gut zu sein, solange wir uns gegenseitig ignorieren können.

In einem Monorepository ist das dritte eigentlich keine Option. Sie sind gezwungen, auf zwei Arten mit der Situation umzugehen. Sie müssen die Kosten für zwei Release-Branches ermitteln. Erfahren Sie, wie Sie sich vor Updates schützen, die die Abwärtskompatibilität beeinträchtigen. Aber am wichtigsten: Sie können ein schwieriges Gespräch nicht vermeiden.

Wenn Teams größer werden, ist es meiner Erfahrung nach nicht mehr möglich, das gesamte System im Auge zu behalten, und das ist der wichtigste Teil. Sie müssen die Sichtbarkeit von Zwietracht im System verbessern. Sie müssen aktiv daran arbeiten, Teams dazu zu bringen, von ihren Komponenten wegzuschauen und sich die Arbeit anderer Teams und Verbraucher anzusehen.

Ja, Sie können Tools erstellen, die versuchen, das Polyrepository-Problem zu lösen. Aber meine Erfahrung im Unterrichten von Continuous Delivery und Automatisierung in großen Unternehmen zeigt mir: Das Standardverhalten ohne den Einsatz zusätzlicher Tools ist das Verhalten, das Sie erwarten. Das Standardverhalten eines Polyrepositorys ist Isolation, das ist der springende Punkt. Das Standardverhalten eines Monorepositorys ist geteilte Verantwortung und Transparenz, das ist der springende Punkt. In beiden Fällen werde ich ein Werkzeug erstellen, das die rauen Kanten glättet. Als Führungskraft werde ich jedes Mal ein Monorepository wählen, weil die Tools die Kultur stärken müssen, die ich möchte, und Kultur entsteht aus kleinen Entscheidungen und der täglichen Arbeit des Teams.

An der Umfrage können nur registrierte Benutzer teilnehmen. Einloggenbitte.

Wer sind die größten Fanatiker? Unterstützer:

  • Monorepo

  • Rust

  • Falsche Umfrage / beides

33 Benutzer haben abgestimmt. 13 Benutzer enthielten sich der Stimme.

Source: habr.com

Kommentar hinzufügen