Il problema: il framework che diventa il padrone
In un'applicazione Laravel tipica, la business logic dipende da Eloquent, da Facade, da Request, da Mail. Se Laravel cambia un'API interna, il tuo dominio si rompe. Se vuoi testare la logica senza database, non puoi — e tutto accoppiato. Se un giorno devi migrare a Symfony (succede), devi riscrivere tutto. Il framework dovrebbe essere un dettaglio implementativo, non il fondamento su cui il dominio si regge.
L'Architettura Esagonale, proposta da Alistair Cockburn nel 2005, inverte questa dipendenza: il dominio e al centro, autosufficiente. Il framework, il database, le API esterne sono alla periferia, collegati tramite Ports (interfacce) e Adapters (implementazioni).
Ports and Adapters: la struttura
L'esagono (la forma e metaforica, non geometrica) ha tre zone:
- Core (Domain): al centro. Contiene entita, value objects, regole di business, interfacce dei repository. Non importa nulla dal framework. Zero dipendenze esterne.
-
Ports: interfacce che definiscono come il dominio comunica con l'esterno. Driving ports (primari): come il mondo esterno usa il dominio (es.
OrderServiceInterface). Driven ports (secondari): come il dominio usa il mondo esterno (es.OrderRepositoryInterface,PaymentGatewayInterface). - Adapters: implementazioni concrete dei ports. Un adapter HTTP traduce una request in una chiamata al driving port. Un adapter PostgreSQL implementa il driven port del repository. Un adapter Stripe implementa il driven port del gateway di pagamento.
Esempio teorico: un sistema di pagamenti
Il dominio definisce un'interfaccia PaymentGatewayInterface con charge(Money $amount, Card $card): PaymentResult. Il dominio non sa se il pagamento passa da Stripe, PayPal o Satispay. Sa solo che esiste un gateway che accetta un importo e una carta e restituisce un risultato.
-
StripePaymentAdapterimplementa l'interfaccia usando l'SDK di Stripe -
PayPalPaymentAdapterimplementa la stessa interfaccia usando l'API PayPal -
FakePaymentAdapterimplementa l'interfaccia per i test — approva sempre, senza rete
Cambiare gateway di pagamento richiede una sola modifica: quale adapter viene iniettato. Il dominio — con tutte le sue regole su limiti di importo, retry, idempotenza — non cambia di una riga.
Hexagonal vs MVC: non si escludono
MVC e Hexagonal non sono alternative: sono complementari. MVC organizza il flusso HTTP (request → controller → view). Hexagonal organizza la struttura interna dell'applicazione (dominio → ports → adapters). Un'applicazione può usare MVC per il layer HTTP e Hexagonal per la struttura del dominio.
In pratica: il Controller (MVC) e un adapter HTTP (Hexagonal) che traduce la request in una chiamata a un driving port (l'interfaccia del Service). Il Repository Eloquent e un adapter di persistenza che implementa un driven port (l'interfaccia del Repository definita nel dominio).
La regola della dipendenza
La regola fondamentale dell'Hexagonal Architecture e la direzione delle dipendenze: tutto punta verso il centro. Gli adapter dipendono dai ports. I ports dipendono dal dominio. Il dominio non dipende da nulla. Mai una use Illuminate\... dentro una classe di dominio. Mai un use Doctrine\... in un'entita.
Questa regola sembra rigida ma produce un beneficio concreto: puoi testare l'intero dominio con mock dei ports — senza database, senza HTTP, senza servizi esterni. I test girano in millisecondi e testano la logica pura.
Quando usare l'Hexagonal Architecture
- Usa Hexagonal quando la business logic e complessa e deve sopravvivere al framework
- Usa Hexagonal quando il progetto ha una vita lunga (anni) e il framework potrebbe cambiare
- Usa Hexagonal quando la testabilita del dominio e una priorità
- Non usare Hexagonal per CRUD semplici: il layer di astrazione aggiuntivo non paga il costo
- Non usare Hexagonal se il team non e pronto: la curva di apprendimento e reale
L'Hexagonal Architecture non e una moda: e una risposta strutturale al problema dell'accoppiamento con il framework. Quando il dominio e al centro e il framework e ai margini, il codice che conta — la business logic — e protetto, testabile e portabile.
Top comments (0)