Creation Is Art, Debugging Is Science

· 4 min read
ai llm programming software-engineering

Two Jobs That Feel Similar and Aren’t

Both of these look like “programming” from the outside, and they’re almost opposites.

Debugging is a closed problem. You have a function, a thing you expected, and a thing that actually happened. Somewhere in the gap is an answer, and it definitely exists. Every step narrows the search. You’re not inventing anything, you’re locating something.

Creation is open. There’s no correct answer sitting at the end waiting to be uncovered, only a large space of possible answers with different trade-offs, most of which won’t reveal themselves for months. You’re not searching, you’re choosing.

That distinction explains almost everything about where these tools help and where they don’t.

Roll Safe think about it

Why Debugging Suits Them So Well

Give a model a stack trace and a chunk of code and it is genuinely excellent, and the reason is that debugging is largely recognition.

Most bugs are not novel. They’re an off-by-one, a mutation somebody didn’t expect, an await that isn’t there, a truthiness check on a value that can legitimately be zero, a timezone. These have been made millions of times and written about nearly as often. Something trained on all of that is very good at going “ah, this shape of failure usually means that.”

There’s a second thing too, which is that debugging benefits from a reader with no history. You’ve been staring at that function for forty minutes and your brain has quietly decided line twelve is fine because you wrote line twelve. A fresh reader doesn’t carry that. Half of what a rubber duck does is provide someone with no prior assumptions, and this is a rubber duck that has read everything.

Why Creation Doesn’t

Ask for an architecture and you’ll get something plausible, conventional, and largely unmoored from your actual situation.

Because the hard part was never producing the structure. It’s knowing that the finance team’s month-end process makes eventual consistency unacceptable here. That the previous team already tried the obvious approach and it fell over for reasons nobody wrote down. That this service has to keep working when a specific third party goes down, which it does, roughly monthly. That there’s an appetite for exactly one migration this year and you need to spend it wisely.

None of that is in the code. It’s in meetings, history, half-remembered arguments, and someone’s Slack DMs from eighteen months ago. Design is mostly the accumulation of constraints that were never written down, and you can’t pattern-match your way to a constraint nobody recorded.

So you get code that’s syntactically fine and situationally wrong, which is a more expensive kind of wrong than code that simply doesn’t compile.

The Line Is Moving

The obvious objection is that this is a snapshot, and a rapidly ageing one.

These tools keep getting better at things I’d have confidently put in the creation column two years ago. Perhaps abstraction really is just pattern matching at a scale we hadn’t reached, and the distinction I’m drawing is a comfortable story rather than a real boundary.

I’d also concede the split is far too clean. Genuinely hard debugging demands creative leaps: forming a hypothesis nobody would have guessed, or realising the bug isn’t in the code at all but in an assumption three layers up. And plenty of creation is honestly just applying a pattern you’ve applied forty times before. It’s a spectrum with two ends, not a wall.

Where I Might Be Wrong

The most likely error is that I’m defending the interesting half of my job because I’d prefer it to remain mine. That’s worth being honest about.

There’s also a decent chance the useful distinction isn’t debugging versus creation at all, but verifiable versus unverifiable. Anything where you can check the answer quickly is somewhere these tools shine, because being wrong is cheap and you’ll find out in seconds. Anything where you find out you were wrong in eight months is where they’re dangerous. That framing might survive better than mine.

Debugging has an answer waiting at the end. Design only has trade-offs.

How I Actually Split It

  1. Point them at anything with a fast feedback loop. Failing tests, stack traces, “why is this undefined”
  2. Never accept a design because it sounded confident. Confidence is free
  3. Bring your own constraints. If you haven’t stated them, they aren’t in the answer
  4. Use them to enumerate options, then choose yourself. Generating candidates is cheap, choosing is the job
  5. Be most suspicious when the output is elegant and you don’t understand why

The art is still ours. The forensics, honestly, I’m glad to share.

Thumbs up

Until next time, happy coding!

Available for rescue and re-platforming work

I take over platforms that already exist and are in trouble. Node, TypeScript, React and Laravel, mostly in regulated or high-traffic environments. If something needs rescuing, re-platforming or finishing, my full history is on the CV.

Related Posts

Comments