Progressive Abstraction

OCTOBER 23, 2013

Balancing Is Important

In this post I am telling a tale of quickly finding the balance point between building future proof abstracted code and an MVP (Minimum Viable Product). It is an important lesson when building large projects on tight timelines. Developing for a larger/tighter project/timeline means staying inside the lines of the specification given by management/customers. Getting outside the lines has implications for each and every sprint along the way.

Balancing Means Making Small Adjustments

Watching a tight-wire artist, I find it striking how little side-to-side movement they make. They start out with a small step and then through a progression of more and more small measured steps they end up at the other side. When developing balanced code, taking similar small steps removes the need to compensate for overcompensation (if that makes an sense). I'm saying that every sideways movement has a sideways movement of equal force in the opposite directions. I am minimizing the initial movements so I can focus on moving forward rather than staying on the wire.

Progressing from Status-Quo to MVP to Abstracted Code

I am starting the journey from status quo to a leading design by taking some email queuing code and copying it into a wrapper class. Making very few changes to the part of the code creating the email queue payload, I am focusing on providing it the data it needs to create all the email fields it requires. If the payload requires an email address, a first and last name, and a username, then I am not going to change the way those fields are used. I am only changing the way that data is provided to the status quo code. That is the first small step. Writing unit tests and verifying that the email queue generating is identical to the status quo will ensure that the inputs and outputs are well defined.

Step two is moving from status quo to an MVP. That means ensuring that the email queueing code is performing it's actions at the right time, and responding to the appropriate events. In my case that is responding to the user signing up for a new subscription. Step two is making sure my new queueing class is working in the system I am designing for.

Step three is abstracting the MVP to work for other similar situations. I am accommodating multiple subscription types and multiple subscription events by using a proxy pattern. My email queuing service is acting as a proxy, using the subscription type and subscription event, to route a queue request to the appropriate email payload builder: setting the custom content of the payload respective to the fields and values.

By abstracting at this point, I am solving for the current situation (sending a purchase confirmation email for a specific subscription type). I am making it easy to test and verify that it is working for this use case. Taking a more meaningful step to a design that can accommodate multiple email types and handlers requires first dealing with one effectively.

Safely Making a Larger Step at the End

It will not harm to start by abstracting code to work for at least one other use case, although not handling that use case specifically. Instead of working on an email handler for a use case I am not currently working on, I am throwing an exception, When a consumer uses it to queue an email for a payload not having a payload builder, my code neatly barfs. The tests are asserting for failure cases where the email is either not existing or is experiencing an error. It's exceptional behavior, but at least it is expected.

It is something not unlike when a tight-wire artists leaps from the wire to the platform after performing a balancing act. It is showing a command of the situation, by exhibiting control when the risk is low that failure will cause catastrophe.