Dr. Carlo Pescio
Il Design Architetturale

Pubblicato su Computer Programming No. 39


Iniziamo a parlare di design architetturale e dell'approccio object oriented alla progettazione dei sistemi.

Introduzione
Riprendiamo, dopo la pausa estiva, la nostra discussione sull'approccio object oriented allo sviluppo del software; da questa puntata, iniziermo a parlare di design, e vedremo come i risultati dell'analisi possano evolvere in un prodotto piu' dettagliato e preciso, che indichi come devono essere svolte le diverse attivita' del sistema. Ricordiamo infatti che compito dell'analisi e' definire cosa il sistema sia chiamato a fare, e compito del design e' stabilire come cio' debba essere realizzato.
Chi ha seguito sin dall'inizio questa serie di articoli, ricordera' che la prima puntata ha dedicato ben poco spazio agli aspetti specifici dell'object oriented, presentando invece una panoramica del processo di sviluppo; in questa puntata, sara' nuovamente necessario staccarsi per un momento dal singolo paradigma, al fine chiarire alcuni punti fondamentali del design architetturale. Non me ne vogliano i lettori "affamati di oggetti", poiche' affrontare temi di piu' ampio spettro consentira' a tutti di considerare l'approccio object oriented per cio' che e' realmente, ovvero un buon metodo per risolvere i problemi, non la panacea di tutti i mali.

Design Architetturale
Se consideriamo la realta' dei processi di sviluppo del software, non limitandoci quindi a discuture le regole auree della progettazione, ma osservando cio' che accade in casi concreti, vedremo che in progetti medio/piccoli, l'analisi tende ad essere poco piu' di una rapida raccolta dei requisiti: in pratica, ci si ferma al documento informale di specifica, e talvolta si individuano le classi principali, sostanzialmente "ad occhio". Come ben sappiamo, spesso poi il design si fonde con l'implementazione, risolvendo i problemi a mano a mano che si incontrano, spesso seguendo un cammino dominato dall'interfaccia utente, o dal flusso dei dati, piu' raramente dagli algoritmi di calcolo. Tutti (o quasi) sappiamo che non e' il modo migliore di procedere nello sviluppo, ma e' altrettanto vero che in piccoli progetti, con budget e tempi di conseguenza limitati, il risultato finale potra' essere comunque accettabile, in funzione ovviamente delle capacita' dello sviluppatore.
Su progetti piu' grandi, un simile metodo non funziona affatto; per quanto molti programmatori, cresciuti su piccoli progetti, siano restii ad accettarlo, lo sforzo necessario allo sviluppo non cresce in maniera lineare con la dimensione del progetto. Chi ha sviluppato programmi da 10.000 linee non puo' direttamente trasferire le sue tecniche di sviluppo ad un progetto da 500.000 linee di codice: la diversa dimensione richiede un approccio piu' sistematico e preciso. La convinzione diffusa di essere in grado di portare a termine un qualunque progetto e' peraltro tipica dell'ambiente software: difficilmente chi ha costruito una passerella su un torrente si sentirebbe autorizzato a progettare il nuovo Golden Gate, ma raramente un programmatore ritiene un progetto troppo ambizioso per le proprie capacita', almeno all'inizio; un ulteriore segno, nel caso servisse, dell'immaturita' dell'ingegneria del software, o perlomeno dello scarso assorbimento dei suoi messaggi.
Un componente fondamentale nei grandi progetti, indipendentemente dal metodo usato per lo sviluppo (analisi strutturata, metodi object oriented, metodo di Jackson, ecc) e' l'architettura. Mentre la passerella (il piccolo progetto) funzionera' a dovere una volta che i suoi elementi fondamentali siano stati costruiti ed incastrati insieme, un grande ponte deve necessariamente essere progettato alternando continuamente due o piu' livelli di astrazione: da una parte avremo "la visione globale", che consente di trattare problemi come le vibrazioni dell'intera struttura, o la distribuzione del carico globale, e cosi' via, includendo anche decisioni strategiche e gestionali. Dall'altra parte dovremo comunque prestare attenzione al singolo dettaglio, al bullone che non deve cedere sotto lo sforzo.
L'architettura del sistema, ovvero una visione ad alto livello delle componenti statiche e dinamiche fondamentali, rappresenta il tratto d'unione tra un vasto elenco di requisiti, frutto dell'analisi, ed un mare di particolari, di minuzie, frutto del design dettagliato. L'architettura guidera' le scelte strategiche a lungo termine, e definira' l'approccio globale del sistema alla soluzione dei problemi.
Un piccolo esempio potra' forse chiarire meglio il concetto di architettura del sistema: consideriamo un programma di elaborazione testi abbastanza sofisticato. Tale programma dovra' essere in grado di leggere e scrivere files in una varieta' di formati, oltre naturalmente a consentirne l'editing. Stabiliti i termini del problema, esistono molte soluzioni; chi di voi ricorda i programmi di parecchi anni fa, ricordera' anche le utility di corredo per la conversione di formato; in quel caso, il design architetturale aveva individuato due componenti, un programma di elaborazione testi con un unico formato di lettura e scrittura, ed uno o piu' programmi separati, in grado di effettuare la conversione dei dati. Programmi piu' moderni sono invece costruiti intorno ad una architettura differente, con moduli piu' piccoli e disaccoppiati: di norma, un componente di editing viene collegato a diversi filtri, in grado di leggere o scrivere un particolare formato; il collegamento tra componente di editing e filtri e' minimo, ed infatti puo' essere in molti casi modificato anche a run-time. Il componente di editing e' a sua volta suddiviso in componenti di alto livello. Ovviamente, la diversa architettura ha anche requisiti di hardware e software di base differenti, rispetto alla soluzione monolitica piu' datata: ecco quindi che considerazioni di tipo strategico e di management fanno la loro comparsa nel design architetturale.
Ritornando per un istante a considerare alcuni paradigmi di sviluppo del software, e' stato osservato come il difetto piu' frequente nei prodotti sviluppati con la tecnica dei prototipi, o con metodi RAD (Rapid Application Development) sia proprio la carenza di struttura, se analizzati ad un livello di astrazione piu' alto. Cio' non dovrebbe stupire piu' di tanto, considerando che nell'approccio a prototipi si finisce spesso per concentrare la propria attenzione su un elemento alla volta, rischiando facilmente di perdere di vista la "big picture", il sistema visto come insieme globale. Un simile rischio e' presente anche nello sviluppo troppo customer-oriented, ovvero troppo incline ad introdurre ogni caratteristica che i singoli utenti desiderano: persi in una marea di opzioni, si perdono di vista le scelte strategiche piu' opportune a lungo termine. La tentazione opposta, ovvero di porre troppa enfasi nel definire la struttura del sistema, arrivando si' ad una architettura estremamente modulare, estendibile, portabile ed elegante, ma con tempi di sviluppo abissali e talvolta con richieste di risorse poco rassicuranti, e' invece l'altra faccia della medaglia. Uno sguardo alle recenti vicissitudini nello sviluppo dei sistemi operativi potra' confermare la difficolta' di operare la scelta corretta, rimanendo in equilibrio tra due tentazioni molto forti.
Proprio per tali ragioni il design in generale, ed il design architetturale in particolare, possono certamente essere considerati come le fasi piu' complesse e critiche nello sviluppo del software. Affermazioni di questo tipo sono abbastanza impopolari, e tendono a far storgere il naso agli analisti, o ai programmatori -specialmente a coloro che si considerano "artisti"- poiche' sembrano sminuire l'importanza del loro lavoro. Vi e' comunque un buon fondamento alla base di tale convincimento: mentre l'analisi e la codifica richiedono, di norma, di operare ad un unico livello di astrazione, nella fase di design si devono continuamente considerare fattori di alto livello, vicini all'analisi, e fattori di basso livello, vicini all'implementazione. Non considerare i primi porterebbe direttamente ad una architettura limitativa (forse il termine piu' espressivo per descriverne il risultato e': "under-architectured"), mentre trascurare i secondi potrebbe facilmente portare a soluzioni difficili da implementare (un problema sentito non di rado dai programmatori, che talvolta devono rifare buona parte del lavoro svolto da progettisti inadeguati).
Purtroppo, molti programmatori e progettisti trovano difficile bilanciare costantemente considerazioni di livello architetturale e considerazioni di dettaglio quasi implementativo. Tuttavia, la capacita' di mantenere la visione globale del sistema, ed allo stesso tempo di concentrarsi sui dettagli, e' forse una delle caratteristiche che meglio identificato il buon progettista, e cio' vale anche per chi progetta l'architettura di un sistema - che dovrebbe essere affidata ai migliori tra i progettisti. Fondamentale e' anche la profonda capacita' critica ed autocritica: i design peggiori che ho incontrato, erano sempre frutto di persone magari brillanti, ma incapaci di identificare i difetti nei propri elaborati. Individuare con chiarezza i problemi ed i vantaggi di ogni soluzione e' uno dei fondamenti del design: nessuna soluzione e' esente da difetti; tuttavia, se li conosciamo possiamo valutarne la rilevanza rispetto ai nostri obiettivi. Una soluzione limitativa, ma con tempi di sviluppo brevi, puo' essere migliore o peggiore di una architettura totalmente aperta ma con richieste di tempi e costi ben piu' consistenti. In questo senso, occorre sempre dubitare di chi non sa, o non vuole, trovare zone d'ombra nella soluzione prospettata: vi e' una elevata probabilita' che non abbia considerato i lati negativi della proposta, o analizzato possibili alternative. Tra l'altro, anche se non pochi pensano che per ogni problema esista una sola soluzione, e' invece abbastanza ragionevole trovarsi in situazioni che consentono diversi risultati di design, tutti completi e consistenti, ognuno dei quali probabilmente sbilanciato verso una caratteristica che il progettista ha ritenuto particolarmente rilevante. Solo con un onesto confronto dei pro e dei contro delle diverse soluzioni si puo' operare la scelta corretta.
Chi desiderasse approfondire alcune delle tecniche di "pensiero creativo" che fanno parte del processo di design, puo' consultare [1], utilizzato all'universita' di Stanford nel corso di design, oppure [2], sempre valido seppure un po' datato, e che dedica una parte consistente della trattazione alla "scienza del design".

Il riuso: "design patterns"
Il design architetturale e' ovviamente piu' semplice da capire che da ideare partendo da zero; affermazione di per se' banale, ma nel campo del software si ha una tendenza quasi spasmodica a reinventare la ruota. Nuovamente, cio' non accade in molti altri settori, dall'architettura all'ingegneria meccanica, dove il riutilizzo di elementi di design e' pratica comune e consolidata. Come avevo accennato nella seconda puntata della serie, alla quale rimando anche per alcuni cenni bibliografici, una tendenza relativamente nuova nel campo del software e' di cercare di identificare, catalogare e distribuire una serie di strutture o scelte architetturali che si sono dimostrate "vincenti" in numerosi contesti applicativi. Tali strutture vengono definite "design patterns", seguendo la terminologia introdotta da Cristopher Alexander, che negli anni 70 ha cominciato a sperimentare l'uso di un linguaggio per esprimere i pattern ricorrenti nell'architettura (degli edifici, non del software!). L'idea di base del riuso e' sempre la stessa: nel contesto del design, significa cercare tra un catalogo di pattern di provata efficacia la soluzione per un problema, o sottoproblema, simile ai nostri, ed adattare tale schema al nostro caso concreto. Alcuni pattern molto interessanti, ad esempio su sistemi distribuiti e sull'I/O sincrono/asincrono, possono essere trovati in [4], che costituisce comunque un'interessante lettura per ogni progettista.
Ovviamente, non dobbiamo limitarci al ruolo di consumatori nel gioco del riuso: se abbiamo applicato con successo una strategia di attacco per una categoria di problemi, potrebbe essere interessante condensare tale esperienza in un sintetico pattern di design, a beneficio dell'organizzazione o del team di sviluppo; in senso piu' esteso, il "design per il riuso", ovvero la definizione dei particolari del design architetturale con un'attenzione particolare alla creazione di pattern flessibili, ma ben definiti, per la soluzione dei problemi, puo' essere una impostazione molto vantaggiosa, se le risorse e la politica dell'ambiente di lavoro la consentono.

Una buona architettura
Scendiamo ora in dettagli piu' tecnici, ed analizziamo le qualita' che caratterizzano una "buona architettura". In generale, potremmo dire che una buona architettura e' allo stesso tempo semplice da capire, da estendere, da implementare, da riutilizzare, e cattura l'essenza statica e dinamica del sistema: ognuna di queste proprieta' gioca un ruolo essenziale, che distingue una architettura elegante da una approssimativa. Ovviamente, il termine "semplicita'" va inteso come "assenza di complessita' artificiosa": l'architettura di un sistema operativo moderno non sara' mai "semplice" in assoluto e tantomeno la sua implementazione; tuttavia vi e' una linea abbastanza netta tra la difficolta' intrinseca del problema e le complicazioni introdotte dallo "sviluppo selvaggio". Tornando al semplice esempio del programma di elaborazione testi, una possibile soluzione artificiosa potrebbe essere quella di avere un interprete centralizzato, in grado di riconoscere un sopra-insieme dei vari formati. Oltre a complicare in modo terribile la realizzazione, un simile approccio costituirebbe l'incubo del team di manutenzione ed estensione. Ciononostante, ho conosciuto sviluppatori che la considerano come "soluzione ideale".
Riprendiamo ora le singole qualita' di una buona architettura: la "semplicita' di comprensione", che potremmo meglio definire "maneggevolezza intellettuale", e' un elemento fondamentale poiche' rendera' piu' agevoli i continui spostamenti dell'attenzione dal particolare al generale. Quando ci si rende conto che la struttura interna di un sistema e' tale per cui ad ogni modifica, aggiunta, variazione dei requisiti, e' necessario riconsiderare una moltitudine di fattori, l'architettura del sistema manca di maneggevolezza intellettuale. Tipicamente, una rappresentazione ad alto livello della struttura statica del sistema dovrebbe rispettare le regole del "magico numero 7" viste in precedenza, e cosi' anche la struttura dinamica (sulla quale torneremo diffusamente in seguito).
La semplicita' di estensione e' uno degli indici primari dell'esistenza di una vera e propria architettura di sistema, che non deve essere composto di moduli che "accidentalmente" operano di concerto.Ritornando all'esempio degli elaboratori di testi, mentre entrambe le soluzioni, al livello di dettaglio dato, sono intellettualmente maneggevoli, la soluzione basata su filtri dinamici e' intrinsecamente piu' flessibile e semplice da estendere rispetto alla soluzione del "programma di import/export monolitico".
La semplicita' di implementazione deriva dalla completezza del design e dall'attenzione posta in tale fase, rispetto ai vincoli di prestazioni, ambiente, e piattaforma target. Un design architetturale che richieda implicitamente la presenza di un database ad oggetti sara' tutt'altro che semplice da implementare su un microcontroller per applicazioni embedded; d'altro canto, un design che imponga vincoli di timing estremamente rigorosi sara' piuttosto complesso da implementare su un sistema con multitasking cooperativo. Chi ritiene che un buon design sia completamente indipendente dalla piattaforma e dal sistema, corre seriamente il rischio di essere odiato dai programmatori, e di vedere il suo lavoro completamente stravolto nella fase di codifica.
La possibilita' di riutilizzo, oltre ad essere uno degli elementi di maggiore interesse economico, e' anche un chiaro indice della generalita' delle scelte compiute, che non sono state ritagliate intorno ad un problema specifico, ma che tengono in considerazione una classe piu' astratta di esigenze. Tornando per l'ennesima volta all'esempio dell'elaboratore di testi, la soluzione dei filtri dinamici e' intrinsecamente piu' riutilizzabile, poiche' piu' generale, di una soluzione che preveda la lettura e la scrittura di un numero fisso di formati "di cui l'utente ha bisogno subito". Gli stessi filtri, se progettati adeguatamente, potrebbero ad esempio essere riutilizzati per importare testo in un foglio elettronico, o in un programma di impaginazione o di grafica.
Maggiori dettagli sull'aspetto architetturale del design possono essere trovati in [5] e [6].

Verso la definizione dell'architettura
Al termine della fase di analisi, abbiamo identificato un certo numero di classi, relazioni, ed eventi tipici del sistema; ci si potrebbe chiedere se tale struttura non identifichi immediatamente l'architettura del sistema stesso, proprio perche' ne cattura gli elementi essenziali. Cio' sarebbe auspicabile, e di fatto costituirebbe un enorme punto a favore dell'approccio object oriented, ma purtroppo in genere non corrisponde a verita'. Se il sistema e' relativamente semplice, come nel caso degli esempi necessariamente ridotti che si trovano in libri ed articoli, si ha in effetti una stretta corrispondenza tra il risultato dell'analisi e l'architettura del sistema; non appena si esce dai confini ridotti della divulgazione, tuttavia, la complessita' dei sistemi richiede metodi di attacco piu' completi.
Esistono fondamentalmente quattro fattori che dovremo bilanciare nel definire l'architettura del sistema:

  1. La piattaforma (o le piattaforme) che dovranno ospitare il sistema. Questo include l'architettura hardware, almeno negli aspetti piu' rilevanti, come la distinzione tra singolo processore o multiprocessore, ed in tal caso tra SIMD, MIMD, architetture sistoliche, eccetera. Il lato hardware si estende inoltre a tutte le periferiche che dovranno essere controllate dal sistema, aspetto particolamente importante (ad esempio) in software di controllo industriale. La piattaforma comprende inoltre il sistema operativo, gli eventuali gestori di basi dati preesistenti con i quali e' necessario interfacciarsi, eventuali sistemi GUI per i quali il sistema dovra' essere disponibile.
  2. La struttura statica. Questa parte sara' in effetti largamente basata sul risultato dell'analisi, ed identifica le componenti statiche del problema, ovvero le astrazioni di piu' alto livello. Come vedremo, il punto di partenza per definire la parte statica dell'architettura saranno proprio le "categorie di classi" o "i soggetti" che dir si voglia, ovvero insiemi di classi omogenei e coesivi, e debolmente accoppiati con il resto del sistema.
  3. La struttura dinamica. Questa parte, per la cui definizione sara' fondamentale ma non sufficiente il risultato dell'analisi, identifica le componenti attive del sistema, il comportamento (behaviour) del sistema stesso, la concorrenza interna, le interazioni con il mondo esterno. La struttura dinamica puo' essere molto semplice in sistemi mono-task, ad esempio un programma di data-entry, ma puo' arrivare a livelli di complessita' enormi in sistemi dinamici e distribuiti.
  4. Una pianificazione di consegna. Troppo spesso nella trattazione teorica dello sviluppo si dimenticano le esigenze contingenti, come la realizzazione di prodotti semi-funzionanti a scopo dimostrativo o di veri e propri sotto-sistemi completamente operanti. Tali vincoli sono invece fondamentali per la definizione di una architettura adeguata per il sistema da realizzare: se e' necessario avere una versione intermedia che possa colloquiare con una base dati esistente, partire con una architettura ambiziosa totalmente basata su oggetti persistenti puo' portare a problemi piuttosto difficili da risolvere e ad imbarazzanti ritardi di consegna. La realizzazione di sistemi complessi include un buon processo di pianificazione, che influisce sulle componenti tecniche del progetto: puo' non piacere, ma e' vero.
La scelta della piattaforma andrebbe eseguita piuttosto rapidamente; anche se cio' puo' sembrare limitativo, in quanto future scelte architetturali potrebbero suggerire piattaforme alternative, in pratica la scelta non di rado e' abbastanza semplice. Spesso, infatti, la scelta di una piattaforma e' motivata piu' da ragioni economiche o strategiche che non tecniche: talvolta un sistema operativo poco diffuso o sperimentale potrebbe forse essere la piattaforma ideale per la nostra applicazione, ma se vogliamo vendere il prodotto dobbiamo orientarci verso uno standard di mercato. Oppure, la scelta di una particolare architettura hardware e' motivata da precedenti esperienze interne alla compagnia, o dalla richiesta del committente. In generale, dove vi sia liberta' di scelta per la piattaforma hardware/software, le motivazioni di ordine tecnico da considerare sono molte e richiedono uno spazio di approfondimento che purtroppo esula dallo spettro di questa rubrica, che dovrebbe comunque occuparsi di object technology. E' comunque evidente che scelte strategiche di questo livello vanno effettuate da figure adeguatamente preparate: e' difficile scegliere una piattaforma SIMD se non si sa cosa sia una architettura Single-Instruction-Multiple-Data-stream.
La pianificazione di consegna e' nuovamente un fattore extra-tecnico, anche se un management illuminato dovrebbe sempre tenere in considerazione gli aspetti tecnici di alto livello, durante la stesura degli schedule per il design e l'implementazione. Nuovamente, di rado esiste una grande liberta' di scelta: trascurando le situazioni del tipo "tutto e subito", sintomo caratteristico di un approccio errato alla pianificazione dei progetti (nel qual caso consiglio la lettura di [7] e del piu' moderno, anche se piu' approssimativo [8]), esistono priorita' ben definite che devono essere rispettate da un punto di vista contrattuale. Far combaciare tali esigenze con la definizione architetturale del sistema non sempre e' semplice o possibile (non a caso i ritardi di consegna non stupiscono piu' di tanto nel mondo del software), ed e' realmente necessario che i progettisti interagiscano e cooperino con il project manager (e viceversa) alla stesura di un piano realistico che non imponga scelte architetturali troppo limitative.
La definizione della struttura statica e della struttura dinamica costituiscono invece il nucleo tecnico del design architetturale, e come tali sono le piu' interessanti dal punto di vista della rubrica. Vedremo di seguito quali sono le loro componenti essenziali, che verranno approfondite nelle prossime puntate.

Elementi essenziali dell'architettura object oriented
Il design architetturale object oriented contempla di norma quattro elementi, che verranno modellati secondo i principi di astrazione del paradigma ad oggetti (classi, attributi, metodi, strutture tutto/parti e generalizzazione/specializzazione, e soggetti o categorie di classi); tali elementi possono essere identificati come:

  1. Dominio del problema
  2. Interfaccia utente
  3. Gestione dei task
  4. Gestione dei dati
Vediamo rapidamente di cosa si tratta:
Il componente di dominio del problema e' un elemento essenziale nel design, e proviene dalla fase di analisi; mantenere la visibilita' del dominio del problema in fase di design garantisce che la struttura organizzativa del sistema progettato ricalchi la struttura organizzativa del sistema che e' stato richiesto di realizzare. Garantisce inoltre la stabilita' del design, poiche' propaga all'interno dell'architettura decisioni provenienti da un piu' alto livello di astrazione.
L'interfaccia utente e' un componente essenziale in quasi ogni sistema informatico; la sua definizione e' solo parzialmente toccata dalla fase di analisi, che si concentrandosi su cosa il sistema debba fare non modella adeguatamente come l'interazione uomo-macchina debba avvenire. Talvolta, in applicazioni che hanno una parte di interfaccia preponderante, l'intero design viene centrato sull'interfaccia utente, utilizzando eventualmente strumenti di prototipazione rapida. Tale soluzione e' adeguata per progetti di entita' medio-piccola, ma tende a generare una architettura troppo disorganizzata in progetti piu' grandi. Pertanto, tratteremo l'interfaccia uomo-macchina come uno dei punti fondamentali, ma non come la base della progettazione.
La gestione dei task e' intimamente connessa con la struttura dinamica: in ogni sistema, esistono uno o piu' task che vengono attivati da azioni esterne (inclusa l'interazione con l'utente), o da un clock di sistema, task che hanno una priorita' e che vengono gestiti e schedulati da uno o piu' coordinatori. Il legame tra la struttura statica delle classi con la attivazione dinamica dei task, lo studio dei parallelismi e della concorrenza, la definizione di opportuni protocolli di comunicazione, e cosi' via, fanno parte della progettazione dell'architettura dinamica del sistema.
La gestione dei dati ricalca invece piu' fedelmente la struttura statica delle classi, quando sia richiesta la persistenza degli oggetti creati su memoria di massa. In questo caso, esistono supporti sia teorici che pragmatici molto validi, provenienti da anni di studi ed esperienze nel campo dei database (come i criteri di normalizzazione), che possono essere opportunamente utilizzati anche nella progettazione orientata agli oggetti.
Ogni componente influira' in modo consistente sulla struttura finale del sistema, e ad ognuno di essi dedicheremo uno spazio di approfondimento nei prossimi articoli.

Reader's Map
Molti visitatori che hanno letto
questo articolo hanno letto anche:

Bibliografia
[1] James Adams: "Conceptual Blockbusting: A Guide to Better Ideas, 2nd edition", Norton press, 1980.
[2] Herbert Simon: "The Science of Artificial", MIT Press, 1969.
[3] Mike Tudball: "Architecture-Driven Development", Objects In Europe, Vol 2 No 1, 1995.
[4] Coplien, Schmidt: "Pattern Languages of Program Design", Addison-Wesley, 1995.
[5] Lawrence Peters: "Handbook of Software Design: Methods and Techniques", Yourdon Press, 1981.
[6] Michael Jackson: "Principles of Program Design", Academic Press, 1975.
[7] Frederick Brooks: "The Mythical Man-Month", Addison-Wesley, 1975.
[8] Steve Maguire: "Debugging the Development Process", Microsoft Press, 1994.
[9] Parnas, Clements: "A Rational Design Process: How and Why to Fake it", IEEE Transactions on Software Engineering, Febbraio 1986.

Biografia
Carlo Pescio (pescio@acm.org) svolge attività di consulenza in ambito internazionale nel campo delle tecnologie Object Oriented. Ha svolto la funzione di Software Architect in grandi progetti per importanti aziende europee e statunitensi. È incaricato della valutazione dei progetti dal Direttorato Generale della Comunità Europea come Esperto nei settori di Telematica e Biomedicina. È laureato in Scienze dell'Informazione ed è membro dell'ACM, dell'IEEE e della New York Academy of Sciences.