Reading code, reading docs, reading errors
The three skills that compound the most. Nobody teaches them in school, and the engineers who pull ahead are usually the ones who just got better at all three.
Prerequisites
00.2
Stack
a real open-source codebase to read (suggested: requests, fastapi, or htmx)ripgrepyour editor's go-to-definition
By the end of this module
- Open an unfamiliar codebase and trace one execution path end-to-end inside an hour.
- Read a docs site without scrolling for 20 minutes — go from TOC to working example to API in under five.
- Read a stack trace from the bottom up, identify the user-frame and the library-frame, and know what to do next.
- Stop the reflex of pasting an error into Google before reading it.
Three skills compound more than any other in this field, and almost no university teaches them: reading other people’s code, reading docs, and reading errors. The students who quietly pull ahead in their second year are almost always the ones who just got better at all three. Everyone else is still pasting errors into Google and wondering why their code “isn’t working.”
This module is short on theory and heavy on muscle memory. You will pick a real codebase, you will trace a real path through it, you will read a real docs site, and you will deliberately misread a real error and then read it correctly. By the end of the two hours, your default move when a thing breaks should change. That’s the entire goal.
The honest take, before we start: most CS students do not read other people’s code. They read tutorials, watch videos, and write their own toy code. Reading real production code feels uncomfortable because it’s unfamiliar — there are imports you don’t know, abstractions you don’t have context for, files that seem to do nothing. Pushing through that discomfort, deliberately, is the skill.
Read these first
Three sources, in this order, then stop.
- Julia Evans — How I got better at debugging. post · 15 min · the canonical short essay on this exact topic.
- Peter Seibel — Code is not literature. post · 20 min · why “reading code like a book” is the wrong frame.
- Mark Dominus — Read the source, Luke. post · 10 min · old, still right; the case for opening the file instead of asking.
Skip “10 tips for reading code” listicles. None of them will help. The tactics below will.
Reading code
The mistake every beginner makes is opening a repo and starting at README.md, then drifting into random files until they give up. That is reading-code-as-tourism. Real code reading is goal-directed.
1. Pick the entry point
Every codebase has a small number of front doors. Find them first.
| Project type | Entry point |
|---|---|
| Python library | __init__.py, setup.py / pyproject.toml |
| Python CLI | the console_scripts entry in pyproject.toml |
| Web app | main.py, app.py, index.ts, server.ts |
| Rust crate | src/lib.rs or src/main.rs |
| Node package | the "main" field of package.json |
Open the entry point. Read 50 lines. You are not trying to understand everything — you are looking for the shape: what does this expose? What does it import?
2. Tests are the best documentation
The single most underrated source of understanding in any codebase is the test directory. Tests are documentation that has to actually work, written by someone who knows the system. When you want to understand “how is feature X used,” open tests/test_x.py first. You will get more in 10 minutes there than from an hour of reading source.
3. Trace one path end-to-end
Pick one user-visible behavior. (“When I call requests.get(url), what happens?”) Then trace it: from the public function, through the helpers, through the network call, until you reach the boundary of the codebase. Use go-to-definition (Cmd-click in VS Code, gd in vim). When the path leaves into a dependency, stop — you’ve reached the edge.
You don’t need to understand every line. You need to know which file does what. That mental map is what reading-code skill actually is.
4. The five-minute rule
If you’ve been staring at a piece of code for five minutes and don’t understand it, do exactly one of these:
- Open the test for it. Read three test cases.
- Run the function with a
print()or a debugger. See what shape its inputs/outputs actually are. - Ask a model to explain that one function, with the file context, in under 200 words. (See module 00.3 for how to ask.)
What you do not do is keep staring. Staring at unfamiliar code does not produce understanding past minute five. New input does.
Exercise: 60 minutes inside FastAPI
Open this hands-on. It will hurt the first time, then it gets easier.
git clone https://github.com/fastapi/fastapi.git
cd fastapi
ls fastapi/
Goal: figure out exactly how the Depends() system works. Specifically, how does FastAPI know to call Depends(get_db) once per request and inject the result?
# 1. Find the entry point
rg "^def Depends" fastapi/
# 2. Find where it's used
rg "Depends\(" docs_src/
# 3. Find where it's resolved
rg "solve_dependencies" fastapi/
# 4. Read the test for it
fd test_dependency tests/
Spend an hour. You will not finish — that’s fine. The win is that you’ll have a usable mental model of FastAPI’s dependency system, which is the kind of thing courses teach in five lectures and you’ll have absorbed by reading.
Reading docs
Most students bounce off docs sites because they read them like a textbook, top to bottom, and zone out by section three. Docs are reference material. Read them like reference material.
The 4-step docs read
For any new library, do exactly this:
1. Open the docs. Look at the table of contents in the sidebar.
Read only the section titles. 60 seconds.
2. Find the "Quickstart" or "Getting started" page.
Type out the example code yourself, run it, see it work.
3. Find the page closest to your actual use case.
("Authentication", "File uploads", "Streaming responses".)
4. Skim the API reference for the one or two functions you'll actually call.
That’s the whole flow. Step 2 is non-negotiable. Reading example code without running it is like reading recipes without cooking.
When the docs are bad
Some libraries have lousy docs. The fallbacks, in order of cost:
- The README +
examples/directory in the repo. - The tests, again.
- The library’s GitHub Discussions or issues — search for your symptom.
- A small AI chat: “I want to do X with library Y, give me a minimal working example, and tell me which symbols I should look up to understand it.” Then look them up.
Skip Stack Overflow as your first stop. Half the answers are five years out of date and most of the rest are slightly wrong.
Reading errors
The fastest single skill upgrade in this whole module is learning to actually read your stack traces. Most beginners glance at the first line, panic, and paste it into Google. That throws away 90% of the information your computer just gave you for free.
Read from the bottom
A Python or Node stack trace is roughly upside-down by default. The most useful frame is at the bottom of the chain (the actual error and the line that triggered it), and the path to it is above. Read it backwards: bottom line first, then walk up to find your code.
Traceback (most recent call last):
File "/Users/me/proj/main.py", line 42, in <module>
user = load_user(user_id)
File "/Users/me/proj/db.py", line 17, in load_user
return cursor.execute(query, [user_id]).fetchone()
File ".../sqlite3/dbapi2.py", line 312, in execute
raise OperationalError(...)
sqlite3.OperationalError: no such table: users
Read this from the bottom: sqlite3.OperationalError: no such table: users. That’s the actual problem. Now walk up: it happened inside cursor.execute, called from your load_user, called from main.py:42. So your code is fine structurally — the database just doesn’t have the table you think it does. You don’t need Google. You need a migration.
The three patterns
Almost every error message you’ll see in the first year falls into one of three buckets.
| Pattern | Example | What it usually means |
|---|---|---|
| ”X is not Y” | 'NoneType' object has no attribute 'foo' | Something returned None upstream that you assumed was an object. Walk up the stack. |
| ”Cannot find / no such” | ModuleNotFoundError, no such table | An expected resource isn’t there. Check imports, paths, env vars, migrations. |
| ”Permission / refused” | EACCES, Connection refused, 403 | An access boundary said no. Check the actual permission/credentials/port. |
If you can classify the error into one of these three within five seconds, you’ve already cut your debug time in half.
Never paste-and-run
The single worst habit in modern dev is copying a Stack Overflow answer (or an AI suggestion) into your codebase without reading it. You will get a fix that “works” for the wrong reason, six months later something subtle will break, and you will not have the mental model to fix it because you skipped the part where the bug taught you something.
Rule: if you paste a fix in, you have 60 seconds to explain in your head why it fixed the bug. If you can’t, undo the paste and reread the error.
Going deeper
When you have specific questions, in this order:
- John Ousterhout — A Philosophy of Software Design. book · short, sharp, and the section on reading code is gold.
- Hillel Wayne — Crash-only software is good actually. post · the kind of writing that teaches you to read systems, not just code.
- Russ Cox — On reading other people’s code. post · senior-engineer perspective from a real one.
- Beej’s Guide to C / Network Programming. link · the canonical example of a docs site that knows what reference material is.
Checkpoints
If any one wobbles, the corresponding section above is what to reread.
- Name three places in any codebase to look first when you want to understand it. (Hint: not
README.md.) - What is the five-minute rule, and what are the three things you do when it fires?
- Walk through the four-step docs read from memory.
- Why do you read a stack trace from the bottom up? What’s at the bottom that isn’t at the top?
- State the test for whether you’ve earned the right to paste a fix into your code.
If you can answer all five from memory and you finished the FastAPI exercise, you’ve earned 00.4. Next: 01.1 — Python deep enough to be dangerous. You’re going to use Python for half this curriculum. Time to actually know it.