You’re reading Register Spill, my weekly newsletter in which I share thoughts I can’t keep in my head.
Yesterday, Mitchell wrote about a bug and its fix in his Ghostty Devlog 002. On displays with a DPI that couldn’t be clearly divided by 72, fonts would end up being blurry. Yes, it’s gnarly. I helped find the bug, but reading Mitchell’s analysis made me realise again: in order to truly fix a bug, one must truly know the bug.
When trying to fix the bug, I traced all the involved values through the code and realised that if I change them to integers the fonts become crisp. Mitchell, on the other hand, understood why the calculation was made in the first place, why it was using the specific values it did, and – most importantly – how that relates to the GPU, how it renders text, and why that leads to blurry fonts. I came up with a 2-line fix, but Mitchell went and fixed the whole data structure in which the values are kept, audited the codebase for similar issues, and found another bug.
It’s really easy (and often tempting) to fix a bug without really fixing it. You make the wrong behaviour go away, but you haven’t fixed the bug. Many race conditions can be “fixed” by adding sleep-statements, but in order to really fix them, you need to understand why and when and how they happen.
That’s not always possible nor feasible, though. Sometimes, say when you’re working with a proprietary API, it might be acceptable to fix a bug and comment // We don't know why this happens, but when we add a newline at the end, it works
. Or maybe the right fix would mean you have to re-architect your whole application, only for, say, some UI jitter to go away when you double-click a button. Tricky balance to strike. Truly fix everything you come across and you might end up having to reinvent the whole stack. Only superficially fix bugs because that’s faster and you might end up with the whole house of duct-taped-together cards crashing down on you. It takes a lot of bug fixing to develop an intuition for when and how to go deep.
Then again: is it even possible to “superficially fix” a bug? Or is that just a workaround? Do you “fix” a wobbly table by shoving a piece of folded-up paper under one leg?
What I do know for certain: you should make conscious choices about how to fix a bug. Make sure you know whether your fix is a fix and if it isn’t you should have an explanation for why it’s not.
Great post. This is even more real when working with legacy code on an environment constrained by management pressure. In those situations, it's often hard to justify major investments in fixes when just a few lines can make the problem seem to go away. Any tips for this kind of situation?