If you are wondering what happened to my flame-war-instigating series on the problems with MVC, you’ll have to continue waiting (as will I for the flame war, apparently). I’ve been busy and haven’t had the time to finish typing and inserting links into the rest of the posts. Such is life.
In the meantime, I hope to start emphasizing the usefulness of developing with patterns. This post was inspired by Sean Chambers recent 31 Days of R efactoring (e-book) and my recent flub when trying to describe the Decorator pattern (ducks, really?).
Setting the Stage
On a recent project using WPF and Prism, we’ve built business layer objects to import and export text and Excel files in batches. These batch processes included importing data, transforming the data into something useful, and persisting the transformed data into our database. We needed to communicate progress back to the UI for each of these tasks to keep the user aware of progress, as these tasks can take quite a long time, especially with multiple files. The initial design was raw and messy with lots of code duplication to explicitly create a BackgroundWorker directly within each ViewModel to start the import/export process and listen for events fired directly from our business objects (which essentially follow the Transaction Script pattern, more or less).
Another co-worker, when he was tasked with building another importer, created a subclass of our base ViewModel class and added all the BackgroundWorker plumbing, then did the same for our base business object class. He also created a ProgressItem : INotifyPropertyChanged type with methods to Start(int items), StartAsIndeterminate, IncrementProgress, EndWithSuccess, and EndWithFailure. He also added a collection wrapper for ProgressItems to allow ease of registering and auto-subscribing (through the AutoNotify method) the owning business object to the PropertyChanged events of the ProgressItems. With this setup, the UI ViewModel could listen to the PropertyChanged events of the business object’s ProgressItems instead of having the business object fire its own events. As you can imagine, this made implementing a batch import / export process immensely easier.
I eventually went back and refactored all of our existing business objects and ViewModels to follow this approach. Not only are both the business objects and ViewModels easier to debug, they are also easier to test since we are no longer firing events, just updating the state of a given ProgressItem. Well, sort of….
I was recently tasked with creating a new batch import process to pull data from Excel. I started by following the pattern JB set up and had the initial steps of my batch import object ready to go. (I also confess to not having written any tests yet because, to date, we hadn’t figured out how to mock out the SpreadsheetDocument, Rows, etc. from the Open XML SDK we’re using to assist in our import / export tasks. I’ve now solved that problem and retro-fitted in unit tests. I’ll post that solution later.)
Identifying the Problem
After taking a step back to look at what I had done, I quickly realized that I was violating SRP with the inclusion of the ProgressItems in each step. Some might think that’s not such a big deal; after all, calling start, increment, and end on a single object is only three lines, which doesn’t seem like a lot. However, multiply those three lines by the number of import/export objects and factor in the number of times we forget just one of the them, and you begin to appreciate removing the extraneous bits.
I’m quite certain I noticed this primarily because of my study of functional programming rather than any object-oriented pattern literature I’ve come across. Nevertheless, I considered only OO patterns for the solution simply because the alternative was likely a monad, and that just scares the pants off of most people. (And I like my co-workers.)
I needed something that could pull the ProgressItem out of my actual import procedure and allow me to focus that logic purely on the import. The two patterns that came to mind were the Decorator and the Visitor.
The Decorator is generally considered (well, at least by the people I know) the simpler of the two. It wraps and extends an object without changing the underlying object and still providing the same interface. Examples include “decorating” coffee with sugar, cream, etc. and returning an adjusted price for the additional “decorations.”
The Visitor, on the other hand, is passed into an object’s
void Accept(Visitor visitor) method and provides some resulting side-effect through the visitor itself. Examples include pretty printing, which print a tree-structure with the appropriate indentation, or adding the appropriate tax to an order. Another example for those using the System.Expression namespace would be using the ExpressionVisitor to allow the use of POCO objects with Entity Framework v1, as JB demonstrated here. (For those familiar with monads, you’ll likely see some resemblance.)
In this case, I had the following interface:
For reference, the initial state of a Loader looked something like this, making adjustments to the method signatures for the addition of the ProgressItem, which initially was passed to each method:
Enter the Decorator
Instead of muddying my interface with a
void Accept(Visitor vistor) method, I chose to just decorate it. My resulting decorated class looked as follows:
The resulting base DetailLoader looked like so:
This made the loader much easier to reason about and test thoroughly, as the ProgressItem is completely removed. I no longer have to remember to add the calls to it or even bother with anything other than loading data. Again, I know some will probably call this an over-engineered example, but as a developer who has had to debug these things when they were initially one method directly on the business object not firing a particular event, the additional abstractions make this a breeze to create, debug, and test. To each his own.
As I mentioned, I figured out a way to test this against the Open XML SDK, but since this is already quite a long post, I’ll postpone that for later. I hope you find this a helpful explanation of how and when to refactor using the
Decorator pattern. Please let me know if you have any feedback on the matter.
[POCO]: Plain Old CLR Objects
[SRP]: Single Responsibility Principle