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'eventoUserCreated. 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à.
Top comments (0)