Writing Facades on Legacy Code

h2. The Setup

Let’s say we have a system in production which manages college financial aid departments. Over the years it has accumulated a fairly complex object model for handling the many kinds of forms a financial aid department has to generate and process. It’s not the most elegant and well-factored model in the world, but it gets the job done.

Here are a few of the classes involved in the forms component of the system:

h2. The Problem

One particular subsystem deals with student applications for financial aid. All of the application forms have a common essential format: a section listing acceptance criteria that must be met in order to qualify; a section listing exclusion criteria which might disqualify the student, and a field for the financial aid counselor to sign off that the student filled out the form correctly.

Currently whenever an administrator clicks the “new application form” button, the controller code which creates the new form does it something like this:

The process for adding a new acceptance or rejection criterion is similarly tedious:

The tests for this logic (which is all contained in controllers) have to duplicate all of this setup in order to exercise the controllers with realistic data. Lately the devs have taken to using Factory Girl to make the setup easier, but it’s still a duplication, and it seems like there’s always some little detail of how the application code assembles a form that differs from how the test code does it. The other day one of the devs tried to debug one of these differences by manually assembling forms in the console, but he quickly got frustrated by all the steps necessary to get the form “just right”.

h2. Facade Methods

Clearly, there is an opportunity for simplification here. One option is to add some facade methods to the Form class which encapsulate the complexity of building application forms:

However, in our hypothetical financial aid system the Form class is already over 1000 lines long, and the developers have decided to draw a Picard Line on it. Not only that, but application forms are only one of many different kinds of forms that the system manages. If the Form class were to contain specialized code for every type of Form it manages, it would grow unmanageably large.

Subclassing is a possibility. But this system doesn’t use Rails Single Table Inheritance, so even if you saved an ApplicationForm it would come back as a plain Form next time you loaded it, and Ruby doesn’t provide any convenient way for us to downcast it to the correct type.

h2. Wrapper Facade

This is a situation where a Wrapper Facade may be called for.

(Note: I got the term form this paper by Doug Schmidt. I believe the pattern described here follows the spirit, if not the letter, of that work.)

It could look something like this:

Here we use the Ruby ‘delegate’ standard library to define a wrapper class which will delegate all undefined calls to an underlying Form instance.

Using the wrapper is straightforward, if slightly more verbose than using methods directly on the Form class:

h2. Advantages Over Other Approaches

Using a delegate class confers several useful advantages. For instance, it is very easy to construct unit tests that test just the functionality in the wrapper facade by mocking out the underlying Form instance.

Using a wrapper instead of extending the @Form@ instance with a module means we can selectively override methods in the Form class if needed. Below, we override the @Form#name@ method with our own which appends some text to the name:

Using a delegate also gives us our own namespace “sandbox” to play in. Any instance variables we use in implementing @ApplicationForm@ will be kept separate from the @Form@ instance variables, so we don’t have to worry about naming clashes.

And, of course, if we ever decide that some or all of the code in the wrapper does belong in the @Form@ class, it is simple enough to move it over.

h2. Conclusion

To sum up, the Wrapper Facade is a useful tool to keep in your toolbox for situations where you want to simplify a particular scenario for a class, without adding any code to the class itself.