Action Domain Responder
Action Domain Responder is an alternative to the "Model 2" misappropriation (for server-side over-the-network request/response interfaces) of the original Model View Controller user interface pattern (for client-side in-memory graphical user interfaces). ADR is a user interface pattern specifically intended for server-side applications operating in an over-the-network, request/response environment.
Aligning expectations and factoring concerns away from the modern derivations of "Model 2" MVC toward Action Domain Responder is not difficult. Here is one way of working through the change in approach.
Model Versus Domain
There are few if any significant differences here, other than that the Responder does not interact with the Domain. The Responder might use domain objects like entities and collections, perhaps wrapped in a Domain Payload, but only for presentation purposes. It does not itself request new information from the Domain or send information back to the Domain.
Thus, the main difference is in the name. Using the word Domain instead of Model is intended to make implementors think of PoEAA domain logic patterns such as Service Layer and Transaction Script, or domain-driven design patterns such as Application Service, or Use Case.
Further, remember that in the original MVC, there are lots of continuously presented models. In "Model 2" MVC, the Model is almost completely undefined. In ADR, the Domain is defined as an entry point into whatever does the domain work (Transaction Script, Service Layer, Application Service, etc.).
View Versus Responder
In a "Model 2" MVC system, a Controller method will usually generate body content via a View (e.g., a Template View or a Two Step View). The Controller will then inject the generated body content into the response. The Controller action method may also manipulate the response directly to set the status code, headers, cookies, and so on.
Some Controller action methods may present alternative content-types for the same domain data. Because these alternatives may not be consistent over all the different methods, this leads to the presentation logic being somewhat different in each method, each with its own preconditions.
However, in a server-side web application, the presentation being delivered as output is not merely the body of the HTTP Response. Instead, the presentation is the entire HTTP Response, including the HTTP status, headers, cookies, and so on. As such, to do any sort of HTTP Response building work in a Controller is to mix concerns inappropriately.
To fully separate the presentation logic, each Action in ADR invokes a Responder to build the HTTP Response. The Responder is entirely in charge of setting headers, setting the body content, picking content types, rendering templates, and so on.
Note that a Responder may incorporate a Template View, Two Step View, Transform View, or any other kind of body content building system. Note also that a particular Responder may be used by more than one Action. The point here is that the Action leaves all header and content work to the Responder, not that there must be a different Responder for each different Action.
In trivial cases, it may be reasonable to collect different sets of Responder logic, e.g., corresponding to the presentation logic for different Actions, into a single class as well. Doing so may be considered a valid but degenerate or inferior implementation of the pattern.
Controller Versus Action
In common usage, most "Model 2" MVC Controller classes contain several methods corresponding to different actions. Because these differing action methods reside in the same Controller, the Controller often needs additional wrapper logic to deal with each action method properly, such as pre- and post-action hooks.
Additionally, different action methods may have different dependencies, leading to over-long constructors and/or attempts at "action injection" of dependencies. Notable exceptions here are:
micro-frameworks, where each Controller is an individual closure or invokable object, mapping more closely to a single Action (cf. Slim)
Hanami, where "an action is an object, while a controller is a Ruby module that groups them."
In contrast to Controller classes with many action methods, a canonical Action is implemented as an individual class with only one main method, or a closure.
The Action interacts with the Domain in the same way a Controller interacts with a Model but does not interact with a View or template system. It sends data to the Responder and invokes it so it can build the HTTP Response.
These limitations on the Action give it a well-defined set of responsibilities. It does only these things:
- collects input from the HTTP Request (if needed);
- invokes the Domain with those inputs (if required) and retains the result;
- invokes the Responder with any data the Responder needs to build an HTTP Response (typically the HTTP Request and/or the Domain invocation results).
All other concerns, including all forms of input validation, error handling, and so on, are therefore pushed out of the Action and into the Domain (for domain logic concerns) or the Responder (for presentation logic concerns).
In trivial cases, it may be acceptable to collect different sets of Action logic into a class as methods, provided they keep the Domain and Responder separations in place. Doing so may be considered a valid, but degenerate or inferior, implementation of the pattern.
In hindsight, it turns out that ADR is an example of the Separated Presentation meta-pattern, one that is finely tuned to server-side applications. Fowler writes:
[Separated Presentation] is a form of layering, where we keep presentation code and domain code in separate layers with the domain code unaware of presentation code.
To use it you begin by looking at all the data and behavior in a system and looking to see if that code is involved with the presentation. Presentation code would manipulate ...
- GUI widgets and structures in a rich client application,
- HTTP headers and HTML in a web application,
- or command line arguments and print statements in a command line application.
We then divide the application into two logical modules with all the presentation code in one module and the rest in another module.
Further layering is often used to separate data source code from domain (business logic), and to separate the domain using a Service Layer.
(Lightly edited for emphasis and clarity.)
Of course, everything comes with pros and cons. What are the tradeoffs of the ADR pattern?