ADR: Action-Domain-Responder, l'MVC ripensato per il web

ADR: Action-Domain-Responder, l'MVC ripensato per il web

# adr# actiondomain# responder
ADR: Action-Domain-Responder, l'MVC ripensato per il webDev-Iadicola

Pillar article su Action-Domain-Responder: come l'evoluzione di MVC proposta da Paul M. Jones risolve i problemi dei controller troppo grandi.

Il problema dell'MVC nel contesto HTTP

MVC e stato progettato per interfacce desktop con interazione continua. Nel web, il ciclo e diverso: una request arriva, viene elaborata, una response parte. Non c'e interazione continua — e un singolo scambio. Eppure forziamo la logica in Controller con molti metodi (index, show, store, update, destroy) che fanno cose completamente diverse. Un UserController con 7 metodi e 7 responsabilità: non e coeso.

ADR (Action-Domain-Responder), proposto da Paul M. Jones nel 2014, e una reinterpretazione di MVC specifica per il web HTTP. L'idea: ogni endpoint e una singola Action (classe) che chiama il Domain e passa il risultato a un Responder.

I tre componenti

Action

L'Action e una classe con un singolo metodo (__invoke()) che gestisce un singolo endpoint. Non UserController con 7 metodi, ma CreateUserAction, ListUsersAction, DeleteUserAction — ognuna con una sola responsabilità. L'Action estrae i dati dalla request, chiama il Domain, e passa il risultato al Responder.

Domain

Il Domain e identico al Model/Service Layer: contiene la business logic, indipendente da HTTP. Riceve dati primitivi, esegue la logica, restituisce risultati o lancia eccezioni. L'Action non contiene logica di business — delega tutto al Domain.

Responder

Il Responder traduce il risultato del Domain in una HTTP response. Se il Domain restituisce un utente, il Responder decide se renderizzare HTML, JSON, XML, o un redirect. La logica di presentazione — quale status code, quali header, quale formato — e nel Responder, non nell'Action.

ADR vs MVC: confronto diretto

  • Controller (MVC): classe con molti metodi. UserController::store(), UserController::index(). Responsabilità multiple.
  • Action (ADR): classe con un metodo. CreateUserAction::__invoke(). Singola responsabilità.
  • View (MVC): template passivo che riceve dati. Non decide il formato della response.
  • Responder (ADR): attivo. Decide status code, header, content-type, e quale template usare in base al risultato.

Esempio pratico in PHP

Un endpoint per creare un utente:

  • CreateUserAction: estrae name ed email dalla request, chiama $this->domain->createUser($name, $email), passa il risultato a $this->responder->created($user) o $this->responder->validationError($errors).
  • UserDomain: valida i dati, crea l'utente nel database, dispara l'evento UserCreated. Nessuna dipendenza da HTTP.
  • UserResponder: se il risultato e un utente, restituisce 201 con JSON o redirect. Se sono errori, restituisce 422 con il form e i messaggi.

Vantaggi concreti

  • Single Responsibility: ogni Action fa una cosa. Niente controller con 500 righe.
  • Testabilita: l'Action e una classe piccola con dipendenze iniettabili. Il test e diretto.
  • Content negotiation: il Responder gestisce i formati (HTML, JSON, XML) senza if nel controller.
  • Navigabilita: cerchi "crea utente"? Apri CreateUserAction. Non devi cercare quale metodo di quale controller.

Quando usare ADR

  • Usa ADR quando i controller crescono troppo e diventano ingestibili
  • Usa ADR per API che devono supportare multipli formati di response
  • Usa ADR quando vuoi massima coesione: una classe per endpoint
  • Non usare ADR se i controller sono piccoli e gestibili: il overhead di una classe per endpoint non si giustifica
  • Non usare ADR se il team e abituato a MVC e il cambio di paradigma creerebbe confusione

ADR non e un sostituto di MVC: e un'evoluzione per il contesto HTTP. Quando i controller crescono e la coesione diminuisce, ADR riporta ordine con una regola semplice: una classe, un endpoint, una responsabilità.


👉 Leggi l'articolo completo su iadicola.it