|
Dr. Carlo Pescio Object Oriented Analysis |
Pubblicato su Computer Programming No. 35
Introduzione
Nella scorsa puntata, abbiamo introdotto i concetti di analisi
dei requisiti, design architetturale, design dettagliato, implementazione,
testing e manutenzione del codice. Da questa puntata, inizieremo
a considerare i dettagli dell'analisi dei requisiti, ed entreremo
nel merito dell'approccio object oriented all'analisi dei sistemi.
Come abbiamo visto, l'analisi si concentra su cosa il sistema
debba fare, non su come debba farlo; Il come e'
dominio del design. Rimanendo sempre a livello di "slogan",
occorre modellare il problema, non la soluzione.
Cio' e' tutt'altro che semplice, in quanto una delle tecniche
tipiche dell'uomo per affrontare la complessita' dei sistemi consiste
nel risolvere alcuni problemi, confidando che il compito diventi
gradatamente piu' semplice. In un certo senso, questo e' il principio
di base del divide et impera, ma puo' nondimeno essere
fuorviante nell'analisi di grandi sistemi, ove occorre sempre
considerare le soluzioni dopo aver compreso, se possible,
l'intero problema.
Gestire la complessita'
Uno dei cardini dell'ingegneria del software e' lo studio di tecniche
per ridurre la complessita' intrinseca dei sistemi; cio' richiede
non solo l'adozione di appropriate metodologie di sviluppo, ma
anche la corretta forma mentale [1]: raramente gli hacker, per
quanto brillanti, sono destinati a sfolgoranti carriere nello
sviluppo di sistemi complessi. Un professionista sa bene che i
sistemi sono complessi ed adotta ogni metodo di comprovata efficiacia
per ricondurre la complessita' del sistema all'interno dei limiti
efficacemente trattabili dagli esseri umani: se non altro, qualora
si ritenga eccezionalmente capace, perche' altre persone possano
accedere ai risultati del suo lavoro.
Ogni metodo di analisi e design proposto nel corso degli anni
utilizza alcune tecniche di base per ridurre la complessita' del
sistema a livelli piu' trattabili. L'astrazione sui dati e sulle
funzioni e' una di tali tecniche: anziche' concentrarsi sull'intero
sistema, si individuano gli elementi fondamentali e le loro relazioni,
si modella un sistema piu' astratto, e poi si scende nel dettaglio
dei singoli sottosistemi.
Alcuni metodi di analisi e design assumono poi prospettive diverse:
in genere, alcuni si concentrano sui dati (intesi come struttura,
ad esempio il modello entita'-relazione) o sulle funzioni (l'approccio
strutturato). l difetti (che e' forse meglio definire limiti)
di tali metodi, che restano comunque validi e che possono vantare,
in alcuni casi, una visione formale che manca al modello object
oriented, sono sostanzialmente due:
- non forniscono una visione globale del sistema, in quanto analizzano
dati e funzioni in modo distinto o parziale.
- non sono omogenei nel passaggio da analisi a design ad implementazione.
L'approccio object oriented, i cui principi di base sono qui riassunti
nella cornice "classi e oggetti", incapsula dati e funzioni
in un'unica struttura (l'oggetto), permettendo quindi una visione
piu' completa del ruolo dei dati e delle funzioni, ed ha inoltre
il vantaggio di utilizzare le stesse tecniche di astrazione nei
passi di analisi, design, ed implementazione, che pertanto possono
essere visti come raffinamenti successivi di un unico processo.
Questo riduce gli errori dovuti all'errata interpretazione dei
documenti di analisi durante il design, o del design durante l'implementazione,
e rende piu' semplice la previsione dell'impatto che modifiche
a livello di requisiti o di design potranno avere in fase di manutenzione.
Inoltre, tende a ridimensionare un problema ben noto, ovvero "la
sindrome di incompetenza apparente": nell'uso delle tecniche
strutturate, ad esempio, accade spesso che i programmatori giudichino
i progettisti e gli analisti incompetenti, e viceversa. Cio' e'
in gran parte motivato dal fatto che l'analisi tende ad essere
cosi' distante dall'implementazione che le richieste nei due sensi
sono viziate da una grande incomprensione di fondo. In molti casi,
la comunicazione tra i vari livelli e' piu' semplice se si utilizzano
le metodologie object oriented, poiche' le diverse figure professionali
parlano un linguaggio comune, anche se si concentrano su aspetti
diversi ed hanno attitudini diverse (un bravissimo programmatore
con scarse attitudini per le pubbliche relazioni avra' comunque
problemi nel ruolo di analista).
Altra caratteristica fondamentale dell'approccio orientato agli
oggetti, se confrontato ad esempio con la progettazione secondo
il metodo data-flow od il metodo di Jackson [2] e' la mancanza
di sequenzialita'. In particolare, il metodo data-flow e' strettamente
legato all'idea di una trasformazione sequenziale dei dati; tuttavia,
le modalita' operative, e quindi le sequenze di operazioni eseguite,
sono uno dei punti piu' frequentemente soggetti a modifiche durante
la vita del sistema. Cio' rappresenta un punto debole dei metodi
citati, in quanto l'analisi stessa tende a modificarsi in modo
anche radicale quando le modalita' operative cambiano; questo
si riflette negativamente sul design e sull'implementazione.
Nell'approccio object-oriented, invece, l'idea stessa di sequenzialita'
e' in larga misura assente: un oggetto ha un suo stato interno
e delle funzioni che operano su di esso. In principio, non vi
e' nessuna regola che dica "la funzione 'a' deve essere chiamata
prima della funzione 'b'"; se vi trovate in casi simili,
probabilmente vi e' un errore nel vostro modello. Da notare che,
a livello di design e di implementazione, operazioni impossibili
da compiere quando l'oggetto e' in un determinato stato (il pop
di un elemento da uno stack vuoto) verranno gestite con
asserzioni ed eccezioni, ma in generale non vi sono dipendenze
temporali tra le funzioni proprie di un oggetto. La mancanza di
sequenzialita' intrinseca sembra molto promettente per la programmazione
parallela e concorrente [3].
Il riutilizzo del software inizia dall'analisi
Molti testi che trattano l'analisi ed il design secondo un particolare
approccio (data flow, strutturata, object oriented, eccetera)
hanno la sfortunata tendenza a considerare l'analisi come un evento
unico nella storia dei sistemi. In realta', sistemi tra loro simili
vengono continuamente costruiti e migliorati: il riutilizzo, tanto
popolare di questi tempi, dovrebbe cominciare dalla fasi di analisi
e di design.
Supponiamo che vi venga commissionato un sistema per l'analisi
dei dati in tempo reale; dopo le necessarie discussioni con il
cliente, e' molto saggio non gettarsi immediatamente a modellare
il sistema, ma analizzare se possibile alcuni prodotti simili
e cercare di ricostruire i requisiti che hanno portato alla costruzione
di un simile sistema (una forma di reverse-engineering molto blanda).
In questo modo, potremmo giungere a conclusioni sorprendenti circa
la completezza dei dati che abbiamo raccolto dalle nostre discussioni
con il committente, e avremo modo di considerare, durante la fase
di modellazione vera e propria, anche il "punto di vista"
di altri prodotti.
Altro scenario tipico di riutilizzo e' lo sviluppo di un sistema
simile ad uno precedentemente realizzato: tale evento e' abbastanza
comune per gli esperti di un particolare settore. In realta',
gli esperti sono piu' produttivi e ottengono in genere risultati
migliori nel loro campo di competenza, proprio perche', in modo
piu' o meno cosciente, riutilizzano conoscenze, strutture, modelli
tra i vari progetti. Il riuso del codice stesso e' invece spesso
impedito da clausole contrattuali.
Queste semplici norme di buon senso hanno portato anche allo sviluppo
di alcuni settori di ricerca, che tentano di portare tali nozioni
a livello piu' formale e strutturato; lo studio dei design
patterns [4] e' una delle nuove interessanti promesse dell'ingegneria
del software, la cui semplice filosofia di fondo e' di creare
un catalogo di strategie di attacco per i diversi problemi
(comunicazione tra processi in ambiente distribuito, realizzazione
di automi finiti, eccetera). E' interessante notare che in alcuni
settori dell'informatica, come lo sviluppo di compilatori, esista
gia' una classificazione dei problemi cosi' ampia che una gran
parte del dominio (grammatiche, analizzatori lessicali, parser)
si puo' considerare esplorata e formalizzata; non a caso, in tali
settori possiamo trovare degli ottimi strumenti per la generazione
automatica di codice (compiler compilers).
Usare il giusto metodo di analisi
Per quanto l'approccio object-oriented sia molto versatile ed
efficace, non sempre si dimostra il migliore: cio' avviene in
quanto si tratta tutto sommato di un paradigma giovane. Se consideriamo
il succitato sviluppo di compilatori, troveremo una enorme bibliografia
ed ottimi tool, tuttavia quasi nulla e' stato pensato in termini
object-oriented; ricondurre risultati noti all'interno di un paradigma
differente puo' essere intellettualmente stimolante, ma professionalmente
deleterio se si hanno tempi piuttosto stretti.
Lo stesso avviene in diversi altri settori: nel corso degli anni,
sono stati sviluppati alcuni metodi specializzati per la soluzione
di problemi specifici; spesso si indicano tali linee guida, metodi
e soluzioni stereotipate come problem frames [5]. Se le
vostre necessita' ricadono esattamente in uno dei frames esistenti,
cercare una soluzione ex-novo con l'approccio object oriented
puo' non essere l'approccio vincente; puo' invece essere interessante
applicare le metodologie object oriented a specifiche fasi di
uno dei frames esistenti (ad esempio, all'interno dell'Environment-Effect
frame per modellare sistemi embedded). Con questa dovuta precisazione,
intesa a ricordare che non esiste la soluzione definitiva a tutti
i problemi, terminiamo la parte introduttiva per concentrarci
invece sulle peculiarita' del paradigma object oriented.
Iniziare l'analisi
Il primo passo dell'analisi e' certamente l'acquisizione della
conoscenza necessaria a comprendere il dominio del problema: l'analista
dovra' essere in grado di discutere con gli specialisti dimostrando
competenza e di trasformare il risultato delle sue conversazioni
in un modello chiaro e completo della realta'. Meglio ancora,
dovra' essere in grado di raggiungere rapidamente una comprensione
dell'insieme (non dei dettagli) persino piu' organica della visione
dei committenti: d'altra parte, e' spesso da questo che la sua
professionalita' viene giudicata. Conseguenza diretta di tale
necessita' e' la tendenza a diventare "esperti" di un
settore, evitando il continuo apprendimento di realta' differenti;
"l'esperto" di automazione industriale conosce a fondo
le problematiche tipiche e la terminologia adeguata per l'ambiente
in cui opera e i suoi passati successi possono positivamente influenzare
l'eventuale committente.
Il secondo passo, che puo' in una certa misura coincidere con
il primo, consiste in una serie di discussioni o "interviste"
con il committente, con i potenziali utenti, ed eventualmente
con altre figure di contorno, che siano di rilevanza ai fini della
comprensione del problema. Risultato di tali conversazioni e'
normalmente una raccolta di requisiti, vincoli, richieste e desideri,
espressi in modo tutt'altro che formale, esplicito o consistente.
In questa fase, e' spesso utile rimanere ad un livello di astrazione
piuttosto elevato, evitando di concentrarsi sui dettagli del problema.
La terza fase, com'e' semplice capire, consiste nel filtrare i
requisiti ottenuti in modo da ottenere un modello piu' chiaro
del problema, sempre espresso in linguaggio naturale, seppure
eventualmente con l'ausilio di grafici; naturalmente, le varie
fasi possono in parte coincidere, per cui non e' irrealistico
pensare di abbozzare un primo modello object oriented gia' a questo
punto. Tuttavia vi sono buone ragioni per rimanere a livello di
linguaggio naturale: normalmente, infatti, il risultato delle
interviste e' un groviglio inconsistente, ed a questo punto dovremo
tornare a confrontarci con committente, esperti, utenti, e cosi'
via, sino ad ottenere un primo livello di confidenza nella rappresentazione
informale del problema.
Infine (quarta fase) potremo passare dal linguaggio naturale al
formalismo object oriented, con le tecniche che vedremo tra breve;
di norma, alcuni punti saranno incompleti, e potremo concentrarci
su di essi singolarmente, ripetendo le fasi precedenti. Almeno,
in teoria; nel mondo reale, spesso le varie fasi si sovrappongono
in modo tale da rendere indistinguibili i confini, e spesso ci
si trova a discutere con l'utente sulla base di classi ed oggetti.
Vedremo in seguito alcuni accorgimenti per rendere la specifica
object-oriented dei requisiti piu' comprensibile anche per i non
addetti, evitando frustrazioni ed incomprensioni.
Dalle parole alle classi
Esistono diverse tecniche che guidano verso la formalizzazione
dei requisiti informali cosi' raccolti in un diagramma object
oriented; il metodo qui presentato e' stato introdotto da Booch
[6] ed in seguito raffinato dallo stesso e da altri influenti
autori, tuttavia in questa sede ho ritenuto opportuno arricchirlo
con note e consigli tratti dall'esperienza su progetti reali,
nonche' adattarlo meglio alla grammatica italiana. Se avete relegato
alcune definizioni tipiche dell'analisi logica (predicati verbali,
predicati nominali, avverbi, ecc) nei recessi dei vecchi compiti
di scuola, un piccolo ripasso di queste nozioni ormai lontane
non fara' male alla comprensione della tecnica qui esposta. Vedremo
ora la strategia generale, per tornare in seguito se necessario
a ridiscutere i singoli punti.
Come abbiamo visto, l'analisi dei requisiti si concentra su cosa
deve essere fatto, non su come; vedremo ora che l'analisi
object oriented si concentra innanzitutto su chi debba
fare qualcosa, e poi su cosa debba fare.
La formalizzazione inizia individuando all'interno della descrizione
informale del sistema, ottenuta come risultato dei passi precedenti,
tutti i nomi e le parti nominali, cercando, se non
lo si e' gia' fatto, di eliminare i sinonimi e gli omonimi, sostituendone
le occorrenze o costruendo un dizionario dei termini. Gli elementi
evidenziati potranno essere oggetti, o classi, o
attributi di un oggetto. Infatti, nella descrizione in
linguaggio naturale i nomi giocano solitamente il ruolo di soggetti
o complementi oggetto, oppure definiscono caratteristiche di altri
oggetti. Potranno esistere particolari relazioni tra gli oggetti
cosi' trovati (ereditarieta', contenimento), che tuttavia
verranno analizzate in seguito. Osserviamo che mentre un nome
puo' individuare un attributo, non tutti gli attributi sono individuati
dai nomi (vedremo oltre come trovarli esaustivamente). Il risultato,
a questo punto, e' un insieme di nomi che possono corrispondere
a classi, oggetti, od attributi.
Occorre ora eseguire un primo passo di raffinamento: inizialmente,
abbiamo insistito sull'importanza di modellare il problema e non
la soluzione. In realta', e' abbastanza normale "inquinare"
la descrizione informale con elementi appartenenti allo spazio
della soluzione anziche' allo spazio del problema. Cio' puo' essere
anche intenzionale, ai fini di ottenere una migliore presentazione
e strutturazione del modello informale, tuttavia e' indispensabile
filtrare tali elementi prima di proseguire. Non necessariamente
dovremo eliminare parte del lavoro fatto: potremmo ad esempio
conservare le informazioni importanti in un promemoria per il
design.
Cerchiamo ora di distinguere, all'interno dello spazio dei nomi,
tra oggetti/classi ed attributi; questo passo puo' essere controverso,
ovvero possono esistere diverse partizioni tutte lecite e consistenti:
d'altra parte, il lavoro di analisi comprende anche la valutazione
di modelli alternativi e di punti di vista contraddittori. Se
vi trovate in una situazione di ambiguita' che non riuscite a
risolvere, in funzione del tempo che potete dedicare all'analisi
potete scegliere il modello apparentemente piu' realistico (e
confidare nella saggezza della scelta) o portare a termine l'analisi
secondo le alternative piu' sensate e confrontare i risultati
finali, al limite in termini del design risultante.
Gli oggetti e le classi si distinguono dagli attributi in quanto
elementi attivi del sistema (ovvero, essi svolgono delle
funzioni all'interno del sistema stesso): ad esempio, un contenitore
puo' essere un elemento attivo, mentre la sua dimensione od il
suo colore (notiamo che sono comunque nomi!) saranno in genere
elementi descrittivi del sistema stesso, ed in quanto
tali attributi.
Esiste un metodo piu' sistematico per la ricerca di classi ed
oggetti? Normalmente, si possono utilizzare le azioni contenute
nella descrizione informale, che associate ai soggetti che le
realizzano permettono di distinguere tra oggetti ed attributi.
Vediamo in dettaglio: si evidenziano tutti i verbi, le
parti verbali ed i predicati verbali; ogni azione
viene poi associata ad un soggetto nello spazio dei nomi. Tali
nomi saranno eleggibili a dignita' di oggetto o classe, in quanto
elementi attivi del modello. Nuovamente, e cio' vale ad ogni passo
ed evitero' quindi di ripeterlo in seguito, grande attenzione
va prestata a sinomi e omonimi; inoltre, termini estremamente
ambigui come "fare" andrebbero innanzitutto sostituiti
con altri dalla semantica piu' caratterizzante.
A questo punto, i nomi rimanenti sono probabilmente attributi,
e come tali vanno ricondotti ad elementi gia' trasferiti nello
spazio degli oggetti/classi. Se non e' possibile capire a quale
oggetto/classe faccia riferimento un attributo, probabilmente
c'e' un errore nel modello ed occorre riesaminare con attenzione
le scelte eseguite. Notiamo che alcuni dei nomi rimanenti potrebbero
essere oggetti che giocano un ruolo esclusivamente passivo, tuttavia
cio' e' spesso indice di un modello inesatto.
Come abbiamo visto, non e' sufficiente analizzare lo spazio dei
nomi per trovare tutti gli attributi; occorre considerare anche
gli aggettivi: ad esempio, nella frase "contenitori
rossi e gialli" abbiamo una possibile classe "contenitore",
ed un attributo implicito "colore" individuato dagli
aggettivi "rossi" e "gialli". La strategia
in questo caso e': evidenziare gli aggettivi, risalire dall'istanza
dell'aggettivo (come "rossi" e "gialli") alla
caratteristica generale (colore), trovare l'oggetto/classe cui
tale aggettivo si riferisce, ed aggiungere il corrispondente attributo.
Osserviamo che, come sottoprodotto della distinzione tra oggetti/classi
ed attributi, abbiamo gia' ottenuto l'elenco delle operazioni
(metodi) che ogni oggetto/classe deve compiere. Le operazioni
avranno in genere dei parametri, che possono essere estratti dalla
descrizione informale considerando sia i complementi oggetto della
frase, sia gli avverbi associati ad ogni verbo relativo
ad una classe. In genere, molti dei parametri saranno gia' presenti
come oggetti od attributi nella descrizione del problema; in ogni
caso, una valutazione critica del modello e' indispensabile in
ogni fase.
Veniamo infine all'ultimo passo fondamentale per la realizzazione
di uno schema di massima (mancheranno infatti le relazioni tra
oggetti, che considereremo piu' avanti): la distinzione tra oggetti
e classi, e la conseguente astrazione (nel modello object oriented,
compariranno solo le classi; gli oggetti compaiono solo come parametri
delle operazioni).
In gran parte, la distinzione fra oggetti e classi e' un semplice
processo di astrazione: da un'istanza della classe (ovvero un
oggetto) presente nella descrizione informale del sistema, e ormai
presente nella partizione oggetto/classe dello spazio dei nomi,
si deve risalire al concetto generale, alla classe astratta cui
l'oggetto appartiene. Si tratta di un compito in genere molto
semplice per gli esseri umani, ed in effetti gran parte dell'efficacia
dell'approccio object oriented risiede proprio nell'utilizzo di
schemi di classificazione tipici della mente umana.
Entro certi limiti, tuttavia, possiamo farci nuovamente coadiuvare
dall'analisi logica della descrizione informale: in genere, i
predicati nominali con sostantivo aggettivizzato ("le
mosche sono insetti") indicano una relazione oggetto/classe.
Tuttavia, per esperienza, posso dire che simili frasi sono molto
rare nelle descrizioni dei sistemi.
Alcune importanti note
Per quanto il metodo descritto sembri semi-algoritmico, in realta'
vi e' un ampio spazio discrezionale: in molti casi, decidere se
qualcosa fa parte dello spazio del problema o delle soluzioni
e' un compito arduo; lo stesso dicasi, in casi non banali, per
la selezione degli oggetti e degli attributi. Pertanto, e' importante
almeno inizialmente sperimentare visioni alternative, specialmente
se vi sono scelte opinabili, e puo' essere realmente utile confrontare
le proprie idee con altri specialisti. Ricordate sempre che i
metodi e le tecniche sono importanti, ma non vi sono sostituti
per il talento e l'esperienza.
Inoltre, il metodo su esposto non e' l'unico approccio all'analisi
object oriented, per quanto sia il piu' universalmente accettato
per la sua comprovata validita'. Ad esempio, alcuni sviluppatori
ripongono grandi speranze nel metodo RDD, Responsibility-Driven-Design,
che al di la' del nome e' in realta' in gran parte un metodo di
analisi per lo spazio dei problemi. Gli approcci alternativi saranno
l'argomento di una futura puntata, dopo che il metodo qui presentato
sara' stato completamente discusso ed esemplificato.
Infine, specialmente trattando sistemi di grandi dimensioni, puo'
essere utile l'impiego di uno strumento C.A.S.E. (Computer Aided
Software Engineering) che supporti l'OOA e magari anche l'OOD
e l'OOP. In una futura puntata, presenteremo alcuni degli strumenti
esistenti e analizzeremo le caratteristiche salienti dei migliori
ambienti per il supporto all'analisi object oriented.
Rappresentare il primo risultato
Veniamo al risultato di questa prima formalizzazione dei requisiti:
avremo distinto le varie classi, i loro attributi, le loro operazioni,
ed i parametri delle operazioni stesse. Come possiamo rappresentare
tali strutture? Ovviamente, possiamo cercare di mantenere tutto
a livello di linguaggio naturale, tuttavia qualche ausilio schematico
si rivela presto prezioso per rendere l'intero modello maneggevole.
In effetti, esistono diversi schemi grafici per la rappresentazione
di classi, attributi, relazioni tra classi, e cosi' via, e si
tratta infatti di un argomento che approfondiremo adeguatamente,
insieme con una serie di considerazioni psicologiche sulle rappresentazioni
grafiche.
Tuttavia, lo scopo della prima formalizzazione e' solo quello
di trasformare i requisiti informali, raccolti da discussioni
ed interviste, in un modello piu' organico, che comunque dovra'
ancora essere discusso a fondo con utenti, committenti ed esperti,
prima di passare a raffinare il modello.
A tal fine, una rappresentazione in forma tabulare, come si puo'
vedere in figura 1, e' normalmente piu' semplice e meno intimidatoria
per i non addetti di un complesso grafo con classi e relazioni.
Notiamo che il livello di precisione e' alto ma il livello di
dettaglio e' minimo: in particolare, per gli attributi non sono
ancora stati stabiliti i tipi corrispondenti, operazione che spesso
si rimanda alla fase di design. Le colonne "azioni"
e "parametri e risultato" possono essere fuse in un'unica
colonna, introducendo un minimo di sintassi piu' formale, o lasciate
separate come nell'esempio dato, dove e' comunque evidente che
i parametri si riferiscono all'azione immediatamente a sinistra
sulla stessa riga.
Alcuni autori (es. Coad e Yourdon) suggeriscono di utilizzare
dei fogli adesivi, tipo Post-It, per le varie caselle, in modo
che gli elementi della tabella si possano sostituire agevolmente
durante le discussioni; ovviamente, a questo punto si scende piu'
che altro nel gusto personale.
Fig. 1
Un esempio di rappresentazione tabulare degli oggetti
| Oggetto o Classe | Attributi | Azioni | Parametri e risultato |
| Sensore | unita' misurata
range ammissibile deriva termica ...eccetera... | Taratura
Lettura Posizionamento | valori di riferimento
restituisce valore posizione geometrica |
| Motore elettrico | potenza
numero di giri al minuto ...eccetera | Start
Stop Singolo Passo | nessuno
nessuno nessuno |
Verificare il modello
Il momento principale della verifica per il modello e' proprio
la presentazione del modello stesso agli utenti o agli esperti
del ramo: spesso le incomprensioni ed i malintesi, avuti al momento
delle discussioni iniziali, emergono quando il committente inizia
ad elencare mancanze nel modello o l'inaderenza del modello stesso
alla sua realta' operativa. Nuovamente, in questi casi e' indispensabile
usare un tatto da mediatore, poiche' e' possibile che voi abbiate
frainteso le sue richieste o che semplicemente il committente
non sia in grado di seguirvi nelle vostre astrazioni. Talvolta
e' utile fare uso di qualche metafora: un banale parallelo tra
lo sviluppo di piccoli e grandi progetti software con la costruzione
di una casetta di legno e di un grande palazzo, e delle diverse
tecniche e competenze necessarie, e' talvolta piu' convincente
di una citazione colta o di un'esposizione eccessivamente tecnica.
Ricordate sempre che l'aspetto umano e' fondamentale durante l'analisi
dei requisiti.
Una volta che il modello sia in qualche modo accettabile per l'utente,
occorre una verifica di tipo tecnico; cosi' come vi sara' capitato
di vedere codice scritto da principianti, e definirlo a colpo
d'occhio come una schifezza, anche un modello object oriented
puo' essere di qualita' molto bassa. Tuttavia, non esistono molti
criteri oggettivi su cui basare una valutazione di qualita' dell'analisi:
in effetti, mentre nella fase di codifica alcune metriche sono,
se non proprio di uso comune, almeno abbastanza diffuse, a livello
di analisi e design object oriented il materiale bibliografico
sulle valutazioni metriche e' molto scarno, ed e' soprattutto
rivolto al design (e verra' quindi presentato quando giungeremo
a tale fase); in ogni caso, elenchero' qui di seguito alcuni accorgimenti
che possono risultare utili per valutare la bonta' del modello;
in gran parte, sono basati sulla mia esperienza personale. Questo
elenco si arricchira' in seguito, quando considereremo anche le
relazioni tra le classi; al solito, le eccezioni sono sempre presenti,
per cui i criteri esposti vanno considerati delle linee guida
e non dei sacri comandamenti.
- Usate il linguaggio e la terminologia adatta al problema da
modellare. Ogni settore ha una sua terminologia specifica, e comprendere
ed usare le parole adatte semplifichera' enormemente la comunicazione
con gli addetti ai lavori. Questa raccomandazione si estende anche
al design, ed in larga misura anche all'implementazione.
- Il modello dovrebbe riflettere il problema: se all'interno del
modello vi sono elementi "di informatica" come code,
stack, automi, e cosi' via, probabilmente state modellando la
soluzione e non il problema.
- Le classi dovrebbero essere significative: dovrebbero cioe'
corrispondere ad oggetti reali o a concetti propri del dominio
del problema. Se non sapete bene che nome dare ad una classe,
il modello e' probabilmente mal fondato.
- Le classi dovrebbero essere limitate ad uno stesso livello di
astrazione: un modello di un sistema complesso e' spesso realizzato
per passi di specializzazione successivi, dove inizialmente si
fornisce un modello di massima e poi si analizza in dettaglio
ogni componente. Evitate di avere all'interno dello stesso modello
classi che siano concettualmente poste a livelli di astrazione
molto distanti: "sistema di controllo del traffico aereo"
e "lampadina di emergenza" sono ad esempio troppo lontani
come dimensione, non solo fisica, per figurare in uno stesso
diagramma.
- gli attributi dovrebbero essere semplici: essi dovrebbero riflettere
qualita', caratteristiche o stati d'essere dell'oggetto a cui
appartengono. Attributi strutturati sono rari e indicano che forse
si e' forzato un oggetto in un attributo. Un attributo strutturato
come insieme o sequenza di dati elementari omogenei puo' ancora
essere accettabile, ma in genere attributi strutturati eterogenei
(ad esempio, uno "stato" che comprenda temperatura,
pressione, velocita', e cosi' via) devono essere separati nelle
loro parti essenziali o assumere la dignita' di oggetto. In questo,
vi e' una certa somiglianza con uno dei passi di normalizzazione
nel modello relazionale.
- i metodi sono sempre definiti? Abbiamo visto che una delle caratteristiche
degli oggetti e' di avere un insieme di metodi che possono essere
richiamati in ogni momento. Non vi sono dipendenze temporali esplicite
in un modello object oriented. Ovviamente un'operazione puo' fallire
se eseguita a partire dallo stato sbagliato, ma occorre verificare
che l'operazione "abbia senso" in se' quando applicata
in ogni stato. Se cio' non accade, probabilmente e' piu' opportuno
introdurre solo qualche funzionalita' di livello piu' alto a livello
di analisi, e lasciare la specifica di tali operazioni alla fase
di design.
- vi sono parametri troppo ricorrenti nei metodi? Se un elemento,
sia esso modellato come un attributo o come un oggetto, e' presente
troppo spesso come parametro di funzioni, e' possibile che il
modello non sia corretto, ovvero che un oggetto attivo sia stato
modellato come passivo. In questo caso, Meyers [7] suggerisce
la "regola dell'inversione", ovvero se un dato e' troppo
presente nelle funzioni, spostare le funzioni nel dato. Cio' significa
far giocare al dato il ruolo di oggetto attivo, spostando le funzioni,
che prima prendevano l'oggetto come parametro, all'interno della
classe dell'oggetto stesso. Cio' non sempre e' possibile: talvolta,
dopo la modifica alcuni altri oggetti, prima attivi, appaiono
costantemente come parametri; in tal caso, siamo comunque di fronte
ad un modello con un elevato grado di accoppiamento fra le classi,
e sarebbe opportuno considerare se non esiste qualche modello
alternativo, magari radicalmente diverso, o se piu' semplicemente
non abbiamo analizzato il problema in modo superficiale; tuttavia,
questa semplice tecnica puo' spesso guidare alla felice ristrutturazione
di un modello troppo interconnesso.
Raffinare il modello Il modello cosi' ottenuto e' ancora piuttosto grezzo: in particolare, manca ogni relazione tra le diverse classi, come il contenimento o l'ereditarieta'; le relazioni fra gli oggetti costituiranno il nucleo della prossima puntata. Potete comunque iniziare a sperimentare il metodo descritto su qualche caso concreto, magari su problematiche gia' risolte, e confrontare i risultati cosi' ottenuti con le vostre precedenti realizzazioni.
Bibliografia
[1] Dijkstra E.: "The Humble Programmer", Communications
of ACM, Ottobre 1972.
[2] Jackson M.: "System Development", Prentice-Hall,
1983.
[3] Chandra, Gupta, Hennessy: "Cool: An Object-Based Language
for Parallel Processing", IEEE Computer, Agosto 1994.
[4] Gamma, Helm, Johnson, Vlissides: "Design Patterns",
Addison-Wesley, 1994.
[5] Jackson M.: "Problems Methods and Specialization",
Software Engineering Journal, Novembre 1994.
[6] Booch G., "Object Oriented Design", Ada Letters,
Marzo/Aprile 1982.
[7] Meyers B., "Object Oriented Software Construction",
Prentice-Hall, 1988; edizione italiana: "La Produzione del
Software Object Oriented", Gruppo Editoriale Jackson, 1991.
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.