Permalink
Switch branches/tags
Nothing to show
Find file Copy path
86795d1 Feb 16, 2018
2 contributors

Users who have contributed to this file

@pmjones @maddcatter
56 lines (29 sloc) 5.62 KB

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 MVC 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 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 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 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 then injects the generated body content into the response. The Controller action method will manipulate the response directly to 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. The presentation is the entire HTTP response, including the HTTP status, headers, cookies, and so on. As such, doing any sort of HTTP response building work in a Controller indicates a mixing of concerns.

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 a particular Responder may be used by more than one Action. The point here is 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 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 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 an ADR system, a single Action is the main purpose of a class or closure. Each Action would be represented by a individual class or 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 make it a very simple bit of logic. It does only these things:

  1. collects input from the HTTP request (if needed);
  2. invokes the Domain with those inputs (if required) and retains the result;
  3. 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 logic, 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 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.

Tradeoffs

Of course, everything comes with pros and cons. What are the tradeoffs of the ADR pattern?