Università Politecnica delle Marche Facoltà di Ingegneria Corso di Laurea Specialistica in Ingegneria Informatica Dipartimento di Ingegneria dell'Informazione CONTINUOUS INTEGRATION IN UNA WEB AGENCY Laureando: Giorgio Mandolini Relatrice: Prof.ssa Claudia Diamantini Anno Accademico 2010/2011 L’entusiasmo è quando le gambe iniziano il primo passo ed il cuore è già a destinazione Indice Indice 1 – Introduzione............................................................................................................... 1 1.1 Obiettivi...................................................................................................................1 1.2 Trattazione degli argomenti ....................................................................................2 2 – La Continuous Integration....................................................................................... 3 2.1 – Definizione ed obiettivi........................................................................................3 2.2 – Ciclo di vita del software..................................................................................... 5 2.2.1 – Modello di sviluppo Waterfall...................................................................... 5 2.2.2 – Modello di sviluppo Iterativo....................................................................... 7 2.2.3 - Continuous Integration e modello di sviluppo iterativo................................7 2.3 – Panoramica di un ambiente di Continuous Integration...................................... 10 2.4 – Best practices della Continuous Integration.......................................................12 i Indice 2.4.1 – Utilizzo di un sistema di controllo versione............................................... 12 2.4.2 – Centralizzare tutto il necessario................................................................. 13 2.4.3 – Automatizzare le build................................................................................14 2.4.4 – Build testate automaticamente....................................................................16 2.4.5 – Commit frequenti........................................................................................17 2.4.6 - Eseguire delle build private nelle workstation locali.................................. 18 2.4.7 – Non inviare codice diffettoso..................................................................... 20 2.4.8 – Eseguire una build ad ogni cambiamento.................................................. 20 2.5.9 – Non scaricare codice difettoso....................................................................21 2.4.10 – Riparare immediatamente le build difettose............................................. 21 2.5.11 – Trattare il database come il codice sorgente............................................ 22 2.6.12 – Garantire un feedback rapido ed efficiente...............................................24 2.5 – Vantaggi offerti ................................................................................................. 26 2.5.1 – Rilasciabilità del software.......................................................................... 26 2.5.2 – Rivelazione degli errori.............................................................................. 27 2.5.3 – Visibilità di progetto ed aumento della comunicazione............................. 28 2.5.4 – Qualità del codice.......................................................................................28 3 – Applicazione della metodologia: analisi iniziale................................................... 30 3.1 – Analisi della situazione iniziale......................................................................... 30 3.1.1 – Prima dell'introduzione del sistema di controllo versione...........................31 3.1.2 – Dopo l'introduzione del sistema di controllo versione................................32 ii Indice 3.2 – Analisi delle mancanze...................................................................................... 34 3.2.1 – Environment eterogenei..............................................................................34 3.2.2 – Mancanza di controllo sull'integrazione.....................................................37 3.2.3 – Mancanza di visibilità di progetto.............................................................. 37 3.2.4 – Nessuna integrazione del database.............................................................38 3.2.5 – Difficoltà di ingresso nel progetto..............................................................39 3.2.6 – Difficoltà nel rilascio di demo................................................................... 39 3.2.7 – Difficoltà di rilascio dell'applicazione....................................................... 39 4 – Progettazione del cambiamento..............................................................................41 4.1 – Scelta degli strumenti......................................................................................... 41 4.1.1 – Sistema di controllo versione...................................................................... 42 4.1.2 – Web Server e DBMS...................................................................................42 4.1.3 – Build scripting system................................................................................ 43 4.1.4 – Strumenti di testing.....................................................................................44 4.1.5 – Server di Continuous Integration................................................................46 4.2 – Standardizzazione delle workstation e dei progetti............................................ 46 4.2.2 – Standardizzazione della struttura cartelle...................................................47 4.2.2.1 – _data...................................................................................................47 4.2.2.2 – library.................................................................................................48 4.2.2.3 – _test.....................................................................................................48 4.2.2.4 – web.....................................................................................................48 iii Indice 4.2.2.5 – _xhtml.................................................................................................49 4.2.2 – Comandi fondamentali.............................................................................. 49 4.2.3 – Standardizzazione del database.................................................................. 50 4.3 – Introduzione del build scripting system............................................................. 50 4.3.1 – Il target build...............................................................................................51 4.3.2 – Il target make-sql........................................................................................53 4.3 – Introduzione di uno script di installazione.........................................................54 4.5 – Introduzione dei test...........................................................................................55 4.6 – Installazione del server di Continuous Integration............................................ 58 4.7 – Training del personale........................................................................................59 4.7.1 – Lezioni frontali........................................................................................... 59 4.7.2 – Redazione di documenti operativi.............................................................. 60 4.7.3 – Post sul corporate blog............................................................................... 60 5 – Risultati ottenuti...................................................................................................... 61 5.1 Soluzione del problema degli environment eterogenei..........................................61 5.2 Soluzione del problema di integrazione del codice.............................................. 62 5.3 Soluzione del problema della visibilità di progetto...............................................63 5.4 Soluzione del problema di integrazione del DB................................................... 66 5.5 Soluzione del problema di ingresso al progetto.................................................... 67 5.6 Soluzione del problema delle demo...................................................................... 69 5.7 Futuri sviluppi: automatizzare il deploy............................................................... 69 iv Indice 6 – Bibliografia...............................................................................................................71 6.1 – Letteratura.......................................................................................................... 71 6.2 – Risorse e strumenti.............................................................................................72 v 1 – Introduzione 1 – Introduzione La seguente tesi si occupa di descrivere il lavoro svolto in una web agency 1, presso la quale è stata presa in considerazione l'adozione della pratica della Continuous Integration. Verranno trattate tutte le fasi che hanno contribuito alla realizzazione del lavoro: da uno studio iniziale della metodologia da introdurre, all'applicazione dei cambiamenti necessari al fine di una sua corretta implementazione. 1.1 Obiettivi L'obiettivo principale del lavoro svolto è lo studio e l'implementazione di un sistema informativo che organizzi l'azienda secondo le best practices della Continuous Integration, al fine di migliorare il processo di sviluppo software. Verranno introdotti 1 e-xtrategy s.r.l. – http://www.e-xtrategy.net/ 1 1 – Introduzione strumenti come un sistema di controllo versione ed un server di Continuous Integration, affiancati ad un insieme di regole da rispettare per ottenere il rispetto della pratica ed il raggiungimento dei benefici offerti. 1.2 Trattazione degli argomenti Nel capitolo 2 viene illustrata la Continuous Integration, definendo quali sono i suoi obiettivi ed il problema dell'integrazione del software; viene fornita una panoramica generale di un ambiente tipico di C.I., delle best practices che lo caratterizzano e dei vantaggi promessi dall'utilizzo di questa metodologia. Il capitolo 3 si occupa dell'analisi delle mancanze ed inefficienze riscontrate in azienda: viene fornita una descrizione della metodologia di sviluppo utilizzata prima e dopo l'introduzione del sistema di controllo versione, analizzando i problemi riscontrati dal team di sviluppo in entrambi i casi. Nel capitolo 4 verranno illustrati tutti i cambiamenti necessari al fine di introdurre la Continuous Integration. In questa fase di progettazione saranno motivate le scelte tecniche, secondo due criteri: l'ambito di sviluppo dell'azienda (web application) e l'eventuale preesistenza di strumenti già adatti alla Continuous Integration. Il capitolo 5 descrive i risultati ottenuti a seguito dei cambiamenti introdotti nel capitolo 4, focalizzando l'attenzione, punto per punto, sui problemi riscontrati nel capitolo 3. In questa fase verranno espresse infine delle conclusioni sul lavoro svolto ed eventuali sviluppi futuri. 2 2 – La Continuous Integration 2 – La Continuous Integration In questo capitolo viene illustrata la Continuous Integration, definendo quali sono i suoi obiettivi ed il problema dell'integrazione del software; viene fornita una panoramica generale di un ambiente tipico di C.I., delle best practices che lo caratterizzano e dei vantaggi promessi dall'utilizzo di questa metodologia. 2.1 – Definizione ed obiettivi La Continuous Integration è una pratica emersa nella comunità Extreme Programming (XP)2, ed i principali sostenitori, Martin Fowler3 e Kent Beck4, iniziarono a parlarne intorno al 1999. 2 Extreme Programming – http://www.extremeprogramming.org/ 3 Martin Fowler – http://martinfowler.com/ 4 Kent Beck – http://www.threeriversinstitute.org/Kent Beck.htm 3 2 – La Continuous Integration In accordo con la definizione5 data da Martin Fowler, si può definire la Continuous Integration una pratica di sviluppo software dove i membri di un team integrano il proprio lavoro frequentemente, da una a più volte al giorno. Ogni integrazione deve essere verificata da una build automatizzata, che include dei test, per individuare errori di integrazione il più presto possibile e permettere ad un team di sviluppare software rapidamente. Il problema dell'integrazione non è nuovo nel campo dello sviluppo ed è tanto più complesso quanto più crescono le dimensioni del software e del team che ne è incaricato allo sviluppo: al crescere della complessità, infatti, cresce anche la necessità di integrare e di garantire il corretto funzionamento di tutti i componenti sviluppati dai diversi membri del team. L'obiettivo principale della Continuous Integration è appunto quello di semplificare l'integrazione del software, facendola diventare parte integrante del processo di sviluppo anziché relegarla ad una fase successiva. 5 Continuous Integration, Martin Fowler – http://martinfowler.com/articles/continuousIntegration.html 4 2 – La Continuous Integration 2.2 – Ciclo di vita del software Possiamo mettere a confronto due modelli di processo di svulippo software ed analizzare l'impatto della fase di test/integrazione su ciascuno di essi: • modello tradizionale Waterfall o “A cascata” • modello Incrementale/Iterativo 2.2.1 – Modello di sviluppo Waterfall Figura 2.1 – Modello di sviluppo Waterfall: il processo scorre dal basso verso l'alto, come una cascata. Nel modello di sviluppo waterfall ogni fase produce un output che è l'input della fase successiva. 5 2 – La Continuous Integration L'intero software passa per ciascuna fase: 1. Requirements: viene effettuata la raccolta, l'analisi e la ristrutturazione dei requisiti. Vengono definiti i requisiti non elicitati in fase di raccolta, che può essere eseguita più volte, presso i vari stakeholders del sistema. 2. Design: viene progettato il software, in modo da rispettare i requisiti definiti nello step precedente. In questa fase viene scelta l'architettura, definite le interfacce delle classi e le relazioni tra di esse. 3. Implementation: il team procede con lo sviluppo vero e proprio del software, traducendo in linee di codice quanto progettato in fase di design. 4. Verification: tutti i componenti implementati vengono messi insieme ed il software testato. E' qui che avviene l'integrazione. 5. Maintenance: il software è entrato in produzione, in questa fase si procede al suo mantenimento, come eventuali bug fix o aggiornamenti. 6 2 – La Continuous Integration 2.2.2 – Modello di sviluppo Iterativo Figura 2.2 – Modello di sviluppo Iterativo, il processo evolve all'interno di ciascuna iterazione, a seguito della quale avviene un rilascio di software già funzionante. Nel modello di sviluppo iterativo, si riconoscono fasi simili al modello waterfall, ma in questo caso non si fa passare l'intero software per ogni fase, bensì una sola porzione alla volta. Anche in questo modello ogni fase produce un output che è l'input della fase successiva, con la differenza che al termine di ciascuna iterazione il software sarà aumentato di funzionalità. Ad ogni iterazione si ha una fase di rilascio (deploy) di software già integrato e funzionante. Esclusa la prima iterazione, tutte le successive avranno come input il software già presente ed un insieme di nuovi requisiti da implementare. 2.2.3 - Continuous Integration e modello di sviluppo iterativo Sulla base delle caratteristiche dei modelli di sviluppo precedentemente illustrati, si può 7 2 – La Continuous Integration affermare che la Continuous Integration ben si coniuga con una metodologia incrementale/iterativa. Su questo tipo di modelli di sviluppo infatti, l'integrazione del software è un evento che avviene frequentemente a differenza del modello a cascata, in cui viene fatta solamente al termine dell'implementazione, per poi essere testata nella sua interezza in fase di collaudo e verifica. Il vantaggio di un modello iterativo sta quindi nel costo di gestione dei bug, sia di sviluppo che di integrazione. E' riconosciuto infatti che tale costo è tanto più elevato quanto più tardi viene scoperto. La Continuous Integration ha inoltre come ulteriore scopo quello di individuare eventuali errori ancora prima: questo significa che per rilevare malfunzionamenti non è necessario attendere il termine dell'iterazione o dell'intero processo di sviluppo. Di seguito due grafici qualitativi, per il costo di risoluzione di un bug: Figura 2.3 – Andamento del costo di un bug in funzione del momento di rivelazione, per il modello di sviluppo Waterfall. 8 2 – La Continuous Integration Figura 2.4 – Andamento del costo di un bug in funzione del momento di rivelazione, per il modello di sviluppo Iterativo. Com'è possibile notare, nel caso di un approccio iterativo le tre macro fasi “Requisiti”, “Sviluppo” e “Test” vengono ripetute ad ogni iterazione, portando ai seguenti vantaggi: • Requisiti aggiornati ad ogni iterazione: il cliente può decidere di cambiare requisiti in corso d'opera, senza l'implicazione una completa riscrittura del software. • Sviluppo incrementale: il software viene scritto sulla base dei requisiti dell'iterazione corrente, che sono quindi temporalmente vicini ed a priorità più alta. Il rischio di scrivere componenti inutilizzati o sovraingegnerizzati è relegato alla singola iterazione e non a tutto lo sviluppo. • Test frequenti: ciascuna nuova funzionalità aggiunta viene testata al momento della sua introduzione, rispettando quindi il criterio per cui un bug è tanto meno costoso quanto prima viene scoperto. 9 2 – La Continuous Integration 2.3 – Panoramica di un ambiente di Continuous Integration Gli attori fondamentali in un ambiente di Continuous Integration sono: • Lo sviluppatore. • Un sistema di controllo versione. • Un sistema di automazione delle build. • Un sistema di testing delle build. • Un server di Continuous Integration. Figura 2.5 – Panoramica di un ambiente di Continuous Integration, con i principali attori che contribuiscono al funzionamento del sistema. 10 2 – La Continuous Integration Il funzionamento generale di un sistema di Continuous Integration è il seguente: 1. Lo sviluppatore esegue i cambiamenti necessari al codice: implementa la feature richiesta, fino a che non la ritiene completata. Insieme ad essa, scrive i test automatici che la riguardano. 2. Esegue una build privata sulla propria workstation: attraverso il processo di build vengono eseguiti tutti i task necessari alla corretta preparazione del software, prima del suo rilascio. In questa fase, oltre alla compilazione, intervengono i test automatici. 3. Invio del codice al repository: una volta soddisfatti tutti i test, lo sviluppatore invia i propri cambiamenti al sistema di controllo versione. 4. Build di integrazione: il Continuous Integration server periodicamente reperisce l'ultima versione del software dal repository ed effettua una nuova build automatica, comprensiva di test, che sarà il prodotto dei cambiamenti inviati da tutti gli sviluppatori del team. 5. Feedback: se il processo di build da parte del Continuous Integration server va a buon fine, erro genera un feedback positivo (es: tramite email o un monitor ben visibile dal team) ed il software è pronto al rilascio. Viceversa il feedback sarà negativo e la soluzione del problema individuato diventa prioritaria rispetto lo sviluppo di nuove funzionalità 11 2 – La Continuous Integration 2.4 – Best practices della Continuous Integration Di seguito verranno illustrate le pratiche fondamentali per implementare correttamente un sistema di Continuous Integration e come esse influenzano il processo di sviluppo. E' importante sottolineare che la Continuous Integration è in primis una pratica e come tale agisce radicalmente sul processo di sviluppo. 2.4.1 – Utilizzo di un sistema di controllo versione L’utilizzo di un sistema di controllo versione è un requisito fondamentale per costruire un ambiente di Continuous Integration. Lo scopo di questo strumento è la gestione dei cambiamenti del codice sorgente e di tutto il necessario per la corretta compilazione del software. L'obiettivo principale è quello di avere un repository centralizzato, che permetta di gestire e monitorare i cambiamenti che avvengono sulla base di codice. Non vi è preferenza sulla scelta dello specifico strumento: l'unico requisito è quello di avere un unico punto di accesso al codice, detto “mainline” o “trunk”, mentre le differenze che intercorrono tra i vari sistemi di controllo versione non sono influenti. Con questo strumento si introduce la possibilità di rollback dei cambiamenti: viene tenuta traccia della storia di ciascun file, fornendo la possibilità di tornare indietro in caso di necessità. 12 2 – La Continuous Integration 2.4.2 – Centralizzare tutto il necessario La Continuous Integration impone che il software e tutto il necessario al suo funzionamento, compresi framework, librerie, dipendenze esterne, test e build script, sia messo sotto controllo versione all’interno del repository: esso dovrà fungere da “single source point” del codice e l'applicazione dovrà essere in grado di funzionare solamente con ciò che vi è contenuto, senza interventi esterni o aggiunte manuali. Questo è necessario per garantire uniformità negli environment di sviluppo: le librerie che i client degli sviluppatori usano per ciascun progetto provengono dal repository e non da fonti esterne, permettendo di: 1. Risparmiare tempo in termini di ricerca ed installazione delle librerie e delle dipendenze da parte dello sviluppatore. 2. Eliminare il rischio di installare versioni di librerie non aggiornate, mal funzionanti o non compatibili. Oltre a ciò, viene aumentata la velocità di ingresso al progetto da parte di eventuali nuovi membri del team: una volta ottenuto l'accesso al repository, non devono essere compiute ulteriori azioni esterne ad esso. 13 2 – La Continuous Integration 2.4.3 – Automatizzare le build Il processo di build non include la sola compilazione del codice, ma anche un determinato numero di azioni, tra le quali il setup e popolazione del database con valori noti (fixtures), che permettono al software di essere correttamente “costruito” e reso funzionante. E' necessario rendere questo insieme di passaggi automatico attraverso un singolo script di build perché in questo modo: 1. Si limita l’intervento umano: la probabilità di errori ed omissioni viene ridotta, in quanto lo sviluppatore utilizza un singolo comando. 2. Si migliora la riproducibilità: tutti gli sviluppatori eseguono gli stessi passaggi in maniera identica, evitando il cosiddetto “but it works on my machine”, dove il software risulta funzionante su alcuni ambienti e non su altri. 14 2 – La Continuous Integration Figura 2.1 – Tipici step di un generico script di build. Lo script stesso deve essere considerato parte del software e come tale soggetto ad evoluzione. 15 2 – La Continuous Integration 2.4.4 – Build testate automaticamente Una delle peculiarità della Continuous Integration è l'utilizzo di test automatici che devono essere inoltre inglobati nei build script. A build completata lo sviluppatore conoscerà il risultato del proprio lavoro e grazie all'esito dei test sarà in grado di averne confidenza sulla bontà. Non è contemplata la verifica ed il collaudo manuale dell'applicazione, esplorando di volta in volta ciascuna delle funzionalità richieste, perché è necessario evitare omissioni, soprattutto nel modello di sviluppo che si sta introducendo. La fase di test viene infatti ripetuta ad ogni build, non è umanamente possibile testare il software manualmente numerose volte al giorno, per ogni cambiamento introdotto. Testare le applicazioni manualmente porta alla cattiva pratica di non verificare quelle parti di codice per le quali si da per scontato il corretto funzionamento, in quanto si assume che le modifiche introdotto non influenzino certi punti del software. Questo, sebbene logico, è comunque non accettabile in un ambiente in cui la garanzia di rilevare errori il prima possibile è considerata una priorità. I test automatici servono ad evitare questa situazione: minori saranno le assunzioni e maggiori saranno le garanzie di un software effettivamente funzionante. I test automatici sono sempre ripetibili nella stessa identica maniera, in qualsiasi istante: ad ogni build verificano tutte le funzionalità per cui sono stati scritti, più velocemente ed in maniera più affidabile di un umano. Non è pensabile che una persona riesca ad eseguire un gran numero di volte la stessa batteria di test senza introdurre di volta in 16 2 – La Continuous Integration volta piccole differenze, perché, proprio per natura, è influenzabile da molteplici fattori non deterministici come l'umore, la concentrazione e la stanchezza. I test automatici sono invece deterministici e si fanno carico di un compito ripetitivo e noioso, ma al tempo stesso critico. 2.4.5 – Commit frequenti Uno dei principi fondamentali per ottenere vantaggi dalla Continuous Integration è quello di integrare “poco, presto e spesso”. Più si attende prima di inviare codice al repository, più il processo di integrazione richiederà del tempo, per via della maggior quantità di dati da integrare, oltre al fatto che gli altri membri del team, nel frattempo, non avranno tenuto conto degli ultimi cambiamenti. Si possono utilizzare le tecniche a seguito descritte per aumentare la frequenza di commit al repository: 1. Eseguire piccoli cambiamenti: non cambiare più componenti software insieme ma scegliere piccoli task per i quali scrivere dei test automatici ed implementare il codice necessario al loro soddisfacimento. Una volta eseguiti e passati tutti i test, inviare il codice al repository. 2. Suddividere il lavoro in task atomici: in altre parole, favorire la 17 2 – La Continuous Integration scrittura di “unit of work” a bassa interdipendenza, quindi semplici da integrare, con codice più snello e meno prono a complessità. In altri termini rispettare il “KISS principle” (Keep It Simple, Smart) [4], secondo il quale la migliore soluzione ad un problema, a parità di risultati, è quella a complessità minore. La principale motivazione a supporto di questa regola risiede nella probabilità di introduzione di un bug a seguito di una commit. Possiamo infatti affermare che la probabilità di introduzione di un errore di integrazione è funzione crescente del numero delle linee di codice che hanno influenzato la modifica. Per cui: P bug (N 1 )⩽P bug ( N 1) se N 1⩽ N 2 , con N 1 , N 2 numero di linee di codice affette dalla modifica. Ne consegue che piccoli cambiamenti integrati frequentemente, rappresentano un criterio di sviluppo più sostenibile, in cui si punta più al non introdurre bug, piuttosto che correggerli in un secondo momento. 2.4.6 - Eseguire delle build private nelle workstation locali Prima di iniziare con lo sviluppo di nuove funzionalità, ciascun membro è tenuto a scaricare dal repository l’ultima versione del software. A questo punto potrà lavorare 18 2 – La Continuous Integration nella propria workstation, effettuando i cambiamenti necessari al completamento del proprio lavoro. Una volta terminato dovrà essere effettuata una build del software sulla workstation ed osservarne i risultati. Se tutto procede correttamente, prima di inviare le proprie modifiche al repository, scaricherà di nuovo da questo gli eventuali cambiamenti effettuati nel frattempo dagli altri sviluppatori e rilancerà la build, integrando di fatto il software. Se tutto va a buon fine, è stato fatto un primo passo verso l’integrazione: i cambiamenti sono stati integrati ed è possibile aggiornare la code-base eseguendo la commit verso il repository. Figura 2.2 – Step fondamentali eseguiti dallo sviluppatore per eseguire una build di integrazione locale. 19 2 – La Continuous Integration 2.4.7 – Non inviare codice diffettoso In caso di fallimento dei test durante la build privata, lo sviluppatore dovrà correggere i malfunzionamenti e rieseguire la build fino alla completa risoluzione dei problemi riscontrati. Non potrà, in nessun caso, inviare modifiche al repository se i test non certificano che esso è correttamente funzionante. Con questa regola si minimizza la probabilità di avere software non funzionante nel repository: la copia malfunzionante resterà confinata nella macchina dello sviluppatore che si occuperà di ripararla. 2.4.8 – Eseguire una build ad ogni cambiamento Ogni volta che il repository viene aggiornato con nuovi cambiamenti, il codice necessita di essere ritestato per avere la garanzia che non siano stati introdotti dei difetti. Successivamente alle build private, quindi, si esegue la vera e propria build di integrazione, su di una macchina dedicata che deve riprodurre il più fedelmente possibile il vero ambiente di produzione. Al pari dei client degli sviluppatori, è importante che questa macchina sia priva di dipendenze e librerie spurie che non provengano direttamente dal repository: in questo modo si accerta che il lavoro dello sviluppatore sia ancora riproducibile e non dipenda da una particolare configurazione a livello locale. L’integration build può essere manuale o effettuata automaticamente tramite un Continuous Integration server. 20 2 – La Continuous Integration Sebbene l'utilizzo di un integration server non sia obbligatorio, è comunque raccomandato usarne uno: esso infatti rileverà i cambiamenti sul repository ed eseguirà le build automaticamente, fornendo inoltre una dashboard con report sui test, code coverage, strumenti di analisi aggiuntivi ed eventuale documentazione auto-generata. 2.5.9 – Non scaricare codice difettoso Nell'ipotesi in cui la build di integrazione fallisca, nonostante siano state correttamente effettuate le build private, sorge il problema della “broken build”: è entrato un bug nella code base e tutti i membri del team che andranno a scaricarlo otterrebbero del software non funzionante. Quando questo avviene la pratica impone di non scaricare affatto il codice difettoso e, se possibile, continuare lo sviluppo tramite la propria copia locale, sebbene non aggiornata, per poi integrarla in un secondo momento. Piuttosto che sviluppare eventuali workaround per far funzionare il software difettoso nella propria workstation è preferibile aiutare gli altri membri del team a far tornare la build nel suo corretto stato di funzionamento. 2.4.10 – Riparare immediatamente le build difettose E' compito dello sviluppatore che ha eseguito l'ultima commit risolvere il problema di una build difettosa. E' importante che questo venga fatto immediatamente, perché è un 21 2 – La Continuous Integration problema che coinvolge tutto il team, che a questo punto non può avere fiducia su quanto contenuto nel repository. Nell'ipotesi in cui la build di integrazione fallisca, infatti, deve essere considerata come prioritaria la soluzione dei problemi emersi piuttosto che lo sviluppo di nuove funzionalità. Come detto precedentemente, è vietato scaricare codice non funzionante: di fatto la regola descritta in precedenza attiverebbe subito tutto il team alla soluzione del problema, in quanto non potrebbe aggiornare il codice delle macchine locali per continuarne lo sviluppo. 2.5.11 – Trattare il database come il codice sorgente Il database dell'applicazione fa parte del software e come tale deve essere posto sotto controllo di versione. Figura 2.2 – La sequenza dell'integrazione automatica del db. Il build script si occupa di far eseguire lo script di definizione al DBMS, per poi procedere con l'inserimento dei dati. 22 2 – La Continuous Integration E' compito del build script gestire il DB: così facendo si può tener traccia anche dei cambiamenti effettuati sulla struttura e sui dati nella stessa maniera con cui viene effettuato con il codice sorgente. Per fare ciò è necessario gestire su file le procedure di Data Definition Language (DDL) e Data Manipulation Language (DML) ed aggiungerle al repository, che in questo modo continua ad essere l'unica fonte a cui attingere per lo sviluppo del sofware. Figura 2.3 – Esempio di integrazione del database, dove entrambi gli sviluppatori possono eseguire modifiche ai dati ed allo schema. 23 2 – La Continuous Integration 2.6.12 – Garantire un feedback rapido ed efficiente E' importante che il processo di build rapido: come regola empirica ci si impone un limite di attesa massimo di 10 minuti per il risultato della build (regola del “10 minute build”). Questo è necessario al fine di non indurre gli sviluppatori ad accumulare troppe linee di codice prima di rieseguire la build, andando contro uno dei principi cardine della Contiuous Integration. Per evitare questo anti pattern sono previste più soluzioni: 1. Eseguire delle staged-build: le build private vanno accompagnate solamente da test unitari e le build di integrazione divise in due: test unitari prima (per individuare subito i problemi più grossolani) per le build lanciate ad ogni commit e test più approfonditi (unitari e funzionali, analisi del codice, delle dipendenze, del code-style, ecc) per build lanciate in un successivo momento, per esempio schedulate in notturna o in seguito al successo delle precedenti build eseguite immediatamente dopo la commit. 2. Aumentare le risorse hardware: garantire una sufficiente potenza di calcolo, sia per le workstation sia per la macchina dedicata all'integrazione finale del codice. Avere una build veloce serve all'ottenimento di un feedback rapido che deve essere coadiuvato da meccanismi che lo rendano facilmente individuabile e interpretabile, 24 2 – La Continuous Integration alcune soluzioni proposte dalla pratica sono: • Un monitor sempre ben visibile al team, sul quale è possibile vedere continuamente lo stato delle build dei vari progetti. • Meccanismi di allarme visivi e/o sonori per segnalare malfunzionamenti (lampada verde/rossa, allarme sonoro). • Una combinazione dei precedenti. A prescindere dal criterio di feedback scelto, è importante che esso sia incentrato sulle informazioni utili ed essenziali, tutto il superfluo aumenta il rischio di far passare inosservati messaggi realmente importanti. A tal proposito è utile considerare i seguenti fattori, tra essi correlati: • L'informazione: ciò che il sistema deve comunicare. • Il destinatario: chi deve ricevere il messaggio. Gli sviluppatori sono interessati allo stato di funzionamento della build, mentre un Project Manager è più interessato ad un andamento globale del progetto (es: metriche sulla qualità del software). 25 2 – La Continuous Integration • Il modo: il meccanismo di comunicazione scelto, come ad esempio una barra verde/rossa per lo stato di una build o un grafico (anziché dei dati in forma tabellare) per il suo andamento nel tempo. • I tempi: le informazioni sono deperibili nel tempo. E' fondamentale che esse giungano a destinazione e vengano correttamente interpretate entro un determinato tempo massimo, altrimenti diventano inutili. 2.5 – Vantaggi offerti Di seguito verranno illustrati i principali vantaggi offerti dal rispetto delle best pratices imposte dalla Continuous Integration. 2.5.1 – Rilasciabilità del software Grazie ad un approccio incrementale, lo sviluppo non è più eseguito orizzontalmente. In altre parole la progettazione del software non viene più fatta a livelli (es: gui, business logic, database) che poi vengono integrati, ma diventa verticale sulla singola funzionalità in fase di realizzazione. Nel primo caso il software è rilasciabile solamente al termine dell'integrazione finale di tutti i livelli, mentre nel secondo ogni funzionalità porta già con se la porzione dei livelli interessati. Grazie alle integrazioni continue tra tutte le funzionalità, nel repository è sempre presente una versione funzionante del software, anche se incompleto, mentre nel 26 2 – La Continuous Integration caso precedente ciò non è possibile, in quanto un livello interamente sviluppato non ha alcuna utilità se il livello da cui dipende non è stato ancora completato. Intero software GUI Business Logic Database Figura 2.4 – Sviluppo non incrementale: il software viene sviluppato orizzontalmente, mentre l'integrazione è verticale. Funzionalità 1 Funzionalità 2 Funzionalità 3 Funzionalità n GUI 1 GUI 2 GUI 3 GUI n Business Logic 1 Business Logic 2 Business Logic 3 Database 1 Database 2 Database 3 Business Logic n Database n Figura 2.5 – Sviluppo incrementale: il software viene sviluppato verticalmente, mentre l'integrazione è orizzontale. 2.5.2 – Rivelazione degli errori Il rispetto della pratica delle build private e l'utilizzo dei test automatici fornisce un sistema efficiente di prevenzione e rivelazione degli errori, che vengono individuati velocemente anche grazie ad un feedback opportuno. L'eseguire una build ad ogni cambiamento è un supporto alla rivelazione istantanea dei bug, che restano confinati a porzioni di codice limitate e recenti. Grazie a ciò la risoluzione di eventuali problemi viene semplificata. 27 2 – La Continuous Integration 2.5.3 – Visibilità di progetto ed aumento della comunicazione L'utilizzo di un repository in cui centralizzare tutti gli elementi che compongono il software, coadiuvato da un meccanismo di feedback opportuno aumenta la visibilità del progetto da parte del team, che in questo modo è in grado di monitorarne costantemente l'andamento. In questo modo si ha un aumento di comunicazione sia interna che verso l'esterno: è possibile infatti tenere aggiornato il cliente sull'andamento generale del progetto e studiare con esso eventuali misure correttive o cambi di direzione, già prima della scadenza finale. 2.5.4 – Qualità del codice L'utilizzo di un Continuous Integration server permette di eseguire automaticamente e continuamente una serie di task ripetitivi e dispendiosi, come ad esempio: • L'analisi della complessità del codice • L'analisi dell'interdipendenza tra classi • Il rispetto del code style • L'analisi della duplicazione del codice • L'analisi della copertura dai test 28 2 – La Continuous Integration Tutte queste operazioni tendono ad aumentare la qualità del prodotto, è infatti possibile scegliere di far fallire una build qualora una o più di queste metriche scendano al di sotto di una soglia prestabilita ed imporre quindi il rispetto degli standard prefissati. 29 3 – Applicazione della metodologia: analisi iniziale 3 – Applicazione della metodologia: analisi iniziale Questo capitolo si occupa dell'analisi delle mancanze ed inefficienze riscontrate in azienda: viene fornita una descrizione della metodologia di sviluppo utilizzata prima e dopo l'introduzione del sistema di controllo versione, analizzando i problemi riscontrati dal team di sviluppo in entrambi i casi. 3.1 – Analisi della situazione iniziale Al momento dell'analisi, l'azienda era già in una situazione di transizione verso l'utilizzo di un sistema di controllo versione, nello specifico SVN6, per la gestione del codice. Lo strumento era già stato introdotto e correttamente configurato, ma non erano ancora state introdotte le conoscenze e la corretta disciplina per un suo utilizzo efficiente. 6 Apache Subversion – http://subversion.apache.org/ 30 3 – Applicazione della metodologia: analisi iniziale 3.1.1 – Prima dell'introduzione del sistema di controllo versione Lo sviluppo delle applicazioni web veniva effettuato tramite un server centrale contenente i sorgenti, il webserver ed il DBMS necessario alla loro esecuzione: le macchine client degli sviluppatori interagivano direttamente con esso. Gli sviluppatori, connessi ai sorgenti tramite mount point su rete locale effettuavano i cambiamenti necessari al completamento del proprio lavoro. L'approccio era quindi centralizzato, e prevedeva i seguenti step: 1. Accesso alle risorse del server di sviluppo tramite rete LAN, 2. modifica diretta dei file sorgente dell'applicazione in sviluppo, 3. accesso all'applicazione tramite browser web per la verifica dei risultati. Figura 3.1 – Flusso di lavoro dell'azienda prima dell'introduzione del sistema di controllo versione. 31 3 – Applicazione della metodologia: analisi iniziale Con questo approccio l'azienda ha lamentato vari inconvenienti, tra i quali: • Mancanza di uno storico delle modifiche ai files e di chi le avesse effettuate. • Impossibilità di poter effettuare dei rollback immediati, che non passassero necessariamente per il sistema di backup del server. • Possibilità di collisione tra sviluppatori che potevano avere la necessità di modificare lo stesso file contemporaneamente. • Blocco del lavoro dell'intero team di sviluppo qualora uno sviluppatore provocasse il malfunzionamento dell'applicazione. 3.1.2 – Dopo l'introduzione del sistema di controllo versione Per i motivi appena citati si è proceduto all'installazione di Subversion sul server di sviluppo e gradualmente migrare tutti i lavori all'interno del nuovo repository. Il processo di sviluppo è quindi passato da centralizzato a distribuito: ogni client si connette al repository contenente i sorgenti, li scarica in locale e lavora con essi, per poi rimandarli al server una volta terminate le modifiche. La modalità appena introdotta è sensibilmente differente da quella vista in precedenza: ciascun client ora dovrà essere dotato di un proprio webserver per eseguire le applicazioni e di un proprio DBMS qualora queste ne richiedano uno. 32 3 – Applicazione della metodologia: analisi iniziale Figura 3.2 – Flusso di lavoro dopo l'introduzione del sistema di controllo versione. Il nuovo processo di sviluppo è caratterizzato quindi dai seguenti step: 1. Installazione del progetto sulla workstation: 1. Modifica manuale del file degli host locale per navigare l'applicazione web. 2. Creazione di un database dedicato all'applicazione. 2. Sviluppo del progetto: 1. Checkout del codice, dal repository verso la macchina client. 2. Sincronizzazione manuale del database, tramite l'importazione di 33 3 – Applicazione della metodologia: analisi iniziale file SQL provenienti dalla versione “legacy” dell'applicazione o salvati nel repository. 3. Modifica dei sorgenti in locale. 4. Accesso all'istanza locale dell'applicazione tramite browser web per la verifica dei risultati. 5. Invio dei nuovi sorgenti al repository. 3.2 – Analisi delle mancanze L'introduzione di SVN nel processo di sviluppo dell'azienda ha incontrato inizialmente una certa inerzia a causa della prospettiva di sviluppo letteralmente invertita. L'abitudine degli sviluppatori di lavorare direttamente con l'applicazione nel server di sviluppo si è scontrata con l'avere tante copie locali per ciascuna workstation. Di seguito, saranno descritti i probleami individuati. 3.2.1 – Environment eterogenei Ogni client presenta delle differenze, più o meno marcate, a seconda delle preferenze dello sviluppatore che ne fa uso o della configurazione hardware/software. Tali differenze sono risultate essere: • il sistema operativo utilizzato (Linux / Mac OS) • la configurazione del webserver (es: i path fisici dove viene salvata 34 3 – Applicazione della metodologia: analisi iniziale l'applicazione). • la configurazione del DBMS (es: eterogeneità delle credenziali di accesso al database utilizzato da una determinata applicazione). • Le librerie esterne ed i framework necessari al funzionamento del progetto che possono presentare discrepanze sul numero di versione o risiedere in path differenti. Di conseguenza quando l'applicazione viene scaricata sulla macchina locale potrebbe non funzionare correttamente e necessitare di una riconfigurazione. Dato per assunto che tutte le applicazioni siano ben scritte e quindi parametrizzabili tramite un singolo file di configurazione (es: config.xml) resta comunque il problema di dover gestire collisioni di configurazione che sono tante quante sono i client di sviluppo, più la configurazione finale per l'ambiente di produzione, dove la release dovrà lavorare per il cliente. Lo scenario è quindi il seguente: 1. Lo sviluppatore scarica l'applicazione 2. Effettua la riconfigurazione 3. Lavora sull'applicazione 4. Invia le modifiche al repository 35 3 – Applicazione della metodologia: analisi iniziale Tale modalità evidenzia subito un'inefficienza: si nota infatti che ad ogni commit sul repository la configurazione viene di volta in volta sovrascritta, ed a causa di ciò si va incontro a due problemi: 1. La necessità di riconfigurare l'applicazione ad ogni aggiornamento ricevuto dal repository. 2. Nel repository non è mai presente una versione dell'applicazione che sia già rilasciabile e correttamente configurata per l'ambiente di produzione. Il primo problema è una criticità che abbassa l'efficienza e la produttività del team: oltre al tempo necessario all'effettiva riconfigurazione si introduce un fattore di rischio dovuto alla possibilità di commettere errori durante questa fase. In altre parole si sta sprecando tempo in un task che non porta alcun valore: la riconfigurazione non aggiunge funzionalità all'applicativo, tantomeno ne migliora alcune preesistenti, pertanto ha valore pari a zero. Il secondo problema è un fattore di rischio che potrebbe portare a problemi in fase di rilascio dell'applicazione, che porta con se altri due svantaggi: 1. Non si ha la certezza che l'applicativo sia effettivamente funzionante una volta rilasciato nell'ambiente di produzione. 36 3 – Applicazione della metodologia: analisi iniziale 2. La pubblicazione di nuove features è ogni volta rallentata dal processo manuale di configurazione. 3.2.2 – Mancanza di controllo sull'integrazione Con la modalità centralizzata ciascuno sviluppatore era costretto a lavorare su porzioni indipendenti dell'applicativo, in quanto non vi era nessun meccanismo di sviluppo concorrente. Con l'introduzione di Subversion questo limite è stato rimosso: grazie al controllo di versione è infatti possibile poter effettuare cambiamenti concorrenti anche sulle stesse aree di codice e poter gestire le collisioni tramite i meccanismi di risoluzione offerti dallo strumento. Resta però il problema dell'integrazione, cioè garantire che la risoluzione dei conflitti sia effettivamente corretta e non causi malfunzionamenti. 3.2.3 – Mancanza di visibilità di progetto Diretta conseguenza del problema visto precedentemente è la mancanza di visibilità sul progetto: il fatto che il software funzioni sulla workstation locale dello sviluppatore non garantisce il corretto funzionamento della build presente nel repository. Qualora due o più sviluppatori lavorino sulla stessa area di codice, al momento della commit Subversion si occupa di segnalare l'avvenuta collisione e permetterne la 37 3 – Applicazione della metodologia: analisi iniziale risoluzione del conflitto: sebbene questo sia un primo livello di protezione, non si ha comunque la garanzia che l'integrazione sia avvenuta correttamente. Ciascuno sviluppatore è infatti responsabile delle modifiche che introduce, ma senza un meccanismo che permetta automaticamente di evidenziare effetti collaterali in altri punti del codice si potrebbero introdurre inavvertitamente dei malfunzionamenti che in prima analisi potrebbero non essere visibili. 3.2.4 – Nessuna integrazione del database Con l'abbandono del server centrale si è passati da un un'unica istanza dell'applicazione in sviluppo ad n istanze, una per ogni client coinvolto nel processo di sviluppo. Replicare il codice in tutte le workstation locali non è visto come un particolare problema, ma per quanto riguarda la gestione del database sono emerse alcune problematiche: • Non esiste più un DBMS centralizzato, al quale tutti fanno riferimento • Non c'è un meccanismo di integrazione tra i cambiamenti ai dati e alla struttura, effettuati nelle copie locali. Tali problematiche, non emergevano invece con il vecchio approccio centralizzato: la macchina di sviluppo era unica, come pure il DBMS e l'istanza dell'applicativo. 38 3 – Applicazione della metodologia: analisi iniziale 3.2.5 – Difficoltà di ingresso nel progetto Una delle difficoltà avvertite dall'azienda è stata la difficoltà di ingresso nel progetto da parte di nuovi membri del team. E' necessario che tutto passi per un client locale, che deve essere configurato affinché sia in grado di ospitare correttamente il progetto, anche per piccolissime modifiche. Il tempo necessario al setup e bootstrap manuali dell'applicazione in locale, complice anche l'eterogeneità degli environment precedentemente descritta, spesso supera il tempo necessario all'implementazione delle modifiche richieste. 3.2.6 – Difficoltà nel rilascio di demo Creare una demo del software significa consegnare al cliente una prima versione funzionante di ciò che è attualmente in sviluppo dentro il repository. Questo processo è risultato essere lento e macchinoso, in quanto eseguito manualmente. Emerge quindi la necessità di automatizzare questa fase e studiare un meccanismo che automaticamente si occupi di scaricare dal repository l'ultima versione del software e pubblicarla in un server di demo. 3.2.7 – Difficoltà di rilascio dell'applicazione Un problema simile a quello del rilascio di demo, ma molto più delicato e critico è 39 3 – Applicazione della metodologia: analisi iniziale quello del rilascio ufficiale. La differenza sta nel fatto che in questo caso la destinazione non è più il server di demo, in cui eventuali malfunzionamenti o imprecisioni possono essere ancora tollerati, ma nel server ufficiale di produzione, dove l'applicazione entrerà definitivamente in produzione per il cliente. Diventa quindi necessario l'utilizzo di strumenti come FTP o SFTP per l'invio dei files e prestare la massima attenzione nel non commettere errori in un ambiente in cui questi non sono assolutamente tollerabili. In questa fase si sta consegnando il software al cliente, è quindi necessario ripulirlo di tutti gli assets aggiuntivi come i files di gestione di Subversion e tutto ciò che non è necessario: mantenere questi files potrebbe rappresentare una vulnerabilità del sistema, oltre che uno spreco di spazio. 40 4 – Progettazione del cambiamento 4 – Progettazione del cambiamento In questo capitolo verranno illustrati tutti i cambiamenti necessari al fine di introdurre la Continuous Integration. In questa fase di progettazione saranno motivate le scelte tecniche, secondo due criteri: l'ambito di sviluppo dell'azienda (web application) e l'eventuale preesistenza di strumenti già adatti alla Continuous Integration. 4.1 – Scelta degli strumenti La scelta è stata fatta preferendo tutti quegli strumenti inerenti alle tecnologie web, reputati quindi più adatti per la tipologia di applicazioni sviluppate dall'azienda. 41 4 – Progettazione del cambiamento 4.1.1 – Sistema di controllo versione E' stato scelto il sistema di controllo di versione Subversion 7 (o SVN) in quanto già utilizzato dall'azienda presa in esame. Per quanto riguarda il server contenente il repository non sono state effettuate modifiche, perché già correttamente configurato per essere usufruito sia dalla rete locale interna che da remoto, tramite una connessione sicura SSH. Sono state dotate di un client SVN tutte le workstation che non ne erano munite, in modo da renderlo disponibile per tutta l'azienda. 4.1.2 – Web Server e DBMS L'azienda sviluppa principalmente applicazioni web in PHP, per le quali il tipico web server è Apache8. Il DBMS scelto, sempre in relazione al tipo di software sviluppato, è MySQL9. La tipica installazione scelta è quindi di tipo LAMP (Linux, Apache, MySQL, PHP) per i client di tipo Linux, oppure MAMP (Mac, Apache, MySQL, PHP) per i client basati su sistema operativo Mac OS. Per entrambe è stato scelto il software Zend Server10. Non sono state infine rilevate macchine dedicate allo sviluppo, dotate di sistema operativo Windows. 7 8 9 10 Apache Subversion – http://subversion.apache.org/ Apache HTTP Server Project – http://httpd.apache.org/ Oracle MySQL – http://www.mysql.com/ Zend Server – http://www.zend.com/products/server/ 42 4 – Progettazione del cambiamento 4.1.3 – Build scripting system Come strumento per lo sviluppo ed esecuzione degli script di build è stato scelto Phing11, in quanto specifico per il linguaggio PHP, con il quale è possibile scrivere eventuali plugin o estensioni. Esso fa uso di un file di build (di tipo XML), attraverso il quale è possibile definire una serie di attività (dette “target”) composte da operazioni (detti “task”) da eseguire in automatico. I task che si possono eseguire attraverso Phing coprono ampiamente le richieste della Continuous Integration, infatti con essi si possono effettuare, tra le altre, le seguenti operazioni: • operazioni su file system • operazioni su database • esecuzione di test automatici • operazioni FTP ed SFTP • interazione con la shell fornita dal sistema operativo 11 Phing – http://www.phing.info/ 43 4 – Progettazione del cambiamento 4.1.4 – Strumenti di testing Con i test unitari si verifica il funzionamento dell'applicazione ad un livello atomico: le classi dell'applicazione vengono testate singolarmente e si testano uno a uno i metodi che le compongono. Con i test funzionali si testa l'applicazione ad un livello più alto: attraverso una procedura automatizzata si simula l'interazione uomo-macchina e si verifica se i risultati ottenuti combaciano con quelli attesi. Per lo sviluppo dei test automatici sono stati scelti i seguenti software: 1. PHPUnit12 per la scrittura di test unitari. 2. Selenium IDE e Selenium RC13 per i test funzionali. La scelta di PHPUnit è motivata dal fatto che l'azienda sviluppa le proprie applicazioni utilizzando il linguaggio PHP. PHPUnit fa inoltre parte della famiglia dei framework di testing xUnit (disponibile per un elevato numero di linguaggi tra cui Java con JUnit e .NET con NUnit) con la quale condivide la sintassi e la modalità di funzionamento. 12 PHPUnit – http://www.phpunit.de/ 13 Selenium , Web Browser Automation – http://seleniumhq.org/ 44 4 – Progettazione del cambiamento Figura 4.1 – Screenshot del software Selenium IDE, con il quale effettuare la registrazione delle sessioni di navigazione. Selenium IDE e Selenium RC sono stati invece scelti in quanto le applicazioni sviluppate dall'azienda sono nello specifico dei siti internet: Selenium IDE consente di registrare delle sessioni di navigazione, mentre Selenium RC in accoppiata a PHPUnit è in grado di rieseguirle senza intervento umano, lanciando una istanza di browser reale. 45 4 – Progettazione del cambiamento 4.1.5 – Server di Continuous Integration Durante la fase di analisi in azienda, è stato scelto Hudson 14 come server di Continuous Integration, in quanto di agevole installazione e configurazione, ma soprattutto integrabile con gli strumenti introdotti in precedenza. Hudson offre infatti supporto a: 1. Numerosi sistemi di controllo di versione, tra cui SVN 2. Vari linguaggi di build scripting, tra cui phing Supporta infine in maniera soddisfacente l'integrazione con i risultati forniti dai test eseguiti con il framework PHPUnit, permettendo la visualizzazione nella dashboard sia dei risultati che di ulteriori dettagli come la code coverage. 4.2 – Standardizzazione delle workstation e dei progetti A seguito dell'installazione degli strumenti elencati precedentemente, tutte le workstation sono state configurate in modo da avere a disposizione tutti i comandi necessari ad eseguire il processo di build del software e tutte le operazioni ad esso connesse che vanno automatizzate. 14 Hudson Continuous Integration – http://hudson-ci.org/ 46 4 – Progettazione del cambiamento Oltre alla standardizzazione degli environment delle worstation si è proceduto con la definizione di una struttura comune a tutti i progetti. 4.2.2 – Standardizzazione della struttura cartelle Per ciascun progetto è stata definita una struttura cartelle consistente, che va sempre rispettata con rigore, in modo da permettere a ciascun membro del team di reperire il necessario nel più breve tempo possibile e senza ambiguità. Di seguito la struttura scelta, comprensiva dei files fondamentali: . ├── │ │ │ │ │ │ ├── ├── │ │ ├── │ ├── └── _data ├── database.create.db.sql ├── database.dati.sql ├── database.struttura.sql ├── install.sh ├── LINUX_dominio.conf └── MAC_httpd.conf library _tests ├── functional └── unit web └── index.php _xhtml build.xml Figura 4.2 – Struttura cartelle scelta, da rispettare per ciascun progetto presente nel repository dell'azienda. 4.2.2.1 – _data In questa cartella sono presenti tutti i dati necessari all'installazione del progetto e la 47 4 – Progettazione del cambiamento popolazione dei dati a partire da valori noti. Qui possiamo trovare i senguenti files: • database.create.db.sql • database.dati.sql • database.struttura.sql • install.sh per la creazione del database. contiene i dati iniziali del database, detti fixtures. contiene la struttura del database. è uno script bash, per l'installazione del progetto nella worskation locale (modifica al file degli host del sistema operativo e creazione di un virtual host). • LINUX_dominio.conf • MAC_httpd.conf contiene il virtual host per i sistemi Linux. contiene il virtual host per i sistemi Mac OS. 4.2.2.2 – library E' la cartella dedicata alle librerie ed ai framework utilizzati nel progetto. 4.2.2.3 – _test E' la cartella sulla quale vengono appoggiati tutti i files relativi ai test. E' ulteriormente suddivisa in due sotto cartelle, unit e functional, contenente rispettivamente i test unitari e funzionali. 4.2.2.4 – web E' la cartella che viene puntata dai virtual host e sulla quale è presente il file index.php 48 4 – Progettazione del cambiamento di ciascun progetto. Contiene la vera e propria web application, nello specifico tutti i files che vanno resi accessibili all'esterno. La suddivisione dei files all'interno di essa dipenderà dagli specifici progetti. 4.2.2.5 – _xhtml E' utilizzata dagli sviluppatori per la creazione dei templates dinamici. Contiene la versione statica della web application, ossia tutti i files HTML da utilizzare come modello per lo sviluppo del frontend. Sono il risultato del lavoro del frontend developer, che esegue il montaggio della grafica progettata dal designer. 4.2.2 – Comandi fondamentali Di seguito un riassunto dei comandi messi a disposizione dopo l'aggiornamento di tutte le workstation: Comando Descrizione phing Per eseguire la build del software mysql Per eseguire operazioni sul database mysqldump phpunit Per eseguire il dump del database su file Per eseguire i test automatici Tabella 4.1 – Lista dei comandi messi a disposizione su ciascuna worsktation per implementare la Continuous Integration. In questo modo è stato possibile creare un unico script di build standardizzato per tutti client e tutti i progetti, in modo da garantire una configurazione omogenea. 49 4 – Progettazione del cambiamento 4.2.3 – Standardizzazione del database Per eliminare i problemi di eterogeneità è stata definita una convenzione sul nome del database da utilizzare per ogni progetto e le credenziali di autenticazione (utente MySQL) con il quale è possibile interagire con esso. In questo modo è stato garanto a ciascuno sviluppatore di gestire il DBMS della propria workstation in autonomia, mantenendo private le proprie credenziali di amministratore, in quanto sono quelle relative al progetto ad essere condivise: l'applicazione, se non diversamente configurata, fa riferimento sempre alle stesse credenziali di accesso al DB. Sono state poi create le procedure SQL necessarie al setup e popolazione del database, ed in seguito salvate nel repository, insieme a tutto il necessario per ottenere tramite un singolo comando: 1. Un utente di progetto attivo e configurato, con le proprie credenziali ed i permessi correttamente configurati per il proprio database. 2. Un database dal nome univoco per il singolo progetto, con la propria struttura ed eventualmente popolato con ben determinati dati iniziali (detti anche fixtures). 4.3 – Introduzione del build scripting system E' stato creato un generico file build.xml ed implementati dei target comuni ad ogni 50 4 – Progettazione del cambiamento progetto. Questo file viene di volta in volta personalizzato secondo le esigenze e posto sotto controllo di versione insieme ad esso. In questo modo ciascuna applicazione ha il proprio script di generazione della build che diventa parte integrante del software e come tale potrà essere migliorato o ampliato di nuove funzionalità. Sono stati definiti due target fondamentali per ciascun progetto: “build” e “make-sql”. 1. <?xml version="1.0" encoding="UTF-8"?> 2. <project name="e-xtrategy" basedir="." default="build"> 3. <property name="db.name" value="e-xtrategy" /> 4. <property name="db.user" value="root" /> 5. <property name="db.password" value="" /> 6. 7. 8. 9. <target name="build"> <!-- target definition --> </target> 10. 11. 12. 13. <target name="make-sql"> <!-- target definition --> </target> 14. 15. </project> Listato 4.1 – Esempio di file build.xml, contenente i target fondamentali “build” e “makesql”. 4.3.1 – Il target build Il target build si occupa dell'effettivo setup dell'applicazione automatizzando la gran parte delle attività che altrimenti sarebbero state manuali e soggette ad errore. 51 4 – Progettazione del cambiamento Tali attività, tipicamente, sono: 1. Cancellazione dei file temporanei ed eliminazione di residui di vecchie build. 2. Impostazione dei permessi di lettura e scrittura nelle directory. 3. Setup del database e dell'utente di accesso tramite le procedure SQL viste precedentemente. 4. Esecuzione di test automatici 1. 2. <target name="build"> <if> 3. <equals arg1="${db.password}" arg2=""/> 4. <then> <property name="pstring" value=""/> 5. 6. </then> 7. <else> <property name="pstring" value="-p${db.password}"/> 8. 9. </else> 10. </if> 11. <exec command="mysql -u${db.user} ${pstring} &lt; _data/$ {db.name}.create.db.sql" checkreturn="true"/> 12. <exec command="mysql -u${db.user} ${pstring} ${db.name} &lt; _data/${db.name}.struttura.sql"checkreturn="true"/> 13. <exec command="mysql -u${db.user} ${pstring} ${db.name} &lt; _data/${db.name}.dati.sql"checkreturn="true"/> 14. </target> Listato 4.2 – Esempio di target “build” con cui viene creato e popolato il database, partendo dai files sql presenti nel repository. 52 4 – Progettazione del cambiamento 4.3.2 – Il target make-sql L'applicazione durante il suo funzionamento interagisce con il database inserendo, modificando o cancellando dei record, oppure lo sviluppatore decide di effettuare dei cambiamenti alla struttura di alcune tabelle o della struttura del database in generale. Qualora lo sviluppatore intenda inviare la nuova versione del database al repository è necessario innanzitutto che ne effettui il dump su file. Questa fase è stata automatizzata creando il target make-sql: vengono effettuati il dump della struttura e dei dati e salvati in due distinti files, che andranno a sostituire quelli contenenti le procedure per la creazione e popolazione della vecchia versione del database. 15. 16. <target name="make-sql"> <if> 17. <equals arg1="${db.password}" arg2=""/> 18. <then> <property name="pstring" value=""/> 19. 20. </then> 21. <else> <property name="pstring" value="-p${db.password}"/> 22. 23. </else> 24. </if> 25. <exec command="mysqldump -u${db.user} ${pstring} --skipcomments --no-create-info ${db.name} >_data/${db.name}.dati.tmp" checkreturn="true"/> 26. <exec command="mysqldump -u${db.user} ${pstring} --skipcomments --no-data ${db.name} >_data/${db.name}.struttura.tmp" checkreturn="true" /> 27. <delete file="_data/${db.name}.dati.sql" /> 28. <delete file="_data/${db.name}.struttura.sql" /> 29. <move file="_data/${db.name}.dati.tmp" tofile="_data/$ 53 4 – Progettazione del cambiamento {db.name}.dati.sql" /> <move file="_data/${db.name}.struttura.tmp" tofile="_data/$ 30. {db.name}.struttura.sql" /> 31. </target> Listato 4.3 – Esempio di target “make-sql” con cui struttura e dati del database vengono fatti persistere su filesystem, prima dell'invio al repository. Una volta effettuata la commit la nuova versione del DB sarà a questo punto presente nel repository. 4.3 – Introduzione di uno script di installazione Come illustrato in precedenza, per poter ottenere il funzionamento di ciascun website in locale, sono necessarie alcune operazioni preliminari, che sono la modifica al file degli host del sistema e la creazione di un virtual host per il webserver. Per facilitare l'installazione di ciascun progetto nelle macchine locali è stato creato uno script bash. 1. #!/bin/bash 2. n=$(grep local.e-xtrategy.net /etc/hosts -c) 3. if [ "$n" = 0 ]; then echo 127.0.0.1 local.e-xtrategy.net >> /etc/hosts 4. 5. fi 6. cp LINUX_dominio.conf /etc/apache2/sites-available/www.extrategy.net.conf 7. cd /etc/apache2/sites-available/ 8. a2ensite www.e-xtrategy.net.conf 9. /etc/init.d/apache2 restart Listato 4.4 – Esempio di file install.sh, per la modifica del file degli host e la creazione del virtual host. 54 4 – Progettazione del cambiamento 4.5 – Introduzione dei test Per testare l'applicazione nella build privata è stato creato il target “test” che si occupa di lanciare PHPUnit configurato in modo da eseguire i test che sono stati scritti per l'applicazione. I test automatici, come il file build.xml, vanno considerati parte del software ed anch'essi posizionati all'interno del repository, nella cartella _test: in questo modo una procedura di test scritta da uno sviluppatore va a beneficio di tutto il team che può inoltre rivederla e migliorarla. I test documentano le funzionalità del codice e ne verificano l'effettivo funzionamento: se un requisito del software cambia, anche i test ad esso correlati verranno aggiornati. 1. <?php 2. require_once 'PHPUnit/Framework.php'; 3. require_once APPLICATION_PATH . '/models/User/CgaUser.php'; 4. require_once APPLICATION_PATH . '/models/User/CgaUsers.php'; 5. 6. class CgaUsersTest extends PHPUnit_Framework_TestCase { 7. 8. /** 9. * setup delle fixtures 10. */ 11. public function setUp() { 12. $u1 = new CgaUser(); 13. $u1->anno_registrazione = 2009; 14. 15. $u2 = new CgaUser(); 16. $u2->anno_registrazione = 2010; 17. 18. $u3 = new CgaUser(); 19. $u3->anno_registrazione = 2008; 20. 21. $this->_users = array($u1, $u2, $u3); 55 4 – Progettazione del cambiamento $this->_cgaUsers = new CgaUsers($this->_users); 22. 23. } 24. 25. /** 26. * testa il risultato dell'operazione su tutta la collection 27. * l'operatore (mock) 28. * che assegna sempre lo stato di confermato 29. */ 30. public function testAllSociOperation() { 31. // Create a stub for the CgaUser class. 32. $userMock = $this->getMock('CgaUser'); 33. // Configure the stub. 34. $userMock->confirmed = true; 35. 36. //Create a stub for the CgaUserChecker Operator class. 37. $operator = $this>getMock('CgaUserChecker1', array('execute')); 38. // Configure the stub. 39. $operator->expects($this->any()) 40. ->method('execute') 41. ->will($this->returnValue($userMock)); 42. 43. $this->_cgaUsers->operation(array($operator)); 44. foreach ($this->_cgaUsers as $user) { 45. $this->assertTrue($user->confirmed); 46. 47. } } 48. 49. /** 50. * testa il risultato dell'operazione su tutta la collection 51. * l'operatore (mock) 52. * che assegna sempre lo stato di non confermato 53. */ 54. public function testNoSociOperation() { 55. // Create a stub for the CgaUser class. 56. $userMock = $this->getMock('CgaUser'); 57. // Configure the stub. 58. $userMock->confirmed = false; 56 4 – Progettazione del cambiamento 59. 60. //Create a stub for the CgaUserChecker Operator class. 61. $operator = $this>getMock('CgaUserChecker1', array('execute')); 62. // Configure the stub. 63. $operator->expects($this->any()) 64. ->method('execute') 65. ->will($this->returnValue($userMock)); 66. 67. $this->_cgaUsers->operation(array($operator)); 68. foreach ($this->_cgaUsers as $user) { 69. $this->assertFalse($user->confirmed); 70. 71. } } 72. 73. /** 74. * testa il risultato di più operazioni sulla collection 75. * il primo operatore assegna sempre lo stato di confermato 76. * il secondo operatore assegna sempre l'anno 2010 77. 78. */ public function testMultipleOperations() { 79. // Create a stub for the CgaUser class. 80. $userMock = $this->getMock('CgaUser'); 81. // Configure the stub. 82. $userMock->confirmed = true; 83. 84. //Create a stub for the CgaUserChecker Operator class. 85. $op1 = $this>getMock('CgaUserChecker1', array('execute')); 86. // Configure the stub. 87. $op1->expects($this->any()) 88. ->method('execute') 89. ->will($this->returnValue($userMock)); 90. 91. $userMock2 = clone $userMock; 92. $userMock2->anno_registrazione = 2010; 93. 94. //Create a stub for the CgaUserChecker Operator class. 57 4 – Progettazione del cambiamento 95. $op2 = $this>getMock('CgaUserChecker1', array('execute')); 96. // Configure the stub. 97. $op2->expects($this->any()) 98. ->method('execute') 99. ->will($this->returnValue($userMock2)); 100. 101. $this->_cgaUsers->operation(array($op1, $op2)); 102. foreach ($this->_cgaUsers as $user) { 103. $this->assertTrue($user->confirmed); 104. $this->assertEquals(2010, $user>anno_registrazione); 105. 106. } } 107. } Listato 4.5 – Esempio di batteria di test unitari per una classe, scritti utilizzando il framework di test PHPUnit. 4.6 – Installazione del server di Continuous Integration Il server di Continuous Integration Hudson è stato installato nella stessa macchina su cui è presente il repository SVN. La scelta di accorpare le due entità anziché tenerle separate è stata fatta in ottica di una diminuzione di carico della rete LAN, Hudson infatti ad ogni build scarica per intero i progetti da integrare: data l'entità del traffico si è preferito passare direttamente per l'hard disk per non influenzare negativamente le prestazioni ed ottenere un feedback rapido. Hudson è stato poi configurato in modo da effettuare dei polling verso il repository SVN ed individuare eventuali cambiamenti: qualora ve ne fossero scarica il codice del 58 4 – Progettazione del cambiamento progetto e ne effettua la build utilizzando lo stesso script di build degli sviluppatori, mostrando l'esito delle operazioni sulla propria dashboard. 4.7 – Training del personale Prima di terminare l'opera di installazione e configurazione dei client e del server di Continuous Integration si è proceduto con la formazione degli sviluppatori per l'utilizzo del nuovo ambiente. La Continuous Integration è infatti anzitutto una pratica che funziona solamente se viene rispettata ed è importante fare in modo che tutti gli sviluppatori prendano coscienza di quali cambiamenti implicherà nel processo di sviluppo software e delle relative motivazioni. 4.7.1 – Lezioni frontali E' stata redatta una presentazione riguardante i temi della Continuous Integration, delle pratiche su cui si basa e dei problemi che si prefigge di risolvere. Successivamente si è passato ad una lezione frontale, alla quale hanno partecipato tutti gli attori coinvolti nello sviluppo software. Sono stati toccati in particolar modo i temi chiave che presentavano un più immediato beneficio per l'azienda, come ad esempio l'integrazione e l'automatizzazione del database. 59 4 – Progettazione del cambiamento 4.7.2 – Redazione di documenti operativi Tutto il materiale visto a lezione è stato messo a disposizione del team di sviluppo e salvato nel wiki aziendale. E' stato redatto inoltre un documento dai toni informali, successivamente appeso in bacheca, per non far perdere l'attenzione circa le nuove tematiche introdotte. Il contenuto del documento è un veloce riassunto delle bestpractises della Continuous Integration, accompagnato da una breve guida che permette di iniziare a lavorare sin da subito con il nuovo ambiente. 4.7.3 – Post sul corporate blog E' stato pubblicato un post15 sul corporate blog dell'azienda in cui viene spiegata a grandi linee la pratica della Continuous Integration e di come sia importante organizzare il lavoro nel team di sviluppo. Lo scopo della pubblicazione del post è stato quello di mandare un segnale, sia all'interno che all'esterno, della presa di coscienza che il successo o l'insuccesso di un sistema informativo non è solamente decretato dalla tecnologia che utilizza, ma anche da come questa è organizzata all'interno dell'azienda e dal rispetto delle buone pratiche di utilizzo. 15 Continuous Integration: quando la pratica va oltre gli strumenti, Giorgio Mandolini, e-xtrategy s.r.l. – http://www.e-xtrategy.net/2010/06/15/continuous-integration-quando-la-pratica-va-oltre-gli-strumenti 60 5 – Risultati ottenuti 5 – Risultati ottenuti Questo capitolo descrive i risultati ottenuti a seguito dei cambiamenti introdotti nel capitolo 4, focalizzando l'attenzione, punto per punto, sui problemi riscontrati nel capitolo 3. In questa fase verranno espresse infine delle conclusioni sul lavoro svolto ed eventuali sviluppi futuri. 5.1 Soluzione del problema degli environment eterogenei L'utilizzo di una convenzione sulle modalità di installazione e configurazione dei progetti ha portato ad una considerevole diminuzione dei problemi di configurazione delle applicazioni. Oltre a ciò lo script di build, grazie alla possibilità di essere parametrizzato, si è dimostrato una strada molto efficace per uniformare anche client all'apparenza 61 5 – Risultati ottenuti eterogenei: esso è stato utilizzato infatti sia su macchine Linux che Mac OS, oltre che in macchine Windows, queste ultime approntate solamente a scopo didattico. Anche il server di Continuous Integration utilizza il medesimo script di build per costruire le applicazioni in maniera automatica: in questo modo si è riusciti ad ottenere la garanzia che tutte le operazioni di installazione e configurazione dei lavori vengono effettuate in maniera identica e ripetibile su ogni macchina, ed il software presente nel repository è già pronto per essere rilasciato in produzione. Quello che inizialmente era un problema di riconfigurazione manuale e dispendiosa è diventato il lancio di un unico comando da shell: l'unico onere dello sviluppatore è di fornire eventuali parametri e credenziali di accesso differenti da quelli di default, qualora sia necessario. 5.2 Soluzione del problema di integrazione del codice L'utilizzo di test automatici fornisce una rapida indicazione sul funzionamento del software una volta effettuate delle modifiche ed integrate con il lavoro del resto del team. Come imposto dalla pratica non si può inviare codice al repository se questo non è prima stato verificato da test automatici ed il feedback fornito in seguito dal Continuous Integration server è una seconda prova sull'avvenuta integrazione. I benefici dell'introduzione dei test automatici sono evidenti, ma al tempo stesso 62 5 – Risultati ottenuti l'effettiva messa in atto di questa buona pratica è il compito che richiede più tempo in azienda. I test automatici infatti necessitano di tempo per essere scritti e vanno visti come un investimento: scrivere una volta un test assicura per sempre che una determinata funzionalità sia testata ed evita il presentarsi due volte dello stesso bug. Oltre a ciò, l'introduzione di test automatici o pratiche di sviluppo come la Test Driven Development (TDD), che si basano su di essi, richiedono un'iniziale curva di apprendimento che durante lo svolgimento del presente lavoro, vista la molteplicità degli argomenti da trattare, non è potuta essere del tutto affrontata. I test automatici sono stati comunque introdotti ed implementati in via sperimentale su alcuni progetti: l'impatto che hanno avuto su di essi è stato giudicato positivo e per questo l'azienda vede il loro utilizzo a regime come un investimento da fare nel prossimo futuro. 5.3 Soluzione del problema della visibilità di progetto La visibilità di progetto ha subito un sensibile miglioramento grazie alla dashboard fornita dal Continuous Integration server. Lo sviluppatore a colpo d'occhio è in grado di monitorare lo status di tutti i progetti seguiti dall'azienda e capire subito se su alcuni di essi vi sono problemi in corso. 63 5 – Risultati ottenuti Figura 5.1 – Dashboard fornita dal C.I. server Hudson. Il verde indica una build funzionante mentre il rosso segnala la presenza di problemi. Figura 5.2 – Dettagli relativi ad un progetto, comprensivi della code coverage dei test unitari. 64 5 – Risultati ottenuti Figura 5.3 – Andamento di una build nel tempo. Figura 5.4 – Dettagli relativi alla copertura del codice. 65 5 – Risultati ottenuti 5.4 Soluzione del problema di integrazione del DB Il salvataggio del database e degli utenti ad esso adibiti su file posti sotto controllo di versione è stato il cambiamento che ha portato i benefici più immediati e che per primo ha incontrato un massiccio utilizzo da parte di tutti gli sviluppatori. L'automatizzazione delle procedure di cancellazione e reimportazione del database ad ogni build ha portato alla completa sincronizzazione dei dati e delle strutture che a tutti gli effetti sono trattate come parti del software. Lo sviluppatore deve preoccuparsi solamente di lanciare i relativi comandi seguiti dalle proprie credenziali di accesso al proprio DBMS locale: tutto il resto è interamente gestito dallo script di build. Figura 5.5 – Schermata con i risultati dell'esecuzione del target build per il setup del database di un progetto. 66 5 – Risultati ottenuti Figura 5.6 – Schermata con i risultati dell'esecuzione del target make-sql per il salvataggio in locale del database di un progetto. 5.5 Soluzione del problema di ingresso al progetto Anche il problema di ingresso al progetto è stato mitigato grazie all'utilizzo di procedure automatiche che rendono l'installazione e la configurazione del software un processo molto più rapido rispetto alla modalità di lavoro precedente. C'è ancora margine di miglioramento: il setup del file degli host è ancora manuale per i client Mac OS. 67 5 – Risultati ottenuti Figura 5.7 – Installazione di un progetto in locale, tramite l'utilizzo dello script bash install.sh. Una miglioria ottenuta, che esula dalla Continuous Integration è stata la configurazione della stessa macchina contenente il repository SVN anche come “client di emergenza”. In essa sono infatti già presenti tutte le applicazioni web correttamente funzionanti: qualora si avesse la necessità di dover effettuare piccole modifiche su una di esse, basterà accedervi direttamente, con la stessa modalità di sviluppo degli altri client; sebbene questa situazione dovrebbe presentarsi in via del tutto eccezionale, è comunque rispettosa della pratica della Continuous Integration. E' da segnalare, infine, che il file degli host va aggiornato una sola volta all'avvio del progetto: anche quando questo non viene più seguito dallo sviluppatore e rimosso dall'hard disk della propria workstation è consigliabile non eliminarne l'entry da tale 68 5 – Risultati ottenuti file. In questo modo, a fronte di pochi kilobyte di informazione, si risparmieranno preziosi minuti di tempo nella sua configurazione in caso di necessità di riaprire il lavoro, mentre per tutto il resto entra in gioco lo script di build. 5.6 Soluzione del problema delle demo Il problema delle demo è stato risolto con successo: grazie al Continuous Integration server che si occupa di reperire periodicamente una versione aggiornata dell'applicazione web, è sempre possibile vederne una copia in anteprima. E' sufficiente dare accesso ai clienti alla URL prestabilita. 5.7 Futuri sviluppi: automatizzare il deploy Per quanto riguarda il deploy delle applicazioni si è preferito non procedere con l'automatizzazione delle operazioni. Il deploy è infatti un compito molto delicato, che di volta in volta potrebbe essere diverso. Non è pensabile di distruggere interamente l'applicazione in produzione per sostituirla con la nuova versione perché verrebbero inevitabilmente persi tutti i dati prodotti dagli utenti durante il periodo di normale funzionamento. E' preferibile una strada di tipo incrementale, in cui gli interventi di pubblicazione dei files siano mirati e posti sotto rigido controllo umano: è necessario inviare al server di 69 5 – Risultati ottenuti produzione solamente lo stretto necessario, impiegando il minor tempo possibile e preservando tutti i dati finora prodotti. Sarebbe comunque interessante proseguire lo studio di metodi di automazione che rientrino anche in quest'ultimo ambito per chiudere il cerchio dello sviluppo e giungere così alla creazione di un ambiente automatizzato in ogni sua parte. 70 6 – Bibliografia 6 – Bibliografia 6.1 – Letteratura Paul M. Duvall, Steve Matyas, Andrew Glover - Continuous Integration: Improving Software Quality and Reducing Risk, http://www.integratebutton.com/, AddisonWesley Professional 2007 Extreme programming – Integrate Often, http://www.extremeprogramming.org/rules/integrateoften.html. Martin Fowler – Continuous Integration, http://martinfowler.com/articles/continuousIntegration.html, 2006. Kent Beck – Test Driven Development: By Example, Addison-Wesley Professional 2002. 71 6 – Bibliografia Kent Beck, Cynthia Andres – Extreme Programming Explained: Embrace Change (2nd Edition), Addison-Wesley Professional, 2004. 6.2 – Risorse e strumenti Extreme Programming – http://www.extremeprogramming.org/ . Martin Fowler – http://martinfowler.com/. Kent Beck – http://www.threeriversinstitute.org/Kent Beck.htm. Apache Subversion – http://subversion.apache.org/. Apache HTTP Server Project – http://httpd.apache.org/ . Oracle MySQL – http://www.mysql.com/ . Zend Server – http://www.zend.com/products/server/ . Phing – http://www.phing.info/. Selenium - Web Browser Automation – http://seleniumhq.org/ . Hudson Continuous Integration – http://hudson-ci.org/ . Continuous Integration: quando la pratica va oltre gli strumenti, Giorgio Mandolini, e-xtrategy s.r.l. – http://www.e-xtrategy.net/2010/06/15/continuous-integrationquando-la-pratica-va-oltre-gli-strumenti, 2010. Continuous Integration: un'introduzione, Giorgio Mandolini, HTML.it – http://php.html.it/articoli/leggi/3905/continuous-integration-unintroduzione/, 2012. 72 Ringraziamenti Ringraziamenti Molto probabilmente questa sarà l'unica parte che verrà letta dai miei amici, alcuni dei quali,senza fare nomi, non ci prendono con le H su Facebook, dubito che siano interessati ai miei tecnicismi , ma sono miei amici anche per questo :D Con queste ultime ultime righe si chiude un importante capitolo della mia vita, qualcosa di nuovo mi attende: è li fuori e non aspetta altro che essere vissuto. Chi mi conosce sa quanto abbia lottato per arrivare a questa svolta, quanto la desiderassi e di quanto ne avessi bisogno, anche in quei momenti in cui ho veramente pensato di arrendermi. Voglio ringraziare innanzitutto la mia famiglia, che mi ha supportato e sopportato sempre, ed alla quale devo tutto. All'amore di mio padre, mia madre e mio fratello. Un pensiero ai miei nonni, a nonno Remo che mi guarda da lassù e nonna Amalia, che ogni volta che passavo un esame ripeteva “Toccherà mettese el cappello”. Non è facile trovare persone che credono in te anche quando tu stesso hai smesso di Ringraziamenti farlo, per questo dedico un ringraziamento speciale ad e-xtrategy, che ha saputo capirmi in uno dei periodi più difficili della mia vita, continuando a darmi fiducia: forse Lorenzo non dimenticherà un nostro colloquio, alquanto poco professionale :-) Al pazzo fine estate 2011, ed alle nuove persone che mi ha portato. Michela, Lara, Luca: parte del sorriso che oggi ho sulle labbra è anche grazie a voi :-) A Mauro, perché è l'Amico, con la A maiuscola. Potrei scrivere pagine e pagine su di lui, le nostre avventure ed aneddoti, ma credo che gliele riferirò personalmente, magari davanti una buona birra. Ai miei compagni di studi Gilberto e Filippo, amici e confidenti di scleri universitari e vita privata. Alla nonchalance (ti fischiano le orecchie Lele ?). A tutti i miei amici storici, non vi posso elencare perché finirei col dimenticare qualcuno, ma credetemi, siete tutti quanti nei miei pensieri. Alla mia amica Alice per le nostre chiacchierate da sognatori. A te ho già dedicato più di un anno di vuoto nel mio libretto, direi che può bastare :D Vabbé, è giunto il momento di andare in copisteria e stampare queste pagine, il mio vicino mi sta mettendo fretta (eh Lele ?) e non ha torto: tutta 'sta neve sta rendendo le cose non troppo semplici, meglio sbrigarsi finché possiamo. Ah, dimenticavo una cosa importantissima! Ora mamma posso dirtelo: ho scelto informatica perché almeno mi compravi il computer :-)