Come eseguire VCS su un refactoring "atomico" su larga scala?

4

Quando si esegue la migrazione di un progetto da una libreria molto usata X a un'altra libreria Y che è essenzialmente equivalente ma non ha la stessa API, potrebbe essere necessario fai molti cambiamenti. Nel caso in cui sto lavorando in questo momento, addition500 aggiunte e cancellazioni: non impossibile, ma direi che sono troppe per un singolo commit! (In passato ho avuto un'esperienza piuttosto negativa con commit troppo grandi e conflitti di fusione in corso.)

Ma con solo un sottoinsieme delle modifiche apportate, il progetto non viene compilato. Inoltre, i cambiamenti sono essenzialmente meccanici: per ogni funzione foo precedentemente utilizzata da X , c'è una foo' in Y che fa esattamente la stessa cosa (nonostante abbia un nome diverso) o solo un wrapper molto semplice deve essere scritto.

È sensato prima apportare tutte le modifiche e inserirle in un singolo commit, o dovrei cercare di dividerlo in qualche modo? Come viene gestito questo quando più persone stanno lavorando al refactoring e non puoi davvero aspettare fino a quando non è tutto pronto prima di interagire tramite VCS - "commit monouso" che vengono schiacciati prima di unirsi al ramo principale, o qualcos'altro?

    
posta leftaroundabout 11.09.2016 - 16:59
fonte

2 risposte

5

La divisione di un grosso commit in quei commit a singolo uso schiacciati non ha importanza dal punto di vista dei conflitti di fusione downstream - dal momento che vengono compressi, continueranno a essere visualizzati come un singolo commit di grandi dimensioni in fase di unione, anche in conflitto risoluzione.

Userei sempre wrapper (invece di riutilizzare solo i nomi delle funzioni). Ognuno di tutti i wrapper incorporerebbe un controllo singolo / centrale in grado di cambiare l'intero prodotto tra il refactoring before e after . L'interruttore rimane nella posizione before nel VCS fino al completamento del refactoring. Gli sviluppatori che lavorano al refactoring possono trasformarlo in after nelle aree di lavoro per lavorare sulle parti del refactoring e riportarlo a before durante il commit del lavoro.

L'aggiunta o la rimozione di wrapper o invocazioni di wrapper può essere eseguita in commit piccoli / incrementali, se necessario.

Questo approccio consente sia al lavoro regolare che al refactoring di accadere nello stesso ramo, eliminando la necessità di andare in un ramo separato solo ai fini del refactoring, quindi elimina del tutto l'unione.

Il grande vantaggio è che puoi combinare 2 diverse esecuzioni CI (una per ogni posizione dell'interruttore di controllo) e ottenere una misura molto precisa di quanto vicino sia il refactoring target. Ciò sarebbe praticamente impossibile se si usasse un ramo separato poiché una fusione di filiali sarebbe ancora dispersa (sempre indeterminata, specialmente per un grande ramo di refactoring).

Il paragrafo precedente presuppone un sistema CI in grado di applicare una piccola modifica VCS (capovolgere l'interruttore di controllo) all'inizio della sua esecuzione. Se tale sistema CI non è disponibile, è possibile utilizzare un piccolo ramo, che contiene solo il cambiamento di interruttore di comando capovolto. Tale ramo può essere automaticamente sincronizzato dopo ogni commit nel ramo principale (dovrebbe essere una sincronizzazione banale). Sì, un'imminente fusione di filiali sarebbe ancora eccezionale, ma è deterministica: un cambiamento di un solo elemento.

Quando il livello di qualità after misurato è accettabile e viene presa la decisione di accettare il refactoring, il controllo passa a after nel sistema VCS e il lavoro di pulizia può iniziare: rimuovere i wrapper, la vecchia libreria e infine l'interruttore di controllo stesso (che può anche essere eseguito in piccoli commit incrementali).

    
risposta data 11.09.2016 - 18:28
fonte
1

Se la transizione avrà un ordine di mesi, è meglio trovare un modo per progettare il software in modo da poter avere entrambe le librerie nel ramo principale contemporaneamente e fare una transizione graduale. Utilizzare wrapper o flag di funzionalità o un modello di microservizio. Questo richiede più tempo, ma ne vale la pena in termini di stabilità.

Se ci vorranno un paio di settimane o meno, è meglio fare un ramo di funzionalità normale. Quando lavoro su compiti simili con un collega, accoppiamo il programma per la creazione iniziale del ramo, la sostituzione della libreria e il fixing dei test di integrazione e unità di un file. Quindi spingiamo il ramo e suddividiamo il resto del lavoro, effettuando i commit dopo ogni modifica del file.

Per quanto riguarda la fusione dei conflitti, l'importante è che le fusioni avvengano frequentemente, non importa in particolare quale direzione. Se unisci da master al tuo branch di funzionalità una volta al giorno, non avrai una grande fusione spaventosa alla fine. È sempre lo stesso numero complessivo di conflitti di unione. È inevitabile. Si è appena diffuso nelle poche settimane in cui stai lavorando alle tue modifiche, e sta succedendo più vicino a quando hai cambiato quel file.

    
risposta data 12.09.2016 - 04:03
fonte

Leggi altre domande sui tag