Testing
Affichè si possa realizzare del software valido, ovvero funzionante ed ottimizzato, occorre effettuare delle campagne di testing rigorose.
A tal proposito è opportuno precisare che esistono diverse metodologie ed approcci per testare il software creato. Tra gli approcci più gettonati vi è il cosiddetto metodo delle white box e quello delle black box. Nel primo caso i test vengono eseguiti tenendo conto del codice sorgente, oltre che del corretto funzionamento del software lato utente. Nel secondo caso, invece, il software viene visto come una vera e propria scatola nera; per la precisione i test si occupano soltanto di verificarne il corretto funzionamento lato utente, tralasciando completamente l'analisi del codice sorgente.
Quando si analizza un software, alla ricerca di eventuali errori, è necessario tenere a mente alcuni termini ricorrenti, quali:
1) failure: ovvero la discrepenza tra il comportamento effettivo di un dato software e quello previsto;
2) fault: malfunzionamento del software causato da uno o più errori;
3) eccezione: ovvero la tecnica attraverso cui il sistema software può segnalare allo sviluppatore (o all'utente) il verificarsi di un dato errore;
4) bug (alias baco): ovvero un errore di programmazione più o meno grave.
In base ai componenti del software da analizzare, esistono diverse tipologie di testing, ad esempio:
1) unit testing, che esamina il funzionamento di un particolare modulo di cui è dotato il sistema;
2) integration testing (conosciuto anche come system testing), ovvero i test immediatamente successivi all'integrazione di uno o più moduli software;
3) acceptance testing, ovvero i test effettuati lato utente che verificano il corretto funzionamento del software e soprattutto la sua conformità con ciò che è stato decretato dall'analisi dei requisiti.
Tornando a bomba sul concetto di integrazione, occorre precisare che esistono diversi approcci per affrontare tale problematica. Il primo approccio consiste essenzialmente nell'integrare dapprima i moduli più importanti, per poi arrivare a quelli più elementari (approccio top-down). Il secondo approccio è speculare al primo, ovvero si parte dall'integrazione dei moduli più elementari per poi arrivare a quelli più importanti (bottom-up). Infine, vi è il cosiddetto approccio a macchia d'olio: si parte da alcuni moduli e si procede con l'integrazione in base alle necessità.
Per i software di grandi dimensioni spesso viene adoperato un approccio leggermente diverso. In particolare, la fase di testing si articola in due sottofasi, quali:
1) alpha testing, in cui gli stessi sviluppatori (o una cerchia ristretta di dipendenti appartenenti alla medesima ditta che ha creato il software), si occupano di verificare il corretto funzionamento del sistema;
2) beta testing, in cui una ristretta cerchia di utenti (esterni alla ditta che ha sviluppato il software) si occupa di verificare la qualità del sistema creato.
Inoltre, poichè spesso esistono più versioni di uno stesso software, magari rilasciate in periodi di tempo successivi, spesso viene adottata la tecnica del cosiddetto testing di regressione. Più precisamente, viene verificato che tutte le componenti funzionanti nelle versioni precedenti del software continuino a funzionare anche nella nuova versione.
Un'importante operazione da effettuare in fase di testing è l'analisi del codice sorgente. Tale analisi può essere di due tipi:
1) analisi statica;
2) analisi dinamica.
Nel primo caso viene controllato il codice dal punto di vista sintattico (definizione delle strutture, uso corretto dei segni di punteggiatura, ecc.) e lessicale (individuazione degli identificatori, delle parole chiave, ecc.). Viene inoltre fatta una verifica sui tipi di dato assegnato alle variabili (e sulle operazioni che le coinvolgono), oltre all'analisi dell'evoluzione temporale delle variabili stesse (dalla laro assegnazione fino al loro flush).
Per ciò che concerne l'analisi dinamica, le operazioni effettuate vengono identificate con il termine di copertura. I tipi di copertura sono molteplici, ovvero:
1) copertura dei comandi, in cui vengono eseguiti, uno per uno, tutti i comandi definiti all'interno del codice;
2) copertura delle decisioni, in cui, a differenza del caso precedente, si tiene conto anche dei costrutti decisionali (if - then - else);
3) copertura dei cammini, che comprende tutti i possibili cammini del programma (definiti dai costrutti decisionali), considerando anche i cicli e le iterazioni.
Documentazione
Alla base di un buon software c'è sempre una buona documentazione. Per documentazione, oltre al manuale dell'utente, si intende:
1) documentazione del progetto, in cui vengono definite le varie fasi da seguire durante la realizzazione del sistema;
2) documentazione del codice, realizzata principalmente attraverso i cosiddetti commenti, presenti all'interno del codice sorgente, oppure attraverso l'uso di librerie apposite (ad esempio JavaDoc).
Per ciò che concerne l'interazione tra le diverse figure professionali che partecipano allo sviluppo del software (analisti, sviluppatori, ecc.) è di vitale importanza utilizzare alcuni strumenti appositi, quali il documento dei requisiti. Esso ha come scopo anche quello di "regolare" lo scambio di informazioni con i clienti e viene realizzato utilizzando dello pseudocodice, meno soggetto ad errori di interpretazione rispetto al linguaggio naturale.
Altri strumenti molto utili per documentare il comportamento del codice sono gli alberi di decisione, le tabelle di decisione e i diagrammi di flusso (flowchart). Un'alternativa ai diagrammi di flusso è rappresentata dal linguaggio UML, i cui diagrammi principali sono i seguenti:
1) diagramma dei casi d'uso, che ha come scopo quello di rappresentare l'interazione dell'utente con il sistema;
2) diagramma degli oggetti;
3) diagramma delle classi;
4) diagramma di sequenza, che rappresenta le modalità con cui entrano in gioco le diverse componenti del sistema;
5) diagramma di deployment, che indica come i vari oggetti vengono distribuiti sui sistemi hardware;
6) diagramma delle attività, che rappresenta l'ordine di esecuzione delle varie attività dell'applicazione;
7) diagramma di collaborazione, che indica come le varie componenti del sistema software interagiscono tra di loro;
8) diagramma degli stati, che specifica l'evoluzione dello stato dei vari oggetti.
Manutenzione
La manutenzione del software è sicuramente una delle operazioni più critiche in assoluto. In particolare essa si occupa delle varie modifiche, evoluzioni ed aggiornamenti a cui il sistema è soggetto durante il corso della sua vita. A tal proposito, per manutenibilità si intende la caratteristica grazie alla quale un dato software può essere modificato senza impattare sulle performance e la funzionalità dello stesso. A ciò si aggiunge un sostanziale risparmio di risorse, sia in termini di denaro e forza lavoro che in termini di tempo.
Altra caratteristica fondamentale di un software è la riusabilità del codice, garantita anche grazie all'uso delle cosiddette API (Application Programming Interface).
Infine, da non sottovalutare è certamente la portabilità del codice, che lo rende teoricamente "indipendente" dall'architettura hardware e dal sistema operativo su cui lo stesso è installato.
Nelle operazioni di manutenzione e sviluppo software il versioning ricopre un ruolo fondamentale. Esso viene realizzato attraverso dei software appositi, detti Concurrent Versioning System (ad esempio CVS), che consentono a più sviluppatori di lavorare contemporaneamente sullo stesso codice, tenendo traccia delle modifiche apportate da ciascuno di essi.
Le operazioni che vengono eseguite, in soldoni, sono due:
1) check out, ovvero lo sviluppatore accede in scrittura al codice per poterlo modificare;
2) check in, grazie al quale lo sviluppatore, tramite un commit, salva le modifiche apportate al codice.
Ovviamente i CVS devono gestire la concorrenza, quindi nel caso in cui due svuluppatori tentassero di salvare contemporaneamente le modifiche apportate al codice sorgente, il software di versioning li avviserebbe di quanto sta avvenendo generando un errore opportuno e suggerendo le possibili soluzioni al problema
Più in generale, una corretta manutenzione del codice prevede le seguenti attività:
1) ispezione del codice sorgente;
2) definizione di regole comuni per la scrittura della documentazione;
3) scrittura di documentazione tecnica allegata al software stesso.
E' tutto. A presto.