Skip to content

Commit 35d9c0b

Browse files
committed
.
1 parent 4efdca4 commit 35d9c0b

File tree

2 files changed

+90
-1
lines changed

2 files changed

+90
-1
lines changed

content/css/main.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ hr::after { content: '❧'; display: block; text-align: center; }
157157
/* Inline */
158158

159159
p>code { white-space: nowrap; } /* Sadly, overflow-wrap: anywhere doesn't compose with this */
160-
p>code { line-height: 0px; } /* https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align */
160+
p>code:not(.display) { line-height: 0px; } /* https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align */
161161
.display { display: block; margin: calc(var(--line-height) / 2) 0; text-align: center; overflow-x: auto; }
162162

163163
a { text-decoration-color: #2156a5; text-decoration-thickness: 7%; color: black; }
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Look Out For Bugs
2+
3+
One of my biggest mid-career shifts in how I write code was internalizing the idea from this post:
4+
[_Don't Write Bugs_](https://www.teamten.com/lawrence/programming/dont-write-bugs.html){.display}
5+
6+
Historically, I approached coding with an iteration-focused mindset --- you write a draft version of
7+
a program, you set up some kind of a test to verify that it does what you want it to do, and then
8+
you just quickly iterate on your draft until the result passes all the checks.
9+
10+
This was a great approach when I was only learning to code, as it allowed me to iterate past the
11+
things which were not relevant for me at that point, and focus on what matters. Who cares if it is
12+
`String args` or `String[] args` in the "паблик статик войд мэйн стринг а-эр-джи-эс", it's just some
13+
obscure magic spell anyway, and completely irrelevant to the maze-traversing thingy I am working on!
14+
15+
Carrying over this approach past the learning phase was a mistake. As Lawrence points out, while you
16+
_can_ spend time chasing bugs in the freshly written code, it is possible to dramatically cut the
17+
amount of bugs you introduce in the first place, if you focus on optimizing that (and not just the
18+
iteration time). It felt (and still feels) like a superpower!
19+
20+
But there's already a perfectly fine article about not making bugs, so I am not going to duplicate
21+
it. Instead, I want to share a related, but different super power:
22+
23+
> You can find bugs by just reading code.
24+
25+
I remember feeling this superpower for the first time. I was investigating various rope
26+
implementations, and, as a part of that, I looked at the `ImmutableText.java`, the implementation
27+
powering IntelliJ, very old and battle tested code. And, by just reading the code, I found a bug,
28+
[since fixed](https://github.com/JetBrains/intellij-community/commit/b16987177e6023cd971d22a503663b7d63691bb2).
29+
It wasn't hard, the original code is just 500 lines of verbose Java (yup, that's all that you need
30+
for a production rope). And I wasn't even _trying_ to find a bug, it just sort-of jumped out at me
31+
while I was trying to understand how the code works.
32+
33+
That is, you can find some existing piece of software, carefully skim through implementation, and
34+
discover real problems that can be fixed. You can do this to _your_ software as well! By just
35+
re-reading a module you wrote last year, you might find subtle problems.
36+
37+
I regularly discover TigreBeetle issues by just covering this or that topic on
38+
[IronBeetle](https://www.youtube.com/watch?v=hPUL8Xo6MJw&list=PL9eL-xg48OM3pnVqFSRyBFleHtBBw-nmZ):
39+
[bug discovered live](https://youtu.be/2_IJJZFMH2M?si=oNnqd8oCckXo8OLf&t=1691),
40+
[fixed](https://youtu.be/2_IJJZFMH2M?si=hluxJXQuK3XtDT3I&t=2090),
41+
[and PR merged](https://github.com/tigerbeetle/tigerbeetle/pull/3194).
42+
43+
Here are some tips for getting better at this:
44+
45+
The key is careful, slow reading. What you actually are doing is building the mental model of a
46+
program inside your head. Reading the source code is just an instrument for achieving that goal. I
47+
can't emphasize this enough: programming is all about building a precise understanding inside your
48+
mind, and then looking for the diff between your brain and what's in git.
49+
50+
Don't dodge an opportunity to read more of the code. If you are reviewing a PR, don't review _just_
51+
the diff, review the entire subsystem. When writing code, don't hesitate to stop and to probe and
52+
feel the context around. Go for `git blame` or `git log -S` to understand the historical "why" of
53+
the code.
54+
55+
When reading, _mostly_ ignore the textual order, don't just read each source file top-down. Instead,
56+
use these two other frames:
57+
58+
: Follow the control flow
59+
60+
Start at `main` or subsystem equivalent, and use "goto definition" to follow an imaginary program
61+
counter.
62+
63+
: Stare at the state
64+
65+
Identify the key data structures and fields, and search for all all places where they are
66+
created and modified.
67+
68+
You want to see a slice across space and time, state and control flow (c.f.
69+
[_Concurrent Expression Problem_](https://matklad.github.io/2021/04/26/concurrent-expression-problem.html)).
70+
71+
Just earlier today I used the second trick to debug an issue for which I haven't got a repro.
72+
I identified
73+
`connection.peer = header_peer;`{.display}
74+
as the key assignment that was recently introduced, then [ctrl + f]{.kbd} for `connection.peer`, and
75+
that immediately revealed a gap in my mental model. Note how this was helped by the fact that the
76+
thing in question, `connection`, was always called that in the source code! If your language allows
77+
it, avoid `self`, use proper names.
78+
79+
Identify and collect specific error-prone patterns or general smells in the code. In Zig, if there's
80+
an allocator and a `try` in the same scope, [you need to be very
81+
careful](https://matklad.github.io/2025/08/16/reserve-first.html). If there's an isolated tricky
82+
function, it's probably fine. If there's a tricky _interaction_ between functions, it is a smell,
83+
and some bugs are lurking there.
84+
85+
---
86+
87+
Bottom line: reading the code is surprisingly efficient at proactively revealing problems.
88+
Create space for calm reading. When reading, find ways to build mental models quickly, this is not
89+
entirely trivial.

0 commit comments

Comments
 (0)