Principi e metodologie di architettura — sono un insieme di regole e raccomandazioni che aiutano gli sviluppatori a creare codice manutenibile, scalabile e comprensibile. Secondo TIOBE Index (2025), i progetti che seguono principi architetturali hanno il 40% in meno di difetti critici. In questo articolo analizzeremo SOLID, GRASP, DRY, KISS, YAGNI e altri principi, oltre a discutere il debito tecnico e Code Smell.
Punti chiave
I principi di architettura sono il fondamento del codice di qualità. SOLID è un acronimo introdotto da Robert Martin («Zio Bob») che descrive cinque principi di progettazione orientata agli oggetti. Seguire SOLID rende il codice più flessibile, testabile e resistente ai cambiamenti. La violazione dei principi architetturali è una delle principali cause di debito tecnico.
Esaminiamo ciascun principio. Single Responsibility Principle (SRP) — ogni classe dovrebbe avere un solo motivo per cambiare. Open/Closed Principle (OCP) — le classi sono aperte all'estensione ma chiuse alla modifica. Liskov Substitution Principle (LSP) — gli oggetti dei sottotipi devono poter sostituire gli oggetti del tipo base senza rompere la logica. Interface Segregation Principle (ISP) — molte interfacce specializzate sono meglio di un'interfaccia generale. Dependency Inversion Principle (DIP) — dipendi dalle astrazioni, non dalle implementazioni concrete.
Secondo l'analisi SonarQube (2025), la violazione dei principi SOLID si verifica nel 68% dei progetti commerciali. I problemi più comuni sono la violazione di SRP (35%) e ISP (22%). In IT Sectr, implementiamo SOLID nella fase di revisione dell'architettura — questo aiuta a identificare i problemi prima che diventino debito tecnico.
SRP (Principio di Responsabilità Unica) — il più importante e allo stesso tempo il principio SOLID più frequentemente violato. Afferma: una classe dovrebbe avere un solo motivo per cambiare. Se una classe fa troppo, è difficile da testare, modificare e comprendere.
Una violazione tipica è una classe che contemporaneamente elabora dati, li salva nel database e invia notifiche email. L'esempio seguente mostra una violazione di SRP in Kotlin e come risolverla.
// Violazione SRP — la classe fa tre cose diverse
class UserService {
fun registerUser(email: String, name: String) {
// 1. Validazione dati
if (!email.contains("@")) throw IllegalArgumentException("Invalid email")
// 2. Salvataggio nel database
val user = User(email, name)
database.save(user)
// 3. Invio notifica
emailService.sendWelcomeEmail(email, name)
}
}
// Correzione — divisione in tre classi
class UserRegistrationService {
fun register(email: String, name: String) {
UserValidator().validate(email)
val user = User(email, name)
UserRepository().save(user)
NotificationService().sendWelcome(user)
}
}
Nella versione corretta, ogni classe è responsabile del proprio compito: UserValidator — per la validazione, UserRepository — per il salvataggio, NotificationService — per le notifiche. Questo rende il codice testabile e riutilizzabile — puoi sostituire l'implementazione del database senza modificare la logica di validazione.
GRASP (General Responsibility Assignment Software Patterns) — nove principi architetturali per distribuire la responsabilità tra gli oggetti, descritti da Craig Larman. A differenza di SOLID, GRASP risponde alla domanda «quale classe dovrebbe contenere questo metodo?». Pattern chiave: Information Expert, Creator, Controller, Low Coupling, High Cohesion, Polymorphism, Pure Fabrication, Indirection, Protected Variations.
Legge di Demetra (LoD, principio di accoppiamento minimo) — una regola semplice: un oggetto dovrebbe comunicare solo con i suoi vicini immediati. Non si dovrebbe scrivere a.getB().getC().doSomething() — questo crea un forte accoppiamento tra le classi. LoD migliora la riutilizzabilità e semplifica i test.
In IT Sectr, verifichiamo la conformità a LoD durante la Revisione del Codice. Se un metodo «attraversa» tre o più oggetti, è un segnale che l'architettura necessita di semplificazione. La violazione di LoD è uno dei Code Smell più comuni nei grandi progetti.
DRY (Don't Repeat Yourself), KISS (Keep It Simple, Stupid) e YAGNI (You Ain't Gonna Need It) — tre principi architetturali di base noti a ogni sviluppatore. Nonostante la loro semplicità, le violazioni si verificano costantemente.
DRY — non duplicare il codice. Se la stessa logica appare in due punti, estraila in un metodo o classe comune. La duplicazione è la principale fonte di bug: una correzione in un punto viene dimenticata di essere applicata in un altro. DRY non significa che non si possa avere codice simile — l'importante è che la logica di business non venga ripetuta.
KISS — più è semplice, meglio è. Soluzioni complesse con molte astrazioni ed eredità sono spesso eccessive. Inizia con una soluzione semplice e complicala solo quando necessario. YAGNI — non scrivere codice per funzionalità che potrebbero servire «un giorno dopo». Questo porta al gonfiamento della base di codice e all'aumento della complessità di manutenzione.
DRY — non si tratta solo dell'assenza di copia-incolla. È un principio secondo cui ogni pezzo di conoscenza o logica dovrebbe avere una rappresentazione unica e inequivocabile nel sistema. La duplicazione può essere esplicita (codice copiato) e implicita (stessa logica in diversi livelli).
In IT Sectr, utilizziamo metriche di analisi del codice per rilevare la duplicazione. Strumenti come SonarQube e Detekt mostrano la percentuale di codice duplicato. Un valore superiore al 5% è un motivo per il refactoring. Tuttavia, è importante ricordare: DRY non dovrebbe essere raggiunto a costo di astrazioni errate — a volte è meglio lasciare due pezzi di codice simili così come sono se combinarli complicherebbe la comprensione.
Separazione delle Preoccupazioni (SoC) — un principio architetturale in cui un sistema è diviso in parti indipendenti (preoccupazioni), ciascuna che risolve il proprio compito. Un esempio classico è la separazione in livelli: presentazione, logica di business, accesso ai dati. Ogni livello dipende solo dal livello sottostante.
Modularità — il grado in cui un sistema può essere suddiviso in moduli. Un modulo è un gruppo di classi logicamente correlate con un'interfaccia ben definita. I moduli dovrebbero essere debolmente accoppiati (low coupling) e fortemente coesi (high cohesion).
Coesione — una misura di quanto gli elementi all'interno di uno stesso modulo siano correlati tra loro. Alta coesione è buona: una classe fa una cosa e la fa bene. Basso accoppiamento — una misura di quanto i moduli siano indipendenti l'uno dall'altro. Basso accoppiamento è buono: cambiare un modulo non rompe gli altri.
L'architettura ideale è alta coesione e basso accoppiamento. In pratica, ciò significa: una classe contiene metodi che lavorano sugli stessi dati (coesione) e dipende solo da astrazioni, non da implementazioni concrete (accoppiamento). Uno squilibrio porta a «Oggetti Dio» o «codice spaghetti».
Debito tecnico — una metafora introdotta da Ward Cunningham che descrive gli «interessi» che un team paga per decisioni architetturali subottimali e violazione dei principi architetturali. Come il debito finanziario, il debito tecnico può essere intenzionale (abbiamo deciso di fare in fretta, rifaremo dopo) e non intenzionale (cattiva architettura per mancanza di esperienza).
Code Smell — segni superficiali di problemi profondi nel codice. Il termine è stato reso popolare da Martin Fowler nel libro «Refactoring». Code Smell tipici: metodi lunghi, classi grandi, lunghe catene di chiamate, duplicazione del codice, uso eccessivo di commenti (invece di codice chiaro).
In IT Sectr, il debito tecnico viene tracciato in Jira come attività separate. Ogni sprint, dedichiamo il 20% del tempo al refactoring e al rimborso del debito. Il lavoro sistematico con il debito tecnico è l'unico modo per evitare una situazione in cui aggiungere una nuova funzionalità richiede più tempo che svilupparla da zero.
Domande frequenti
Single Responsibility Principle (SRP) — il più importante, poiché la sua violazione porta automaticamente alla violazione degli altri principi. Una classe con più responsabilità è difficile da testare, estendere e mantenere. Inizia con SRP — il resto seguirà.
Coesione — la connessione all'interno di un modulo (più è alta, meglio è). Accoppiamento — la connessione tra moduli (più è basso, meglio è). Una buona architettura mira ad alta coesione e basso accoppiamento.
No, i principi sono linee guida, non leggi assolute. In progetti piccoli o prototipi, un'adesione eccessiva a SOLID può portare a overengineering. È importante trovare un equilibrio tra un'architettura «abbastanza buona» e la velocità di sviluppo.
Usa analizzatori statici (SonarQube, Detekt, ESLint), Revisione del Codice e metriche del codice. Segni di debito: il codice è difficile da testare, i cambiamenti in un punto ne rompono un altro, il tempo per aggiungere una nuova funzionalità aumenta di sprint in sprint. Il refactoring regolare è l'unico modo per controllare il debito.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.