Read an unfamiliar codebase fast: find entry points, trace call graphs instead of reading line by line, and write an orientation brief so the next reader starts ahead of you. Use when onboarding onto a repo, scoping a change in code you did not write, reviewing unfamiliar code, or answering how something works.
./install.sh code-reading-techniquename: code-reading-technique description: "Read an unfamiliar codebase fast: find entry points, trace call graphs instead of reading line by line, and write an orientation brief so the next reader starts ahead of you. Use when onboarding onto a repo, scoping a change in code you did not write, reviewing unfamiliar code, or answering how something works."
Give you a repeatable way to go from "I have never seen this code" to "I know how it works and where my change goes" in one focused pass. The enemy is random browsing. The method is entry points first, one traced flow, then a written record. Techniques come from Diomidis Spinellis's Code Reading: The Open Source Perspective (Addison-Wesley, 2003), Michael Feathers's Working Effectively With Legacy Code, and published onboarding practice; the 30-minute pass itself is this skill's own timeboxed procedure.
This is a timeboxed first pass, not a full review. Set a timer. Stop when it rings and write the brief. Depth comes later, in layers.
Minutes 0-5: Orient. Answer four questions: what is it, what language/runtime, how do I run it, what does the README claim it does. Run it before you read it. Use the software, call a function or two, watch the output. The input/output model you build here carries the whole rest of the pass. If it won't run, note that as your first finding and keep going.
Minutes 5-12: Find the entry points. Every codebase has a canonical start. Hunt for it, do not guess:
package.json, Cargo.toml, pyproject.toml, go.mod. Scripts and binaries tell you what runs.main(), the server setup, the CLI dispatch, the app root.Minutes 12-22: Trace one real flow. Pick the single most representative action (one HTTP request, one CLI command, the core job) and follow it end to end: entry -> handler -> domain logic -> data access -> response. Use go-to-definition and find-references, not your eyes. Skip everything that is not on this path. One traced flow teaches more than ten files read in isolation.
Minutes 22-30: Map and write it down. Before the details fade, capture: the one-line summary, entry points, the traced flow, key data structures, the vocabulary the code keeps reusing, and the questions you still have. Write the orientation brief (see Output Contract). The reader after you starts ahead.
1. Entry points first, never alphabetical. Spinellis's core rule. Reading files in tree order is how you drown. Start at main() or the handler and follow execution forward. Grep finds text; tracing finds how it works.
2. Trace the call graph, not the lines. Build the graph of who calls whom around your flow before you read any function body deeply. Get the shape, then zoom into the nodes on your path. Line-by-line reading is the last resort, for the three functions that matter.
3. Tests are the spec. When a function confuses you, read its tests first. Tests are executable documentation that does not drift. The test that exercises your flow shows intended usage and edge cases in one place.
4. Data structures before control flow. Learn the key types first: the request object, the domain record, the config struct. Control flow is just manipulation of these. A handler is unreadable until you know what it passes around.
5. Locate the heart. Somewhere in every system there is a function or module that every path passes through (the dispatcher, the store, the render loop). Find it and you own the map. High fan-in plus high fan-out is the signal.
6. Break small things in a scratch copy. Change one small thing, watch what fails. The failure pattern reveals dependencies and invariants faster than any doc. This is a legitimate technique, not recklessness: do it on a throwaway branch or git stash it away after. Never commit the experiment.
7. Mine the repo history. When "current vs legacy" is unclear, git log --oneline -- <file> and git log -L on the function you care about settle it. The newest change usually wins. Blame tells you who to ask.
8. Ask a human early. If someone who worked on the code is available, one whiteboard session beats an afternoon of grep. Orientation is a legitimate reason to ask.
Deeper techniques for when static reading stalls (from Feathers) and practice drills live in references/deep-techniques.md.
A small repo with src/server.py, src/routes.py, src/orders.py, src/db.py, tests/test_orders.py. Minutes 5-12 and 12-22 look like this:
bash
# Entry points: what runs?
rg -n "__main__|def main|register_routes" src tests
# -> src/server.py:4: def main(): ...
# Trace one flow: who touches OrderService?
rg -n "OrderService" src tests
# -> routes.py builds it, orders.py defines it, tests exercise it
# History of the traced file: is this current or legacy?
git log --oneline -- src/orders.py
# Tests as spec: what is get_order supposed to do?
python3 -m pytest tests/ -q
Two minutes in, you know the shape: server.py main() -> register_routes -> OrderService -> Store, and the tests pin the intended behavior. That is the whole pass on a small codebase.
Every pass ends with an orientation brief the next reader can use. Use the template at assets/orientation-brief-template.md. It must contain:
publisher key 2e43c913833850e6d80f939677e3de76e806d47785c0f1caaca90f9d18c98e1e
No ratings yet — be the first to rate it.