Come gestisci l'integrazione del codice da più rami / sviluppatori ogni sprint?


42

Sono appena uscito da una chiamata retrò in cui gli sviluppatori hanno espresso preoccupazione per l'integrazione delle loro storie nel ramo principale ogni sprint. Tutti gli sviluppatori codificano tutti all'interno del proprio ramo e verso la fine dello sprint si uniscono tutti in un ramo principale.

Quindi, uno sviluppatore (di solito lo stesso) ha il compito di assicurarsi che tutto sia ben integrato con il codice di altri sviluppatori (la maggior parte delle modifiche si trovano nella stessa pagina. Ad esempio, una storia di visualizzazione dei dati, una storia di filtro dei dati e un indicatore SLA).

Come possiamo ridurre questo onere e semplificare l'unione del nostro codice? Dal mio punto di vista, se l'OP o l'SM danno priorità alle storie in modo più efficiente, quindi non abbiamo questo tipo di dipendenze nello stesso sprint, potremmo risolvere alcuni dei problemi. Come lo affrontano tutti gli altri? O è solo una parte del processo?


18
Non hai un ramo di sviluppo in cui viene effettuata l'integrazione continua?
Kayaman,

13
Sono qui con Kayaman, la migliore pratica per questo è implementare l'integrazione continua.
RandomUs1r

27
Buon Merge Day! Ogni volta che il tuo problema è troppo simile a qualcosa su The Daily WTF, sai che sei nei guai.
user3067860

Unisci in anticipo, unisci spesso: {scrivi il codice di test più piccolo che fallirà (rosso), scrivi il codice di produzione più piccolo che passerà (verde), refactor, ritesterà, unirà} quando non sarà finito.
ctrl-alt-delor

1
Vince il primo check-in! Non essere mai l'ultimo! :-)
ChuckCottrill

Risposte:


88

Se stai usando Git, ogni sviluppatore trarrebbe dal developramo nel proprio ramo di funzionalità in modo da assicurarsi che non si allontanino troppo dalla linea di base corrente. Possono farlo quotidianamente, in modo che le attività che richiedono più di un paio di giorni rimangano sincronizzate e uniscano i problemi mentre sono ancora piccoli.

Quando lo sviluppatore ha terminato il proprio lavoro, crea una richiesta pull . Una volta approvato, viene unito al developramo.

Il developramo dovrebbe sempre avere un codice funzionante ed essere pronto per il rilascio in qualsiasi momento. Quando si effettivamente fare un comunicato, si uniscono developin mastere tag esso.

Se si dispone di un buon server di integrazione continua, verrà creato ogni ramo quando vengono archiviate le modifiche, in particolare per le richieste pull. Alcuni server di compilazione si integrano con il tuo server Git per autorizzare automaticamente o disapprovare una richiesta pull se la compilazione fallisce o i test automatici falliscono. Questo è un altro modo per trovare potenziali bug di integrazione.


73
La parte importante (che è solo implicita nella tua risposta) è che i rami dovrebbero essere uniti non appena sono pronti, in genere con solo 1 - 5 commit, e non solo alla fine dello sprint. Un ramo per funzione / storia, non un ramo per sviluppatore. Ciò richiede che le storie siano veramente minuscole, cioè che durino al massimo due giorni.
amon,

@amon, d'accordo. Aggiunte le parole "ramo delle caratteristiche", ma cercando di mantenere questa risposta abbastanza piccola. Ci sono molti buoni articoli che approfondiscono questo processo.
Berin Loritsch,

5
Non rimanere isolato sul tuo ramo. Ecco come inizia l'unione dell'inferno. Utilizzare lo sviluppo della linea principale, isolare il work-in-progress dietro gli interruttori di funzionalità o altre configurazioni di runtime.
Rob Crawford,

3
@Zibbobz Il mio team utilizza esplicitamente "Feature Branches" per coloro che sono sostanzialmente trattati come il branch di sviluppo, ma solo per richieste pull e commit relativi a quel cambiamento. In generale, a seconda di quanto tempo deve rimanere separato, ogni pochi giorni qualcuno unirà le modifiche sviluppandosi nella funzione e risolverà eventuali problemi. In questo modo i rami sono il più simili possibile quando arriva il momento di unirsi. Come nota, questo è solo per grandi cambiamenti di rottura
reffu

9
"isolare work-in-progress dietro toggle funzionalità o altra configurazione di runtime" Hai appena evitato di unire l'inferno andando invece a configurarlo. "Unisci l'inferno" è solo un problema per uno sviluppatore alla volta e può essere facilmente evitato semplicemente sincronizzandosi regolarmente, avere tonnellate di configurazione effimera è un inferno per tutti i futuri sviluppatori per sempre.
Cubico

23

Ho lavorato in una squadra in cui abbiamo lottato con lo stesso problema. Abbiamo scoperto che meno tempo abbiamo trascorso prima dell'integrazione, meno è diventato difficile. So che la maggior parte delle persone che insegnano l'integrazione continua parlano di impegni ogni pochi minuti - probabilmente ci siamo impegnati circa ogni ora.

Abbiamo anche scoperto che il solo edificio non era abbastanza. Avevamo bisogno di un buon livello di copertura dei test per assicurarci di non infrangere accidentalmente il codice degli altri.


2
Questa è anche la mia esperienza. Non importa quanto spesso ti impegni, ma una volta impegnati rapidamente l'integrazione / fusione del commit consente di risparmiare molto sforzo. Una volta ero su un progetto in cui avevamo tre rami di sviluppo divergenti, ognuno dei quali aveva mesi di lavoro. Unirli non è stato divertente. Ho imparato molto da questo errore :)
Amon,

4
Sì, questo significa "integrazione continua"! Integra continuamente le tue modifiche con le modifiche degli altri sviluppatori!
Rob Crawford,

@Rob, d'accordo. La mia affermazione non intendeva suggerire che l'integrazione continua non sia, beh, continua. Solo che non siamo riusciti a realizzare l'ideale e abbiamo comunque visto molti vantaggi avvicinarci ad esso.
Daniel,

12
  • Mantieni i tuoi rami di breve durata (sembra che tu lo stia già facendo).
  • Lascia che i risultati dei test parlino da soli.
  • Non aspettare la fine dello sprint.

Non è nemmeno necessario abbonarsi a TDD per questo. Tutto ciò di cui hai bisogno sono alcuni test che dimostrano che le funzionalità dei tuoi sviluppatori funzionano correttamente. Questi potrebbero includere test unitari e test di integrazione, ma idealmente saranno un paio di test end-to-end automatizzati delle caratteristiche critiche. Elementi del pacchetto di regressione standard.

Quindi, una volta completata l'unione, è possibile controllare insieme il rapporto del test di automazione e verificare che tutto sia stato integrato correttamente.

Concordo con una delle altre risposte in cui l'autore ha dichiarato che Git PRs avrebbe risolto questo problema facendo in modo che ogni sviluppatore unisse il proprio lavoro.

Un altro punto che ritengo sia abbastanza importante da lasciare fino all'ultimo paragrafo. Ti suggerisco di eseguire test manuali sulle tue build notturne, piuttosto che aspettare fino alla fine dello sprint. Gli sviluppatori dovrebbero unirsi non appena la funzionalità è completa in modo che possa essere integrata, distribuita e testata il più presto possibile.


6

non

A seconda della lingua e dei file che stai modificando, potrebbe non avere senso per ogni sviluppatore modificarli nel proprio ramo. Ad esempio, in C # ho scoperto che è meglio che una sola persona modifichi qualsiasi file del designer dell'interfaccia utente alla volta. Si tratta di file generati automaticamente, quindi a volte il codice viene spostato senza motivo apparente, e questo causa il caos della maggior parte degli strumenti di fusione.

Ciò significa che alcune storie potrebbero bloccare altre storie fino a quando il lavoro dell'interfaccia utente non viene completato. E / o, viene creata una nuova storia per il layout dell'interfaccia utente, mentre le altre storie implementano funzionalità. Oppure, forse uno sviluppatore fa funzionare l'intera UI mentre altri implementano le funzionalità di quella UI.

In una nota correlata, se sai che più storie toccheranno tutti gli stessi file, potresti voler evitare di lavorarci tutti contemporaneamente. Non trascinarli tutti nello stesso sprint o non iniziare a lavorarli tutti fino a quando uno o più non sono stati completati.


Onestamente, lo strumento di controllo della versione in uso è più critico per la ramificazione e l'unione riuscite. Anche con il codice C # e presumibilmente il codice WinForms o WebForms con cui devi lavorare in genere non cambia molto . Se lo sono, forse è necessario fare alcuni modelli prima di giocare con il codice. Le UI basate su XAML sono stabili quanto il codice normale e il codice intermedio non è archiviato.
Berin Loritsch,

2
@BerinLoritsch Il codice del designer WinForms può davvero cambiare molto, anche con piccoli cambiamenti visivi. Ho scoperto che le stesse righe di codice sono le stesse, ma l'ordinamento è molto diverso, soprattutto quando più sviluppatori stanno apportando modifiche contemporaneamente. Forse è un problema dello strumento VCS (ne abbiamo usati diversi, forse stiamo usando solo quelli sbagliati), ma per noi è molto più semplice modificare leggermente il nostro processo.
mmathis,

2
@BerinLoritsch Devo secondare mmathis qui almeno per i moduli di vincita (moduli web mai usati). Il designer dell'interfaccia utente di winforms ama riordinare casualmente tutto il codice nel file designer in risposta a una banale modifica da qualche parte nel modulo. A meno che non annulli manualmente i riordini prima di ogni commit (qualcosa che può facilmente essere di 10 o 15 minuti in un modulo complesso), la cronologia del file di progettazione è assolutamente inutile e se 2 persone lavorano contemporaneamente sull'interfaccia utente del modulo, un conflitto di unione dall'inferno. Il blocco è generalmente un'opzione terribile, ma con le forme di vittoria è davvero il meno cattivo.
Dan Neely,

@DanNeely, questo è solo uno dei motivi per cui il nostro team è emigrato dal codice WinForms. Un altro motivo è che il designer è terribilmente fragile e alcune delle nostre forme complesse non possono essere modificate visivamente comunque. Alla fine abbiamo dovuto apportare modifiche direttamente nel codebehind - probabilmente perché non ricordo troppo sconvolgimento lì. Questo e i nostri utenti che lavorano con display ad alta densità ci hanno davvero spinti a WPF. Un processo doloroso con un'alta curva di apprendimento, ma una bella ricompensa alla fine. La maggior parte delle storie nel backlog riguardava comunque parti diverse dell'app.
Berin Loritsch,

@BerinLoritsch stesso qui. I moduli Win hanno pagato gran parte delle mie bollette per quasi un decennio nel mio lavoro precedente, ma sarò abbastanza felice di non toccarlo mai più in futuro.
Dan Neely,

2

Un altro possibile approccio per evitare fusioni tardive e di grandi dimensioni sono i flag delle funzionalità : proteggi le tue modifiche con un flag configurabile (idealmente dinamicamente) che impedisce loro di diventare attivi prima del previsto.

Ciò consente di unire le modifiche all'inizio mastero al ramo di sviluppo congiunto senza interrompere nulla. Altri sviluppatori possono quindi ricollegare questi cambiamenti ai loro rami delle caratteristiche (o ridisporre i loro rami di conseguenza).

Come hanno già sottolineato le altre risposte, questo dovrebbe essere combinato con una soluzione di integrazione continua.

I flag delle caratteristiche offrono ulteriori vantaggi (ad esempio, semplificano l'esecuzione dei test A / B). Vedi questo articolo di Martin Fowler per maggiori informazioni.


0

Stiamo seguendo un approccio di ramo di sviluppo separato per ciascuna funzionalità, quindi uniamo i rami a un ramo di controllo qualità per testare in un ambiente di test di integrazione.

Una volta completati i test di regressione e integrazione, spostiamo facilmente le funzioni pronte per essere avviate nel ramo di rilascio.

Se tutto va bene, uniamo il ramo di rilascio al ramo principale.


0

Per dirla semplicemente, impegnarsi e fondersi spesso riduce la finestra di opportunità per unire i conflitti e ridurrà notevolmente i conflitti. L'altra parte è infatti pianificata dal responsabile, che può ulteriormente garantire che il lavoro scorra senza intoppi.

Le altre risposte forniscono alcune informazioni dettagliate sulle migliori pratiche per gli commit e semplicemente seguendo quelle probabilmente ridurrete la stragrande maggioranza dei problemi di unione. Un maggior numero di fusioni è quasi certamente una necessità, ma per un team più piccolo, il tuo approccio filiale per persona probabilmente funziona abbastanza bene. Ovviamente, non fa male (molto) entrare in pratiche più estensibili!

Tuttavia, nessuno sembra aver affrontato una delle domande più significative: cosa fare quando si toccano tutti le stesse aree di codice. È qui che è utile avere un lead che abbia familiarità con la base di codice e in grado di riconoscere le dipendenze di diverse attività. Se non orchestrano i tempi del lavoro e gli impegni, probabilmente finirai per unire i conflitti e la risoluzione riga per riga. Organizzare i compiti \ i tempi è molto più difficile con una squadra più grande, ma con una squadra piccola è possibile identificare questi compiti in conflitto. Il lead potrebbe quindi spostare tutte le attività correlate allo stesso ingegnere, per evitare del tutto il conflitto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.