Monorepository: per favore, è necessario

Monorepository: per favore, è necessario

La traduzione dell'articolo è stata preparata per gli studenti del corso «Pratiche e strumenti DevOps» nel progetto educativo OTUS.

Dovresti scegliere un monorepo, poiché il comportamento che promuove nei tuoi team è la trasparenza e la responsabilità collettiva, soprattutto con la crescita dei team. In ogni caso, dovrai investire negli strumenti, ma è sempre meglio quando il comportamento predefinito è quello che desideri vedere nei tuoi team.

Perché ne parliamo?

Matt Klein ha scritto un articolo «Monorepos: Per favore, non farlo!»  (nota del traduttore: traduzione su Habr «Monorepository: per favore non farlo»). Mi piace Matt, penso che sia molto intelligente, e dovresti leggere il suo punto di vista. Inizialmente ha pubblicato un sondaggio su Twitter:

Monorepository: per favore, è necessario

Traduzione:
In questo giorno di Capodanno, discuterò di quanto siano ridicoli i monorepos. Il 2019 è iniziato senza clamore. In questo spirito, ti propongo un sondaggio. Chi sono i grandi fan? Sostenitori:
Monorepo
Rust
Sondaggio errato / entrambi

La mia risposta è stata: «Io ho letteralmente entrambe queste persone». Invece di parlare di quanto sia tossico Rust, vediamo perché penso che si sbagli sui monorepository. Un po' su di me. Sono il Chief Technology Officer di Chef Software. Abbiamo circa 100 ingegneri, una base di codice che ha circa 11-12 anni e 4 prodotti principali. Parte di questo codice si trova in un monorepo (la mia posizione iniziale), parte in un polirepo (la mia posizione attuale).

Prima di iniziare: ogni argomento che presento qui sarà applicabile a entrambi i tipi di repository. A mio avviso, non ci sono motivi tecnici per cui dovreste scegliere l'uno o l'altro tipo di repository. Potrete far funzionare qualsiasi approccio. Sono felice di discuterne, ma non mi interessano motivazioni tecniche artificiali per cui uno sarebbe superiore all'altro.

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

Perché su larga scala, un monorepo affronterà gli stessi problemi che affronta un polirepo, ma ti porterà a una forte coesione del codice e richiederà uno sforzo straordinario per aumentare la scalabilità del tuo sistema di controllo delle versioni.

Dovrai affrontare gli stessi problemi indipendentemente dal fatto che tu scelga un monorepo o un polirepo. Come gestisci i rilasci? Qual è il tuo approccio agli aggiornamenti? Retrocompatibilità? Dipendenze incrociate tra progetti? Quali stili architetturali sono accettabili? Come gestisci la tua infrastruttura di build e testing? L'elenco è infinito. E affronterai tutto questo mentre cresci. Non esiste un formaggio gratuito.

Penso che l'argomento di Matt sia simile alle opinioni condivise da molti ingegneri (e manager) che rispetto. Proviene dalla prospettiva di un ingegnere che lavora su un componente, o di un team che lavora su un componente. Sentirai cose come:

  • Il codice è ingombrante — non ho bisogno di tutto questo ciarpame.
  • È più complicato da testare, perché devo controllare tutto questo materiale che non mi serve.
  • È più difficile lavorare con dipendenze esterne.
  • Ho bisogno dei miei sistemi di versioning virtuali.

Sicuramente, tutti questi punti sono validi. Accade in entrambi i casi: nel mio polirepo ho il mio materiale, oltre a quello necessario per la build… Potrei aver bisogno anche di altro materiale. Quindi, "semplicemente" creo strumenti che effettuano il checkout dell'intero progetto. Oppure creo un falso monorepo con sottoggetti. Potremmo discutere di questo tutto il giorno. Ma penso che l'argomento di Matt trascuri la causa principale, che ho abbastanza fortemente ribaltato a favore del monorepo:

Provoca comunicazione e mette in mostra i problemi

Quando separiamo i repository, di fatto creiamo un problema di coordinazione e trasparenza. Questo si allinea con il nostro modo di pensare ai team (soprattutto come i singoli membri li percepiscono): siamo responsabili di un determinato componente. Lavoriamo in relativa isolamento. I confini sono fissati sul mio team e sul/i componente/i su cui stiamo lavorando.

Con l'aumentare della complessità dell'architettura, un singolo team non può più gestirla da solo. Pochissimi ingegneri riescono a tenere a mente l'intero sistema. Supponiamo che tu stia gestendo un componente comune A, utilizzato dai team B, C e D. Il team A sta effettuando un refactoring, migliorando l'API e modificando anche l'implementazione interna. Di conseguenza, le modifiche non sono retrocompatibili. Quale consiglio daresti?

  • Trova tutti i luoghi in cui viene utilizzata la vecchia API.
  • Ci sono luoghi in cui la nuova API non può essere utilizzata?
  • Puoi correggere e testare altri componenti per assicurarti che non si rompano?
  • Possono questi team verificare le tue modifiche proprio ora?

Si prega di notare che queste domande non dipendono dal tipo di repository. Dovrete trovare i team B, C e D. Dovrete parlare con loro, capire i tempi e le priorità. Almeno speriamo che lo farete.

In realtà, a nessuno piace farlo. È molto meno interessante che semplicemente correggere un dannato API. Tutto questo è umano e complicato. Nel polirepository potrete semplicemente apportare modifiche, sottoporle a revisione a chi lavora su quel componente (probabilmente non B, C o D) e andare avanti. I team B, C e D possono rimanere alla loro attuale versione nel frattempo. Si aggiorneranno quando realizzeranno il vostro genio!

Nel monorepository la responsabilità del cambiamento si sposta per impostazione predefinita. Il team A modifica il proprio componente e, se non fa attenzione, danneggia immediatamente B, C e D. Questo porta B, C e D a bussare alla porta di A, chiedendosi perché il team A abbia rotto la build. Questo insegna a A che non possono trascurare la mia lista sopra. Devono discutere ciò che intendono fare. Possono B, C e D procedere? E se B e C possono, ma D fosse strettamente legato all'effetto collaterale del comportamento del vecchio algoritmo?

Dobbiamo poi parlare di come uscirne:

  1. Supporto per molteplici API interne, con il vecchio algoritmo contrassegnato come obsoleto, finché D non sarà in grado di cessarne l'uso.
  2. Supporto per più versioni delle release, una con la vecchia interfaccia e una con la nuova.
  3. Ritardare il rilascio delle modifiche A finché B, C e D non saranno tutti in grado di accettarle.

Supponiamo di aver scelto 1 o più API. In questo caso abbiamo due pezzi di codice: il vecchio e il nuovo. È piuttosto comodo in alcune situazioni. Rimandiamo il codice vecchio, lo contrassegniamo come obsoleto (deprecated) e concordiamo un piano per la sua rimozione con il team D. Essenzialmente è identico per i repository polifilari e monorepo.

Per rilasciare più versioni abbiamo bisogno di un ramo. Ora abbiamo due componenti: A1 e A2. I team B e C utilizzano A2, mentre D utilizza A1. È necessario che ogni componente sia pronto per il rilascio, poiché prima che D possa procedere, potrebbero essere necessari aggiornamenti di sicurezza e correzioni di bug. Nella polirepository possiamo nascondere questo in un ramo a lungo termine che funziona bene. Nella monorepository forziamo la creazione del codice in un nuovo modulo. Il team D dovrà ancora apportare modifiche al componente 'vecchio'. Ognuno può vedere il costo che stiamo pagando qui: abbiamo ora il doppio del codice e qualsiasi correzione di bug applicata a A1 e A2 deve essere applicata a entrambi. Con l'approccio all'uso dei rami nella polirepository, ciò è nascosto tramite cherry-pick. Riteniamo che il costo sia inferiore perché non ci sono duplicazioni. Da un punto di vista pratico, il costo è lo stesso: dovrai costruire, rilasciare e mantenere due basi di codice sostanzialmente identiche fino a quando non potrai eliminarne una. La differenza è che nella monorepository questo dolore è diretto e in vista. È ancora peggio, ed è un bene.

Finalmente, siamo arrivati al terzo punto. Ritardo nel rilascio. Potrebbe essere che le modifiche apportate da A miglioreranno la situazione del team A. Importante, ma non urgente. Possiamo semplicemente ritardare? Nel polirepository stiamo spingendo per consolidare l'artefatto. Certo, stiamo parlando di questo con il team D. Rimanete semplicemente sulla vecchia versione, finché non recuperate! Questo innesca una partita a essere vigliacchi. Il team A continua a lavorare sul proprio componente, ignorando il fatto che il team D sta utilizzando una versione sempre più obsoleta (è un problema del team D, sono stupidi). Nel frattempo, il team D parla male della negligenza del team A riguardo alla stabilità del codice, se ne parla addirittura. Passano mesi. Finalmente, il team D decide di esplorare la possibilità di un aggiornamento, ma i cambiamenti in A sono solo aumentati. Il team A ricorda a malapena quando e come hanno rotto D. L'aggiornamento è più doloroso e richiederà più tempo. Questo lo fa scivolare ulteriormente verso il basso nella lista delle priorità. Fino al giorno in cui abbiamo un problema di sicurezza in A, che ci costringe a fare un branch. Il team A deve tornare indietro nel tempo, trovare il momento in cui D era stabile, risolvere il problema lì e renderlo pronto per il rilascio. Questa è di fatto la scelta che fanno le persone, e sicuramente è la peggiore. Sembra che questo vada bene sia per il team A che per il D, finché possiamo ignorarci a vicenda.

In un monorepo, il terzo non è davvero un'opzione. Devi affrontare la situazione in uno dei due modi. Devi considerare i costi derivanti dall'avere due rami di rilascio. Imparare a proteggerti dagli aggiornamenti che rompono la retrocompatibilità. Ma la cosa principale è: non puoi evitare una conversazione difficile.

Per la mia esperienza, quando i team diventano grandi, non c'è più la possibilità di tenere in mente l'intero sistema, e questa è la parte più importante. Devi migliorare la visibilità delle discrepanze nel sistema. Devi lavorare attivamente per far sì che i team distolgano lo sguardo dai propri componenti e guardino il lavoro degli altri team e dei loro consumatori.

Sì, puoi creare strumenti che cercheranno di risolvere il problema dei polirepository. Ma la mia esperienza nell'apprendimento della continuous delivery e nell'automazione in grandi aziende mi dice questo: il comportamento predefinito senza l'uso di strumenti aggiuntivi è quello che ti aspetti di vedere. Il comportamento predefinito di un polirepository è l'isolamento, e questo è il punto. Il comportamento predefinito di un monorepository è la responsabilità condivisa e la trasparenza, e questo è il punto. In entrambi i casi, intendo creare uno strumento che aiuti a smussare gli angoli. Come manager, scelgo sempre il monorepository perché gli strumenti devono rafforzare la cultura che desidero, e la cultura nasce da piccole decisioni e dal lavoro quotidiano del team.

Solo gli utenti registrati possono partecipare al sondaggio. Accedi, per favore.

Chi sono i fanatichi più accaniti? Sostenitori:

  • Monorepo

  • Rust

  • Sondaggio errato / entrambi

Hanno votato 33 utenti. 13 utenti hanno scelto di astenersi.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster