{
    "href": "/post/2017/02/21/wikimedia-clean-architecture-and-adr/",
    "relId": "2017/02/21/wikimedia-clean-architecture-and-adr",
    "title": "WikiMedia, Clean Architecture, and ADR",
    "author": "pmjones",
    "markup": "html",
    "tags": [
        {
            "href": "/tag/adr/",
            "relId": "adr",
            "title": "Action Domain Responder",
            "author": null,
            "created": "2020-08-17 21:07:42 UTC",
            "updated": [
                "2020-08-17 21:07:42 UTC",
                "2020-09-22 15:41:16 UTC",
                "2020-10-14 18:20:29 UTC",
                "2020-10-14 18:36:31 UTC",
                "2020-10-14 18:36:53 UTC",
                "2020-10-14 18:37:08 UTC",
                "2020-10-14 18:37:48 UTC",
                "2020-10-14 18:39:26 UTC",
                "2020-10-14 19:03:17 UTC",
                "2020-10-14 19:03:35 UTC",
                "2020-10-26 18:12:53 UTC"
            ],
            "markup": "markdown"
        },
        {
            "href": "/tag/php/",
            "relId": "php",
            "title": "PHP",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        },
        {
            "href": "/tag/programming/",
            "relId": "programming",
            "title": "Programming",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        },
        {
            "href": "/tag/radar/",
            "relId": "radar",
            "title": "Radar",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        }
    ],
    "created": "2017-02-21 13:30:32 UTC",
    "updated": [
        "2017-02-21 13:30:32 UTC"
    ],
    "html": "<p><strong>tl;dr:</strong> <a href=\"http://pmjones.io/adr\">Action-Domain-Responder</a> 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.</p>\n<hr>\n<h3 id=\"i\">\n<a name=\"user-content-i\" href=\"#i\" class=\"headeranchor-link\" aria-hidden=\"true\"><span class=\"headeranchor\"></span></a>I.</h3>\n<p>Jeroen de Dauw has a fantastic post on <a href=\"https://www.entropywins.wtf/blog/2016/11/24/implementing-the-clean-architecture/\">Implementing the Clean Architecture</a> in PHP, with Domain Driven Design elements. You should read the whole thing, and examine <a href=\"https://github.com/wmde/FundraisingFrontend\">the implementation codebase</a>, 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.</p>\n<p>In his article, Jeroen notes they are using <a href=\"http://silex.sensiolabs.org/\">Silex</a> for their HTTP user-interface system, and describes the logic of each route action:</p>\n<blockquote>\n<p>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.</p>\n</blockquote>\n<p>That is a very near paraphrase of <a href=\"http://pmjones.io/adr\">Action-Domain-Responder</a>:</p>\n<ul>\n<li>The Action marshals input from the HTTP request</li>\n<li>The Action invokes a Domain element with that input and gets back a result</li>\n<li>The Action passes that result to a Responder to build the HTTP response</li>\n</ul>\n<p>In Jeroen\u2019s implementation, each Action is a closure defined in the <code>routes.php</code> file. The Action marshals input from the HTTP request using a \u201crequest model\u201d (an input object tailored to the domain) and passes it to a \u201cuse case.\u201d Each \u201cuse case\u201d is an entry point into the Domain, and returns a \u201cresponse model\u201d (the domain result).</p>\n<p>The only place where Jeroen\u2019s 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.)</p>\n<p>Because the rest of the implementation is so well done, refactoring to a <a href=\"https://www.martinfowler.com/eaaDev/SeparatedPresentation.html\">separated presentation</a> in the form of a Responder is a straightforward exercise. Let\u2019s see what that might look like.</p>\n<h3 id=\"ii\">\n<a name=\"user-content-ii\" href=\"#ii\" class=\"headeranchor-link\" aria-hidden=\"true\"><span class=\"headeranchor\"></span></a>II.</h3>\n<p>First, as an example, review the code in the <a href=\"https://github.com/wmde/FundraisingFrontend/blob/master/app/routes.php#L246-L253\">check-iban</a> action. The following reorganization of that action code makes the ADR pattern more obvious:</p>\n<pre><code>&lt;?php\n$app-&gt;get(\n    'check-iban',\n    function( Request $request ) use ( $app, $ffFactory ) {\n\n        // marshal input\n        $input = new Iban( $request-&gt;query-&gt;get( 'iban', '' ) );\n\n        // invoke domain and get back result\n        $result = $ffFactory-&gt;newCheckIbanUseCase()-&gt;checkIban($input);\n\n        // presentation\n        return $app-&gt;json(\n            $ffFactory-&gt;newIbanPresenter()-&gt;present( $result )\n        );\n    }\n);\n?&gt;\n</code></pre>\n<p>Very clear and straightforward. However, the presentation work is embedded in the action with the <code>$app-&gt;json(...)</code> call. (My guess is that\u2019s probably a result of working with existing Silex idioms.)</p>\n<p>Another good example is the <a href=\"https://github.com/wmde/FundraisingFrontend/blob/master/app/routes.php#L196-L211\">list-comments.html</a> action. Reorganizing the logic to make the ADR pattern more obvious gives us the following:</p>\n<pre><code>&lt;?php\n$app-&gt;get(\n    'list-comments.html',\n    function( Request $request ) use ( $app, $ffFactory ) {\n\n        // marshal input\n        $input = new CommentListingRequest(\n            10,\n            (int)$request-&gt;query-&gt;get( 'page', '1' )\n        );\n\n        // invoke domain and get back result\n        $result = $ffFactory\n            -&gt;newListCommentsUseCase()\n            -&gt;listComments( $input );\n\n        // presentation\n        return new Response(\n            $ffFactory-&gt;newCommentListHtmlPresenter()-&gt;present(\n                $result,\n                (int)$request-&gt;query-&gt;get( 'page', '1' )\n            )\n        );\n    }\n);\n?&gt;\n</code></pre>\n<p>Again, the presentation work is embedded in the action code.</p>\n<p>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 <em>the entire HTTP response</em>, including headers and status. (For more on this, see <a href=\"http://paul-m-jones.com/archives/5993\">The Template Is Not The View</a>.)</p>\n<p>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 <code>list-comments</code> action could have the presentation work completely removed like so:</p>\n<pre><code>&lt;?php\n// hypothetical class with the extracted logic\nclass ListCommentsHtmlResponder\n{\n    public function buildResponse($request, $result, $ffFactory)\n    {\n        return new Response(\n            $ffFactory-&gt;newCommentListHtmlPresenter()-&gt;present(\n                $result,\n                (int)$request-&gt;query-&gt;get( 'page', '1' )\n            )\n        );\n    }\n}\n\n// the refactored action code\n$app-&gt;get(\n    'list-comments.html',\n    function( Request $request ) use ( $app, $ffFactory ) {\n\n        // marshal input\n        $input = new CommentListingRequest(\n            10,\n            (int)$request-&gt;query-&gt;get( 'page', '1' )\n        );\n\n        // invoke domain and get back result\n        $result = $ffFactory-&gt;newListCommentsUseCase()-&gt;listComments($input);\n\n        // hand result to responder\n        return $ffFactory-&gt;newListCommentsHtmlResponder()-&gt;buildResponse(\n            $request,\n            $result,\n            $ffFactory\n        );\n    }\n);\n?&gt;\n</code></pre>\n<p>Now the presentation work of building an HTTP response is cleanly separated from the rest of the action code.</p>\n<h3 id=\"iii\">\n<a name=\"user-content-iii\" href=\"#iii\" class=\"headeranchor-link\" aria-hidden=\"true\"><span class=\"headeranchor\"></span></a>III.</h3>\n<p>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.</p>\n<p>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.</p>\n<p>When that realization occurs, you can build a single action handler that coordinates between injected input marshals, domain entry points, and response builders. That\u2019s exactly what the Arbiter <a href=\"https://github.com/arbiterphp/Arbiter.Arbiter/blob/1.x/src/ActionHandler.php\">ActionHandler</a> does, and <a href=\"https://github.com/radarphp/Radar.Project\">Radar</a> uses that in turn to specify the <a href=\"https://github.com/radarphp/Radar.Project/blob/1.x/docs/routing.md#manually-specifying-a-custom-input-class\">input</a> + <a href=\"https://github.com/radarphp/Radar.Project/\">domain</a> + <a href=\"https://github.com/radarphp/Radar.Project/blob/1.x/docs/routing.md#manually-specifying-a-custom-responder-class\">responder</a> callables for each route.</p>\n<p>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 \u2013 which is exactly how things <em>should</em> be.</p>\n<h3 id=\"ps\">\n<a name=\"user-content-ps\" href=\"#ps\" class=\"headeranchor-link\" aria-hidden=\"true\"><span class=\"headeranchor\"></span></a>P.S.</h3>\n<p>Jeroen\u2019s writeup also reveals that at least some of the elements in his implementation are returning something like <a href=\"https://vaughnvernon.co/?page_id=40\">Domain Payload</a> objects. Cf. the <a href=\"https://github.com/wmde/FundraisingFrontend/blob/master/src/Validation/ValidationResult.php\">ValidationResult</a> class, used in the <a href=\"https://github.com/wmde/FundraisingFrontend/blob/master/app/routes.php#L53-L71\">validate-payment-data</a> action among other places.</p>\n<p>I\u2019m a big fan of the <a href=\"http://paul-m-jones.com/archives/6043\">Domain Payload pattern in ADR</a>, and using a Domain Payload for <em>all</em> returns received by the action code. Doing so simplifies the response-building logic even further; for example, by collecting common \u201csuccess\u201d and \u201cfailure\u201d presentation work across different JSON responders.</p>\n<p>Then there\u2019s this bit about containers:</p>\n<blockquote>\n<p>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[\u2018logger\u2019] or some such, which forces us to bind to a string and leaves us without type hint.</p>\n</blockquote>\n<p>This resonates with some other ideas I\u2019ve 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 \u201cphysical\u201d boundary between the two.</p>\n<p>Overall, congratulations to Jeroen on putting together such a good writeup.</p>\n<p class=\"reddit-links\">Read the Reddit discussion about this post <a href=\"https://www.reddit.com/r/PHP/comments/5vbhoj/wikimedia_clean_architecture_and_adr/\">here</a>.</p>\n"
}
