ingegneria del software - ghezzi jazayeri mandrioli.pdf

659

Upload: baroneazzurro

Post on 07-Jul-2018

1.075 views

Category:

Documents


391 download

TRANSCRIPT

21' edizione
 
Prefazione alla seconda edizione  xi  Il ruolo dell 'orientamento agli oggetti xii  Lo scopo dei casi di studio xiii  Risorse per i docenti xiii 
Prefazione alla prima edizione xv  A chi è rivolto xvi  Prerequisiti xvi  Organizzazione e contenuti xvi  Esercizi xvii  Casi di studio xviii  Laboratorio xviii  Percorsi di lettura xviii  Ringraziamenti xix 
Capitolo 1 Ingegneria del software: visione d'insieme  1 1.1 II ruolo dell'ingegneria del software nel progetto di un sistema 2  1.2 Breve storia dell'ingegneria del software 3  1.3 II ruolo dell'ingegnere del software 6  1.4 II ciclo di vita del software 6  1.5 Rapporto tra l'ingegneria del software e altri campi dell' informatica 9 
1.5.1 Linguaggi di pro gra mma zio ne 9 
1.5.2 Sistemi opera tivi 10 
1.5.3 Basi di dat i 11 
1.5.4 Intellige nza artificiale 12 
1.5.5 Mode lli teorici 12 
1.6 Relazioni tra l'ingegneria del software e altre discipline 13  1.6.1 Scienze organizza tive 13 
1.6.2 Ingeg neria dei sistemi 14 
1.7 Osservazioni conclusive 14  Note bibliografiche 15
Capitolo 2 II software: natura e qualità 17  2.1 Classificazione delle qualità del software 18 
2.1.1 Qual ità inte rne ed esterne 18 
 
2.2 Principali qualità del software 19  2.2.1 Correttezza, affidabilità e robustezza 19 
2.2 .2 Prestazioni 13 
2.2.5 Manute nibil i tà 26  2.2. 6 Riusabilità 29 
2.2 .7 Portabilità 31  2.2.8 Compren sibil t à 31 
2.2.9 Interoperabi lità 32  2.2.1 0 Produtt ività 33  2.2.1 1 Tempestiv ità 34  2.2 .12 Visibilità 36 
2.3 Requisiti di qualità in diverse aree applicative 37  2.3.1 Sistemi informa tivi 37  2.3 .2 Sistemi in te mp o reale 38 
2.3. 3 Sistemi distribuiti 40 
2.3. 4 Sistemi emb edd ed 41 
2.4 Misura della qualità 42  2.5 Osservazioni conclusive 42
 Note bibliografiche 43
Capitolo 3 Principi dell'ingegneria del software  45  3.1 Rigore e formalità 47  3.2 Separazione degli interessi 49  3.3 Modularità 51  3.4 Astrazione 55  3.5 Anticipazione del cambiamento 56  3.6 Generalità 58  3.7 Incrementalità 59  3.8 Illustrazione dei principi dell'ingegneria del software attraverso
due casi di studio 60  3.8.1 Caso di studi o nella costru zione di un comp ilat ore 61 
3.8 .2 Cas o di stu dio nell' ingeg neria dei sistemi 66 
3.9 Osservazioni conclusive 71  Note bibliografiche 73
Capitolo 4 Progettazione e architetture software  75  4.1 Attività di progettazione del software e suoi obiettivi 78 
4.1.1 Progettazi one in vista del ca mbi ame nt o 80 
4.1 .2 Famiglie di prod otti 85 
4.2 Tecniche di modularizzazione 87  4.2.1 La stru ttu ra mod ula re e la sua rappres entazi one 87 
4.2.2 Interfaccia, impleme ntazio ne e infor matio n hidin g 95 
 
4. 2. 6 Ra ff in am en to per passi successivi 122 
4.2.7 Progettazione top- down e bo tt om- up 129 
4.3 Gestione delle anomalie 130  4.4 Un esempio di progettazione 134  4.5 Software concorrente 137 
4.5 .1 I dati condivi si 138 
4.5. 2 Software real-time 146 
4.5 .3 Software dist ribui to 148 
4.6 Progettazione orientata agli oggetti 154  4.6 .1 Genera lizza zione e specializzazi one 155 
4.6 .2 Associazioni 158 
4.6 .3 Aggregazione 160 
4.6 .4 Ulteri ori noz ion i sui di ag ra mmi delle classi U M L 160 
4.7 Architettura e componenti 161  4.7.1 Archi tett ure stan dard 162  4.7.2 Co mp on ent i software 165 
4.7. 3 L'architettura com e pia tta form a per l 'integrazi one dei co mp on en ti 167 
4.7. 4 Archit ettu re per sistemi distribu iti 169 
4.8 Osservazioni conclusive 170  Note bibliografiche 175
Capitolo 5 Specifica  177 5.1 I possibili usi delle specifiche 178  5.2 Qualità delle specifiche 181  5.3 Classificazione degli stili di specifica 184  5.4 Verifica delle specifiche 187  5.5 Specifiche operazionali 188 
5.5.1 Di ag ra mm i di flusso di dati : la specifica delle fu nz io ni
dei sistemi inf orm ati vi 188
5-5-2 Dia gra mmi U M L per co mp ort am en ti specifici 194 
5. 5. 3 Ma cc hi ne a stati finiti: des cri zio ne del flusso di co nt ro ll o 196 
5.5. 4 Le reti di Petri: specifica di sistemi asin croni 20 4 
5.6 Specifiche descrittive 230  5.6.1 Dia gra mmi entità-relazio ne 23 0  5.6.2 Specifiche logiche 23 3 
5.6.3 Specifiche algebriche 251 
5.7 Stesura e uso delle specifiche nella pratica 259  5.7.1 Requis iti per le not azi oni di specifica 25 9  5.7.2 Cost ruz ion e di specifiche mod ular i 26 3 
5.7 .3 Specific he per l'u ten te finale 28 2 
5.8 Osservazioni conclusive 283  Note bibliografiche 291
Capitolo 6 Verifica  295 6.1 Obiettivi e requisiti della verifica 296 
6.1.1 Verificare tu tto 29 6 
 
6.1.3 La verifica può essere oggettiva o soggettiva 298  6.1.4 Verificare anche le qualità implicite 299 
6.2 Approcci alla verifica 300  6.3 Test 300 
6.3.1 Obiettivi del test 302  6.3.2 Fondamenti teorici del test 304  6.3.3 Principi empirici di test 306  6.3.4 Test in piccolo 309  6.3.5 Test in grande 330  6.3.6 Separazione degli interessi nell'attività di test 340  6.3.7 Test di software concorrente e real-time 342 
6.4 Analisi 345  6.4.1 Tecniche di analisi informale 346  6.4.2 Prove di correttezza 349 
6.5 Esecuzione simbolica 368  6.5.1 Concetti fondamentali dell'esecuzione simbolica 370  6.5.2 Programmi con array 373  6.5.3 Uso dell'esecuzione simbolica nel test 376 
6.6 Model checking 378  6.7 Integrazione delle tecniche di verifica 381  6.8 Debugging 382  6.9 Verifica di altre proprietà del software 387 
6.9.1 Verifica delle prestazioni 387  6.9.2 Verifica dell'affidabilità 388  6.9.3 Verifica di qualità soggettive 392
6.10 Osservazioni conclusive 403  Note bibliografiche 413 
Capitolo 7 Processo di produzione del software 417  7.1 Cos'è un modello di un processo di produzione del software? 419  7.2 Perché i modelli di processo di sviluppo del software sono importanti? 421  7.3 Attività principali della produzione del software 423 
7.3.1 Studio di fattibilità 424  7.3.2 Acquisizione, analisi e specifica dei requisiti 424  7.3.3 Definizione e progettazione dettagliata dell'architettura software 432  7.3.4 Produzione di codice e test dei moduli 432  7.3.5 Integrazione e test del sistema 433  7.3.6 Rilascio, installazione e manutenzione 433 
7.4 Visione d'insieme dei modelli di processo del software 435  7.4.1 Modello a cascata 435  7.4.2 Modelli evolutivi 443  7.4.3 Modello trasformazionale 446  7.4.4 Modello a spirale 449  7.4.5 Studio dei modelli di processo 450 
7.5 Gestione del software esistente 453  7.6 Casi di studio 454 
 
7.6.3 Caso di studio: il processo "synchronize and stabilize" di Microsoft 464  7.6.4 Caso di studio: l'approccio open-source 465
7.7 Organizzazione del processo 466  7.7.1 Structured Analysis/Structured Design 467  7.7.2 Metodologia di Jackson 472  7.7.3 Processo unificato di sviluppo del software (UP) 477 
7.8 Gestione delle configurazioni 481  7.9 Standard per il software 484
7.10 Osservazioni conclusive 485  Note bibliografiche 488 
Capitolo 8 Gestione dell'ingegneria del software  491  8.1 Funzioni del management 493  8.2 Pianificazione di progetto 494 
8.2.1 Produttività del software 496  8.2.2 Persone e produttività 503  8.2.3 Stima dei costi 504 
8.3 Controllo di progetto 512  8.3.1 Schemi di scomposizione delle attività 512  8.3.2 Diagrammi di Gantt 513  8.3.3 Diagrammi PERT 515  8.3.4 Gestione delle deviazioni rispetto al piano 518 
8.4 Organizzazione 519  8.4.1 Organizzazione centralizzata 522  8.4.2 Organizzazioni decentralizzate 524  8.4.3 Organizzazioni miste 525  8.4.4 Valutazione delle organizzazioni di gruppo 526 
8.5 Gestione dei rischi 527  8.5.1 Tipici rischi di management nell'ingegneria del software 528 
8.6 II modello CMM 530  8.7 Osservazioni conclusive 532
 Note bibliografiche 536
Capitolo 9 Strumenti e ambienti dell'ingegneria del software  539
9.1 Evoluzione storica degli strumenti e degli ambienti 540  9.2 Parametri di confronto degli strumenti 541  9.3 Strumenti rappresentativi 545 
9.3.1 Editor 546  9.3.2 Linker 547  9.3.3 Interpreti 547  9.3.4 Generatori di codice 548  9.3.5 Debugger 549  9.3.6 Strumenti utilizzati nel test 550  9.3.7 Analizzatori statici 552  9.3.8 Strumenti per le interfacce grafiche 554  9.3.9 Strumenti di gestione delle configurazioni 556
9.3.10 Sistemi per il tracciamento 560
 
9.3.11 Strumenti di reverse engineering e reingegnerizzazione 561 9.3.12 Strumenti di supporto al processo 562 9.3.13 Strumenti di management 563
9.4 Integrazione di strumenti 564 9.5 Fattori di influenza dell'evoluzione degli strumenti 565 9.6 Osservazioni conclusive 566
 Note bibliografiche 568
Capitolo 10 Epilogo 571
10.1 II futuro 571 10.2 Responsabilità etiche e sociali 574 10.3 Codice etico e deontologia dell'ingegneria del software 575 10.4 Commenti conclusivi 576
 Note bibliografiche 576
Appendice Casi di studio 579
Caso di studio A: automazione di un ufficio legale 579 A. 1 Pianificazione economica e finanziaria 581 A.2 Pianificazione tecnica e gestione 581 A.3 Monitoraggio del progetto 583 A.4 Rilascio iniziale 583 A. 5 Un parziale recupero 584
Caso di studio B: costruzione di una famiglia di compilatori 584 B.l Pianificazione iniziale del prodotto 584 B.2 Pianificazione economica e finanziaria 585 B.3 Pianificazione e gestione tecnica 586 B.4 Prime fasi dello sviluppo 586 B.5 Monitoraggio del progetto 587 B.6 Riesame del progetto, ristrutturazione e precisazione
degli obiettivi 587 B.7 Assegnamento di responsabilità 589 B.8 Progresso continuo e rilascio del prodotto 590 B.9 Distribuzione del prodotto 590 B.10 Commenti 590
Caso di studio C: sviluppo incrementale 593 Caso di studio D: applicazione di metodi formali nell'industria 594
D.l Formazione 596 D.2 Specifica dei requisiti 596 D.3 Convalida dei requisiti e pianificazione della verifica 598 D.4 Progettazione, implementazione e verifica 599 D.5 Valutazione complessiva 600 D.6 Impatto del progetto sulla strategia aziendale 602
Considerazioni finali 603  Note bibliografiche 604
Bibliografìa 605
 
P R E F A Z I O N E A L L A S E C O N D A E D I Z I O N E
La prima edizione di questo libro è stata pubblicata nel 1991. Da quella data, numerosi sono stati i progressi registrati nell'informatica e nel campo dell'ingegneria del software. Certamente, la diffusione di Internet ha esercitato una profonda influenza sulla società: dalla formazione alla ricerca, dall'economia all'industria, al commercio. Abbiamo deciso di scrivere la seconda edizione per aggiornare il libro rispetto ai progressi nell'ingegneria del software nell'ultimo decennio.
In tutti questi anni abbiamo avuto conferma della validità dell'approccio su cui il li-  bro è basato, e cioè la durabilità e l 'importanza dei principi, che hanno retto il passaggio del tempo: nonostante la tecnologia sia migliorata, i principi dell'ingegneria del software sono rimasti invariati. Abbiamo, quindi, potuto aggiornare tutti i capitoli senza modifi- care la struttura originaria del libro, che rimane la seguente:
• Introduzione: Capitoli 1-3;
• Processo e gestione: Capitoli 7-8;
• Strumenti e ambienti: Capitolo 9.
I Capitoli relativi al prodotto seguono questo ordine: progetto (Capitolo 4), specifica (Capitolo 5) e verifica (Capitolo 6). Ciò differisce dall'approccio tenuto da altri libri, che trattano la specifica prima del progetto. La nostra scelta deriva invece dall'approccio ba- sato sui principi seguiti dal libro. Le attività di progetto, specifica e verifica permeano l'in- tero ciclo di vita del software. Ad esempio, l'attività di progetto non riguarda solo la de- finizione dell'architettura del software, ma anche la produzione delle specifiche. L'approccio  basato sulla progettazione modulare ci aiuta a strutturare non solo il software, ma anche i documenti di specifica. Altri libri trattano la specifica prima del progetto siccome, se- condo i processi tradizionali di software, prima si specifica un software e poi lo si proget- ta. Al contrario, noi crediamo che apprendere prima gli approcci e l'attività di progetta- zione crei la motivazione necessaria per lo studio della specifica e fornisca le tecniche e le capacità per poter strutturare tali specifiche.
 
è quella degli strumenti e degli ambienti di sviluppo. Il Capitolo 9, quindi, è stato note- volmente rivisto, anche se il nostro approccio consiste nel presentare i principi più che gli specifici strumenti. Abbiamo visto durante gli anni che gli strumenti cambiamo di pari  passo con l'evoluzione tecnologica, e la scelta di quali particolari strumenti studiare di-  pende sia dal problema che dall'ambiente di lavoro. Ci concentreremo pertanto su un qua- dro di riferimento per lo studio e la valutazione degli strumenti software, senza trattarne dettagliatamente nessuno in particolare.
Oltre ad aggiunte e cambiamenti minori, sono state apportate le seguenti modifiche.  Nel Capitolo 3 sono stati aggiunti due nuovi casi di studio, uno riguardante un sem-
 plice compilatore e l'altro riguardante il sistema di ascensori, che viene poi utilizzato am-  piamente nel libro. I due casi di studio sono complementari, in quanto trattano di aree applicative diverse e pongono problemi progettuali diversi. Vengono presentati in questo capitolo in modo semplice e intuitivo per far riflettere lo studente riguardo ai problemi dei sistemi complessi e per illustrare l'uso dei principi generali con esempi concreti.
 Nel Capitolo 4 è stata estesa la trattazione riguardante l'orientamento agli oggetti, l'architettura software, i componenti e i sistemi distribuiti.
 Nel Capitolo 5 è stata aggiunta la trattazione riguardante Z e UML. Vi è, inoltre, un nuovo paragrafo che affronta in maniera più sistematica l'ingegneria dei requisiti.
 Nel Capitolo 6 sono stati aggiunti il model checking e GQM come tecniche di va- lutazione e verifica.
 Nel Capitolo 7 sono state incluse trattazioni del processo software in connessione con UML, del processo open-source e del processo synchronize-and-stabilize  di Microsoft. E stato inoltre aggiunto un nuovo caso di studio sull'ingegneria dei requisiti.
 Nel Capitolo 8 sono stati aggiunti il  capability maturìty model e la descrizione delle fabbriche del software di Nokia.
 Nel Capitolo 9 è stata aggiunta una trattazione di CVS.  Nel Capitolo 10 è stata aggiunta una trattazione dei problemi di tipo etico nell'am-
 bito dell'ingegneria del software.  Nell'Appendice, è stato aggiunto un nuovo caso di studio riguardante l'uso dei me-
todi formali nell'industria.
Il ruolo dell'orientamento agli oggetti
 
Lo scopo dei casi di studio
I casi di studio presentati nel libro e nell'appendice hanno due scopi: presentare gli argo- menti trattati in un contesto più ampio, per poter dare allo studente una visione più am-  pia riguardo all'importanza dei principi e delle tecniche e fornire agli studenti che non hanno mai visto progetti reali una "visione della realtà pratica". I casi di studio, pur es- sendo semplificati per focalizzare l'attenzione sugli argomenti più importanti, sono utili soprattutto agli studenti meno esperti. Lo studio dell'ingegneria del software in un am-  biente universitario pone dei problemi, in quanto lo studente medio non è mai venuto in contatto con i problemi che gli ingegneri del software trattano tutti i giorni; i casi di stu- dio cercano pertanto di ovviare a questo problema.
Risorse per i docenti
E disponibile per i docenti un CD-ROM d'accompagnamento che comprende soluzioni agli esercizi e un programma del corso d'esempio. È anche disponibile, sia per gli studenti che  per i docenti, un sito Web complementare fornito dall'editore, attraverso il quale è possi-  bile scaricare le slide (in inglese) e contattare gli autori: www.prenhall.com/ghezzi.  Commenti, suggerimenti e feedback sono sempre ben accetti.
Carlo Ghezzi  Milano, Italia
Dino Mandrioli  Lugano, Svizzera
 Alle nostre famiglie,  per il  loro sostegno  e la pazienza.
 
P R E F A Z I O N E A L L A P R I M A E D I Z I O N E
Questo è un libro di testo dedicato all'ingegneria del software. Il tema conduttore è l'im-  portanza del rigore nella pratica di questa disciplina. I libri di testo tradizionali sono ba- sati sul modello di ciclo di vita dello sviluppo del software e su una illustrazione delle fa- si che lo compongono: requisiti, specifica, progetto, codifica, manutenzione. Al contra- rio, la nostra presentazione si basa sui principi fondamentali che possono essere adottati indipendentemente dal modello di ciclo di vita, e in tutte le sue fasi. Ci focalizzeremo,
 pertanto, sull'identificazione e l'applicazione di principi fondamentali applicabili per tut- to il ciclo di vita.
Vediamo ora le caratteristiche principali del libro.
• Affronta i problemi dell'ingegneria del software, non quelli della programmazione.  Ad esempio, sono state omesse tutte le discussioni riguardanti i costrutti dei linguaggi di programmazione, come  goto,  cicli, etc. Riteniamo che lo studente di ingegneria del software debba già avere familiarità con tali argomenti, che sono trattati nei li-  bri di testo sui linguaggi di programmazione. Non viene neppure affrontato il pro-  blema di tradurre la descrizione di un progetto software in determinati linguaggi di  programmazione. II libro assume come prerequisito l'abilità di realizzare i singoli mo- duli che compongono un programma complesso e si concentra sui problemi di com-  posizione di un progetto modulare.
• Sottolinea i principi e le tecniche piuttosto  che gli strumenti  specifici. Oggi molte azien- de stanno sviluppando strumenti e ambienti d'ingegneria del software, ed è auspi- cabile che ne verranno inventati migliori e più sofisticati al crescere delle conoscen- ze sulla disciplina. Una volta che lo studente abbia compreso i principi e le tecniche sulle quali lo strumento si basa, gli sarà facile padroneggiarlo. I principi e le tecni- che sono applicabili a vari strumenti mentre l'acquisizione della padronanza nell'u- so di un particolare strumento non prepara lo studente all'uso di altri strumenti. Inoltre, è rischioso usare strumenti senza comprenderne i principi sottostanti.
 
ticolare tecnica seguendo un insieme di indicazioni pratiche, questo libro vuole met- ter in grado il lettore di comprendere perché   debba, o non debba, essere usata una  particolare tecnica. Nonostante nella trattazione venga anche mostrato come certe tecniche possono essere usate per implementare un principio specifico, lo scopo prin- cipale è la comprensione del perché.
In questo senso, libro incarna la nostre convinzioni sull'uso dei principi fondamentali e l'importanza delle teoria nella pratica dell'ingegneria, ed è stato usato sia in corsi univer- sitari che professionali sui diversi aspetti dell'ingegneria del software.
A chi è rivolto
Il volume è stato pensato per essere usato sia come libro di testo per studenti che frequentano corsi di ingegneria del software che per autodidatti. Ingegneri, professionisti e manager  potranno trovare materiale che li convinca dell'utilità delle moderne pratiche dell'inge- gneria del software e della necessità di adottarle. Può essere usato da quanti siano dispo- sti a una riflessione approfondita, mentre non è del tutto appropriato per una rapida con- sultazione. In particolare, ove necessario, abbiamo sacrificato l'ampiezza dei temi trattati  per la profondità di analisi. Per i professionisti, le note sui possibili approfondimenti pos- sono essere estremamente utili. E inoltre disponibile un manuale per docenti1, con idee  per l'organizzazione dei corsi e le soluzioni di alcuni esercizi.
Prerequisiti
Il libro è pensato per studenti di informatica che conoscano la programmazione, gli al- goritmi e le strutture dati e che siano esperti in almeno un linguaggio di programmazio- ne. Il ragionamento analitico, anche se non strettamente necessario, agevolerà notevolmente la capacità del lettore di comprendere i concetti più profondi del libro. Queste capacità sono sviluppate tramite corsi di analisi matematica, matematica discreta e, ovviamente, informatica teorica. Riteniamo infatti necessario che lo studente, indipendentemente dal- la disciplina ingegneristica seguita, sia "matematicamente maturo".
Organizzazione e contenuti
L'ingegneria del software è una disciplina vasta e multi-dimensionale. Organizzare quin- di un libro di testo su questo argomento presenta numerose difficoltà, in quanto dovreb-  be presentare il materiale in maniera sequenziale, mentre i numerosi aspetti dell'ingegne- ria del software sono talmente correlati tra di loro da rendere impossibile una sequenza ottimale di argomenti. Il libro è stato organizzato in base a queste considerazioni:
 
• utilizzo di un processo  per costruire tale prodotto;
• utilizzo degli strumenti  per supportare tale processo.
Il libro è suddiviso in tre blocchi, che trattano a turno il prodotto software (dal Capitolo 4 al 6), il processo di ingegneria del software e la sua gestione (Capitoli 7 e 8), gli stru- menti (Capitolo 9). I Capitoli 1, 2 e 3 forniscono un'introduzione generale alla materia e costituiscono un prologo per i capitoli successivi.
 Nel Capitolo 2 vengono discussi i numerosi aspetti e le caratteristiche desiderabili del software. Queste caratteristiche impongono dei limiti al costruttore di software e al proces- so da utilizzare. Nel Capitolo 3 sono presentati i principi per costruire software di alta qua- lità. Studiando i principi, invece degli strumenti specifici, lo studente acquisisce una cono- scenza indipendente da una particolare tecnologia e dall'ambiente applicativo. Siccome la tecnologia cambia e gli ambienti evolvono, lo studente dovrebbe così disporre di fondamenti e tecniche che possono essere utilizzate in diverse aree applicative. Dal Capitolo 4 al Capitolo 8 vengono affrontate le tecniche per applicare i principi del Capitolo 3 al progetto, alla spe- cifica, alla verifica, al processo ingegneristico e alla sua gestione. Nel Capitolo 9, viene di- scusso l'uso dei computer come supporto alla creazione del software. Le discussioni sui va- ri strumenti specifici accennati nel libro sono rinviate a questo capitolo.
Mentre il materiale dei primi due blocchi dovrebbe in linea di massima reggere il  passaggio del tempo, è molto probabile che il materiale della terza sezione diventi supe- rato a causa dell'auspicabile sviluppo di nuovi e migliori strumenti. Siccome i linguaggi di programmazione sono uno strumento fondamentale dell'ingegnere del software, il Capitolo 9 serve da unione tra le problematiche della progettazione e il mondo dei lin- guaggi di programmazione.
Esercìzi
Il libro contiene tre tipi di esercizi.
• Esercizi brevi, con lo scopo di ampliare la conoscenza acquisita attraverso il libro o di applicare tale conoscenza in modo più specifico; questi esercizi sono distribuiti al- l'interno dei diversi capitoli.
• Esercizi più lunghi, alla fine del capitolo, che richiedono l'integrazione del materia- le presente nel capitolo.
• Progetti che richiedono lo sviluppo di software da parte di una piccola squadra.
 
Casi di studio
 Nel testo vengono utilizzati numerosi casi di studio per dimostrare l'integrazione di con- cetti differenti e per confrontare diversi approcci in situazioni realistiche. Inoltre, sono pro-  posti e analizzati tre casi di studio di progetti reali. Questi casi di studio possono essere letti ed analizzati in momenti diversi e con diversi scopi. Da questi casi di studio, lo stu- dente con scarsa esperienza può acquisire un'idea sintetica dei problemi che si incontra- no nello sviluppo industriale. Mentre quello che disponga già di competenze pratiche po- trà riconoscere certi aspetti e trarre arricchimento dall'altrui esperienza. Questi casi di stu- dio possono anche essere analizzati durante la lettura del libro. Numerosi esercizi del li-  bro si riferiscono a questi casi di studio.
Laboratorio
Molti corsi di ingegneria del software combinano lezioni tradizionali a progetti di labo- ratorio. E alquanto difficile svolgere tutte queste attività in un singolo semestre. Il docente si troverebbe a discutere problemi organizzativi mentre gli studenti sono concentrati sui  problemi giornalieri del debug. Crediamo che l'ingegneria del software debba essere inse- gnata, come tutte le altre discipline ingegneristiche, fornendo prima allo studente una so- lida base teorica. Solo dopo che questa è stata raggiunta, l'attività di laboratorio aumen- terà e potenzierà le conoscenze dello studente. Ciò implica che un progetto di laborato- rio debba partire più o meno a metà del semestre, invece che all'inizio. Dal nostro punto di vista, un approccio ancora migliore è quello di dedicare un semestre alla teoria e un al- tro al laboratorio. II manuale per i docenti propone numerose idee per organizzare un cor- so di laboratorio basato su questo libro.
Percorsi di lettura
Il libro può essere letto seguendo sequenze diverse e a vari livelli. I Capitoli dal 4 al 7 con- tengono materiale che può essere omesso durante una prima lettura o nei corsi di studio meno dettagliati. I Capitoli 1-3 sono necessari per un corretto inquadramento dei capi- toli seguenti. Il grafo illustra la dipendenza tra i capitoli e i vari percorsi di lettura del li-  bro. La notazione «P indica la lettura parziale del Capitolo  n; nC   ne indica invece la let- tura completa.
 
Ringraziamenti
Ringraziamo Reda A. Ammar, University of Connecticut; Larry C. Christensen, Brigham University; William R Decker, University of Iowa; David A. Gustafson, Kansas State University; Richard A. Kemmerer, University of California at Santa Barbara; John C. Knight, University of Virginia; Seymour V. Pollack, Washington University e K. C. Tai,
 North Carolina State University, per le revisioni delle bozze iniziali. Ringraziamo anche le seguenti presone che hanno fornito importanti feedback su va-
rie bozze del libro: Vincenzo Ambriola, Paola Bertaina, David Jacobson e Milon Mackey. Gli Hewlett-Packard Laboratories, Alfredo Scarfone, HP Italia e il Politecnico di
Milano hanno reso possibile la nascita di questo libro supportando un corso tenuto da Mehdi Jazayeri al Politecnico di Milano nella primavera del 1988. Vorremmo anche rin- graziare il supporto degli Hewlett-Packard Laboratories, in particolare John Wilkes, Dick Lampman, Bob Ritchie, Frank Carrubba a Palo Alto e Peter Porzer a Pisa. Ringraziamo anche Bart Sears per il suo aiuto su vari sistemi e John Wilkes per l'utilizzo del suo data-  base per la gestione dei riferimenti bibliografici. Ringraziamo infine per i contributi rice- vuti il Consiglio Nazionale delle Ricerche.
Carlo Ghezzi  Milano, Italia
Dino Mandrioli Pisa, Italia
Ingegneria del software: visione d'insieme
L'ingegneria del software è il settore dell'informatica che si occupa della creazione di siste- mi software talmente grandi o complessi da dover essere realizzati da una o più squadre di ingegneri. Di solito questi sistemi esistono in varie versioni e rimangono in servizio per pa- recchi anni. Durante la loro vita subiscono numerose modifiche: per eliminare difetti, per
 potenziare caratteristiche già esistenti, per implementarne nuove, per eliminare quelle ob- solete, o per essere adattati a funzionare in un nuovo ambiente.
Possiamo definire l'ingegneria del software come "l'applicazione dell'ingegneria al software". Più precisamente, l'IEEE Standard 610.12-1990  Glossario standard della termi- nologia dell'ingegneria del software (ANSI) definisce l'ingegneria del software come l'applica- zione di un approccio sistematico, disciplinato e quantificabile nello sviluppo, funzionamento e manutenzione del software.
Parnas [1978] ha definito l'ingegneria del software come la "creazione di software mul- tiversione da parte di più operatori". Questa definizione mette in risalto l'essenza dell'inge- gneria del software e sottolinea le differenze tra programmazione e ingegneria del software. Un programmatore scrive un programma completo, mentre un ingegnere del software scri- ve un componente software che sarà poi combinato con componenti scritti da altri inge- gneri del software per creare un sistema. Il componente scritto da un ingegnere del software  può essere modificato da altri ingegneri del software e potrà essere usato da altri per creare versioni diverse del sistema, anche se il suo creatore ha abbandonato il progetto da tempo. La programmazione è un'attività individuale mentre l'ingegneria del software è essenzialmente un'attività di gruppo.
 
Indubbiamente, l'ingegneria del software ha fatto progressi dagli anni Sessanta a oggi. Sono state create tecniche standard e, più che essere praticata come un qualcosa di artigia- nale, l'ingegneria del software ha acquisito una maggiore disciplina, cosa che è tradizional- mente associata con l'ingegneria. Nonostante ciò, le differenze con l'ingegneria tradiziona- le permangono. Nel disegnare un sistema elettrico, come ad esempio un amplificatore, l'in- gegnere elettronico può descrivere il sistema in modo preciso. Tutti i parametri e i livelli di tolleranza sono stabiliti chiaramente e sono compresi facilmente e in modo chiaro sia dal- l'ingegnere sia dal cliente. Nei sistemi software tali parametri rimangono ancora sconosciu- ti. Non sappiamo ancora quali parametri specificare e come specificarli.
 Nelle discipline ingegneristiche classiche, l'ingegnere ha strumenti e competenze mate- matiche per descrivere le caratteristiche del prodotto, separatamente da quelle del progetto. Per esempio, un ingegnere elettronico può fare affidamento sulle equazioni matematiche per veri- ficare che un progetto non violerà requisiti di alimentazione. Nell'ingegneria del software, ta- li strumenti matematici non sono ancora ben sviluppati e si sta tuttora discutendo sulla loro reale applicabilità. L'ingegnere del software si appoggia più sull'esperienza e sul suo giudizio
 personale che su tecniche matematiche. Viceversa, mentre esperienza e giudizio sono necessa- ri, anche strumenti di analisi formale sono essenziali nella pratica dell'ingegneria.
Questo libro presenta l'ingegneria del software come una disciplina ingegneristica, evi- denziando determinati principi che riteniamo essere essenziali alla "creazione di software mul- tiversione da parte di più persone". Questi principi sono molto più importanti di qualsiasi
 particolare notazione o metodologia per costruire software e permettono all'ingegnere del software di valutare differenti metodologie e usarle al momento opportuno. Il Capitolo 3 analizza i principi dell'ingegneria del software; quelli successivi mostrano invece la loro ap-  plicazione nei vari ambiti della disciplina.
In questo capitolo passiamo in rassegna l'evoluzione dell'ingegneria del software e le sue relazioni con altre discipline. Scopo di questo capitolo è offrire uno scorcio sul settore dell'ingegneria del software.
1.1 II ruolo dell' ingegneria del software nel progetto di un sistema
Un sistema sofware è spesso un componente di un sistema più vasto. L'ingegneria del software è quindi parte di un'attività di progettazione di sistema molto più vasta in cui i requisiti del software interagiscono con i requisiti di altre parti del sistema durante la progettazione. Ad esem-  pio, un sistema telefonico è composto da computer, telefoni, linee telefoniche e cavi, altri com-  ponenti hardware come i satelliti e infine da software che controlla i vari componenti. E la combinazione di tutti questi componenti che deve soddisfare i requisiti del sistema.
 
re il software come un componente di un più ampio sistema. Il software diviene sempre di  più la parte interna intelligente di vari sistemi, dalle televisioni agli aeroplani. Si parla, in tal caso, di software embedded. Avendo a che fare con tali sistemi, l'ingegnere del software deve rivolgere uno sguardo più ampio al problema più generale dell'ingegneria di sistema. Ciò ri- chiede che l'ingegnere del software partecipi allo sviluppo dei requisiti di tutto il sistema e che questi comprenda l'area applicativa prima di iniziare a pensare quali interfacce astratte debbano essere soddisfatte dal software. Ad esempio, se il dispositivo hardware che svolge funzione di interfaccia con l'utente ha capacità limitate per l'input di dati, nel sistema non risulterà necessario un word processor sofisticato.
Considerare l'ingegneria del software come parte dell'ingegneria dei sistemi ci fa rico- noscere l'importanza del compromesso, che è la caratteristica di ogni disciplina ingegneri- stica. Una classico compromesso concerne la scelta di ciò che deve essere trasformato in software e ciò che deve essere trasformato in hardware. L'implementazione in software offre maggiore flessibilità, mentre l'implementazione in hardware offre migliori prestazioni. Ad esempio, nel Capitolo 2 vedremo un esempio di macchina operante a gettoni che può esse- re costruita sia con varie fessure, ciascuna per un tipo diverso di gettone, sia con una sola fessura, lasciando al software il compito di riconoscere i diversi gettoni. Un compromesso ancora più di base implica la decisione su cosa debba essere automatizzato e cosa debba es- sere eseguito manualmente.
1.2 Breve storia dell'ingegneria del software
La nascita e l'evoluzione dell'ingegneria del software come disciplina nel campo dell'infor- matica risale alla maturazione dell'attività di programmazione. Agli albori dell'informatica, il problema principale della programmazione era come mettere insieme una sequenza di istru- zioni per fare in modo che il computer producesse qualcosa di utile. I problemi che veniva- no programmati erano ben compresi e conosciuti: ad esempio, come risolvere un'equazione differenziale. Il programma era scritto, ad esempio, da un fisico per risolvere un'equazione di proprio interesse e il problema era circoscritto tra il computer e l'utente-programmatore; nessun'altra persona era coinvolta.
Con la diminuzione dei prezzi dei computer e la loro diffusione, un numero sempre maggiore di persone iniziarono a utilizzarlo. I linguaggi di alto livello furono inventati nei tardi anni Cinquanta per rendere più facile comunicare con le macchine, ma nonostante ciò, l'attività di far eseguire al computer qualcosa di utile rimaneva sempre essenzialmente il com-  pito di una sola persona che doveva scrivere un opportuno programma per un ben deter- minato compito.
 
 Nei primi anni Sessanta i progetti di software complessi furono veramente pochi e quei  pochi furono intrapresi da pionieri del campo dell'ingegneria, che erano molto esperti. Ad esempio, il sistema operativo CTSS sviluppato al MIT fu un progetto vasto, sviluppato da individui estremamente motivati e competenti.
 Nella seconda parte degli anni Sessanta, vi furono tentativi di creare grandi sistemi di software commerciali. Di questi progetti, quello meglio documentato fu il sistema operati- vo OS 360 per la famiglia di computer IBM 360. Le persone che lavoravano in questi am-  biti presto si resero conto che costruire vasti sistemi di software era decisamente diverso ri- spetto a quelli più piccoli. Vi erano delle difficoltà profonde nel cercare di adattare le tec- niche di sviluppo di piccoli programmi allo sviluppo di grossi software. L'espressione "inge- gneria del software" fu coniata in questo specifico periodo e vennero tenute conferenze per discutere sui problemi che tali progetti incontravano nello sviluppare il prodotto promesso. I progetti di grossi software, generalmente, sforavano il budget prefissato ed erano in ritar- do rispetto al termine previsto. Un'altra locuzione coniata in quel periodo fu "crisi del software".
Si comprese che i problemi riscontrati nella creazione di grandi sistemi software non riguardavano la pura e semplice capacità di combinare tra loro le istruzioni del computer. Piuttosto, i problemi che dovevano essere risolti non erano ben compresi, almeno non da tutte le persone coinvolte nel progetto. Coloro che lavoravano sul progetto spendevano mol- to più tempo per comunicare tra di loro che per scrivere codice. Addirittura a volte alcune
 persone abbandonavano il progetto, influenzando così non solo il lavoro che avevano fatto, ma anche il lavoro di quanti facevano affidamento su di loro. Sostituire un individuo richiedeva il trasferimento orale dei requisiti del progetto e del modello del sistema. Ci si rese conto che ogni cambiamento dei requisiti del sistema originale influenzava numerose parti del pro- getto, ritardando inoltre la consegna del sistema. Questo tipo di problemi non esisteva ai tempi della "programmazione" e richiedeva quindi un nuovo tipo di approccio.
Vennero proposte e provate numerose soluzioni. Alcuni suggerirono un miglioramen- to delle tecniche di organizzazione e gestione dei progetti; altri proposero una diversa orga- nizzazione in squadre. Altri ancora sostennero che fossero necessari linguaggi di program- mazione e strumenti migliori; molti auspicarono l'adozione di standardizzazioni, come ad esempio convenzioni di codifica uniformi. Alcuni invocarono l'uso di un approccio forma- le e matematico. Di certo non mancavano le idee. Alla fine si raggiunse un accordo sul fat- to che il problema della costruzione di un software dovesse essere affrontato nello stesso mo- do adottato dagli ingegneri per costruire sistemi grandi e complessi come ponti, raffinerie, fabbriche, navi e aeroplani. Lo scopo era vedere il sistema software finale come un prodot- to complesso e la sua creazione come un lavoro ingegneristico. L'approccio ingegneristico ri- chiedeva management, organizzazione, strumenti, teorie, metodologie e tecniche. Nacque così l'ingegneria del software.
 
che o per l'economia - richiedono sforzo intellettuale, creatività e tempo. Brooks sostenne che non vi era alcuna soluzione magica, nessun "proiettile d'argento"1  per risolvere i pro-  blemi essenziali incontrati dagli ingegneri del software.
Il ragionamento di Brooks mostra le false supposizioni dietro alla locuzione "crisi del software", che venne ideata in quanto i progetti di software erano continuamente in ritardo e oltre il budget prestabilito. La conclusione fu che il problema era temporaneo e avrebbe  potuto essere risolto con strumenti e tecniche di management migliori. In realtà i progetti erano in ritardo perché l'applicazione era complessa e scarsamente compresa sia dai clienti che dagli sviluppatori e nessuno aveva alcuna idea di come stimare la difficoltà del lavoro e di quanto tempo ci sarebbe voluto per risolverlo. Nonostante l'espressione "crisi del software" sia talvolta ancora usata, è opinione generale che le difficoltà inerenti lo sviluppo di software non siano di breve periodo. Applicazioni nuove e complesse sono ardue da affrontare e non sono di rapida soluzione.
La storia mostra la crescita dell'ingegneria del software partendo dalla programmazio- ne. Alcune evoluzioni tecnologiche hanno giocato un ruolo importante nello sviluppo del- la disciplina. L'influenza maggiore è stata il cambio di equilibrio tra i costi dell'hardware e del software. Mentre un tempo il costo di un sistema computerizzato era determinato so-  prattutto dal costo dell'hardware, e il software era un fattore ininfluente, ora la componen- te software è di gran lunga quella dominante nel costo di un sistema. La diminuzione del costo dell'hardware e la crescita di quello del software ha sfavorito quest'ultimo, accentuan- do l'importanza economica dell'ingegneria del software.
Un altro orientamento evolutivo si è creato anche all'interno del campo stesso. Vi è stata una crescente enfatizzazione a vedere l'ingegneria del software come una disciplina che va ben oltre la pura attività di codifica. Al contrario, il software viene considerato un pro- dotto che ha un intero ciclo di vita, partendo della sua concezione, continuando attraverso la progettazione, lo sviluppo, la messa in funzione, la manutenzione e l'evoluzione. Lo spo- stamento dell'enfasi dalla codifica all'intero ciclo di vita del software ha favorito lo sviluppo di metodologie e di sofisticati strumenti a sostegno delle squadre coinvolte.
Per parecchie ragioni, possiamo quindi pensare che l'importanza dell'ingegneria del software continuerà ad aumentare. Una prima ragione è di tipo economico: le spese mon- diali per il software sono passate da 140 miliardi di dollari nel 1985 a 800 miliardi di dol- lari nel 2000. Solo questo basterebbe a dimostrare quanto l'ingegneria del software crescerà come disciplina. In secondo luogo, il software ormai permea la nostra società: sempre di più viene usato software per controllare funzioni critiche di varie macchine, come aeroplani e dispositivi medici, e per supportare funzioni di importanza critica per il mondo intero, co- me ad esempio il commercio elettronico. Questo fatto garantisce una crescente attenzione della società verso software affidabile, al punto da promulgare legislazioni su standard spe- cifici, requisiti e procedure di certificazione. Senza dubbio, imparare a creare software mi- gliore in modo migliore continuerà a essere fondamentale.
 
1.3 II ruolo dell' ingegnere del software
L'evoluzione dell'ingegneria del software ha portato a definire il ruolo professionale dell'in- gegnere del software, l'esperienza e la formazione richiesta. L'ingegnere del software deve, ov- viamente, essere un buon programmatore, molto versato in strutture dati e algoritmi ed esper- to in uno o più linguaggi di programmazione. Questi sono dei requisiti per la cosiddetta "pro- grammazione in piccolo", definita approssimativamente come la creazione di programmi che  possono essere scritti interamente da un unico individuo. Ma un ingegnere del software è coin- volto anche nella "programmazione in grande", che richiede molte più abilità.
L'ingegnere del software deve aver familiarità con più approcci di progetto, deve esse- re capace di tradurre richieste e desideri vaghi in precise specifiche, e anche di interagire con l'utente di un sistema nei termini dell'applicazione più che nel gergo tecnico degli informatici. Queste capacità richiedono a loro volta flessibilità e apertura mentale per comprendere e fa- miliarizzare con i fondamenti delle differenti aree applicative. L'ingegnere del software deve essere capace di muoversi attraverso diversi livelli di astrazione nei diversi stadi del proget- to, dalle procedure applicative e dai requisiti di una specifica applicazione, alle astrazioni per il sistema software, a uno specifico progetto del sistema fino al livello dettagliato della co- difica in un linguaggio di programmazione.
Come in molti altri campi dell'ingegneria, l'ingegnere del software deve sviluppare ca-  pacità che gli permettano di costruire una vasta varietà di modelli e di ragionare su questi per  poter operare scelte riguardo ai vari compromessi  (trade-off) che si incontrano nel processo di sviluppo del software. I modelli usati nella fase di definizione dei requisiti sono diversi da quel- li usati nella progettazione dell'architettura software, i quali a loro volta sono diversi da quelli usati nella fase di implementazione. In alcuni momenti, il modello può essere usato per ri- spondere a domande sia sul comportamento del sistema che sulle sue prestazioni.
L'ingegnere del software è anche un membro di un gruppo di lavoro e necessita quin- di di capacità comunicative e interpersonali. Deve inoltre essere in grado di coordinare il la- voro, sia il proprio sia quello di altri.
Come già detto in precedenza, un ingegnere del software ha molteplici responsabilità. Sovente, molte organizzazioni dividono le responsabilità tra vari specialisti con qualifiche dif- ferenti. Ad esempio, un analista di sistema ha la responsabilità di ricavare i requisiti, di in- teragire con il cliente e di comprendere l'area applicativa, mentre un analista di prestazioni ha la responsabilità di analizzare le prestazioni del sistema. A volte lo stesso ingegnere svol- ge ruoli differenti in momenti differenti del progetto o in progetti differenti.
1.4 II ciclo di vi ta del software
 
dei risultati parziali ("artefatti") che vengono trasferiti a una ben identificata fase sue- va. Raramente però nella realtà le cose sono così semplici. Un modello a cascata è com- o dalle seguenti fasi.
Analisi e specifica dei requisiti.  L'analisi dei requisiti è di solito la prima fase di un  progetto per lo sviluppo di un software di grandi dimensioni. Viene intrapresa dopo aver compiuto uno studio di fattibilità per definire in modo preciso i costi e i benefi- ci di un sistema software con lo scopo di identificare e documentare i requisiti del si- stema. Questo studio può essere compiuto dal cliente, dallo sviluppatore, da speciali- sti nell'analisi di mercato o da una qualsiasi combinazione di questi. Nei casi in cui i requisiti non siano chiari (per esempio, un nuovo sistema che non è mai stato prece- dentemente realizzato), è necessario che vi sia ampia interazione tra il cliente e lo svi- luppatore. In questa fase i requisiti dovrebbero essere scritti impiegando una termino- logia comprensibile dall'utente finale, ma molte volte non è cosi. Numerose metodo- logie di ingegneria del software ritengono che questa fase debba anche portare alla crea- zione di manuali per gli utenti e alla progettazione dei test di sistema che saranno ef- fettuati alla fine, prima della consegna del sistema.
Progettazione di sistema e sua specifica.  Una volta che i requisiti del sistema sono stati documentati, gli ingegneri del software progettano un sistema software che li sod- disfi. Questa fase è a volte divisa in due sottofasi: il progetto architetturale, o di alto li- vello, e il progetto dettagliato. Il progetto architetturale affronta l'organizzazione glo-  bale del sistema in termini di componenti di alto livello e delle loro interazioni. Man mano che ci si addentra in livelli di progettazione sempre più dettagliati, i vari com-  ponenti vengono scomposti in moduli di basso livello, con interfacce definite in mo- do accurato. Tutti i livelli di progettazione vengono indicati in un documento di spe- cifica che fornisce informazioni sulle decisioni di progettazione prese. La separazione della fase di analisi dei requisiti da quella di progettazione è un perfet- to esempio della fondamentale dicotomia tra "che cosa" e "come" che spesso incon- triamo nell'informatica. Il principio generale consiste nel fare una chiara distinzione tra che cosa è il problema e come si risolve tale problema. In questo caso, la fase di ana- lisi dei requisiti cerca di specificare qual è esattamente il problema. E per questo che diciamo che i requisiti dovrebbero essere specificati in base alle esigenze dell'utente fi- nale. Di solito vi sono numerosi modi di soddisfare i requisiti, a volte ricorrendo an- che a soluzioni manuali che non richiedono l'uso del computer. Lo scopo della fase di  progettazione è quella di giungere alla specifica di un particolare sistema software che soddisfi i requisiti dichiarati. Anche in questo caso, vi sono numerosi modi per creare il sistema specificato. Nella fase di codifica, che segue quella di progettazione, un pre- ciso sistema viene codificato per soddisfare le specifiche di sistema. Nel prosieguo del libro vedremo altri esempi della dicotomia del che "cosa/come".
 
manutenzione
Figura 1.1  Modello del cic lo di vita a cascata del software.
• Integrazione e test di sistema. Tutti i moduli sviluppati e testati singolarmente nella fa- se precedente vengono in questa assemblati, integrati, e testati come un unico sistema.
• Consegna e manutenzione.   Una volta che il sistema supera tutti i test, viene conse- gnato al cliente ed entra nella fase di manutenzione in cui vengono incorporate tutte le modifiche apportate al sistema dopo la prima consegna.
La Figura 1.1 offre una visione grafica del ciclo di vita dello sviluppo di un software e offre un chiarimento grafico del termine "cascata". Ciascuna fase crea risultati che "fluiscono" in quella seguente e idealmente il processo procede in modo ordinato e lineare.
Per come è stato qui presentato, questo modello offre una visione parziale e semplifi- cata del convenzionale ciclo di vita a cascata del software. Il processo può essere scomposto in un diverso insieme di fasi, con nomi diversi, diversi fini e una diversa granularità. Potrebbero anche essere proposti schemi di cicli di vita totalmente differenti, non basati strettamente su fasi sviluppate in cascata. Ad esempio, è ovvio che se un test dovesse scoprire i difetti del sistema, occorrerebbe tornare indietro almeno fino alla fase di codifica e forse anche a quel- la di progettazione per correggere gli errori. In generale, ogni fase potrebbe portare alla lu- ce problemi nelle fasi antecedenti, e quando ciò dovesse accadere sarebbe necessario torna- re indietro e rifare parte del lavoro già svolto. Ad esempio, se la fase di progettazione del si- stema scopre inconsistenze o ambiguità nei requisiti del sistema, si dovrà riesaminare la fa- se di analisi dei requisiti per determinare quali erano quelli che realmente si intendeva spe- cificare e quali quelli errati.
 
essere necessario perché le persone pronte a iniziare la fase successiva sono disponibili e non hanno altri lavori da fare. Un'altra ragione per sovrapporre le varie fasi può anche essere la riduzione del tempo di lancio del prodotto. Il termine usato per definire tale moderno pro- cesso organizzativo, che cerca di abbreviare il tempo di consegna dei prodotti introducendo del parallelismo nelle fasi di sviluppo di processi precedentemente sequenziali è  ingegneria concorrente.  Posporremo questa e altre questioni legate al ciclo di vita del software fino al Capitolo 7.
Molti libri sull'ingegneria del software sono organizzati seguendo il modello tradizio- nale del ciclo di vita del software, con paragrafi o capitoli incentrati solamente su una fase. Invece, questo libro è stato organizzato facendo riferimento a una serie di principi. Una vol- ta che tali principi vengono compresi e conosciuti a fondo, possono essere usati dall'inge- gnere del software in tutte le fasi di sviluppo del software, anche in modelli di ciclo di vita diversi da quelli basati su uno sviluppo in fasi, come si è detto prima. Infatti l'esperienza maturata e alcune ricerche hanno mostrato che vi è un'ampia varietà di modelli del ciclo di vita del software e che nessuno di essi è adatto a tutti i sistemi software. Nel Capitolo 7 esa- mineremo diversi modelli di ciclo di vita.
1.5 Rapporto tra l' ingegneria del software e altri campi dell'informatica
L'ingegneria del software, che è ormai diventata una disciplina a sé stante, è un settore im-  portante dell'informatica. Occorre notare che esistono numerosi rapporti sinergici tra que- sta e altri numerosi ambiti dell'informatica che influenzano e sono a loro volta influenzati dall'ingegneria del software. Affrontiamo ora alcuni casi.
1.5.1 Linguaggi di programmazione L'influenza dell'ingegneria del software sui linguaggi di programmazione è evidente. I lin- guaggi di programmazione sono tra gli strumenti principali impiegati nello sviluppo di software e di conseguenza hanno un profondo impatto sul corretto raggiungimento dei tra- guardi dell'ingegneria del software.
 
Un esempio è che i requisiti e il progetto debbano essere descritti in modo preciso, usando  possibilmente un linguaggio rigoroso ed elaborabile da una macchina come un linguaggio di programmazione. Un altro esempio è il fatto di trattare l'input in un sistema software co- me un programma codificato in una sorta di linguaggio di programmazione. I comandi che un utente può immettere in un sistema non sono una collezione casuale di caratteri, bensì formano un linguaggio usato per comunicare con il sistema. Progettare un linguaggio di in-  put appropriato fa parte della progettazione dell'interfaccia del sistema.
I vecchi sistemi operativi, come ad esempio OS 360, avevano un'interfaccia complica- ta e criptica - chiamata  linguaggio di controllo di lavoro  (JCL ,job control language)  - che era usata per dare ordini al sistema operativo. I successivi sistemi operativi  —   in particolare UNIX - introdussero i linguaggi a linea di comando, specificatamente ideati per program- mare il sistema operativo. L'approccio attraverso i linguaggi rese l'interfaccia molto più fa- cile da comprendere e utilizzare.
Una conseguenza del considerare l'interfaccia di sistemi software come un linguaggio di programmazione è che gli strumenti di sviluppo dei compilatori  —  che sono molto avan- zati - possono essere usati per lo sviluppo di software generico. Ad esempio, possiamo im-  piegare grammatiche per specificare la sintassi dell'interfaccia e generatori di analizzatori sin- tattici per individuare inconsistenze e ambiguità nell'interfaccia, e quindi generare automa- ticamente la "facciata" del sistema.
Le interfacce per utenti sono un caso interessante, perché in esse possiamo vedere un'in- fluenza nel senso opposto: le problematiche di ingegneria del software riguardo alle inter- facce utente grafiche hanno favorito lo studio di linguaggi di programmazione visuali. Questi linguaggi cercano di riprodurre la semantica delle finestre e dei paradigmi di interazione of- ferti dai dispositivi di visualizzazione grafica. Un'altra influenza del settore dei linguaggi di
 programmazione sull'ingegneria del software riguarda le tecniche implementative, sviluppa- te per anni per l'elaborazione dei linguaggi. Un approccio generativo all'ingegneria del software si basa sulla lezione appresa con i linguaggi di programmazione, che la formalizzazione por- ta all'automazione: creare una grammatica formale per un linguaggio permette di produrre automaticamente un analizzatore sintattico. Questa tecnica è ampiamente sfruttata in mol- te aree dell'ingegneria del software per la creazione di specifiche formali e la generazione au- tomatica di software.
1.5 .2 Sistemi operativi L'influenza dei sistemi operativi sull'ingegneria del software è notevole, soprattutto perché questi furono i primi sistemi di software di ragguardevoli dimensioni a essere realizzati, e quindi costituirono il primo esempio di software che richiedeva un lavoro di ingegnerizza- zione. Molte originarie idee di progettazione di software nacquero dai primi tentativi di rea- lizzazione dei sistemi operativi.
 
specifica dall'implementazione. L'idea dei livelli di astrazione è un altro modo di modula- rizzare il progetto di un sistema.
Esempi dell'influenza delle tecniche di ingegneria del software sulla struttura dei siste- mi operativi sono i sistemi operativi portabili e i sistemi operativi che sono strutturati in modo da contenere un piccolo micro-kernel "protetto", che provvede a fornire solo una mi- nima parte di funzionalità per interfacciarsi con l'hardware, mentre la maggior parte delle funzionalità usualmente associate ai sistemi operativi vengono fornite da una parte "non pro- tetta". Ad esempio, la parte non protetta potrebbe permettere all'utente di controllare lo sche- ma di gestione delle pagine di memoria, che è sempre stato tradizionalmente visto come par- te integrante del sistema operativo.
Allo stesso modo, nei primi sistemi operativi, l'interprete di comandi era parte inte- grante di essi. Oggi, invece, è considerato come qualsiasi altro programma  {utility),  il che  permette a ogni utente di avere una versione personalizzata dell'interprete. In molti sistemi UNIX ci sono almeno tre di questi interpreti.
1.5 .3 Basi di dati Le basi di dati rappresentano un'altra classe di sistemi software di grandi dimensioni il cui sviluppo ha influenzato l'ingegneria del software attraverso la scoperta di nuove tecniche di  progettazione. Probabilmente, l'influenza più importante è rappresentata dalla nozione di "indipendenza dei dati", che è ancora un ennesimo esempio di separazione della specifica dall'implementazione. Una base di dati permette di scrivere applicazioni che usano tali da- ti senza preoccuparsi della loro rappresentazione sottostante. Questa indipendenza fa in mo- do che la base di dati possa essere in qualche modo modificata —   ad esempio, per aumenta- re le prestazioni del sistema - senza che sia necessario cambiare anche le applicazioni che in- teragiscono con essa. Questo è un esempio dei benefici dell'astrazione e della separazione degli interessi (separation of  concerti), due principi fondamentali dell'ingegneria del software come vedremo nel Capitolo 3.
Un altro interessante influsso della tecnologia delle basi di dati sull'ingegneria del software è la possibilità di usare sistemi di basi di dati come componenti di sistemi software di gros- se dimensioni. Siccome le basi di dati hanno risolto molti dei problemi legati alla gestione degli accessi concorrenti da parte di più utenti a grandi quantità di informazioni, non c'è alcun bisogno di re-inventare quelle soluzioni quando stiamo creando un sistema software;  possiamo semplicemente usare un sistema esistente per la gestione di basi di dati come un componente.
Un'interessante influenza dell'ingegneria del software sulla tecnologia delle basi di da- ti ha le sue origini nei primi tentativi di usare le basi di dati per supportare gli ambienti di sviluppo del software. Questa esperienza mostrò che la tecnologia tradizionale delle basi di dati era incapace di trattare i problemi posti dai processi di ingegneria del software. Ad esem-  pio, un database tradizionale non è in grado di gestire in maniera ottimale le seguenti ri- chieste: memorizzare grossi oggetti non strutturati come programmi sorgente, manuali per utente o codice eseguibile; mantenere diverse versioni dello stesso oggetto; memorizzare og- getti, come un prodotto, con molti ampi campi, strutturati e non, come codice sorgente, codice oggetto e un manuale utente.
 
del software invece necessitano di transazioni molto lunghe: un ingegnere può richiedere un lavoro prolungato per ricostruire un sistema costituito da molti moduli o potrebbe prelevare dal database (check  out) un programma e lavorarci per settimane prima di riconsegnarlo (check in). Il problema per la base di dati è come trattare il blocco di codice durante quelle settima- ne. Se l'ingegnere del software volesse lavorare solo su una piccola parte del programma? Durante tale periodo è proibito l'accesso a tale programma a tutti i programmatori?
Queste richieste hanno stimolato progressi nell'area delle basi di dati che hanno portato a nuovi modelli di database e di transazioni o all'adattamento dei modelli preesistenti.
1.5.4 Intelligenza artif iciale L'intelligenza artificiale è un altro campo che ha esercitato un'influenza sull'ingegneria del software. Molti sistemi software creati nella comunità di ricerca dell'intelligenza artificiale sono sistemi complessi e di grosse dimensioni, ma sono sempre stati significativamente di- versi dagli altri. Molti di essi furono costruiti avendo solo una vaga idea di come il sistema avrebbe funzionato. Il termine "sviluppo esplorativo" è stato impiegato per il processo uti- lizzato per costruire questi sistemi.
Lo sviluppo esplorativo è l'opposto dell'ingegneria del software tradizionale, ove il pro- gettista svolge determinati passi per cercare di produrre un progetto completo prima di pro- cedere con la codifica. Con l'intelligenza artificiale sono nate nuove tecniche per gestire le specifiche, la verifica e l'analisi quando vi è un dato grado di incertezza. Altre tecniche por- tate dall'intelligenza artificiale includono l'uso della logica sia nella specifica di un software che nei linguaggi di programmazione.
Tecniche di ingegneria del software sono state usate nei sistemi di intelligenza artifi- ciale chiamati sistemi esperti. Questi sistemi sono modularizzati, con una chiara divisione tra i "fatti" conosciuti dal sistema e le "regole" usate dal sistema per elaborare tali fatti, ad esempio, una regola per decidere il corso di un'azione. Questa separazione ha permesso la creazione e la commercializzazione di shell  (letteralmente "gusci") di sistemi esperti che in- cludono solo regole. Un utente può applicare quindi la shell a un'applicazione di suo inte- resse fornendole fatti specifici dell'applicazione. L'idea è che la conoscenza riguardo l'appli- cazione sia fornita dall'utente, mentre i principi generali su come applicare tale conoscenza a un qualunque problema sia fornita dalla shell.
Alcuni ricercatori hanno provato a usare tecniche di intelligenza artificiale per perfe- zionare i compiti dell'ingegneria del software. Ad esempio, sono stati sviluppati "assistenti di programmazione" che svolgano funzione di consulenti per il programmatore, controllando frasi di programmazione idiomatiche o i requisiti del sistema.
Il problema di fornire interfacce agli utenti inesperti - ad esempio, attraverso l'uso del linguaggio naturale - fu affrontato inizialmente dall'intelligenza artificiale. Per tracciare il  profilo dell'utente furono utilizzati modelli cognitivi. Questi studi hanno influenzato l'area dell'ingegneria del software che si occupa dell'interfaccia utente.
 
del software. Protocolli di comunicazione e analizzatori di linguaggio utilizzano macchine a stati finiti come modelli di processo.
Sono stati impiegati anche gli automi a pila ( pushdoum automato), ad esempio, per spe- cifiche operazionali di sistemi e per costruire processori per tali specifiche. E interessante ri- marcare il fatto che gli automi a pila sono essi stessi scaturiti da tentativi pratici di creazio- ne di analizzatori sintattici e compilatori per linguaggi di programmazione.
Le reti di Petri, descritte nel Capitolo 5, sono un altro contributo dell'informatica teo- rica all'ingegneria del software: vennero inizialmente usate per creare modelli di sistemi hardware, ma furono sempre più utilizzate anche per modellare il software.
Infine, un ulteriore importante esempio è fornito dalla logica matematica, che è stata la base di molti linguaggi di specifica.
Allo stesso tempo, l'ingegneria del software ha influenzato l'informatica teorica. Specifiche algebriche e tipi di dati astratti sono nati per motivi di ingegneria del software. Inoltre nell'area delle specifiche, l'ingegneria del software ha focalizzato maggiore atten- zione su teorie logiche non del primo ordine, come ad esempio la logica temporale. I lo- gici matematici hanno sempre prestato molta più attenzione alle teorie di primo ordine che a quelle di ordini più elevati, perché le due sono equivalenti in potenza, ma le teorie di primo livello sono, da un punto di vista matematico, più essenziali. Esse però non so- no così espressive come le teorie di ordine più elevato. Un ingegnere del software, a di- spetto di un informatico teorico, è interessato sia alla potenza sia all'espressività di una teoria. Per esempio, la logica temporale assicura un stile più naturale e compatto per la specifica dei requisiti di un sistema concorrente rispetto alle teorie di primo ordine. Le necessità dell'ingegneria del software hanno quindi ispirato nuovi studi dei teorici verso tali teorie di ordine superiore.
1.6 Relazioni tra l'ingegneria del software e altre discipline
 Nelle sezioni precedenti abbiamo analizzato i rapporti tra ingegneria del software e gli altri campi dell'informatica. In questo paragrafo vedremo come l'ingegneria del software ha rap-  porti con altri campi al di fuori dell'informatica.
L'ingegneria del software non può essere praticata su una torre d'avorio. Vi sono mol- ti problemi non specifici dell'ingegneria del software che sono stati risolti da altri campi. Tali soluzioni possono essere adattate all'ingegneria del software. In questo modo non c'è biso- gno di reinventare ogni singola soluzione. Ad esempio, le scienze cognitive possono aiutar- ci a sviluppare interfacce utenti migliori e le teorie economiche ci supportano nella scelta tra diversi modelli dei processi di sviluppo.
 
Le scienze organizzative studiano esattamente questi problemi. Sono stati sviluppati mol- ti modelli gestionali che possono essere applicati all'ingegneria del software e, facendo ri- corso alle scienze organizzative, è possibile sfruttare i risultati di decenni di studi ed espe- rienze.
Allo stesso tempo l'ingegneria del software ha fornito alle scienze organizzative un nuo- vo dominio nel quale testare teorie e modelli organizzativi e gestionali. I modelli tradizio- nali adatti alla produzione per linea non sono applicabili ad attività incentrate sul lavoro uma- no quale l'ingegneria del software.
1.6 .2 Ingegneria dei sistemi L'ingegneria dei sistemi si occupa dello studio dei sistemi complessi. L'ipotesi sottostante è che certe leggi governino il comportamento di qualunque sistema complesso costituito da molti componenti con complicate interrelazioni. L'ingegneria dei sistemi è utile quando l'interesse dello studio è incentrato sul sistema piuttosto che sui suoi componenti. L'ingegneria dei siste- mi tenta di scoprire approcci comuni che si applicano a sistemi diversi come impianti chimi- ci, costruzioni di edifici e di ponti.
Il software è spesso un componente di un sistema molto più grande. Per esempio il software di gestione di una fabbrica o il software di controllo del volo di un aereo sono componenti di sistemi più complessi. Le tecniche dell'ingegneria dei sistemi possono essere applicate allo stu- dio di questi sistemi. Possiamo anche considerare un sistema software composto da migliaia di moduli come un sistema candidato per essere studiato con le leggi dell'ingegneria dei sistemi.
Allo stesso tempo l'ingegneria dei sistemi si è arricchita di un insieme crescente di mo- delli analitici, che tradizionalmente erano basati su metodi matematici classici, fino a includere modelli discreti che sono di uso comune nell'ingegneria del software.
1.7 Osservazioni conclusive
 
Note bibliografiche
La definizione di ingegneria del software citata all'inizio del capitolo è tratta da Parnas [1978]. La di- stinzione tra "programmare in piccolo" e "programmare in grande" e la constatazione che l'ingegne- ria del software conc erne la pro gra mma zio ne in gran de è di DeRe me r e Kron [1976 ].
Il termine "ingegneria del software" fu usato per la prima volta in una conferenza della NATO, tenutasi a Garmisch, Germania, nel 1968. Un rapporto su tale conferenza si trova in un libro pub-  bl icat o da Naur et al. [1 976].
Per la terminologia standard del campo, il lettore può far riferimento alla collezione degli standard  pubblic ata dall a IEEE [1999].
Boehm [1976] portò all'attenzione di tutti l'ingegneria del software e le sue sfide.
Le difficoltà pratiche incontrate nello sviluppo di prodotti software industriali sono trattate nel libro classico di Brooks,  The MythicalMan-Month  [1975, 1995]. Di Brooks [1987] è anche l'ormai classico articolo sul "proiettile d'argento". Boehm [1981, 1995] fornisce le fondamenta per modella- re e valutare i costi di un software.
Gli articoli di Parnas [1985] e Brooks [1987] contengono acute discussioni sulla natura del software e le difficoltà a esso inerenti. Un'opinione provocatoria è contenuta nel dibattito riportato in Denning [1989], che contiene un discorso tenuto da Dijkstra [1989] e confutazioni da parte di molti dei più importanti informatici.
Per un dibattito sulla relazione tra ingegneria del software e linguaggi di programmazione, si consulti Ghezzi e Jazayeri [1 998], che fornisce anche una visione globale dei linguaggi di prog ram- mazione, dei loro concetti e della loro evoluzione.
Molti lavori sui sistemi operativi hanno influenzato la progettazione del software; citiamo, in  part icolare, i lavori iniziali di Di jkstr a [1 968a e b , e 19 71] , Hoare [1 972 , 197 4, 19 85 ] e Br in ch Hansen [1977]. L'interazione tra sistemi operativi e ingegneria del software è discussa da Browne [1980],
Le basi di dati sono studiate da Ullman e Widom [1997] e Date [2000], Gli specifici requisiti delle basi di dati richiesti dall'ingegneria del software sono analizzati da Dittirch et al. [2000].
I rapporti tra ingegneria del software e intelligenza artificiale sono analizzati in vari articoli, e le opi nio ni sono spesso controverse. Ad esempio, Simon [1986] eT ic hy [1987] sosten gono che l'in- gegneria del software dovrebbe adottare i metodi e gli strumenti dell'intelligenza artificiale, mentre Parnas [1988] sostiene il contrario e fornisce una visione critica dell'intelligenza artificiale. Alcuni ap-  proc ci al sof tw are ba sa to sulla cono sc en za sono de sc ri tt i da Kant e Ba rs to w [1981], dal l 'e diz ione spe- ciale dell'IEEE Transactions on Software Engineering curato da Mostow (TSE [1985]), Goldberg [1986], e Rich e Waters [1988],
Una discussione dei rapporti tra informatica teorica e sviluppo di software può essere trovata in Mandrioli e Ghezzi [1987]
Boehm [2000] sottolinea l'importanza dei rapporti tra ingegneria del software e ingegneria dei sistemi. Spector e Gifford [1986] discutono delle relazioni tra ingegneria del software e un altro cam-  po de ll 'i nge gne ri a, il progetto di ponti .
 Neu mann [1 995] fo rn is ce un allarmante el en co di rischi per il pubblico, dovuti a softwa re di - fettosi, e solleva il fondamentale problema della responsabilità sociale di un ingegnere del software.
Bohem e Sullivan [2000] discute dell'importanza dell'economia nell'ingegneria del software.
 
Il software: natura e qualità
Obiettivo di ogni attività ingegneristica è costruire qualcosa, un artefatto' o un prodotto; così l'ingegnere civile costruisce un ponte, l'ingegnere aerospaziale un aereo, l'ingegnere elet- tronico un circuito. Il prodotto dell'ingegneria del software è un sistema software: questo non è tangibile alla pari degli altri, ma è comunque un manufatto in grado di rispondere a una specifica funzione d'uso.
La caratteristica che forse distingue maggiormente il software dagli altri prodotti è il fatto che sia "duttile": ossia, è possibile modificare il prodotto anziché modificare il proget- to in maniera molto facile e questo lo rende sostanzialmente diverso dagli altri prodotti, co- me le automobili o i forni.
Questa peculiarità del software è spesso male utilizzata. Quantunque sia possibile mo- dificare un ponte o un aereo per soddisfare nuove necessità (per esempio, adeguare il pon- te al crescente flusso di traffico o consentire a un aereo di trasportare più merci) questa mo- difica non viene mai intrapresa a cuor leggero, e certamente non viene tentata senza prima rielaborare il progetto e verificare l'impatto del cambiamento in maniera approfondita. Al contrario, agli ingegneri del software viene spesso richiesto di effettuare modifiche sostan- ziali. La duttilità del software porta a pensare che apportare modifiche sia banale, ma in pra- tica non è così.
È facile cambiare il codice attraverso un editore di testi, ma non è facile fare in mo- do che il software soddisfi i fabbisogni per i quali era richiesto un cambiamento. È bene dunque che il software sia trattato alla pari degli altri prodotti ingegneristici: una modi- fica nel software deve essere vista come un cambiamento nel progetto piuttosto che nel codice. Una proprietà come la duttilità può essere vantaggiosamente sfruttata, ma occor- re farlo con disciplina.
Un'altra caratteristica del software è che la sua creazione è  human intensive,  ossia ri- chiede un'elevata intensità di lavoro; richiede essenzialmente un'attività di "ingegneria" piut- tosto che di "fabbricazione". Nella maggior parte delle altre discipline, il processo di fab-
 
 bricazione determina il costo finale del prodotto; inoltre il processo di produzione deve es- sere gestito in maniera accurata, in modo che non vengano introdotti difetti indesiderati nel  prodotto. Le stesse considerazioni si applicano ai prodotti hardware, mentre invece per il software la fabbricazione si riduce a un banale processo di duplicazione. Il processo di pro- duzione del software consiste essenzialmente nel progetto e nell'implementazione, e non nel- la fabbricazione. Questo processo deve soddisfare opportuni criteri che assicurino la produ- zione di software di elevata qualità. E auspicabile che un prodotto soddisfi determinate ne- cessità e rispetti standard di accettazione che prescrivono le qualità che deve possedere. Ad esempio, la funzionalità di un ponte è quella di rendere facile il collegamento da un posto a un altro; una delle qualità attese è che questo non crolli in presenza di vento molto forte o quando è attraversato da una fila di camion.
 Nelle discipline dell'ingegneria tradizionale, l'ingegnere dispone di strumenti per descri- vere le qualità del prodotto in maniera distinta rispetto al progetto del prodotto stesso. Nel- l'ingegneria del software questa distinzione non è cosi chiara: le qualità di un prodotto software sono molte volte mescolate nelle specifiche, insieme alle qualità intrinseche del progetto.
In questo capitolo esamineremo le qualità rilevanti nei prodotti software e nei proces- si di produzione del software. Queste qualità diventeranno i nostri obiettivi da perseguire nella pratica dell'ingegneria del software. Nel capitolo successivo presenteremo i principi del- l'ingegneria del software applicabili per raggiungere questi obiettivi. E inoltre importante ve- rificare e misurare la presenza di qualità: questi argomenti sono introdotti nel Paragrafo 2.4 e approfonditi nel Capitolo 6.
2.1 Classi f icazione delle quali tà del software
Esistono molte qualità desiderabili per il software; alcune si applicano sia al prodotto che al  processo utilizzato per il suo sviluppo.
L'utente richiede che il prodotto software sia affidabile, efficiente e facile da usare. Il  produttore del software desidera che sia verificabile, manutenibile, portabile ed estendibile. Il manager di un progetto software desidera che il processo di sviluppo sia produttivo, pre- vedibile e facile da controllare.
In questo paragrafo analizzeremo due diverse classificazioni delle qualità relative al software: qualità interne e qualità esterne da un lato, e qualità di prodotto e qualità del pro- cesso dall'altro.
 
2.1 .2 Qual ità del processo e qualità del prodotto Per realizzare un prodotto software si utilizza un processo.  E possibile attribuire alcune qua- lità a un processo, anche se le qualità del processo sono spesso correlate con quelle del pro- dotto. Per esempio, l'affidabilità di un prodotto aumenta se il processo relativo richiede un'accurata pianificazione dei dati di test prima che sia effettuata un'attività di progettazio- ne e di sviluppo del sistema. Nell'affrontare le qualità del software è bene comunque cerca- re di distinguere tra qualità del processo e qualità del prodotto.
II termine prodotto di solito si riferisce a quanto viene alla fine consegnato al commit- tente. Quantunque questa sia una definizione accettabile dal punto di vista del committen- te, non è corretta per lo sviluppatore, in quanto questi, nel corso del processo di sviluppo,  produce una serie di prodotti intermedi. Il prodotto effettivamente visibile al committente consiste nel codice eseguibile e nei manuali utente, ma lo sviluppatore produce un numero elevato di altri artifatti, quali i documenti di specifica dei requisiti e di progetto, i dati di test e così via. Noi useremo il termine artefatto per denotare questi prodotti intermedi e per distinguerli dal prodotto finale consegnato al committente. Questi prodotti intermedi sono spesso soggetti agli stessi requisiti di qualità del prodotto finale. Poiché esistono molti pro- dotti intermedi, è possibile che diversi sottoinsiemi di questi vengano poi resi disponibili a diversi committenti.
Per esempio, un costruttore di computer potrebbe vendere a un'azienda produttrice di sistemi di controllo di processo il codice oggetto che deve essere installato nell'hardware specializzato di un'applicazione embedded; questa potrebbe poi distribuire il codice og- getto e i manuali utente ai rivenditori di software. Infine, potrebbe cedere il progetto e il codice sorgente ai produttori di software, i quali potrebbero modificarli per costruire al- tri prodotti.
L'attività di gestione delle configurazioni  (configuration  management ) costituisce quel- la parte del processo di produzione del software che affronta il problema di mantenere e con- trollare le relazioni tra tutti i diversi prodotti intermedi delle varie versioni di un prodotto. Gli strumenti di gestione delle configurazioni supportano la manutenzione di famiglie di
 prodotti e dei loro componenti e aiutano a controllare e a gestire i cambiamenti ai prodot- ti intermedi. Discuteremo l'attività di gestione della configurazione nel Capitolo 7.
2.2 Pr incipal i quali tà del software
In questa sezione presentiamo le più importanti qualità dei prodotti e dei processi software; ove appropriato, analizziamo una qualità con riferimento alle classificazioni che abbiamo de- scritto nel paragrafo precedente.
 
2.2.1.1 Correttezza
Un programma deve soddisfare la specifica dei suoi requisiti funzionali  ( functional require- ments specification)-, esistono tuttavia altri requisiti, quelli di prestazioni e di scalabilità, i qua- li non fanno riferimento alle funzionalità del sistema; questi sono chiamati requisiti non fun- zionali (nonfunctional requirements).  Un programma è funzionalmente corretto se si com-  porta secondo quanto stabilito dalle specifiche funzionali. Spesso si usa il termine "corret- to" invece di "funzionalmente corretto", e analogamente, in questo contesto si usa il termi- ne "specifiche" invece di "specifiche dei requisiti funzionali". Noi seguiremo questa con- venzione quando il contesto è chiaro.
La definizione di correttezza assume che le specifiche del sistema siano disponibili e che sia possibile determinare in maniera non ambigua se un programma soddisfi le specifi- che. Tali specifiche raramente sono disponibili per la maggior parte dei sistemi software esi- stenti. Se una specifica esiste, questa è normalmente scritta in linguaggio non formale usan- do il linguaggio naturale; pertanto è probabile che contenga ambiguità. Tuttavia la defini- zione di correttezza è utile perché cattura un obiettivo desiderabile dei sistemi software.
La correttezza è un proprietà matematica che stabilisce l'equivalenza tra il software e la sua specifica. Ovviamente, possiamo essere tanto più sistematici e precisi nel valutare la cor- rettezza quanto più rigorosi siamo stati nello specificare i requisiti funzionali. Come vedre- mo nel Capitolo 6, si può valutare la correttezza di un programma mediante vari metodi, alcuni basati su un approccio sperimentale (ad esempio il testing), altri basati su un approc- cio analitico, come le ispezioni del codice o la verifica formale della sua correttezza. La cor- rettezza può essere migliorata usando strumenti adeguati quali linguaggi di alto livello, in  particolare quelli che suppor tano un'analisi statica approfondi ta dei programmi. Analo- gamente, la correttezza può essere migliorata usando ben noti algoritmi standard o librerie di moduli standard, piuttosto che inventarne ogni volta di nuovi. Infine, la correttezza può essere migliorata utilizzando metodologie e processi di provata efficacia.
2.2.1.2 Affidabilità
Informalmente, il software è considerato affidabile nella misura in cui l'utente può fare af- fidamento sulle sue funzionali tà2. La letteratura specializzata definisce l'affidabilità in ter- mini statistici, ovvero come la probabilità che un software operi come atteso in un intervallo di tempo determinato. Approfondiremo questo approccio più avanti, per ora ci acconten- teremo invece di una definizione informale.
La correttezza è una qualità assoluta: una qualunque deviazione rispetto a quanto stabi- lito rende un sistema non corretto, indipendentemente dalla serietà delle conseguenze di tale deviazione. La nozione di affidabilità è invece relativa. Se la conseguenza di un errore software non è grave, un software non corretto può continuare a essere considerato affidabile.
È comune attendersi che i prodotti dell'ingegneria siano affidabili: quelli non affida-  bili di solito scompaiono velocemente dal mercato. Sfortunatamente i prodotti software non hanno raggiunto questo invidiabile stato, e vengono spesso rilasciati insieme a una lista di malfunzionamenti noti; gli utenti del software accettano come ineluttabile il fatto che la ver-
 
Figura 2.1  Relazione tra correttezza e affidabilità nel caso ideale.
sione 1 di un prodotto contenga errori (un prodotto del genere viene definito "bacato", in inglese  buggy).  Questo è uno dei sintomi più evidenti dell'immaturità dell'ingegneria del software rispetto agli altri campi dell'ingegneria3.
 Nelle discipline classiche, un prodotto non viene rilasciato se può generare malfun- zionamenti. Nessuno, infatti, accetterebbe di acquistare un automobile insieme a una lista di inconvenienti noti, o attraverserebbe un ponte che presenta un cartello di avvertimento sui pericoli del suo utilizzo. Gli errori di progettazione sono rari e qualora si manifestino vengono pubblicati sui giornali come fatti di cronaca. Il crollo di un ponte comporta inevi- tabilmente la denuncia dei progettisti.
Al contrario, gli errori di progettazione del software vengono spesso trattati come ine- vitabili e, quando troviamo errori in un'