Progettazione
Definizione
La risoluzione di un problema attraversa due fasi: la prima è analitica, la seconda sintetica. Nella fase analitica il problema viene decomposto, approfondito nel dettaglio per capire di quali parti è formato (approccio top-down); in quella sintetica, invece, si ricompongono i pezzi trovati al passo precedente e si sintetizza una soluzione per il problema (approccio bottom-up). Se la fase analitica ("qual è il problema?") corrisponde grosso modo all'attività di analisi dei requisiti, quella sintetica ("come risolvere il problema?") è proprio la progettazione. Formalmente, la progettazione è la definizione[1] dell'architettura, dei componenti, delle interfacce e delle altre caratteristiche di un sistema o componente.
L'architettura di un software è, tipicamente, un insieme di moduli che si raggruppano in unità, che a loro volta si raggruppano in componenti, che vanno a formare un sistema. Acronimo tattico per ricordarsi: SCUM.
Progettazione architetturale e progettazione di dettaglio
Il processo di progettazione passa attraverso due attività, che si situano tra l'analisi dei requisiti e l'implementazione:
- progettazione architetturale, di alto livello, che descrive come il software viene organizzato in componenti;
- progettazione di dettaglio, che descrive il comportamento di tali componenti.
Nel piano di qualifica, se l'analisi è verificata dal test di sistema, la progettazione architetturale è verificata dai test d'integrazione e quella di dettaglio dai test di unità. (Questo è il cosiddetto "modello a V".)
Architettura
Obiettivo della progettazione è definire l'architettura del sistema. Per architettura s'intende la decomposizione di un sistema in componenti, l'organizzazione di tali componenti, le interfacce dei componenti e i loro paradigmi di composizione. In generale, una buona architettura deve rispettare i seguenti princìpi:
- sufficienza — deve soddisfare tutti i requisiti;
- comprensibilità — può essere capita dagli stakeholders;
- modularità — le sue parti sono chiare e distinte, non si sovrappongono;
- robustezza — è capace di gestire un'ampia classe di input diversi;
- flessibilità — permette modifiche a costo contenuto;
- riusabilità — alcune sue parti possono essere utilmente impiegate in altre applicazioni;
- efficienza;
- affidabilità — è altamente probabile che svolga bene il suo compito;
- disponibilità — necessita di poco tempo di manutenzione fuori linea;
- sicurezza rispetto ai malfunzionamenti;
- sicurezza rispetto a intrusioni;
- semplicità — ogni parte contiene solo il necessario e niente di superfluo;
- incapsulamento — nasconde i dettagli implementativi;
- coesione — parti associate concorrono agli stessi obiettivi (l'approccio a oggetti aiuta molto a ottenere coesione);
- basso accoppiamento — parti distinte dipendono il meno possibile le une dalle altre.
Tutte queste qualità devono essere misurabili. In particolare, l'accoppiamento è misurabile interpretando le componenti di un sistema come i nodi di un grafo orientato dove gli archi sono dipendenze di un componente nei confronti di un altro; il numero di archi entranti (fan-in) è indice di utilità, mentre il numero di archi uscenti (fan-out) è indice di dipendenza. Riguardo alla riusabilità, infine, è bene notare che costituisce un guadagno soltanto nel lungo termine, mentre nel breve termine è un puro costo.
Design pattern e stili architetturali
Un design pattern è una soluzione progettuale a un problema ricorrente. Per la progettazione esistono soluzioni progettuali di alto livello (gli stili architetturali) e di basso livello (i design pattern).
Progettazione architetturale
Esistono vari stili architetturali e aderire a uno di essi garantisce coerenza; alcuni stili sono:
- strutture generali (livelli, oggetti, pipes e filtri, blackboard);
- sistemi distribuiti (client-server, three-tiers, peer-to-peer, broker);
- sistemi interattivi (Model-View-Controller, Presentation-Abstraction-Control);
- sistemi adattabili (microkernel, riflessione);
- altri (batch, interpreti...).
Progettazione di dettaglio
Uno stile architetturale è una soluzione progettuale di alto livello; per la progettazione di dettaglio, invece, si ricorre ai design pattern, che si dividono in tre famiglie:
- design pattern creazionali, che cercano di rendere un sistema indipendente dall'implementazione concreta delle sue componenti;
- design pattern strutturali, che affrontano problemi riguardanti la composizione di classi e oggetti;
- design pattern comportamentali, che si occupano del comportamento degli oggetti e delle collaborazioni tra essi.
La progettazione di dettaglio deve definire delle unità il cui carico di lavoro sia realizzabile da un singolo programmatore, in parallelo con le altre unità. Quanto più piccolo è il compito tanto più piccolo è il rischio.