I principi SOLID rap­pre­sen­ta­no le linee guida per un codice pulito, so­ste­ni­bi­le e fles­si­bi­le nell’ambito della pro­gram­ma­zio­ne orientata agli oggetti. Ap­pli­can­do e ri­spet­tan­do tali principi, è possibile pro­get­ta­re software in modo semplice e com­pren­si­bi­le anche nell’arco di lunghi periodi di sviluppo. Questo permette non solo di scrivere un codice migliore, ma anche di mantenere più ef­fi­ca­ce­men­te il codice esistente.

Che cosa sono i principi SOLID?

Un buon codice sorgente è ca­rat­te­riz­za­to da regole, paradigmi di pro­gram­ma­zio­ne e uno stile di pro­gram­ma­zio­ne ap­pro­pria­to in grado di garantire un codice ef­fi­cien­te e pulito. I cinque principi SOLID sono stati coniati da Robert C. Martin, Bertrand Meyer e Barbara Liskov proprio allo scopo di per­se­gui­re queste ca­rat­te­ri­sti­che del codice. Seguendo questi principi nell’ambito della pro­gram­ma­zio­ne orientata agli oggetti (OOP) con linguaggi come Python o Java, non solo è possibile scrivere un codice migliore, ma si ottiene anche una ma­nu­ten­zio­ne del codice più ef­fi­cien­te, una pro­get­ta­zio­ne del software fles­si­bi­le e longeva, oltre che una maggiore sicurezza a lungo termine.

I principi SOLID rap­pre­sen­ta­no dunque una solida base per tutti coloro che de­si­de­ra­no imparare a pro­gram­ma­re. Il nome SOLID, ideato da Micheal Feathers, non è altro che un acronimo delle prime lettere di ciascuno dei cinque principi:

  • Single Re­spon­si­bi­li­ty Principle (principio di singola re­spon­sa­bi­li­tà): una classe dovrebbe avere una singola re­spon­sa­bi­li­tà (non un compito) e un solo motivo per cambiare.
  • Open Closed Principle (princpio aperto/chiuso): le classi devono essere aperte per l’esten­sio­ne e chiuse per la modifica.
  • Liskov Sub­sti­tu­tion Principle (principio di so­sti­tu­zio­ne di Liskov): le sot­to­clas­si devono essere in grado di ereditare e im­ple­men­ta­re tutti i metodi e le proprietà della su­per­clas­se.
  • Interface Se­gre­ga­tion Principle (principio di se­gre­ga­zio­ne delle in­ter­fac­ce): le in­ter­fac­ce non devono contenere più metodi di quelli richiesti per l’im­ple­men­ta­zio­ne delle classi.
  • De­pen­den­cy Inversion Principle (principio di in­ver­sio­ne delle di­pen­den­ze): le classi non devono dipendere da altre classi, ma da in­ter­fac­ce o classi astratte.

Quali vantaggi offrono i principi SOLID?

“Dove non ci sono regole, regna il caos”. Questo è par­ti­co­lar­men­te vero nell’ambito della pro­gram­ma­zio­ne. Quando si programma basta un piccolo errore, un’im­pre­ci­sio­ne o una lacuna per rendere un buon codice sorgente inu­ti­liz­za­bi­le. Sono suf­fi­cien­ti classi ec­ces­si­va­men­te complesse, che rendono più difficile l’im­ple­men­ta­zio­ne, o sot­to­clas­si che mancano di singole proprietà delle loro su­per­clas­si. I principi SOLID as­si­cu­ra­no che il codice da riparare mediante re­fac­to­ring sia il meno possibile.

I vantaggi dell’ap­pli­ca­zio­ne dei principi SOLID includono:

  • Chiarezza, pulizia e eleganza: il software e i codici sono più facili da capire, più com­pren­si­bi­li, più efficaci e più gradevoli anche a livello estetico.
  • Facilità di ma­nu­ten­zio­ne: la struttura chiara e ordinata rende più semplice mantenere e ag­gior­na­re il codice, sia nuovo che obsoleto, anche in caso di team di sviluppo composti da più persone.
  • Per­so­na­liz­za­bi­le, esten­si­bi­le, riu­ti­liz­za­bi­le: grazie alla migliore leg­gi­bi­li­tà, alla di­mi­nu­zio­ne della com­ples­si­tà e delle re­spon­sa­bi­li­tà, nonché alla riduzione delle di­pen­den­ze delle classi, il codice si presta per essere fa­cil­men­te mo­di­fi­ca­to e per­so­na­liz­za­to, esteso at­tra­ver­so le in­ter­fac­ce e riu­ti­liz­za­to in modo fles­si­bi­le.
  • Meno soggetto a errori: un codice pulito con una struttura semplice significa che le modifiche apportate a una parte non in­flui­sco­no in­vo­lon­ta­ria­men­te su altre aree o funzioni.
  • Più sicuro e af­fi­da­bi­le: un numero minore o nullo di vul­ne­ra­bi­li­tà, in­com­pa­ti­bi­li­tà o errori migliora la fun­zio­na­li­tà e l’af­fi­da­bi­li­tà dei sistemi e quindi anche la sicurezza.

I principi SOLID in sintesi

I principi SOLID rap­pre­sen­ta­no leregole d’oro per una buona pro­gram­ma­zio­ne e do­vreb­be­ro fare parte del bagaglio di co­no­scen­ze di chiunque si occupi di pro­gram­ma­zio­ne a oggetti. Ti pre­sen­tia­mo i cinque principi nel dettaglio.

SRP: Single Re­spon­si­bi­li­ty Principle (principio di singola re­spon­sa­bi­li­tà)

Come affermato da Robert C. Martin in “Agile Software De­ve­lo­p­ment: Prin­ci­ples, Patterns and Practices”:

Citazione

“Non dovrebbe mai esistere più di un motivo per mo­di­fi­ca­re una classe.”

Il principio di re­spon­sa­bi­li­tà unica afferma che per ogni classe della pro­gram­ma­zio­ne orientata agli oggetti deve essere applicata una sola re­spon­sa­bi­li­tà. Pertanto, deve esserci un solo motivo alla base delle modifiche apportate alla classe. Con­tra­ria­men­te a quanto si possa credere, questo non significa che una classe o ogni modulo possano avere un solo compito. Do­vreb­be­ro però essere re­spon­sa­bi­li soltanto di compiti specifici, in modo da non so­vrap­por­si ad altre aree.

Una so­vrap­po­si­zio­ne di re­spon­sa­bi­li­tà, ad esempio fornendo funzioni per diverse aree aziendali, in caso di modifiche a un’area può avere un impatto sulla fun­zio­na­li­tà dell’intera classe. A causa di mol­te­pli­ci re­spon­sa­bi­li­tà e troppe di­pen­den­ze, una modifica all’interno di un’area può com­por­ta­re diverse altre modifiche o errori di codice.

Il principio di singola re­spon­sa­bi­li­tà mira quindi a svi­lup­pa­re moduli coerenti che siano re­spon­sa­bi­li di un compito ben com­pren­si­bi­le o di oggetti chia­ra­men­te definiti. Grazie alla forma ben strut­tu­ra­ta, con di­pen­den­ze ridotte e im­ple­men­ta­zio­ni di­sac­cop­pia­te, le modifiche e le mo­du­la­zio­ni suc­ces­si­ve possono essere ef­fet­tua­te in modo più semplice, rapido e senza com­pli­ca­zio­ni.

N.B.

Le classi, che de­fi­ni­sco­no i tipi di oggetti, sono l’elemento centrale della pro­gram­ma­zio­ne orientata agli oggetti. Possono essere intese come un progetto con attributi per oggetti reali e simili da costruire in oggetti software. Pe questo motivo le classi, note anche come moduli, sono spesso pa­ra­go­na­te ai tipi di file.

OCP: Open Closed Principle (principio aperto/chiuso)

Per de­scri­ve­re il principio aperto/chiuso, ri­pren­dia­mo questa citazione di Bertrand Meyer e Robert C. Martin in “Object Oriented Software Con­struc­tion”:

Citazione

“Le entità software (classi, moduli, funzioni, ecc.) devono essere sia aperte per le esten­sio­ni che chiuse per le modifiche.”

Questo principio fa in modo che non sia ne­ces­sa­rio ri­scri­ve­re il software nel suo nucleo per im­ple­men­ta­re le modifiche. In caso contrario, qualora siano ne­ces­sa­rie modifiche ap­pro­fon­di­te del codice, si rischiano errori im­per­cet­ti­bi­li e code smell. Un codice ben strut­tu­ra­to deve poter essere dotato di in­ter­fac­ce che per­met­ta­no di esten­der­lo con funzioni ag­giun­ti­ve. La parola chiave in questo caso è ere­di­ta­rie­tà delle classi.

Le nuove fun­zio­na­li­tà e le esten­sio­ni con nuove funzioni e metodi da im­ple­men­ta­re possono essere sem­pli­ce­men­te ag­gan­cia­te a una su­per­clas­se sotto forma di sot­to­clas­si tramite un’in­ter­fac­cia. In questo modo, non è ne­ces­sa­rio “ar­meg­gia­re” con il codice scritto e stabile. Così facendo viene sem­pli­fi­ca­ta la ma­nu­ten­zio­ne e la cura dei programmi e la riu­ti­liz­za­bi­li­tà degli elementi di codice stabile viene pro­get­ta­ta in modo molto più ef­fi­cien­te grazie alle in­ter­fac­ce.

LSP: Liskov Sub­sti­tu­tion Principle (principio di so­sti­tu­zio­ne di Liskov)

Citando Barbara H. Liskov e Jeannette M. Wing in “Be­ha­viou­ral Subtyping Using In­va­rian­ts and Con­strain­ts”, il principio afferma quanto segue:

Citazione

“Se q (x) è una proprietà dell’oggetto x di tipo T, allora q (y) dovrebbe ap­pli­car­si a tutti gli oggetti di tipo S, dove S è un sottotipo di T.”

Un concetto che a prima vista potrebbe sembrare criptico, ma in realtà è piuttosto semplice: le sot­to­clas­si collegate o estese devono fun­zio­na­re come le loro su­per­clas­si o classi di base. Ciò significa che ogni sot­to­clas­se deve mantenere le proprietà della ri­spet­ti­va su­per­clas­se tramite l’ere­di­ta­rie­tà e queste proprietà non devono essere mo­di­fi­ca­te nella sot­to­clas­se. In linea di principio, devono essere so­sti­tui­bi­li: da qui il nome “principio di so­sti­tu­zio­ne”. Le su­per­clas­si, invece, possono essere mo­di­fi­ca­te tramite cam­bia­men­ti.

Il principio di so­sti­tu­zio­ne di Liskov può essere spiegato in maniera com­pren­si­bi­le anche uti­liz­zan­do il classico esempio del ret­tan­go­lo e del quadrato di Robert C. Martin. In geometria, tutti i quadrati sono ret­tan­go­li, ma non tutti i ret­tan­go­li sono quadrati. Un quadrato condivide la proprietà “lati ad angolo retto” con la su­per­clas­se dei ret­tan­go­li, ma possiede la proprietà ag­giun­ti­va “lati di uguale lunghezza”.

Nella pro­gram­ma­zio­ne le cose fun­zio­na­no di­ver­sa­men­te: qui, il pre­sup­po­sto che classi simili o ap­pa­ren­te­men­te identiche si re­la­zio­ni­no tra loro o dipendano l’una dall’altra porta a errori, frain­ten­di­men­ti e codice poco chiaro. Per questo motivo, nella pro­gram­ma­zio­ne, la classe “ret­tan­go­lo” non è un quadrato e la classe “quadrato” non è un ret­tan­go­lo. Entrambe le classi sono “di­sac­cop­pia­te” e im­ple­men­ta­te se­pa­ra­ta­men­te. Senza un col­le­ga­men­to integrato tra le classi, un’in­com­pren­sio­ne non può portare a errori in­cro­cia­ti tra le classi. Questo aumenta la sicurezza e la stabilità, per­met­ten­do di so­sti­tui­re le im­ple­men­ta­zio­ni nelle sot­to­clas­si o nelle su­per­clas­si senza ri­per­cus­sio­ni.

ISP: Interface Se­gre­ga­tion Principle (principio di se­gre­ga­zio­ne delle in­ter­fac­ce)

La de­fi­ni­zio­ne di principio di se­gre­ga­zio­ne delle in­ter­fac­ce è stata data da Robert C. Martin in “The Interface Se­gre­ga­tion Principle”:

Citazione

“I client non do­vreb­be­ro essere costretti a dipendere da in­ter­fac­ce che non uti­liz­za­no.”

Il principio afferma che l’utente non dovrebbe avere l’obbligo di uti­liz­za­re in­ter­fac­ce di cui non ha bisogno. In altre parole: per fornire ai client le funzioni di alcune classi, è bene adattare nuove in­ter­fac­ce più piccole a requisiti specifici. In questo modo si evita che le in­ter­fac­ce diventino troppo grandi e si creano forti di­pen­den­ze tra le classi. Il vantaggio è che un software con classi di­sac­cop­pia­te e diverse piccole in­ter­fac­ce adattate a requisiti specifici risulta più facile da mantenere.

DIP: De­pen­den­cy Inversion Principle (principio di in­ver­sio­ne delle di­pen­den­ze)

Come riportato da Robert C. Martin in “The De­pen­den­cy Inversion Principle”, il quinto e ultimo dei principi SOLID afferma:

Citazione

“A. I moduli di alto livello non do­vreb­be­ro dipendere dai moduli di basso livello. Entrambi do­vreb­be­ro dipendere da astra­zio­ni. B. Le astra­zio­ni non devono dipendere dai dettagli. I dettagli do­vreb­be­ro dipendere dalle astra­zio­ni.”

Il principio di in­ver­sio­ne delle di­pen­den­ze assicura che le funzioni e le di­pen­den­ze concrete nei livelli del codice sorgente siano basate su in­ter­fac­ce astratte, anziché l’una sull’altra. In altre parole: le ar­chi­tet­tu­re software possono essere suddivise ap­pros­si­ma­ti­va­men­te in livelli utente superiori e livelli astratti inferiori o più profondi. Lo­gi­ca­men­te, si può supporre che la base astratta determini il com­por­ta­men­to dei livelli superiori. Cio­no­no­stan­te, il principio afferma che ciò sia soggetto a errori, in quanto i livelli superiori sono di­pen­den­ti dai livelli inferiori.

Invece di collegare i livelli superiori a quelli inferiori, le classi dei livelli alti e bassi do­vreb­be­ro dipendere da in­ter­fac­ce astratte in­ter­me­die. Le in­ter­fac­ce re­cu­pe­ra­no le fun­zio­na­li­tà richieste ai livelli superiori dai livelli inferiori e le rendono di­spo­ni­bi­li. In questo modo, si può evitare una “gerarchia di di­pen­den­ze bottom-to-top (dall’alto verso il basso)”, che nel tempo potrebbe portare a errori nel codice. Questo facilita la riu­ti­liz­za­bi­li­tà dei moduli e consente di apportare modifiche alle classi inferiori senza in­fluen­za­re i livelli superiori.

Web Hosting
Diventa il n°1 della rete con il provider di hosting n°1 in Europa
  • Di­spo­ni­bi­li­tà garantita al 99,99%
  • Dominio, SSL ed e-mail inclusi
  • As­si­sten­za 24/7 in lingua italiana

Cosa succede quando i principi SOLID non vengono ri­spet­ta­ti?

Un codice elegante e di facile lettura, che renda la ma­nu­ten­zio­ne il più semplice possibile, dovrebbe essere l’obiettivo di chiunque si occupi di sviluppo di software. Tra­scu­ran­do aspetti fon­da­men­ta­li come le linee guida dettate dai principi SOLID, il codice in­vec­chie­rà male a causa di vul­ne­ra­bi­li­tà, ri­don­dan­ze, errori ac­cu­mu­la­ti e troppe di­pen­den­ze. Nel peggiore dei casi, col passare del tempo il codice diventerà com­ple­ta­men­te inu­ti­liz­za­bi­le. Questo rap­pre­sen­ta un serio problema so­prat­tut­to nell’ambito dello sviluppo agile del software, che so­li­ta­men­te prevede la col­la­bo­ra­zio­ne si­mul­ta­nea di più persone a un codice complesso.

Le con­se­guen­ze di un codice non pulito o di una scarsa ma­nu­ten­zio­ne del codice includono:

  • Code smell: le vul­ne­ra­bi­li­tà derivanti da codice non pulito sono co­no­sciu­te come code smell. So­li­ta­men­te si svi­lup­pa­no a causa di errori fun­zio­na­li e programmi in­com­pa­ti­bi­li.
  • Code rot: se il codice non viene mantenuto at­tra­ver­so re­fac­to­ring o costose revisioni del codice può “marcire” fino a perdere com­ple­ta­men­te la sua fun­zio­na­li­tà. Un altro termine per indicare un codice il­leg­gi­bi­le, confuso e in­gar­bu­glia­to è “spaghetti code”.
  • Falle di sicurezza: oltre a guasti, problemi nella ma­nu­ten­zio­ne e in­com­pa­ti­bi­li­tà, tra­scu­ra­re i principi SOLID può anche portare a falle di sicurezza e vul­ne­ra­bi­li­tà che po­treb­be­ro aprire la strada ad attacchi in­for­ma­ti­ci tramite exploit, come gli exploit zero day.

Chi ha svi­lup­pa­to i principi SOLID?

L’origine dei principi SOLID risiede in diversi principi in­tro­dot­ti per la prima volta da Robert C. Martin (“Uncle Bob”), uno degli ini­zia­to­ri della pro­gram­ma­zio­ne agile, nel suo saggio “Design Prin­ci­ples and Design Patterns” del 2000. A coniare il gruppo dei cinque principi SOLID sono stati Robert C. Martin, Bertrand Meyer e Barbara Liskov. L’acronimo ac­cat­ti­van­te composto dalle cinque lettere iniziali dei principi è stato ideato da Michael Feathers.

Esistono principi di pro­gram­ma­zio­ne simili?

Nell’ambito dello sviluppo software, i principi rap­pre­sen­ta­no linee guida generali o spe­ci­fi­che e rac­co­man­da­zio­ni di azione. In questo contesto, i principi SOLID offrono una serie di principi per il paradigma della pro­gram­ma­zio­ne orientata agli oggetti. Altri principi di pro­gram­ma­zio­ne per clean code includono:

  • Principio DRY (Don’t repeat yourself), che descrive l’im­por­tan­za di funzioni non ripetute, ovvero rap­pre­sen­ta­te in maniera unica e singola
  • Principio KISS (Keep it simple, stupid), che detta le linee guida per un codice costruito nel modo più semplice possibile
Vai al menu prin­ci­pa­le