Enterprise Integration Zone is brought to you in partnership with:

Ayende Rahien is working for Hibernating Rhinos LTD, a Israeli based company producing developer productivity tools for OLTP applications such as NHibernate Profiler (nhprof.com), Linq to SQL Profiler(l2sprof.com), Entity Framework Profiler (efprof.com) and more. Ayende is a DZone MVB and is not an employee of DZone and has posted 473 posts at DZone. You can read more from them at their website. View Full User Profile

The Command Design Pattern, Not Completely in Fashion

12.04.2012
| 5284 views |
  • submit to reddit
In my previous post about the command pattern, I gushed about how much I loved it. That doesn’t mean that the command pattern as originally envisioned is still completely in fashion.

In particular, the notion of “Undo” was  one of the major features in the command pattern’s cap. Today, that is almost never the case. Sure, if you are building an application such as an editor. Something like Photoshop or a text editor would find the notion of commands with the ability to have an undo stack very compelling. Other than that, however, that is a very rare need.

In most business scenarios, there really is no good way to undo things. How would you implement SendEmailCommand.Undo(), for example? But even something like PlaceOrder.Undo() is a lot more complex and hard to do than you would think. The mere notion of undoing the operation assumes that this isn’t going to have any side affects. But cancelling an order may result in cancellation fees, require you to ship back things you got back, end. It is not “Undoing PlaceOrder”, rather that is a whole different and distinct business process, usually represented by another command: CancelOrder.

Another common issue that people have is the degeneration of the entire architecture to something like:

CommandExecuter.Execute(Command cmd);

To that I answer, more power to you! I love code that is composed of a lot of small classes all doing things about the same way. There is no easier way to look at a system, and that allows you to quite easily add additional functionality to the system easily. That said, mind how you handle routing in that scenario. I have seen people go into the “when a request comes to this URL, let us invoke the following commands” in XML. One of the reasons that people dislike this approach is how you actually call this. If just getting to the command executer is hard and involved, you lose a lot of the advantages.

This popped up in the mailing list, and I really dislike it. The notion of Composite Command. A command that can execute multiple commands. Now, from a programming point of view, I can easily see why you would want to do that. The PlaceOrderCommand operation is composed of a lot of smaller commands. But, and this is important, the notion of Composite Commands basically mean that you get the same thing as the PlaceOrderCommand, but you just lost the name. And naming is important. Almost as important, error handling is quite different between different business scenarios, and you sometimes end up with something like:

    var placeOrderCommand = new CompositeCommand(

       new RegisterOrderCommand(),

       new ReserveStockCommand(),

       new ChargeCardCommand(),

       new ShipOrderCommand()

    )

    {

       Sequential = true,

       StopOnError = true

   }

And this is simple, how do you handle an error in the ShipOrderCommand after you already charged the card, for example?

Published at DZone with permission of Ayende Rahien, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Ant Kutschera replied on Tue, 2012/12/04 - 4:00pm

How about a composite command where the class is called OrderCompletionCommand, which consists of different steps, depending upon the sales channel (web, mobile, business partner).  The name isn't lost, but depending upon how the command is composed, it functions differently as a whole.

Btw, charging a card is typically a non-transactional command. So regardless of whether something fails after it, you need to handle cases where you get no response (a timeout for example), where your payment partner may have charged the card and you don't know.  One solution is to first reserve the money, then complete the sale including a transaction commit on your side, and if that's successful, confirm the reservation with the payment partner to complete payment.  That confirmation is retried multiple times if it fails, asynchronously, after the fact.  If anything fails before your commit, or indeed your commit fails, you'll need compensation to free the reservation fairly quickly before the customer goes shopping and can't purchase anything coz their card is blocked.

So, cases where you use composite commands tend to be very complex and you need to design and test your error handling really well.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.