Jako Heiberg
HomeInsightsMusingsPortfolioAboutContact
Jako Heiberg

From DBase III+ to edge computing.
The journey continues.

Pages

  • About
  • Portfolio
  • Resume / CV
  • Insights
  • Musings
  • Archive
  • Contact

© 2026 Jako Heiberg · Cape Town, South Africa · UTC+2

Built with React + Cloudflare Workers. No PHP was harmed.

Back to Insights
Insights

The Perfect Code Illusion: Why Good Enough Is Usually Better

Every developer has a codebase they're ashamed of. The secret is that perfect code is mostly a myth — and chasing it is often the actual problem.

April 21, 2026
5 min read

The Perfect Code Illusion: Why Good Enough Is Usually Better

Somewhere in every developer's career, they encounter code that makes them wince. A function that does six things. A variable called data2. A comment that says // fix this later with a date from 2019. A module that was "temporary" and is now load-bearing infrastructure.

The first response is judgment. The second, more mature response is empathy. And the third, hardest response is to genuinely grapple with the question: was this actually wrong?

The Cost of Imperfection Is Real

Let me be clear before I argue the other side: bad code has real costs. Code that is hard to read is hard to change. Code that is hard to change attracts workarounds. Workarounds accumulate. Eventually, the codebase is a calcified mess where every change takes twice as long as it should and introduces twice as many bugs. Technical debt is a real thing that real companies collapse under.

So the goal is not to write bad code. The goal is to think clearly about what "good" actually means in context.

What "Clean Code" Actually Costs

Clean code — well-named, well-structured, with clean abstractions and no repetition — takes time. It takes time to write, and perhaps more importantly, it takes time and understanding to design. You need to know what the code needs to be before you can design it cleanly. Often, you don't have that knowledge yet.

This is the dirty secret of premature abstraction: the abstraction that looks elegant when you build it is frequently the wrong one. You pull out a shared function because two things look the same. Then a third requirement comes in and they're no longer the same, and now you're working around your own abstraction. The duplication you so efficiently eliminated has turned into a tangled dependency.

"Three strikes and you refactor" is a more defensible rule than "don't repeat yourself." Let things repeat until you understand the pattern well enough to abstract it correctly.

The 80/20 Rule of Code Quality

In most codebases, about 20% of the code changes frequently and matters a lot. This is your core business logic: the code that makes your product different from someone else's product. This code should be well-designed, well-tested, and well-documented. Invest here.

The other 80% — glue code, configuration, boilerplate, infrastructure scripts — changes rarely and doesn't need to be beautiful. It needs to work. The fact that your Dockerfile is not a work of art is not a crisis. Expending significant energy making it a work of art is a crisis, because that energy has an opportunity cost.

AI tools have made this more useful to talk about, not less. One of the highest-leverage uses of AI-assisted coding is letting it write the 80% — the stuff that needs to exist but doesn't need to be precious. Generated code that works is better than hand-crafted code that doesn't exist yet because you haven't had time to write it.

The Refactoring Argument

"We'll refactor it later" is a joke in most engineering organisations. It never happens. The backlog grows, priorities shift, and the thing that was going to be cleaned up last quarter is the thing you're carefully working around next year.

This is true, and it's a reason to write things reasonably well the first time. But it's not a reason to delay shipping while you achieve theoretical perfection. The refactoring you do when you understand the problem better — when you've seen what the code actually needs to do in the real world — is more valuable than the refactoring you do speculatively upfront.

There's also something important about pace. A codebase that ships regularly gets feedback regularly. Feedback shapes what matters and what doesn't. A codebase that ships slowly because every feature is an exercise in craftsmanship gets feedback slowly — and often discovers, eventually, that it built the wrong thing beautifully.

What "Good Enough" Actually Means

"Good enough" does not mean "as sloppy as possible." It means: appropriate for the context, the stakes, and the timeline.

A medical device has different standards than a personal blog. A feature that will be used by ten people has different standards than one used by ten million. A proof-of-concept has different standards than production infrastructure. Context is everything.

The questions to ask are: Is it correct? Does it work as intended? Is it readable enough that the next developer can understand what it does and why? Is it testable? Does it fail safely?

If the answer to those is yes, you are probably done. The impulse to keep polishing, to find the perfect variable name, to extract one more function — that impulse has real value, but it has diminishing returns, and the returns approach zero faster than you think.

AI and the Perfectionism Trap

Interestingly, AI coding tools have a complex relationship with perfectionism. They can generate a clean-looking first draft very quickly, which makes it tempting to treat that first draft as a finished product. They can also suggest endless refactoring when you ask for improvements.

The discipline is the same as always: know when you're done. The definition of done hasn't changed because the typing is faster. The standard should still be: correct, readable, tested, and appropriate for the context.

Perfect code, in the sense of code that admits no further improvement, doesn't exist. The best code you can write today will look naive to you in five years. That's not a failure — it's growth. Ship the good-enough thing. Learn from it. Write something better next time.

The codebase you're embarrassed by isn't evidence of past failure. It's evidence that you've improved since you wrote it. That's actually something to celebrate.

Jako Heiberg

Software developer with 40+ years of building things that work. Full-stack, FastAPI, React. Based in Cape Town, working remotely, worldwide.

Related Posts

Insights

Vim From Scratch — Part 2: Modal Editing, and Why Modes Are a Feature

Every other editor lets you type text the moment you open it. Vim makes you ask for permission first. This sounds insane until you realise it's the reason Vim can do so much with so few keys.

August 26, 2026
5 min read
Insights

The Long Game: Staying Employable Without Burning Out

A software career is a forty-year marathon disguised as a series of sprints. Here is how to keep learning without chasing every shiny thing, and keep going without burning to the ground.

August 19, 2026
6 min read
Insights

Vim From Scratch — Part 1: Why a 1970s Editor Refuses to Die

Vim is older than most of the people using it, has a reputation for trapping newcomers who can't figure out how to quit, and is still one of the fastest ways to edit text ever built. Both of those things are true, and that's exactly why it's worth your time.

August 18, 2026
5 min read