Domain Logic and Email Templates

From an email conversation with a reader:

Hi Paul,

I’ve been following your writing and examples about the ADR pattern for some time now. It’s taken me awhile to wrap my head around it but ADR has really added a lot of structure to my code and I’m thankful for your work!

One dilemma that I’ve been struggling with is how to organize emails that are sent out by my service classes. Currently my business logic dictates when to send an email and most of them contain html and text templates. It just feels wrong to include those email templates within the Domain. Do you have any recommendations? Any help you can provide would be greatly appreciated.

In a somewhat related question – Recently I’ve been organizing my “views” folders within the folders of their parents (Http, Mail). I think I based it on your ADR example on github. Do you still prefer this method or do you lean towards organizing within a “resources” folder?

My intuition is that you are right to keep the email templates out of the domain.

In a way, sending an email as part of a web request/response cycle is like sending two responses: the normal HTTP response, and the email response. With that in mind, it might make sense to think of the HTML + Text email templates as part of a presentation layer. Or, as a combination of infrastructure (the email-sending client) plus presentation (the templates). That would be how to think about the separation of concerns there.

Here’s an example of what that separation of concerns might look like in a package directory structure:

resources/
    templates/
        web/
            # web page templates
        email/
            message-1/
                message-1.html
                message-1.txt
            message-2/
                message-2.html
                message-2.txt
src/
    Domain/
        AppService/
            FooAppService.php
            BarAppService.php
        EmailInterface.php
        # ... other domain classes
    Infrastructure/
        DataSource/
            # ... mappers, tables, etc
        Emailer.php # implements Domain\EmailInterface
    Web/
        Foo/
            FooAction.php
            FooResponder.php
        Bar/
            BarAction.php
            BarResponder.php

The specifics of directory structure are not important, as long as you see that the Emailer class is separated from the Domain application services (or use cases, or whatever).

The Emailer class, for its part, might be a facade [1] that coordinates between a “real” emailer (e.g. Swiftmailer or PhpMailer) and a template class, to put together and then send the email. You could configure the Emailer class with the template location (resources/templates/email/*) and inject it into your application service (which depends on the EmailInterface).

Now, sending emails inline as part of the web request might be fine in a lower-traffic situation. But as volume scales up, this kind of separation will make it easy to extract all email-sending to a workers. Then the Emailer can queue emails to the workers instead of sending them inline with the web request; the email-sending can become the job of a queue worker, and the template work will go there instead.

As far as where to put templates for views:

The extended example ADR code on GitHub is a few years old at this point. I still think it’s a reasonable setup, especially for people transitioning out of pseudo-MVC toward ADR, but it might do well to receive an update (or some examples of variations).

I don’t prefer any particular method or structure on where to put templates. Sometimes it makes sense to keep templates near the things using them, sometimes it makes sense to collect them all one place. The needs of the system, and the prior experiences of the developer(s), will be the deciding factor as far as I’m concerned. I had PHP-PDS on the brain when I replied, so the pds/skeleton with its “resources” directory was at hand.


[1] A real facade, not a Laravel one. 😉

Controllers and Domain Exceptions

A few months ago I had a great email conversation with a correspondent about how to handle business logic exceptions in his controller code. His message follows, lightly edited for brevity and clarity:

I think controller has single responsibility – to mediate communication between caller’s context and actual business logic services. (I believe business logic services should be unaware of caller’s context, be it HTTP request or CLI.)

Given that services should be unaware of who called them, they should not throw HTTP-specific exceptions. So instead of throwing a Symfony HttpNotFound Exception, the service would throw ObjectNotFound (which is HTTP agnostic) in cases where DB record could not be found.

Yet at the same time the logic that converts exceptions to HTTP responses expects HTTP-specific Symfony exceptions. This means that the exception thrown by service needs to be transformed into Symfony exception.

One of solutions I see to this is that the controller could take that responsibility. It would catch domain exceptions thrown by service and wrap them into appropriate HTTP exceptions.

class FooController
{
    public function fooAction()
    {
        try {
            $this->service->doSomething('foo');
        } catch (ObjectNotFound $e) {
            throw new NotFoundHttpException('Not Found', $e);
        } catch (InvalidDataException $e) {
            throw new BadRequestHttpException('Invalid value', $e);
        } // ...
    }
}

The downside I see with this approach is that if I have many controllers I will have code duplication. This also could lead to big amount of catch blocks, because of many possible exceptions that could be thrown.

Another approach would be to not have try/catch blocks in controller and let the exceptions thrown by service bubble up the stack, leaving the exception handling to exception handler. This approach would solve the code duplication issue and many try/catch block issue. However, because the response builder only accepts Symfony exceptions, they would need to be mapped somewhere.

It also feels to me that this way the controller is made cleaner, but part of controllers responsibility is delegated to something else, thus breaking encapsulation. I feel like it’s controllers job to decide what status code should be retuned in each case, yet at the same time, cases usually are the same.

I truly hope you will be able to share your thoughts on this and the ways you would tackle this.

If you find yourself in this situation, the first question to ask yourself is, “Why am I handling domain exceptions in my user interface code?” (Remember: Model-View-Controller and Action-Domain-Responder are user interface patterns; in this case, the user interface is composed of an HTTP request and response.) Domain exceptions should be handled by the domain logic in a domain-appropriate fashion.

My correspondent’s first intuition (using domain-level exceptions, not HTTP-specific ones) has the right spirit. However, instead of having the domain service throw exceptions for the user interface controller to catch and handle, I suggest that the service return a Domain Payload with domain-specific status reporting. Then the user interface can inspect the Domain Payload to determine how to respond. I expand on that approach in this post.

By way of example, instead of this in your controller …

class FooController
{
    public function fooAction()
    {
        try {
            $this->service->doSomething('foo');
        } catch (ObjectNotFound $e) {
            throw new NotFoundHttpException('Not Found', $e);
        } catch (InvalidDataException $e) {
            throw new BadRequestHttpException('Invalid value', $e);
        } // ...
    }
}

… try something more like this:

class FooController
{
    public function fooAction()
    {
        $payload = $this->service->doSomething('foo');
        switch ($payload->getStatus()) {
            case $payload::OBJECT_NOT_FOUND:
                throw new NotFoundHttpException($payload->getMessage());
            case $payload::INVALID_DATA:
                throw new BadRequestHttpException($payload->getMessage());
            // ...
        }
    }
}

(I am not a fan of using exceptions to manage flow control; I’d rather return a new Response object. However, I am trying to stick as closely to the original example as possible so that the differences are more easily examined.)

The idea here is to keep domain logic in the domain layer (in this case, a service). The service should validate the input, and if it fails, return a “not-valid” payload. The service should catch all exceptions, and return a payload that describes the kind of error that occurred. You can then refine your controller to examine the Domain Payload and handle it however you want.

Using a Domain Payload in this way is not a huge leap. Essentially you move from a try/catch block and exception classes, to a switch/case block and status constants. What’s important is that you are now handling domain-level exceptions in the domain and not in the user interface layer. You are also encapsulating the status information reported by the domain, so that you can pass the Domain Payload object around for something other than the controller to inspect and handle.

Encapsulation via Domain Payload opens the path to a more significant refactoring that will help reduce repetition of response-building logic across many controller actions. That next refactoring is to separate out the response-building work to a Responder, and use the Responder in the controller action to return a response. You can then pass the Domain Payload to the Responder for it to handle.

class FooController
{
    public function fooAction()
    {
        $payload = $this->service->doSomething('foo');
        return $this->responder->respond($payload);
    }
}

class FooResponder
{
    public function respond($payload)
    {
        switch ($payload->getStatus()) {
            case $payload::OBJECT_NOT_FOUND:
                throw new NotFoundHttpException('Not Found', $e);
            case $payload::INVALID_DATA:
                throw new BadRequestHttpException('Invalid value', $e);
            // ...
        }
    }
}

Once you do that, you’ll realize the majority of your response-building logic can go into a common or base Responder. Custom cases can then be be handled by controller- or format-specific Responders.

And then you’ll realize all your Action logic is all pretty much the same: collect input from the Request, pass that input to a Domain-layer service to get back a Domain Payload result, and pass that result to a Responder to get back a Response. At that point you’ll be able to get rid of controllers entirely, in favor of a single standardized action handler.

“Action Injection” As A Code Smell

Circumstance has conspired to put Action Injection discussions in front of me multiple times in the past few days. Having seen the approach several times before, I have come to think that if Action Injection is the answer, you might be asking the wrong question. I find it to be a code smell, one that indicates the system needs refactoring or reorganizing.

Action Injection …

As far as I can tell, the term “Action Injection” originates with Alex Meyer-Gleaves in a 2010 article on ASP.NET MVC development. He summarizes Action Injection in this way:

Your [controller class] constructor is provided the dependencies [by the DI container] that are shared by all actions in your controller, and each individual action [method] can request any additional dependencies that it needs.

To expand on that, let’s say you have a controller class with several action methods in it. You realize after a while that the different action methods have slightly different dependencies. For example, some of the methods need a logger, while others need a template system, or access to the router. But you don’t want to pollute the controller class constructor with these method-specific dependencies, since those dependencies will be used only if that particular action method gets invoked.

With Action Injection, when you pull the controller from your dependency injection container and call a particular action method, the DI container will automatically pass the right dependencies for the method call arguments. Voila: now you can define all the common dependencies as parameters on the controller constructor, and all the action-specific dependencies as parameters on the method definition.

You can see a PHP-specific description of the problem, with Action Injection as the solution, in this Symfony pull request:

https://github.com/symfony/symfony/pull/21771

You can also hear about it in this presentation from Beau Simensen, from around 32:21 to 34:31:

https://www.youtube.com/watch?v=JyrgwMagwEM&feature=youtu.be&t=1941

The Yii and Laravel containers appear to support this behavior as well, using the term “method injection.” (I think that’s a misnomer; the term appears overloaded at best, as sometimes it may mean “methods called by the DI container at object-creation time” instead of “resolving method arguments at call-time”.) Perhaps other DI containers support Action Injection as well.

… As A Code Smell

The explicit reason for using Action Injection is “to reduce dependencies or overhead” when constructing an object. You don’t want to have to pass in a dozen dependencies, when only three are used in every method, and the others are used only in specific methods.

But the fact that your controller has so many dependencies, used only in some cases and not in others, should be an indicator that the class is doing too much. Indeed, it’s doing so much that you cannot call its action methods directly; you have to use the dependency injection container not only to build the controller object but also to invoke its action methods.

Reorganizing To Avoid Action Injection

What approaches exist to help you avoid the Action Injection code smell? I assert that the better solution is to change how you organize your controller structures.

Instead of thinking in terms of “a controller class with action methods,” think in terms of “a controller namespace with action classes.” Actions are the targets for your routes anyway, not controller classes per se, so it makes sense to upgrade actions to “first-class” elements of the system. (Think of them as single-action controllers, if you like.)

Thus, instead of …

<?php
namespace App;

class BlogController {
    public function browse() { ... }
    public function read() { ... }
    public function edit() { ... }
    public function add() { ... }
    public function delete() { ... }
}

… reorganize to:

<?php
namespace App\BlogController;

class Browse { ... }
class Read { ... }
class Edit { ... }
class Add { ... }
class Delete { ... }

Then the DI container can use plain old constructor injection to create the Action object, with all of its particular dependencies. To invoke the Action, call a well-known method with the user input from the route or request. (I like __invoke() but others may prefer exec() or something similar.)

In fact, I realized only after watching the Simensen clip a second time that his example is a single-action controller in everything but name. His example code was this …

<?php
class Home {
    /**
     * @Route("/myaction", name="my_action")
     */
    public function myAction(
        Request $request,
        Router $router,
        Twig $twig
    ) {
        if (!$request->isMethod('GET')) {
            return new RedirectResponse(
                $router->generateUrl('my_action'),
                301
            );
        }

        return new Response(
            $twig->render('mytemplate.html.twig')
        );
    }
}

… but the controller action method parameters might just as well be Action class constructor parameters:

<?php
namespace Home;

class MyAction {

    public function __construct(
        Request $request,
        Router $router,
        Twig $twig
    ) {
        $this->request = $request;
        $this->router = $router;
        $this->twig = $twig;
    }

    /**
     * @Route("/myaction", name="my_action")
     */
    public function __invoke() {
        if (!$this->request->isMethod('GET')) {
            return new RedirectResponse(
                $this->router->generateUrl('my_action'),
                301
            );
        }

        return new Response(
            $this->twig->render('mytemplate.html.twig')
        );
    }
}

(UPDATE: That example code looks like it originates from Kevin Dunglas and his DunglasActionBundle — which is itself a single-action controller implementation for Symfony.)

Action Domain Responder

For more on this organizational structure, please read my Action Domain Responder offering. ADR is a refinement of MVC that is tuned specifically to server-side request/response over-the-network interactions.

But you need not go full ADR to avoid Action Injection. Just using single-action controllers will do the trick. Then you can have well-factored single-responsibility controller classes that do not require a DI container in order to call their action methods, and Action Injection becomes a thing of the past.

Toward A Better Separation of Session Behaviors in PHP

Andrew Shell asks, What is the best way to handle sessions with ADR? (The problem is that the built-in PHP session extension combines the concerns of reading input, managing storage, and sending output; the solution is a domain-layer session-data manager.)

I’ve reached a point with a couple of my Radar projects where I need to add a login and set permissions. I’m trying to figure out the best way to handle this, especially with PSR-7 and ADR. …

[In Action-Domain-Responder] it’s ok to read the session cookie in an Input class, and it’s ok to write the cookie in a Responder class, but pretty much everything else should be in the Domain layer. …

[In the Domain layer,] Cadre.DomainSession takes a session id (or generates one) and loads session data from storage. It’s smart enough to handle regenerating session ids and cleaning up expired sessions.

Read the whole article at FutureProof PHP for examples and links!

UPDATE: Reddit discussion.

“A False Sense of Simplicity”

These year-old posts from Piotr Solnica are about Ruby On Rails …

… but the experiences related therein should be valuable to anyone using or building a full-stack PHP framework. (I can imagine it applying to CMSes as well.)

Does this story from Piotr remind you of any framework-based project you’ve worked on in PHP?

Once, I joined an existing project. It was a huuuuge app which was running an on-line shopping community website. Complicated sales model, complicated promotions, complicated product setups, coupons, user groups, messages – it had it all. I joined them to help ship a few new features. One of my early tasks was to … add a link to something on some page. It took me few days to add this stupid link. Why? The app was a big ball of complex domain logic scattered across multiple layers with view templates so complicated, it wasn’t even simple to find the right template where the link was supposed to be added. Since I needed some data in order to create that link, it wasn’t obvious how I should get it. There was a lack of internal application APIs and relying on ActiveRecord exclusively made it extremely difficult.

I’ve consulted on projects like that more than once. Indeed, the posts might well have been subtitled “The Perils of Convenience-Oriented Development”:

People are attracted by Rails because it gives you a false sense of simplicity, whereas what really happens is that complexity is being hidden by convenient interfaces.

Read both of the posts, and see if you can relate. They just reinforce to me that this is what to expect when you embed your domain logic in your user interface logic.

Remember: with server-side web-based applications, the user interface is the HTTP request and response. Any code that reads from the request, or that writes to the response, is part of the user interface. Putting your domain logic in the user interface is convenient to start with, but as soon as things become even a little bit complex, that “convenience” becomes a burden.

WikiMedia, Clean Architecture, and ADR

tl;dr: Action-Domain-Responder is a natural fit for the HTTP user-interface portions of Clean Architecture (or Hexagonal), especially with Domain Driven Design. Just be sure to remember to separate the HTTP response presentation from the action code.


I.

Jeroen de Dauw has a fantastic post on Implementing the Clean Architecture in PHP, with Domain Driven Design elements. You should read the whole thing, and examine the implementation codebase, for a number of useful insights. Though I might quibble over some elements of the implementation, I think it is a good offering, and serves as a solid reference point.

In his article, Jeroen notes they are using Silex for their HTTP user-interface system, and describes the logic of each route action:

Inside this [Silex action] we construct our framework agnostic request model and invoke the Use case with it. Then we hand over the response model to a presenter to create the appropriate HTML or other such format.

That is a very near paraphrase of Action-Domain-Responder:

  • The Action marshals input from the HTTP request
  • The Action invokes a Domain element with that input and gets back a result
  • The Action passes that result to a Responder to build the HTTP response

In Jeroen’s implementation, each Action is a closure defined in the routes.php file. The Action marshals input from the HTTP request using a “request model” (an input object tailored to the domain) and passes it to a “use case.” Each “use case” is an entry point into the Domain, and returns a “response model” (the domain result).

The only place where Jeroen’s implementation deviates from ADR is that the Action code builds the presentation itself, instead of handing off to a Responder. (This may be a result of adhering to the idioms and expectations specific to Silex.)

Because the rest of the implementation is so well done, refactoring to a separated presentation in the form of a Responder is a straightforward exercise. Let’s see what that might look like.

II.

First, as an example, review the code in the check-iban action. The following reorganization of that action code makes the ADR pattern more obvious:

<?php
$app->get(
    'check-iban',
    function( Request $request ) use ( $app, $ffFactory ) {

        // marshal input
        $input = new Iban( $request->query->get( 'iban', '' ) );

        // invoke domain and get back result
        $result = $ffFactory->newCheckIbanUseCase()->checkIban($input);

        // presentation
        return $app->json(
            $ffFactory->newIbanPresenter()->present( $result )
        );
    }
);
?>

Very clear and straightforward. However, the presentation work is embedded in the action with the $app->json(...) call. (My guess is that’s probably a result of working with existing Silex idioms.)

Another good example is the list-comments.html action. Reorganizing the logic to make the ADR pattern more obvious gives us the following:

<?php
$app->get(
    'list-comments.html',
    function( Request $request ) use ( $app, $ffFactory ) {

        // marshal input
        $input = new CommentListingRequest(
            10,
            (int)$request->query->get( 'page', '1' )
        );

        // invoke domain and get back result
        $result = $ffFactory
            ->newListCommentsUseCase()
            ->listComments( $input );

        // presentation
        return new Response(
            $ffFactory->newCommentListHtmlPresenter()->present(
                $result,
                (int)$request->query->get( 'page', '1' )
            )
        );
    }
);
?>

Again, the presentation work is embedded in the action code.

In general, it is better to completely separate the presentation work from the action code. Remember that in an HTTP context, the presentation is not just the body of the HTTP response. Instead, the presentation is the entire HTTP response, including headers and status. (For more on this, see The Template Is Not The View.)

With the above examples, because they are already so well structured, it would be easy to extract the presentation to a Responder class. For example, the list-comments action could have the presentation work completely removed like so:

<?php
// hypothetical class with the extracted logic
class ListCommentsHtmlResponder
{
    public function buildResponse($request, $result, $ffFactory)
    {
        return new Response(
            $ffFactory->newCommentListHtmlPresenter()->present(
                $result,
                (int)$request->query->get( 'page', '1' )
            )
        );
    }
}

// the refactored action code
$app->get(
    'list-comments.html',
    function( Request $request ) use ( $app, $ffFactory ) {

        // marshal input
        $input = new CommentListingRequest(
            10,
            (int)$request->query->get( 'page', '1' )
        );

        // invoke domain and get back result
        $result = $ffFactory->newListCommentsUseCase()->listComments($input);

        // hand result to responder
        return $ffFactory->newListCommentsHtmlResponder()->buildResponse(
            $request,
            $result,
            $ffFactory
        );
    }
);
?>

Now the presentation work of building an HTTP response is cleanly separated from the rest of the action code.

III.

When separating concerns along these lines, you begin to see the similarities in the presentation work, and can start to reduce repetition across the codebase. For example, any Action that delivers a JSON response might use the same base JSON Responder.

Eventually, you may realize that the logic of each action is effectively identical. That is, you always collect input, pass that input through the domain to get back a result, and pass that result to a response builder.

When that realization occurs, you can build a single action handler that coordinates between injected input marshals, domain entry points, and response builders. That’s exactly what the Arbiter ActionHandler does, and Radar uses that in turn to specify the input + domain + responder callables for each route.

At that point, you are out of the business of writing action methods entirely. Then the user-interface code can focus on marshaling inputs going to the domain, and on presenting the results coming out of the domain – which is exactly how things should be.

P.S.

Jeroen’s writeup also reveals that at least some of the elements in his implementation are returning something like Domain Payload objects. Cf. the ValidationResult class, used in the validate-payment-data action among other places.

I’m a big fan of the Domain Payload pattern in ADR, and using a Domain Payload for all returns received by the action code. Doing so simplifies the response-building logic even further; for example, by collecting common “success” and “failure” presentation work across different JSON responders.

Then there’s this bit about containers:

We decided to go with our own top level factory, rather than using the dependency injection mechanism provided by Silex: Pimple. Our factory internally actually uses Pimple, though this is not visible from the outside. With this approach we gain a nicer access to service construction, since we can have a getLogger() method with LoggerInterface return type hint, rather than accessing $app[‘logger’] or some such, which forces us to bind to a string and leaves us without type hint.

This resonates with some other ideas I’ve been toying with, namely that the user-interface container might better be separated from the domain container. They can be wired up separately from each other, making it easier to package the Domain portions independently from the user-interface portions, and enforcing a “physical” boundary between the two.

Overall, congratulations to Jeroen on putting together such a good writeup.

Radar Project Skeleton Now Stable

I am happy to announce that the project skeleton for Radar, an Action-Domain-Responder system for PHP, is now stable and available for use.

One significant difference between this release and the last alpha is that it now uses the standard pds/skeleton names for directories. Existing Radar projects will not need to change directory names, but be aware that starting a new project with the 1.0.0 version will use “public/” instead of “web/”.

Many thanks to everyone who contributed to this release, especially Jake Johns, who put together a post-create-project command to “clean up” the initial installation.

ADR with HTTP Caching

Great conversation with “MatTheCat” on Github today, regarding HTTP caching headers and the ADR pattern.

A quick summary:

  • You want to return a 304 “Not Modified” response if the proper preconditions are met.
  • You can only tell if the resource is unmodified if you touch some form of storage.
  • In ADR, one rule of thumb is “if it touches storage, it probably goes in the Domain.”
  • So you need to do all the precondition-checking in the Domain, not in the Action.
  • The Domain can return a payload indicating “not modified” as appropriate, and the Responder can read that payload status to send back a 304.

You can read the whole thing here. Thanks for the great question Mathieu!

Why Do PHP Developers Think MVC Is An Application Architecture?

I’ve pointed out before that Model-View-Controller is a user interface pattern, not an application architecture. But why would PHP developers get the idea that MVC is an application architecture in the first place? (This may apply to all server-side developers, not just PHP folks.)

I used to think that MVC was an application architecture. Even after reading Fowler’s POEAA and seeing that MVC was for the user interface, I figured that meant I was doing “user interface applications.” But that was not quite right; it would have been more accurate to say that I had been mixing the concerns of user interface with the underlying core application.

Based on that experience, I think the reason MVC is mistaken for an application architecture is because PHP developers generally start with page scripts. In our first page scripts, we combine all the concerns in a single ball of mud: SQL queries are intermingled with HTML, and the business logic is scattered throughout. As far as we are concerned, the page script itself is “the application.” Later, as more functionality is required, we add another page script, and another, and another. We continue to see that collection of page scripts as “the application.”

Then, as we progress in our profession, and begin to learn how to better organize our work, we start separating the different concerns of “the application.” When we begin separating concerns, we separate them out of the page script, which we see as “the application.” Extracting the view concerns from the page script means extracting them from “the application.” Separating the model from the page script into its own layer means separating it from “the application.” Pulling the controller logic out of the page script means pulling it out of “the application.” So of course Model-View-Controller is seen as an application architecture – we separated the concerns of our application according to that pattern, right?

Except, in retrospect, it’s not. One of the big leaps we have to make is to realize that MVC is for the user interface portion of our systems, just like Fowler notes. We on the server side think the user interface is HTML, CSS, and Javascript, but it’s not. Instead, the user interface is the HTTP Request and Response. In other words, the template is not the View.

Once we make that conceptual leap, we begin to realize that the Model layer is the entry point to “the application”. That is where “the application” should live, or at least where it should look like it lives. The Controller should have little to do but take input from the Request and pass it to the Model; likewise, the View should do nothing but put together the Response using the output from the Model.

With that idea of server-side MVC, we then begin to see that a lot of what’s in server-side MVC frameworks is “too much.” Framework functionality that is not related to merely taking input from a Request and presenting output through a Response becomes entirely secondary to, perhaps even actively harmful to, building well-structured applications – applications that are independent of any particular user interface.

Afterword

The server-side MVC pattern, as descended through Sun’s Model 2 architecture, is so distinctive from the client-side MVC pattern as to be a completely different thing. I realized this as I was writing my book on modernizing legacy applications, and further research led me to write up Action-Domain-Responder as a web-specific alternative to MVC. Action-Domain-Responder places a much stronger emphasis on the HTTP Request and Response as the user interface elements. If you are interested in building better applications, you may wish to read the ADR essay, and try it out in your next project.

Command Bus and Action-Domain-Responder

Over the past few weeks, different people have asked me where a Command Bus goes in an Action-Domain-Responder system. While I’m not a DDD expert, after brushing up on the subject a little, my answer is: “In the Domain.”

First, let’s recall the three components in ADR:

  • “Action” is the logic that connects the Domain and Responder. It uses the request input to interact with the Domain, and passes the Domain output to the Responder. (The Action is intentionally “dumb”: it should have no logic at all, aside from perhaps the most minimal of ternaries to allow for default input values. If the Action has a conditional, it is doing too much.)

  • “Domain” is the logic to manipulate the domain, session, application, and environment data, modifying state and persistence as needed. (The word “Domain” here is explicitly intended to remind you of “domain logic” and “domain-driven design.”)

  • “Responder” is the logic to build an HTTP response or response description. It deals with body content, templates and views, headers and cookies, status codes, and so on.

Next, let’s see what Command Bus is. There’s a lot written about it elsewhere …

… so I’ll try to sum up here:

  • A “Command” is a typed or named set of inputs (essentially a data-transfer object) that gets sent to a “Command Bus.”

  • The “Command Bus” then hands off the “Command” to a “Command Handler” specific to that “Command”; the “Command Bus” figures out which “Command Handler” to use from the name or type of the “Command.”

  • The “Command Handler” uses the “Command” inputs to perform some sort of activity.

This series of objects is part of an overarching architectural pattern called Command Query Responsibility Segregation (see here and here). Under CQRS, writes (Commands) are handled separately from reads (Queries). Handling a Command modifies data but does not return a result, while handling a Query returns a result but must not modify data.

This means that a Command Bus does not actually return a result for inspection. You dump a Command into the Bus, and you’re done; there’s no checking for errors at that time. To conform to CQRS properly, you have to perform a separate Query in order to determine the result of the Command.

At this point, just from having read the literature on the patterns and concepts, we can see that Command Bus and its related components are part of the domain layer, not part of the user interface layer. With that in mind, it seems like Command Bus is a candidate for the “Domain” portion of Action-Domain-Responder, to be used like this in an Action:

class CreateItemAction
{
    public function __construct(
        CommandBus $domain,
        CommandResponder $responder
    ) {
        $this->domain = $domain;
        $this->responder = $responder;
    }

    public function __invoke(Request $request)
    {
        $input = $request->getParsedBody();
        $command = new CreateItemCommand(
            $input['item_name'],
            $input['item_description']
        );
        $this->domain->handle($command);
        return $this->responder->createResponse();
    }
}

So the Action gets constructed with a CommandBus element as an entry point into the Domain, and with a generic Responder to build the response. At invocation time, the user interface code sends along the current HTTP request; the Action pulls data out of it to create Command to send to the Command Bus, then tells the Responder to create an HTTP response. (Because a Command never returns anything, one Responder should suffice for all Commands in this setup.)

This is straightforward as an minimal case, but I think it avoids at least two substantial issues.

  1. Where does input validation go? (Input validation, or form validation, is separate from domain model validation.)

  2. Where does error handling go? (While a Command might not return anything, the various elements related to CQRS might very well throw exceptions or raise errors.)

In what we think of as server-side MVC, those two concerns might well be placed in the Controller somewhere. Translating a Controller method directly to an Action, that might look something like this:

    public function __invoke(Request $request)
    {
        // get the input and validate it
        $input = $request->getParsedBody();
        if (! $this->validate($input)) {
            // create an "invalid input" response
            return $this->responder->invalid($input);
        }

        // create the command
        $command = new CreateItemCommand(
            $input['item_name'],
            $input['item_description']
        );

        // try the command
        try {
            $this->domain->handle($command);
            // succcess!
            return $this->responder->success();
        } catch (Exception $e) {
            // there was some sort of subsequent failure
            return $this->responder->failure($e);
        }
    }

On consideration, that seems like a lot of extraneous activity in the user interface layer. In ADR, the Action is intentionally supposed to be dumb. It should not be doing anything even remotely interesting, and certainly should not be dealing with any conditional logic.

As such, I say that Command-related activity should be taken out of the Action entirely, and relegated to something like an Application Service or some other Domain entry point. That Service is what should perform the Command-related activity.

Further, while a Command may not return a result, a Service certainly can. This means that the Action can call the Domain and get back a Domain Payload as a result, which can then be passed to the Responder for presentation.

Under that way of thinking, we get something more like this:

class CreateItemAction
{
    public function __construct(
        ItemService $domain,
        CreateItemResponder $responder
    ) {
        $this->domain = $domain;
        $this->responder = $responder;
    }

    public function __invoke(Request $request)
    {
        $input = $request->getParsedBody();
        $payload = $this->domain->create($input);
        return $this->responder->createResponse($payload);
    }
}

class ItemService
{
    public function create(array $input)
    {
        if (! $this->validate($input)) {
            // create an "invalid input" response
            return new InvalidInputPayload($input);
        }

        // create the command
        $command = new CreateItemCommand(
            $input['item_name'],
            $input['item_description']
        );

        // try the command
        try {
            $this->domain->handle($command);
            return new CommandAcceptedPayload();
        } catch (Exception $e) {
            return new CommandRejectedPayload($e);
        }
    }
}

Now the Domain is fully separated from the user interface. It can be used with both HTTP and command-line interfaces, and tested separately from them. Per the ADR pattern, the Responder becomes responsible for examining the Payload to see what kind of presentation to deliver to the client. Different Payloads result in different responses being built. Finally, the Action becomes entirely uninteresting; all of the business logic has been pushed down into the Domain, where it belongs.

So, to sum up: Command Bus is a domain layer pattern, and should be used in the Domain, not in the Action. A Command cannot return a result, but a Service can, so the entry point into the Domain is probably better as a Service that returns a Payload. This keeps the HTTP and CLI user interface logic well separated from business logic, and independently testable and reusable.