Thursday, June 21, 2012

Artistic Test Harnesses

Modern object-oriented development is primarily cobbling small pieces of reusable functionality together. In the midst of development — during Spring training when you are hitting, running, throwing, and batting all day — you implement very specific business rules in small modules. Given certain input conditions and certain characteristics of the underlying data the invoker expects you to return the right properties or accomplish a persisted change in the data with a specified method.

Quite frequently the classes doing the heavy-lifting work behind the scenes without any visible interface to the user. How then do you make sure that your modules work properly? And how do you verify they work correctly under different conditions when called by different classes and when the underlying data changes? This job my friend calls for the use of a test harness.

A good test harness is like an automated batting cage where you can walk in, press a button for sixty mile per hour pitches, and have a machine throw consistent strikes.

Essentially a test harness is an ugly, quickly thrown together form with a handful of buttons and data-bound fields (or perhaps a data grid) that allows you full access to all of the ways possible to invoke your methods and set or get your public properties.

I like to use a tabbed interface when I’m building a harness; frequently I develop several objects simultaneously as part of a larger library and each tab tests the features of one of the objects. The complete form thus covers a large chunk of the library. Click a different tab to have a slower or faster pitch thrown toward you.

The best part about a harness, aside from the convenience it affords to unit testing, is that in the throes and craziness of implementation you can use it for quick and dirty fixes (invoking methods directly rather than bothering a fully implemented interface). Yes you can always take a shortcut and set debug checkpoints to carry out unit tests. But the extra flexibility and thoroughness afforded by a test harness, even though it requires an extra day to throw together, is always well worth the effort.

Tuesday, June 5, 2012

Artful Deprecation

In a couple earlier posts I discussed three alternatives for handling changes to business rules in an object-oriented development environment. Now we come to the last approach, deprecation. We use deprecation when we want to "take back" a previously distributed method; we want to completely replace its implementation with something new and different.

Rather than reusing the same method name, we create (within the same class) an entirely new method with a new name. Then in meta-compiler statements we deprecate the old method (we prepend the "Obsolete" directive) so that if a developer attempts to use it they will receive a pop-up that recommends that they use the new method name instead. Unlike an overload, it may not be possible for to modify the old method to call the new method with nulls in the new arguments. Do it however if a safe way can be found to "translate" between the two methods.

The only drawback with deprecation is that once a team becomes accustomed to certain common method-names it becomes a hassle to have to relearn them. Usually when you deprecate a method you will make an extra effort to communicate this change to the development staff with a global notice; you may even make the effort to search the source code library for any routines that used the old method and then schedule some working time to update them.

In summary then, handle change by overloading, inheriting, propertizing, and deprecating, but use the approach that is appropriate for your situation.