Mono-Repositories: bitte nicht

Vom Übersetzer: Hallo Habr! Ja, dies ist ein weiterer Artikel über die Vor- und Nachteile von Monorepositories. Ich wollte meinen Artikel darüber schreiben, wie wir das Mono-Repository verwenden, wie wir von Maven zu Bazel gewechselt sind und was daraus wurde. Aber während ich darüber nachdachte, kam ein ausgezeichneter Artikel des Entwicklers von Lyft heraus, den ich für Sie übersetzen wollte. Ich verspreche, meine Ergänzungen zum Artikel sowie die Erfahrung mit Bazel als Fortsetzung zu veröffentlichen.
Wir befinden uns im neuen Jahr 2019 und ich bin bereit für eine weitere Diskussion über die Vorteile (oder das Fehlen davon) beim Speichern des gesamten Quellcodes der Organisation im „Monorepository“. Für diejenigen unter Ihnen, die mit diesem Ansatz nicht vertraut sind, besteht die Idee darin, den gesamten Quellcode in einem einzigen Repository des Versionskontrollsystems zu speichern. Eine Alternative besteht natürlich darin, den Quellcode in mehreren unabhängigen Repositorys zu speichern und diese normalerweise entlang der Grenze zwischen Diensten / Anwendungen / Bibliotheken aufzuteilen.

In diesem Beitrag werde ich diesen Ansatz "Polyrepository" nennen.

Einige der IT-Giganten verwenden Mono-Repositories, darunter Google, Facebook, Twitter und andere. Wenn solche seriösen Unternehmen Mono-Repositories verwenden, sollten die Vorteile dieses Ansatzes natürlich enorm sein, und wir sollten alle das Gleiche tun, oder? Nein! Wie der Titel des Artikels sagt: "Bitte benutzen Sie nicht das Mono-Repository!" Warum? Denn im großen Maßstab löst das Monorepository dieselben Probleme, die auch das Polyrepository löst, provoziert Sie jedoch gleichzeitig zur starken Kohärenz Ihres Codes und erfordert unglaubliche Anstrengungen, um die Skalierbarkeit Ihres Versionskontrollsystems zu verbessern .

Mittel- und langfristig bietet das Mono-Repository keine organisatorischen Vorteile, während die besten Ingenieure des Unternehmens ein posttraumatisches Syndrom haben (das sich in Form von Sabbern und inkohärentem Murmeln über die Git-Leistung manifestiert).


Kurzer Exkurs: Was meine ich mit "im großen Stil"? Es gibt keine einzige Antwort auf diese Frage, sondern weil Ich bin sicher, Sie fragen mich danach. Nehmen wir an, es gibt ungefähr 100 Entwickler, die Vollzeitcode schreiben.

Theoretische Vorteile eines Monorepositorys und warum sie nicht ohne Werkzeuge erreicht werden können, die für Polyrezitories verwendet werden (oder falsch)


Theoretischer Vorteil 1: Einfachere Zusammenarbeit und Code-Sharing


Befürworter von Mono-Repositorys behaupten, dass, wenn sich der gesamte Code im selben Repository befindet, die Wahrscheinlichkeit einer Duplizierung des Codes geringer ist und es wahrscheinlicher ist, dass verschiedene Teams an einer gemeinsamen Infrastruktur zusammenarbeiten.

Hier ist die bittere Wahrheit über selbst mittelgroße Mono-Repositorys (und dies wird in diesem Abschnitt ständig zu hören sein): Es wird für einen Entwickler schnell unpraktisch, den gesamten Repository-Code auf seiner Workstation zu behalten oder die gesamte Codebasis mit Dienstprogrammen wie grep zu durchsuchen. Daher sollte jedes Mono-Repository, das skalieren möchte, zwei Dinge bereitstellen:

1) so etwas wie ein virtuelles Dateisystem, mit dem Sie nur einen Teil des Codes lokal speichern können. Dies kann mit einem proprietären Dateisystem wie Perforce erreicht werden , das diesen Modus nativ unterstützt, indem das interne G3- Tool von Google oder das GVFS von Microsoft verwendet werden.

2) ausgefeilte Tools als Service (als Service) zum Indizieren / Suchen / Anzeigen von Quellcode. Weil Keiner der Entwickler wird den gesamten Quellcode in einem durchsuchbaren Zustand auf seiner Workstation speichern. Es wird wichtig, eine solche Suche in der gesamten Codebasis durchführen zu können.

Gibt es aufgrund der Tatsache, dass der Entwickler zu einem bestimmten Zeitpunkt nur auf einen kleinen Teil des Quellcodes zugreifen kann, zumindest einen Unterschied zwischen dem Herunterladen eines Teils des Mono-Repositorys oder dem Herunterladen mehrerer unabhängiger Repositorys? Es gibt keinen Unterschied .

Im Zusammenhang mit der Indizierung / Suche / Suche und ähnlichem Code kann ein solches hypothetisches Tool leicht mehrere Repositorys durchsuchen und das Ergebnis kombinieren. Genau so funktioniert die Suche auf GitHub sowie mit komplexeren Such- und Indizierungswerkzeugen wie Sourcegraph .

Unter dem Gesichtspunkt der kollaborativen Arbeit an Code in großem Maßstab sind Entwickler daher auf jeden Fall gezwungen, nur mit einem Teil der Codebasis zu arbeiten und übergeordnete Tools zu verwenden. Es spielt keine Rolle, ob der Code in einem Mono-Repository oder in mehreren unabhängigen Repositorys gespeichert ist, das Problem auf dieselbe Weise gelöst wird und die Effektivität der Zusammenarbeit am Code nur von der Engineering-Kultur und nicht von der Art und Weise abhängt, wie die Quellcodes gespeichert werden .

Theoretischer Vorteil 2: eine Assembly / kein Abhängigkeitsmanagement


Das nächste Argument, das normalerweise von Befürwortern von Mono-Repositorys angeführt wird, ist, dass das Speichern des gesamten Codes in einem einzigen Mono-Repository Ihnen die Notwendigkeit nimmt, Abhängigkeiten zu verwalten Der gesamte Code wird gleichzeitig erfasst. Das ist eine Lüge! Im großen Maßstab gibt es einfach keine Möglichkeit, den gesamten Quellcode neu zu erstellen und alle automatisierten Tests jedes Mal auszuführen, wenn jemand Änderungen am Versionskontrollsystem festlegt (oder, was noch wichtiger ist, häufiger auf dem CI-Server, wenn eine neue Verzweigungs- oder Pull-Anforderung erstellt wird). Um dieses Problem zu lösen, verwenden alle großen Mono-Repositorys ihr ausgeklügeltes Build-System (z. B. Bazel / Blaze von Google oder Buck von Facebook), mit dem Änderungen und ihre abhängigen Blöcke überwacht und ein Abhängigkeitsdiagramm des Quellcodes erstellt werden können. Mit diesem Diagramm können Sie das effiziente Caching von Baugruppenergebnissen und -tests organisieren, sodass nur Änderungen und deren Abhängigkeiten erneut zusammengesetzt und getestet werden müssen.

Darüber hinaus seit Der gesammelte Code sollte schließlich bereitgestellt werden. Wie Sie wissen, kann nicht die gesamte Software gleichzeitig bereitgestellt werden. Es ist wichtig, dass alle Assembly-Artefakte kontrolliert werden, damit die Artefakte bei Bedarf erneut erstellt werden. Im Wesentlichen bedeutet dies, dass selbst in der Welt der Mono-Repositorys mehrere Versionen des Codes gleichzeitig existieren können und sorgfältig überwacht und koordiniert werden müssen.

Befürworter von Mono-Repositories werden auch argumentieren, dass dies selbst unter Berücksichtigung der Notwendigkeit, Assemblys / Abhängigkeiten zu verfolgen, immer noch einen unbestreitbaren Vorteil bietet Ein einziges Commit beschreibt den gesamten Zustand der ganzen Welt. Ich würde sagen, dass dieser Vorteil ziemlich kontrovers ist, da das Abhängigkeitsdiagramm bereits vorhanden ist, und es scheint eine ziemlich triviale Aufgabe zu sein, die Festschreibungskennung für jedes unabhängige Repository als Teil dieses Diagramms einzuschließen, und tatsächlich kann Bazel problemlos mit mehreren unabhängigen Repositorys sowie mit einem arbeiten Mono-Repository, das die zugrunde liegende Ebene vom Entwickler abstrahiert. Darüber hinaus ist es einfach, solche automatisierten Refactoring-Tools zu implementieren, mit denen die Versionen abhängiger Bibliotheken in mehreren unabhängigen Repositorys gleichzeitig automatisch aktualisiert werden, wodurch der Unterschied zwischen dem Mono-Repository und dem Polyrepository in diesem Teil ausgeglichen wird (dazu später mehr).

Das Endergebnis ist, dass die Realitäten der Montage / Bereitstellung in großem Maßstab für Mono- und Poly-Repositorys größtenteils gleich sind. Es gibt keinen Unterschied für Tools, es sollte nicht für Entwickler sein, die Code schreiben .

Theoretischer Vorteil 3: Code-Refactoring ist ein einfaches atomares Commit


Die letzte Tugend, die Befürworter von Monorepositories erwähnen, ist die Tatsache, dass ein Repository das Refactoring von Code aufgrund der einfachen Suche vereinfacht und die Idee, dass ein Commit das gesamte Repository umfassen kann. Dies gilt aus mehreren Gründen nicht:

1) Wie oben beschrieben, kann der Entwickler in großem Umfang nicht die gesamte Codebasis auf seinem lokalen Computer bearbeiten oder durchsuchen. Daher ist die Idee, dass jeder problemlos sein gesamtes Repository für sich selbst klonen und nur grep / replace ausführen kann, nicht so einfach in die Praxis umzusetzen.

2) Selbst wenn wir davon ausgehen, dass ein Entwickler mithilfe eines komplexen virtuellen Dateisystems die gesamte Codebasis klonen und bearbeiten kann, wie oft wird dies dann passieren? Ich spreche nicht von der Behebung eines Fehlers bei der Implementierung einer gemeinsam genutzten Bibliothek, da diese Situation bei einem einzelnen Repository und bei einem Multi-Repository (unter der Annahme eines ähnlichen Build- / Bereitstellungssystems, wie oben beschrieben) gleichermaßen behandelt wird. Ich spreche über das Ändern der Bibliotheks-API, worauf viele Kompilierungsfehler an den Stellen folgen, an denen diese Bibliothek aufgerufen wird. In einer sehr großen Codebasis ist es fast unmöglich, eine Änderung an der Basis-API vorzunehmen, die von allen beteiligten Teams in der Vorschau angezeigt wird, bevor die Zusammenführungskonflikte Sie zwingen, den Prozess erneut zu starten . Der Entwickler hat zwei echte Möglichkeiten: Er kann aufgeben und eine Problemumgehung für das Problem mit der API finden (in der Praxis geschieht dies häufiger als wir alle möchten), oder er kann die vorhandene API ablenken, eine neue API schreiben und sich dann auf die lange und Aktualisieren aller Aufrufe der alten API in der gesamten Codebasis. In jedem Fall ist dies absolut der gleiche Vorgang wie beim Polyrepository .

3) In einer serviceorientierten Welt bestehen Anwendungen aus vielen lose gekoppelten Komponenten, die unter Verwendung einer gut beschriebenen API miteinander interagieren. Große Unternehmen werden früher oder später auf IDL (Interface Description Language) wie Thrift oder Protobuf umsteigen, mit denen Sie typsichere APIs erstellen und abwärtskompatible Änderungen vornehmen können. Wie im vorherigen Abschnitt zur Assembly / Bereitstellung beschrieben, kann der Code nicht gleichzeitig bereitgestellt werden . Es kann über einen bestimmten Zeitraum bereitgestellt werden: Stunden, Tage oder sogar Monate. Daher müssen Entwickler über die Abwärtskompatibilität ihrer Änderungen nachdenken. Dies ist die Realität der modernen Softwareentwicklung, die viele gerne ignorieren würden, aber nicht können. Wenn es um Dienste geht (im Gegensatz zu API-Bibliotheken), sollten Entwickler daher einen der beiden oben beschriebenen Ansätze verwenden (API nicht ändern oder den Verfallszyklus durchlaufen). Dies ist sowohl für das Monorepository als auch für das Polyrepository absolut gleich .

In Bezug auf das Refactoring großer Codebasen entwickeln viele große Unternehmen ihre eigenen automatisierten Refactoring-Tools wie Fastmod , die kürzlich von Facebook veröffentlicht wurden. Wie immer kann dieses Tool problemlos mit einem oder mehreren unabhängigen Repositorys arbeiten. Lyft hat ein Tool namens "Refactorator", das genau das tut. Es funktioniert wie Fastmod, automatisiert jedoch Änderungen in mehreren unserer Repositorys, einschließlich der Erstellung von Pull-Anforderungen, der Verfolgung des Status von Überprüfungen usw.

Einzigartige Nachteile von Monorepositories


Im vorherigen Abschnitt habe ich alle theoretischen Vorteile des Mono-Repositorys aufgelistet und festgestellt, dass unglaublich komplexe Tools erstellt werden müssen, die sich nicht von denen für Poly-Repositorys unterscheiden, um sie nutzen zu können. In diesem Abschnitt werde ich zwei einzigartige Nachteile von Mono-Repositories erwähnen.

Nachteil 1: Starke Konnektivität und Open Source-Software


Organisatorisch provoziert ein Monorepository die Erstellung eng gekoppelter und fragiler Software. Es gibt Entwicklern das Gefühl, dass sie Fehler in Abstraktionen leicht korrigieren können, obwohl dies in der Realität aufgrund des instabilen Montage- / Bereitstellungsprozesses und menschlicher / organisatorischer / kultureller Faktoren, die auftreten, wenn versucht wird, Änderungen sofort in der gesamten Codebasis vorzunehmen, nicht möglich ist.

Die Codestruktur in Polyrepositorys stellt klare und transparente Grenzen zwischen Teams / Projekten / Abstraktionen / Codebesitzern dar und zwingt den Entwickler, die Interaktionsschnittstelle sorgfältig zu prüfen. Dies ist ein subtiler, aber sehr wichtiger Vorteil: Entwickler denken breiter und längerfristig. Darüber hinaus bedeutet die Verwendung von Multi-Repositorys nicht, dass Entwickler die Grenzen des Repositorys nicht überschreiten können. Ob dies geschieht oder nicht, hängt nur von der Entwicklungskultur ab und nicht davon, ob ein Monorepository oder ein Polyrepository verwendet wird.

Eine starke Bindung hat auch schwerwiegende Konsequenzen für das Öffnen des Quellcodes. Wenn ein Unternehmen Open Source-Software erstellen oder verwenden möchte, ist die Verwendung von Multi-Repositorys ein Muss. Die Verzerrungen, die auftreten, wenn ein Unternehmen versucht, sein Projekt in Open Source aus seinem Mono-Repository darzustellen (Import / Export von Quellcodes, öffentlicher / privater Bug-Tracker, zusätzliche Ebenen, um den Unterschied in Standardbibliotheken zu abstrahieren usw.), führen nicht zu einer produktiven Zusammenarbeit und Aufbau einer Community sowie erhebliche Gemeinkosten.

Fehler 2: Skalierbarkeit des Versionskontrollsystems



Die Skalierung eines Versionskontrollsystems für Hunderte von Entwicklern, Hunderte Millionen Codezeilen und einen riesigen Strom von Commits ist eine monumentale Aufgabe. Das vor 5 Jahren erstellte Twitter-Mono-Repository (basierend auf git) war eines der wertlosesten Projekte, die ich in meiner Karriere gesehen habe. Das Ausführen eines einfachen Befehls wie git status dauerte Minuten . Wenn die lokale Kopie des Repositorys zu alt war, konnte das Update Stunden dauern (zu diesem Zeitpunkt war es sogar üblich, Festplatten mit einer Kopie des Repositorys mit der neuesten Version des Codes an Remote-Mitarbeiter zu senden). Ich erinnere mich daran, nicht um Twitter-Entwickler zu verspotten, sondern um zu veranschaulichen, wie komplex dieses Problem ist. Ich kann sagen, dass die Leistung des Twitter-Mono-Repositorys 5 Jahre später immer noch weit von der Leistung entfernt ist, die die Entwickler des Tilling-Teams gerne sehen würden, und das nicht, weil sie sich sehr bemüht haben.

Natürlich hat in den letzten 5 Jahren in diesem Bereich eine gewisse Entwicklung stattgefunden. Microsofts Git VFS , das zur Entwicklung von Windows verwendet wird, hat zur Entstehung eines realen virtuellen Dateisystems für Git geführt, das ich oben als Voraussetzung für die Skalierung eines Versionskontrollsystems beschrieben habe (und mit dem Kauf von Microsoft Github scheint diese Skalierungsstufe ihren Höhepunkt zu finden Anwendung in den Funktionen, die GiHub seinen Firmenkunden bietet). Und natürlich investieren Google und Facebook weiterhin enorme Ressourcen in ihre internen Systeme, damit sie weiterhin funktionieren, obwohl fast nichts davon öffentlich verfügbar ist.

Warum müssen Sie diese Probleme im Allgemeinen mit der Skalierung des Versionskontrollsystems lösen, wenn das Toolkit, wie im vorherigen Abschnitt beschrieben, genau das gleiche sein muss wie für das Multirepository? Dafür gibt es keinen vernünftigen Grund.

Fazit


Wie so oft in der Softwareentwicklung betrachten wir die erfolgreichsten Softwareunternehmen als Beispiel und versuchen, ihre Best Practices auszuleihen, ohne zu verstehen, was genau diese Unternehmen zum Erfolg geführt hat. Monorepositories sind meiner Meinung nach ein typisches Beispiel für einen solchen Fall. Google, Facebook und Twitter haben eine große Menge an Ressourcen in ihre Codespeichersysteme investiert, um eine Lösung zu finden, die im Wesentlichen der für ein Multi-Repository erforderlichen entspricht, jedoch eine starke Verknüpfung hervorruft und eine enorme Investition in die Skalierung der Versionskontrolle erfordert .

In der Tat, in großem Maßstab, wie ein Unternehmen mit der Zusammenarbeit mit Code, Zusammenarbeit, starker Bindung usw. zusammenarbeitet. hängt direkt von der Ingenieurkultur und der Führung ab und hat nichts damit zu tun, ob ein Monorepository oder ein Polypository verwendet wird . Beide Lösungen sehen für den Entwickler gleich aus. Warum also ein Monorepository verwenden? Bitte nicht!

Source: https://habr.com/ru/post/de435306/


All Articles