Con questo articolo vorrei analizzare la pratica del version control, sicuramente il primo, fondamentale passo da compiere quando si vuole iniziare a sviluppare codice in maniera professionale.
Partiamo da zero, il versionamento del codice consente innanzitutto di mantenere una memoria storica del proprio lavoro. Quante volte vi è capitato di iniziare a programmare una feature , solo per scoprire pochi giorni dopo di esservi infilati in un vicolo cieco ed impiegare ore per “disfare” tutte le modifiche e tornare allo stadio iniziale? Avendo a disposizione uno storico dei cambiamenti del vostro codice, tornare indietro ad un qualsiasi istante temporale diventa una questione di pochi click piuttosto che una sudata sfida alla vostra buona memoria.
Altro scenario: il vostro prodotto naviga ormai sicuro verso il rilascio della versione 3.5 quando un vostro importantissimo cliente vi chiede un bugfix urgentissimo… sulla versione 1.7 installata presso di lui. Il cliente non si può contraddire, un upgrade all’ultima versione è impensabile… Che fare?
Anche in questo caso il version control ci può salvare la vita. Oltre infatti a mantenere uno storico dei cambiamenti, ci permette anche di gestire anche la non-linearità degli stessi ovvero le loro diramazioni (branch) e il ricondurre all’occorrenza tali modifiche sul filone principale (merge)
L’Ultimo scenario tipo riguarda il lavoro quotidiano di un team di sviluppatori. Mr.A sviluppa una feature a lui assegnata, la impacchetta e la carica sul server di test. Nel frattempo anche Mr.B completa il suo lavoro, lo carica sul server di test ma, non essendo a conoscenza del lavoro di A lo sovrascrivere parzialmente. Morale: Mr.A perde due ore di tempo per capire come mai la sua feature abbia smesso di funzionare di punto in bianco e, una volta scoperta la causa, sfoga il suo malcontento su B. che si difende accusandolo a sua volta di non aver comunicato a nessuno ciò su cui stava lavorando.
Se mai avete lavorato in un team saprete benissimo che questo scenario è tutt’altro che surreale, anzi piuttosto semplicistico visto che spesso i team sono composti da un numero molto maggiore di persone, magari anche dislocate in uffici differenti.
In questo caso il sistema di versionamento fornisce un tracciamento del lavoro di ciascun membro del team ed una versione di riferimento centralizzata e ufficiale a cui confrontarsi prima di iniziare a lavorare su qualcosa di nuovo e prima di ogni rilascio.
Nel nostro caso Mr.A prima di iniziare avrebbe dovuto sincerarsi di scaricare l’ultima versione del codice e avrebbe caricato le sue modifiche sul sistema prima di rilasciare il tutto sul server di test, rendendole così “ufficiali”. Sull’altro fronte Mr.B avrebbe dovuto , prima di fare lo altrettanto, verificare che nessun altro avesse caricato delle modifiche mentre terminava il suo lavoro, in questo caso si sarebbe accorto del lavoro di A e lo avrebbe integrato all’interno del suo prima di caricare il tutto sul server di test.
Indipendentemente dagli scenari il sistema di versionamento ha creato un punto di riferimento per chi sviluppa, supportandolo nel suo lavoro, organizzando i vari filoni di sviluppo e migliorando le sinergie interne ai team.
Notate inoltre come finora non si sia fatto nessun riferimento ad un software specifico di versionamento.
Esistono infatti decine di diversi sistemi (potete trovare su wikipedia un’utile matrice di confronto tra le diverse alternative), ma prima di gettarvi a capofitto nella loro installazione ricordatevi che è molto più importante definire la politica di utilizzo del sistema stesso all’interno del vostro processo di sviluppo del codice.
Prima di iniziare stendente alcune regole di utilizzo, la struttura e il tipo di storico che volete impostare sul vostro sistema. Condividete questo primo draft con i diversi team di sviluppo e raccogliete i feedback, sicuramente vi renderete contro di aver scordato alcuni scenari o alcune necessità. Aggiornate il documento e iterate il procedimento fino ad aver ottenuto un risultato soddisfacente, ricordatevi, non è quasi mai possibile accontentare tutti, ma un Ottimo Paretiano sarebbe già una gloriosa conquista 😉
Ricordatevi soprattutto di definire:
- La politica di Commit: cosa volete ottenere in seguito ad un nuovo caricamento di codice? Per voi il sistema di versionamento è un semplice backup del lavoro, o volete che ogni commit rappresenti un immagine funzionante (o almeno compilabile) del vostro codice? Sepenate di realizzare un sistema di continuous integration, definire bene questo punto sarà fondamentale in quanto sarà l’evento scatenante di diverse procedure automatiche.
- La politica di Branching: indispensabile in progetti medio-grandi o condivisi tra più sviluppatori. Che struttura deve avere il flusso di sviluppo? Possono coesistere più versioni live e/o di development? Chi può creare nuovi rami e chi può re-integrarli nel flusso principale? Come gestire release e bugfix? Anche in questo caso in un ottica di continuous integration diventa fondamentale organizzare le diverse versioni dello stesso codice (ad esempio una libreria) a seconda dei rami da cui proviene in modo da non creare confusione o sovrapposizioni.
- La politica di Merging: la fase di integrazione di sviluppi paralleli è una delle più delicate da gestire, sia a livello pratico, come corretta fusione di due estratti di codice senza introduzione di bug, sia a livello di team management per non creare tensione tra i rispettivi sviluppatori. Alcuni tool potrebbero agevolarvi a livello di comunicazione, tracciabilità o addirittura di gestione del merge vero e proprio, ma ricordatevi che dovrete essere voi in primis a definire i dettagli. Spendete anche due righe sulle cosiddette Roles & Resposibilities, cercando di definire chi dovrebbe occuparti di cosa in caso di merge particolarmente delicati e complessi, in modo da evitare drammatici scaricabarile 😉
- La politica di Tagging: come creare una baseline, ovvero una sorta di istantanea immodificabile del nostro codice che funga da punto di riferimento per i rilasci del codice in produzione. Tali baseline dovrebbero essere rese non alterabili, e spesso questo richiede dello sviluppo a seconda del tipo di sistema di versionamento che si intende adottare. Cercate di definire una naming convention per i tag che vi permetta di gestire rilasci di Major/minor version, bugfix o quant’altro possa rientrare nelle vostre necessità
- Qualsiasi cosa si renda necessario definire per avere un quadro completo del processo e delle (vostre!) best practices e agevolare chiunque inizi ad utilizzare il sistema per la prima volta, in modo da rendere il passaggio il più indolore possibile.
Formalizzare e soprattutto comunicare tutte queste informazioni all’intero team di sviluppo è un passo importantissimo, ogni membro di ogni team deve essere messo al corrente di come deve operare per evitare incomprensioni ed errori di utilizzo dello strumento.
Ricordate sempre di sottolineare le necessità e i vantaggi di ogni decisione, in modo da non farle “calare dall’alto” (pratica che spesso aumenta la resistenza da parte degli elementi più senior dei team, aumentando l’inerzia del processo di rollout del nuovo sistema) ma rendere il team partecipe del loro primo passo in un approccio che migliorerà e ottimizzerà il lavoro di tutti. Siate a vostra volta pronti ad assorbire critiche (costruttive) e cercate di analizzare tutte le singolarità che si presenteranno, spesso molti problemi si possono facilmente ricondurre a pratiche standard, ma qualche volta serve maggiore tempo e pazienza da entrambe le parti per arrivare alla soluzione migliore.
Nei prossimi articoli cercheremo di analizzare qualche approccio alle diverse problematiche oltre all’installazione di alcuni dei sistemi di versionamento più popolari.
A presto!