Where does this come from, where is it used?
Lesson 4.3 gave you the unit of curiosity: the symbol. This lesson gives you the move that connects symbols to each other.
“Where does this come from?” and “where is this used?” are the same question, asked in two directions. Both used to take experienced developers an hour with
grep. Now they take a sentence.
If there’s one chapter in this level to internalize hard, it’s this one.
The two directions of tracing
Code is a web. Almost everything in a codebase connects to something else: a function calls another function, a variable is set in one place and read in another, a value flows from the database through the backend to the frontend and onto the screen.
When you want to understand any piece of that web, you have two natural questions:
- Where did this come from? — backward, toward the source.
- Where is this used? — forward, toward the consequences.
Both questions used to be hard. Now they aren’t.
Where does this come from?
You’re reading a function and you see a variable called apiKey being used. Where did it get its value? You don’t have to scroll. Ask:
where does the apiKey variable in src/server/auth.ts get its value? Trace it back.
Claude will follow the trail: maybe it’s read from an environment variable. Maybe it’s passed in from a parent function. Maybe it’s loaded from a config file. The answer is a chain — “it starts in .env, gets loaded by loadConfig() in src/config.ts, then passed to auth.ts as part of the Config object.”
That chain is a real mental model of how the code is wired. You couldn’t have read it linearly. Claude assembled it for you.
Where is this used?
Now flip it. You’ve understood a function. The next question is who depends on it? — because that’s what tells you whether changing it is safe.
what calls handleLogin? List the files and what they do with the return value.
You’ll get an answer like: “three callers — the login page form submit handler, the session refresh worker, and a test in auth.test.ts.” That’s gold. You now know:
- What changes if you break this function.
- Whether your change needs to keep the same return type.
- Whether there’s already a test that’ll catch you when you mess up.
This is the question senior developers ask before every refactor. It’s the question that separates “I’ll move this function around” from “oh no, I just broke production.”
The hour-of-grep that turned into a sentence
Before agents like Claude, tracing was a job. You’d open the project in your editor, run text searches, follow imports manually, open four files at once, keep a mental stack of “and this is called from here, which is called from here…” If the codebase was unfamiliar, an hour could disappear into one trace.
The thing this lesson is really about: the cost of curiosity has dropped to nearly zero. Trace everything. Trace twice. Trace when you don’t even need to. It used to be expensive, so people skipped it. Don’t.
A few more shapes worth knowing
Tracing data backward:
where does the value of `user.email` on this page actually come from? Trace it back to the database.
Tracing data forward:
when a user submits the signup form, what happens? Walk me through every function that runs, in order.
Tracing imports:
what imports from src/lib/utils.ts? Are any of them important?
Finding configuration:
where is the database connection string set in this project?
Different questions, same shape: start at one point, follow the wire.
The thing that trips people up
You’ll be tempted to ask Claude “is this function used anywhere?” and trust a yes/no. Don’t. Always ask Claude to list the callers — file by file. Two reasons:
- “Yes, it’s used” tells you almost nothing. The list is what’s actionable.
- A list is checkable. You can open one of those files in a few seconds and confirm Claude found a real caller — not an imagined one. (More on this in Lesson 4.7.)
A trace you can’t verify isn’t a trace. It’s a story.
The trace, by hand
This whole lesson rests on one claim: an hour of grep collapses into a sentence. So let’s run the grep, so you can feel both ends of it.
In the taskly project, the login code leans on a helper called validate. Trace it — both directions at once:
grep -rn "validate" src
Read the three lines that come back. One is the definition — export function validate in src/utils.ts. That’s where it comes from. The other two are inside src/auth.ts: the import, and the spot where login actually calls it. That’s where it’s used. One command, both directions — the exact two questions this lesson is built on.
When you ask Claude “where does validate come from, and what uses it?”, this is the search underneath. The difference is the payoff: Claude reads each hit and hands you a sentence — “defined in utils.ts, called once in the login check” — instead of leaving you to decode line numbers. A list you can act on, not a wall you have to read.
Then take it to a real project: pick a variable you don’t recognize and ask where it comes from; pick a function and ask what calls it. One question, then the follow-up. A mental map in three minutes that used to take an hour cold.
What’s next
Tracing helps when the code is working but unfamiliar. The other half of reading is when the code is broken — when you’ve got a wall of red error text and no idea what it means. That’s the next lesson.