The Abstraction I Built For A Second Case That Never Came

by Serguey Shinder

The requirement was simple enough that I felt slightly insulted by it. One report, one format, one consumer. I could have written it in an afternoon as a function that did exactly that and nothing else. Instead I spent three days building a small framework, because I could see, clearly and confidently, that there would be a second report soon, and a third after that, and I did not want to be the person who had to rewrite everything when they arrived.

I built an interface, a registry, a configuration layer, and a pair of extension points that were beautifully general and completely unexercised. I was proud of it in the way you are proud of a thing that anticipates the future. My reviewer, who had been doing this longer than me, asked whether the second report existed yet. I said it was coming. He approved the change anyway, which I took as agreement, and which I now think was patience.

The second report did not come. Something changed in the business, priorities moved, and the thing I had prepared for simply never happened. What remained was one report being produced by a machine designed for many, and every person who later touched that code had to understand the whole apparatus in order to change one line of output. I had turned an afternoon of work into a permanent tax on everyone downstream of me, paid in comprehension, forever.

The part I got wrong was not the prediction, though the prediction was wrong. It was the belief that generality is free once you have written it. It is not. An abstraction is a promise that the variation it allows for is real, and every reader has to take that promise seriously, tracing through indirection to find out what actually runs. When the variation never materialises, the reader pays the full cost of a flexibility that buys nothing.

What I have learned since is that the cheapest thing to change is code that is small and specific. Two functions that repeat themselves are easy to merge later, once you can see what they genuinely have in common, and by then you are working from evidence rather than imagination. A wrong abstraction is far harder to unwind, because it has already shaped everything that grew around it, and unpicking it means touching all of that too.

So I let things stay duplicated for longer than feels comfortable now, and I wait until the third case rather than the second before I generalise anything. It looks less clever. It occasionally means doing the same work twice. But I would rather write a small amount of honest repetition than build another elegant structure whose only justification is a future I confidently invented and never once had to live in.

– Serguey Asael Shinder

Leave a Reply