Mathieu Eveillard

Don’t write code that guesses the future

Don’t write code that guesses the future

Don’t write code that guesses the future; arrange your code so you can adapt to the future when it arrives.

This quote from Sandi Metz urges us to exercise restraint and elegantly highlights a very real pitfall in software development: over-anticipation.

An example: the 1-N (one-to-many) relationship in SQL. “It could evolve into an N-N relationship,” we tell ourselves. It’s even very likely—it’s planned for in 6 months, a year at most. So right from the start, we set it up as an N-N relationship, with the “appropriate” join table and all the trimmings, and we effectively use it as a 1-N relationship.

This is a real-life example; I’ve seen it. In fact, I’ve seen worse: a company that implemented all relationships—including 1-to-1 relationships—as N-N relationships, because… “just in case” 😮

So long as a 1-to-N relationship remains a 1-to-N relationship, everything will be just fine. On the other hand, we can ensure that any changes, should they occur, are as localized as possible. Domain isolation can help, though it probably won’t be enough on its own (hexagonal architecture, functional core/imperative shell).

Failing to plan ahead is a subtle art: since that upcoming feature and the complexity it brings won’t be an issue right away, let’s not lay the groundwork for it just yet. Let’s wait until it actually arrives, save the generics for later… while making sure it can happen.

So it’s a real tightrope walk, a balancing act. To be honest, this quote has haunted me for years, because I don’t see any obvious heuristics. The code I write might not be “enough,” unless it’s “already too much”—how can I know?

It’s all the more difficult because our creative minds are fascinated by complexity and power. There will always be that temptation to do a little more—just “in case,” “because it might come in handy,” or “it doesn’t cost any more”; it’s tempting, but it’s already the beginning of the end.

Why is this over-anticipation problematic?

Because the future has a knack for being unpredictable: that feature, which we’re certain will happen, might not happen after all. Because users tell us the feature isn’t useful, or isn’t a priority, or because the budget runs out—you know the drill (all those situations that call for Agility). So you’ll have spent weeks writing code that adds no value to the user.

Code that, at the same time, complicates the entire codebase. The code, once simple and concise, now reflects a more complex, more abstract model, of which the application’s features are merely a special case (once again, all of this is done in anticipation). You’re dragging this extra code around like a ball and chain: implementing new features takes longer and comes with more bugs.

It’s therefore better to introduce complexity just in time, at the very last moment, by relying on an architecture that leaves the door open.

← All posts