Vai al contenuto
Principi di design

Principi di software design: accoppiamento, coesione e cambiamento 🧭

Il problema dello sviluppo software non è scrivere codice. Quello, con abbastanza caffeina e un minimo di ostinazione, succede quasi sempre. Il problema vero è gestire il cambiamento senza trasformare ogni modifica in un piccolo incidente diplomatico tra moduli, team e infrastruttura.

Per questo i principi di design contano più delle buzzword del momento: servono a ridurre il costo del cambiamento, non a rendere il diagramma più elegante.

Accoppiamento: quando tutto dipende da tutto 🔗

L’accoppiamento misura quanto una parte del sistema dipende da un’altra. Più il coupling è alto, più una modifica locale tende a propagarsi in modo imprevedibile.

Segnali tipici:

  • un cambiamento in un modulo costringe a ritoccarne altri tre
  • i test richiedono metà applicazione per avviarsi
  • la logica di business conosce dettagli di DB, framework o rete

Un po’ di coupling è inevitabile. Il punto non è eliminarlo, ma renderlo intenzionale, esplicito e stabile.

Coesione: stare insieme per un motivo valido 🧲

La coesione misura quanto gli elementi di un modulo appartengono davvero allo stesso problema. Un componente coeso ha responsabilità affini; un componente incoerente è il classico cassetto dove finisce di tutto, comprese cose che nessuno ricorda più di aver messo lì.

Segnali di bassa coesione:

  • una funzione valida dati, chiama API, salva su DB e formatta l’output
  • una classe contiene regole di business, logging, retry e configurazione
  • il nome del modulo è talmente generico da non dire nulla: Utils, Manager, Helper

Meno accoppiamento e più coesione non sono slogan gentili: sono il modo più concreto per avere refactoring meno traumatici.

Separation of concerns: ognuno faccia il suo mestiere 🧹

La separation of concerns è il principio che impedisce al dominio di trasformarsi in una discarica di dettagli tecnici. Significa separare ciò che cambia per motivi diversi.

Esempio semplice:

  • il dominio decide cosa è valido
  • l’infrastruttura decide come salvare o inviare dati
  • l’interfaccia decide come presentare lo stato all’utente

Quando tutto finisce nello stesso punto, il sistema diventa fragile. Quando i confini sono chiari, cambiare tecnologia o comportamento costa meno.

Incapsulamento e information hiding: proteggere gli invarianti 🛡️

Incapsulare non significa solo nascondere campi dietro metodi con nomi vagamente rispettabili. Significa proteggere gli invarianti del sistema.

L’information hiding aggiunge un livello di maturità: gli altri moduli non devono sapere come fai qualcosa, ma solo quale contratto offri.

Se il chiamante deve conoscere dettagli interni per usare correttamente un componente, quel componente non sta nascondendo nulla. Sta solo facendo il timido.

Composition over inheritance: meno genealogie, più collaborazione 🧩

L’ereditarietà promette riuso, ma spesso consegna gerarchie rigide, violazioni del principio di sostituzione e debugging dal sapore archeologico. La composizione tende a funzionare meglio perché costruisce comportamento combinando parti piccole e sostituibili.

Considera questo scenario: hai un sistema di notifiche. Con l’ereditarietà potresti creare una classe base Notifier specializzata in EmailNotifier, SMSNotifier, PushNotifier. Quando vuoi inviare email e SMS contemporaneamente, il problema si complica: duplicazione, ereditarietà multipla o gerarchia ancora più profonda.

Con la composizione, il servizio riceve un Notifier e non sa nulla di come è implementato. Puoi costruire un MultiNotifier che delega a una lista di notificatori senza toccare nessun implementatore esistente. Il comportamento cresce per aggregazione, non per discendenza.

Usa la composizione quando:

  • vuoi variare il comportamento senza riscrivere una gerarchia
  • hai bisogno di sostituire collaboratori in test o runtime
  • il rapporto tra componenti è più di collaborazione che di identità
  • devi combinare comportamenti che variano in modo ortogonale tra loro

L’ereditarietà non è vietata. È solo spesso più costosa di quanto sembri all’inizio, specialmente quando le gerarchie iniziano a crescere in più dimensioni.

Il costo del cambiamento è il vero indicatore 💸

Un design ragionevole non è quello più astratto o più “pulito” in senso estetico. È quello che rende economiche le modifiche più probabili.

Domande utili:

  • quale parte del sistema cambierà più spesso?
  • quali dipendenze sono volatili e quali sono stabili?
  • dove vale davvero la pena introdurre un’astrazione?
  • cosa sto proteggendo: il dominio, il framework o il mio ego?

Se un’astrazione riduce il costo di cambiamenti reali, bene. Se esiste solo per soddisfare una teoria, probabilmente stai pagando in anticipo un debito che nessuno ti aveva ancora chiesto.

Trade-off reali: semplicità contro rigidità ⚖️

Ogni scelta di design è un trade-off:

  • troppa semplicità può produrre accoppiamento nascosto
  • troppa astrazione può creare over-engineering
  • troppe interfacce possono nascondere la logica
  • troppo poco isolamento può rendere tutto fragile

La domanda giusta non è “qual è il principio corretto in assoluto?” ma “quale struttura rende questo sistema più adattabile senza farlo collassare sotto il proprio peso?”

Checklist pratica per review e refactoring ✅

  • questo modulo ha una responsabilità leggibile o è un contenitore generico?
  • le dipendenze sono esplicite o nascoste dietro stato globale e magia?
  • sto separando concetti che cambiano per motivi diversi?
  • il chiamante conosce dettagli interni che dovrebbe ignorare?
  • un cambiamento locale resta locale oppure si propaga troppo facilmente?

In sintesi 🧾

Accoppiamento, coesione, separation of concerns, incapsulamento e composizione non sono ornamenti teorici. Sono strumenti per costruire software che tollera il cambiamento senza reagire come un castello di carte in una giornata ventosa.

Se vuoi scendere nel concreto, i passi naturali dopo questa guida sono S.O.L.I.D., Clean code e la guida su Dependency Injection e Inversion of Control.

Ultimo aggiornamento il