Always Be Blaming

vinhnx1 pts0 comments

Always Be Blaming

A few tips on 4D-ing your code comprehension skills.

I wrote on the importance of reading code before:<br>Look Out For Bugs<br>My default approach to reading is “predictive”: I don’t actually read<br>the code line by line. Rather, I try to understand the problem that it<br>wants to solve, then imagine my own solution, and read the “diff”<br>between what I have in my mind and what I see in the editor. Non-empty<br>“diff” signifies either a bug in my understanding, or an opportunity<br>to improve the code.

This is 2D reading, understanding a snapshot of code, frozen in time.<br>This is usually enough to spot “this feels odd” anomalies, worthy of<br>further investigation.

Ideal code is memoryless — it precisely solves the problem at hand.<br>Most real code is Markov — the shape of the code at time T depends not only on the problem statement, but also on the<br>shape of the code at time T - 1. The 3D step is to trace<br>the evolution of code over time,<br>Where Do We Come From? What Are We? Where Are We Going?.

The step after that is to understand the why. What were we<br>thinking back then, when we wrote this code? It’s useful to have the<br>“theory of mind” concept ready here. I personally learned the term way<br>too late in my life, so let me give a short intro for today’s lucky 10 000. Theory of mind is the ability to imagine<br>yourself in someone else’s skin. Not just in their shoes (“I certainly<br>would have acted differently in that situation”), but with their mind<br>(“I wouldn’t have acted that way, but I get why they<br>did”). This is something people learn. The experimental setup here is<br>to have a child in a room with toys, with a doll sitting near the<br>opposite end of the room, and asking the child “what does the doll<br>see?”. Younger children describe the room from their<br>perspective, older begin to intuit that doll’s perspective is<br>different.

So this is the goal of reading code — understanding what the original author was thinking, and<br>why.

End of the mumbo-jumbo, some practical advice. First, read<br>Every line of code is always documented,<br>it is very good.

Second, make sure it is effortless for you to find out how a<br>given snippet of code evolved. This is harder than it seems! Just<br>git blame isn’t an answer — mind the gap between the<br>problem that’s easy to solve, and the problem in need of solving.

git blame answers spatial question of “how each line<br>appeared in this file”, because there’s a relatively straightforward<br>UI for this — annotate each line with a commit hash. But this is not<br>the question you are asking most of the time! You don’t care about the<br>file! There’s a small snippet of code in the middle, and you want a<br>temporal history of that.

As much as I<br>don’t like working in the browser<br>GitHub’s web interface for blaming is probably better than what you<br>get locally by default. It starts with the y<br>shortcut, which resolves a symbolic reference like

https://github.com/tigerbeetle/tigerbeetle/blob/main/src/vsr/replica.zig

into the one which has a commit hash in the URL:

https://github.com/tigerbeetle/tigerbeetle/blob/c54f613a2eb2a127a0ba212704e3fa988c42e5cb/src/vsr/replica.zig

This commit hash is critical, because it anchors the entire repository<br>— if you open a different file from the web UI, it will be shown as of<br>that commit. This enables you to not myopically focus on just the diff<br>in question, but to absorb the entire context at that point in time.

So my usual web workflow is:

ctrl+f to find the line I am<br>interested in

b to toggle blame

Click “blame prior to change” a couple of times, repeating ctrl+f to go back to the snippet I am<br>curious about.

cmd-click on the commits that are potentially<br>relevant, pinning their commit hashes in the URL in new tabs.

Then, from the commit page, “Browse files” button to then go and<br>t to other files. Or,<br>cmd+l to focus browser’s address<br>bar, and s/commit/tree/ (or back!) as needed, to switch<br>between diff and snapshot views.

Again, my goal here is not to annotate a diff on a file but rather to<br>get a “virtual checkout” as of the interesting commit.

This web approach is what I was using throughout most of my career,<br>but I’ve finally found a way to replicate it locally. The idea is to<br>make blaming “in-place”. Instead of git blame annotating<br>lines of code, I directly switch to a historical commit. I have the<br>following<br>devil hydra of shortcuts:

, b l blames line. It notes the $line the cursor is at, runs<br>git blame -L $line,$line<br>to find $commit that introduced the line, and then runs<br>git switch --detach $commit<br>to check it out. I have<br>a dedicated worktree for code archeology, so I don’t worry about<br>trashing my work. There’s also a half-hearted attempt to maintain<br>“logical” cursor position, but it doesn’t work very well. Is there<br>some git command that tells me directly “what’s the equivalent of<br>$file:$line:column in $sha-A for $sha-B?”

, b p blames parent. Which is just switching to<br>the parent commit of the current HEAD, what “blame before<br>this change” does on GitHub (it works...

code line commit blame time problem

Related Articles