Learning to Read (Code)

Nobody taught me how to review code. Here's how I figured it out.

Programs must be written for people to read, and only incidentally for machines to execute

Structure and Interpretation of Computer Programs (1984)


Reviewing code is a core responsibility of software engineers — but we do not teach it. We spend much of our academic years learning to write code, our formative years sharpening that skill, and our latter years debating tabs vs spaces. Yet very little effort is put into teaching how to read code. We assume that if you can write code, surely you can read it! But “reading” and “writing”, while related, are two totally different skills (just ask my five year old - he’s learning to do both!)

With the continued advances in agentic development, authoring code is no longer the bottleneck. What used to take hours or even days can be accomplished in mere minutes with the help of LLMs. This has unleashed a torrent of creativity, new features, and much more code that needs to be carefully inspected. Reading code is a critical skill that must be deliberately sharpened.

So how do you learn? Let me tell you how I did.

Starting from Zero

While I’ve been responsible for doing code reviews my entire career, it not something that I focused on until I had been a senior engineer for some time. I spent my early years bouncing around a few different industries and earning my stripes. After that I spent a year as the lead (see: only) engineer of a small local startup. Given that I worked alone I received zero feedback and since I was the only one writing any code I had zero feedback to give. Code reviews were nonexistent. Once that startup failed I found myself thrust into the exact opposite situation: working in a massive organization with seemingly-insurmountable complexity and more engineers with opinions than you could shake a stick at!

In order to compensate, I started asking questions. My aptitude was in code, and since that’s where I was most comfortable, that’s where I directed my efforts:

  • What does this language syntax mean?
  • Where can I find this method?
  • What if you wrote it this way?

These questions, while basic and sometimes even pedantic, helped me orient myself in this chaotic new environment. Through asking these simple questions I was able to form relationships with my new peers, immerse myself in the language and tools that we used, and (perhaps most importantly) establish the confidence to keep asking questions as those questions started to become more informed.

Note that every example above was a question, not a statement. Its okay not to have the answers. Its expected! There truly is no such thing as a dumb question. Any question that you ask will result in one of two things happening (maybe even both!): the author reconsiders their code from a new perspective, or you learn something new that you can take with you.

Just because its easier to focus on the technology (its what we’re experts in after all), that doesn’t diminish the value in doing so. I started my code review journey focusing on those things - but they’re still far and away the majority of review comments I leave. It’s fun to quibble with and push for cleaner, more well-designed code! It’s important too!

Growing the Context Window

After a few months into my new position I had developed a much stronger understanding of the business and the players involved. With this growth in context came bigger questions:

  • Will this change help or hinder next week’s planned feature work?
  • Should we really couple this implementation to that tool when we’re looking at migrating to this other tool?

These are the sorts of questions that arise when you consider a changeset as just one component of delivering customer value. A PR represents, in the micro, a gradual step - but a step towards what? Having a concrete understanding of the team’s goals and ever-evolving philosophy should inform how we consider individual code changes.

This is the part where writing code and reading code really diverge as skills. The misconception that “software engineering” equals “writing code” is understandable — after all, it’s the most tangible thing we do. But think about the last time you built something consequential. You researched the problem, talked to the people who knew more, formulated a plan, then wrote the code, then had several people review it. The actual writing was already just a small part. It is the complex cerebral work required to write the correct code and get it into the hands of customers that is the proper role of engineering — and reviewing code is where that broader context pays dividends.

Thinking Across Boundaries

Fast-foward to a couple of years later. I’m working as the tech lead on a different team, and the context I brought to my reviews had grown further still:

  • Is this change going to conflict with what that other team is building right now? Or plans to build next month?
  • This change couples us to a conception of the domain model that is highly volatile. Can we reconsider this change or wait until we have clearer architectural guidance?

Same habit, bigger aperture. I was still “just asking questions” — but the questions now drew on context that spanned teams, timelines, and architecture. You get here the same way you got to the previous stage: by expanding your awareness. Meet new people for coffee chats to discuss their work. Review incoming requests from outside contributors. The more you understand about why things are being built, the more useful your reviews become.

Now its Your Turn

Observing my own personal journey reveals two key themes:

  1. Always Ask Questions. Start where you’re comfortable — syntax, style, whatever. The questions get bigger as your context grows, but the habit is the same from day one.
  2. Always Be Expanding Your Context Window. Following directly from asking questions, you should always be increasing your awareness (not necessarily concrete knowledge) of the product/team/organizational context within which you’re reviewing code.

It takes humility and bravery to ask questions and engage in conversations. Start asking them anyway.