Skip to main content

Controller classes vs. Action classes

This blog post might be outdated!
This blog post was published more than one year ago and might be outdated!
· 4 min read
Stephan Hochdörfer

Paul M. Jones asked me to go into detail and explain my thoughts on the Action-Domain-Response pattern, particular why I think action classes make more sense than the commonly used controller classes.

Disclaimer: I am very biased on this topic. Mostly because we are using action classes in our application framework for almost the last decade. I have seen controller classes in the wild (aka customer projects and open-source projects) but I never built a large scale application from the scratch with controller classes. So maybe my assumptions are all wrong. But I do not think so ;)

First of all I do have the feeling that controller classes make it harder to structure your logic. I have seen a lot of "God Controllers" that do a shitload of stuff. Stuff that is not really related to each other. I assume this happened because it seems to be easier to add a new method to an existing controller than to add a new class, think about how to name the class properly and in which namespace to put it. action classes tend to be rather small, typically less than 100 loc for us. That also helps a lot when trying to understand what's going on. I am aware that there are developers out there who are afraid when it comes to dealing with a lot of classes. Do not be afraid. Use a proper IDE and everything will be good. That's another bonus point for action classes: It is easier to search for a class name than a method name in most IDEs.

(God) Controllers tend to have a lot of dependencies. Dependencies get instantiated for each request even though they might be not used. Obviously people came up with a few "creative" solutions for this problem, mainly the creation of lazly loaded dependencies. That are dependencies that really get instantiated the first time they are accessed (a method is called). That is an appropriate solution for the problem but not really needed when we deal with action classes. action classes depend on what they really needed. Typically that's just a few services for a single action. Again that makes the code way easier to understand and easier to test. Yes, I do refer to testing. I know that are people out there who believe that testing controllers and/or actions is not needed because in most cases action classes are just responsible to invoke a service method and pass a few arguments to the service method. Yes that is true, but how can you guarantee that this part of your application is working as wanted?

Action classes in contrast to controller classes can be reusable. Again, we did this in the past a couple of times. Not always, but in quite a few cases this can perfectly make sense. Let's say I have written my own CMS. I developed logic to edit different components, e.g. headline, image and content. Traditionally I would create 3 separate actions, one for each of the components. However looking closely what code we have written it is clear that the overall logic behind editing a component is the same for all the three components. What is different is just the service which gets called. So why not create a more "general" action, add some configuration code to inject the services needed?

Action classes come in pretty handy as "common logic" can be defined in the parent class. Let's have a look how in the past form submissions (aka post requests) got handled: Data is comming in, we magically create a domain object from the incoming data and validate it. If the validation failed we present the user an error page, if the validation succeeded we execute our custom code. Do you really want to implement that flow over and over again in all of your controller methods? Doesn't it make more sense to "just" implement the logic that should be executed after the validation was successful? Action classes and a bit of class inheritance can solve this problem for you.

As a I hopefully outlined action classes do make sense. Try it for yourself ;)