Simple ain't easy

caeus

Alejandro Navas

Posted on October 16, 2024

Simple ain't easy

"Keep It Simple, Stupid."
"Premature optimization is the root of all evil."
"Perfect is the enemy of good"
"Make it work, make it right, make it fast"
"You are not gonna need it" (YAGNI)

We've all heard these sayings and principles, right? So much so that they've been baked into our DNA as developers. We recite them like gospel, drop them in code reviews, and maybe even slap them onto a motivational poster with a picture of a sunrise.

But let's take a step back. Have we misunderstood these principles? Are we taking them too literally, like some kind of techie version of 'telephone,' where by the time it reaches the last developer in the chain, Keep It Simple has morphed into Take shortcuts, do what's convenient for you, ignore edge cases, and move on?

Underengineering: The Silent Killer

What if I told you that keeping things "simple" (or at least what sounds simple) can actually be more dangerous than adding that extra interface or helper method you were scolded for in the last sprint? Here’s why: simple code and easy code aren’t the same. And favoring "ease" tends to lead to underengineering. You know, that sneaky cousin of overengineering who always dodges the blame in post-mortems?

Let’s get something clear—ease is subjective. "How easy is it to speak Chinese?" is a question with a hundred answers. If you’re from Beijing, it’s like taking a Sunday stroll. If you’re not, it’s like solving a Rubik’s Cube with your feet.

But complexity is different. Complexity isn’t some vague feeling of frustration that arises when trying to understand code after a long night. It’s an objective measure of how many exceptions, irregularities, and "oh, I forgot about that!" cases exist within a system. The more special cases, the more complex the system—period.

This distinction is crucial. When we write code that’s merely "easy," we're optimizing for ourselves and our current state of knowledge. The next developer, probably a junior bootcamp grad who's only been exposed to pristine textbook examples, is gonna look at your code and feel like a detective unravelling a conspiracy.

Anecdote Time: The Non-escaped string.

Picture this: A junior developer, fresh out of their bootcamp, is excited to tackle their first solo ticket. It's a small fix, a string field is not being correctly escaped in a certain endpoint. Being conscientious, they realize that it's a bug of the current implementation, one that could affect any endpoint that's processing strings with especial characters. "Should I fix the current implementation, and therefore fix not only this endpoint, but other that may be affected?"

They ask the team, and the response is something like:
"Don’t over-engineer it. Just fix that endpoint."

And that’s how the codebase accumulates more of those one-off ad-hoc fixes, scattered all over like digital breadcrumbs. Next developer writing another endpoint may face the same problem, same bug, and will spend important time fixing something that could've been fixed if the team had chosen the simple solution over the easy one.

As it stands, we've saved a few minutes up front and added an ongoing cost down the line —More time spent hunting, copy-pasting, and patching. We took the road of least resistance, mistaking it for the best path.

The Burden of Knowledge: Write Code for stupid
So, how do we avoid this pitfall? One trick is to imagine that you’re writing code to be maintained by a team of stupid fresh inexperienced junior developers. No, not that your fellow devs are stupid—although some codebases might make you wonder—but because it forces you to think in terms of clarity and coherence.

Another helpful prompt: Would a junior developer be able to easily ruin this?

If your code relies on deep domain knowledge or a trick you picked up in some obscure corner of the internet, there's a good chance it's not simple—no matter how "clean" it looks to you. Remember, what's intuitive for one developer may be a series of dark rituals for another. Code as if you're leaving behind a trail of breadcrumbs that any developer can follow, without needing to text you at 2 a.m. for directions.

KISS Isn't an Excuse for Laziness

So, yes—Keep It Simple, Stupid. But also, Keep It Smart, Sensible. The problem with sayings is they don't tell you what to do when you've hit the sweet spot between too much and too little. When you take shortcuts, you're not simplifying, you're just putting future-you in a world of pain.

Conclusion: Striking the Balance

The real art lies in finding the balance—making code simple, not easy. Aim for solutions that are straightforward, not quick hacks that fit your immediate mental model. That might mean adding a couple more lines or splitting that big class that doesn't seem worth it now. Because good code is a lot like explaining something to a five-year-old: it takes extra effort to strip away the jargon, to rephrase the convoluted, and to ensure the core idea is both obvious and reusable.

In the end, the difference between a complex mess and elegant simplicity is rarely about what you did, but why you did it. Take the time to do it right, and your code won't just be clean—it'll be future-proof. After all, the only thing worse than over-engineering is under-engineering.

💖 💪 🙅 🚩
caeus
Alejandro Navas

Posted on October 16, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related