The importance of abstraction

I've spent most of the day up to my waist in graph data, for a project that had been behind schedule, so it had picked up some technical debt already. We'd spent a while trying to refactor some third party code (also rushed, and full of technical debt) so this had been a rush fix built on a hacked together prototype.

As I was coming back to it to add a new feature, I went back into the same mindset of trying to get it across the line as quick as possible. Real artists ship after all.

After fervently pounding at my keyboard for most of the morning, I was left with this mess:

Well, thats... not quite right. The aim was to take the jagged downward trending line, pass it through an exponent function to smooth it, and add a single dot to provide a point of reference.

So I took a step back.

Part of the mandate for this project was that all components should be as reusable as possible. As at this point all of the data processing was happening inside the graph component, it seemed to me that the graph knew too much about it's data and would be pretty hard to reuse. So out came the knife, and it was divided up into smaller classes with smaller responsibilities.

As we're using Angular1 for this project, that didn't actually mean more components, as Angular's 'filters' concept makes it easy to chain together small filters that pass their input through, much like unix's pipes.

The process ran something like this:

  1. Should the <graph> be doing the exponential smoothing? - No
  2. OK, lets make a smoothing filter.
  3. Should the filter be manipulating the data set directly? - No
  4. OK, lets make a mapper class (SimpleDataset) to handle manipulating the data.
  5. Should the mapper class try to pretend its the plain data object too? - No
  6. OK, lets add two more filters, one to wrap (o2sds) and one to unwrap (sds2o).

And there you have it. <graph> secretly contained SimpleDataset, o2sds, exponentialSmoothColumn and sds2o. No wonder it felt bloated and awkward to work with.

After stopping to examine where components were trying to take on too much responsibility, it only took me about an hour to tidy up to produce the actual desired result:

In the end if I'd have just spent some time examining the issue from the start, I'd have actually saved time, not wasted it. Plus the mapper class was a great help adding the extra data layer to add the point of reference dot.

Give yourself permission to put your code on a diet too. You never know what useful utilities are struggling to get out of that behemoth of a component!