Architettura Esagonale — Cheat Sheet

Tag: architecture, ddd, ports-and-adapters, software-design, backend, clean-architecture

Livello: intermedio

TL;DR: Isola il dominio di business dal framework e dai dettagli infrastrutturali tramite porte (interfacce) e adattatori (implementazioni concrete). Le dipendenze puntano sempre e solo verso l'interno.

Concetti chiave

Creata da Alistair Cockburn (nota anche come Ports and Adapters).

Nucleo centrale: dominio ed entita' privi di qualsiasi dipendenza tecnologica.

Application layer: orchestra i casi d'uso esponendo la logica di business.

Porte: interfacce che definiscono i contratti di ingresso o di uscita.

Driving Ports (primarie): API esposte dal core per interagire con l'esterno.

Driven Ports (secondarie): SPI definite dal core per accedere a risorse esterne.

Adapters primari: traducono input esterni verso le driving ports (es. controller REST, CLI).

Adapters secondari: implementano le driven ports (es. repository SQL, client HTTP, code).

Inversione delle dipendenze: l'infrastruttura dipende dal core, mai il contrario.

Testabilita' isolata: il core e' testabile al 100% senza database o server web.

Domande tipiche e risposte pronte

Q: Qual e' la differenza tra Driving e Driven Ports?R: Le Driving Ports guidano l'applicazione ricevendo comandi dall'esterno (es. casi d'uso), mentre le Driven Ports sono guidate dall'applicazione per delegare compiti infrastrutturali come persistenza o messaggistica.

Q: Come si relaziona l'architettura esagonale con la Clean Architecture?R: Condividono lo stesso principio: la Dependency Rule. La Clean Architecture di Uncle Bob formalizza ulteriormente i layer concentrici (Entities, Use Cases, Gateways, Web), ma il nucleo concettuale coincide.

Q: Dove risiedono le interfacce dei repository?R: All'interno del dominio o del layer applicativo come Driven Port; l'implementazione concreta (SQL, MongoDB) risiede esclusivamente nel layer infrastrutturale.

Insidie e errori comuni

Far dipendere il dominio da librerie esterne o decoratori ORM (es. TypeORM, Hibernate).

Confondere le porte con gli adattatori inserendo logica di framework dentro le interfacce.

Saltare il layer applicativo chiamando direttamente gli adapter secondari dai controller.

Anemizzazione del modello di business trasferendo tutta la logica negli adapter.

Overengineering su progetti CRUD semplici a basso tasso di logica di business.

Snippet e comandiTypeScript

// 1. Driven Port (Core)
export interface OrderRepositoryPort {
  save(order: Order): Promise<void>;
  findById(id: string): Promise<Order | null>;
}

// 2. Driving Port / Use Case (Application)
export interface CreateOrderUseCase {
  execute(command: CreateOrderCommand): Promise<void>;
}

// 3. Driven Adapter (Infrastructure)
export class PostgresOrderRepository implements OrderRepositoryPort {
  async save(order: Order): Promise<void> {
    await db.query('INSERT INTO orders VALUES ($1, $2)', [order.id, order.total]);
  }
  async findById(id: string): Promise<Order | null> {
    // Implementazione query SQL
  }
}

// 4. Driving Adapter (Infrastructure / Delivery)
export class OrderController {
  constructor(private readonly createOrder: CreateOrderUseCase) {}

  async handlePost(req: Request, res: Response): Promise<void> {
    await this.createOrder.execute(req.body);
    res.status(201).send();
  }
}

Da ripassare

[ ] Mappatura tra DTO di trasporto, command applicativi ed entita' di dominio

[ ] Configurazione della Dependency Injection per il binding porte/adattatori

[x] Regola fondamentale di direzione delle dipendenze (verso l'interno)

[x] Distinzione semantica tra Driving (Inbound) e Driven (Outbound)

Riferimenti

Alistair Cockburn: Hexagonal Architecture (Ports and Adapters Pattern)

Robert C. Martin: Clean Architecture

Eric Evans: Domain-Driven Design (DDD)

Jarvis Interviews
Jarvis