Monorepositories: snälla, måste

Monorepositories: snälla, måste

Översättning av artikeln förberedd för kursstudenter "DevOps praxis och verktyg" i utbildningsprojektet OTUS.

Du bör välja en monorepository eftersom beteendet det främjar i dina team är transparens och delat ansvar, särskilt när team växer. Hur som helst måste du investera i verktyg, men det är alltid bättre om standardbeteendet är det beteende du vill ha i dina kommandon.

Varför pratar vi om detta?

Matt Klein skrev artikeln "Monorepos: Snälla gör det inte!"  (översättarens anmärkning: översättning på Habré "Monorepositories: snälla inte"). Jag gillar Matt, jag tycker att han är väldigt smart och du borde läsa hans synpunkt. Han publicerade ursprungligen omröstningen på Twitter:

Monorepositories: snälla, måste

Översättning:
På nyårsdagen ska jag bråka om hur löjliga monorepositories är. 2019 började lugnt. I andan av detta erbjuder jag dig en undersökning. Vilka är de stora fanatikerna? Supportrar:
- Monorepo
- Rust
- Felaktig omröstning / båda

Mitt svar var: "Jag är bokstavligen båda dessa människor." Istället för att prata om hur Rust är en drog, låt oss titta på varför jag tror att han har fel om monorepositories. Lite om dig själv. Jag är CTO för Chef Software. Vi har cirka 100 ingenjörer, en kodbas som går tillbaka cirka 11-12 år och 4 huvudprodukter. En del av den här koden finns i ett polyrepository (min startposition), en del finns i ett monorepository (min nuvarande position).

Innan jag börjar: varje argument jag gör här kommer att gälla båda typerna av arkiv. Enligt min mening finns det inget tekniskt skäl till varför man ska välja en typ av förvar framför en annan. Du kan få vilken strategi som helst att fungera. Jag pratar gärna om det, men jag är inte intresserad av konstgjorda tekniska skäl till varför en är överlägsen en annan.

Jag håller med den första delen av Matts poäng:

För i skala kommer ett monorepository att lösa alla samma problem som ett polyrepository löser, men samtidigt tvinga dig att koppla ihop din kod tätt och kräva otroliga ansträngningar för att öka skalbarheten i ditt versionskontrollsystem.

Du kommer att behöva lösa samma problem oavsett om du väljer ett monorepository eller ett polyrepository. Hur släpper du releaser? Vad är ditt förhållningssätt till uppdateringar? Bakåtkompatibilitet? Cross projektberoenden? Vilka arkitektoniska stilar är acceptabla? Hur hanterar du din bygg- och testinfrastruktur? Listan är oändlig. Och du kommer att lösa dem alla när du växer. Det finns ingen gratis ost.

Jag tror att Matts argument liknar åsikter som delas av många ingenjörer (och chefer) som jag respekterar. Detta sker utifrån ingenjörens perspektiv som arbetar med komponenten eller teamet som arbetar med komponenten. Du hör saker som:

  • Kodbasen är skrymmande - jag behöver inte allt detta skräp.
  • Det är svårare att testa eftersom jag måste testa allt skräp som jag inte behöver.
  • Det är svårare att arbeta med externa beroenden.
  • Jag behöver mina egna virtuella versionskontrollsystem.

Naturligtvis är alla dessa punkter berättigade. Detta händer i båda fallen - i polyrepository har jag mitt eget skräp, utöver det som behövs för bygget... Jag kan också behöva annat skräp. Så jag skapar "helt enkelt" verktyg som kontrollerar hela projektet. Eller så skapar jag en falsk monorepository med undermoduler. Vi kunde gå runt det här hela dagen. Men jag tror att Matts argument missar huvudorsaken, som jag vände ganska kraftigt till förmån för monorepository:

Det provocerar fram kommunikation och visar på problem

När vi separerar förråd skapar vi ett de facto-problem med samordning och transparens. Detta motsvarar hur vi tänker om team (särskilt hur enskilda medlemmar tänker om dem): vi är ansvariga för en viss komponent. Vi arbetar relativt isolerat. Gränserna är fixerade på mitt team och den/de komponent(er) vi arbetar med.

När arkitekturen blir mer komplex kan ett team inte längre hantera den ensam. Väldigt få ingenjörer har hela systemet i sina huvuden. Låt oss säga att du hanterar en delad komponent A som används av team B, C och D. Team A refaktorerar, förbättrar API:t och ändrar även den interna implementeringen. Som ett resultat är ändringarna inte bakåtkompatibla. Vad har du för råd?

  • Hitta alla platser där det gamla API:et används.
  • Finns det platser där det nya API:et inte kan användas?
  • Kan du fixa och testa andra komponenter för att se till att de inte går sönder?
  • Kan dessa team testa dina ändringar just nu?

Observera att dessa frågor är oberoende av förvarstyp. Du kommer att behöva hitta team B, C och D. Du måste prata med dem, ta reda på tiden, förstå deras prioriteringar. Åtminstone hoppas vi att du gör det.

Ingen vill verkligen göra det här. Det här är mycket mindre roligt än att bara fixa det jäkla API:et. Allt är mänskligt och rörigt. I ett polyrepository kan du helt enkelt göra ändringar, ge det till personerna som arbetar med den komponenten (förmodligen inte B, C eller D) för granskning och gå vidare. Lag B, C och D kan bara stanna kvar med sin nuvarande version tills vidare. De kommer att förnyas när de inser ditt geni!

I en monorepository flyttas ansvaret som standard. Lag A ändrar sin komponent och, om inte försiktigt, bryter omedelbart B, C och D. Detta leder till att B, C och D dyker upp vid A:s dörr och undrar varför Lag A bröt sammansättningen. Detta lär A att de inte kan hoppa över min lista ovan. De måste prata om vad de ska göra. Kan B, C och D röra sig? Tänk om B och C kan, men D var nära relaterad till en bieffekt av den gamla algoritmens beteende?

Sedan måste vi prata om hur vi ska ta oss ur den här situationen:

  1. Stöd för flera interna API:er och kommer att markera den gamla algoritmen som föråldrad tills D kan sluta använda den.
  2. Stöd för flera versioner, en med det gamla gränssnittet, en med det nya.
  3. Fördröja frisläppandet av A:s ändringar tills B, C och D samtidigt kan acceptera det.

Låt oss säga att vi har valt 1, flera API:er. I det här fallet har vi två stycken kod. Gammal och ny. Ganska bekvämt i vissa situationer. Vi checkar in den gamla koden igen, markerar den som föråldrad och kommer överens om ett borttagningsschema med D-teamet. I huvudsak identiskt för poly- och monorepositories.

För att släppa flera versioner behöver vi en filial. Nu har vi två komponenter - A1 och A2. Lag B och C använder A2 och D använder A1. Vi behöver varje komponent vara redo för release eftersom säkerhetsuppdateringar och andra buggfixar kan krävas innan D kan gå vidare. I ett polyrepository kan vi gömma detta i en långlivad gren som känns bra. I ett monorepository tvingar vi koden att skapas i en ny modul. Lag D kommer fortfarande att behöva göra ändringar i den "gamla" komponenten. Alla kan se kostnaden vi betalar här – vi har nu dubbelt så mycket kod, och alla buggfixar som gäller för A1 och A2 måste gälla för dem båda. Med förgreningsmetoden i ett polyrepository döljs detta bakom cherry-pick. Vi anser att kostnaden är lägre eftersom det inte finns någon dubblering. Ur praktisk synvinkel är kostnaden densamma: du bygger, släpper och underhåller två i stort sett identiska kodbaser tills du kan ta bort en av dem. Skillnaden är att med ett monorepository är denna smärta direkt och synlig. Det här är ännu värre, och det är bra.

Slutligen kom vi till den tredje punkten. Frigöringsfördröjning. Det är möjligt att ändringar som görs av A kommer att förbättra livet för Team A. Viktigt, men inte brådskande. Kan vi bara skjuta upp? I ett polyrepository trycker vi på detta för att fästa artefakten. Naturligtvis berättar vi detta för Team D. Fortsätt bara på den gamla versionen tills du kommer ikapp! Detta gör dig redo att spela fegis. Team A fortsätter att arbeta med sin komponent och ignorerar det faktum att Team D använder en allt mer föråldrad version (det är Team D:s problem, de är dumma). Samtidigt pratar Team D dåligt om Team A:s slarviga inställning till kodstabilitet, om de överhuvudtaget pratar om det. Månader går. Till sist beslutar Team D att titta på möjligheten att uppdatera, men A har bara fler ändringar. Lag A kommer knappt ihåg när eller hur de bröt D. Uppgraderingen är mer smärtsam och kommer att ta längre tid. Vilket skickar den längre ner i prioritetsstacken. Tills den dagen vi har ett säkerhetsproblem i A som tvingar oss att göra en filial. Team A måste gå tillbaka i tiden, hitta en punkt när D var stabil, fixa problemet där och göra det redo för release. Detta är det de facto val människor gör, och det är det absolut värsta. Det verkar vara bra för både Lag A och Lag D så länge vi kan ignorera varandra.

I ett monolager är det tredje verkligen inte ett alternativ. Du tvingas hantera situationen på ett av två sätt. Du måste se kostnaderna för att ha två releasegrenar. Lär dig att skydda dig mot uppdateringar som bryter bakåtkompatibiliteten. Men viktigast av allt: du kan inte undvika att ha en svår konversation.

Enligt min erfarenhet är det inte längre möjligt att ha hela systemet i åtanke när team blir stora, och det är den viktigaste delen. Du måste förbättra synligheten av oenighet i systemet. Du måste aktivt arbeta för att få team att titta bort från sina komponenter och titta på andra teams och konsumenters arbete.

Ja, du kan skapa verktyg som försöker lösa problemet med polyrepository. Men min erfarenhet av att lära ut kontinuerlig leverans och automatisering i stora företag säger mig detta: standardbeteendet utan användning av ytterligare verktyg är det beteende du förväntar dig att se. Standardbeteendet för ett polyrepository är isolering, det är hela poängen. Standardbeteendet för en monorepository är delat ansvar och transparens, det är hela poängen. I båda fallen ska jag skapa ett verktyg som jämnar ut de grova kanterna. Som ledare kommer jag att välja ett monorepository varje gång eftersom verktygen behöver förstärka den kultur jag vill ha, och kultur kommer från små beslut och teamets dagliga arbete.

Endast registrerade användare kan delta i undersökningen. Logga in, Snälla du.

Vilka är de största fanatikerna? Supportrar:

  • Monorepo

  • Rust

  • Felaktig omröstning / båda

33 användare röstade. 13 användare avstod från att rösta.

Källa: will.com

Lägg en kommentar