Reading Code Is a Skill: Why It Matters and How to Practice

Engineers spend far more time reading code than writing it, yet almost nobody practices reading on purpose. Here is what skilled readers do and how to train it.

By The OpenVisio Team · · 11 min read

Ask a group of engineers how they got better at writing code and you will hear about side projects, code review, books, and years of shipping. Ask how they got better at reading code and most will pause. Reading is treated as something you just do, like breathing, rather than a skill that can be trained. Yet a working engineer reads far more code than they write: every bug fix starts with reading, every review is reading, every new feature in an existing system is mostly reading followed by a small amount of writing.

Robert C. Martin put the ratio of time spent reading versus writing at "well over 10 to 1" in Clean Code. Whatever the exact number in your job, it is clearly lopsided. This post argues that reading code is a distinct skill, describes what skilled readers do differently, and offers concrete drills you can practice in 20 minutes a day. If you want the step-by-step procedure for a specific unfamiliar repo, start with how to read an unfamiliar codebase; this post is about getting better at the underlying skill.

Key takeaways

  • Reading code is not the reverse of writing it. It uses different moves: hypothesis, navigation, skimming, and verification.
  • Skilled readers read with a question, skip most code, and spend attention on data shapes, boundaries and side effects.
  • Beacons, recognizable patterns and names, let experienced readers understand chunks of code without reading every line. You can build your library of beacons on purpose.
  • Reading improves with feedback. Predict what code does, then run it or test it to check.
  • Practice in short, regular sessions: trace a flow in an open source project, review a PR you were not asked to, or explain a file in writing.
  • AI tools change the cost of a first draft explanation, not the need to verify it. Reading skill is what lets you check the explanation.

Why reading is a separate skill

Writing code moves from intent to implementation. You know what you want and you choose how to express it. Reading moves the other way: you see an implementation and have to reconstruct the intent, often without the author, the ticket, or the constraints they faced. That reverse direction is harder, and it uses different mental moves.

Research on program comprehension has described two broad strategies for decades. In top-down comprehension, the reader forms a hypothesis about what the code does ("this looks like a retry loop") and then confirms or rejects it by checking details. In bottom-up comprehension, the reader works through statements and groups them into larger meanings. Experts switch between the two fluidly. Novices tend to get stuck reading bottom-up, line by line, and run out of working memory before the meaning emerges.

The practical lesson: good reading is mostly about forming and testing hypotheses quickly, and that is trainable.

What skilled readers do differently

They read with a question

A skilled reader rarely opens a file to "understand it". They open it to answer something: why does this endpoint return 404 for archived users, where does the retry limit come from, what calls this function. The question decides what to read and, just as important, what to skip.

They skip most of the code

Most lines in a typical function are plumbing: argument checks, logging, error wrapping, type conversions. A skilled reader's eye jumps past them to the lines that matter, the branch conditions, the state changes, the calls across a boundary. They read signatures and names first and open bodies only when the question requires it.

They recognize beacons

A beacon is a familiar pattern that lets you understand a chunk of code at a glance. When you see this:

for attempt in range(max_retries):
    try:
        return client.send(request)
    except TransientError:
        time.sleep(base_delay * 2 ** attempt)
raise RetriesExhausted()

you do not read it line by line. You recognize "retry with exponential backoff" and check only the details that could differ: is there jitter, which errors count as transient, what happens on the last attempt. Experienced readers carry a large library of these: guard clauses, builder patterns, middleware chains, state machines, pagination loops, double-checked caches, the shape of a React reducer. Each one turns twenty lines into one idea.

You build beacons by reading a lot of code in a domain and by naming what you see. When you notice a pattern for the third time, give it a name in your notes.

They follow data, not just calls

Call stacks tell you what runs. Data tells you what matters. Skilled readers track a value as it flows: where the order.total is computed, where it is modified, where it is stored, where it is displayed. Following data often reveals the design faster than following control flow, especially in systems with many layers of indirection.

They verify instead of trusting names

Names are a hypothesis written by the author. validateUser might also send an email. cache.get might fall through to the database. A skilled reader uses "find references", the debugger and tests to confirm what code does, especially when a bug suggests the names are lying.

They know their tools

Fast navigation is a large part of reading speed. Go to definition, find references, call hierarchy, search by symbol, and blame inline are the core moves. Readers who rely only on scrolling and text search spend most of their time getting to the code instead of reading it.

MoveWhat it answersCommon shortcut (VS Code)
Go to definitionWhat is this?F12
Find all referencesWho uses this?Shift+F12
Call hierarchyWho calls this, transitively?Shift+Alt+H
Go to symbol in workspaceWhere is the thing named X?Ctrl+T (Cmd+T on macOS)
Inline blame / file historyWhy is this here, and since when?Via GitLens or the built-in timeline

How to practice

Skills improve with deliberate practice: short sessions, a clear goal, and feedback. Here are drills that fit into 20 to 30 minutes.

Drill 1: Predict, then check

Pick a function you have not read before. Read its name and signature only, and write one sentence predicting what it does and what side effects it has. Then read the body and check. Then find a test or run it to check again. Keep score. Over a few weeks you will notice your predictions get more precise, which means your beacon library is growing.

Drill 2: Trace one flow in an open source project

Pick a well-maintained open source project in a language you use. Choose one user-visible action, for example "what happens when you run git status" in Git, "how does Flask match a URL to a view", or "how does Express run middleware". Trace it from entry point to output, writing file and line at each step. Stop after 30 minutes and write down how far you got. Next session, continue. The guide to learning by reading open source code has a list of repos that work well for this.

Drill 3: Review a PR you were not asked to review

Pick a merged pull request in your team's repo, in an area you do not know. Before reading the description, read the diff and write what you think it does and why. Then read the description and the discussion. Where were you wrong? This drill trains reading in context, the most common real situation.

Drill 4: Explain a file in writing

Take one file and write a five-sentence explanation for a new teammate: what it is for, its main entry points, what it depends on, what depends on it, and one non-obvious thing about it. Writing forces you to resolve the vague parts you would otherwise skim past. If you cannot write the five sentences, you have found the parts you do not yet understand.

Drill 5: Read the same code at two speeds

Pick a module. First pass: two minutes, names and signatures only, then write a one-paragraph summary. Second pass: twenty minutes, full read. Compare. The goal is to make the two-minute summary closer to the twenty-minute one over time. That is the skimming skill, and it is what lets experienced engineers move through large codebases quickly.

Drill 6: Rebuild the structure from imports

Take a small project, ignore the folder names, and draw its module structure purely from imports. Then compare against the folders and the README. Mismatches teach you that structure is what the code does, not what the folders say.

A weekly routine

You do not need a lot of time. A sustainable routine:

Mon  Drill 1 (predict then check) on 3 functions in your own repo
Tue  Drill 3 (review a merged PR outside your area)
Wed  Drill 2 (30 minutes tracing a flow in an OSS project)
Thu  Drill 4 (write a 5-sentence explanation of one file, share it)
Fri  Drill 5 (two-speed read of one module)

Two of these produce artifacts other people can use: explanations and flow traces. Sharing them gets you feedback from people who know the code, which is the fastest correction loop available.

Reading in the age of AI explanations

AI tools can now produce a plausible explanation of almost any file in seconds. That changes the cost of a first draft, and it is genuinely useful: a summary of a module is a good hypothesis to start from. It does not remove the need to read. Explanations can be confidently wrong about edge cases, side effects and which code path actually runs, for exactly the reasons names can be wrong: the model infers intent from surface patterns.

The skill shifts from "produce an understanding from scratch" toward "check an understanding quickly". That is still reading: you need beacons to judge whether the summary matches the code, navigation to find the lines it refers to, and the habit of verifying with tests or a debugger. A good explanation tool helps by pointing at specific code rather than speaking in generalities. When you use OpenVisio's Ask on a repo, for example, the answer comes with the relevant code beside each step, which makes checking it a reading exercise rather than an act of faith. For more on how to frame questions so you get answers worth checking, see asking better questions about code.

Signs you are getting better

You will not get a certificate for reading code, so watch for these signals:

  • You can tell within a minute or two whether a file is relevant to your question.
  • Your predictions about what a function does are right more often, and wrong in smaller ways.
  • You reach for "find references" and the debugger before scrolling.
  • You can explain a module to someone else without opening it again.
  • Reviews take you less time and you catch more, because you see what the diff touches beyond the lines shown.

Reading code well is the quiet skill underneath debugging, reviewing, refactoring and onboarding. It deserves the same deliberate practice people give to writing code, and it pays back every working day.

reading codedeveloper skillsdeliberate practicecode comprehension

See it on your own repo

Paste a GitHub URL and get the day-one walkthrough — free, in your browser.

Index a repo

Keep reading