Il processo di produzione del software
Il processo che seguiamo per costruire, consegnare, installare ed evolvere il prodotto software, dall’idea fino alla consegna e al ritiro finale del sistema, è chiamato processo di produzione software.
Innanzitutto occorre riconoscere diverse problematiche.
-
I requisiti imposti dal cliente possono cambiare spesso.
-
Produrre software non è solo scrivere codice (alla Programmazione I).
-
Bisogna risolvere i problemi di comunicazione tra tutte le diverse figure in gioco (tra sviluppatori, tra progettista e sviluppatori, ecc).
-
Bisogna essere rigorosi, anche se può risultare difficile. Ci sono lati positivi e negativi: la rigorisità può facilitare la comprensione di ciò che bisogna fare ma implica al contempo molta fatica extra, e viceversa.
Ipotesi di Bauer-Zemanek (BZh3): Metodi formali riducono in maniera significativa gli errori di progettazione, oppure permettono di eliminarli e risolverli prima.
Questa affermazione resta un’ipotesi perchè non è possibile dimostrare che sfruttando dei metodi formali ci sia una diminuzione degli errori, anche se nella pratica ciò avviene costantemente.
Trovare gli errori prima della fase di sviluppo permette di facilitarne la risoluzione e di risparmiare sia tempo che soldi: tanto prima si individua un errore, tanto più facile sarà risolverlo. Tuttavia è importante sottolineare che utilizzare metodi formali non è necessario in ogni caso, perchè queste operazioni richiedono molto tempo, che deve essere sottratto ad altre fasi, ma spesso a causa delle consegne imminenti non è possibile permettersi di investire troppo tempo nella formalità.
-
Ci sono tanti aspetti da considerare, che andranno affrontati uno alla volta. Per parlare di aspetti diversi ho bisogno di metodi comunicazione diversi, che interessano ruoli diversi in tempi diversi (Aspect Oriented Programming).
Tenendo a mente tutto queste problematiche è necessario decidere come organizzare l’attività di sviluppo software in modo da mitgarle. Per modellare un ciclo di vita del software, occorre dunque in primo luogo identificare le varie attività necessarie e quindi:
- deciderne le precedenze temporali;
- decidere chi le debba fare.
In particolare, ci si pone due domande:
- cosa devo fare adesso?
- fino a quando e come?
L’ingegneria del software prova a rispondere a queste domande per individuare quali siano le fasi necessarie per sviluppare un software e quale sia la loro migliore disposizione temporale. È dunque bene specificare da subito che lo sviluppo di un programma non è solo coding: tale presupposto genera conseguenze disastrose.
Inizialmente, infatti, nell’ambito dello sviluppo software è stato adottato il modello code-and-fix, che consisteva nei seguenti passi:
- scrivi il codice;
- sistemalo per eliminare errori, migliorare funzionalità o aggiungere nuove funzionalità.
Ben presto però questo modello si è dimostrato pesantemente inefficace in gruppi di lavoro complessi, specialmente quando il cliente non era più lo sviluppatore stesso ma utenti con poca dimestichezza con i computer, generando codice estremamente poco leggibile e manutenibile.
Per organizzare meglio l’attività di sviluppo e non ricadere negli errori del passato gli ingegneri del software hanno dunque individuato diverse fasi del ciclo di vita di un software che, combinate, permettessero di produrre del software di qualità. Diamo dunque un’occhiata a quelle principali.
Le fasi del ciclo di vita del software
Studio di fattibilità
Lo studio di fattibilità è l’attività svolta prima che il processo di sviluppo inizi, per decidere se dovrebbe iniziare in toto. L’obiettivo è quello di produrre un documento in linguaggio naturale presentante diversi scenari di sviluppo con soluzioni alternative, con una discussione sui trade-off in termini di benefici e costi attesi. Questo documento è scritto utilizzando un linguaggio naturale perchè è destinato ai manager e non direttamente a coloro che devono sviluppare il progetto.
Più specificatamente, il documento include:
- uno studio di diversi scenari di realizzazione, scegliendo:
- le architetture e l’hardware necessario;
- se sviluppare in proprio oppure subappaltare ad altri.
- stima dei costi, tempi di sviluppo, risorse necessarie, benfici delle varie soluzioni e valutazione del return on investment.
È spesso difficile fare un’analisi approfondita, a causa del poco tempo disponibile o di costi troppo elevati, di conseguenza non è raro che questa fase venga commissionata esternamente, in modo da poterla affidare a del personale esperto e investire il tempo risparmiato per altre attività.
Analisi e specifica dei requisiti
L’analisi e specifica dei requisiti è l’attività più critica e fondamentale del processo di produzione del software. L’obiettivo è la stesura di un documento di specifica .
In questa fase i progettisti devono:
- comprendere il dominio applicativo del prodotto, dialogando con il cliente e la controparte tecnica;
- identificare gli stakeholders, ovvero tutte le figure interessate al progetto, e studiarne le richieste. Spesso non si tratta di figure omogenee (può essere il top manager fino al segretario) e le loro necessità sono molto diverse;
- capire quali sono le funzionalità richieste: la domanda più importante che deve porsi il programmatore è il cosa non il come; al cliente non devono infatti interessare gli aspetti tecnici e le scelte architetturali interne. Le specifiche vanno quindi viste dal punto di vista del cliente.
- stabilire un dizionario comune tra cliente e sviluppatore che può anche far parte della specifica per agevolare la comunicazione (questo perchè la stessa parola in contesti differenti può assumere significati diversi, e quindi creare ambiguità);
- definire altre qualità eventualmente richieste dal cliente: per esempio, “la centrale non deve esplodere” non è un dettaglio implementativo, ma un requisito. Queste ulteriori qualità, che non sempre sono solo esterne, si dicono requisiti non funzionali.
Lo scopo del documento di specifica è duplice: da una parte, deve essere analizzato e approvato da tutti gli stakeholders in modo da verificare il soddisfacimento delle aspettative del cliente, e dall’altra è usato dai programmatori per sviluppare una soluzione che le soddisfi, fungendo da punto di partenza per il design. È un documento contrattuale e deve essere scritto in modo formale per evitare contestazioni contrattuali e ambiguità.
Deve essere presente anche un piano di test, ovvero una collezione di collaudi che certificano la correttezza del lavoro: se questi test hanno esito positivo il lavoro viene pagato, altrimenti il progetto non viene accettato. A differenza dei lavori di altri tipi di ingegneria, per esempio l’ingegneria civile, dove il collaudo è diretto, nell’ingegneria del software è molto difficile collaudare tutti i casi e gli stati possibili.
Un altro output di questa fase può essere anche il manuale utente o maschere di interazione, ovvero la “vista esterna” (ciò che il cliente vuole vedere, evitando i dettagli implementativi) del sistema da progettare.
Il documento di specifica è un documento scritto in modo formale, perchè è la base da cui partire per iniziare lo sviluppo. è possibile sfruttare due tipi di modelli per produrre il documento di specifica:
- Modelli descrittivi: I modelli descrittivi rappresentano il sistema logicamente in modo da poter verificare le sue proprietà.
- Modelli operazionali: I modelli operazionali forniscono una rappresentazione del sistema tramite un modello eseguibile capace di mostrare le proprietà del sistema (in questo caso è facile cadere nella tentazione di pensare subito al come realizzare una funzioalità).
Legge di David: Il valore dei modelli che rappresentano il software da diversi punti di vista dipendono dal punto di vista preso (assunto), ma non c’è nessuna vista che è la migliore per ogni scopo.
Progettazione (design)
Il design è l’attività attraverso la quale gli sviluppatori software strutturano l’applicazione a diversi livelli di dettaglio. Lo scopo di questa fase è quello di scrivere un documento di specifica di progetto contenente la descrizione dell’architettura software (i diversi linguaggi e viste).
Durante questa fase occorre quindi:
- scegliere un’architettura software di riferimento;
- scomporre in moduli o oggetti gli incarichi e i ruoli: si tratta del cosiddetto object oriented design, non necessariamente accompagnato da object oriented programming;
- identificare i patterns, ovvero problemi comuni a cui è già stata trovata una soluzione generale giudicata come “bella” dalla comunità degli sviluppatori (ne vedremo un paio più avanti nel corso). I pattern favoriscono alcune qualità, come il design.
Programmazione e test di unità
In questa fase le “scatole nere” - i moduli o oggetti definiti al punto precedente - vengono realizzate e per ognuna di esse vengono definiti dei test unitari che ne mostrano la correttezza. Vi è infatti spesso la brutta abitudine di non fare il testing durante lo sviluppo di ciascun componente, ma solamente alla fine di tutto: questa usanza è molto pericolosa perché un problema scoperto solo alla fine è molto più oneroso da risolvere.
I singoli moduli vengono testati indipendentemente, anche se alcune funzioni da cui dipendono non sono ancora sono state implementate: per risolvere tale dipendenza si utilizzano allora moduli fittizzi (stub) che emulino le funzionalità di quelli mancanti. Altri moduli, detti driver, forniscono invece una situazione su cui applicare il modulo che sto testando. Nei linguaggi più utilizzati esistono framework che facilitano le suddette operazioni al programmatore.
L’obiettivo di questa fase è avere un insieme di moduli separati sviluppati indipendentemente con un’interfaccia concordata e singolarmente verificati.
Integrazione e test di sistema
In questa fase i moduli singolarmente implementati e testati vengono integrati insieme a formare il software finito. In alcuni modelli di sviluppo (come nello sviluppo incrementale) questa fase viene accorpata alla precedente.
Nei test, i moduli stub e driver vengono sostituiti con i componenti reali formando un sistema sempre più grande fino ad ottenere il risultato richiesto. Quindi i diversi moduli non vengono “assemblati” in una volta sola per poi testare il risultato finale, ma è un’operazione incrementale, fatta aggiungendo un modulo alla volta per evitare che si presentino diversi errori difficili da individuare. Infine è fondamentale testare che l’intero programma per verificare che funzioni una volta assemblato (non basta che le singole parti funzionino!): test di questo tipo vengono detti test di integrazione.
L’integrazione può essere adottata seguendo un approccio top down o bottom up. La fase finale è l’alpha testing, ovvero il testing del sistema in condizioni realistiche.
Consegna, installazione e manutenzione
Dopo aver completato lo sviluppo, il software deve essere consegnato ai clienti. Prima di consegnarlo a tutti, si seleziona un gruppo di utenti per raccogliere ulteriore feedback; questa fase è chiamata beta testing.
L’installazione (deployment) definisce il run-time fisico dell’architettura del sistema. Per esempio, un servizio di rete potrebbe necessitare di apparecchiatura server da installare e particolari configurazioni.
Infine, la manutenzione può essere definita come l’insieme delle attività finalizzate a modificare il sistema dopo essere stato consegnato al cliente. La manutenzione può essere di tipo:
- correttivo: sistemare errori nel sistema;
- adattivo: adattare il software ai nuovi requisiti (vd. evolvibilità);
- perfettivo: migliorare certi aspetti interni al programma senza modificare gli aspetti esterni, anche se quest’ultimi possono subire dei miglioramenti. Serve per migliorare la futura manutenzione riducendo il cosiddetto debito tecnico.
Come già detto, è necessario sviluppare avendo in mente la futura manutenzione di ciò che si sta scrivendo: infatti, il costo della manutenzione concorre al costo del software in una misura spesso superiore al 60%.
L’output di questa fase è un prodotto migliore.
Altre attività
Alle attività sopracitate se ne aggiungono altre:
- Documentazione: può essere vista come attività trasversale, da creare seguendo l’evoluzione del progetto. Per esempio, un documento di specificazione contenente diagrammi UML e una descrizione narrativa che spiega le motivazione dietro certe decisioni può essere il risultato principale della fase di progettazione. È un’attività che spesso viene procastinata, perché le specifiche possono cambiare spesso. In alcuni gruppi esistono delle figure che si occupano di questa attività, anche se può essere pericoloso: non tutti possono capire ciò che un programmatore ha creato.
- Verifica e controllo qualità (Quality Assurance): nella maggior parte dei casi, la verifica è svolta attraverso review e ispezioni. L’obiettivo è anticipare il prima possibile la scoperta e la sistemazione degli errori in modo da evitare di consegnare sistemi difettosi. Andrebbe fatta costantemente e non tutta alla fine.
- Gestione del processo: gestione incentivi (premi di produzione), responsabilità, formazione del personale, perfezionamento del processo con l’esperienza guadagnata, eccetera.
- Gestione delle configurazioni: gestione delle relazioni inter-progettuali, ovvero delle risorse di sviluppo non appartenenti ad un singolo progetto. Un esempio potrebbe essere una libreria condivisa tra più progetti, i quali vorrebbero modificare la libreria stessa.
Tutte queste diverse attività saranno specificate successivamente entrando nel dettaglio.