La Difficile Professione Dell'Ingegnere Del Software

Share Embed Donate


Short Description

Articolo tratto da Programmazione.it...

Description

La difficile professione dell’ingegnere del software di: Paolo De Nictolis pubblicato il: 18/06/2006 Introduzione Questo articolo nasce dalla lettura del testo “Principi di ingegneria del software – quarta edizione” di Roger S. Pressman, edito in Italia da McGraw-Hill (http://www.programmazione.it/index.php?entity=eitem&idItem=33643). Dopo aver finito di studiarlo, m i sono reso conto che la mole di considerazioni ed appunti che avevo raccolto non poteva esaurirsi nello spazio di una, per forza di cose sintetica, recensione; ed è così nato questo lavoro. Troverete in esso continui riferimenti al testo stesso, che ritengo una “lettura obbligata” per chiunque sia coinvolto, a qualsiasi titolo, in un progetto software. “Nell’attività professionale il termine ‘ingegnere del software’ ha sostituito il termine ‘programmatore’”: è una delle prime frasi della quarta edizione italiana (traduzione della sesta edizione inglese) del Pressman ma, purtroppo, è un’affermazione cui si potrebbero trovare molti controesempi nelle piccole realtà del software nostrano, alle quali gioverebbe molto la lettura di un’ottima (ed in molti capitoli semplice) panoramica introduttiva come questa.

Il processo di sviluppo software Il Pressman è ricco di citazioni, che “illuminano” la lettura. Dal canto mio, non posso che ricordare la mie preferite, quelle di Brooks: “Aggiungere persone a un progetto software in ritardo lo rallenta ulteriormente”; “Einstein sosteneva che deve esistere una spiegazione semplice della natura, perché Dio non è né capriccioso né arbitrario. Purtroppo l’ingegnere software non può essere sostenuto da questa fede: molte delle complessità che si trova a gestire sono di tipo arbitrario”. In quelle giornate un pò così (per l’ingegnere del software, una su tre), ci viene in soccorso Steve Wozniak: “Mai fidarsi di un computer che non puoi lanciare fuori da una finestra”. Leggendo il testo, sarebbe il caso di soffermarsi sul paragrafo 1.5, “I miti del software”: fra management, committente e programmatore, non si salva davvero nessuno. Ognuno reciti il proprio mea culpa (mi sono riconosciuto, agli inizi della mia carriera, in ogni mito del programmatore: il lavoro è finito una volta rilasciato il programma, che è l’unico frutto del lavoro svolto, mentre la documentazione serve a dare lavoro agli incapaci, ecc.), ma quando leggo i miti sui “volumi di standard e procedure che già abbiamo”, sull’orda mongola, sull’outsourcing totale e, soprattutto, sui “mutamenti che si gestiscono agevolmente grazie alla flessibilità del software” (cui aggiungerei la citazione di Paulk: “molto spesso i dirigenti ritengono che sia meglio avere qualcosa di sbagliato piuttosto che in ritardo, poiché si può sempre correggere il software in un secondo tempo”), mi tornano in mente, con un ghigno sarcastico e doloroso, tante scenette del mio lungo film di architetto (“Se ti chiedessimo di cambiare le fondamenta ad un palazzo di cui hai già fatto dieci piani lo voglio capire che è un lavoro che ti richiede tempo, ma mi spieghi perché ci vogliono tre mesi per rifare la reportistica? Credi che abbia l’anello al naso? Lo sanno tutti che con i moderni IDE generate il codice premendo un bottone!!!”). Nelle prime pagine del secondo capitolo trovo un’altra frase che mi piace molto, “il processo che si adotta dipende dal software che si sta realizzando”. Che per progettare la cuccia del cane serve un metro flessibile e per progettare un grattacielo serve uno studio di architettura lo sanno più o meno tutti, mentre molte figure dirigenziali, quando escono i modelli ciclici, il RUP, le metodologie agili e la programmazione Aspect-Oriented, devono appiccicare un bollino alla quarta revisione del gestionale ed al primo sito Web trionfalmente varato dalle quattro stanze prese in affitto …. ehm, dalla “software house”. Tornando al testo, nella panoramica iniziale sul processo di sviluppo software non può non trovare posto il meta-modello CMMI (http://www.sei.cmu.edu/cmmi/), nel suo duplice

1 di 16

aspetto di modello continuo ed a fasi. Non si può sbrigare il CMMI in qualche pagina, ma al di là del diventare esperti del meta-modello, occorrerebbe appiccicare da qualche parte sul muro il contenuto del box “Il CMMI: che cosa fare e che cosa evitare”. Certo, una volta adottato un processo, bisognerebbe adottare anche un approccio di valutazione del medesimo come quelli descritti nel paragrafo 2.5, possibilmente tentando di non ridurre per esempio la ISO 9001:2000 alla “cosa che ci serve per partecipare alle gare”, o di far credere in giro che “abbiamo il marchio ISO 9001:2000, la ISO 9126 la facciamo automaticamente”. Per le software house nostrane esistono addirittura i processi personali e di team, più o meno tutti riconducibili a tal Humphrey, tenendo presente che “il miglior processo di sviluppo software è quello più adatto alle persone che svolgeranno il lavoro”: in fondo è su questa base che sono state sviluppate le metodologie agili. Prima però di arrivarvi, non dovremmo mai dimenticare i classici modelli a processo prescrittivo: a cascata, incrementale, evolutivo, con una puntatina sul RUP (Rational Unified Process), del quale viene detto che “rappresenta un tentativo di sfruttare le migliori funzionalità e caratteristiche dei modelli convenzionali di sviluppo software, ma caratterizzandoli in modo da implementare molti dei migliori principi dello sviluppo agile”. Un breve paragrafo è anche dedicato all’Aspect-Oriented Programming: sostanzialmente, oltre al rimando al classico sito http://www.aosd.net, la bibliografia fa riferimento soprattutto al prodotto AspectJ (http://www.parc.com/research/projects/aspectj/default.html). Il RUP, grazie all’importanza dei casi d’uso scritti dall’utente, opera in un certo senso una rivoluzione copernicana nei processi di sviluppo, portata poi alle estreme conseguenze dalle metodologie agili: l’analisi dei requisiti diventa una responsabilità condivisa con il committente, piuttosto che un “processo maieutico” guidato dall’analista. Al di là della descrizione delle cinque fasi, delle “4 viste + 1” e degli artefatti del processo, è importante sottolineare, ancora una volta, che il team di sviluppo adatta il processo sulla base delle proprie esigenze. Lo sviluppo agile, o ingegneria del software leggera, la cui nascita si fa risalire al manifesto di Kent Beck e compagni del 2001 (http://www.agilemanifesto.com, anche se per esempio l’eXtreme Programming risale sicuramente al 1999, secondo alcuni alla fine degli anni ’80, il DSDM al 1997, e Scrum addirittura al 1996), è oggetto del quarto capitolo. Molto si è detto pro e contro questo tipo di ingegneria, che pone l’accento sulla costituzione di piccoli gruppi di progetto, sulla soddisfazione del cliente e sul rilascio incrementale di software funzionante a scapito, a detta dei suoi detrattori, dell’analisi, della progettazione e della documentazione: in sostanza, della soddisfazione stessa del cliente, nel lungo termine. In effetti lo stesso Cockburn, un esperto di metodologie agili, le loda per la loro capacità di tenere conto del fattore umano nell’ingegneria del software (anche se a volte si stenta a crederlo, gli sviluppatori sono esseri umani con le loro fragilità e debolezze), ma ammette al contempo che proprio per questo possono rivelarsi meno produttive dei processi prescrittivi. Potrei aprire qui un delicato discorso sull’equilibrio domanda/offerta di lavoro nel campo dell’informatica che determina richieste di produttività più o meno vicine agli standard umani, ma è meglio attenersi alla recensione del testo. Certo, mi piacerebbe conoscere il parere di Cockburn sul fatto che in Italia un “ingegnere del software” o “programmatore” che sia è di solito un laureato che segue un costante ed impegnativo percorso di aggiornamento professionale (di solito a proprie spese dopo le dodici.... pardon, otto ore di lavoro quotidiano), impegnato in un lavoro creativo e ad altissimo valore aggiunto, flessibile fino all’estremo ed orientato al risultato, che riceve lo stipendio di un metalmeccanico non specializzato alla catena di montaggio. Salomonicamente, Pressman non può che ricordare che, come tutte le metodologie, quella agile non può essere applicata a tutti i progetti (l’ingegneria dovrebbe essere, nella sua forma migliore, il campo in cui muoiono una volta per sempre i “massimi sistemi” e trovano posto i compromessi progettuali) e non è antitetica ad una solida pratica di ingegneria del software. Inoltre, afferma sempre Pressman, nessuno è contrario ai principi dell’agilità (soddisfazione del cliente, risposta rapida ai cambiamenti, ecc.), ma vi è tremenda discordanza e le solite “guerre di religione” sul modo di applicarla: in effetti, nello stesso ambito della scuola [i]agile[/i], sono stati proposti molti modelli a processo (Extreme Programming, http://www.xprogramming.com; Adaptive Software Development, http://www.adaptivesd.com; Dynamic Systems Development Method, http://www.dsdm.org; Scrum, http://www.controlchaos.com; Crystal, http://www.crystalmethodologies.org; Feature Driven Development, http://www.thecoadletter.com; Agile Modeling, http://www.agilemodeling.com, tutti presentati nel Paragrafo 4.3), e molti concetti della metodologia agile non sono altro che adattamenti dei migliori concetti di ingegneria del software. L’aver posto il capitolo sulle metodologie agili praticamente all’inizio del testo, ed i continui richiami “in avanti” ed “all’indietro”, testimoniano l’importanza che Pressman attribuisce loro. Personalmente, però, sebbene non metta in discussione (non lo fa nessuno) la validità di una seria e puntuale applicazione delle metodologie agili, sono molto dubbioso in merito ai fraintendimenti ed alle misinterpretazioni che possono ingenerare in ambienti immaturi (dal punto di vista dell’ingegneria del software, of course....), sia dalla parte degli sviluppatori che (soprattutto) da quella dei clienti. Capisco che uno dei fondamenti delle metodologie agili sia proprio quello di “eliminare ogni atteggiamento di tipo ‘noi e loro’”, ma è anche vero che la realtà è una brutta bestia quando si tratta di negarla. A mio avviso, le

2 di 16

metodologie agili forniscono straordinarie opportunità quando si verifichi una (miracolosa) “congiunzione astrale” di elevate competenze fra gli stakeholder; negli altri casi, per quanto sia una prassi pedagogica poco alla moda oggidì, ritengo che i bambini hanno bisogno di disciplina. Personalmente, per esempio, ho una grande ammirazione per il principio alla base del DSDM: quanti di noi spendono il 20% del loro tempo per sviluppare le funzionalità effettive di un prodotto software, e l’80% per renderlo usabile da un cliente che è.... beh, siccome gli eufemismi vanno di moda, diciamo “non sempre un esperto di tecnologie informatiche”? Un’altra affermazione di Pressman su cui voglio richiamare l’attenzione, se non altro perchè è nascosta in un box, è la seguente: “poichè lo sviluppo agile è di moda, la maggior parte dei produttori di strumenti software sostiene di fornire prodotti che supportano un approccio agile”. Mutatis mutandis, è una frase che ci accompagnerà durante tutta la nostra (spero lunga) vita di informatici.

La pratica dell’ingegneria del software Una panoramica sugli aspetti pratici dell’ingegneria del software non può che essere incentrata sui due tipi di modelli utilizzati: quelli analitici, con la loro rappresentazione del software nei tre domini delle informazioni, funzionale e comportamentale, e quelli progettuali. Sempre con riferimento al Pressman, i capitoli della seconda parte si occupano, in sostanza, di presentare (senza, ahimè, alcuna pretesa di completezza) i metodi e le notazioni tecniche che consentono agli ingegneri software di creare i modelli analitici e progettuali. Il primo passo è una visione ingegneristica non del solo software che si andrà a sviluppare, ma dell’intero sistema (hardware, software, database, procedure, persone...) in cui andrà ad inserirsi. Tutti gli ingegneri del software (me compreso) sono degli entusiasti tecnologi, pronti ad attaccarsi all’IDE ed a produrre codice, ma se ci si precipita a realizzare gli elementi tecnologici prima di comprendere il sistema, si commetteranno indubbiamente degli errori che faranno irritare il cliente. E senza cliente, ahimè, di software se ne sviluppa (soprattutto in Italia) davvero poco. Naturalmente, occorre affrontare il duplice aspetto dell’ingegneria di processo e di prodotto. Il Capitolo 7 affronta l’ingegneria dei requisiti, sostanzialmente l’incubo di ogni ingegnere del software. Inutile raccontarsi per l’ennesima volta le barzellette sul cliente che non ha idea dei tempi e dei costi, che ha una visione miracolistica dell’ingegneria del software (“siete così bravini, voi col compiuter” – l’errore è intenzionale – “fate tutto in cinque minuti”) e che in conclusione è il cliente della vignetta di Dilbert: “Prima di cominciare a sviluppare, dovremo fare dei lunghi incontri sul cosa sviluppare. In primo luogo: qual è il tuo obiettivo?” “Il mio obiettivo è farti cominciare a scrivere il software”. Innanzitutto, il cliente peggiore è l’altro tipo di cliente. Non avete mai incontrato l’altro? E’ il cliente che ha la Patente Europea del Computer, o un qualsiasi attestato di formazione su Windows/Office, ed in forza di questa preziosa certificazione, di informatica ne capisce molto più di voi. Ma al di là del nemico cliente, è vero purtroppo anche il contrario, ovvero che troppo spesso l’ingegnere del software non è un esperto del dominio del problema che dovrebbe risolvere. Sono più di quanti si pensi i casi in cui non lo è nemmeno il cliente, sed transeat. A questo si aggiungono due simpatici problemi, uno per parte. In primo luogo, la mutevolezza dei requisiti. Si può discutere a lungo se i requisiti che cambiano ad ogni minuto siano dovuti alla turbolenza del mercato o alla semplicioneria del cliente, ma la continua variazione dei requisiti è un dato di fatto: a volte, non si fa nemmeno in tempo a buttare giù un documento riassuntivo, che sono già cambiati. Questo porta al secondo problema, stavolta dalla parte degli sviluppatori: “visto che questi cambiano idea ogni momento, a che serve perdere tempo a fare l’ingegneria dei requisiti?”. L’ingegnere del software è un subdolo smanettone; paradossalmente, è il miglior amico del cliente delle barzellette, è il complice entusiasta del “come pretendete che vi dica sì o no sulla base delle vostre pile di carte? Datemi in mano un prodotto finito, ed io vi dico come rifarlo daccapo”. Delle sette funzioni dell’ingegneria dei requisiti, va a finire che la più importante è la terza, la negoziazione. Oltre ai problemi evidenziati, non è infrequente il caso di utenti differenti che pongano requisiti in conflitto, accompagnandoli con la magica frase “è fondamentale per le nostre necessità. Inutile anche chiedere al cliente la prioritizzazione dei task: sono tutti indispensabili, andavano tutti fatti entro ieri e sono tutti troppo costosi. L’ingegneria del software è l’ultimo residuo della schiavitù nel mondo occidentale, è il mondo in cui il cliente ti mette in mano mille vecchie lire e pretende la tua incondizionata disponibilità ventiquattr’ore su ventiquattro, e quella dell’ingegnere del software è una battaglia persa in partenza. Come ogni bravo professionista, lo sviluppatore vorrebbe essere uno specialista, vorrebbe diventare l’esperto di driver in C++ per l’industria elettromeccanica piuttosto che di interfacce Web con tecnologie Java. Gli viene invece richiesto di essere uno sviluppatore-sistemista-DBA universale, esperto riconvertibile di tutti i linguaggi e di tutte le tecnologie, figura fungibile in tutte le fasi del ciclo di vita, consulente di tutti i possibili clienti in tutti i possibili domini applicativi che siano mai stati inventati, oltre che team leader, commerciale ed ingegnere dei processi di business, della qualità e di tutto ciò che va di moda in giacca e cravatta. Con una particolare propensione a fare il commerciale, è ovvio, ed il tutto ad un milione-e-ottocentomila vecchie lire al mese, come ricordato.

3 di 16

Insomma, per non divagare troppo, l’ingegneria dei requisiti è la fase del ciclo di vita del software che ha ben poco di informatico, e molto di umano. Il primo compito dell’ingegnere dei requisiti è quello di individuare gli stakeholder del progetto (possono arrivare a diverse decine) e di farli collaborare in una metaforica stanza: non parliamo nemmeno delle metodologie agili, che si fanno un punto d’onore del rendere il cliente un membro del team di sviluppo. Per frenare i conflitti uno dei metodi più utilizzati è quello dei punti di priorità: a tutte le figure coinvolte nello sviluppo viene fornito un certo numero di punti, che possono essere spesi per i vari requisiti. E’ un metodo straordinariamente semplice, e nel contempo si è rivelato straordinariamente efficace nel combattere la sindrome del “tutto è importantissimo, tutto va fatto subito”. Ovviamente il numero di punti da distribuire può essere deciso in maniera arbitraria; il mio consiglio (non riportato nel libro) è: date meno punti a disposizione, di quanti siano i requisiti, e obbligate ad attribuire un numero intero di punti. Alla fine fate una matrice requisiti-votanti, e riempite solo gli incroci che hanno ottenuto punti. Ancor prima di esaminare i valori numerici, questa matrice vi aiuterà ad individuare non solo, com’è ovvio, i requisiti veramente importanti e quelli da spostare in fondo alla lista, ma anche e soprattutto le figure che hanno visioni contrastanti del progetto, nonché quelle il cui sguardo è concentrato solo su alcuni aspetti. Dopo la fase di avvio, vi sono solo tecniche dettate dall’esperienza, ma è sorprendente notare come questi insiemi di regole, dettate solo dal buon senso, siano sistematicamente ignorate da tutti gli attori coinvolti. L’attenzione del testo si concentra sulla tecnica del QFD (Quality Function Deployment, http://www.qfdi.org), che pone l’accento nella suddivisione di requisiti in classi che generano un diverso grado di soddisfazione del cliente. Inutile dire, infine, che una particolare enfasi è posta sul modello dei casi d’uso. La modellazione analitica, trattata nel Capitolo 8 ma già introdotta nel settimo, rappresenta un ponte fra la descrizione del sistema ed il modello progettuale; in realtà è talvolta difficile definire una distinzione netta fra progettazione ed analisi, anche perché tutti gli elementi del modello analitico rimandano direttamente alle parti del modello progettuale. La modellazione dei dati è una delle attività irrinunciabili della modellazione analitica, quella che di solito precede tutte le altre (primo o poi dovrò decidermi a recensire l’ultima versione dello storico ERWin, http://www3.ca.com/solutions/Product.aspx?ID=260). La modellazione analitica con i diagrammi UML prosegue con la creazione degli scenari, sotto forma di casi d’uso, diagrammi delle attività (Activity Diagram) e diagrammi Swimlane. Quest’ultimo è fondamentalmente un diagramma delle attività UML in cui viene indicato quale attore ha la responsabilità per ogni azione, suddividendo il diagramma in una serie di segmenti paralleli verticali, come le corsie di una piscina (da cui il nome). Ancora, la modellazione orientata al flusso di dati, tipica dell’analisi strutturata, tramite i diagrammi DFD (Data Flow Diagram), continua ad essere una delle notazioni più utilizzate, anche in affiancamento ai diagrammi UML, caratteristici invece dell’analisi orientata agli oggetti. Poiché esiste un’ampia gamma di applicazioni pilotate da eventi anziché da dati, è opportuno per essere affiancare la modellazione del flusso di controllo a quella dei dati, tramite i consueti strumenti della specifica del controllo (CSPEC), attuata solitamente tramite il noto diagramma stati-transizioni, della specifica procedurale (PSPEC), ed altri. La metodologia che riscuote più successo oggidì è sicuramente la modellazione basata su classi, cui viene dedicato il resto del capitolo. E’ oramai invalso l’uso di determinare un primo elenco delle classi da una semplice analisi grammaticale dei casi d’uso1, distinguendole fra classi necessarie per implementare la soluzione (spazio della soluzione) e classi utili solo per descrivere una soluzione (spazio del problema). In questa fase, un semplice esame dei nomi aiuta ad individuare le classi analitiche, mentre un ‘nome procedurale imperativo’ (come “installa-sensore”) definirà un metodo di una classe, più che una classe stessa. Occorre poi raffinare le classi individuate introducendo attributi e metodi. Per attribuire un grado di rilevanza alle classi individuate e scartare quelle superflue, molti team usano la modellazione CRC (ClassResponsibility-Collaborator). Per ogni classe viene costruita una scheda con il nome della classe, le sue responsabilità (gli attributi e le operazioni rilevanti per la classe) e le sue collaborazioni (che identificano le relazioni fra le classi). Come afferma giustamente il testo, “E’ molto più economico gettare via un mazzo di schede che dover riorganizzare una mole ingente di codice sorgente”. E’ oggi in auge la prassi di suddividere le responsabilità fra le classi, in modo da non “concentrare l’intelligenza” del software, ma da avere componenti che svolgono poche, ben specifiche funzioni, in modo ottimizzato e riusabile: prassi, naturalmente, alla base dello sviluppo per componenti. Le collaborazioni aiutano invece ad identificare quelle classi che devono essere organizzate in sottosistemi. Fino a questo punto, sono stati affrontati gli elementi statici del modello analitico. Un modello comportamentale indica invece come il software risponde agli eventi, ed al passare del tempo. Tipici prodotti della modellazione comportamentale sono i diagrammi stati-transizioni per ogni classe ed i sequence diagram (che sono, in pratica, delle versioni abbreviate dei casi d’uso). La progettazione è, invece, quel creativo lavoro che praticamente ogni ingegnere desidera fare, e che raramente riesce a fare. A differenza del modello analitico, il modello progettuale fornisce dettagli relativi alle strutture di dati,

1

L’analisi di un linguaggio naturale è, naturalmente, soggetta ad errori ed ambiguità. E’ il problema alla base della nascita dei metodi formali, come quelli che usano le estensioni OCL o il linguaggio Z.

4 di 16

all’architettura, alle interfacce ed ai componenti del software che sono necessari per implementare il sistema. Generalmente si progettano cinque viste, tra loro interrelate e piramidali: 1. i dati; 2. l’architettura; 3. le interfacce; 4. i componenti; 5. il deployment. E’ tuttavia opinione comune, non solo dell’Autore, che “ad oggi la maggior parte delle metodologie di progettazione del software non ha le doti di profondità, flessibilità e natura quantitativa che normalmente vengono associate alle discipline più classiche di ingegneria della progettazione”. Ciò che abbiamo sono metodi per la progettazione, criteri per la qualità del progetto e notazioni per la progettazione. Tuttavia, ogni sforzo umanamente possibile deve essere posto nella bontà del progetto, sulla base del principio di minor costo di reingegnerizzazione così efficacemente espresso dalla citazione dell’architetto Frank Lloyd Wright: “Sul tavolo da disegno si usa la gomma, mentre sul cantiere si deve utilizzare la mazza”. La progettazione è indipendente dal modello di processo software utilizzato, e costituisce il ponte fra modellazione e costruzione. L’input della progettazione è il modello analitico, espresso nella forma di elementi basati su scenari, basati su classi, orientati al flusso e comportamentali. La progettazione dei dati e delle classi avviene naturalmente per raffinamento delle classi e relativi attributi prodotte nella modellazione analitica, ed in particolare la progettazione dei dati assume maggiore dettaglio, in maniera iterativa, man mano che vengono progettati i componenti software. Un’interessante domanda, naturalmente, è quante sono le software house che sviluppano [b]realmente[/b] per componenti. Come afferma un bel lavoro del CBDI Forum (http://www.cbdiforum.org), la progettazione per componenti non solo costa, ma non ha nemmeno un ROI nell’immediato. Ma avremo occasione di riparlarne. E’ quasi inutile sottolineare quanto una buona progettazione influenzi la qualità del progetto software. Qualità intesa nel senso di manutenibilità e possibilità di collaudare il prodotto e valutarlo molto prima delle ultime fasi del processo, quando le scadenze incombono minacciose e le ultime briciole del budget vengono spese per lo spuntino di mezzanotte del team in concorde straordinario permanente. Un accenno è fatto alle revisioni tecniche formali, oggetto di un paragrafo nel capitolo sulla qualità. Un’utile pagina richiama gli attributi di qualità FURPS (funzionalità, usabilità, affidabilità-reliability, prestazioni e sopportabilità) definiti da Hewlett – Packard. Indipendentemente dagli attributi sui quali concentrare l’attenzione (un progetto porrà l’accento sulla sicurezza, un altro sulle prestazioni, un altro ancora sull’usabilità, è così via) occorrerebbe sempre ricordare che la qualità si applica durante, non dopo il processo di ingegneria del software. Il capitolo del Pressman prosegue con un paragrafo dedicato ai principi di progettazione, nell’ordine: 1. Astrazione 2. Architettura 3. Modelli 4. Modularità 5. Incapsulamento delle informazioni 6. Indipendenza funzionale (entrambe tecniche di riduzione della propagazione degli errori) 7. Raffinamento 8. Refactoring (così in auge nelle metodologie agili) 9. Classi progettuali. Il modello progettuale può essere considerato in due dimensioni: il livello di astrazione (salendo di dettaglio dal modello analitico a quello progettuale) e gli elementi di processo, che comprendono l’architettura, l’interfaccia, i componenti ed il deployment. Normalmente, lo sviluppo degli elementi dell’interfaccia e dei componenti viene parallelizzato dopo la progettazione preliminare dell’architettura (che comprende la progettazione dei dati), mentre il modello di deployment viene ritardato al termine del progetto. Il capitolo si chiude con l’interessante (e quantomai poco nota) progettazione del software basata su modelli. Un costruttore di televisioni è abituato a lavorare con un corposo catalogo di componenti da assemblare come i pezzi delle costruzioni Lego, mentre l’attività preferita dell’ingegnere del software medio sembra essere la reinvenzione della ruota. Per quanto riguarda la progettazione dell’architettura, il testo enfatizza il ruolo dei componenti in ogni rappresentazione. Più precisamente, vengono considerati due livelli: la progettazione dei dati e la progettazione dell’architettura (rappresentazione della struttura dei componenti software e delle loro proprietà ed interazioni). Un breve paragrafo iniziale è riservato alla progettazione dei dati, con qualche accenno all’abusato argomento dei data warehouse. Il capitolo procede con una panoramica sugli stili e

5 di 16

modelli architetturali, da quelli basati sui dati alle più recenti architetture a livelli ed object-oriented. La progettazione dell’architettura comincia con un diagramma di contesto, che definisce le entità esterne (altri sistemi, dispositivi, persone) con cui il software dovrà interagire e la natura dell’interazione. Prosegue con la definizione degli archetipi, ovvero quelle classi o modelli che rappresentano un’astrazione fondamentale e critica per progettare un’architettura per il sistema obiettivo, generalmente derivati a partire dalle classi del modello analitico, così come i componenti che costituiscono la struttura del sistema. Il procedimento termina (in senso iterativo) con una istanziazione dell’architettura, ovvero la sua applicazione ad un determinato problema con lo scopo di dimostrare che la struttura ed i componenti sono appropriati. Il successivo paragrafo è dedicato alla valutazione dei progetti di architettura alternativi così prodotti. Viene presentato il metodo iterativo ATAM (Architectural Tradeoff Analysis Method, http://www.sei.cmu.edu/ata/ata_method.html) prodotto nel 1998 dal SEI (Software Engineering Institute) della Carnegie Mellon University, sostanzialmente basato sulla valutazione comparativa di una serie di attributi di qualità e sui punti di sensibilità, ovvero sugli attributi che vengono influenzati in modo significativo da variazioni anche piccole dell’architettura. La complessità dell’architettura viene valutata con riferimento alle dipendenze esistenti fra i vari componenti, un procedimento in cui può essere di aiuto il prodotto Lattix LDM (http://www.programmazione.it/index.php?entity=eitem&idItem=33266), ed approfondito in parte nel Capitolo 15 dedicato alle metriche di prodotto per il software. Sin troppo breve il sottoparagrafo 10.5.3, dedicato all’importante argomento degli ADL (Architectural Description Language): troviamo solo un utile elenco di progetti di ricerca, e l’avvertenza che UML non è un linguaggio ADL completo. L’ultimo paragrafo del capitolo è dedicato alla progettazione strutturata introdotta da Yourdon e Constantine (prima del successo dei linguaggi object-oriented), una tecnica orientata al flusso dei dati in cui rivestono notevole importanza i DFD (Data Flow Diagrams). Il testo sottolinea come la tecnica abbia ancora una sua ragion d’essere, ma sia inadatta per sistemi che richiedono sostanziali modifiche nel tempo o in cui l’elaborazione dei dati non è sequenziale. La progettazione a livello di componenti è un importante argomento, in parte ripreso dal Capitolo 25 dedicato proprio alla CBSE (Component-Based Software Engineering). Il capitolo comincia con una definizione di componente, dal punto di vista dell’object-orientation, dell’ingegneria del software classica e di quella basata sui processi. Al di là dei distinguo, tutti gli approcci concordano nel definire un componente come un insieme di logiche di elaborazione, strutture dati interne ed interfacce. Il capitolo prosegue con la progettazione dei componenti basati su classi, introducendo i fondamentali principi di coesione ed accoppiamento e con una particolare attenzione verso il principio OCP (Open-Closed Principle), ovvero “Un modulo (o componente) deve essere aperto alle estensioni ma chiuso alle modifiche”, che si traduce concretamente nella creazione di astrazioni (solitamente interfacce) che fungono da buffer tra la funzionalità che deve essere estesa e la classe progettuale. Ai diagrammi grafici UML è spesso opportuno affiancare dei vincoli espressi in un linguaggio formale: un paragrafo introduce brevemente, rimandando al capitolo “metodi formali” negli “argomenti avanzati”, il linguaggio OCL (Object Constraint Language), formalizzato da OMG (http://www.omg.org). Questo linguaggio, per il quale esistono vari strumenti quali Dresden OCL toolkit (http://dresdenocl.sourceforge.net) o l’OCL parser (http://www3.ibm.com/software/ad/library/standards/ocldownload.html) di IBM, rivela la propria utilità anche nella specifica di pre- e postcondizioni per il completamento di un’azione specificata dal progetto. Per quanto il modello a componenti faccia spesso pensare ai linguaggi O-O, esiste una solida letteratura, il cui precursore è Edsgar Dijkstra, sulla progettazione di componenti cosiddetti ‘convenzionali’ per linguaggi procedurali, che prendono in tal caso solitamente il nome di moduli, procedure o subroutine. Naturalmente, il Pressman presenta i principi della programmazione strutturata ed i tre costrutti fondamentali di sequenza, condizione e ripetizione, e viene illustrato l’uso dei flowchart o diagrammi di flusso. Un paragrafo apposito è dedicato alla descrizione del comportamento di un componente in pseudocodice attraverso il PDL (Program Design Language). Il volume non presenta invece le reti di Petri; per un’introduzione all’argomento, si veda http://etd.adm.unipi.it/theses/available/etd-06282004120407/unrestricted/capitolo2.pdf. Il capitolo 12 tratta la progettazione dell’interfaccia utente. Inutile negarcelo: possiamo mugugnare quanto vogliamo sulle scarse conoscenze dell’utente finale, ma l’interfaccia utente è come la giacca-e-cravatta al colloquio di assunzione. Indipendentemente da quanto impegno venga profuso nello scrivere ‘bene’ il codice, un’interfaccia utente mal realizzata porta a ritenere che il software sia ‘scadente’. Lo stesso Pressman non trova meglio che cominciare col riepilogare le tre regole d’oro espresse da Mandel in un testo del 1997: • • •

lasciare che il controllo sia nelle mani dell’utente limitare il ricorso alla memoria da parte dell’utente usare un’interfaccia uniforme.

6 di 16

In poche parole: “non sottovalutate mai quanto stupido puo’ essere un utente”. Inevitabile il riferimento al sito UseIt (http://www.useit.com) di Jakob Nielsen. La progettazione dell’interfaccia parte dalla considerazione di chi saranno gli utenti finali del sistema: al solito, un ovvio consiglio della nonna troppo spesso trascurato. Una volta conosciuti gli utenti, le operazioni che effettueranno e l’ambiente in cui opereranno le fasi di progettazione, costruzione e convalida dell’interfaccia costituiscono un modello iterativo ed a spirale. L’interfaccia utente è il regno dei prototipi: è inutile aspettarsi di poter effettuare una verifica su carta del comportamento di una variabile imprevedibile quanto un utente finale. L’analisi e la progettazione delle interfacce, oggetto dei successivi due paragrafi, sono state inserite entrambe in questo capitolo in quanto opinione dell’Autore che, nel caso specifico delle interfacce utente, il confine fra le due sia troppo vago per non trattarle insieme. Si presti attenzione a non sopravvalutare il confronto (scontro?) con l’utente finale: un’opinione forte non è necessariamente condivisa dalla maggior parte degli utenti. Ancora, un input assolutamente da non sottovalutare è quello del supporto tecnico. Il testo non discute, se non in un breve box riepilogativo, alcun modello di interfaccia utente, per i quali si viene rimandati ai numerosi testi in Bibliografia. Quattro comuni problemi, solitamente affrontati solo quando è disponibile un prototipo operativo, sono: • • •

i tempi di risposta del sistema i sistemi di help la gestione degli errori

• la denominazione dei comandi. Per quanto riguarda il tempo di risposta, più che alla sua lunghezza si dovrebbe guardare alla sua variabilità: l’utente è molto più disposto ad adeguare i suoi ritmi di lavoro ad un tempo di risposta standard, anche abbastanza lungo, di quanto non lo sia ad adeguarsi ad “una macchina che non si sa se sputerà fuori il risultato fra due secondi o due ore”; peggio ancora, nel caso di un tempo di risposta indeterminato, è esperienza comune che l’utente non sappia mai decidere se il sistema sta lavorando o è bloccato in errore. Per quanto riguarda i messaggi d’errore, si finisce sempre col ripetersi le stesse barzellette su “Il modulo xxxyyyzzz ha determinato un errore oh123aaa9239203 nel modulo di sistema aaabbbcc”. Un discorso a parte, naturalmente, è quello sull’accessibilità, che oltre ad essere un imperativo morale e commerciale è diventato, anche in Italia con la ‘Legge Stanca’ (L. 4/2004, http://www.camera.it/parlam/leggi/04004l.htm), un obbligo di legge. Ancora, è prassi comune sottovalutare i problemi di utilizzo di un software da parte di utenti che utilizzano una lingua diversa da quella dello sviluppatore; e pensare che esiste addirittura una Guida all’internazionalizzazione del software (http://oss.software.ibm.com/icu/userguide/i18n.html) redatta da IBM. La valutazione delle interfacce utente è anch’essa un argomento sostanzialmente rimandato alla Bibliografia. Le strategie e le tecniche di testing del software, e le metriche di prodotto, sono oggetto degli ultimi tre capitoli della seconda parte; strettamente collegati alla qualità del software, sono pertanto ripresi nei successivi capitoli. Si tratta di argomenti che per me hanno sempre rivestito un fascino particolare; a chi non condividesse il mio entusiasmo, voglio ricordare la citazione di Yourdon (scritta, è il caso di ricordarlo, molti anni prima dell’analoga battuta di Brad Pitt in ‘Vi presento Joe Black’): “Come la morte e le tasse, il collaudo è sia spiacevole che inevitabile”. Il collaudo deve mirare a massacrare il programma per individuarne il maggior numero possibile di errori, con un impiego di risorse ragionevole: su questo siamo tutti d’accordo. E’ anche oramai affermato nella teoria (ma quanto mai poco utilizzato nella prassi) che qualunque strategia di collaudo deve incorporare: 1. la pianificazione, 2. la progettazione dei casi di prova, 3. la loro esecuzione e 4. la raccolta e valutazione dei risultati. Il motivo per cui si conducono, di solito, pessimi test è un errore metodologico di base: il collaudo viene visto come la fase in cui si “inietta” la qualità nel sistema, come se la qualità fosse un’’appendice’ e non una parte integrante di tutto il processo di sviluppo. Ancora, si è soliti rimandare il test a “quando tutto il codice è già stato scritto, per poi scoprire a poche ore della consegna che ne rimane da scrivere il doppio (esperienza, ahimè, di vita: senza il controllo degli errori, scriverei molto meno codice. Senza utenti, ne scriverei poco e di molto creativo, ma è pur vero che probabilmente non ne scriverei proprio). E’ invece abbastanza affermato il principio di collaudo ‘dal piccolo al grande’, procedendo per aggregazione di gruppi di componenti, salvo che nei ‘figli del COBOL’ e negli studenti di Informatica, due gruppi di sviluppatori accomunati dalla passione nella scrittura di lunghissimi listati che immancabilmente non vengono compilati. Il testo interviene salomonicamente nella lunga discussione che ha per oggetto se il collaudo debba essere affidato allo stesso sviluppatore o ad un gruppo esterno, affermando che i test di unità ed integrazione sono a carico del gruppo di sviluppo, mentre nelle fasi di validazione entra in gioco l’ITG (Independent Test Group) che collabora con gli sviluppatori. Vengono presentate le strategie di collaudo per il software

7 di 16

convenzionale e ad oggetti; sostanzialmente, per entrambi vengono adottate le medesime quattro fasi di test: 1. di unità (singolo modulo o classe), 2. di integrazione, 3. di convalida (ovvero rispetto dei requisiti) e 4. di sistema. Il testing di software ad oggetti differisce significativamente da quello di software convenzionale nella fase di integrazione, perché naturalmente il software O-O non una struttura di controllo gerarchica ovvia, che consenta di scegliere una strategia top-down, bottom-up o intermedia. In tal caso vengono usate due diverse strategie: il collaudo thread-based integra l’insieme di classi necessarie per rispondere ad un input o ad un evento del sistema, lavvove quello use-based inizia collaudando le classi indipendenti, per poi aggiungere gradualmente le classi dipendenti. Viene poi trattata la convalida, distinguendo in particolare i collaudi alfa (effettuati dall’utente in presenza dello sviluppatore) da quelli beta (in cui lo sviluppatore è assente); è quasi inevitabile la citazione da “La cattedrale ed il bazar” (http://www.catb.org/~esr/writings/cathedral-bazaar/). Il collaudo di sistema accenna brevemente alle prove di recovery, di sicurezza, di stress e di prestazioni, mentre il paragrafo finale è dedicato al debugging. La conclusione è quella che mi aspettavo: sebbene il debugging possa e debba essere un processo disciplinato, rimane a tutti gli effetti un’arte, addirittura una ‘dote innata’ secondo alcuni studi. Al di là della presenza di strumenti semiautomatici di debugging, rimane sempre valido il vecchio consiglio “quando sbatti la testa da tre ore su un bug, fai vedere il codice ad un collega” (e dunque la pratica agile del pair programming). Nella pratica, si suole distinguere fra testing che tiene conto della struttura interna del programma, o whitebox, e testing realizzato sulla base dei requisiti funzionali, a volte senza nemmeno conoscere il programma, o black-box. I due approcci, sorprendentemente, non sono contrapposti, ma complementari: è davvero utile provare a risolvere l’esercizio finale, che chiede di fornire tre esempi in cui il collaudo black-box non rileva problemi mentre quello white-box scopre un errore, e viceversa. Ad ogni buon conto, per motivi legati più che altro alla complessità computazionale, è prassi usare il collaudo white-box nei test di livello inferiore, ovvero di unità e di integrazione, e quello black-box nei test di convalida e di sistema. L’elenco dei metodi white-box parte con un mio vecchio amore, che ha segnato gli inizi della mia carriera, ovvero il collaudo per cammini di base elaborato da McCabe. Sostanzialmente, questo metodo si basa sull’intuitiva idea che più un programma è ‘complesso’, più elevata è la probabilità che contenga errori; la nozione intuitiva di complessità viene misurata tramite un indice metrico, la complessità ciclomatica, che tiene conto fondamentalmente dei costrutti decisionali e viene solitamente calcolata a partire dal grafo di flusso del programma. E’ bene sottolineare che, naturalmente, tale indice consente solo una “scrematura” su base statistica delle parti più soggette ad errori: un modulo di programma potrebbe avere un indice ciclomatico bassissimo, ed essere tuttavia pieno di bug. La complessità ciclomatica pone un limite superiore al numero di collaudi che devono essere condotti per garantire che tutte le istruzioni vengano verificate almeno una volta; la parte interessante del metodo McCabe è che la costruzione del grafo di flusso ed il calcolo di una base di cammini linearmente indipendenti (fondamentalmente, percorsi di test che ‘tocchino’ tutte le istruzioni) sono attività automatizzabili con l’ausilio di una matrice di grafo di flusso. Altri metodi di testing white-box, che completano l’analisi McCabe, sono il collaudo per condizioni, per flusso dei dati e per cicli. I test di tipo blackbox sono invece comportamentali, basati come detto sui requisiti funzionali, e pongono l’accesso sull’uso di grafi che descrivano le chiamate di un programma, sulla suddivisione dei possibili dati d’ingresso in classi di equivalenza per ridurre il numero di test significativi, sull’analisi dei valori limite (fortunatamente, oltre ad essere una delle più importanti, è anche una delle più utilizzate; la maggior parte dei programmatori sa perfettamente che una funzione che accetta in ingresso valori da 1 a 100 va testata almeno per -1, 0, 1, 2, 99, 100 e 101), o su metodi volti a ridurre il numero di valori di input come il collaudo ad array ortogonale. Il collaudo di software object-oriented è da un lato facilitato dal fatto che può iniziare già dai modelli, senza aspettare la scrittura del codice, dall’altro reso più complicato dai problemi legati all’ereditarietà. Per quanto riguarda i test delle singole classi, si suole utilizzare un collaudo casuale, che invoca una serie ‘plausibile’ di metodi della classe, ed uno a partizionamento, fondamentalmente l’analogo O-O della suddivisione in classi di equivalenza. Vi sono infine metodi di collaudo speciali per le interfacce grafiche, le architetture client/server, la documentazione ed i sistemi real-time (che introducono l’ulteriore variabile tempo), mentre il testo rimanda ai classici in Bibliografia per l’analisi dei modelli di collaudo. La definizione di metriche per il software è da sempre un obiettivo di tipo ingegneristico (non vi è ingegneria dove non vi è misura) volto a stabilire la qualità del software realizzato; i primi fattori di qualità storicamente elaborati, ovvero i fattori d’uso, di revisione e di transizione del prodotto di McCall ed i sei attributi dello standard ISO 9126, sono però di tipo qualitativo. In effetti, ad oggi, tutte le metriche definite sono solo misure indirette della qualità: non misuriamo cioè direttamente la qualità del software, ma alcune sue manifestazioni. L’argomento è ancora in divenire, tanto che si rende necessario un paragrafo che introduca il quadro di riferimento: la differenza fra

8 di 16

misure, metriche ed indicatori, i principi della misurazione, il paradigma GQM (Goal/Question/Metric) per la misurazione orientata all’obiettivo, ed un panorama delle metriche di prodotto. Le metriche per il modello concettuale partono dall’assunto, simile all’equazione ‘complessità = numero di errori’ alla base del metodo McCabe, che sia ragionevole pensare che la taglia e la complessità del modello progettuale siano direttamente correlate. La prima, importante metrica che viene esaminata è quella dei punti funzione o Function Points (FP). Il metodo è stato proposto inizialmente da tal [b]Albrecht[/b] della IBM Research nel 1979 e gode di un crescente consenso nella comunità, tanto che è stato adottato come criterio di stima e valutazione dei progetti software dal CNIPA (Centro Nazionale per l’Informatica nella Pubblica Amministrazione, http://www.cnipa.gov.it). Il conteggio dei punti funzione è standardizzato in un manuale revisionato periodicamente dall’IFPUG (International Function Point Users Group, http://www.ifpug.org), il cui capitolo italiano è il DPO (http://www.dpo.it). In sostanza, i punti funzione vengono derivati utilizzando una relazione empirica che si basa su misure calcolabili (dirette) nel dominio delle informazioni del software e valutandone la complessità; un database storico di progetti aiuta poi il project manager nell’associare la complessità di un’applicazione in punti funzione all’impegno in mesi-uomo necessari, stabilito il linguaggio di programmazione, ed a valutare il numero di errori che ci si aspetta di trovare nell’implementazione. E’ necessario in primo luogo valutare un insieme di valori nel dominio delle informazioni: • numero di input esterni (EI), • numero di output esterni (EO), • numero di richieste esterne (EQ), • numero di file logici interni (IFL) e • numero di file dell’interfaccia esterna (EIF). La somma di questi valori, pesata con un fattore che valuta il grado di complessità (‘semplice’, ‘medio’ o ‘complesso’), costituisce il numero di function point unadjusted, cui viene applicato un fattore di correzione e sommati dei fattori di aggiustamento (VAF) determinati dalla risposta ad una serie di domande (reperibili all’URL http://www.ifpug.com/fpafund.htm), espressa come ‘voto’ da 0 a 5. Si tratta, naturalmente, di un metodo soggettivo, che segue però dei criteri standard internazionalmente riconosciuti, applicati da esperti certificati. I Function Point sono un importante argomento che viene ripreso nel capitolo 17, ove si cerca di metterli in relazione con una metrica di processo quale le LOC (numero di linee di codice). Le metriche per la qualità delle specifiche proposte da Davis e colleghi assegnano invece un indice di coerenza, fondato sull’accordo fra le interpretazioni date dai revisori a ciascun requisito, ad una serie di caratteristiche di tipo qualitativo. Le metriche di progettazione comprendono un insieme di indici suddivisi in metriche di alto livello, orientate agli oggetti, orientate alle classi, a livello di componenti, orientate alle operazioni e per la progettazione di interfacce. Sulle metriche per il codice sorgente viene fatto un accenno al controverso lavoro di Halstead, basato sul numero di operatori ed operandi presenti nel codice e sottoposto a numerose verifiche sperimentali dal 1977 ad oggi. Per quel che riguarda il testing, la maggioranza delle metriche proposte è rivolta al processo di collaudo, non alle caratteristiche tecniche delle prove in sé. Per il software procedurale si usano metriche derivate dalle misure di Halstead, ed ugualmente per il software ad oggetti le metriche di progettazione hanno un’influenza diretta sulla collaudabilità di un sistema O-O, e vengono considerati gli aspetti relativi all’incapsulamento ed all’ereditarietà. Per quanto riguarda infine la manutenzione, l’IEEE ha proposto uno specifico standard, SMI (Software Maturity Index) che riassume il grado di stabilità di un prodotto software sulla base delle modifiche apportate alle nuove versioni del prodotto. Calcolato a partire dal numero di moduli finali, modificati, aggiunti ed eliminati, si suppone che al tendere di SMI ad 1 il prodotto tende a stabilizzarsi, e che il tempo medio necessario per produrre una nuova versione del prodotto è correlato ad SMI, per cui si possono sviluppare modelli empirici di previsione dell’impegno di manutenzione. Dal punto di vista dei tool software disponibili, solitamente il calcolo di alcune metriche è implementato come funzionalità aggiuntiva di più vasti strumenti di analisi e progettazione, programmazione o collaudo.

Gestione dei progetti software L’interessante argomento del Project Management non può prescindere da una necessaria panoramica sulle quattro P (persone, prodotto, processo e progetto); l’ordine delle quattro P non è casuale, e per le persone il solito Software Engineering Institute ha elaborato addirittura un modello di maturità della capacità di gestione delle persone, People-CMM (http://www.sei.cmu.edu/cmm-p). Un approccio straordinariamente semplice, dettato dal solo buon senso (e pertanto pochissimo utilizzato) è il principio W5HH di Boehm, che consiste semplicemente nel rispondere a sette domande, le cui iniziali danno il nome al metodo, il cui immenso vantaggio è quello di essere applicabile indipendentemente dalle dimensioni o dalla complessità del progetto

9 di 16

software. Sul fronte degli strumenti, può essere utile il Project Control Panel (http://www.spmn.com/products_software.html) realizzato in Excel. Il discorso può proseguire con un approfondimento sulle metriche per il software, dal punto di vista delle metriche di processo e di progetto. Per quanto molte metriche siano utilizzabili in entrambi i casi, le due famiglie sono complementari: le misurazioni di processo portano a miglioramenti a lungo termine, laddove ovviamente quelle di progetto servono a guidare i lavori in corso. L’efficacia di un processo di sviluppo software si misura indirettamente: a partire da informazioni derivate dal processo si ricava una famiglia di metriche. E’ opportuno che le metriche di processo rimangano private, ovvero non attribuite ai singoli individui del team ma raccolte su base statistica, per evitare inutili rimpalli di responsabilità; viene suggerito addirittura un “galateo” nella raccolta delle metriche. Le metriche dimensionali sono quelle storicamente usate per prime e per le quali esiste il più vasto corpus di studi, si basano fondamentalmente sulle LOC (linee di codice) prodotte, e sono naturalmente le più controverse: i principali argomenti contro l’uso delle linee di codice sono che: • le misure in LOC dipendono dal linguaggio di programmazione, • penalizzano i programmi ben architettati ma brevi, e • non si adattano facilmente ai linguaggi non procedurali. Io aggiungerei che riducono l’attività creativa dello sviluppatore ad un lavoro ‘a cottimo’ simile a quello dello scaricatore di porto, e che concettualmente sono alla base del noto “se vediamo che siamo in ritardo, aggiungeremo altre persone al team”, ovvero uno dei modi più sicuri per devastare un progetto già votato al fallimento. Anche le più recenti metriche basate sulle funzioni, la più utilizzata delle quali è il metodo basato sui Function Points, hanno però i loro detrattori: sono in molti a far notare che l’elemento di soggettività è alto (due esperti del metodo dei punti funzione possono arrivare a risultati diversi per lo stesso prodotto) e che i punti funzione non hanno alcun significato fisico diretto. Sono stati condotti peraltro vari studi per riconciliare i risultati ottenuti con le metriche LOC ed FP, anche dallo stesso Albrecht, e tenendo conto che la relazione fra le due metriche dipende dal linguaggio di programmazione utilizzato. Se guardiamo alla tabella riportata nel testo, comunque, scopriremo che, quale che sia il linguaggio di programmazione scelto, la varianza fra LOC per punto funzione minime e massime rilevate arriva tranquillamente a fattori 10 ed oltre. Ancora, che si scelga di utilizzare le LOC o i FP, per avere una stima dell’impegno richiesto dal progetto è necessaria una nutrita serie storica. Metriche diverse sono state proposte per i linguaggi O-O, considerando che né LOC né FP forniscono una granularità sufficiente per valutare correttamente le iterazioni svolte tramite processi evolutivi o incrementali. Un’importante metrica di qualità del software è invece la DRE (Defect Removal Efficiency, o efficienza di rimozione dei difetti), ovvero una misura della capacità di rimuovere gli errori (non-conformità ai requisiti scoperti prima del rilascio alla fase successiva) prima che divengano difetti (non-conformità ereditate dalla fase del ciclo di vita precedente). L’integrazione delle metriche nel processo software, con una particolare attenzione per le piccole aziende (con meno di 20 sviluppatori), e la definizione di un programma di valutazione metrica del software, con i dovuti riferimenti al Guidebook for Goal-Driven Software Measurement (http://www.sei.cmu.edu/pub/documents/96.reports/pdf/hb002.96.pdf), chiudono il capitolo. I successivi capitoli della terza parte coprono le cinque attività della conduzione di un progetto software: • la stima, • la pianificazione, • l’analisi dei rischi, • la gestione della qualità e • quella delle modifiche. Ultimamente è abbastanza comune trovare in letteratura tecnica il cosiddetto paradosso della stima: la stima è estremamente imprecisa nelle fasi iniziali del processo, quando serve, e raggiunge la perfezione una volta che il processo è completato, quando non serve più. Tuttavia, il grado di incertezza può essere ridotto adottando almeno due metodi di stima, e riconciliando i risultati ottenuti. Un processo di stima comincia definendo la portata e la fattibilità (tecnica, finanziaria, temporale ed in termini di risorse) del software. La stima delle risorse comprende persone, componenti software riutilizzabili ed ambiente di sviluppo (strumenti hardware e software). Per avere stime affidabili, ci si serve di tecniche di scomposizione e di modelli empirici di stima. L’esempio adottato per le tecniche di scomposizione vi darà modo di farvi una sana risata: si parla di “un costo del lavoro pari a 8000 Euro mensili” (sic). I modelli empirici legano tutti la variabile utilizzata (LOC o FP) a delle costanti derivate empiricamente per stimare l’impegno in mesi/uomo; ognuno dei modelli proposti in letteratura produce un risultato diverso per lo stesso valore di LOC o FP, per cui i modelli di stima devono essere adattati alle esigenze locali. Il modello di stima probabilmente più noto al mondo è il COCOMO II (http://sunset.usc.edu/cse/pub/research/COCOMOII/cocomo_main.html) originariamente proposto da Boehm nel suo classico testo “Software Engineering Economics”

10 di 16

(http://www.amazon.com/gp/product/0138221227/002-6561127-5158441?v=glance&n=283155), ma ne esistono anche altri, quali l’equazione del software di Putnam e Myers (basato su una serie storica di 4000 progetti). Particolari accorgimenti vanno adottati per la stima dei progetti O-O e per i progetti di breve durata, con particolare riferimento allo sviluppo agile. Un importante paragrafo finale tratta le scelte cosiddette make-orbuy, ovvero la difficile alternativa fra sviluppare in proprio ed acquistare o affidare lo sviluppo all’esterno. La pianificazione del progetto comincia con l’importante argomento dell’allocazione delle risorse umane. Il mito “Se siamo in ritardo, possiamo aggiungere altri programmatori e recuperare” viene sfatato, oltre che dal buon senso, anche dalla matematica, presentando la curva di Putnam-Norden-Rayleigh (PNR, https://www.esi-intl.com/public/publications/horizonspdfs/horizons1201.pdf). La curva, sostanzialmente, ci dice che: • non ha senso comprimere i tempi di progetto più del 75% di quelli ottimali • lungo l’asse temporale si raggiunge un punto in cui il lavoro non può più essere completato in tempo, indipendentemente dal numero di persone che lo svolgeranno, •

a parità di obiettivi, si ottengono benefici dall’impiegare un numero inferiore di persone per un periodo più lungo. Fondamentale importanza assume il paragrafo dedicato alla distribuzione del carico di lavoro tra le varie fasi: solitamente si raccomanda la regola del ’40-20-40’, ovvero assegnare il 40% dell’impegno all’analisi ed alla progettazione, la stessa percentuale ai collaudi ed al debugging, e solo il 20% alla stesura del codice. Una regola che va davvero contro il senso comune dei principianti della programmazione J La suddivisione in un insieme di compiti, collettivamente denominati anche WBS (Work Breakdown Structure), e la pianificazione temporale passano, ovviamente, per le note tecniche PERT (Program Evaluation and Review Technique) e CPM (Critical Path Method). Al di là delle differenze, entrambe le tecniche forniscono strumenti quantitativi che consentono al pianificatore di determinare il cammino critico, ossia la catena di compiti che determina la durata di un progetto, stabilire le stime dei tempi più probabili e definire le finestre temporali entro cui ciascun compito deve essere iniziato e terminato. Nessun approfondimento è dedicato a PERT/CPM, mentre un breve paragrafo illustra l’uso dei diagrammi di Gantt. Un paragrafo finale è dedicato ad una nota tecnica quantitativa, dovuta ad Humphrey, per stabilire i progressi compiuti durante lo svolgimento del progetto: l’analisi del valore aggiunto o EVA (Earned Value Analysis, http://www.acq.osd.mil/pm/). Il capitolo sull’analisi dei rischi presenta argomenti molto noti ai cultori della disciplina, naturalmente adattati al panorama dello sviluppo software, che in molti casi, come al solito, si riassumono in una serie di pratiche di buon senso. L’approccio è quello classico del prodotto probabilità x conseguenze dei singoli fattori di rischio, corredato naturalmente da un’analisi costi/benefici (nessuno compra mai una cassaforte da centomila euro per custodirvi lo stipendio mensile di un ingegnere del software). La gestione dei rischi può essere strutturata in un piano di riduzione, monitoraggio e gestione (RMMM, ovvero Risk Mitigation, Monitoring and Management); in alternativa, ogni rischio può essere documentato singolarmente utilizzando un foglio informativo RIS (Risk Information Sheet), che riassume in una forma simile ad un caso d’uso tutti i parametri quantitativi individuati (probabilità/conseguenze, raffinamento e contesto, riduzione e monitoraggio, esposizione al rischio RE, ovvero prodotto della probabilità per il costo del rischio qualora si verifichi, stato, ecc.). Venendo al capitolo sulla qualità, l’analogia di Philip Crosby fra la qualità ed il sesso meriterebbe da sola il prezzo di copertina, ma al di là delle battute, e delle giuste precisazioni sulle attività e metriche per la garanzia della qualità, mi ha molto colpito un’affermazione: “Chiunque sia coinvolto nel processo di ingegnerizzazione del software è anche responsabile della sua qualità”. Pensare ad un Reparto Qualità che assicura la magica ‘Certificazione ISO 9001:2000’ mentre lo sviluppatore continua ad operare in pura anarchia, o magari dopo che è stato prodotto il codice, viene sempre più riconosciuta come un’amenità. Alla base di ogni processo di qualità vi è il controllo delle variazioni: non è forse, del resto, la ripetibilità uno dei fondamenti del metodo scientifico? Naturalmente, tale tipo di controllo presuppone una misurabilità del software, già oggetto del Capitolo 15. Il fondamento su cui misurare la qualità sono i requisiti: la mancanza di conformità ai requisiti è una mancanza di qualità. Se dei requisiti espliciti del cliente si è già discusso, esiste una serie di requisiti impliciti (ad es. la facilità di manutenzione) la cui mancata soddisfazione è un sicuro indice di scarsa professionalità. La revisione tecnica formale è un argomento citato ad ogni piè sospinto nel testo: finalmente ne troviamo in questo capitolo la trattazione organica. Una caratteristica importante delle revisioni tecniche formali (FTR) è quella di essere “condotte da tecnici per tecnici”, poiché mirano a scoprire gli errori durante il processo di sviluppo: molti si stupirebbero nel sapere che durante le attività di progettazione si introducono fra il 50 ed il 65% di tutti gli errori; alcuni studi affermano che le tecniche di revisione formale possono scoprire fino al 75% degli errori di progettazione. Per aiutarci contro il management che ci parla dei ‘costi della qualità’, ci

11 di 16

viene stavolta in aiuto uno studio della stessa IBM: se la correzione di un errore rilevato durante la progettazione costa 1 unità, il costo prima dei collaudi sale a 6,5 unità, durante i collaudi a 15 unità, dopo la consegna ad un valore compreso fra 60 e 100 unità; non considerando il danno di immagine in quest’ultimo caso, ovviamente. Non male come argomento da usare contro il caporale che ci minaccia: “non stai lavorando, stai scrivendo carte!”. Desta raccapriccio anche esaminare i modelli di propagazione dell’errore, sempre prodotti da IBM; al manager che ne capisce solo di vile denaro, si può far notare che i modelli conducono ad un costo totale triplo, in assenza di revisioni. Il problema, come sempre, è un altro. La gestione della qualità ci consente di scegliere se “pagare ora, o pagare molto di più in seguito”: un argomento che ha ben poca presa per molte PMI italiane, che giorno dopo giorno non sanno se ci sarà un ‘seguito’ (ma molto spesso non hanno mai lavorato perché ci fosse). Un’Azienda che ha una ragionevole certezza di rimanere sul mercato per tre anni non ha, invece, alcuna scusa: il management di una tale Azienda che non adotti prassi formali di ingegneria del software dimostra, volendo usare un eufemismo, mancanza di professionalità e di visione strategica. Tra parentesi, nessuno ha mai pensato che una FTR è un’ottima palestra per un neoassunto, permettendogli di osservare diversi approcci all’analisi, progettazione e implementazione del software? Come per i team di sviluppo, così per le riunioni di revisione condivido l’idea del gruppo limitato (da tre a cinque persone): del resto, la Storia è stata fatta dai piccoli gruppi ben organizzati, non dagli eserciti. Ricordatelo al manager che organizza per i propri fini la classica ‘riunione del personale’ spacciandola per FTR. Un altro consiglio che mi sento di sottoscrivere è quello classico del pair programming: fate esaminare il prodotto da qualcuno che non l’ha realizzato. Per le revisioni valgono alcune prassi da adottare in tutti i tipi di riunione: • • • •

una revisione incontrollata è spesso peggio che il non farne del tutto; quello che viene sottoposto ad esame è il codice, non lo sviluppatore; occorrerebbe dedicare due ore a preparare ogni riunione, la quale a sua volta non dovrebbe superare le due ore; occorre individuare i problemi ed andare avanti, per quanto l’umana tentazione sia quella di risolverli sul posto: una revisione non è una sessione di lavoro dedicata alla soluzione dei problemi;



devono essere stabiliti i tempi di rilascio delle modifiche, che sono il risultato di una FTR: la riunione che si conclude senza aver prodotto altro che il verbale sarà quasi sicuramente l’ultima riunione che riuscirete ad organizzare. Per quanto riguarda la preparazione della riunione, insistete fino alla morte perché i partecipanti si presentino con una serie di commenti scritti sul materiale esaminato. Tutti sono convinti di aver capito alla perfezione un argomento, finchè non provano a metterlo su carta. Da parte vostra (non c’è scritto sul libro, è un mio consiglio), seguite la regola del galateo giapponese sui biglietti da visita: invece di mettere la pila di appunti “che leggerete dopo la riunione” in un angolo del tavolo o nella borsa, scorreteli rapidamente, sottolineando le frasi che ritenete più significative, ed avendo cura di leggerle ad alta voce. Vi assicuro che avrete ottime probabilità di ritrovarvi con una documentazione di prodotto che presenti correttamente evidenziati i concetti – chiave. Visto che “nel mondo reale dei progetti software, le risorse sono limitate ed il tempo manca, è opportuno raffinare le tecniche di campionamento dei prodotti dell’ingegneria del software da sottoporre ad FTR; il riferimento obbligato in questo caso è la metodologia Six Sigma (http://www.isixsigma.com) portata al successo da Motorola negli anni ‘80. Un argomento affascinante, ripreso nei capitoli avanzati della quarta parte, è quello dei metodi formali per l’assicurazione della qualità. Ribadisco comunque il problema espresso precedentemente: tutti i metodi quantitativi ad oggi conosciuti si basano sull’esame di dati storici, per cui dovremmo pensare ad un’Azienda, che comincia a ‘fare qualità sul serio’ (nel concreto, a salire livelli del CMMI) non meno di quattro-cinque anni dopo aver cominciato a raccogliere metriche sul software, esigenza che, come ho già ricordato, viene in mente (quando viene in mente) quando si ha una ragionevole certezza di rimanere sul mercato per tre anni ancora. Un’altra lezione non riportata sul testo, parte dell’esperienza che voglio trasmettervi, è la seguente: la documentazione è relativamente semplice da produrre; la vera difficoltà sta nel mantenerla in linea con il codice, giorno dopo giorno, anche quando le scadenze incombono. Un piano di ingegneria del software dovrebbe sempre individuare, dinamicamente nel corso dell’evolversi del progetto, quell’insieme di attività volte all’assicurazione della qualità che lo sviluppatore deve eseguire anche quando il fuoco ha raggiunto la scrivania, i terroristi hanno fatto irruzione nell’ufficio o mancano cinque minuti all’inizio della finale dei Mondiali di calcio. Inutile tenerle ‘nel cassetto’, anche se il rischio che il team finisca per fare solo quelle è molto alto: in un’attività come lo sviluppo di software, la chiave del successo non sta nell’imposizione, ma nella condivisione degli obiettivi. L’analisi di affidabilità del software, inizialmente condotta cercando di applicare mutatis mutandis i metodi matematici della teoria dell’affidabilità dell’hardware (particolarmente consolidati), ha finito per scontrarsi con un’insanabile difformità di scenario: tutti i guasti di un prodotto software risalgono a problemi di progettazione

12 di 16

o di implementazione, mentre l’usura non esiste; esattamente il contrario, insomma, degli assunti di base per l’hardware. Rimane comunque valido l’approccio basato sul tempo medio fra i guasti (MTBF, Mean Time Between Failure) e sulla disponibilità, fortemente legata al tempo medio di riparazione. Un breve paragrafo, quasi d’obbligo, sullo standard ISO 9001:2000 chiude il capitolo, che purtroppo non sfiora nemmeno strumenti classici di gestione della qualità come gli schemi di controllo, i diagrammi a dispersione, quelli di affinità e quelli a matrice. “Se non controllate i cambiamenti, saranno i cambiamenti a controllarvi”: così comincia l’ultimo capitolo della terza parte, dedicato alla gestione delle configurazioni software, argomento su cui in Programmazione.it è presente una mia recensione di un testo di Brian A. White sull’argomento, focalizzato sull’uso dell’allora Rational ClearCase (http://www.programmazione.it/index.php?entity=eitem&idItem=32149). Parte del materiale del capitolo è stata tratta dai numerosi lavori di Susan Dart, della Carnegie Mellon University, sul tema (http://www.sei.cmu.edu/legaci/scm/tech_rep/TR11_90/TOC_TR11_90.html). Ho qualche perplessità sulla lapidaria affermazione del testo “la maggior parte delle modifiche è giustificata”, ma la necessità di dotarsi di meccanismi e strumenti per gestire il cambiamento è fuori di dubbio. Posso anche assicurarvi che, nonostante il sempre maggiore successo delle architetture distribuite, una primaria necessità, condivisa anche dal testo, è che l’archivio del progetto si trovi in un luogo centralizzato e controllato. Un elemento da porre sotto configurazione cui pochi pensano all’inizio sono gli stessi strumenti software, ovvero editor, compilatori e strumenti CASE: eppure, chiunque lavori da qualche anno nel campo dello sviluppo può assicurarvi che due versioni successive di un compilatore cui venga passato lo stesso codice sorgente non danno mai lo stesso risultato. E’ quasi superfluo sottolineare che ad giorno d’oggi tutti gli strumenti per l’SCM (Software Configuration Management) si avvantaggiano di un archivio implementato come DBMS, ma pensate a quanto sono ancora diffusi gli “archivi umani”, ovvero gli sviluppatori o responsabili nella cui testa o nei cui cassetti si annida l’intera conoscenza di un progetto (molto spesso, solo perché è rimasto l’unico motivo della loro esistenza aziendale). Soffermate la vostra attenzione sulla Figura 22.3; possibilmente, fatene una fotocopia in grande formato ed appendetela al muro. Descrive il contenuto di un archivio di SCM; se nel vostro progetto manca qualcuno di questi elementi, fermatevi cinque minuti a riflettere se è perché il vostro progetto è abbastanza semplice da non richiederlo, o perché avete commesso un errore. La gestione delle versioni è naturalmente la prima caratteristica di un prodotto di SCM, ma altrettanto importanti sono il monitoraggio delle dipendenze e dei requisiti, la gestione delle release, la reportistica e l’audit (chi ha fatto cosa, e quando). Posso assicurarvi che per quanto riguarda l’audit rischiate facilmente di trovarvi in ufficio le barricate e gente con l’elmetto ed il fucile. Ricordate sempre la massima di Bennet: “ogni cambiamento, anche se è un miglioramento, è sempre accompagnato da inconvenienti e disagi”. Una funzionalità essenziale di un sistema di SCM deve essere la possibilità di raccogliere, in maniera automatica o almeno semiautomatica, tutti gli oggetti di configurazione rilevanti e costruire una specifica versione del software. Tutti sanno, per esempio, che il notissimo CVS (http://www.cvshome.org) non è un sistema di compilazione, ma che è possibile usarlo per costruire una specifica versione del software integrando in essi altri strumenti, per esempio Makefile. Un limite ineliminabile di questo strumento, peraltro meritoriamente assai diffuso, è invece il fatto che non implementa un processo di controllo delle modifiche (per esempio richieste di modifica, report delle modifiche, monitoraggio di bug). Infine, lavorate per una breve settimana in un team (ovvero almeno con un’altra persona), ed imparerete a benedire ogni mattina le funzionalità di check-in e check-out. Il paragrafo sul controllo dei cambiamenti è semplicemente meraviglioso; peccato che mi abbia fatto venire alla mente mille telefonate (di due minuti l’una) del cliente, che si sono trasformate in una catena gerarchica di n-mila telefonate (di un minuto l’una) culminate nello squillo del telefono sul tavolo dello sviluppatore. Considerate i lavori di Shannon sul deterioramento dell’informazione nel passaggio in una catena di elaborazioni, ed il gioco è fatto. Chi vuole avere qualche speranza di evitare i week-end in ufficio dovrebbe invece imparare a memoria una delle note finali: “è probabile che un controllo ‘un po’ eccessivo’ sia quello più appropriato”. Il momento immediatamente successivo all’approvazione della modifica è simile a quello in cui il paracadutista ha appena staccato il piede dall’aereo: chi garantirà che la modifica sia stata correttamente effettuata? La risposta, in cui perseverare con la dovuta disciplina, è una revisione tecnica formale per tutte le modifiche, tranne le più banali (ed in un progetto software complesso, scoprirete a vostre spese che di banale c’è ben poco. Siete davvero sicuri che semplicemente modificando la lunghezza di un messaggio d’errore nulla cambierà? Provare per credere…). A proposito: siete sicuri di sapere chi sono, per ogni modifica, tutte le persone che debbono venirne a conoscenza? Per finire: avreste mai creduto che in materia di SCM esiste una nutrita serie di standard IEEE, ISO, EIA e militari? Il testo non accenna nemmeno al problema del numbering delle versioni. In proposito, posso dirvi che nel management è diffusa l’idea che il numbering non debba nemmeno esistere, ovvero: tutti i prodotti devono portare come numero di versione 1.0, 2.0 e così via, per far credere che ognuno di essi è un prodotto innovativo e perfetto. Una favoletta alla

13 di 16

quale non crede nessuno, ed un ennesimo marchio di fabbrica facilmente riconoscibile delle ‘software house’ ospitate in un sottoscala.

Argomenti avanzati dell’ingegneria del software La quarta parte, dedicata agli ‘argomenti avanzati’, occupa opportunamente un posto a sé, ma non dovrebbe esserne trascurata, pur con qualche oggettiva difficoltà per chi non padroneggia gli strumenti matematici necessari, la lettura. In particolare modo, non vi sono scuse per non studiare il Capitolo 25 sull’ingegneria del software a componenti, che sempre più potrebbe essere l’unica strada per uscire dall’impasse dei progetti sempre più complessi con tempi e budget sempre più ristretti. Si comincia con il capitolo sui metodi formali, culminante naturalmente nell’introduzione ad OCL (Object Constraint Language) e Z. La chiave dei metodi formali sta in una specifica non ambigua dei prerequisiti, utilizzando la teoria degli insiemi e la notazione logica. Il campo di applicazione più naturale di questi metodi è il software mission-critical, ed in effetti troviamo riferimenti al lavoro di Warmer e Kleppe, pubblicato in versione aggiornata nel 1999 dalla Addison-Wesley, nelle specifiche militari DoDAF (DoD Architecture Framework 1.0, http://www.software.org/pub/architecture/dodaf.asp). La realtà dei fatti è che non vi è nessun argomento reale contro i metodi formali: essi vengono solo definiti “troppo difficili”, in un Paese in cui quasi mai un ingegnere può fare il suo lavoro. I metodi formali riescono a conseguire la mancanza di ambiguità e la coerenza delle specifiche, mentre al momento è assai più difficile raggiungere la completezza. Le basi matematiche per l’applicazione dei metodi formali richiedono solo la conoscenza di alcune nozioni di teoria degli insiemi davvero banali per chi ha seguito un corso di studi universitari scientifico (ma quanti, fra i key decisors aziendali, l’hanno seguito?). Veniamo, finalmente, ai due linguaggi formali presentati nel capitolo. OCL è, in effetti, non un vero e proprio linguaggio formale, ma un linguaggio di modellazione, pur con tutti gli attributi di un linguaggio formale; esso infatti costituisce una parte delle specifiche UML standardizzate da OMG, poiché è stato pensato come un’’estensione’ formale per consentire agli utilizzatori di UML di impiegare una maggiore precisione nelle loro specifiche. Per facilitarne l’adozione e renderlo più facilmente elaborabile dai calcolatori, i progettisti hanno sostituito la notazione matematica convenzionale con caratteri ASCII, rendendolo però al contempo più prolisso. OCL aggiunge un insieme di condizioni o vincoli ad un diagramma UML (tipicamente delle classi, degli stati o delle attività), ed è un linguaggio object-oriented, che utilizza anche i classici operatori O-O come quello di referenziazione o la dot notation. L’esempio d’uso di OCL, un gestore di blocchi per file system, introduce tutti i concetti alla base di un metodo formale, ovvero invarianti, pre- e post-condizioni. Z è invece, probabilmente, il linguaggio per specifiche formali oggi più utilizzato, vantando ormai vent’anni di storia. Si basa sulla logica dei predicati di primo ordine per costruire degli schemi, ovvero l’equivalente nel campo delle specifiche formali di una subroutine o procedura in un linguaggio di programmazione. Uno schema in Z descrive i dati memorizzati che un sistema consulta e modifica, ovvero ciò che in Z si chiama stato. Si tratta di un linguaggio notevolmente più formale di OCL, ma chi ha dimestichezza con la logica degli insiemi ne trarrà notevoli vantaggi. Nel campo degli strumenti, purtroppo, troviamo solo progetti di ricerca: focalizzando l’attenzione su OCL, per esempio, nessuno dei produttori di tool UML riconosciuti da OMG (http://www.uml.org/#Links-UML2Tools) ha implementato funzionalità per applicare questo metodo formale. Nonostante i vantaggi che si possono ottenere, la decisione di adottare un metodo formale non va presa alla leggera ma, come al solito, pesando una serie di fattori: i principali sono la valutazione dei costi d’adozione, piuttosto alti nelle fasi iniziali, e la scelta dei componenti cui applicarli. E’ importante notare, però, che i metodi formali possono essere in concreto l’unica strada per creare librerie di componenti riutilizzabili. Un esempio di processo in grado di incorporare i metodi formali nell’ingegneria del software tradizionale è la produzione di software in camera sterile (cleanroom), proposta per la prima volta da Mills, Dyer e Ginger nel 1987 ed oggetto del successivo capitolo. La cleanroom software engineering si propone di eliminare i costi della rimozione degli errori scrivendo porzioni di software corrette per principio e verificandone la correttezza prima del collaudo; il modello di processo corrispondente incorpora la certificazione statistica di qualità delle porzioni di codice a mano a mano che vengono prodotte. L’ingegneria in camera sterile è esattamente l’opposto del metodo preferito dai clienti e dai manager meno ‘illuminati’, il “portami una cosa funzionante che ti dico come correggerla” ripetuto n volte (con n molto alto) che causa tanta frustrazione negli ingegneri, figure preparate per essere progettisti e controllori che vengono ridotte a meri esecutori. Se pensate di valere qualcosa, lottate fino alla morte per i metodi formali e lo sviluppo a componenti: sono il modo più sicuro per tagliare fuori le mezze calzette dal mercato. Per quanto un lavoro proposto nel 1994 sull’IBM Systems Journal (http://domino.research.ibm.com/tchjr/journalindex.nsf/e90fc5d047e64ebf85256bc80066919c/ad8310e10e47 aa4185256bfa00685cc5?OpenDocument) sottolineasse i successi dei primi tentativi, l’ingegneria del software in camera sterile è, manco a dirlo, poco diffusa: un articolo di Henderson del 1995 suggerisce i

14 di 16

motivi plausibili; io li riassumerei con un vecchio proverbio delle mie parti: il raglio di cento asini riesce a coprire perfino l’ululato di un lupo. In termini più pragmatici, perché dare ad un preparato ingegnere diecimila euro al mese, quando sul mercato ci sono dieci mezze calzette che si accontentano di novecento euro (e se per caso ad un’Azienda capita sottomano un preparato ingegnere, il mercato è livellato e sempre novecento euro sono)? La soluzione a camera sterile adotta una versione specializzata del modello incrementale; la caratteristica distintiva è quella di spostare i collaudi dal singolo sviluppatore ad un team indipendente. Il raffinamento si basa sul concetto di scatola, ovvero una rappresentazione del sistema (o di un aspetto del sistema) ad un certo livello di dettaglio. Un analista ripartisce gerarchicamente il sistema tramite tre tipi di scatole: nere, che definiscono “la reazione di una parte del sistema ad una serie di stimoli”, di stato, che racchiudono i dati ed i servizi necessari per implementare il comportamento definito dalle scatole nere, e chiare, in cui sono specificati i dettagli procedurali. Ad ogni passo di raffinamento si svolge la verifica di correttezza. Il collaudo su basi statistiche chiude questo interessante capitolo, seguito a ruota da quello sull’ingegneria del software a componenti. Questa prevede due attività di ingegnerizzazione parallele: l’ingegnerizzazione del dominio, che esplora il dominio di un’applicazione con lo scopo di individuare i componenti (funzioni, comportamenti e dati) che possono essere candidati per il riutilizzo, e lo sviluppo per componenti. E’ importante soffermarsi un attimo a riflettere cosa ha significato la nascita dell’ingegneria a componenti: l’implementazione ha lasciato il posto all’integrazione, uno dei mercati attualmente più fiorenti dell’industria del software. L’analisi del dominio (http://www.sei.cmu.edu/str/descriptions/deda.html), in particolare, secondo alcuni potrebbe ben presto diventare importante “quasi quanto l’ingegneria del software”, non foss’altro in quanto è applicabile a qualsiasi paradigma di ingegneria ed a qualsiasi tipo di sviluppo, convenzionale o ad oggetti. Vengono brevemente presentati, naturalmente, i tre standard industriali più affermati, ovvero CORBA, Microsoft COM (mentre la sua evoluzione COM+ viene rimandata alla bibliografia di capitolo) e Sun JavaBean, ed il comune modello ORB (Object Request Broker) che tutti e tre implementano. La disponibilità di una vasta libreria di componenti riutilizzabili comporta, in maniera abbastanza ovvia, la necessità di uno schema di classificazione che consenta di effettuare facilmente ricerche; sono stati proposti vari schemi (http://research.microsoft.com/users/cszypers/events/WCOP2001/Lucena.pdf), tutti basati sul modello 3C (Concetto, Contenuto e Contesto). Soprendentemente, la maggior parte del lavoro svolto finora suggerisce l’impiego dei tradizionali metodi bibliotecari, in luogo dei sistemi di intelligenza artificiale ed ipertestuali. Lo sviluppo per componenti ha un significativo (e benefico) impatto sulla qualità del software: ad ogni riutilizzo i difetti non rilevati nell’uso precedente vengono individuati ed eliminati, convergendo verso un componente virtualmente esente da difetti. Un interessante effetto collaterale dell’ingegneria per componenti è la possibilità di utilizzare come metrica di costo, invece dei LOC o dei Function Points, i punti struttura, ovvero costrutti all’interno di un modello strutturale, che a sua volta è un approccio ingegneristico sul dominio basato su schemi ricorrenti nelle applicazioni. Nella pratica, i punti struttura coincidono con i componenti o i package riutilizzabili; naturalmente, ad essi è associato un costo in termini di validazione, adattamento, integrazione e manutenzione. Manco a dirlo, un’analisi di tali costi è facilitata dall’esistenza di una serie storica dei casi di utilizzo. L’ultimo capitolo ‘tecnico’ del testo è dedicato alla reingegnerizzazione. Nutro un particolare affetto per l’argomento, come per tutte le cose che risalgono agli inizi della mia carriera, ma in generale il problema del software reengineering non dovrebbe essere sottovalutato: vi capiterà più spesso di quanto pensiate dover manutenere codice del quale si è persa ogni traccia della documentazione (se mai esistita) ed ogni riferimento al team di sviluppo, nonché i sorgenti nei casi peggiori. Il capitolo comincia però non con la reingegnerizzazione del codice, ma con la ben nota BPR (Business Process Reengineering): non ho naturalmente nulla in contrario ad una disciplina nata sotto i crismi della Harvard School, nonché alla naturale evoluzione dei processi aziendali stessi alla radice di tanti progetti software (quasi la totalità se consideriamo il caso italiano), ma credo che ognuno di noi abbia esperienza dei consulenti in giacca e cravatta che vendono costosa aria fritta in salsa linguistica anglosassone. Nei casi non patologici, invece, il BPR segue le buone prassi dell’ingegneria, a cominciare dal modello iterativo ed incrementale; è convinzione comune, almeno nel panorama scientifico, che una reingegnerizzazione delle funzioni aziendali debba concentrarsi su processi o sottoprocessi individuali, piuttosto che avventurarsi in una rischiosa rimodellazione dell’intera gerarchia. Venendo al discorso della reingegnerizzazione del software, non dovremmo mai dimenticare che l’ingegneria del software è nata proprio come risposta al problema dell’iceberg della manutenzione, ovvero di quelle applicazioni, evolutesi selvaggiamente nel corso degli anni, per le quali ogni modifica si trasformava in una serie di effetti imprevisti e gravi. La situazione è oggi a dir poco preoccupante: la manutenzione di software esistente assorbe più del 60% del lavoro in un’azienda di produzione, e la percentuale è in crescita. A parte l’obsolescenza (o la semplice non applicazione) delle tecniche di ingegneria in auge dieci o quindici anni fa, il problema – principe delle applicazioni legacy è la mobilità del personale di sviluppo; vi è qui un

15 di 16

infinito problema dell’uovo e della gallina fra Aziende che non investono in formazione e non valorizzano le competenze, e ‘programmatori’ sulla breccia da troppi anni, che si rifiutano ostinatamente di aderire alle prassi di documentazione e standardizzazione perché temono di perdere l’ultima ragione della loro esistenza aziendale. La reingegnerizzazione richiede tempo, ha costi rilevanti e assorbe risorse; un progetto di reengineering è destinato a durare parecchi anni. Il reverse engineering per il software consiste nell’analizzare un programma al fine di produrne una rappresentazione ad un livello di astrazione superiore a quello del codice sorgente; si tratta cioè di recuperare un modello progettuale. L’attività di reingegnerizzazione più comune è la ristrutturazione del codice: se l’architettura di programma è relativamente solida ma il codice dei singoli moduli presenta problemi, lo si può sottoporre ad analisi, rilevando le violazioni dei principi di programmazione strutturata e modificando di conseguenza i sorgenti: le prassi in materia sono così consolidate, che spesso esistono strumenti in grado di effettuare automaticamente la ristrutturazione. Viceversa, un programma con architettura dei dati debole è difficile da adattare e migliorare; a differenza di quella del codice, la ristrutturazione dei dati è un’attività di reingegnerizzazione a pieno titolo, che comporta un alto livello di astrazione. E’ da tenere presente che ogni modifica ai dati si riflette in modifiche all’architettura o sul piano del codice. Un discorso a parte merita il forward engineering, che non solo estrae informazioni di ordine progettuale da software esistente, ma utilizza queste informazioni per alterare o ricostruire il sistema così da migliorarne la qualità. Il capitolo esamina, naturalmente, tutte e tre le tecniche citate.

Conclusioni Il testo si chiude con uno sguardo sul futuro, ben consapevole dei limiti di ogni previsione: ma del resto, in che altro modo si può chiudere un testo storico nel suo campo? Comunque andranno le cose, è facile prevedere che l’ingegneria del software del ventunesimo secolo si occuperà sempre di più dell’elaborazione dell’informazione, cercando di estrarre conoscenza dalla sterminata mole di dati accumulata grazie all’informatica negli ultimi sessant’anni. E’ facile anche prevedere l’affermazione delle architetture orientate alla collaborazione. Vada come vada, il futuro spetta al software. E costruire il futuro spetterà, ancora una volta, agli ingegneri.

16 di 16

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF