Clean code: principi pratici per scrivere meno e meglio 🧼
Scrivere buon codice non è una gara a chi conosce più design pattern, ma a chi consegna sistemi chiari, testabili e facili da mantenere. Tre principi aiutano più di altri: DRY, KISS e il sano realismo di “less code, less bugs”. Qui trovi come usarli senza religione, con esempi concreti e una checklist pronta per le PR.
Perché il clean code conta 🧠
Il codice “pulito” non è quello più elegante, ma quello che il tuo collega capisce al primo sguardo (anche quando il collega sei tu tra 6 mesi). Benefici immediati:
- meno bug e regressioni
- cicli di sviluppo più veloci
- costi di manutenzione più bassi
- team meno dipendenti dai “guru del progetto”
DRY: non ripeterti 🧴
Il principio DRY (Don’t Repeat Yourself) dice che ogni informazione dovrebbe avere una sola rappresentazione autorevole nel sistema. Come sintetizzato in modo celebre: “Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.” Formulato da Andy Hunt e Dave Thomas in “The Pragmatic Programmer”, si applica anche a schemi di database, piani di test, build system e documentazione.
Quando applicarlo:
- estrai funzioni/metodi per logiche ripetute
- centralizza validazioni, mapping e formattazioni
- usa un’unica fonte di verità per costanti e configurazioni
Attenzione alle trappole:
- DRY non è “creare una mega-astrazione”. Se per rimuovere due righe duplicate ne introduci cinquanta, hai perso.
- non astrarre troppo presto: la duplicazione moderata nelle prime iterazioni può chiarire il design.
Esempio prima/dopo (Go):
|
|
Nota: per importi monetari reali evita float64 (problemi di arrotondamento binario). Usa rappresentazioni a centesimi (int64), librerie decimal o big.Rat e applica regole fiscali di rounding (es. 2 decimali commerciali, half-up).
KISS: mantienilo semplice 😌
Il principio KISS (Keep It Simple, Stupid) invita a scegliere la soluzione più semplice che funziona. Nato in ambito militare (U.S. Navy, anni ’60), ricorda che la semplicità è spesso l’asset più affidabile. Varianti popolari: Keep it short and simple e Keep it simple and straightforward. Non serve un microservizio per ogni if. Alcune pratiche:
- preferisci funzioni piccole con nomi chiari
- evita ottimizzazioni premature: prima la correttezza, poi la velocità
- riduci gli indici di complessità ciclomatica
- scegli strutture dati semplici finché bastano
Antipattern tipici da evitare:
- over-engineering “perché un giorno potrebbe servire”
- astrazioni a strati che nascondono la logica
- configurazioni iper-dinamiche dove basterebbe un enum
- ignorare YAGNI (You Aren’t Gonna Need It): costruire oggi ciò che non ha ancora validato un bisogno reale
Less code, less bugs: misura e riduci 📉
Meno codice significa meno superfici d’errore, meno dipendenze mentali, meno merge conflittuali. Non è minimalismo estetico: è gestione del rischio. Meno codice significa meno superfici d’errore, meno dipendenze mentali, meno conflitti di merge. Non è minimalismo estetico: è gestione del rischio.
Come ridurre:
- elimina feature morte o mai usate (misura con telemetria)
- elimina funzionalità morte o inutilizzate (telemetria: endpoint non chiamati, flag sempre off)
- sostituisci 200 righe di “plumbing” con una libreria affidabile
- accorpa funzioni quasi identiche con parametri ben tipizzati
- automatizza boilerplate (generator, template, snippet)
Misura ciò che conta:
- complessità per file/modulo
- percentuale di duplicazione
- tempo medio di onboarding su una codebase
Quando NON applicare DRY e KISS alla cieca 🚧
- prototipi ed esplorazione: duplicare può essere più veloce e chiarificatore
- domini ancora instabili: astrazioni premature invecchiano male
- performance critiche: a volte un po’ di “bruttezza” localizzata è l’ottimo globale
Regola d’oro: duplica prima, astrai quando capisci davvero il pattern. Corollario: applica YAGNI — implementa solo ciò che serve ora; il resto quando (e se) emerge un requisito reale.
Checklist per review e refactoring ✅
- il nome della funzione dice davvero cosa fa?
- la funzione / il modulo ha una singola responsabilità chiara (SRP)?
- c’è duplicazione evidente di logica o costanti?
- la soluzione più semplice funzionerebbe lo stesso?
- posso cancellare qualcosa senza che nessuno se ne accorga?
- i test descrivono il comportamento, non l’implementazione?
Ricette veloci 🍝
- estrai funzione: quando vedi 2+ blocchi identici o simili
- sostituisci condizionali annidati con guard clause
- promuovi costanti “magiche” a nomi espliciti
- sposta la logica vicino ai dati che la usano
- aggiungi test prima di toccare codice sospetto
Strumenti utili 🔧
- linters e formatter (golangci-lint, eslint, rubocop)
- analisi duplicazioni (SonarQube, PMD CPD)
- metriche di complessità (gocyclo, complexity-report)
- metriche di complessità (gocyclo per Go, complexity-report per codebase JS)
- refactoring assistito dall’IDE (rename, extract method, inline)
In sintesi 🧾
Applica DRY per rimuovere ripetizioni, KISS per evitare ghirigori inutili e ricordati che meno codice spesso significa meno problemi. Lavora in piccoli passi, misura l’impatto e lascia il codice un po’ migliore di come l’hai trovato.