Monorepository: per favore, obbligatori

Monorepository: per favore, obbligatori

Traduzione dell'articolo preparato per gli studenti del corso "Pratiche e strumenti DevOps" nel progetto educativo OTUS.

Dovresti scegliere un monorepository perché il comportamento che promuove nei tuoi team è la trasparenza e la condivisione della responsabilità, soprattutto man mano che i team crescono. In ogni caso, dovrai investire negli strumenti, ma è sempre meglio se il comportamento predefinito è quello che desideri nei tuoi comandi.

Perché ne stiamo parlando?

Matt Klein ha scritto l'articolo "Monorepos: per favore, non farlo!"  (nota del traduttore: traduzione su Habré “Monorepository: per favore no”). Mi piace Matt, penso che sia molto intelligente e dovresti leggere il suo punto di vista. Inizialmente aveva pubblicato il sondaggio su Twitter:

Monorepository: per favore, obbligatori

Traduzione:
Questo Capodanno discuterò di quanto siano ridicoli i monorepository. Il 2019 è iniziato in sordina. Nello spirito di questo, vi propongo un sondaggio. Chi sono i grandi fanatici? Sostenitori:
- Monorepo
- Ruggine
- Sondaggio errato/entrambi

La mia risposta è stata: "Sono letteralmente entrambe quelle persone". Invece di parlare di come Rust sia una droga, vediamo perché penso che abbia torto riguardo ai monorepository. Un po' di te. Sono il CTO di Chef Software. Abbiamo circa 100 ingegneri, una base di codice che risale a circa 11-12 anni fa e 4 prodotti principali. Parte di questo codice è in un polyrepository (la mia posizione iniziale), parte è in un monorepository (la mia posizione attuale).

Prima di iniziare: ogni argomento che sostengo qui si applicherà a entrambi i tipi di repository. Secondo me non esiste alcun motivo tecnico per cui dovresti scegliere un tipo di repository piuttosto che un altro. Puoi far funzionare qualsiasi approccio. Mi fa piacere parlarne, ma non mi interessano le artificiose ragioni tecniche per cui uno è superiore ad un altro.

Sono d'accordo con la prima parte del punto di Matt:

Perché su larga scala, un monorepository risolverà tutti gli stessi problemi risolti da un polyrepository, ma allo stesso tempo ti costringerà ad accoppiare strettamente il tuo codice e richiederà sforzi incredibili per aumentare la scalabilità del tuo sistema di controllo della versione.

Dovrai risolvere gli stessi problemi indipendentemente dal fatto che tu scelga un monorepository o un polyrepository. Come rilasciate le release? Qual è il tuo approccio agli aggiornamenti? Retrocompatibilità? Dipendenze tra progetti incrociati? Quali stili architettonici sono accettabili? Come gestisci la tua infrastruttura di creazione e test? L'elenco è infinito. E li risolverai tutti man mano che cresci. Non c'è formaggio gratis.

Penso che l'argomentazione di Matt sia simile alle opinioni condivise da molti ingegneri (e manager) che rispetto. Ciò avviene dal punto di vista dell'ingegnere che lavora sul componente o del team che lavora sul componente. Senti cose come:

  • La base di codice è ingombrante: non ho bisogno di tutta questa spazzatura.
  • È più difficile testare perché devo testare tutta questa spazzatura di cui non ho bisogno.
  • È più difficile lavorare con le dipendenze esterne.
  • Ho bisogno dei miei sistemi di controllo della versione virtuale.

Naturalmente, tutti questi punti sono giustificati. Questo succede in entrambi i casi: nel polyrepository ho la mia spazzatura, oltre a quella necessaria per la compilazione... potrei aver bisogno anche di altra spazzatura. Quindi creo “semplicemente” strumenti che controllano l’intero progetto. Oppure creo un falso monorepository con sottomoduli. Potremmo girarci intorno tutto il giorno. Ma penso che l'argomentazione di Matt non copra il motivo principale, che ho ribaltato piuttosto pesantemente a favore del monorepository:

Provoca la comunicazione e mostra problemi

Quando separiamo gli archivi, creiamo di fatto un problema di coordinamento e trasparenza. Ciò corrisponde al modo in cui pensiamo ai team (soprattutto al modo in cui i singoli membri li pensano): siamo responsabili di una determinata componente. Lavoriamo in relativo isolamento. I confini sono fissati tra il mio team e i componenti su cui stiamo lavorando.

Man mano che l’architettura diventa più complessa, un team non può più gestirla da solo. Pochissimi ingegneri hanno in testa l’intero sistema. Supponiamo che tu gestisca un componente condiviso A utilizzato dai team B, C e D. Il team A sta eseguendo il refactoring, migliorando l'API e modificando anche l'implementazione interna. Di conseguenza, le modifiche non sono compatibili con le versioni precedenti. Che consiglio hai?

  • Trova tutti i luoghi in cui viene utilizzata la vecchia API.
  • Ci sono luoghi in cui la nuova API non può essere utilizzata?
  • Potete riparare e testare altri componenti per assicurarvi che non si rompano?
  • Questi team possono testare le tue modifiche in questo momento?

Tieni presente che queste domande sono indipendenti dal tipo di repository. Dovrai trovare le squadre B, C e D. Dovrai parlare con loro, scoprire l'orario, capire le loro priorità. Almeno speriamo che lo farai.

Nessuno vuole davvero farlo. Questo è molto meno divertente che semplicemente aggiustare quella maledetta API. È tutto umano e disordinato. In un polyrepository, puoi semplicemente apportare modifiche, fornirle alle persone che lavorano su quel componente (probabilmente non B, C o D) per la revisione e andare avanti. Le squadre B, C e D per ora possono semplicemente restare con la loro versione attuale. Si rinnoveranno quando realizzeranno il tuo genio!

In un monorepository, la responsabilità viene spostata per impostazione predefinita. La squadra A cambia il proprio componente e, se non sta attenta, rompe immediatamente B, C e D. Questo porta B, C e D a presentarsi alla porta di A, chiedendosi perché la squadra A ha interrotto l'assemblaggio. Questo insegna ad A che non possono saltare la mia lista sopra. Devono parlare di quello che faranno. B, C e D possono muoversi? E se B e C potessero farlo, ma D fosse strettamente correlato a un effetto collaterale del comportamento del vecchio algoritmo?

Poi dobbiamo parlare di come usciremo da questa situazione:

  1. Supporto per più API interne e contrassegnerà il vecchio algoritmo come deprecato finché D non potrà smettere di utilizzarlo.
  2. Supporto per più versioni di rilascio, una con la vecchia interfaccia, una con quella nuova.
  3. Ritardare il rilascio delle modifiche di A fino a quando B, C e D non potranno accettarle simultaneamente.

Diciamo che abbiamo selezionato 1, diverse API. In questo caso abbiamo due pezzi di codice. Vecchio e nuovo. Abbastanza conveniente in alcune situazioni. Ricontrolliamo il vecchio codice, lo contrassegniamo come deprecato e concordiamo un programma di rimozione con il team D. Essenzialmente identico per i repository poly e mono.

Per rilasciare più versioni, abbiamo bisogno di un ramo. Ora abbiamo due componenti: A1 e A2. Le squadre B e C usano A2 e D usa A1. Abbiamo bisogno che tutti i componenti siano pronti per il rilascio perché potrebbero essere necessari aggiornamenti di sicurezza e altre correzioni di bug prima che D possa andare avanti. In un polyrepository possiamo nasconderlo in un ramo longevo che ci fa sentire bene. In un monorepository forziamo la creazione del codice in un nuovo modulo. La squadra D dovrà comunque apportare modifiche alla “vecchia” componente. Tutti possono vedere il costo che stiamo pagando qui: ora abbiamo il doppio del codice e qualsiasi correzione di bug che si applica ad A1 e A2 deve applicarsi a entrambi. Con l'approccio di ramificazione in un polyrepository, questo è nascosto dietro il cherry-pick. Riteniamo che il costo sia inferiore perché non vi sono duplicazioni. Da un punto di vista pratico, il costo è lo stesso: creerai, rilascerai e manterrai due codebase sostanzialmente identiche finché non potrai eliminarne una. La differenza è che con un monorepository questo dolore è diretto e visibile. Questo è ancora peggio, e questo è un bene.

Infine siamo arrivati ​​al terzo punto. Ritardo nel rilascio. È possibile che i cambiamenti apportati da A migliorino la vita della squadra A. Importante, ma non urgente. Possiamo semplicemente ritardare? In un polyrepository, lo spingiamo per bloccare l'artefatto. Ovviamente lo diremo al Team D. Rimani sulla vecchia versione finché non raggiungi! Questo ti prepara a fare il codardo. La squadra A continua a lavorare sul proprio componente, ignorando il fatto che la squadra D sta utilizzando una versione sempre più obsoleta (questo è un problema della squadra D, sono stupidi). Nel frattempo, il Team D parla male dell'atteggiamento negligente del Team A nei confronti della stabilità del codice, se non ne parla affatto. Passano i mesi. Alla fine, la squadra D decide di valutare la possibilità di aggiornare, ma A ha solo più cambi. La squadra A ricorda a malapena quando e come ha rotto D. L'aggiornamento è più doloroso e richiederà più tempo. Il che lo manda più in basso nello stack di priorità. Fino al giorno in cui abbiamo un problema di sicurezza in A che ci costringe a fare una filiale. La squadra A deve tornare indietro nel tempo, trovare un punto in cui D era stabile, risolvere lì il problema e prepararlo per il rilascio. Questa è la scelta di fatto che le persone fanno, ed è di gran lunga la peggiore. Sembra che sia una buona cosa sia per la squadra A che per la squadra D finché possiamo ignorarci a vicenda.

In un monorepository, il terzo non è davvero un'opzione. Sei costretto ad affrontare la situazione in due modi. È necessario vedere i costi per avere due rami di rilascio. Impara a proteggerti dagli aggiornamenti che interrompono la compatibilità con le versioni precedenti. Ma soprattutto: non puoi evitare di avere una conversazione difficile.

Nella mia esperienza, quando i team diventano grandi, non è più possibile tenere a mente l'intero sistema, e questa è la parte più importante. È necessario migliorare la visibilità della discordia nel sistema. È necessario lavorare attivamente per convincere i team a distogliere lo sguardo dai propri componenti e guardare il lavoro di altri team e consumatori.

Sì, puoi creare strumenti che tentano di risolvere il problema del polyrepository. Ma la mia esperienza nell'insegnamento della distribuzione continua e dell'automazione nelle grandi aziende mi dice questo: il comportamento predefinito senza l'uso di strumenti aggiuntivi è il comportamento che ti aspetti di vedere. Il comportamento predefinito di un polyrepository è l'isolamento, questo è il punto. Il comportamento predefinito di un monorepository è la responsabilità condivisa e la trasparenza, questo è il punto. In entrambi i casi, creerò uno strumento che appianerà i bordi irregolari. In qualità di leader, sceglierò ogni volta un monorepository perché gli strumenti devono rafforzare la cultura che desidero e la cultura deriva da piccole decisioni e dal lavoro quotidiano del team.

Solo gli utenti registrati possono partecipare al sondaggio. AccediPer favore.

Chi sono i più grandi fanatici? Sostenitori:

  • Monorepo

  • Ruggine

  • Sondaggio errato/entrambi

33 utenti hanno votato. 13 utenti si sono astenuti.

Fonte: habr.com

Aggiungi un commento