DEV Community

Cover image for Read other people's code: a habit I'm trying to build
Suraj Nandan
Suraj Nandan

Posted on

Read other people's code: a habit I'm trying to build

Most of my learning is from writing my own code. That means I mostly see my own habits, including the bad ones.

Reading other people's code is the other half of the skill, and the half I practise less. This post is a method I'm trying to turn into a routine: how to pick something to read, how to read it without drowning, and how to turn that into a first contribution. I'm presenting it as a plan, not a record of achievement.

Why reading matters

Writers become better by reading. Programmers are the same, with extra reasons:

  • You see choices you wouldn't have made, and sometimes they're better.
  • You learn how real projects handle messy cases: errors, versions, odd inputs.
  • You get humility. Most mature codebases are less tidy than their READMEs.
  • You prepare for the job. Most professional work is reading and changing code that someone else wrote.

What not to do

The classic mistake is opening a large repository and trying to understand all of it. You'll be lost in an hour and quit. Reading code is not like reading a book from page one.

A method that works for me

1. Pick a small library you already use

Familiarity gives you a hook: you know what the library does, so you can read for how. Small matters, since a few hundred lines can be understood completely.

Good candidates: a tiny utility (a debounce helper, an ID generator, a small state library), or a single plugin.

2. Read the README and the tests first

Tests are executable documentation. They show how the author expects the code to be used and which edge cases they cared about. A test file often explains a module faster than the module itself.

3. Find the entry point

Where does the main function live? Look at package.json (main, exports), then open that file.

4. Read one file, not the whole repo

Pick the file that does the core job and read it top to bottom. Ignore everything else for now.

5. Trace one feature end to end

Choose a single behaviour ("what happens when I call debounce(fn, 200)?") and follow it through the code, writing down each hop:

debounce(fn, wait)
  -> returns wrapped()
  -> wrapped() clears any pending timer
  -> sets a new timer for `wait` ms
  -> when it fires, calls fn with the *latest* arguments
Enter fullscreen mode Exit fullscreen mode

Writing the trace in your own words is what turns reading into understanding.

6. Ask "why is it structured this way?"

For every surprising decision, form a guess: why a Map instead of an object? Why is this check first? Then look for evidence (a comment, a commit message, an issue). The gap between your guess and the truth is where you learn.

7. Run it and break it

Add a console.log, change a line, see what fails. Reading with a running debugger beats reading alone.

A short worked example

Take a small debounce utility. In about thirty lines you can learn:

function debounce<A extends unknown[]>(fn: (...a: A) => void, wait: number) {
  let t: ReturnType<typeof setTimeout> | undefined;
  return (...args: A) => {
    if (t) clearTimeout(t);
    t = setTimeout(() => fn(...args), wait);
  };
}
Enter fullscreen mode Exit fullscreen mode

Questions this raises, each a mini-lesson:

  • Why is t declared outside the returned function? (It's closure state shared across calls.)
  • What happens if the component unmounts before the timer fires? (A cleanup/cancel method is missing.)
  • Should the first call run immediately (a "leading" option)?

Mature libraries answer those questions in code, which is exactly what you learn by reading them.

Reading code you'll have to change

At work, the goal is usually different: find where to make a change safely. A workflow for that:

  1. Reproduce the behaviour.
  2. Search for a distinctive string from the UI or log message.
  3. Follow it to the function that produces it.
  4. Read the tests around that function.
  5. Make the smallest possible change, and run the tests.

From reading to contributing

Reading becomes much more useful once it produces something. Small, realistic first contributions:

  • Fix a typo or a confusing sentence in the docs.
  • Add a missing test for an edge case you noticed.
  • Improve an error message.
  • Reproduce a bug someone reported and add what you found.

Open the issue first for anything beyond a typo, read the contributing guide, and keep the change small. A tiny accepted pull request teaches more about a project's workflow than weeks of reading.

The next step I want to take

I want to open a small pull request on a project I use. I haven't made that a regular habit yet, so I'm saying it here to commit. If it happens I'll write up what I learned, including anything that went wrong.

A weekly routine

Day Activity
Mon Pick a small library; read the README and tests
Tue Read the core file; write the trace for one feature
Wed Run and break it; note three questions
Thu Look for the answers (issues, commits, docs)
Fri Write five lines of what you learned

Tools that make reading code easier

You don't have to hold everything in your head. A few commands do a lot.

Find where something is used

rg "transition_transaction"          # fast text search (ripgrep)
git grep -n "transition_transaction"  # search tracked files
Enter fullscreen mode Exit fullscreen mode

Find when a line or string appeared

git log -S"SKIP LOCKED" --oneline    # commits that added or removed that string
git blame -L 40,70 src/claim.ts      # who last changed lines 40 to 70, and in which commit
Enter fullscreen mode Exit fullscreen mode

See the history of one file

git log --follow -p -- src/claim.ts
Enter fullscreen mode Exit fullscreen mode

See what a commit changed, and why

git show <commit>                     # the diff plus the message
Enter fullscreen mode Exit fullscreen mode

Commit messages and linked issues are often where the reasoning lives, which the code alone can't tell you.

How to read a pull request

Reviewing someone's change is reading practice with a built-in goal.

  1. Read the description first. What is this supposed to do?
  2. Read the tests. They show intended behaviour.
  3. Skim the file list. Does the shape of the change match the description?
  4. Read the core change top-down.
  5. Ask questions as you read. "What happens if this is empty?"
  6. Run it if you can.

Practise on open-source projects you use: read recently merged pull requests and see what reviewers pushed back on. That's free mentoring from strangers.

Questions to ask of any unfamiliar code

  • What is the input and what is the output?
  • Where does state live, and who can change it?
  • What can fail, and what happens then?
  • What does this depend on?
  • What would break if I deleted it?
  • Why is there a special case here?

If you can answer all six for a module, you understand it.

Keeping a reading log

A tiny habit with outsized returns:

2026-10-30  library: <name>  file: <path>
  Learned:   <one thing the code did that I wouldn't have thought of>
  Question:  <something I couldn't explain>
  Steal:     <a pattern worth reusing>
Enter fullscreen mode Exit fullscreen mode

After a month, the "steal" column is a personal library of patterns, and the "question" column is your study list.

Choosing something to read

Goal Pick
Learn clean small-scale design A tiny utility library (a few hundred lines)
Learn how frameworks work A small plugin or example app from the framework's own repository
Learn production patterns Mid-sized open-source apps with good tests
Learn algorithms in practice A scheduler, a parser or a small database

Start with something you use, so you already have questions.

Common obstacles

"It's too big." Read one file, not the repo.

"I don't understand the language features." Look each one up, then continue. Don't pretend.

"There are no comments." Read the tests, the commit history and the issues.

"I get lost in the indirection." Trace one concrete call with a debugger or print statements instead of reading abstractions.

"I keep forgetting." Write the trace down. Writing is how memory sticks.

One small contribution to aim for

Pick one project you use. Read its issue tracker for tickets labelled "good first issue" or "docs". Find one you can understand in an hour. Leave a comment saying you're taking it, make the smallest change, and run the project's checks before opening the pull request. Being polite and patient matters as much as the code.

Key takeaways from day 28

What's your favourite codebase to read, and what made it easy to follow?


☕ Enjoyed this post? You can support my writing on Ko-fi.

Support me on Ko-fi

Top comments (0)