(sorry, but no, this really has very little to do with OOP Design Patterns as describe by the GOF.  This is much more simple, for people who have never heard of this book! (though I highly recommend it, nonetheless))

When I started typing this blog, it had a title of “VBA Class Module Use Case” and was intended to be an extension of the When to Use Class Modules post from earlier last year. After completing it though, I decided to change the name as the ultimate lesson in here is far more important than “when to use a class module.”

A couple of days ago I was working on an Access/VBA project, and the task at hand called for an excellent use of a class module. Also recently, I had been working on my blog and thus I had my “When to Use Class Modules” blog post from last year in mind. It occurred to me that I hadn’t mentioned this specific type of use case for a class module in the previous entry, and it’s a great case example, so I figured I’d jot something up on it quickly and link the two together.

The task is to build an emailer that will run on a daily basis as the tail end of a larger batch import/analyzation process. For the emailer portion, we’ll have a couple hundred records to loop through, checking a few things such as whether the target address is blacklisted and which internal account it needs to be sent from. In this case, the email mechanism is actually the eBay API, which uses XML as one of its formats for sending and receiving messages. As such, we have not only the email information to process from the database itself, but also some minor XML stuff to handle on a per-batch, per-internal account and per-recipient level.

Here’s some pseudo-outline for what ultimately needs to be done:

The “send the message” portion of this has a fair amount of work. An outline for that:

For the XML processing, some of it can be done once and will apply to the entire process regardless of how many messages will go out. Other information can only be applied on a per-record basis.

Here’s one way we could do it, but it’s not a good way (and I’ll explain why after):

This would work, and can be done in a standard module without too much issue, but there’s a few significant problems with the design:

  • The code is not isolated based on the task it performs. The code should, ideally, handle one specific task, which in this case should be “process records that we need to send a message for”. Processing the details of the message sending itself should be in a different procedure somewhere else, so that if the client wants to switch from eBay messaging to, say, gmail messaging, all we have to do is replace a function call instead of going through this entire procedure and changing all the tightly coupled XML processing that’s mixed in with it. This would be difficult, because:
  • We have so many different things that need to be done with the XML processing and general messaging that it wouldn’t make sense to try to handle it all within a single procedure. We could split out the XML parts to private procedures in the modules, which would help considerably, then call it as the “send a message” routine, but this means that the initial XML build would happen once for each record processed, though we only should have to do that one time for the whole batch. That’s considerable overhead being wasted: from within our loop, we should only have to update those details that are pertinent to the record. We could take it a step further and apply some static and/or module-level variables to hold the base XML stuff, but then we’re faced with having to manage those, such as making sure they’re all cleared/reset when the procedure is done so the next time a new batch starts, there will be nothing left over from the previous batch that’s getting in our way.
  • I don’t really care for doing a bunch of message sending through an eBay API – and the logging of the results after – within the recordset loop. I’d much rather run the loop, store only the few pieces I need, dispose of the recordset, then process all the emails, then log the results of how it all went. I prefer to keep resources tied for as short amount of time as reasonable.

Considering the standard module approach given above and the weak points as described, let’s see what a class module can do for us. Here’s the outline for the class:

Given a class module design under that type of pattern, here’s how we can modify our processing module:

This code is considerably cleaner. Referencing the list of three weak points for the standard module implementation, let’s see how this stands up:

  • The eBay message sending logic is now isolated and completely separate from the logic to handle what messages will be sent and how they will be sent. Next month or next year when we need to modify this to use gmail instead of eBay for messages, we only need to change one thing, which is the class name of the object that we’re creating (this assumes that we’d create a similar emailer for gmail emails which provides the same interface as this eBay one does). We just tell it to use a different type of object at the outset, and if we hold to our interface pattern for both the gmailer and the ebay emailer, we don’t have to change anything else. In fact, we could easily late bind the object and then use either or from within this procedure, if we wanted. (side note: if studying OOP languages, you’ll see the term Interface quite a bit. An Interface is a definition that classes must adhere to, specifically for the reason stated here: so that the classes can be swapped out with no changes to the code that makes use of them. Clean separation – plug ‘n play. Great stuff. In this case, if we were using real OOP, we might want to create an IEmailer interface that says “have a public AddInfo method that takes these parameters, have a public RunBatch method, and provide them a public Results collection”. Then we’d build the gmailer and ebayMailer using the rules of that interface, and we could swap the two in and out anywhere one or the other would be used (not to mention building different types of emailers later, with all these same advantages)
  • XML processing: Now we’ve handled the initial XML setup before we start the loop, and those parameters don’t need to be redone again until we need a whole new emailer class. All the details of this XML stuff is now nicely tucked away inside the class, quite clear of our work area in the main procedure. Furthermore, we don’t need to worry about resetting any variables or tracking what’s been changed or anything of the sort, because now we can create a hundred emailers at the same time (if we wanted), and they would all have their own separate XML.
  • With the new pattern, we can whip through the recordset processing, only loading vital information in a very basic format into a collection in the class. After the recordset is completed and cleaned up, we can then run the processing on all of the items previously stored by calling the emailer’s RunBatch() method. This method would log its results to a collection, which we can then access from our main procedure and do whatever we will with it from there, outside of the context of the class. And so, the class module only processes information related to its requirements, the main logic procedure only processes instructions related to its own requirements, everything is nice and cleanly separated, and maintainability is awesome and scalability is awesome and you sit back and have a drink and pat yourself on the back for having such great looking code!

Another added plus to the eBay emailer class is this: the eBay API, for example, takes various different types of messages. This class was designed with a specific message type in mind, but now that we have this isolated, portable object, we can add handling for other types of messages. We can extend the functionality of this class far beyond its original design requirements, all while – when done correctly – maintaining backwards compatibility for the original design.

The stability, reusability, portability, extensibility, manageability, and whatever other *bilities you want to add (possibilities! (on many levels, that word works: go me! Nice one Jack!)) – so anyway yea… the benefits to using class modules in such cases is clearly significant.

On the business end of things, I toot my horn about quality a lot. Quality in my previous industry of manufacturing was much easier to define and quantify than it is in programming. In programming, it’s much more subtle: it’s not a measure of how good your code works and how many errors you don’t raise, it’s a measure of professional design choices and smart patterns in the code itself for the *bility reasons stated above, because if you tried to do this task in a standard module, the quality of the code – while it may run just fine – would still be sub-par at best compared to the class module route.

Cheers!