Monorepositories: vær så snill, må

Monorepositories: vær så snill, må

Oversettelse av artikkelen utarbeidet for kursstudenter "DevOps-praksis og verktøy" i OTUS utdanningsprosjekt.

Du bør velge et monorepository fordi atferden det fremmer i teamene dine er åpenhet og delt ansvar, spesielt når teamene vokser. Uansett, du må investere i verktøy, men det er alltid bedre hvis standardoppførselen er den oppførselen du ønsker i kommandoene dine.

Hvorfor snakker vi om dette?

Matt Klein skrev artikkelen "Monorepos: Ikke gjør det!"  (oversetterens notat: oversettelse på Habré "Monorepositories: vennligst ikke"). Jeg liker Matt, jeg synes han er veldig smart, og du bør lese hans synspunkt. Han la opprinnelig avstemningen ut på Twitter:

Monorepositories: vær så snill, må

Oversettelse:
På nyttårsdag skal jeg krangle om hvor latterlige monorepositories er. 2019 startet rolig. I ånden av dette tilbyr jeg deg en undersøkelse. Hvem er de store fanatikerne? Supportere:
- Monorepo
- Rust
- Feil avstemning / begge deler

Mitt svar var: "Jeg er bokstavelig talt begge disse menneskene." I stedet for å snakke om hvordan Rust er et stoff, la oss se på hvorfor jeg tror han tar feil når det gjelder monorepositories. Litt om deg selv. Jeg er CTO for Chef Software. Vi har rundt 100 ingeniører, en kodebase som går tilbake rundt 11-12 år, og 4 hovedprodukter. Noe av denne koden er i et polyrepository (min startposisjon), noe er i et monorepository (min nåværende posisjon).

Før jeg begynner: hvert argument jeg kommer med her vil gjelde for begge typer depoter. Etter min mening er det ingen teknisk grunn til at du bør velge en type depot fremfor en annen. Du kan få enhver tilnærming til å fungere. Jeg snakker gjerne om det, men jeg er ikke interessert i kunstige tekniske årsaker til at en er overlegen en annen.

Jeg er enig i den første delen av Matts poeng:

For i stor skala vil et monorepository løse alle de samme problemene som et polyrepository løser, men samtidig tvinge deg til å koble koden tett og kreve utrolig innsats for å øke skalerbarheten til versjonskontrollsystemet.

Du må løse de samme problemene uansett om du velger et monodepot eller et polydepot. Hvordan slipper du utgivelser? Hva er din tilnærming til oppdateringer? Bakoverkompatibilitet? Tverrprosjektavhengigheter? Hvilke arkitektoniske stiler er akseptable? Hvordan administrerer du bygge- og testinfrastrukturen din? Listen er uendelig. Og du vil løse dem alle etter hvert som du vokser. Det er ingen gratis ost.

Jeg tror Matts argument ligner på synspunkter som deles av mange ingeniører (og ledere) jeg respekterer. Dette skjer fra ingeniørens perspektiv som jobber med komponenten eller teamet som jobber med komponenten. Du hører ting som:

  • Kodebasen er klumpete - jeg trenger ikke alt dette søppelet.
  • Det er vanskeligere å teste fordi jeg må teste alt dette søppelet som jeg ikke trenger.
  • Det er vanskeligere å jobbe med eksterne avhengigheter.
  • Jeg trenger mine egne virtuelle versjonskontrollsystemer.

Selvfølgelig er alle disse punktene berettiget. Dette skjer i begge tilfeller - i polyrepositoryet har jeg min egen søppel, i tillegg til den som trengs for byggingen... Jeg kan også trenge annet søppel. Så jeg lager "bare" verktøy som sjekker hele prosjektet. Eller jeg lager et falsk monorepository med undermoduler. Vi kunne gå rundt dette hele dagen. Men jeg tror Matts argument går glipp av hovedårsaken, som jeg snudde ganske kraftig til fordel for monorepository:

Det provoserer frem kommunikasjon og viser problemer

Når vi skiller depoter, skaper vi et de facto-problem med koordinering og åpenhet. Dette tilsvarer måten vi tenker om lag (spesielt måten individuelle medlemmer tenker om dem): vi er ansvarlige for en bestemt komponent. Vi jobber relativt isolert. Grensene er fastsatt på teamet mitt og komponenten(e) vi jobber med.

Ettersom arkitekturen blir mer kompleks, kan ett team ikke lenger administrere den alene. Svært få ingeniører har hele systemet i hodet. La oss si at du administrerer en delt komponent A som brukes av team B, C og D. Team A refaktoriserer, forbedrer API og endrer også den interne implementeringen. Som et resultat er endringene ikke bakoverkompatible. Hvilke råd har du?

  • Finn alle steder der den gamle API-en brukes.
  • Er det steder hvor det nye API-et ikke kan brukes?
  • Kan du fikse og teste andre komponenter for å sikre at de ikke går i stykker?
  • Kan disse teamene teste endringene dine akkurat nå?

Vær oppmerksom på at disse spørsmålene er uavhengige av depottypen. Du må finne lag B, C og D. Du må snakke med dem, finne ut tiden, forstå deres prioriteringer. Vi håper i hvert fall du vil.

Ingen ønsker egentlig å gjøre dette. Dette er mye mindre moro enn å bare fikse API-en. Det hele er menneskelig og rotete. I et polyrepository kan du ganske enkelt gjøre endringer, gi det til de som jobber med den komponenten (sannsynligvis ikke B, C eller D) for gjennomgang, og gå videre. Lag B, C og D kan bare forbli med sin nåværende versjon inntil videre. De vil bli fornyet når de innser genialiteten din!

I et monorepository flyttes ansvaret som standard. Lag A endrer sin komponent og bryter umiddelbart B, C og D, hvis ikke forsiktig. Dette fører til at B, C og D dukker opp ved A sin dør og lurer på hvorfor lag A brøt sammenstillingen. Dette lærer A at de ikke kan hoppe over listen min ovenfor. De må snakke om hva de skal gjøre. Kan B, C og D bevege seg? Hva om B og C kan, men D var nært knyttet til en bivirkning av den gamle algoritmens oppførsel?

Da må vi snakke om hvordan vi skal komme oss ut av denne situasjonen:

  1. Støtte for flere interne APIer, og vil merke den gamle algoritmen som utdatert til D kan slutte å bruke den.
  2. Støtte for flere utgivelsesversjoner, en med det gamle grensesnittet, en med det nye.
  3. Utsett utgivelsen av A sine endringer til B, C og D kan godta det samtidig.

La oss si at vi har valgt 1, flere APIer. I dette tilfellet har vi to stykker kode. Gammelt og nytt. Ganske praktisk i noen situasjoner. Vi sjekker den gamle koden inn igjen, merker den som foreldet, og blir enige om en fjerningsplan med D-teamet. I hovedsak identisk for poly- og mono-repositorier.

For å gi ut flere versjoner trenger vi en filial. Nå har vi to komponenter - A1 og A2. Lag B og C bruker A2 og D bruker A1. Vi trenger at hver komponent er klar for utgivelse fordi sikkerhetsoppdateringer og andre feilrettinger kan være nødvendig før D kan gå videre. I et polyrepository kan vi skjule dette i en langvarig gren som føles bra. I et monorepository tvinger vi koden til å bli opprettet i en ny modul. Lag D vil fortsatt måtte gjøre endringer i den "gamle" komponenten. Alle kan se kostnadene vi betaler her – vi har nå dobbelt så mye kode, og eventuelle feilrettinger som gjelder for A1 og A2 må gjelde for dem begge. Med forgreningstilnærmingen i et polyrepository er dette skjult bak cherry-pick. Vi vurderer kostnadene som lavere fordi det ikke er noen duplisering. Fra et praktisk synspunkt er kostnadene de samme: du vil bygge, frigjøre og vedlikeholde to stort sett identiske kodebaser til du kan slette en av dem. Forskjellen er at med et monorepository er denne smerten direkte og synlig. Dette er enda verre, og det er bra.

Til slutt kom vi til det tredje punktet. Utslippsforsinkelse. Det er mulig at endringer gjort av A vil forbedre livene til Team A. Viktig, men ikke presserende. Kan vi bare utsette? I et polyrepository skyver vi dette for å feste artefakten. Selvfølgelig forteller vi dette til Team D. Bare hold deg på den gamle versjonen til du tar igjen! Dette setter deg opp til å spille feiging. Team A fortsetter å jobbe med komponenten sin, og ignorerer det faktum at Team D bruker en stadig mer utdatert versjon (det er Team Ds problem, de er dumme). I mellomtiden snakker Team D dårlig om Team A sin uforsiktige holdning til kodestabilitet, hvis de i det hele tatt snakker om det. Måneder går. Til slutt bestemmer Team D seg for å se på muligheten for oppdatering, men A har bare flere endringer. Team A husker knapt når eller hvordan de brøt D. Oppgraderingen er mer smertefull og vil ta lengre tid. Noe som sender den lenger ned i prioritetsstabelen. Helt til den dagen vi har et sikkerhetsproblem i A som tvinger oss til å lage en filial. Team A må gå tilbake i tid, finne et punkt da D var stabil, fikse problemet der og gjøre det klart for utgivelse. Dette er de facto-valget folk tar, og det er det desidert verste. Det ser ut til å være bra for både lag A og lag D så lenge vi kan ignorere hverandre.

I et monorepository er det tredje egentlig ikke et alternativ. Du blir tvunget til å håndtere situasjonen på en av to måter. Du må se kostnadene ved å ha to utgivelsesgrener. Lær å beskytte deg selv mot oppdateringer som bryter bakoverkompatibiliteten. Men viktigst av alt: du kan ikke unngå å ha en vanskelig samtale.

Min erfaring er at når team blir store, er det ikke lenger mulig å ha hele systemet i tankene, og det er den viktigste delen. Du må forbedre synligheten av uenighet i systemet. Du må aktivt jobbe for å få team til å se bort fra komponentene sine og se på arbeidet til andre team og forbrukere.

Ja, du kan lage verktøy som prøver å løse polyrepository-problemet. Men min erfaring med å undervise i kontinuerlig levering og automatisering i store bedrifter forteller meg dette: standardoppførselen uten bruk av tilleggsverktøy er oppførselen du forventer å se. Standardoppførselen til et polyrepository er isolasjon, det er hele poenget. Standardoppførselen til et monorepository er delt ansvar og åpenhet, det er hele poenget. I begge tilfeller skal jeg lage et verktøy som jevner ut de grove kantene. Som leder vil jeg velge et monorepository hver gang fordi verktøyene trenger for å forsterke kulturen jeg ønsker, og kultur kommer fra bittesmå beslutninger og teamets daglige arbeid.

Kun registrerte brukere kan delta i undersøkelsen. Logg inn, vær så snill.

Hvem er de største fanatikerne? Supportere:

  • Monorepo

  • Rust

  • Feil avstemning / begge deler

33 brukere stemte. 13 brukere avsto.

Kilde: www.habr.com

Legg til en kommentar