← /blog
2024.09.22·4 min·craft

In praise of boring code

I used to write clever code. Really clever. The kind where you read it three months later and wonder who approved it. These days I write boring code, and my life is better for it.

What I mean by boring

Boring code is code that does exactly what it looks like it does. No surprises in the implementation. No "wait, how does this work?" moments. The function name tells you what it does, the body confirms it, and you move on with your life.

// clever
const result = arr.reduce((a, b, i) => (a[b] = fn(i), a), {});

// boring
const result = {};
for (let i = 0; i < arr.length; i++) {
  result[arr[i]] = fn(i);
}

Both do the same thing. One takes 2 seconds to read. The other takes 10. In a codebase with 200k lines, that difference compounds into hours per week.

The half-life of cleverness

Clever code has a short shelf life. The trick that impressed your reviewer today will confuse the junior developer next month, and it will confuse you in six months when you're debugging a production issue at midnight. Cleverness doesn't survive context switches.

Clarity, on the other hand, compounds. Every boring function you write makes the next function easier to understand. Every straightforward module reduces the cognitive load for everyone who touches the codebase after you.

I once spent 45 minutes debugging a one-liner that chained map, filter, reduce, and a ternary. The fix was a two-line change. The time wasn't spent fixing — it was spent understanding. That's the tax on cleverness, and everyone pays it.

Practical rules

Name things for what they do, not how they work. A function called getActiveUsers is better than filterByStatusAndDate. The "how" belongs in the body, not the name.

Avoid negation in conditions. if (!isInactive) makes everyone pause. if (isActive) doesn't. Flip the variable, flip the logic, save the reader a mental gymnastics routine.

One level of abstraction per function. A function that mixes SQL queries, business logic, and HTTP response formatting isn't doing one thing. It's doing three, badly. Extract until each function tells a clear story.

Prefer early returns over nested ifs. The guard clause pattern — check the error case, return early, then handle the happy case — eliminates indentation and makes the normal path through the function obvious.

// nested
function process(user) {
  if (user) {
    if (user.active) {
      return doSomething(user);
    }
  }
  return null;
}

// boring
function process(user) {
  if (!user || !user.active) return null;
  return doSomething(user);
}

Don't abstract too early. The first time you see duplication, note it. The second time, note it again. The third time, extract it. Premature abstraction is worse than duplication because it adds indirection that might not be needed.

Boring doesn't mean slow

There's a misconception that boring code is slow code — that you need cleverness for performance. In practice, the opposite is true. Boring code is easy to profile, easy to optimize, and easy to parallelize. Clever code is hard to reason about, hard to measure, and hard to improve because you can't change what you don't understand.

The fastest code I've ever written was boring: a straightforward loop with no allocations, no branches, and no surprises. The profiler told me exactly where the time went, and the fix was obvious.

Write code that your future self, sleep-deprived and debugging at 2am, will thank you for.

← all poststhanks for reading