Premature Flexibilization Is The Root of Whatever Evil Is Left

Dan Milstein

Okay, so you know how they teach you, in Computer Science school, that lovely quote: "premature optimization is the root of all evil"? (variously attributed to Donald Knuth, or Tony Hoare, or other CS luminaries).  Well, in my more recent experience, there's another programmer habit which is in hot competition for the evil-rooting title.  I don't think it has as catchy a name, so I'm going to propose one here: Premature Flexibilization.

And here's what I mean: the practice of adding complexity to your code to make it more "flexible", in anticipation of future change.

Why would this be so bad? I hear you saying.  I mean, we all know that software requirements change, so isn't it good to make your code future-proof, by making it flexible, able to handle those changes that are inevitably going to come?  Most of the classic expositions of the glories of Object-Oriented programming are rife with this -- look, we're using abstract classes, so now the subclasses can vary, thus our code will be flexible and reusable, isn't that great?

Here's why this fails so badly in real life: it's not just that requirements change, it's that they almost always change in ways which the initial programmers didn't expect. E.g. you've got your nice abstract base classes, all set to add more variants, but it turns out you just need the one variant... but you need to add a whole bunch of features to it.  Or you have to make it thread-safe.  Or connect it via RPC to Javascript code running in a browser.  Or auto-generate it via a script.  But, because you've made it flexible in one direction (adding more variants), you've also made it harder to vary in other directions (features, thread-safety, connecting-to-a-browser-ness, auto-generability).  This is a near iron-clad rule: flexibility comes with attendant complexity, and complexity makes things harder to change in unexpected ways.

Or, to put it another way: if you make something as absolutely damn simple as possible, then extending it along any axis is at least doable.  But that's the only way.

Take a careful look at Design Patterns, that classic text of OO design.  Notice how so many of the patterns are about making your software flexible, about making it adaptable to change.  Then notice that all their lovely real-world examples are for frameworks which no one uses anymore.  They've been replaced by other "flexible" frameworks (actually, they've usually been replaced by several generations of "flexible" frameworks, each of which turned out to be the wrong kind of flexible)

In contrast, consider the C standard library.  It wasn't designed to be flexible, it was designed to be as simple as possible. And, lo, these 35 years later, it's still being used.  Sure, it's been wrapped by other layers, improved this way and that, but it's still a live thing.

Also, note that "simple" is a very subtle idea.  It doesn't necessarily mean "crude".  Sometimes, the simplest way to do something is to, e.g. write a Domain-Specific Language--which is in no way trivial.  But, and here's the key distinction, it's a solution to the problems you have right now.  It's not a solution to problems you think are coming later.  If you can train yourself into the deep habit of only solving today's problems, you'll be far better prepared for tomorrow than if you tried to look ahead.

What do you think?  Agree? Disagree?  Any examples that loom large in your experience?

wan