Monorepositionen: bitte nicht (Teil 2)

    Hallo an alle!

    Also, ein neuer Teil des versprochenen Holivars über Monorepositorien. Im ersten Teil haben wir die Übersetzung eines Artikels eines angesehenen Ingenieurs von Lyft (und früher von Twitter) erörtert, was die Mängel von Monospositorien ist und warum sie fast alle Vorteile dieses Ansatzes aufheben. Ich persönlich stimme den Argumenten des ursprünglichen Artikels weitgehend zu. Um diese Diskussion zu beenden, möchte ich, wie versprochen, noch einige weitere Punkte ansprechen, die meiner Meinung nach noch wichtiger und praktischer sind.

    Ich erzähle Ihnen etwas über mich - ich habe in kleinen und relativ großen Projekten gearbeitet und in einem Projekt mit mehr als 100 Microservices (und SLA 99,999%) Poly-Repositories verwendet. Im Moment bin ich damit beschäftigt, ein kleines Mono-Repository (eigentlich nicht nur das vordere js + java-Backend) von maven nach bazel zu transferieren. Funktionierte nicht bei Google, Facebook, Twitter, d. H. Ich hatte nicht das Vergnügen, ein Mono-Repository zu verwenden, das richtig eingestellt und aufgehängt wurde.

    Was ist ein Mono-Repository? Kommentare zur Übersetzung des Originalartikels zeigten, dass viele glauben, dass das Mono-Repository der Fall ist, wenn alle fünf Entwickler des Unternehmens an einem Repository arbeiten und das Front-End und das Back-End darin behalten. Natürlich nicht. Ein Mono-Repository ist eine Möglichkeit, alle Projekte, Bibliotheken, Tools zum Erstellen, Plug-Ins für IDE, Implementierungsskripts und alles andere in einem großen Repository zu speichern. Details hier trunkbaseddevelopment.com .

    Wie heißt dann der Ansatz, wenn ein Unternehmen klein ist und es einfach nicht so viele Projekte, Module, Komponenten gibt? Dies ist auch ein nur kleines Repository.
    Der ursprüngliche Artikel besagt natürlich, dass alle beschriebenen Probleme in einem bestimmten Umfang auftreten. Diejenigen, die schreiben, dass ihr Mono-Repository für 1,5 Digger einwandfrei funktioniert, sind natürlich absolut richtig.

    Die erste Tatsache, die ich gerne korrigieren möchte: Ein Mono-Repository ist ein guter Start für Ihr neues Projekt . Wenn Sie den gesamten Code auf einen Stapel legen, erhalten Sie zunächst nur einen Vorteil, weil Die Unterstützung für mehrere Repositorys führt sicherlich zu einem gewissen Aufwand.

    Was ist das Problem dann? Und das Problem beginnt, wie im Originalartikel erwähnt, in einem gewissen Umfang. Und vor allem, verpassen Sie nicht den Moment, wenn eine solche Waage bereits angekommen ist.

    Daher neige ich dazu zu sagen, dass im Wesentlichen die Probleme, die sich ergeben, nicht die Probleme des Ansatzes sind, „all Ihren Code auf einen Haufen“, und dies sind Probleme nur großer Quellcode-Repositories. Ie Wenn Sie davon ausgehen, dass Sie Poly-Repositories für verschiedene Services / Komponenten verwendet haben und einer dieser Services so groß geworden ist (wie viel, werden wir im Folgenden besprechen), werden Sie höchstwahrscheinlich genau dieselben Probleme haben, aber auch ohne die Vorteile von Monorepositories (falls vorhanden) , natürlich gibt es).

    Wie groß sollte das Repository sein, um als problematisch zu gelten?
    Es gibt definitiv zwei Indikatoren, von denen es abhängt - die Menge des Codes und die Anzahl der Entwickler, die mit diesem Code arbeiten. Wenn Ihr Projekt über Terabytes an Code verfügt, aber gleichzeitig 1-2 Personen damit arbeiten, werden sie höchstwahrscheinlich kaum Probleme feststellen (oder zumindest ist es einfacher, nichts zu tun, selbst wenn sie es bemerken :)

    Wie können Sie das feststellen? Ist es Zeit zu überlegen, wie Sie Ihr Repository verbessern können? Natürlich ist dies ein subjektiver Indikator. Ihre Entwickler werden sich höchstwahrscheinlich damit beschweren, dass sie mit etwas nicht zufrieden sind. Aber das Problem ist, dass es zu spät sein kann, um etwas zu ändern. Ich gebe einige Zahlen in meinem eigenen Namen: Wenn das Klonen Ihres Repositorys mehr als 10 Minuten dauert, dauert der Projektaufbau mehr als 20 bis 30 Minuten, wenn die Anzahl der Entwickler mehr als 50 beträgt, und so weiter.

    Eine interessante Tatsache aus der persönlichen Praxis:
    я работал над довольно большим монолитом в команде из примерно 50 разработчиков, разделенных на несколько небольших команд. Разработка велась в фича-бранчах, а мердж происходил перед самым фича-фризом. Однажды я потратил на мердж нашей командной ветки 3 дня, после того как передо мной замерджились 6 других команд.

    Gehen wir nun die Liste der Probleme durch, die in großen Repositories auftreten (einige davon wurden im Originalartikel angesprochen, andere nicht).

    1) Repository-Downloadzeit


    Zum einen können wir sagen, dass dies ein einmaliger Vorgang ist, den der Entwickler während der Ersteinrichtung seiner Workstation ausführt. Ich persönlich habe oft Situationen, in denen ich ein Projekt in den nächsten Ordner klonen, darin graben und es dann löschen möchte. Wenn das Klonen jedoch mehr als 10-20 Minuten dauert, ist das nicht so komfortabel.

    Außerdem sollten Sie nicht vergessen, dass Sie vor dem Erstellen eines Projekts auf einem CI-Server das Repository für jeden Build-Agent klonen müssen. Und hier fangen Sie an zu überlegen, wie Sie diese Zeit sparen können. Wenn jede Baugruppe 10 bis 20 Minuten länger dauert und das Ergebnis der Montage 10 bis 20 Minuten später erscheint, ist dies für niemanden geeignet. Das Repository erscheint also in den Images der virtuellen Maschinen, von denen die Agenten bereitgestellt werden, und es erscheinen zusätzliche Komplexität und zusätzliche Kosten, um diese Lösung zu unterstützen.

    2) Montagezeit


    Dies ist ein ziemlich offensichtlicher Punkt, der oft diskutiert wurde. Wenn Sie über viele Quellcodes verfügen, wird der Build ohnehin viel Zeit in Anspruch nehmen. Eine vertraute Situation, wenn Sie nach dem Ändern einer Codezeile eine halbe Stunde warten müssen, während die Änderungen wieder zusammengesetzt und getestet werden. In der Tat gibt es nur eine Lösung - ein Montagesystem zu verwenden, das auf Zwischenspeicherungsergebnissen und inkrementellen Assemblierungen basiert.

    Es gibt hier nicht so viele Möglichkeiten - obwohl die Caching-Funktionen zu demselben Gradle hinzugefügt wurden (leider wurden sie in der Praxis nicht verwendet), bringen sie keinen praktischen Nutzen, da traditionelle Build-Systeme keine wiederholbaren Ergebnisse haben. (reproduzierbare Builds). Ie Aufgrund der Nebeneffekte des vorherigen Builds muss zu einem bestimmten Zeitpunkt noch ein Cache-Flush ausgelöst werden (Standardansatz maven clean build). Daher bleibt nur die Option, Bazel / Buck / Pants und ähnliche zu verwenden. Warum das nicht sehr gut ist, werden wir unten ein wenig diskutieren.

    3) IDE-Indizierung


    Mein aktuelles Projekt ist in Intellij IDEA von 30 bis 40 Minuten indiziert. Und deine? Natürlich können Sie nur einen Teil des Projekts öffnen oder alle nicht benötigten Module von der Indizierung ausschließen. Das Problem besteht jedoch darin, dass jedes Mal, wenn Sie von einem Zweig zu einem anderen wechseln, eine erneute Indizierung erfolgt. Deshalb klicke ich das Projekt gerne in das nächste Verzeichnis. Einige Leute kommen zu dem Punkt, dass sie anfangen, den IDE-Cache zu cachen :)
    <Bild von D-Caprio mit zusammengekniffenen Augen>

    4) Montageprotokolle


    Welchen CI-Server verwenden Sie? Bietet es eine bequeme Benutzeroberfläche zum Anzeigen und Navigieren in Montageprotokollen mit einer Größe von mehreren Gigabyte? Leider mein nicht :(

    5) Commit Geschichte


    Magst du es, die Geschichte des Commits zu sehen? Ich liebe es, vor allem im GUI-Tool (ich nehme die Informationen besser visuell wahr, schimpfe nicht :).
    Dies ist die Geschichte von Commits in meinem Repository.
    image

    Gefällt? Günstig? Ich persönlich nicht!

    6) Defekte Tests


    Was passiert, wenn jemand defekte Tests / nicht kompilierten Code im Master ausführen kann? Sie werden natürlich sagen, dass Ihr CI dies nicht zulässt. Was ist mit den instabilen Tests, die vom Autor durchgeführt werden, und keinem anderen? Nun stellen Sie sich vor, dass sich dieser Code auf die Maschinen von 300 Entwicklern ausgeweitet hat und keiner von ihnen ein Projekt erstellen kann. Was ist in dieser Situation zu tun? Warten Sie, wann der Autor es bemerkt und korrigiert? Richtig für ihn? Änderungen rückgängig machen? Im Idealfall lohnt es sich natürlich, nur guten Code zu schreiben und ohne Fehler sofort zu schreiben. Dann tritt dieses Problem nicht auf.
    (Für diejenigen, die sich im Tank befinden und die Hinweise nicht verstanden haben, handelt es sich um die negativen Auswirkungen, wenn dies im Repository mit 10 Entwicklern geschieht und im Repository mit 300 etwas anders sein wird.)

    7) Merge bot


    Schon mal was von so etwas gehört? Weißt du, warum sie gebraucht wird? Sie werden lachen, aber dies ist ein weiteres Werkzeug, das nicht existieren sollte :) Stellen Sie sich vor, die Erstellungszeit Ihres Projekts beträgt 30 Minuten. Und 100 Entwickler arbeiten an Ihrem Projekt. Angenommen, jeder schießt einen Commit pro Tag. Stellen Sie sich nun ein ehrliches CI vor, das Änderungen an dem Master erst dann zulässt, wenn sie auf den letzten Commit des Masters (Rebase) angewendet wurden.

    Achtung, die Frage ist: Wie viele Stunden sollte ein Tag sein, damit ein ehrlicher CI-Server die Änderungen von allen Entwicklern lesen kann? Die richtige Antwort ist 50. Wer richtig geantwortet hat, kann den Lebkuchen aus dem Regal nehmen. Nun, oder stellen Sie sich vor, wie Sie gerade Ihr Commit für das letzte Commit für den Master debütiert haben, mit dem Build begonnen haben, und als er fertig war, hatte der Master bereits 20 Commits vor sich gelassen. Immer wieder

    Merge Bot oder Merge Queue ist also ein Dienst, der das erneute Senden aller Merge-Anforderungen an den neuen Master, das direkte Ausführen der Tests und des Merge automatisiert und Commits in Batch-Dateien zusammenfasst und zusammen testet. Sehr praktische Sache. Siehe mergify.io , k8s test-infra prow von google, bors-ngua (Ich verspreche, in Zukunft mehr darüber zu schreiben)

    Nun zu weniger technischen Problemen:

    8) Verwenden eines einzigen Build-Tools


    Ehrlich gesagt ist es mir immer noch ein Rätsel, warum das gesamte Mono-Repository mithilfe eines gemeinsamen Montagesystems gesammelt wird. Warum nicht Javascript Garn, Java Gradle, Scala - sbt usw. bauen? Wenn jemand die Antwort auf diese Frage kennt (nicht vermutet oder annimmt und das heißt, weiß), schreibe in die Kommentare.

    Natürlich ist es offensichtlich, dass die Verwendung eines Build-Systems besser ist als mehrere verschiedene. Aber sie verstehen trotzdem, dass alles Universale offensichtlich schlechter ist als ein spezialisiertes, da Es hat höchstwahrscheinlich nur eine Teilmenge aller spezialisierten Funktionen. Schlimmer noch, unterschiedliche Programmiersprachen können unterschiedliche Paradigmen in Bezug auf Assemblierung, Abhängigkeitsverwaltung usw. haben, die in einem gemeinsamen Wrapper sehr schwer zu fassen sind. Ich möchte nicht auf Details eingehen, ich werde ein Beispiel über Bazel geben (warten Sie auf Details in einem separaten Artikel) - Wir haben 5 unabhängige Implementierungen von Javascript-Build-Regeln für Bazel von 5 verschiedenen Unternehmen auf GitHub zusammen mit den offiziellen von Google gefunden. Überlegenswert.

    9) Allgemeine Ansätze


    Als Antwort auf den ursprünglichen CTO-Artikel von Chefkoch schrieb Monorepo seine Antwort : Bitte machen Sie es! . In seiner Antwort argumentiert er, dass "die Hauptsache bei monorepo ist, dass er Gespräche macht und Fehler sichtbar macht." Er bedeutet, wenn Sie Ihre API ändern möchten, müssen Sie alle Verwendungszwecke finden und Ihre Änderungen mit den Betreuern dieser Codeteile besprechen.

    Meine Erfahrung ist also genau das Gegenteil. Es ist klar, dass dies sehr stark von der Ingenieurskultur im Team abhängt, aber ich sehe in diesem Ansatz feste Nachteile. Stellen Sie sich vor, Sie haben einen bestimmten Ansatz gewählt, der Ihnen eine Zeit lang treu gedient hat. Deshalb haben Sie sich aus irgendeinem Grund entschieden, ein ähnliches Problem zu lösen, eine etwas andere, vielleicht modernere Methode zu verwenden. Wie groß ist die Wahrscheinlichkeit, dass die Hinzufügung eines neuen Ansatzes eine Überprüfung durchläuft?

    In meiner jüngsten Vergangenheit erhielt ich wiederholt Kommentare wie "Wir haben bereits einen bewährten Pfad, verwenden Sie ihn" und "Wenn Sie einen neuen Ansatz implementieren möchten, aktualisieren Sie den Code an allen 120 Stellen, die den alten Ansatz verwenden, und erhalten Sie von allen Teams, die dafür verantwortlich sind." diese Code-Teile. " Normalerweise endet der begeisterte "Innovator" dort.

    Und wie viel kostet es Ihrer Meinung nach, einen neuen Dienst in einer neuen Programmiersprache zu schreiben? In Polyrepositorien - überhaupt nicht. Sie erstellen ein neues Repository und schreiben, und Sie nehmen auch das am besten geeignete Build-System. Und jetzt dasselbe in Monorepositories?

    Ich verstehe sehr gut, dass „Standardisierung, Wiederverwendung, gemeinsame Nutzung von Code“ das Projekt jedoch entwickelt werden sollte. Meiner subjektiven Meinung nach verhindert ein Mono-Repository dies eher.

    10) Open Source


    Kürzlich wurde ich gefragt: „ Gibt es Open-Source-Tools für Monorepositories? “ Ich antwortete: „Das Problem ist, dass die Tools für Monorepositories seltsamerweise im Monorepository selbst entwickelt werden. Daher ist es schwierig, sie in Open Source zu stellen! “

    Betrachten Sie das Projekt auf Github mit dem Bazel-Plugin für Intellij IDEA . Google entwickelt es in seinem internen Repository und "spritzt" Teile davon in Github mit dem Verlust der Commit-Historie, ohne die Möglichkeit, eine Pull-Anfrage zu senden, und so weiter. Ich betrachte diese Open Source nicht (hier ist ein Beispiel meiner kleinen PR.)die statt der Zusammenführung geschlossen wurde und dann in der nächsten Version geändert wurde). Übrigens wird diese Tatsache in dem ursprünglichen Artikel erwähnt, dass Mono-Suppositorien das Einfügen in Open Source behindern und eine Community rund um das Projekt bilden. Ich denke, viele haben diesem Argument keine große Bedeutung beigemessen.

    Alternativen


    Nun, wenn wir darüber reden, was wir tun müssen, um all diese Probleme zu vermeiden? Der Ratschlag ist genau eine - streben Sie an, ein möglichst kleines Repository zu haben.
    Und was ist mit dem Mono-Repository hier? Und auch wenn dieser Ansatz es Ihnen unmöglich macht, kleine, leichte und unabhängige Repositories zu haben.

    Was sind die Nachteile des Polyrepository-Ansatzes? Ich sehe genau 1: die Unfähigkeit zu ermitteln, wer Ihr API-Konsument ist. Insbesondere betrifft es den Ansatz in micro share "nichts nichts"in dem der Code nicht zwischen Microservices durchgebrannt wird. (Denken Sie, dass dieser Ansatz von jedermann in Mono-Repositorys verwendet wird?) Dieses Problem muss leider entweder durch organisatorische Mittel gelöst werden oder durch den Einsatz von Code-Browsing-Tools, die unabhängige Repositorys unterstützen (z. B. https://sourcegraph.com) / ).

    Wie wäre es mit Kommentaren wie „Wir haben Poly-Repositories ausprobiert, aber dann mussten wir ständig Features in mehreren Repositories gleichzeitig implementieren, was anstrengend war und wir alles in einem Kessel zusammenführten“ ? Die Antwort darauf ist sehr einfach: "Verwechseln Sie die Probleme des Ansatzes nicht mit der falschen Zerlegung".. Niemand argumentiert, dass genau ein Microservice im Repository sein sollte und das war's. In meiner Zeit der Verwendung von Polypositories haben wir eine Familie eng verwandter Microservices perfekt zu einem Repository zusammengefasst. Da es jedoch mehr als 100 Services gab, gab es mehr als 20 solcher Repositorys. Das Wichtigste bei der Zerlegung ist die Art und Weise, in der diese Services bereitgestellt werden.

    Aber was ist mit dem Argument über die Version? Monorepositories ermöglichen es Ihnen schließlich, keine Versionen zu haben und alles aus einem einzigen Commit bereitzustellen! Erstens ist die Versionierung das einfachste aller hier angesprochenen Probleme. Selbst in so einem alten Ding wie maven gibt es ein Maven-Version-Plugin, mit dem Sie eine Version mit nur einem Klick freigeben können. Und zweitens, und vor allem, verfügt Ihr Unternehmen über mobile Apps? Wenn ja, dann haben Sie bereits Versionen, und Sie werden davon nichts bekommen!

    Nun, es gibt immer noch das wichtigste Argument für die Unterstützung von Mono-Repositorys - Sie können damit die gesamte Codebasis in ein Commit umwandeln! Eigentlich nein. Wie im Originalartikel erwähnt, aufgrund der Einschränkungen, die die Wärme auferlegt. Sie sollten immer daran denken, dass Sie lange Zeit (die Dauer hängt davon ab, wie Ihr Prozess organisiert ist) zwei Versionen desselben Dienstes parallel haben. Bei meinem letzten Projekt befand sich unser System beispielsweise mit jeder Verzögerung mehrere Stunden in diesem Zustand. Dies führt dazu, dass es unmöglich ist, globale Refactorings, die die Interaktionsschnittstellen betreffen, in einem Commit auszuführen, selbst in einem Mono-Repository.

    Anstatt zu folgern:


    Also, diese ausgezeichneten und wenigen Kollegen, die in Google, Facebook usw. arbeiten. und sie werden hierher kommen, um ihre Monopositorien zu verteidigen, ich würde gerne sagen: „Mach dir keine Sorgen, du machst alles richtig, genießt dein Gespann, das Hunderttausende oder Millionen von Mannstunden verbracht hat. Sie sind bereits ausgegeben worden. Wenn Sie es also nicht verwenden, wird es niemand tun. “

    Und zu allem anderen: "Sie sind kein Google, verwenden Sie keine Monorepositories!"

    PS Wie der hochgeachtete Bobuk im Radio-T- Podcast in der Erörterung des Originalartikels feststellte : „Es gibt ~ 20 Unternehmen auf der Welt, die Mono-Repositorys erstellen können. Der Rest sollte es nicht einmal versuchen . “

    Jetzt auch beliebt: