I used to think removing special cases – the extra if statement that handles the unusual file format that doesn’t quite fit – was the best way to improve my programming. Every time I had to add a special case to a function it meant I wasn’t solving the problem generally enough.
In a way, which I’ll come to in a moment, this was ok. In a much more important way, it was really-and-I-mean-shoot-yourself-in-the-foot-and-throw-the-remains-into-a-vat-of-industrial-strength-paint-stripper stupidly wrong.
What made it right was my innocence – back when I knew nothing about programming (i.e. when I thought I knew everything) longer-lived programs started accruing odd if-statements and shoe-horned additional functionality all over the place until they were an ugly, barnacled mess of additions and changes that I didn’t understand and couldn’t work with any more. Every time I promised myself that next time I’d resist the temptation to add just one little exception and instead refactor to a more general level right away and everything would be clean and smooth and regular and easy to work with forever.
I guess lots of people have reached the same conclusion, because I notice examples of the unsaid assumption that Special Cases Are Harmful a lot. Today, I’m taking a stand: adding special cases – making exceptions – is the single most important thing we can do.
It’s All Fun And Games Until Someone Loses An AbstractEyeMonsterFactoryFactory Class
I wrote lots of little games when I was learning to program and I’m guessing you did, too. I made them because I wanted to play them, and that meant I tried to generate levels and enemies randomly in the hope that my own game could surprise me. I didn’t want to add special code for boss monsters or for each level – that would defeat the point. Every level had to run the same code, just with different data. No special cases, remember?
Well, all of my games sucked. Sometimes the mechanics were fun enough, but after a couple of levels the game just got boring. Algorithmically-generated enemies and levels simply weren’t interesting, because after a while the patterns became obvious and then there was no reason to keep exploring deeper into the game; one level was much the same as any other.
I’m sure this is stupidly clear to anyone who actually designs games for a living or works in the industry, but it was a revelation to me that the most interesting and valuable parts of a game are the parts that show a human touch, where I could feel the presence of a real person who put some thought into the experience. While ‘special cases’ looked like cruft at the level of an individual algorithm, they turn out to be the essential, core content and personality at the user-facing level. I’d been systematically stripping my work of any personal, human touch whatsoever.
In real applications, whether games or business sites, special cases add a massively disproportionate amount of value.
Posterous know this – they’re laboriously and painstakingly adding beautiful import functionality from each of the other major blogging platforms. Each one is a special case, they didn’t restrict themselves to one common ‘import blog’ feature that scans a page and does its best to rip the text, formatting and images – no, they give users from each of the major platforms special, individual treatment.
Google were the first to do this in a big way in search: how cool is it when Google converts a currency right there are the top of the page? Or shows the weather forecast? Or the cinema listings? Each of these are laboriously hand-coded special cases. I once met a guy at Google whose full-time job was working on showing sports results at the top of mobile search queries. That’s dedication to the special case.
There’s a couple of reasons why looking at special cases are often better than adhering doggedly to an increasingly complex general case:
- Special cases are solvable. We can be very, very clever when we’re only handling a small, discrete part of a problem. The general ‘show the most relevant information to a search query in an immediately readable and usable way’ is so hard it’s still unsolved despite decades of attempts. Just look at Wolfram Alpha. In comparison, pulling up the current forecast for queries containing a local word for ‘weather’ is almost trivial.
- The results are better. The general ‘import blog’ problem is hard to get exactly right, but we can write code to import just wordpress blogs perfectly because the problem domain is both smaller and better defined.
- Whatever we think about solving the general case is almost certainly wrong until we’ve solved a few special cases first. The real world is not a well-defined problem; special cases help us explore the problem space.
I’m tired of hearing that ‘if you solve a problem right, you only have to solve it once’. Yes, this is fine in theory, but is completely bonkers when applied to the changable, unpredictable real world. If we try then most of the time we:
- Never find a perfect ‘general’ solution for all cases, or
- Find one but spend so much time and effort on it that we neglect a million other important things, or
- Get ‘close enough’ and just stop, which means a solution that’s imperfect in most cases, and by ‘imperfect in most cases’ I mean ‘that makes most people slightly unhappy’.
Look After The Pennies And The Pounds Will Look After Themselves
You know what? When we try so hard to make each special case just right, general cases will start to fall out naturally. This is the right way around. The other way, hypothesizing a general case and enforcing it onto everyone, that is the wrong way.
Look after the special cases and the general case will look after itself (well, unless you’re unusually incompetent)
– Mark, Make Exceptions
Adding super-slick handling for a few common cases is such ridiculously low-hanging fruit that I can’t believe so many companies miss the opportunity. I think it’s this pattern of reasoning we learn when we begin programming – this desire to avoid messy details and refactor to a more general level that handles all those cases implicitly. It turns out that this simply doesn’t apply well to product design and, if we want anyone to use the programs we’re writing, we should always be thinking about product design.
So yes: we can make exceptions for people and go out of our way to make them smile. People are trying to accomplish real tasks with our applications, our websites, our businesses. We have to keep looking out for next special case we can handle that makes just one of those tasks improbably and awesomely simple. Software’s not about ticking the most feature boxes with the fewest function calls, it’s about making someone’s day.
Note: Yield Thought has moved to http://yieldthought.com – check there for the latest posts!