The Command Pattern: A Lightweight Alternative to DCI
February 09, 2012 - 11 Comments - ruby rails patterns command pattern dci
Recently the Rails community has seen a flurry of activity regarding a new approach to encapsulating business logic in Rails called Data, Context, Interaction, or, DCI. And rightfully so! The old mantra of “fat models, skinny controllers” has cracked with wisdom as models in larger and more complicated applications have become not just fat but in fact rather obese. Furthermore, the question of which model some piece of business logic should live in has always been vague regarding operations involving multiple models of different kinds.
It is a problem. The results have been sub-optimal design, testability, and readability, coupled with huge model files bloating into thousands of lines of code. The DCI approach has been explored at length as a possible solution. Mike Pack wrote a great article both explaining the benefits of DCI and an example implementation.
The DCI Pattern: Pros and Cons
There are some clear benefits of the DCI approach, especially compared to the old way of just shoving business logic into the nearest relevant model:
- Skinny models. DCI effectively cleans up your models, and should leave them with nothing but declarative associations, validations, and callbacks, plus any convenient accessor methods and query scopes. Models are left dealing strictly with the access and persistence of your data. In this way, they are dumb, knowing nothing about the business logic beyond how to find, validate, and persist the data for which they are responsible.
- Explicit definition of user roles. In the Agile development methodology, user stories are defined as being the goal a user who represents a given “role”, such as a “Customer”, “Client”, or “Administrator”. In DCI, abilities tied to these roles are defined explicitly in their own Role modules which extend the actor instances at runtime.
- Clarity. As mentioned before, when working with the fat models approach, it’s often ambiguous as to which model a given set of business logic should live in, especially when that business logic involves manipulating a number of different kinds of models. With DCI, each business goal lives in its own Context class, regardless of the types of models it requires, so there is no confusion.
- Testability. With the clean separation of logic, it’s very easy to test each user story in isolation.
Sounds great, right? It turns out that DCI is just the kind of scalpel Rails needs to divvy up responsibilities around complicated business logic, and its nearly lock-step fit with Agile user stories is a great extra feature. That said, here are some of the drawbacks that I can see:
- Performance. One of the main bogeymen regarding DCI right now is performance. The “correct” approach to DCI is to extend the actors with their appropriate Roles at runtime, which can be a significant performance hit if done enough times. In larger applications with a high request volume, this can be significant. Mike Pack has written another article addressing different approaches to injecting Roles into actors, each with its own trade-offs of performance and purity. It’s definitely worth a look.
- Extra classes/modules and boilerplate. Each Role requires its own Module, and each Context must begin by extending the given actors with their appropriate Roles. It’s just additional overhead during development.
- More moving parts. Each Context requires an intimate knowledge of the actions available to the Roles involved.
I still think DCI is an excellent solution, but it occurs to me that it might be a little heavyweight for some applications. That’s why I’m proposing a lightweight alternative which has been a steadfast design pattern for nearly two decades.
The Command Pattern: Pros and Cons
The Command pattern has long been the go-to pattern for encapsulating undoable/redoable actions in GUI applications. I used it in the development of my game, Elite Command, to great effect. My original intent was to add multiple undo to the game, but then it had the great side-benefit of removing a lot of game logic from my models and separating possible player commands into their own easily-testable classes. The result: skinny controllers, skinny models, and relatively skinny Command classes each concerned with an individual feature of the game.
Here are some of the advantages to the Command approach, many of which are the same as for DCI:
- Skinny models. Like DCI, the Command pattern encapsulates individual business goals into their own classes, leaving models concerned purely with access, validation, and persistence.
- Clarity. Like with DCI, there is no question as to where the logic for a given business role should go: it goes into its own Command class.
- Testability. Like with DCI, since each business goal lives in its own class, it is supremely easy to test each scenario in isolation.
- Peformance. Unlike DCI, the Command pattern requires no extension of objects at runtime. Commands are merely Plain Old Ruby Objects hiding a business goal behind a simple interface. Indeed, the Command pattern can in many ways be regarded as DCI without the Roles.
- Fewer classes, less boilerplate. Without Roles or runtime extension of objects, one only needs to look in one place for a complete step-by-step view of a given feature’s functionality.
- Undo and redo support. The Command pattern was originally designed with undo support in mind, so it’s a natural fit if you plan to add undo or redo to your Rails application. Of course, it’s basically just DCI without Roles, so I don’t see why DCI couldn’t also do this fairly easily.
- A natural fit with the Composite pattern. The Composite pattern allows a tree of objects to be treated as a single object. An advanced implementation of the Command pattern might include a CompositeCommand class which allows multiple Commands to be executed in sequence. This can be useful for things like minimizing Ajax requests by bundling multiple Commands into a single CompositeCommand, a technique I used to great effect in Elite Command. DCI may be capable of this as well, although I’ve never seen an implementation.
I like the Command pattern for its simplicity. Of course, there are always trade-offs. Here are some of the cons to the Command pattern versus DCI:
- No explicit Roles. You don’t get the one-to-one mapping of Agile user roles to Role modules that you do with DCI. This can be a nice thing to have, depending on the relative complexity of the application
- Not necessarily as DRY. I can imagine some circumstances where Roles might be a good place for code which is reused between Commands.
- Coupling between Commands and model interfaces. Where DCI has coupling between Roles and models, the Command classes have coupling between Commands and models, with no intermediary. This might not be a big deal, but it’s something to keep in mind.
The real disadvantage to the Command pattern versus DCI is that Roles are not present. This results in fewer classes and less boilerplate, but as a trade-off you may need to place some logic which would go into Roles into either a Command superclass or into one of the models themselves in order to keep the code DRY. In Elite Command, I opted to include shared logic as modules into the Command class, which has generally worked fine.
The main advantages over DCI are the performance gains from not having to extend anything at runtime and the fewer classes and lines of code required to support the pattern.
An example of the Command pattern in action
Here is a simple implementation of adding an item to a shopping cart using the Command pattern. Elite Command actually uses a much more sophisticated, fully-featured implementation which I may cover in a future article, but for now here is a quick demonstration.
First, our simple models:
And now, the Command superclass:
And finally, a spec and implementation for adding an item to a cart:
Simple, no? Of course, because it’s an exceedingly simple example. However, Commands really shine when they encapsulate more complex algorithms involving interactions between multiple models. And with a dash of persistence and the addition of #unexecute! methods, we have really easy undo support ready to go!
As mentioned above, there are more sophisticated features which can be attained with the Command pattern and which proved to be a great boon for Elite Command. If there’s enough interest, I may write on this further in the future.
Conclusion
As always, design decisions come with trade-offs. I am not advocating the use of the Command pattern instead of DCI. Rather, I am suggesting an alternative which shares many of DCI’s benefits but with a slightly different set of drawbacks. Before going with one or the other, ask yourself whether the explicitly defined Roles are worth it to your application, or whether the lighter conceptual overhead and smaller performance footprint of the Command pattern are of greater concern.

Mike Pack said:
Good article. I like how you addressed the pros-cons of each implementation. IMHO the real benefit of the command pattern is the intrinsic ability to chain and undo commands. I would love to see how you use this in Elite Command.
Also, do you ever find your command classes growing too large? Is there one command class per use case?