Quando un'app Flutter supera le poche decine di schermate, la classica divisione per tipo (screens/, models/, services/) smette di funzionare: ogni modifica tocca mezza codebase, i merge conflict esplodono e nessuno sa più chi può chiamare cosa.
La risposta è un'architettura a feature (feature-first) con confini espliciti tra moduli: ogni funzionalità è una cartella autonoma con i suoi layer interni, espone una piccola API pubblica e nasconde tutto il resto. I confini non restano però nella documentazione: in questo tutorial li rendiamo eseguibili, con regole di lint e un controllo automatico in CI che fa fallire la build se qualcuno importa il file sbagliato.
Alla fine avrai:
- una struttura
lib/features/<feature>/{domain,data,presentation}piùcore/eshared/; - un barrel file per feature che funge da facciata pubblica;
- una composition root che collega le implementazioni ai contratti;
- routing modulare con
go_routerdelegato alle singole feature; - regole di dipendenza applicate con
import_linte uno script di verifica.
Prerequisiti: buona conoscenza di Dart moderno (classi sealed,
abstract interface class), di un gestore di stato (useremo Riverpod) e dei fondamenti di testing.