Det finns två huvudstrategier för att lagra och hantera kod genom Git: monorepo vs multi-repo. Båda tillvägagångssätten har sina fördelar och nackdelar.

Vi kan använda båda tillvägagångssätt för vilken kodbas som helst på vilket språk som helst. Du kan använda både dessa strategier för projekt som innehåller bara några bibliotek till tusentals. Även om det handlar om några teammedlemmar eller hundratals, eller om du vill hosta privat eller öppen källkod, kan du fortfarande välja monorepo eller multi-repo baserat på olika faktorer.

Vilka är fördelarna och nackdelarna med respektive tillvägagångssätt? När borde vi använda det ena eller det andra? Låt oss ta reda på det!

Vad är repo för något?

Ett repo (förkortning för repository, som betyder förvar, förråd, eller arkiv) är en lagringsplats för alla ändringar och filer från ett projekt, vilket gör det möjligt för utvecklare att ”versionskontrollera” projektets tillgångar under hela utvecklingsstadiet.

Vi brukar hänvisa till Git-förråd (som tillhandahålls av GitHub, GitLab, eller Bitbucket), men konceptet gäller även för andra versionskontrollsystem (t.ex. Mercurial).

Vad är monorepo?

Monorepo-metoden använder ett enda förråd för att hosta all kod för flera bibliotek eller tjänster som utgör ett företags projekt. I allra högsta grad är hela kodbasen från ett företag – som rör olika projekt och kodas på olika språk – förvarade i ett enda förråd.

Fördelar med monorepo

Att förvara hela kodbasen i ett enda förråd ger följande fördelar.

Sänker inträdeströskeln

När nya anställda börjar arbeta för ett företag måste de ladda ner koden och installera de nödvändiga verktygen för att börja arbeta med sina uppgifter. Antag att projektet är utspritt över många förråd, var och ett med egna installationsanvisningar och verktyg. I så fall kommer den ursprungliga installationen att vara komplex, och ofta kommer dokumentationen inte vara fullständig, så att dessa nya teammedlemmar behöver ta hjälp av kollegor.

Ett monorepo förenklar saker. Eftersom det finns en enda plats som innehåller all kod och dokumentation kan du effektivisera den ursprungliga introduktionen.

Centralt belägen kodhantering

Att ha ett enda förråd gör all kod synlig för alla utvecklare. Detta förenklar kodhantering eftersom vi kan använda en enda problemtracker för att titta på alla problem under programmets livscykel.

Dessa egenskaper är till exempel värdefulla när ett problem sträcker sig över två (eller flera) underbibliotek där felet finns på det beroende biblioteket. Med flera förråd kan det vara utmanande att hitta den bit kod där problemet inträffar.

Utöver detta skulle vi behöva ta reda på vilket förråd som borde användas för att skapa problemet och sedan bjuda in och korstagga medlemmar i andra team för att hjälpa till att lösa problemet.

Med ett monorepo kan det bli mycket enklare att både lokalisera kodproblem och samarbeta med felsökningen.

Enkel applikationsomfattande refaktorering

När du skapar en applikationsomfattande refaktorering av koden kommer flera bibliotek att påverkas. Om du förvarar dem på flera förråd kan hantering av alla olika pull-förfrågningar för att hålla dem synkroniserade med varandra snabbt bli en utmaning.

Ett monorepo gör det enkelt att utföra alla ändringar av all kod för alla bibliotek och skicka in dem under en enda pull-förfrågan.

Svårare att förstöra intilliggande funktionalitet

Med monorepo kan vi köra alla tester för alla bibliotek när ett enda bibliotek ändras. Som ett resultat har en förändring i vissa bibliotek en mindre negativ effekt på andra bibliotek.

Teamen delar utvecklingskultur

Även om det inte är omöjligt blir det med en monorepo-strategi utmanande att inspirera unika subkulturer bland olika team. Eftersom de kommer att dela samma förråd kommer de troligen att dela samma programmerings- och hanterings-metoder och använda samma programutvecklingsverktyg.

Problem med monorepo-strategin

Att använda ett enda förråd för all vår kod har flera nackdelar.

Långsammare utvecklingscykler

När koden för ett bibliotek innehåller brytande ändringar som får testerna för beroende bibliotek att misslyckas måste koden också fixas innan ändringarna slås samman.

Om dessa bibliotek är beroende av andra team, som är upptagna med att arbeta med en annan uppgift och inte kan (eller vill) anpassa sin kod för att undvika att bryta förändringar och få testen godkända kan utvecklingen av den nya funktionen avstanna.

Dessutom kan projektet börja avancera endast enligt företagets långsammaste teams hastighet. Detta kan frustrera medlemmarna i de snabbaste teamen och få dem att vilja lämna företaget.

Dessutom måste ett bibliotek utföra testerna för alla andra bibliotek också. Ju fler tester som måste göras, desto mer tid tar det, vilket saktar ner hur snabbt vi kan iterera vår kod.

Kräver nedladdning av hela kodbasen

När ett monorepo innehåller all kod för ett företag kan det vara enormt, med flera gigabyte av data. För att bidra till ett bibliotek som lagras där skulle man behöva ladda ner hela förrådet.

Att hantera en stor kodbas innebär dålig användning av utrymme på våra hårddiskar och långsammare interaktioner. Till exempel vardagliga handlingar som exekvering av git status eller söka i kodbasen med en regex kan ta många sekunder eller till och med minuter längre än de skulle med multi-repo.

Omodifierade bibliotek kan ha nyligen gjorda versioner.

När vi taggar monorepot kommer all kod i det få den nya taggen. Om den här åtgärden utlöser en ny utgåva kommer alla bibliotek i förrådet att släppas som nya med versionsnumret från taggen, även om många av dessa bibliotek kanske inte har haft några ändringar.

Det är svårare att forka

Projekt med öppen källkod måste göra det så enkelt som möjligt för bidragsgivarna att engagera sig. Med flera förråd kan bidragsgivare gå direkt till det specifika förrådet för det projekt de vill bidra till. Med ett monorepo som lagrar olika projekt måste dock bidragsgivare först navigera till rätt projekt och kommer behöva förstå hur deras bidrag kan påverka alla andra projekt.

Vad är multi-repo?

Multi-repo-metoden använder flera förråd för att lagra flera bibliotek eller tjänster av ett projekt som utvecklats av ett företag. Som mest kan det lagra varje liten uppsättning återanvändbar kod eller fristående funktionalitet (t.ex. en mikrotjänst) under ett eget förråd.

Fördelar med multi-repo

Att förvara varje bibliotek oberoende av alla andra ger en mängd fördelar.

Oberoende biblioteksversionshantering

När du taggar ett förråd tilldelas hela kodbasen den ”nya” taggen. Eftersom endast koden för ett specifikt bibliotek finns i förrådet kan biblioteket märkas och versioneras oberoende av alla andra bibliotek som lagras någon annanstans.

Att ha en oberoende version för varje bibliotek hjälper till att definiera beroendeträdet för programmet, så att vi kan konfigurera vilken version av varje bibliotek som ska användas.

Oberoende tjänstutgåvor

Eftersom förrådet endast innehåller koden för en specifik tjänst och inget annat kan det ha sin egen distributionscykel, oberoende av eventuella framsteg som gjorts på applikationerna som har tillgång till tjänsten.

Tjänsten kan använda en snabb utgivningscykel såsom kontinuerlig leverans (där ny kod distribueras efter att den fått godkänt i alla tester). Vissa bibliotek som använder tjänsten kan använda en långsammare cykel, till exempel de som bara producerar en ny utgåva en gång i veckan.

Hjälper till att definiera åtkomstkontroll över hela organisationen

Endast de teammedlemmar som arbetar med att utveckla ett bibliotek måste läggas till i motsvarande förråd och ladda ner koden. Som ett resultat finns det en implicit åtkomstkontrollstrategi för varje lager i applikationen. De som är involverade i biblioteket kommer att beviljas redigeringsrättigheter, och ingen annan kan få tillgång till förrådet. Eller så kan de få läs- men inte redigerings-rättigheter.

Hjälper team arbeta autonomt

Teammedlemmar kan designa bibliotekets arkitektur och implementera dess kod isolerat från alla andra team. De kan fatta beslut utifrån vad biblioteket gör i allmänhet utan att påverkas av specifika krav från något externt team eller program.

Problem med multi-repo-strategin

Att använda flera förråd kan ge upphov till flera problem.

Bibliotek måste ständigt förnyas

När en ny version av ett bibliotek som innehåller brytande ändringar släpps måste alla bibliotek som är beroende av detta bibliotek anpassas för att använda den senaste versionen. Om bibliotekets utgivningscykel är snabbare än dess beroende bibliotek kan de snabbt bli osynkroniserade med varandra.

Team måste ständigt komma i kapp för att använda de senaste utgåvorna från andra team. Med tanke på att olika team har olika prioriteringar kan det ibland vara svårt att uppnå.

Följaktligen kan ett team som inte kan komma i kapp hålla sig till den föråldrade versionen av det beroende biblioteket. Detta kommer få konsekvenser för applikationen (när det gäller säkerhet, hastighet och andra faktorer), och klyftan i utveckling över de olika biblioteken blir bara bredare.

Kan fragmentera team

När olika team inte behöver interagera med varandra kan de arbeta helt avskilt på flera sätt. På lång sikt kan detta leda till att teamen producerar sina egna subkulturer inom företaget, till exempel olika metoder för programmering eller hantering, eller använda olika uppsättningar utvecklingsverktyg.

Om en teammedlem så småningom behöver arbeta i ett annat team kan de drabbas av en kulturchock av att behöva lära sig ett nytt sätt att göra sitt jobb.

Monorepo vs multi-repo: primära skillnader

Båda strategierna handlar i slutändan om samma sak: att hantera kodbasen. Därmed måste de båda lösa samma utmaningar, inklusive utgivingshantering, främja samarbete mellan teammedlemmar, lösa problem, testa koden, och mycket mer.

Deras huvudsakliga skillnad gäller deras timing för teammedlemmar att fatta beslut: antingen direkt med monorepo eller allteftersom med multi-repo.

Låt oss analysera detta lite mer i detalj.

Eftersom alla bibliotek är oberoende versionerade i multi-repo kan ett team som släpper ett bibliotek med brytande ändringar göra det säkert genom att tilldela ett nytt versionsnummer till den senaste versionen. Andra grupper kan låta sina beroende bibliotek hålla sig till den gamla versionen och byta till den nya när deras egen kod anpassats.

Detta tillvägagångssätt lämnar beslutet om när man ska anpassa alla andra bibliotek upp till varje enskilt team, som kan göra det när som helst. Om de gör det för sent och nya biblioteksversioner släpps blir det allt svårare att stänga klyftan mellan biblioteken.

Följaktligen, medan ett team kan iterera snabbt och ofta med sin egen kod kan andra team visa sig oförmögna att komma i kapp, vilket i slutändan producerar bibliotek som avviker från varandra.

Å andra sidan kan vi i en monorepo-miljö inte släppa en ny version av ett bibliotek som bryter något annat bibliotek eftersom deras tester kommer att misslyckas. I det här fallet måste det första teamet kommunicera med det andra teamet för att införliva ändringarna.

Detta tillvägagångssätt tvingar team att anpassa alla bibliotek tillsammans när en förändring för ett enda bibliotek måste ske. Alla team tvingas prata med varandra och nå en lösning tillsammans.

Som ett resultat kommer det första teamet inte att kunna iterera så fort de vill, men koden över olika bibliotek kommer inte att börja avvika från varandra.

Sammanfattningsvis kan multi-repo-strategin bidra till att skapa en kultur av ”gå snabbt fram och bryt saker och ting” bland team, där oberoende team kan producera ny kod med sin egen hastighet. Monorepo-strategin gynnar å andra sidan en kultur av medvetenhet och omtänksamhet, där team inte kommer hamna efter för att behöva hantera ett problem helt själva.

Hybrid poly-as-mono-strategi

Om vi inte kan besluta om att använda antingen multi-repo eller monorepo-strategin, finns det också mellanliggande strategier: att använda flera förråd och använda några verktyg för att hålla dem synkroniserade, vilket får dem att lika ett monorepo men med mer flexibilitet.

Meta är ett sådant verktyg. Det organiserar flera förråd i underkataloger och tillhandahåller ett kommandoradsgränssnitt som exekverar samma kommando på dem alla samtidigt.

Ett metaförråd innehåller information om vilka förråd som ett projekt består av. Kloning av detta förråd via meta kommer sedan rekursivt klona alla nödvändiga förråd, vilket gör det lättare för nya teammedlemmar att börja arbeta med sina projekt omedelbart.

För att klona ett metaförråd och alla dess definierade förrådd, måste vi exekvera följande:

meta git clone [meta repo url]

Meta kommer att exekvera en git clone för varje förråd och placera den i en undermapp:

Kloning av ett metaprojekt
Kloning av ett metaprojekt. (Bildkälla: github.com/mateodelnorte/meta)

Därefter kommer kommandot meta exec att exekvera kommandot på varje undermapp. Till exempel används git checkout master på varje förråd så här:

meta exec "git checkout master"

Hybrid mono-as-poly-strategi

Ett annat tillvägagångssätt är att hantera koden via ett monorepo för utveckling, men kopiera varje biblioteks kod till sitt oberoende förråd för distribution.

Denna strategi är utbredd inom PHP-ekosystemen eftersom Packagist (det huvudsakliga Composer-förrådet) kräver en offentlig förrådsadress för att publicera ett paket, och det är inte möjligt att ange att paketet finns i en underkatalog till förrådet.

Med tanke på Packagists begränsning kan PHP-projekt fortfarande använda monorepo för utveckling, men måste använda multi-repo-metoden för distribution.

För att uppnå denna konvertering kan vi köra ett skript med git subtree split eller använda ett av de tillgängliga verktygen som utför samma logik:

Vem använder monorepo vs multi-repo

Flera stora teknikföretag använder monorepo-metoden, medan andra har bestämt sig för att använda multi-repo-metoden.

Google, Facebook, Twitter, och Uber har alla offentligt sagt att de använder monorepo. Microsoft driver det största Git monorepot på planeten för att lagra källkoden för Windows operativsystem.

Å andra sidan är Netflix, Amazon och Lyft kända företag som använder multi-repo-strategin.

När det gäller hybrid poly-as-mono uppdaterar Android flera förråd, som hanteras som ett monorepo.

När det gäller hybrid mono-as-poly har Symfony koden för alla sina komponenter i ett monorepo. De delar upp det i oberoende förråd för distribution (t.ex. symfony/dependency-injection och symfony/event-dispatcher.)

Exempel på monorepo och multi-repo

WordPress-kontot på GitHub har exempel på både monorepo och multi-repo-strategierna.

Gutenberg, WordPress blockredigerare, består av flera dussin JavaScript-paket. Dessa paket lagras alla på WordPress/gutenberg monorepo och hanteras genom Lerna för att publicera dem i npm-förrådet.

Openverse, sökmotorn för öppet licensierade medier, har sina huvuddelar i oberoende förråd: Frontend, Catalog, och API.

Monorepo vs multi-repo: hur väljer man?

Som med många utvecklingsproblem finns det inget fördefinierat svar på vilket tillvägagångssätt du borde använda. Olika företag och projekt kommer att gynnas av en specifik strategi baserat på deras unika förhållanden, såsom:

  • Hur stor är kodbasen? Innehåller den många gigabyte data?
  • Hur många kommer att arbeta på kodbasen? Är det runt 10, 100 eller 1000?
  • Hur många paket kommer det att finnas? Är det runt 10, 100 eller 1000?
  • Hur många paket behöver teamet arbeta på vid en given tidpunkt?
  • Hur tätt kopplade är paketen?
  • Är olika programmeringsspråk inblandade? Behöver de en viss programvara installerad eller speciell hårdvara för att köra koden?
  • Hur många distributionsverktyg krävs, och hur komplexa är de att konfigurera?
  • Vad är företagets kultur? Uppmuntras team att samarbeta med varandra?
  • Vilka verktyg och vilken teknik kan teamen använda?

Sammanfattning

Det finns två huvudstrategier för att lagra och hantera kod: monorepo vs multi-repo. Monorepo-metoden innebär att koden lagras för olika bibliotek eller projekt – och till och med all kod från ett företag – i ett enda förråd. Och multi-repo-systemet delar upp koden i enheter, till exempel bibliotek eller tjänster, och lagrar sin kod i oberoende förråd.

Vilket tillvägagångssätt du borde använda beror på en mängd olika omständighet. Båda strategierna har flera fördelar och nackdelar, och vi har gått igenom dem alla i detalj i den här artikeln.

Har du några frågor kvar om monorepo eller multi-repo? Berätta i kommentarerna nedan!

Leonardo Losoviz

Leo writes about innovative web development trends, mostly concerning PHP, WordPress and GraphQL. You can find him at leoloso.com and twitter.com/losoviz.