
Last week I had to diagnose a bug in an open source library I maintain. The issue was gnarly enough that I couldn’t find it right away, but then I thought: if I set a breakpoint here and fire up the…
Last week I had to diagnose a bug in an open source library I maintain. The issue was gnarly enough that I couldn’t find it right away, but then I thought: if I set a breakpoint here and fire up the debugger, I will likely find the root cause very soon… and then proceed to mercilessly destroy it!
So I rolled up my sleeves, set the breakpoint, fired up the debugger, and… saw the program run to completion without interruptions whatsoever. My breakpoint had been ignored, even though I knew for certain that the line of code in question must have been executed (I double-checked just to be sure).
Since I was in “problem solving mode”, I ignored the debugger issue and started thinking of other approaches to diagnosing it. Prey to my tunnel vision, I modified the code to log potentially interesting data, but it didn’t yield the insights I was hoping for. How frustrating!
My fingertips itched to write even more troubleshooting code when it suddenly dawned on me: just fix the darn debugger already! Sure, it might feel slower, but it will give you the ability to see what you need to see, and then actually solve the problem.
So I fixed the debugger (it turned out to be a one-line configuration change), observed the program’s behavior in more detail, and used that knowledge to solve the issue.
What a paradox, I realized afterwards. The very desire to fix the bug prevented me from seeing I had to fix the tool first, and made me less effective in my bug hunt. This blog post is a reminder to myself, and to every bug-hungry programmer out there: fix your tools! They will do wonders for you.
The caveat is that you might end up shaving a yak.
More often than not I end up three or four tasks deep while trying to fix a tiny issue.
There is simply no general recipe for this. Sometimes I put my little tools and libraries in order and then I'm very productive with them and looking back it seems to have been the key enabler to the actual thing getting done. Other times I go dirty mode and just hardcode constants, copy code files under time pressure and looking back it is clear that getting to the same result with the clean approach would have taken months and the benefit for later tasks would be unclear.
I know some are tired of AI discourse, but I found AI can help to sharpen the tools but at the same time I find that my scope grows such that dealing with the tools takes just as much time but the tools have more features "just in case" and support platforms or use cases that I won't often need, but it feels easy enough to just do, but then as I said it still takes long in total.
It's all mostly an emotional procrastination issue underneath it. Though that can go both ways. Sometimes you procrastinate on thinking about the overall architecture in favor of just making messy edits because thinking about the overall problem is more taxing than just doing a small iteration, sometimes you procrastinate on getting the thing done in favor of working on more tightly scoped neat little tools that are easier to keep in mind than the vague and sprawling overall goals.
What looks like "wasting time on procrastination" may be actually "spending time on thinking". Thinking takes time.
Making messy edits is a bet on previous code quality. If you have paid off enough technical debt, you can take another "technical loan" and expect the rest of the owl to still function despite the mess being introduced. If things are already messy, there's always a risk to make the fess incomprehensible and failing in mysterious seemingly unrelated ways, with the only way to fix it being to git reset --hard to the prior point, and do a more right thing. But the time would have been wasted already.
My approach is usually to timebox it, and cut the losses if an acceptable solution is not yet in sight when the time runs out.
[dead]
I knew which vid's it gonna be before even clicking. Still hilarious.
This only happens when the tools have become so neglected that every single one is broken. You should still take the time to pay down that debt, and in the process learn the lesson to pay the debt in smaller chunks in the future.
You are going to pay it anyway, its not an "if" its a "when"
Relevant XKCD: https://xkcd.com/349
This comic definitely speaks to me on a deep emotional level, but at the same time one of the things I like so much about computers is they're essentially unbreakable.
Not that you can't get one into a non-working state, that is, of course, trivial but with the lone exception of deleting data, you can always restore a computer, the only tool being needed is some kind of boot disk.
(Compare that to breaking a literal hammer, you'd need a pretty specialized set of tools handy if you wanted to actually restore it)
And perhaps less well known to the Hacker News crowd, relevant Malcom in the Middle: https://www.youtube.com/watch?v=5W4NFcamRhM
Weird. I happen to be watching Malcolm in the Middle and I find a link to Malcolm in the Middle
LOL! Well, somebody's gotta shave it!
biggest lesson i learned here: all-in-one tools that promise to handle your whole workflow are almost always worse than stitching purpose-built ones together.
i tried every no-code automation platform (make, airtable, n8n) for a content pipeline i was building. they all break the moment you need to run it more than twice a day at any real scale. weird rate limits, silent failures, state management nightmares.
ended up just writing python scripts that call APIs directly. less "elegant" but infinitely more debuggable. the fix-your-tools moment for me was realizing the tool itself was the problem -- sometimes fixing means replacing with something simpler and more transparent.
Engineering is a continual lesson in axe-sharpening (if you have 6 hours to chop down a tree, spend the first 4 sharpening your axe).
My favorite framing, from Kent Beck: “first make the change easy, then make the easy change.”
I recently got assigned to enhance some code I've never seen before. The code was so bad that I'd have to fully understand it and change multiple places to make my enhancement. I decided that if I was going to be doing that anyway, I might as well refactor it into a better state first. It feels so good to make things better instead of just making them do an extra thing.
Just be careful that 'better' doesn't just mean 'written by me'. I've seen that a lot too
I don't think you spend all 4 hours up front, friend.
In my experience you're going to want a sharp axe later in the process, once you've dulled it.
Not sure if that ruins the analogy or not.
I have mixed feelings here because on one hand I prefer the “axe” when programming (vim with only the right extensions and options). But for trees… chainsaws are quite a bit easier. Once it is chopped down, maybe rent a wood splitter.
[dead]
This approach is also what I'm still missing in agentic coding. It's even worse there because the AI can churn out code and never think "I've typed the same thing 5x now. This can't be right.".
So they never make the change easy because every change is easy to them... until the lack of structure and re-use makes any further changes almost impossible.
Most of my colleagues are content to spend 50 hours chopping up the tree with a pipe. We don't have time to spend making things work properly! This tree has to be finished by tomorrow! Maybe after we've cut up this forest, then we'll have a bit of spare time to sharpen things.
As Charlie Munger used to say “show me the incentives and I’ll show you the outcome”.
What are the incentives for these developers? Most businesses want trees on trucks. That’s the only box they care to check. There is no box for doing it with a sharp axe. You might care, and take the time to sharpen all the axes. Everyone will love it, you might get a pat on the back and a round of applause, but you didn’t check any boxes for the business. Everyone will proceed to go through all the axes until they are dull, and keeping chopping anyway.
I see 2 year old projects that are considered legacy systems. They have an insurmountable amount of technical debt. No one can touch anything without breaking half a dozen others. Everyone who worked on it gets reasonable rewarded for shipping a product, and they just move on. The business got its initial boxes checked and everyone who was looking for a promotion got it. What other incentives are there?