La traduzione dell'articolo è preparata per gli studenti del corso nel progetto educativo OTUS.
Dovete scegliere un monorepo, perché il comportamento che favorisce nei vostri team è la trasparenza e la responsabilità collettiva, soprattutto con la crescita delle squadre. In ogni caso dovrete investire in strumenti, ma è sempre meglio quando il comportamento di default è quello che volete vedere nei vostri team.
Perché ne parliamo?
Matt Klein ha scritto un articolo (nota del traduttore: traduzione su Habr ). Mi piace Matt, penso che sia molto intelligente e dovete leggere il suo punto di vista. Inizialmente ha pubblicato un sondaggio su Twitter:
Traduzione:
In questo giorno di Capodanno discuterò di quanto siano ridicoli i monorepo. Il 2019 è iniziato in modo impercettibile. In questo spirito vi propongo un sondaggio. Chi sono i grandi fan? Sostenitori:
— Monorepo
— Rust
— Sondaggio errato / entrambi
La mia risposta è stata: «Sono letteralmente entrambe queste persone». Invece di parlare di quanto sia una droga Rust, vediamo perché penso che si sbagli sui monorepo. Un po' su di me. Sono il direttore tecnico di Chef Software. Abbiamo circa 100 ingegneri, un codice base di circa 11-12 anni e 4 prodotti principali. Parte di questo codice è in un polyrepo (la mia posizione di partenza), parte è in un monorepo (la mia posizione attuale).
Prima di cominciare: ogni argomento che presento qui sarà applicabile a entrambi i tipi di repository. Secondo me, non ci sono motivi tecnici per cui dovreste scegliere un tipo di repository rispetto all'altro. Potete far funzionare qualsiasi approccio. Sono felice di parlarne, ma non sono interessato a motivi tecnici artificiali per cui uno sia superiore all'altro.
Sono d'accordo con la prima parte del punto di vista di Matt:
Perché su larga scala un monorepo affronterà tutti gli stessi problemi che affronta un polyrepo, ma vi spingerà a una forte coesione del codice e richiederà sforzi incredibili per aumentare la scalabilità del vostro sistema di controllo versione.
Dovrete affrontare problemi simili indipendentemente dal fatto che scegliate un monorepo o un polirepo. Come rilasciate le versioni? Qual è il vostro approccio agli aggiornamenti? Compatibilità retroattiva? Dipendenze incrociate tra i progetti? Quali stili architettonici sono accettabili? Come gestite la vostra infrastruttura di build e test? La lista è infinita. E dovrete risolverli tutti man mano che crescete. Non esiste il formaggio gratuito.
Penso che l'argomento di Matt somigli ai punti di vista condivisi da molti ingegneri (e manager) che rispetto. Questo avviene dal punto di vista di un ingegnere che lavora su un componente o di un team che lavora su un componente. Sentirete affermazioni del tipo:
- Il codice è ingombrante — non ho bisogno di tutta questa spazzatura.
- È più difficile da testare, perché devo controllare tutta questa spazzatura che non mi serve.
- È più complicato lavorare con dipendenze esterne.
- Ho bisogno dei miei sistemi di gestione delle versioni virtuali.
Senza dubbio, tutti questi punti sono giustificati. Questo accade in entrambi i casi — in un polirepo ho la mia spazzatura, oltre a quella necessaria per la build... Potrei aver bisogno anche di altra spazzatura. Quindi io 'semplicemente' creo strumenti che fanno il checkout dell'intero progetto. Oppure creo un finto monorepo con sottocontrolli. Potremmo discuterne per tutta la giornata. Ma penso che l'argomento di Matt trascuri la ragione principale che ho molto fortemente rovesciato a favore del monorepo:
Favorisce la comunicazione e mette in evidenza i problemi
Quando separiamo i repository, creiamo di fatto un problema di coordinazione e trasparenza. Questo corrisponde a come pensiamo ai team (soprattutto a come li vedono i singoli membri): siamo responsabili per un componente specifico. Lavoriamo in relativa isolamento. I confini sono stabiliti nel mio team e nel (-i) componente(-i) su cui lavoriamo.
Completando l'architettura, un solo team non può più gestirla da solo. Molti pochi ingegneri riescono a mantenere l'intero sistema a mente. Supponiamo che tu stia gestendo un componente comune A, utilizzato dai team B, C e D. Il team A effettua un refactoring, migliora l'API e cambia anche l'implementazione interna. Di conseguenza, le modifiche non sono retrocompatibili. Quale consiglio daresti?
- Trova tutti i posti in cui viene utilizzata la vecchia API.
- Ci sono posti in cui la nuova API non può essere utilizzata?
- Puoi correggere e testare altri componenti per assicurarti che non si rompano?
- Possono questi team controllare le tue modifiche proprio ora?
Nota che queste domande non dipendono dal tipo di repository. Dovrai trovare i team B, C e D. Dovrai parlarne con loro, capire i tempi e le loro priorità. Almeno speriamo che tu lo faccia.
In realtà, nessuno vuole occuparsene. È molto meno coinvolgente che semplicemente sistemare una dannata API. Tutto ciò è umano e complicato. In un polo repository puoi semplicemente apportare modifiche, farle revisionare a chi lavora su quel componente (probabilmente non B, C o D) e andare avanti. I team B, C e D possono semplicemente rimanere sulla loro attuale versione. Si aggiorneranno quando realizzeranno la tua genialità!
Nel monorepository, la responsabilità si sposta per default. Il team A modifica il proprio componente e, se non fa attenzione, rompe immediatamente B, C e D. Questo porta B, C e D alla porta di A, chiedendosi perché il team A abbia rotto la build. Questo insegna ad A che non possono ignorare la mia lista sopra. Devono parlare di ciò che intendono fare. Possono B, C e D procedere? E se B e C possono, ma D fosse strettamente legato a effetti collaterali del comportamento del vecchio algoritmo?
Poi dobbiamo parlare di come uscirne:
- Supporto per più API interne, con l'algoritmo vecchio contrassegnato come obsoleto, finché D non può smettere di usarlo.
- Supporto per più versioni di rilascio, una con l'interfaccia vecchia, una con quella nuova.
- Ritardo del rilascio delle modifiche A finché allo stesso tempo B, C e D non possono accettarlo.
Supponiamo di aver scelto 1, diversi API. In questo caso abbiamo due pezzi di codice. Uno vecchio e uno nuovo. È piuttosto comodo in alcune situazioni. Ritorniamo il codice vecchio, lo contrassegniamo come obsoleto (deprecated) e coordiniamo il piano per la sua rimozione con il team D. È sostanzialmente identico sia per i mono-repository che per i poly-repository.
Per rilasciare diverse versioni abbiamo bisogno di un ramo. Ora abbiamo due componenti — A1 e A2. I team B e C utilizzano A2, mentre D utilizza A1. Dobbiamo assicurarci che ogni componente sia pronto per il rilascio, perché prima che D possa avanzare, potrebbero essere necessarie aggiornamenti di sicurezza e correzioni di altri bug. Nel poly-repository possiamo nascondere questo in un ramo a lungo termine, che si sente bene. Nel mono-repository forziamo la creazione di codice in un nuovo modulo. Il team D dovrà comunque apportare modifiche al componente "vecchio". Ognuno può vedere il costo che stiamo pagando qui: ora abbiamo il doppio del codice e qualsiasi correzione di bug applicata a A1 e A2 deve essere applicata a entrambi. Con l'approccio dei rami nel poly-repository, questo è nascosto dietro il cherry-pick. Consideriamo il costo minore, perché non c'è duplicazione. Da un punto di vista pratico, il costo è lo stesso: dovrete costruire, rilasciare e mantenere due basi di codice, fondamentalmente identiche, finché non potrete rimuovere una di esse. La differenza è che nel mono-repository questo dolore è diretto e in vista. È ancora peggio, e questo è positivo.
Finalmente, siamo arrivati al terzo punto. Ritardo nel rilascio. È possibile che le modifiche apportate da A migliorino la vita del team A. È importante, ma non urgente. Possiamo semplicemente ritardare? Nel monorepository stiamo spingendo per fissare l'artefatto. Ovviamente, ne parliamo con il team D. Rimanete semplicemente sulla vecchia versione fino a quando non recuperate! Questo porta a una mentalità imprudente. Il team A continua a lavorare sul proprio componente, ignorando il fatto che il team D utilizza una versione sempre più obsoleta (è un problema del team D, sono sciocchi). Nel frattempo, il team D parla male dell'atteggiamento irrispettoso del team A nei confronti della stabilità del codice, se ne parla anche. Passano mesi. Alla fine, il team D decide di esaminare la possibilità di un aggiornamento, ma le modifiche in A sono aumentate. Il team A ricorda a malapena quando e come hanno rotto D. L'aggiornamento è più doloroso e richiederà più tempo. Cosa che lo spinge ulteriormente verso il basso nella lista delle priorità. Fino al giorno in cui non abbiamo un problema di sicurezza in A, cosa 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 e prepararlo per il rilascio. Questa è de facto una scelta che le persone fanno, ed è senza dubbio la peggiore. Sembra che questo vada bene sia per il team A che per il team D, finché possiamo ignorarci a vicenda.
In un monorepo, il terzo non è davvero un'opzione. Sei costretto a gestire la situazione in uno dei due modi. Devi vedere i costi di avere due rami di rilascio. Imparare a proteggerti dagli aggiornamenti che rompono la compatibilità retroattiva. Ma la cosa principale è: non puoi evitare una conversazione difficile.
Per la mia esperienza, quando i team crescono, non c'è più la possibilità di tenere a mente l'intero sistema, ed è la parte più importante. Devi migliorare la visibilità dei conflitti all'interno del sistema. Devi lavorare attivamente per far sì che i team stacchino lo sguardo dai propri componenti e guardino al lavoro degli altri team e dei consumatori.
Sì, puoi creare strumenti che tenteranno di risolvere la questione dei polirepository. Ma la mia esperienza nell'apprendimento della consegna continua (continuous delivery) e nell'automazione in grandi imprese mi dice questo: il comportamento predefinito senza l'uso di strumenti aggiuntivi è quello che ci si aspetta di vedere. Il comportamento predefinito dei polirepository è l'isolamento, ecco il succo. Il comportamento predefinito dei monorepository è la responsabilità condivisa e la trasparenza, ecco il succo. In entrambi i casi, intendo creare uno strumento che permetta di smussare gli angoli. Come responsabile, sceglierò sempre 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. , per favore.
Chi sono i fanatici maggiori? Sostenitori:
Monorepo
Rust
Sondaggio errato / entrambi
Hanno votato 33 utenti. 13 utenti si sono astenuti.
Fonte: habr.com
