3. Principi dell'Ingegneria del Software
Last updated
Last updated
Un sistema complesso può essere suddiviso in parti più piccole chiamate moduli. Un sistema composto da moduli è detto modulare. Il vantaggio principiale della modularità è quello di consentire di applicare il principio di separazione degli interessi in due fasi. In una prima fase si possono trattare i dettagli di un singolo modulo separatamente, ignorando i dettagli degli altri e, in una seconda fase, si possono esaminare le caratteristiche complessive di tutti i moduli e le loro relazioni, in modo da integrarli in un sistema coerente. Quando le due fasi vengono eseguite concentrandosi inizialmente sui moduli e quindi sulla loro composizione, diciamo che il sistema viene progettato bottom-up. Al contrario, quando scomponiamo innanzitutto un problema in moduli e ci concentriamo successivamente sulla progettazione di ciascuno di questi, il processo viene chiamato progettazione top-down. La modularità è una proprietà importante di quasi tutti i processi e prodotti ingegneristici. Ad esempio, nell'industria automobilistica, la costruzione delle auto procede assemblando blocchi costitutivi che sono progettati e costruiti separatamente. Inoltre, le parti sono spesso riusate da un modello all'altro, dopo aver apportato minimi cambiamenti. Anche i processi industriali sono modulari, costituiti da moduli di lavorazione che sono combinati in maniera semplice (in sequenza o in parallelo) al fine di raggiungere i risultati desiderati.
Il prossimo capitolo tratta la modularità nel contesto della progettazione del software. La modularità comunque non è solo un principio di progettazione, ma permea l'intero processo di sviluppo del software. In particolare, la modularità dà luogo a quattro fondamentali tipi di benefici:
la capacità di scomporre un sistema complesso in parti più semplici
la capacità di comporre un sistema complesso a partire dai moduli esistenti
la capacità di capire un sistema in funzione delle sue parti
la capacità di modificare un sistema modificando soltanto un piccolo insieme delle sue parti.
La capacità di scomporre un problema in parti consente di suddividere il problema originario top-down in sottoproblemi e di applicare la scomposizione successivamente e ricorsivamente a ciascun sottoproblema. Questo modo di procedere riflette il motto latino divide et impera, il quale ben descrive la filosofia degli antichi romani nel dominare le altre nazioni: dividere e isolare innanzitutto, e quindi conquistare singolarmente ciascun paese. La capacità di comporre un sistema è basata invece su un procedimento bottom-up, a partire da componenti elementari combinati successivamente fino a raggiungere il sistema completo. Ad esempio, un sistema di automazione di ufficio può essere progettato aggregando componenti hardware esistenti, quali personal computer, una rete locale, periferiche e componenti software quali il sistema operativo, strumenti di produttività personale (software per la gestione di documenti, di basi di dati, di fogli elettronici). L'automobile è un altro ovvio esempio di sistema costruito a partire da componenti: la carrozzeria, il sistema di alimentazione elettrica, il sistema di trasmissione, il motore. Ciascuno di questi elementi, a sua volta, viene costruito a partire da componenti standard. Ad esempio: batteria, fusibili, cavi, etc., formano il sistema elettrico. Quando si genera un malfunzionamento, si sostituiscono i componenti difettosi con quelli nuovi. Idealmente, nel processo di produzione del software vorremmo poter essere in grado di costruire nuove applicazioni attraverso l'interconnessione di componenti (moduli) prelevati da una libreria e combinati in maniera tale da fornire le funzionalità richieste. I moduli dovrebbero essere progettati con l'obiettivo di costruire componenti riutilizzabili. Attraverso l'uso di componenti riutilizzabili è possibile aumentare la velocità di costruzione del sistema e della sua messa a punto. Ad esempio, diventa possibile sostituire un componente con un altro che fornisce la stessa funzionalità , ma che differisce in termini di utilizzo di risorse computazionali. La capacità di comprendere la struttura interna di un sistema e quella di modificarlo sono strettamente connesse tra di loro, in quanto la comprensione di un sistema è spesso il primo passo nell'effettuare modifiche. Abbiamo enfatizzato la capacità di evolvere come obiettivo di qualità , in quanto gli ingegneri del software devono spesso ritornare su un'applicazione precedentemente sviluppata per modificarla. In un sistema che può essere compreso soltanto nella sua interezza, le modifiche sono difficili da effettuare e il risultato di una modifica produce probabilmente un software inaffidabile. Quando è necessario riparare un difetto o migliorare una funzionalità , la modularità aiuta a confinare la ricerca di un difetto o del punto in cui intervenire per il miglioramento, limitandola a un singolo componente. Pertanto la modularità diventa fondamentale ai fini della capacità del software di evolvere. Per ottenere la capacità di comporre, scomporre, comprendere e modificare il software in maniera modulare, l'ingegnere del software deve progettare i moduli in modo che abbiano alta coesione e basso accoppiamento. Un modulo ha un'alta coesione se tutti i suoi elementi sono strettamente connessi. Gli elementi di un modulo (vale a dire, le istruzioni, le procedure e le dichiarazioni) sono raggruppati per un motivo logico, non in maniera puramente casuale, e cooperano tra di loro in modo tale da raggiungere un obiettivo comune: la realizzazione della funzione richiesta per il modulo. Mentre la coesione è una proprietà interna al modulo, l'accoppiamento caratterizza la relazione del modulo con altri moduli. L'accoppiamento misura l'interdipendenza di due moduli; ad esempio, un modulo A chiama una funzione definita nel modulo B o accede a una variabile dichiarata dal modulo B. Due moduli hanno un elevato accoppiamento se dipendono strettamente l'uno dall'altro. È desiderabile avere moduli con un basso livello di accoppiamento, in quanto ciò rende possibile analizzare, capire, modificare, testare o riusare ciascun modulo separatamente. La figura sottostante fornisce una visione grafica della coesione e dell'accoppiamento. Un buon esempio di sistema con elevata coesione e basso accoppiamento è il sistema elettrico all'interno di una casa. Il sistema ha un basso livello di accoppiamento in quanto è costituito da un insieme di dispositivi e apparecchiature che forniscono funzioni ben identificabili e che sono connessi attraverso semplici cavi elettrici di collegamento. Il sistema ha un'elevata coesione in quanto ciascuna apparecchiatura e ciascun dispositivo è costituito internamente da componenti elementari che si trovano all'interno del dispositivo o del componente, proprio per assicurare la funzione che esso deve fornire. Strutture modulari con alta coesione e basso accoppiamento ci consentono di vedere i moduli come delle black box (scatole nere) quando si vuole descrivere la struttura complessiva del sistema, e vedere invece ciascuno di essi nei suoi dettagli quando è necessario descrivere e analizzare la struttura interna del modulo. In altre parole, la modularità supporta l'applicazione del principio di separazione degli interessi.