Chapter 4: Let Go of Cleverness
“Everyone knows that debugging is twice as hard as writing a program in the first place. So if you’re as clever as you can be when you write it, how will you ever debug it?”
— Brian Kernighan
I once wrote a function I was deeply proud of. It was a single line that dynamically constructed nested configuration objects from dot-separated strings. You could call it with cfg("database.pool.max", 10) and it would build the whole nested structure on the fly. Elegant. Compact. Clever.
Here’s the one-liner I shipped:
const cfg = (key, value, config = {}) =>
key.split(".").reduce((acc, part, idx, parts) => (
acc[part] = idx === parts.length - 1 ? value : acc[part] || {}
),
config
);
I showed it to a colleague, expecting admiration. He stared at it for a long moment, then asked what it did. I explained. He asked why I hadn’t just written it the obvious way. I didn’t have a good answer.
The obvious way would have been this:
function createNestedConfig(path, value, config = {}) {
const keys = path.split(".");
let current = config;
for (const key of keys.slice(0, -1)) {
if (!current[key]) {
current[key] = {};
}
current = current[key];
}
current[keys[keys.length - 1]] = value;
return config;
}
More lines. Less impressive. But anyone reading it could understand what it did without needing it explained. My clever version required a pause, a squint, a mental unpacking of the reduce and the ternary and the mutation inside the accumulator. It was a small puzzle that gave me pleasure to write and would give everyone else a headache to maintain.
I merged the clever version anyway. I was proud of it.
Six months later, someone tried to chain configuration calls and the whole thing fell apart. The function didn’t even return the config object. It returned whatever value you’d just set. The bug had been there from the beginning, but the code was so dense that nobody had questioned it, including me. I’d looked at that function dozens of times. I’d never actually traced what reduce returns when you write it that way.
It took me an hour to admit my own code was the problem. I had to re-derive what I’d written, step by step, before I could see what should have been obvious: I’d been so focused on making it clever that I’d never checked if it was correct. The person who eventually fixed it replaced my one-liner with something boring and obvious. I felt a small sting of loss, followed by relief.
The Seduction
Cleverness feels like mastery. When you compress something complex into something dense and elegant, there’s a satisfaction that’s hard to explain to non-programmers. You’ve done something impressive. You’ve proven something about your ability to hold complexity in your head and manipulate it fluently.
The problem is that this feeling optimizes for the wrong thing. It optimizes for the moment of writing, not the lifetime of reading. And code is read far more often than it’s written.
I’ve noticed that my desire to be clever peaks when I’m feeling insecure. New job, new codebase, new team watching my pull requests. That’s when the temptation is strongest to write something that demonstrates sophistication. Look at this. Look what I can do. The code becomes a performance rather than a solution.
The clearest code I’ve encountered barely seems like code at all. It reads like a description of what needs to happen, written for a future reader who might be tired, or distracted, or new to the codebase. There’s nothing to admire because there’s nothing in the way.
I’m still learning to write like that. The ego wants to leave fingerprints.
The Clever Trap
Early in my career, I worked on a marketing automation platform. Our team built the engine that let customers chain workflows together: if a user does X, trigger workflow A, which might trigger workflow B, and so on.
The problem, obviously, was loops. What happens if workflow A triggers B triggers A? The naive answer is infinite recursion, a system that emails your customers until someone pulls the plug.
We needed loop detection, and we were proud of the solution we came up with. Each workflow execution carried the ID of the workflow that triggered it. Before running, we’d check: did my parent trigger me? If so, we were in a loop. Elegant. Simple. Clever.
It worked perfectly for direct loops. A triggers B triggers A: caught. But it completely missed indirect loops. A triggers B triggers C triggers A: not caught. We’d only ever looked one step back.
The failure happened on a Thursday night. A customer’s workflows started looping, firing over and over, sending thousands of duplicate emails to their most important clients. The system slowed to a crawl. Support tickets poured in. We spent the entire night trying to figure out what had gone wrong.
The worst part wasn’t the technical failure. It was how long it took us to consider that our clever solution might be the problem. We’d been so pleased with its elegance that we’d developed a blind spot. We kept looking for bugs elsewhere, in the workflow definitions, in the queue processing, anywhere but the loop detection we’d been so proud of.
When we finally traced it back to our code, the fix was embarrassingly simple. Instead of tracking just the parent, track the entire history:
function runWorkflow(workflowId, context = { history: [] }) {
if (context.history.includes(workflowId)) {
throw new Error(
`Cycle detected: ${context.history.join(" -> ")} -> ${workflowId}`
);
}
const workflow = workflows[workflowId];
const nextId = workflow.execute(context);
if (nextId) {
runWorkflow(nextId, {
...context,
history: [...context.history, workflowId]
});
}
}
Not clever. Just correct.
What Cleverness Costs
The customer whose emails got blasted was furious, and rightly so. We spent weeks rebuilding trust, offering credits, writing postmortems. The engineering team’s morale took a hit; we’d believed we were good at this, and now we had evidence that our pride had blinded us.
But the cost I think about most is subtler. It’s all the hours we spent not questioning our solution because it felt too elegant to be wrong. Cleverness created a kind of immunity to scrutiny. We’d admired our own work so much that we stopped looking at it clearly.
I see this pattern everywhere now. The abstraction that’s so clever it takes twenty minutes to explain in code review. The type system gymnastics that technically prevent a category of bugs but that nobody on the team can read. The architecture that’s beautiful on the whiteboard and miserable in production.
Each of these has the same shape: someone optimized for the feeling of being smart rather than the outcome of being understood. And each of them accumulates cost that’s invisible until something breaks.
The Humility of Clarity
Clear code tends to come from experience, which seems paradoxical until you realize that experience includes getting burned by your own cleverness enough times to stop trusting it.
There’s a particular kind of humility required to write obvious code. You have to accept that your job isn’t to impress anyone. You have to care more about the person who’ll read this at 2 AM during an incident than about the satisfaction of an elegant solution. You have to be willing to look ordinary.
I remember reviewing a pull request from a principal engineer, someone with decades of experience. The code was so simple I almost asked if he’d meant to include the rest of it. Just a few functions, clearly named, doing exactly what they said they did. No tricks. No compression. Nothing clever.
I asked him about it later. He said he’d learned that his job was to make the next person’s job easier. If they had to pause to understand his code, he hadn’t finished writing it. “Cleverness is a tax on everyone who comes after you,” he said. “I try to pay my taxes differently.”
That phrase stuck with me. A tax on everyone who comes after. Every time I’m tempted to write something clever, I try to think about who’s going to pay that tax and whether it’s worth it.
Simplicity as Strength
There’s a misconception that simple code is the same as easy code. It’s not. Simple code is often harder to write than clever code because it requires you to fully understand the problem before you start solving it. Cleverness lets you skip that step. You can write something dense and impressive without ever having to articulate clearly what it’s supposed to do.
The forty-minute rewrite from Chapter 3 was simple. The three-week struggle that preceded it was full of cleverness: abstractions trying to be general, edge cases handled with tricks, patterns borrowed from blog posts that didn’t quite fit. When I finally saw the solution clearly, the cleverness evaporated. It wasn’t needed. It had never been needed. It was just what I’d reached for when I didn’t understand the problem well enough to write something obvious.
I’ve started treating the urge to be clever as a diagnostic. When I feel it, I ask myself: am I writing this because it’s the right solution, or because I don’t know what the right solution is? Usually it’s the second one. The cleverness is a way of hiding my confusion from myself.
The code that lasts, the code that gets copied into new systems and outlives the teams that wrote it, is almost never clever. It’s just clear. It says what it means and means what it says. It doesn’t require anyone to be impressed by it. It just works.
Letting Go
Somewhere in a codebase I left years ago, my clever one-liner has been replaced by something obvious. Somewhere else, an elegant abstraction I was proud of has been rewritten into something boring and maintainable. These things used to bother me. Now they feel like evidence that the system is working. The code got better after I stopped touching it.
Letting go of cleverness isn’t a single decision. It’s a practice, like the practices in the previous chapters. Each pull request is an opportunity to choose clarity over impressiveness. Each code review is a chance to ask whether the cleverness serves the reader or just the writer. Each debugging session is a reminder of what cleverness costs.
The Kernighan quote at the top of this chapter has been in my head for twenty years. It’s one of those pieces of wisdom that sounds obvious until you catch yourself violating it. If you’re as clever as you can be when you write the code, you’ve already used up all your capacity. There’s nothing left for the inevitable moment when something goes wrong.
Write for the debugger. Write for the maintainer. Write for the person who’ll read this when they’re tired and confused and just need to understand what the code does.
That person, more often than not, will be you.