Stacks

Monorepo of losse repositories: wat past bij je team

Bouw je met één team aan één product, kies dan een monorepo. Losse repositories passen bij onderdelen met een eigen team, releaseritme of eigen toegangsrechten.

Gestapelde zeecontainers in veel kleuren
Foto: Teng Yuhong via Unsplash

Bouw je met één team aan één product, kies dan een monorepo: frontend, backend, gedeelde code en infrastructuur in één repository. Losse repositories passen beter als onderdelen los van elkaar staan, met een eigen team, een eigen releaseritme of eigen toegangsrechten. Voor een verspreid team telt vooral hoe makkelijk iemand de code vindt, reviewt en lokaal draait.

Wat een monorepo je oplevert

Een wijziging die de API en de frontend raakt, staat in één pull request. De reviewer ziet beide kanten en ze gaan samen live. Met losse repositories heb je twee pull requests die je in de goede volgorde moet mergen en uitrollen.

Gedeelde code is gewoon een map. Types, validatie, een designsysteem en de configuratie voor linting en TypeScript staan op één plek. Je hoeft geen interne pakketten te publiceren en geen versies bij te houden.

Een nieuwe developer kloont één repository, leest één README en start alles met één commando. Dat scheelt veel in de eerste week (zie ook een remote developer onboarden).

Wat een monorepo kost

Bouwt en test CI bij elke wijziging alles, dan wordt het trager naarmate de repository groeit. Nx bepaalt met nx affected welke projecten door een wijziging geraakt worden en draait alleen daar de taken. Turborepo bewaart de uitkomst van taken in een cache, en die cache kun je via een remote cache delen met je team en met CI.

Eigenaarschap vervaagt. Als iedereen overal aan kan zitten, voelt niemand zich verantwoordelijk voor de betaalmodule. Met een CODEOWNERS-bestand leg je in GitHub vast wie eigenaar is van welke map. Die mensen krijgen automatisch een reviewverzoek, en met een branch protection rule maak je hun goedkeuring verplicht.

Leestoegang is alles of niets. Op GitHub regel je leesrechten per repository. CODEOWNERS bepaalt wie moet reviewen, niet wie de code mag zien.

Ook upgrades raken alles. Eén versie van React of TypeScript voor de hele repository is overzichtelijk, maar een grote upgrade moet dan overal tegelijk.

Wanneer losse repositories beter zijn

  • Onderdelen hebben een eigen team en een eigen releaseritme, zoals een mobiele app naast een webplatform.
  • Een externe partij mag aan één deel werken en de rest niet zien.
  • Een onderdeel is open source of wordt als pakket door anderen gebruikt.
  • De onderdelen delen geen code, en je wilt ze los van elkaar kunnen overdragen of verkopen.

Daar betaal je wel voor met coördinatie. Een wijziging over repositories heen vraagt versies, changelogs en een duidelijk contract tussen de onderdelen. Een OpenAPI-specificatie helpt daarbij (zie API-first ontwerpen).

Wat het betekent voor een verspreid team

MonorepoLosse repositories
InwerkenEén repository, één READMEPer repository uitzoeken hoe het werkt
Wijziging in API en frontendEén pull requestMeerdere pull requests in de goede volgorde
Code reviewReviewer ziet het geheelReviewer ziet een deel
Snelheid van CIVraagt caching en alleen bouwen wat geraakt isPer repository klein en snel
Leestoegang beperkenKan niet per mapPer repository te regelen

Werk je niet in één ruimte, dan loop je niet even naar iemand toe om te vragen hoe iets werkt, dus helpt het als de repository dat zelf uitlegt. Schrijf in de README hoe je alles lokaal draait, zet een template voor pull requests klaar en houd CODEOWNERS bij. Over reviews in een verspreid team schreef ik een apart stuk: code review op afstand.

Zo zou ik beginnen

  1. Eén repository met een map apps/ voor wat je uitrolt en een map packages/ voor gedeelde code.
  2. De workspaces van je package manager om die mappen aan elkaar te koppelen.
  3. Een CODEOWNERS-bestand vanaf de eerste week, ook als het team nog klein is.
  4. Nx of Turborepo zodra CI merkbaar trager wordt, en niet eerder.
  5. Een onderdeel pas afsplitsen als er een concrete reden is: toegang, een eigen releaseritme of een ander team.

Begin met minder tooling dan je denkt nodig te hebben. Een monorepo met twee apps en één gedeeld pakket heeft genoeg aan workspaces en een nette CI-configuratie.

Later van richting veranderen

Een deel uit een monorepo halen is goed te doen. Met git-tooling verplaats je een map met de eigen history naar een nieuwe repository. Losse repositories samenvoegen kost meer werk, omdat je build-scripts, CI en dependencies gelijk moet trekken. Begin daarom liever met één repository en splits als het nodig is.

Welke keuze je ook maakt, schrijf hem op in een kort beslisdocument in de repository zelf. Een nieuwe developer ziet dan waarom het zo is ingericht, en jij weet over een jaar nog waarom je deze keuze maakte.

Bronnen

Veelgestelde vragen

Is een monorepo geschikt voor een klein team?

Ja, vooral voor een klein team dat aan één product werkt. Je hebt één plek voor de code, één CI-configuratie, en een wijziging in frontend en backend staat in één pull request.

Welke tools heb je nodig voor een monorepo?

Om te beginnen alleen de workspaces van je package manager en een CODEOWNERS-bestand. Wordt CI traag, dan voeg je een tool als Nx of Turborepo toe die alleen bouwt wat geraakt is en resultaten in een cache bewaart.

Kun je in een monorepo de toegang per map beperken?

Niet voor lezen. Op GitHub regel je leesrechten per repository, en CODEOWNERS bepaalt alleen wie moet reviewen. Code die niet iedereen mag zien, zet je in een eigen repository.

Over de auteur

Erik Schoorl

Erik Schoorl

CTO en hoofdarchitect

Erik richtte samen met Bas ESBL op. Hij is CTO van Brainpower Group en eindverantwoordelijk voor architectuur en oplevering.

Meer van Erik
Contact
Bas Leijder HavenstroomMaarten ter VeldeBarry Willems

Vertel ons wie je zoekt.

Een kennismaking duurt een half uur, online of op ons kantoor in Amsterdam. In de chat antwoorden we meestal binnen een paar minuten.

Of bel +31 20 210 1978hello@brainpowergroup.eu

Bas, Maarten en BarryNu live · antwoord binnen een paar minuten

Na het versturen gaat de chat open.