Refactoring To Action-Domain-Responder

Posted by Unknown on Thursday, June 5, 2014

The v1 version of the Aura framework includes a controller to handle web assets. The idea for this controller was that an Aura package might have images, scripts, and stylesheets that need to be publicly available, but in development you don’t necessarily want to copy them to a public document root every time you change them. The framework dispatches all “/asset/*” routes to the asset controller, which in turn reads the requested package asset from the file system and places its contents into the response body. Performance-wise this is horrible, so in a production environment one would use a build process to copy all the package assets to a static asset server, but in a local development it is a valuable convenience.


Take a look at the v1 version of the asset controller. It is constructed as a Page Controller within an MVC architecture. The default actionIndex() method receives an Aura package name in the form of Vendor.Package and a trailing file path indicating the asset to load from that package, then reads that file from the package and loads it into the response body.


That v1 version is a mess. The Controller handles the response-building entirely, and there is no Model separation at all. Let’s try refactoring it to an Action-Domain-Responder architecture and clean it up some for a v2 version. (For this example refactoring, we have Hari KT to thank for getting us started.)




  1. First, we need to extract the Domain portions of the code. After some discussion, we determined that the Domain here is the file-reading portions of the code. Instead of an Aura-specific Vendor.Package algorithm, we build a map of vendor/package keys that point to arbitrary directory prefixes (typically but not necessarily in a Composer installation). Finally, we figure that the caching elements would be better as part of a build process rather than on-the-fly, so we remove those caching elements; this reduces a significant portion of the Domain work.




  2. Next, we extract the response-building activity to a separate Responder class. The response-building work turns out to be relatively straightforward: if the asset has a path, that means the service found it, and we should present it as 200 OK; if not, we present it as 404 NOT FOUND.




  3. Last, we rename the Controller to an Action, and name its one-and-only “main” entry point as __invoke(). We modify the code in the Action to (1) invoke the Domain with the incoming request input, (2) place the Domain data into the Responder, and (3) return the Responder.




The end result is three classes instead of one: AssetService to handle Domain work, AssetResponder to handle the response presentation, and AssetAction to handle the incoming request and pass data from the Domain to the Responder.


Compared to the original Controller class, we clearly have more classes, and (aside from the fact that we removed the caching functionality) we likely have somewhat more code as well. But each class, and each method in each class, is relatively short, and the package overall is much more testable:




  • the AssetServiceTest is completely freed up from the Action and Responder (as it should have been in the original MVC code)




  • the AssetResponderTest does not need either the AssetAction or the AssetService, and is able to examine both the body and the headers of the response




  • the AssetActionTest does little more than to check if __invoke() returns a Responder, and see if the assigned data was retained




This separation has the effect of making the underlying components much more independent of each other and a lot easier to test. If we wanted to get really serious we would use interfaces and test doubles to fully isolate the classes.


Right now, some readers are looking at this example and


Truncated by Planet PHP, read more at the original (another 2134 bytes)




more

{ 0 comments... » Refactoring To Action-Domain-Responder read them below or add one }

Post a Comment

Popular Posts