- Die Einführung eines Monorepos bringt Vorteile wie organisatorische Konsistenz, gemeinsame Code-Nutzung und eine stärkere gemeinsame Tooling-Umgebung, doch wer einfach die Beispiele der Big-Tech-Unternehmen kopiert, wird mit neuen Problemen und Herausforderungen konfrontiert
- Für ein erfolgreiches Monorepo muss das Prinzip gelten, alle wesentlichen Aufgaben nicht O(repo), sondern O(change) zu machen; dafür braucht es in Build, Tests und CI/CD jeweils passende Werkzeuge und Strategien
- Bei der Versionsverwaltung startet man meist mit Git, sollte mit wachsender Größe aber schrittweise Erweiterungen wie sparse checkout und virtuelle Dateisysteme in Betracht ziehen
- Das Build-System sollte nach Möglichkeit bei einer einzigen Sprache bleiben, möglichst lange die nativen Build-Tools der jeweiligen Sprache nutzen und erst bei echtem Bedarf schrittweise auf Bazel/Buck2 oder Ähnliches umsteigen
- Tests und CI/CD sollten schnell nur den von Änderungen betroffenen Bereich erkennen, um zu bauen, zu testen und auszurollen; in großen Monorepos sind zudem Strategien zur Sicherung der Zuverlässigkeit wie automatische Test-Wiederholungen und die Isolierung flaky Tests unverzichtbar
Einleitung: Der Beginn der Reise zum Monorepo
- Wer als Engineer in einem neuen Developer-Productivity-Team arbeitet, beschäftigt sich nach der Entscheidung für ein Monorepo schnell mit der Frage, welche Vorbereitungen und Anstrengungen dafür nötig sind
- Best Practices großer Unternehmen wie Google, Meta oder Uber wirken beeindruckend, doch in der Realität ist es unmöglich, Ergebnisse auf exakt demselben Niveau zu erzielen
- Jede Organisation muss die Entscheidung für ein Monorepo anhand ihrer eigenen Gründe und Anforderungen treffen und kann dabei Vorteile wie Konsistenz, organisatorische Integration und gemeinsames Tooling anstreben
Die Notwendigkeit eines Monorepos klar definieren
- Die Beispiele großer Unternehmen zeigen nur das Endergebnis und eignen sich kaum als Orientierung für die Anfangsphase
- In der Praxis entstehen neue Probleme, und es treten andere Arten von Herausforderungen auf als bei der Verwaltung vieler getrennter Repositories
- Ziel der Einführung eines Monorepos ist es, Konsistenz zu wahren, Tooling über die gesamte Organisation hinweg zu vereinheitlichen sowie Engineering-Standards und Konventionen durchzusetzen
- Jedes Team sollte Ziele klar definieren, die zu seiner eigenen Kultur und Ausrichtung passen, um wirksame Ergebnisse zu erzielen
Goldene Regel: Das O(change)-Prinzip
- Alle Repository-bezogenen Werkzeuge sollten für hohe Geschwindigkeit nicht eine Komplexität von O(repo), sondern von O(change) haben
- Je größer ein Monorepo in der Praxis wird, desto deutlicher treten die Ineffizienzen bestehender Tools hervor; deshalb ist ein strukturelles Design zur Überwindung von Performance-Problemen unverzichtbar
- Auch die Innovationen, die in Tech-Blogs großer Unternehmen beschrieben werden, konzentrieren sich meist darauf, die durch O(repo) verursachten Ineffizienzen zu überwinden
Versionsverwaltung
- Die meisten Software-Organisationen verwenden standardmäßig Git, doch Git stößt in einem zentralisierten Monorepo-Umfeld bei großer Skalierung an Performance-Grenzen
- Realistisch gesehen können die meisten Organisationen mit Git+GitHub noch ziemlich lange gut arbeiten
- Mit zunehmendem Wachstum werden Strukturen wie sparse checkout (teilweiser Checkout/Klon) und virtuelle Dateisysteme (Dateien werden bei Bedarf dynamisch vom Server geladen) erforderlich
- Große Unternehmen passen Git dafür per Fork an oder entwickeln eigene Systeme (Microsoft: eigener Git-Fork, Meta: Mercurial-Fork, Google: Piper)
- Auch Source-Control-Systeme der nächsten Generation wie Jujutsu sind eine Überlegung wert
- Solange die Größe noch überschaubar ist, lässt sich Git problemlos nutzen; im Wachstum sollte man jedoch eine Skalierungsstrategie im Blick behalten
- Wenn der Quellcode aus IDL (Interface Definition Language) generierten Code enthält, kann die Repository-Größe in der Praxis zudem exponentiell anwachsen
Build-System
- Bazel, Buck2 und ähnliche Werkzeuge sind typische Monorepo-Build-Tools, die viele Sprachen und komplexe Build-Graphen unterstützen
- Sie sind leistungsstark, bringen aber auch hohe Komplexität und erheblichen Betriebsaufwand mit sich
- Wenn man den Build auf eine einzige Sprache beschränkt, wird vieles deutlich einfacher; auch die sprachspezifischen Build-Systeme (z. B. Maven, Gradle, Cargo, Go) sind hoch skalierbar
- Die Kernaufgabe eines Build-Systems besteht darin, „das angegebene Build-Target effizient zu bauen (effiziente Artefakterzeugung)“ und „schnell zu ermitteln, welche Targets von geänderten Dateien betroffen sind“
- Dafür braucht es das Konzept eines target determinator (Werkzeug zur Target-Bestimmung); in Ökosystemen wie Rust, Go und Bazel gibt es bereits verschiedene Lösungen
- Remote Execution und Caching sind praktisch erst in sehr großen Maßstäben wirklich nötig; für gewöhnliche Unternehmen ist target determination deutlich praxisnäher
Tests
- Da es ineffizient ist, jedes Mal die gesamte Test-Suite auszuführen, braucht es ein System, das nur den von Änderungen betroffenen Bereich testet
- Flaky Tests können in großen Testsystemen zu einem noch schwerwiegenderen Problem werden
- Ein Testsystem sollte automatische Wiederholungsversuche, automatische Bestimmung des Test-Impact-Bereichs und die Isolierung flaky Tests unterstützen
- Einige Sprachen bzw. Frameworks (z. B. Rust mit nextest oder Java mit JUnit) bieten solche erweiterten Funktionen standardmäßig oder per Erweiterung an
- Die Testarchitektur eines Monorepos ist nur dann wirksam, wenn sie eng mit dem Build-System integriert ist
Kontinuierliche Integration (CI)
- Ein CI-System sollte abhängig von den Änderungen die erforderlichen Build-Artefakte und Validierungen automatisch ausführen
- Leistung und Effizienz des target determinator sind Schlüsselelemente der CI-Pipeline
- Moderne CI setzt verschiedene Strategien wie eine „Merge Queue“ ein und muss dabei das Gleichgewicht zwischen Code-Qualität und Merge-Geschwindigkeit optimieren
- Etwa die Frage, ob bei jedem einzelnen Commit/PR alle Prüfungen laufen sollen, nur ein Teil davon oder mehrere PRs gebündelt verarbeitet werden
- Die Trade-offs zwischen Throughput, Correctness und Tail Latency müssen organisationsspezifisch definiert und gestaltet werden
- Die Verwaltung von Merges in großen Monorepos und die Steigerung der CI-Effizienz bleiben bis heute Herausforderungen ohne perfekte Lösung
- Rust (bors), Chromium und Uber verfolgen jeweils unterschiedliche Merge- und Validierungsstrategien
Kontinuierliche Auslieferung (CD)
- Die Illusion, dass alle Änderungen in einem Monorepo atomar ausgerollt würden, entspricht nicht der Realität
- Zwar lassen sich in einem einzigen PR Interfaces und Implementierungen vieler Services sowie deren Clients gleichzeitig ändern, doch das tatsächliche Deployment erfolgt letztlich asynchron, sodass beim Ausrollen Probleme auftreten können
- Änderungen, die Verträge zwischen Services brechen, können beim Deployment schwerwiegende Ausfälle verursachen
- Eine wirksame CD-Strategie für Monorepos braucht daher die Taktung des Deployment-Systems, die Validierung von Service-Verträgen sowie die Fähigkeit, Probleme schnell zu erkennen und darauf zu reagieren
Fazit
- Ein Monorepo ist ein mächtiges Werkzeug zur Stärkung organisatorischer Konsistenz und der Engineering-Kultur, erfordert jedoch kontinuierliche Investitionen in Engineering und Tooling
- Entscheidend ist, in jeder Phase Automatisierung, Werkzeuge und Kultur nach dem O(change)-Prinzip aufzubauen
- Mit dem Wachstum müssen sich auch die Werkzeuge kontinuierlich weiterentwickeln; wichtig ist eine systematische Steuerung, die die Ziele und die Kultur der Organisation widerspiegelt
- Mit ausreichender Entschlossenheit, Hingabe und kontinuierlicher Investition schafft ein Monorepo letztlich den entsprechenden Mehrwert
4 Kommentare
Das ist wirklich ein gehaltvoller Artikel. Man braucht nicht nur starke Tools, sondern muss auch bereit sein, bei Bedarf die nötigen Werkzeuge selbst zu bauen. Wenn dann alles gut läuft, sind die Vorteile entsprechend groß.
Als ich im Masterstudium war, kam mein Betreuer wohl von einem Essen mit einem ehemaligen Google-Ingenieur zurück, bei dem sie über Monorepos gesprochen hatten, und schlug vor, dass auch wir künftig alles in einem Monorepo verwalten sollten. Ich hatte damals alle Hände voll zu tun, ihn davon abzubringen...
Monorepos haben zwar viele Vorteile, aber in unserem Labor mussten wir aufgrund unserer Arbeitsweise Ergebnisse häufig mit externen Personen teilen. Hätten wir diese Ergebnisse in einem Monorepo verwaltet, hätten wir uns gerade dabei vermutlich besonders schwergetan. Mit einem Multi-Repo kann man den Veröffentlichungsgrad einfach pro Ergebnis steuern.
Ich glaube, die meisten Fälle, in denen Monorepos Schmerzen verursachen, entstehen dann, wenn ein Projekt ohnehin schon viel zu stark zerkleinert wurde. Man nimmt ein Projekt, das ursprünglich ein oder zwei Projekte hätte sein können, zerlegt es in etwa zehn Teile und versucht dann, diese per Monorepo zusammenzuführen und zu verwalten — dadurch braucht man zusätzlich noch Monorepo-Management-Tools und die Komplexität steigt weiter. Besser ist es, das Projekt selbst einfach auf ein oder zwei Projekte zu konsolidieren; und selbst wenn es mehr als zwei Projekte sind, kann man es oft entspannter verwalten, wenn man keine separaten Management-Tools nutzt, sondern einfach nur die Verzeichnisse trennt und es als Konzept versteht, alles in ein Repository zu legen.
Hacker-News-Kommentare
Beim Lesen dieses Threads musste ich an die alten Geschichten über „complexity merchants“ denken und wollte diese Erfahrung teilen. Ich stimme der Meinung überhaupt nicht zu, dass der Wechsel zu einem Monorepo technische Opfer erfordert. Wenn man die Stärke hierarchischer Dateisysteme versteht, erkennt man den Wert eines Monorepos. CI/CD in einem einzigen Monorepo zu organisieren ist viel klarer als verstreute Konfigurationen überall. Der Kern eines Monorepos ist, dass die gesamte Organisation atomare Commits machen kann. Bei der Koordination vieler Entwickler ist dieser Nutzen überwältigend. Einmal rebasen und ein großes Meeting reicht. Selbst wenn Teammitglieder sich nicht mögen und nicht zusammenarbeiten, ist ein Monorepo aus Managementsicht ein großes HR-Werkzeug.
Entwickler neigen in letzter Zeit übermäßig zu Trennung, Microservices, vielen kleinen Repositories und einer extremen Vermeidung von Monolithen. Das vergrößert die Komplexität und verwandelt organisatorische Strukturprobleme in zukünftige technische Probleme. Auch die internen Abhängigkeiten von Softwaresystemen werden nicht richtig erkannt. Es ist kaum zu glauben, wie viel Zeit in meinem früheren Job damit verschwendet wurde, Protocol-Buffer-Schemadateien zu aktualisieren. Zum Glück ist das in meiner jetzigen Firma nicht so.
Commits über mehrere Projekte hinweg zu verfolgen ist ein nettes Extra, macht aber in Bezug auf Abhängigkeitsverfolgung oder das Auslösen von Downstream-Tests in der Praxis keinen großen Unterschied. Das lässt sich mit Multi-Repo-Automatisierung ausreichend lösen. Monorepos helfen, sind aber nicht perfekt und haben hohe Kosten. Deployments oder Builds werden nicht atomar abgewickelt. Wenn ein Monorepo eine bestimmte Größe erreicht, reicht git nicht mehr aus und man braucht neue Tools, was ein sehr großer Aufwand ist. Ohne entsprechende Erfahrung sagt sich das leicht.
Die Vorteile von Monorepos sind eindeutig vorhanden, aber die Verwaltungskosten sind höher als bei einem Polyrepo. Ein Monorepo ist nicht in jeder Situation automatisch besser. Details dazu finden sich in diesem Artikel. Das Kosten-Nutzen-Verhältnis hängt vom Kontext ab.
Eine nützliche Faustregel beim Entwurf von Programmierumgebungen lautet: Je mehr Macht man einem Team gibt, desto mehr Probleme entstehen. Technisch gesehen sind atomare Commits keine größere Macht, sondern eher weniger, aber sie ermöglichen Arbeit mit schlechten Interfaces und schaffen dadurch gerade Probleme.
Die Annahme, dass Änderungen mit einem Monorepo atomarer seien, ist laut dieser Meinung eine Falle. [Zitat aus dem Original: Die größte Illusion des Monorepos ist, dass atomare Commits über die gesamte Codebasis möglich seien. In Wirklichkeit gibt es unterschiedliche Deployment-Artefakte, und selbst wenn man Services und Clients gleichzeitig ändert, erfolgen Deployments asynchron. In mehreren Repositories muss man mit mehreren PRs arbeiten, wodurch ein Risikobewusstsein entsteht. Die CI im Monorepo dient vor allem der Verifikation von Serviceverträgen (CI jobs), und falls nötig muss der Grund für Änderungen angegeben werden.]
Es gibt zwei Arten von Monorepos in Big Tech. Erstens das im Artikel beschriebene unternehmensweite einzelne „THE“-Monorepo, das ein Custom-VCS/CI braucht und von 200 Ingenieuren unterstützt wird. Google, Meta und Uber arbeiten so. Das Leid auf dem Weg dorthin übersteigt jede Vorstellung, und gewöhnlich wächst es schrittweise aus kleineren „teambezogenen“ Monorepos heraus. Jeder Stack, jede Sprache und jedes Team verwaltet zunächst mit Tools wie Bazel, Turborepo oder Poetry sein eigenes Monorepo, und mit der Zeit werden sie in ein größeres Monorepo zusammengeführt. Doch beide Varianten kosten Entwicklern und Unternehmen Millionen von Dollar und Millionen von Stunden Investition und werden letztlich durch die Unterstützung jener Entwickler aufrechterhalten, die diesen Prozess durchgestanden haben.
Als ich in einem Unternehmen mit großem Monorepo gearbeitet habe, habe ich Monorepos viel stärker bevorzugt. Ein einzelnes Monorepo hilft enorm dabei, das Ganze transparent zu verstehen, etwa den Service-Graphen oder die Struktur der Code-Aufrufe. Beim Polyrepo ist Wissen auf Teams verteilt, die Übernahme neuen Codes schwierig, und das Verständnis des Code-Archivs fühlt sich an wie die Erkundung eines Labyrinths. Polyrepos wirken wie alte Discord-/Slack-Nachrichten, die in Vergessenheit geraten. Wenn Monorepos teuer sind, dann verursachen Polyrepos auf andere Weise ebenfalls Kosten. Monorepos sind riesige pflanzenfressende Kontinentalwesen, Polyrepos sind viele verschiedene Arten, die in der Dunkelheit verschwinden.
In meiner aktuellen Firma ist das Backend auf etwa 11 git-Repositories verteilt, und für ein einziges Feature braucht man 4 bis 5 Merge Requests, was sehr mühsam ist. Wir prüfen daher die Einführung eines Monorepos, um mehrere Projekte zusammenzuführen. Falls sich die Repositories aber nicht zusammenlegen lassen, frage ich mich, welche Alternative es zu einem Monorepo gibt.
Ein einfaches und leistungsfähiges Monorepo-Orchestrierungssystem, das sprachunabhängig funktioniert, gibt es noch nicht. Bazel ist komplex und schwer zu lernen, aber die Dokumentation hat sich zuletzt stark verbessert. Es gibt auch andere Optionen wie Buck, NX oder Pants, aber jede hat ihre Eigenheiten, und besonders die Web-Unterstützung ist eingeschränkt. Die meisten CI-Systeme unterstützen diese Tools nicht sauber, wodurch die Konfiguration mühsam wird. Zur Referenz: Rush von Microsoft bietet die beste Erfahrung, besonders für Frontend-/NodeJS-Monorepos; dafür ist die offizielle Rush-Seite empfehlenswert.
Die Realität ist, dass die meisten Monorepos nicht bis zur Größenordnung von Google, Uber oder Meta anwachsen. Die Zahl der Services variiert je nach Unternehmen, und selbst bei etwa 100 Services gibt es keine VCS-Skalierungsprobleme, und auch LSP-Tags laufen problemlos auf einem Laptop. Selbst wenn man in der CI alle Tests stumpf ausführt, funktioniert das meist noch gut. Fazit: Nicht jedes Unternehmen muss Google-Größe erreichen.
Unsere Firma baut derzeit Monorepos pro Sprach-Stack auf. Das ist ein ziemlich guter Kompromiss.
Ein Punkt, der in der Diskussion Monorepo vs. Multi-Repo oft nicht auftaucht, ist das Auftreten eines „umgekehrten Conway-Gesetzes“. Die Repository-Struktur beeinflusst die Organisationsstruktur und die Art, wie Probleme gelöst werden. Monorepos führen zu heroischer Arbeit bei gemeinsamen Infrastrukturteams, und sobald gemeinsame Bereiche angefasst werden, steigt das Potenzial für Brüche, sodass selbst die Entwicklung eines einzelnen Features schwieriger wird. In Multi-Repo-Setups braucht man mehrere PRs zwischen Teams, Abstimmung und interne Politik, dafür können aber mehr unterschiedliche Entwickler die Rollen verteilt übernehmen.
Auch im Monorepo lassen sich stark zentrale, tief vernetzte Änderungen in mehreren Schritten ausrollen. Dabei muss man ebenfalls mehrere PRs, Abstimmung und politische Themen bewältigen, aber gerade im Monorepo ist die Rollout-Situation klarer sichtbar.
In Polyrepos werden Änderungen in gemeinsamen Bereichen viel häufiger nicht in Downstream-Repositories übernommen, sodass einzelne Repositories auf unterschiedlichen Versionen festhängen und über Jahre nicht aktualisiert werden, was große Probleme verursacht.
Es wird gefragt, ob die Annahme stimmt, dass eine Organisation zunächst ihre Richtung über die Repository-Struktur wählt und die technischen Entscheidungen später folgen. In der Praxis geht meist eine grundlegendere Organisationsphilosophie voraus, also Fragmentierung vs. Teilen, statt einer konkreten Repo-Struktur. Selbst wenn sich die Richtung ändert, lässt sich die Art der Codeverwaltung anpassen. Auch in einem Multi-Repo können Ingenieure Zugriff auf fast den gesamten Code haben, und selbst in einem Monorepo sind starke Isolation sowie separate Regeln für CI oder Deployment-Management möglich.
In Monorepos werden Änderungen über Projekte hinweg viel häufiger überhaupt versucht, weil sie in Polyrepos so umständlich sind, dass man sie oft gar nicht erst angeht.
Aus Erfahrung in großen Tech-Unternehmen braucht das Management von Build-Systemen ein eigenes dediziertes Team. Große Monorepos basieren auf virtuellen Dateisystemen, die Quelldateien bei Bedarf herunterladen. Ein Punkt, der im Artikel nicht erwähnt wurde: Fast die gesamte Entwicklung läuft auf Dev-Servern im Rechenzentrum, mit Umgebungen aus 50 bis 100 Cores oder On-Demand-Containern, die laufend auf den neuesten Commit aktualisiert werden. Die IDE ist mit dem Dev-Server integriert, und Vorbereitung sowie Auto-Setup je nach Sprache oder Service werden mit chef/ansible automatisiert. Direkte Entwicklung großer Monorepos auf dem Laptop ist sehr selten, mit Ausnahmen wie Mobile- oder Mac-Apps.
Vermutlich jemand mit Erfahrung im selben Build-Team. In einer Monorepo-Entwicklungsumgebung ist Reproduzierbarkeit wichtiger als lokal oder remote. Mit einem imageten Remote-Dev-Server ist das einfacher und zuverlässiger.
Auch in kleinen Teams gibt es Erfahrung mit Entwicklungsumgebungen im Rechenzentrum. Bei heutigen Hardwarepreisen und -dichten ist es viel sinnvoller, ein eigenes Rack aufzubauen und dort On-Demand-Tools für dev/staging/test laufen zu lassen. Wenn man eine produktionsähnliche Entwicklungsumgebung gemeinsam nutzt, wirkt der Monorepo-Ansatz ganz anders. Kleine und mittlere Unternehmen haben aber nicht die Ressourcen, in Build-Systeme zu investieren, und ihnen entstehen diese Probleme großer Build-Systeme meist gar nicht erst nicht, denn selbst bei 10 bis 20 Personen und sehr komplexen Produkten erfolgt die Wartung womöglich nur nebenbei in Teilzeit.
Ein kleines Team bei Molnett (serverless cloud) berichtet von enormer Effizienz mit einem Bazel-basierten Monorepo (1,5 Vollzeitkräfte). Mit Tilt+Bazel+Kind kann die gesamte Plattform einschließlich Kubernetes-Operator auf dem Laptop gestartet werden, mit Unterstützung für Mac und Linux. Selbst ein auf Bottlerocket basierendes OS und Firecracker lassen sich lokal verifizieren. Dank einer Tool-Layer verwenden alle Entwickler dieselben Versionen von go/kubectl, ohne lokale Installation. Die Pflege kostet Mühe, war aber dank eines ehemaligen Google-SRE-Mitglieds möglich. Man möchte künftig nur noch auf diese Weise arbeiten. (Wichtige Sprachen sind Golang, Bash und Rust)
Bei einem kleinen Team von 1,5 Personen ist ein einzelnes Repository selbstverständlich. Die Erfahrung mit Bazel war zwar sehr schlecht, aber für große Projekte könnte es den Einsatz wert sein. Bei weniger als zwei Personen reicht eher schon Kind+Tilt. Die Tool-Layer wird in Go ohnehin schon teilweise durch
go.modgelöst. Beikubectlgeht Ähnliches. Man sollte auch über das Gehaltsniveau eines Ex-Googlers nachdenken. Hoffentlich bleibt der Wartungsaufwand von Bazel auch künftig lohnenswert.Unsere Firma deployt mit systemd-basierten Services und ansible playbooks, und mit tmuxinator werden Backend/DB/Suchmaschine/Frontend per dev mode mit einem einzigen Terminalbefehl automatisch gestartet. Einmal
tmuxinatorim Root-Verzeichnis, und die komplette Dev-Umgebung steht. Ein einzelnes Monorepo ist überwältigend viel bequemer als zuvor.Ähnliche Situation, und es wird geteilt, dass der Effekt der Bazel-Einführung maximal war. Dank der Tool-Layer lässt sich die Entwicklungsumgebung konsistent halten. Man muss allerdings direkt
bazel runverwenden und fragt sich, ob es eine bessere Automatisierung gibt. Es wird darum gebeten zu erklären, wie das konkret funktioniert.Bei einem Team von zwei Personen ist schon das Microservices-/K8s-Muster selbst Overengineering. Bei dieser Teamgröße funktioniert praktisch jeder Ansatz. Früher liefen auch Dropbox/SVN/MS VCS und alles Mögliche irgendwie, mit Unbequemlichkeiten zwar, aber ohne echte Probleme. In dieser Größenordnung kann jeder den Gesamtprozess im Kopf behalten. Komplexe Tools oder Infrastruktur sind nicht der Erfolgsfaktor.
Ein Freelancer berichtet, in den letzten vier Jahren bei mehreren Firmen dreimal ein Monorepo eingerichtet zu haben. Da es auf das Frontend begrenzt war und nur das JavaScript/TypeScript-Ökosystem verwendet wurde, war es noch relativ leicht zu verwalten. Ein wirklich gutes Monorepo funktioniert intern wie ein Polyrepo: Jedes Projekt kann unabhängig entwickelt/deployed/gehostet werden, koexistiert aber in einer Codebasis, teilt gemeinsame Komponenten wie UI frei und gewährleistet ein konsistentes Look-and-Feel. Als praxisnaher Leitfaden wird dieses Referenzmaterial empfohlen.
Am Ende hängt alles vom Einzelfall ab. Unsere Firma verwaltet etwa 40 git-Repositories mit separater CI, baut/testet/packt sie und erstellt am Ende ein integriertes Dateisystem-Image für Integrationstests. Komponenten kommunizieren über Flatbuffers-Nachrichten, und auch Flatbuffers werden als Submodul verwaltet. Downstream-Abhängigkeiten sind schwierig zu handhaben, aber mit progressive enhancement wird eine gewisse Flexibilität erreicht. In so einem Fall ist schon die Diagnose schwierig: Ist das ein Multi-Repo oder ein Monorepo mit vielen Submodulen? Ob ein Wechsel zum Monorepo Vorteile brächte, ist unklar. Letztlich geht es um Trade-offs und darum, welche Art von Unbequemlichkeit man in Kauf nehmen will.
Ein Autor eines Blogposts zu Monorepo-Tools berichtet aus Erfahrung. Leute betonen gern nur die Vorteile von Monorepos, aber die Komplexität eines tatsächlich erfolgreichen Monorepo-Betriebs wird meist im Hintergrund von DevOps-/DevTools-Teams getragen. Deshalb sollte die Einführung vorsichtig angegangen werden, aber wenn es gut aufgebaut ist, kann es ausreichend Wert liefern.
Die Erfahrung mit einem gut verwalteten Monorepo ist so gut, dass man nicht zu anderen Workflows zurückkehren möchte. Aber ein unvorbereitetes „Lasst uns auch ein Monorepo machen“ ist ein Albtraum. Wenn man eine vorbereitete Monorepo-Umgebung mitsamt Tooling als Paket verkaufen würde, gäbe es darin vermutlich eine große Geschäftschance.
In großen Organisationen kann ein Monorepo paradoxerweise Abhängigkeiten zwischen Teams extrem begrenzen und dadurch die Code-Wiederverwendung verringern. Wenn ein Library-Team etwas ändern will, müssen alle nachgelagerten Nutzer aktualisiert werden, und weil manche Teams Dinge auf unerwartete Weise verwenden, verkomplizieren sich Änderungen stark (Hyrum's Law). Am Ende landen Großunternehmen bei internem Copy-and-Paste, Forks, strenger Zugriffskontrolle und langsamer Freigabe von Änderungen.
Wenn man eine Library für allgemeine Nutzung baut, sollte man das API-Design sorgfältig planen. Nach Möglichkeit sollte die API nicht geändert werden; wenn doch, dann sollte eine große Änderung sauber geplant oder durch neue Funktionen ersetzt und die alte Version deprecated werden. Bei kleinem Code kann auch Copy-and-Paste in Ordnung sein.
Trotzdem bleibt ein Vorteil des Monorepos, dass man alle Verwendungsstellen leicht findet und bei Bedarf atomar ändern oder reparieren kann.
Jede Software muss Abhängigkeiten berücksichtigen, und im Monorepo steigt aus Sicht der Library oder der Nutzer eher die gegenseitige Befugnis, einander zu ändern.
Im Monorepo sind Änderungen für den eigenen Bedarf leicht möglich, daher ist die Wahrscheinlichkeit der Code-Wiederverwendung höher als im Polyrepo.