Realizzazione della più evoluta Architettura di Continuous Integration


Il software è tradizionalmente  sviluppato in tre distinte fasi lineari: progettazione, codifica e test. Tuttavia, questo processo lascia troppo spazio alla possibilità di errori; nella progettazione funzionale, i bug introdotti dalla codifica di scarsa qualità, ed una fase di test avviata solo alla fine del processo, possono infatti aggiungere una rilevante quantità di tempo e rischi ad un progetto.

Una fase di  testing tardiva e protratta nel tempo ha un effetto domino. Più a lungo i bug restano nascosti,  maggiori sono infatti le possibilità per gli sviluppatori di  lavorare con software di scarsa qualità  che causerà solo ulteriori ritardi, poiché più bug verranno trovati nella base di codice e dovranno essere corretti. Questi ritardi non sono costosi solo in termini di tempo, ma anche finanziariamente,  e potenzialmente trasformano quello che era un progetto fattibile in un disastro per il budget.

La strategia ideale per qualsiasi azienda in procinto di rilasciare sul mercato un prodotto  software è quella di avere un processo in atto che supporti il test del software il più anticipatamente possibile nel ciclo di sviluppo,che consenta di effettuare molto rapidamente le modifiche e di essere pronti per una immediata distribuzione sul  mercato.

Può sembrare il Nirvana? Ė possibile, e  in questo articolo voglio illustrare il mio pensiero su come realizzare il più evoluto Sistema di Continuous Integration (CI).

Come realizzare una architettura CI intelligente e scalabile?  

L’idea di Continuous Integration (CI) ruota attorno alla capacità  di continuare a compilare e testare una applicazione ogni qualvolta una modifica sia stata o debba essere eseguita. Il testing manuale funziona bene se la base del codice è piccola ma  oggigiorno, con software embedded posti al cuore di così tanti prodotti e progetti, specialmente nei settori regolamentati, questo processo deve essere automatizzato per poter affrontare la quantità di software da testare.

Risolvere il problema della qualità del software e del time to market resta una lotta senza tregua, ma la Continuous Integration aiuta sviluppatori ed ingegneri a risolvere queste questioni senza timori.

Credo ci siano cinque considerazioni da tenere presente nella costruzione dell’ambiente di analisi ideale

  • Anticipate le attività di test – offrite strumenti che consentano agli sviluppatori di effettuare i test ogni volta che ne hanno bisogno.
  • Fornitevi di strumenti che consentano agli sviluppatori una visione della completezza del testing e generino automaticamente test case per frammenti di codice che non siano completi.
  • Costruite un archivio che consenta di automatizzare la programmazione delle attività di integrazione. Gli sviluppatori hanno bisogno di essere messi in grado di eseguire test di integrazione con la stessa facilità con cui possono eseguire i test di unità.
  • Parallelizzate e scalate l’architettura di test per ottenere tempi di compilazione più veloci. Ciò dovrebbe includere la possibilità di effettuare test e simulazioni di tutti i diversi ambienti hardware sui quali il software sarà distribuito.
  • Realizzate una supervisione intelligente in grado di comprendere quale sia il minore numero  di test da rieseguire in presenza di una variazione del codice sorgente.

Questa architettura intelligente e scalabile consentirà alle aziende di beneficiare dall’essere in grado di ricavarne un vantaggio competitivo,in quanto esse possono facilmente rispettare le date di rilascio e reagire rapidamente ai cambiamenti del mercato.

Anticipazione delle attività di test: Agile development o Test-DrivenDevelopment(TDD), è lo stesso

Lo scopo del sistema di Continuous Integration (CI) più evoluto è quello di abilitare i test subito e spesso (sviluppo basato su test) al fine di evitare ciò che è noto come ”l’inferno dell’Integrazione”. Nelle moderne applicazioni embedded con milioni di righe di codice, lasciare la fase di collaudo per ultima è una pratica pericolosa.

Gli sviluppatori potrebbero trovarsi costretti ad abbandonare un progetto o ad affrontare gravi difficoltà finanziarie e possibili sanzioni per aver scoperto un bug troppo tardi. Questo ben noto grafico mostrato nella figura 1 illustra perfettamente il punto in cui è più facile e più conveniente ricercare e correggere un bug prima che sia tardi.

La Continuous Integration è pensata per essere combinata con test di unità automatizzati. Storicamente si riteneva fosse meglio eseguire tutti i test di unità in ambiente locale degli sviluppatori e confermare che tutti questi test fossero stati superati  prima di rendere disponibile questo codice archivio per evitare la diffusione di codice con problemi.

Con lo sviluppo delle pratiche di CI, è stato introdotto il concetto di server di compilazione per eseguire automaticamente i test di unità e, nel tempo, questo è stato ampliato per includere anche l’applicazione di processi continui di QA. Questa evoluzione migliora la qualità del software, riduce il Time-ToMarket e costruisce una solida base per il futuro del codice riducendo la prevalenza del Debito Tecnologico (Technical Debt).

Chi e cos’è  Jenkins?

Senza Jenkins, uno strumento Open Source server-based di Continuous Integration scritto in Java, eseguire la ricompilazione incrementale di una applicazione può richiedere ore, e i test potrebbero richiedere settimane, mentre Jenkins abilita test continui ogni volta che una variazione del codice sorgente viene eseguita molto rapidamente.

Introdotto ad inizio 2005, Jenkins ha ora oltre 400 plugin che consentono al software di essere utilizzato con altri linguaggi di codifica per supportare compilazione e test di qualsiasi progetto. Jenkins è meglio descritto come “job server” con nessun limite riguardo a quale processo sia necessario eseguire,che si tratti di un comando ‘make’ per compilare e collegare un’applicazione, uno script batch per installare le precondizioni per un test, o un eseguibile che favorisca un ambiente di simulazione completo di un sistema embedded.

Jenkins assiste la Continuos Integration offrendo un’infrastruttura distribuita di test che fornisce la possibilità di definire un elenco di ‘nodi’ (questi possono essere macchine fisiche o virtuali), ‘taggare’ un nodo per indicare i tipi di processi che possono essere eseguiti, inviare da remoto liste di processi di nodi e relazionare sullo stato di un processo quando questo è terminato. In termini semplici, Jenkins è il maggiordomo che prende istruzioni sotto forma di un elenco di processi da eseguire.

Il risparmio di tempo è  uno dei vantaggi chiave della CI, e Jenkins contribuisce a questo offrendo un ambiente di lavoro per un approccio ottimizzato e distribuito alla compilazione ed esecuzione dei test.

Jenkins gioca un ruolo vitale nella CI, ma è necessario software aggiuntivo per gestire il processo di integrazione complessiva e fornire visibilità  per un completo ambiente di  test CI. Perché laContinuous Integration sia più efficace, tutti i membri di un team di sviluppo software hanno bisogno di essere messi in grado di condividere i test ed essere sempre aggiornati riguardo alla rapidità dei rilasci.

Tuttavia, molte delle applicazioni odierne vengono distribuite in più ambienti e configurazioni e, pertanto, l’ambiente di compilazione e test deve poter  testare diversi sistemi operativi e combinazioni hardware. Questo è normalmente controllabile con i file di configurazione, le macro e le opzioni del compilatore per specificare le diverse versioni. È fondamentale che il testing sia completato per ogni configurazione e, pertanto, ilSistema CI più evolutoha bisogno di strumenti per gestire i processi.

Aggiungere Parallelizzazione alla Simulazione

L’organizzazione del processo è solo una parte del processo stesso. E’ anche fondamentale l’utilizzo di una struttura parallela di testing per l’elemento di riduzione dei tempi della CI. Utilizzando Jenkins come server CI, i Target di test devono anche essere vagliati, ed una delle scelte più note è l’utilizzo di  Simics® di Wind River®. Simics funziona come un simulatore che può replicare una modalità dell’Hardware Target.

Utilizzando Jenkins e Simics insieme, gli ingegneri possono decidere quale ambiente testare ed individuare quali casi necessitano di essere ricompilati ed eseguiti in base alle modifiche apportate al codice sorgente. Gli sviluppatori possono effettuare il set up di differenti configurazioni della stessa scheda per eseguire test equivalenti, il che consente complete attività di coverage dei test.

Simics rende il testing più affidabile dato che, avendo la possibilità di testare un modello dell’hardware (a volte persino prima che questo sia disponibile),ci sono meno possibilità di incorrere in errori con i test effettivi, che potrebbe far sprecare tempo prezioso. Simics offre anche la possibilità di registrare e riprodurre i valori di input, il che supporta la CI consentendo l’accesso alle informazioni e al loro utilizzo da parte di altri membri del team.

Per agevolare un ambiente completo di CI, è necessaria una piattaforma unificata che metta insieme tutti questi elementi in un solo luogo. La soluzione ideale è una piattaforma che possa organizzare tutti i test case in gruppi che consentono agli sviluppatori di mappare l’architettura dell’applicazione e consenta di testare singoli stack, anticipando i test di sistema, e accelerando la versione pronta per la distribuzione.

Effettuare i test solo su ciò che effettivamente lo richiede

Ora che abbiamo un ambiente che possa eseguire una suite completa di test e il più rapidamente possibile, ulteriori prestazioni software ottimali possono essere ottenute soltanto effettuando quegli specifici test richiesti, per ripristinare il 100% della totalità del testing quando viene apportata una modifica al codice sorgente.  Il principio dell’analisi di impatto di un cambiamento (Change-Impact Analysis) è ben conosciuto e documentato ed è l’ingrediente finale nella creazione delpiù evoluto Sistemadi CI.

In VectorCAST abbiamo una funzionalità di Change-Based Testing che identifica automaticamente i test minimi necessari da eseguire per ogni variazione del codice.  Ciò significa che, invece di eseguire 10.000 test, sia richiesto che solo una frazione dei test siano eseguiti nuovamente quando avviene un cambiamento. Questo riduce notevolmente il tempo, che si riduce da giorni a minuti.

Conclusioni

Per inserire tutto questo in un contesto voglio condividere un esempio di un ipotetico scenario che potete trovare sul nostro sito Web. Abbiamo un piccolo progetto di 20 ambienti per un totale di 122 test di unità che utilizza il nostro ambiente di analisi mostrato in figura 3, che contiene VectorCAST, un server di Jenkins con 9 nodi slave distribuiti su 3 host di prova, ognuno con 3 ambienti di board simulati. Sappiamo che abbiamo un riferimento di 47 minuti per compilazione ed esecuzione combinati, utilizzando un singolo nodo slave e scheda Simics per eseguire un set completo di test.

Per dimostrare la potenza del parallelismo, creiamo i processi dei 20 ambienti test utilizzando VectorCAST, che li invia ad una coda di compilazione Jenkins. Jenkins eseguirà i primi 9 processi sui nodi slave dove vengono eseguiti sulle schede Simics, e ciò prosegue fino a quanto la compilazione non sia completa. Il risultato è un tempo complessivo di ricompilazione ripartito di 7:47secondi. Ciò equivale ad una compilazione  6 volte più veloce o l’85% di risparmio sui tempi.

Apportiamo alcune modifiche a 2 dei moduli e quindi avviamo una ricompilazione. Tra VectorCAST e Jenkins, il sistema eseguirà solo quei test che hanno bisogno di essere  nuovamente eseguiti, ed invierà i processi in coda e sui nodi slave. Ciò che accade è che il primo modulo ha bisogno di una completa ricompilazione e analisi dei tre casi di test, mentre il secondo modulo deve solo completare una ricompilazione incrementale e l’esecuzione di 2 dei 9 casi.

Il risultato è stato che solo per 5 test case è stata necessaria l’esecuzione, su un totale di 122 totalidel progetto. Ne è conseguito un tempo di esecuzione per la ricompilazione inferiore ai due minuti. In termini di tempo risparmiato rispetto al riferimento stabilito, stiamo parlando di circa il 95%.

Ritengo che questo dimostri chiaramente la potenza di un ambiente di testing distribuito parallelizzato in grado di supportare continue variazioni dei requisiti.

 

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *