Come preparo un’architettura per crescere senza riscrivere tutto dopo un anno
Come preparo un’architettura per crescere senza riscrivere tutto dopo un anno

Se hai lavorato in una startup, in una PMI o in un team “sempre in emergenza”, lo sai già:
all’inizio vai veloce. Funziona. Spedisci. Chiudi ticket.
Poi dopo 6 mesi (a volte 3) ti accorgi che ogni feature nuova costa il doppio.
Dopo un anno ogni modifica è chirurgia a cuore aperto.
E spesso finisce con la frase che nessuno vuole dire ad alta voce:
“Ok, dobbiamo riscrivere tutto.”
Questo articolo è un antidoto pragmatico a quella situazione.
Non parlo da eroe senza macchia.
Sono il primo ad aver “spaghettificato”. Più di una volta.
E proprio perché ho pagato quel debito tecnico con interessi da usura, oggi ti dico:
non ti serve fare architetture perfette, ti serve fare architetture che reggono.
Con qualche abitudine semplice e un’ora in più ogni tanto, puoi risparmiarti centinaia di ore dopo.
Il problema: quando non hai tempo, “spaghettifichi” (e lo fai per buone ragioni)
La spaghettificazione non nasce perché siamo incompetenti.
Nasce perché siamo sotto pressione.
- devi consegnare ieri
- non hai tempo di mettere ordine
- non sai se questa feature verrà usata davvero
- il business ti cambia la priorità ogni 3 giorni
- magari sei pure in sotto-organico
E quindi fai la cosa più umana del mondo:
- metti la logica “dove capita”
- duplichi un pezzetto di codice “perché ci metto 5 minuti”
- fai una scorciatoia “tanto poi la sistemiamo”
- i test? “dopo”
Il problema è che quel “poi” arriva sempre quando il sistema è più grande, più fragile e più costoso da cambiare.
L’obiettivo non è scalare: è evitare la riscrittura
Quando si parla di architettura “per crescere”, molti pensano subito a:
- microservizi
- event-driven
- CQRS
- Kubernetes
- service mesh
Ma la maggior parte dei progetti non muore perché non ha Kubernetes.
Muore perché:
- nessuno capisce dove sta la logica
- ogni change rompe qualcosa di imprevedibile
- il riuso è impossibile
- fare refactoring costa troppo
- onboarding nuovi dev = settimane di panico
Quindi il focus vero è:
rendere il sistema modificabile senza paura.
La regola d’oro: disaccoppiamento logico, non per forza “distribuito”
Qui c’è un concetto che salva progetti interi.
Disaccoppiare non significa “spezzare tutto in 10 servizi”.
Significa prima di tutto una cosa più semplice:
✅ Separare le responsabilità a livello logico
Esempio (molto comune):
- Controller / Handler: parsing input e risposta
- Use case / Service: logica applicativa
- Repository / Gateway: accesso a DB e API esterne
- Domain: regole e strutture centrali
Non è “architettura da libro”. È un modo per evitare che:
- query SQL finiscano dentro i controller
- logica di business sia sparpagliata in 12 file
- chiamate esterne siano mischiate con validazioni e calcoli
Questo disaccoppiamento è quello che ti permette, dopo un anno, di fare:
- refactoring senza riscrivere
- test senza diventare matto
- nuove feature senza rompere il resto
Il trucco che costa poco tempo: progettare i confini, non tutto il castello
Non serve disegnare un’architettura completa.
Serve mettere confini chiari dove la spaghettificazione esplode più facilmente.
I 3 confini “salva-progetto” sono:
1) Confine tra logica e infrastruttura
La logica applicativa non dovrebbe sapere:
- se i dati arrivano da MySQL o Postgres
- se stai chiamando un REST o un gRPC
- se sei in sync o async
2) Confine tra dominio e UI/API
HTTP non deve diventare la tua architettura mentale. Le entità e i casi d’uso devono avere senso anche senza REST.
3) Confine tra moduli che evolvono a velocità diversa
Esempio: fatturazione e tracking spedizioni. Magari entrambi nel “prodotto”, ma cambiano con frequenze e rischi diversi.
Riutilizzo del codice: non copiare/incollare, estrai il concetto
Il riuso è un tema noioso.
Sembra una predica da community tech anni 2000.
Eppure il costo nascosto del copia/incolla è devastante, perché:
- correggi un bug in un punto e lo lasci in altri 3
- modifichi un flusso e ne rompi uno “gemello”
- ogni feature diventa un giro turistico nel repo
La soluzione pragmatica non è “fare una libreria interna perfetta”.
È:
✅ creare punti di riuso molto semplici
Tipo:
- package/module
commonsolo per utilità stabili - componenti
lib/per codice condiviso tra moduli - funzioni “pure” (senza I/O) che sono testabili e riusabili
Un buon indicatore è questo:
Se lo stesso concetto lo scrivi 2 volte, probabilmente tra 1 mese lo scriverai 5.
Test “per quanto possibile”: non serve coprire tutto, serve coprire ciò che fa male quando si rompe
Altro tema ultra-trito: “bisogna fare i test”.
Sì, ma detta così non aiuta nessuno. Perché quando sei in pressione, la frase “fai i test” compete con “devo consegnare”.
Quindi la versione vera è:
✅ fai test dove riducono davvero il rischio
Priorità pratica:
Test su funzioni pure
roba che prende input → produce output
(sono veloci, affidabili e costano poco)Test sui casi d’uso principali
i flussi che generano soldi o disastri se fallisconoTest su bug che hai già pagato
se un bug ti è costato 6 ore una volta, metti un test e non lo rivedi più
E poi una frase che a me ha salvato la vita:
“Un test non serve a dimostrare che funziona.
Serve a farti cambiare codice senza paura.”
Repo unica vs multi repo: spesso monorepo è meglio (soprattutto all’inizio)
Tema delicato, perché c’è religione attorno.
Ma nella pratica, per tantissimi team piccoli e medi:
✅ una repo unica è più efficiente
Perché ti dà:
- visibilità immediata del sistema
- refactoring cross-modulo più semplice
- un solo posto dove cercare
- onboarding più veloce
- versioning più lineare
Il multirepo ha senso quando hai davvero:
- team indipendenti
- rilasci indipendenti
- ownership separate
- policy di accesso diverse
Ma il multirepo troppo presto porta spesso a:
- duplicazione di codice
- dipendenze incrociate ingestibili
- versioni non compatibili
- “non posso cambiare X perché rompe Y che vive altrove”
Monorepo non è “più bello”. È solo più pragmatico finché il costo organizzativo di separare non è giustificato.
La cosa più importante: investire un’ora adesso per non spenderne cento dopo
Lo so: tutto quello che ho scritto sembra ovvio. Sembra roba detta da decenni.
Ma io continuo a vedere team interi (anche forti) fare fatica a:
- fermarsi
- respirare
- dire “ok, investiamo un’ora in più”
E il problema è proprio lì: non è che non sappiamo cosa è giusto, è che non ci concediamo il tempo per farlo.
Io sono stato il primo a non farlo. E mi sono trovato poi a pagare settimane di dolore:
- feature che richiedono giorni invece che ore
- bug imprevedibili
- paura di toccare pezzi delicati
- refactoring rimandati fino alla riscrittura
Quindi se posso lasciarti 3 regole finali, sono queste:
- Separare la logica dall’I/O è la forma più economica di architettura
- Riuso = meno bug e meno lavoro invisibile
- Test piccoli e mirati battono “zero test” e battono anche “test perfetti mai finiti”
Non serve fare i puristi.
Serve fare scelte che ti lasciano respirare tra 6 mesi.
Perché crescere è bello…
ma crescere e dover riscrivere tutto ogni anno è una condanna.
Valerio's Cave