Architettura Esagonale — Cheat Sheet

Tag: architettura, hexagonal-architecture, ports-and-adapters, ddd, backend, clean-architecture

Livello: intermedio

TL;DR: Disaccoppia il dominio applicativo da framework e infrastruttura tramite porte e adattatori, rendendo la logica di business pura, testabile e intercambiabile.

Concetti chiave

Il core contiene le entita' e la logica di business pura, senza dipendenze esterne.

La regola di dipendenza punta sempre verso l'interno: l'infrastruttura dipende dal core.

Una porta e' un'interfaccia che definisce il contratto di interazione con il dominio.

Le porte primarie o driving espongono i casi d'uso verso l'esterno.

Le porte secondarie o driven definiscono i servizi infrastrutturali richiesti dal core.

Gli adattatori primari convertono richieste esterne in chiamate al dominio applicativo.

Gli adattatori secondari implementano le porte secondarie verso database, code e servizi terzi.

L'inversione delle dipendenze garantisce l'isolamento completo del dominio tecnologico.

Permette di testare l'intera logica di business sostituendo l'infrastruttura con mock o fake.

La forma a esagono rappresenta visivamente molteplici canali di interazione simmetrici.

Domande tipiche e risposte pronte

Q: Qual e' la differenza concettuale tra porta e adattatore?R: La porta e' l'interfaccia astratta definita dal dominio per stabilire un contratto, mentre l'adattatore e' l'implementazione concreta che dialoga con la tecnologia specifica.

Q: Come si distinguono driving ports e driven ports durante l'esecuzione?R: Le driving port guidano l'applicazione e sono invocate dai controller esterni, mentre le driven port sono chiamate dal dominio verso risorse esterne come database o broker.

Q: Come gestisci le transazioni su database senza violare l'isolamento del dominio?R: Incapsulo la transazione in un middleware dell'adattatore o uso un'interfaccia UnitOfWork dichiarata nel dominio e implementata nell'infrastruttura.

Insidie e errori comuni

Far dipendere le entita' di dominio da annotazioni ORM o librerie di terze parti.

Far trapelare DTO HTTP o modelli di persistenza all'interno della business logic.

Dichiarare le interfacce delle porte nel layer infrastrutturale anziche' nel core.

Applicare l'architettura esagonale a semplici operazioni CRUD aggiungendo complessita' ingiustificata.

Confondere il controller HTTP con la driving port invece che trattarlo come adattatore primario.

Snippet e comandiTypeScript

// Porta secondaria (definita nel dominio)
export interface OrderRepositoryPort {
  save(order: Order): Promise<void>;
  findById(id: string): Promise<Order | null>;
}

// Porta primaria / Caso d'uso (nel core applicativo)
export interface CreateOrderUseCase {
  execute(command: CreateOrderCommand): Promise<string>;
}

// Adattatore secondario (infrastruttura)
export class PostgresOrderAdapter implements OrderRepositoryPort {
  constructor(private readonly db: DatabaseClient) {}

  async save(order: Order): Promise<void> {
    await this.db.query("INSERT INTO orders ...", [order.id, order.total]);
  }

  async findById(id: string): Promise<Order | null> {
    const record = await this.db.query("SELECT * FROM orders WHERE id = $1", [id]);
    return record ? OrderMapper.toDomain(record) : null;
  }
}

Da ripassare

[ ] Mappatura bidirezionale esplicita tra modelli di dominio e modelli di persistenza

[ ] Pattern Unit of Work per la gestione delle transazioni atomiche

[x] Differenza architetturale tra porte primarie (driving) e secondarie (driven)

[x] Applicazione del Dependency Inversion Principle alle porte esterne

Riferimenti

Alistair Cockburn — Hexagonal Architecture (Ports and Adapters, 2005)

Robert C. Martin — Clean Architecture: A Craftsman's Guide to Software Structure and Design

Eric Evans — Domain-Driven Design: Tackling Complexity in the Heart of Software

Jarvis Interviews
Jarvis