Con il termine SOLID si indica un insieme di tecniche/pratiche/principi riassunte per la prima volta da Robert C. Martin e orientate a ridurre la complessità che tende ad emergere col susseguirsi di richieste di modifica ad una applicazione software.
In questa prima lezione, scopriremo dall'analisi di quali problematiche è stato coniato questo acronimo ed in che modo esso intende aiutarci nella progettazione di applicazioni sempre meno predisposte ad implodere sotto il peso di cambi in corso d'opera.
Martin Fowler, in un articolo chiamato DesignStaminaHypothesis, evidenzia in modo marcato come lo sforzo iniziale profuso nel design della propria applicazione sia a lungo andare ampiamente
ripagato dalla migliore adattabilità ai cambiamenti:
Rigida, Fragile, Immobile ed Invischiata
Il titolo elenca i quattro attributi principi di una applicazione poco propensa ad adattarsi al cambiamento. Ognuno di questi termini, se applicato in ambito software, denota una mancanza di design e inevitabilmente si risolve in un continuo accumulo di technical debt che porta il prodotto, in ultima analisi, a seguire un percorso simile a quello della curva blu dell'immagine precedente.
Rigidità
Un'applicazione è rigida quando ogni singola modifica da apportare si risolve in una cascata di interventi, ognuno dei quali non fa che gettare luce su di un nuovo frammento del codice da aggiornare. Un software rigido scoraggia l'adozione di cambiamenti che non siano essenziali e impedisce una qualunque attività di stima.
Fragilità
Fragilità e rigidità sono in qualche modo correlate, pur trattando di aspetti diversi dal punto di vista pratico. L'attributo fragile entra in gioco ogniqualvolta un cambiamento in una applicazione provoca un errore inatteso, magari in un altro modulo o in una parte del codice sorgente che si riteneva 'lontana' dalle istruzioni modificate. La fragilità conduce alle stesse complicazioni della rigidità e, in ultima analisi, porta ad un software completamente statico.
Immobilità
Tutte le volte che, pur avendo già scritto in applicazioni precedenti del codice per risolvere il problema che stiamo affrontando, decidiamo di ripartire con una stesura da zero, stiamo implicitamente ammettendo immobilità. Un software si dice immobile quando i suoi componenti sono così strettamente interdipendenti tra di loro da rendere impossibile l'estrazione di uno di questi per l'utilizzo in nuove applicazioni.
Viscosità
Esistono due diverse sfaccettature di questo attributo: in un primo caso aumentiamo la viscosità di una applicazione se rendiamo più facile implementare una soluzione contro le convenzioni di design concordate, il cosiddetto "hack". Nel secondo caso se facciamo in modo che gli strumenti o i tool di sviluppo ci portino alla stessa conclusione.
Un esempio di 'viscosità del secondo tipo' si verifica quando l'estrema lungaggine dei commit su di un repository di controllo versione spinge lo sviluppatore a modificare il minor numero di file sorgente possibile, indipendentemente dall'architettura e dalle scelte di design dell'applicazione.
È tutto un problema di dipendenze
La causa che genera i quattro comportamenti che abbiamo appena elencato è da ricercarsi principalmente in una cattiva gestione dell'architettura delle dipendenze. È infatti molto comune radicare correlazioni all'interno delle applicazioni in modo così pervasivo e poco strutturato da rendere l'intero software simile ad una matassa ingarbugliata. Esiste anche un termine generico che descrive questo genere di situazione: 'spaghetti con polpette'.
Per risolvere questo problema, scrive Martin, dobbiamo creare all'interno del nostro codice dei firewall attraverso i quali le dipendenze non possano propagarsi, mantenendo in questo modo il giusto grado di segregazione tra i componenti. Già, ma come fare ?
Diamo il benvenuto a S.O.L.I.D.
La risposta è, ovviamente, applicare i principi SOLID. In questa guida li analizzeremo nel dettaglio, con profusione di esempi ed approfondimenti; per ora accontentiamoci di una veloce panoramica e di una breve descrizione studiata appositamente per mantenere un vago alone di mistero:
- S - Single Responsibility
- Non deve esistere mai più di una ragione per cui una classe debba essere modificata;
- O - Open/Closed
- Le entità della programmazione (classi, moduli, funzioni, ...) devono essere aperte alle
estensioni ma chiuse per quanto riguarda la modifica; - L - Liskov Substitution
- Le sottoclassi devono poter sempre essere utilizzate al posto della loro classe padre;
- I - Interface Segregation
- Interfacce specializzate per ogni client sono migliori di una singola grossa interfaccia;
- D - Dependency Inversion
- Moduli di alto livello non devono dipendere da moduli di basso livello, entrambi devono dipendere da astrazioni. Le astrazioni non devono dipendere dai dettagli, ma viceversa.