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:

  class Form < ActiveRecord::Base
    has_many :form_revisions
    # ...
  end

  class FormRevision < ActiveRecord::Base
    has_many :form_sections
    has_many :form_signoffs
    # ...
  end

  class FormSection < ActiveRecord::Base
    has_many :form_questions
    # ...
  end

  class FormQuestion < ActiveRecord::Base
    # ...
  end

  class FormSignoff < ActiveRecord::Base
    # ...
  end

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:

  form = Form.create!(:name => form_name)
  first_version = FormRevision.create!(:form => form, :version => 1)
  acceptance_section = FormSection.create!(:name => "Acceptance Criteria")
  rejection_section = FormSection.create!(:name => "Rejection Criteria")
  first_version.form_sections < < acceptance_section
  first_version.form_sections << rejection_section
  first_version.form_signoffs.create!(:name => 'Counselor')

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

  form = Form.find_by_name(name)
  form_version = form.current_version
  section = form_version.sections.find_by_name('Acceptance Criteria')
  section.form_questions.create!(:text => question_text)

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:

  class Form
    def self.create_application_form!
      # ...
    end

    def add_criterion(question_text, kind=:acceptance)
      # ...
    end
  end

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:

  require 'delegate'
  class ApplicationForm < DelegateClass(Form)
    def self.create!
      form = Form.create!(:name => form_name)
      first_version = FormRevision.create!(:form => form, :version => 1)
      acceptance_section = FormSection.create!(:name => "Acceptance Criteria")
      rejection_section = FormSection.create!(:name => "Rejection Criteria")
      first_version.form_sections < < acceptance_section
      first_version.form_sections << rejection_section
      first_version.form_signoffs.create!(:name => 'Counselor')
      self.new(form)
    end

    def add_criterion(question_text, kind=:acceptance)
      form_version = current_version # delegated to the underlying Form
      section_name = 
        (kind == :acceptance) ? 'Acceptance Criteria' : 'Rejection Criteria'
      section = form_version.sections.find_by_name(section_name)
      section.form_questions.create!(:text => question_text)
    end
  end

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:

  # To create a form:
  form = ApplicationForm.create!
  form.add_criterion("Do you own an Escalade?", :rejection)

  # To modify a form:
  form = ApplicationForm.new(Form.find(form_id))
  form.add_criterion("Can you count to ten without using your fingers?",
                     :rejection)

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.

  describe ApplicationForm do
    before :each do
      @form = stub("form")
      @it   = ApplicationForm.new(@form)
    end

    it "should be able to add eligibility sections to the form" do
      @form.should_receive(:current_version).and_return(stub("version"))
      # etc...
      @it.add_criterion("Test")
    end
  end

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:

  require 'delegate'
  class ApplicationForm < DelegateClass(Form)
    # ...
    def name
      __getobj__.name + " (Aid Application)"
    end
  end

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.

8 comments

  1. could do something like this:

    view plaincopy to clipboardprint?
    int sum = x.get() + y.get();
    This will block the current thread until both of those integers are available, then add them together. But why wait for that? If you have an ExecutorService, you can create a new Future that computes the sum:

    view plaincopy to clipboardprint?
    Future<Integer> sum = executorService.submit(new Callable<Integer>() {
    public Integer call() {
    return x.get() + y.get();
    }
    });
    Now the current thread can continue, but we’ve started a new thread that does nothing until the values of x and y have both been calculated by yet another thread.

    We’re beginning to see a problem here. We want to be able to compose Futures together to form new Futures, but find that the number of threads required to compose n Future values is on the order of O(n). If we have a fixed-size thread pool, we’ll run into starvation. If we have an unbounded thread pool, then we might start more threads than the operating system can handle, most of which will be doing nothing at all but wait for other threads.

    This should all sound very familiar. Threads are a space resource. What kind of processes are O(n) in their space requirement? If you said “linearly recursive processes”, go to the head of the class. Intuitively, for the same reason that we can find iterative versions of any recursive algorithm, it seems that we should be able to find an algorithm to accomplish the same thing with O(1) threads.

    …and it is a Monad

    In the above example, it’s like we’re giving seperate instructions, waiting for the results of each in between. Imagine if we were working in an office with Bob and Alice, and we needed work on something from both of them. We might go to Bob and say: “Bob, process this and give me the result”. Then we’d take the result to Alice and say: “Alice, here’s a result from Bob.” It would be much better, if we could just go to Bob and say: “Bob, process this and give the result to Alice.” This is the essential difference between recursive and iterative processes.

    But wait! We say that kind of thing all the time, in Java:

    view plaincopy to clipboardprint?
    public Work bob(Work w) { … }
    public Work alice(Work w) { … }

    public Work bobThenAlice(Work w) {
    Work b = bob(w);
    return alice(b);
    }
    Here, we’re instructing a single thread to do some work, then use the result of that work to do more work. What’s really sneaky here is the meaning of the semicolon. In this context, what the former semicolon means is “take the stored value b from the previous statement and bind it to the free variable b in the next statement”. You can think of the second semicolon as binding a blank statement over the result of the preceding statement.

    Using first-class functions from Functional Java, and using the Callables monad from the first part of this series, you could implement that same behaviour using something like this:

    view plaincopy to clipboardprint?
    F<Work, Callable<Work>> bob = new F<Work, Callable<Work>>() {
    public Callable<Work> f(final Work w) {
    return new Callable<Work>() {
    public Work call() { … }
    };
    }
    };
    F<Work, Callable<Work>> alice = new F<Work, Callable<Work>>() { … };

    public Callable<Work> bobThenAlice(Work w) {
    return Callables.bind(bob.f(w), alice);
    }

Leave a Reply

Your email address will not be published. Required fields are marked *