← Claude for Real Work

Reading before writing

Lesson 13 of 28 · 12 min · Updated

Reading before writing is using Claude Code to understand code you did not write, and checking its explanation against the source before you change anything. Most of the value is here, and most people skip it.

The thing Claude Code is unambiguously good at is reading a codebase faster than you can. It can hold three files in its head at once, follow a call through four of them, and tell you what happens, in about the time it takes you to find the second file. On code you already know, that is a small saving. On code you have never seen, it is the difference between a morning and ten minutes.

The catch is that it will do this equally confidently when it is wrong, and an explanation is much harder to check than a diff. So this lesson is half about asking and half about checking.

The file to be afraid of

wc -l src/reports/index.ts
     335 src/reports/index.ts

Seven reports in one file. That is the file in stockroom you would dread being handed, so it is the one worth practising on.

Open a session and ask:

Give me a map of src/reports/index.ts. What is in it, roughly what does each part
do, and what would I need to understand before changing any of it?

You will get a section-by-section tour. Read it, and notice what it is doing for you: it gives you an order to read the file in. That is the service. You still have to read the parts you are going to change.

Follow one thread all the way down

Broad questions get broad answers. The useful ones are narrow and end somewhere checkable:

When I run `node src/cli/main.ts low`, trace what happens from main() down to the
rows that get printed. Name every function it goes through, in order.

The chain is real and short: main() dispatches on the command, lowStock() calls belowReorder() in src/domain/stock.ts, which calls levels(), which sums the movement ledger; then paginate(); then renderLowStock() turns the rows into text.

Now check it. Open src/reports/index.ts and read lowStock. It should take about forty seconds and it is the difference between having been told something and knowing it.

Use @ to point at a file. Typing @src/reports/ opens a completion list, and @src/reports/index.ts puts that file in front of Claude rather than making it go looking. On a small repository this saves a few seconds. On a large one it is the difference between an answer about your file and an answer about a file with a similar name three directories away.

The history is context nobody uses

The most useful question about a strange file is usually not what it does. It is how it got like this.

Why is src/reports/index.ts so long? Use git log and git blame on it.
git log --oneline -- src/reports/index.ts
4ec254f Let toCsv take the report row types
f7096db Render the reports as text instead of dumping JSON
6972109 CSV export, because the office lives in a spreadsheet
2c18909 Ageing buckets, as the auditor asked
ce08270 Movement history with a running balance
7540a8c Variance: the count against the ledger
970e004 Valuation, and the reorder list it needs
23a7a82 Low stock report

Eight commits, and the story is legible from the messages alone: it was fifty lines and one report in March, and every few weeks somebody added another one. Nobody made a decision to write a 335-line file. It accreted, which is how nearly every file like this happens.

That matters for what you do next. A file that is long because one person wrote it that way has an intention in it somewhere. A file that is long because seven changes landed in it does not, and splitting it is a much safer proposition than it looks.

git blame gives you the finer version: which lines came from which change. Ask for it when you need to know whether a piece of code is load-bearing or left over.

Where will the explanation be wrong?

Three failure modes, in rough order of how often you will hit them.

It answers from the name. Ask what atOrBefore does and you will get a correct answer whether or not it read the function, because the name says it. Ask about something whose name lies and you find out how much reading happened. This is the reason to ask narrow questions with checkable endings.

It smooths over the inconsistency. src/reports/index.ts reports failure three different ways: history throws, valuation returns null, and variance returns { ok: false, error }. A summary will often describe “the error handling” as though there is one. There is not, and each function’s comment says why it did not get changed to match the others. If an explanation of messy code sounds tidy, the tidiness came from the explainer.

It believes the documentation. The README in stockroom documents a command called stockroom count. There is no such command; it was renamed to stocktake and the README was not. Ask Claude how to run a stock take variance report and there is a real chance you get the command from the README, because the README is the most confident-sounding thing in the repository.

That last one is worth sitting with. Documentation is text, code is truth, and the tool reads both. When they disagree, you have to be the one who notices.

Ask it to be uncertain

You can get a lot of this back by asking for it directly.

Explain how averageCost handles a return. Tell me which parts you are confident about
because you read them and which parts you are inferring.

That prompt gets a different answer from the same question without the second sentence. Not a magic one, and not one you can stop checking, but the hedges land in roughly the right places, and a hedge is a pointer to what to read yourself.

Your turn

src/config.ts defines five configuration options. One of them is dead: nothing anywhere in the codebase reads it.

Find out which, using Claude Code rather than grep. Ask something like:

For each field in the Config interface in src/config.ts, tell me every place in src/
that reads it. Read the files, do not guess from the names.

Then check it yourself:

grep -rn "enableAuditLog" src/

Check: Claude names enableAuditLog as the dead one, and grep finds it in exactly two places, both in src/config.ts itself: the interface and the line that reads the environment variable. Nothing consumes it. If Claude named a different field, or hedged about all five, run the grep on each field yourself and see which of you was right.

Then, for the harder half: ask why it exists. The comment above it says TODO: the audit log itself. See STK-118. The honest answer is that somebody added the switch first and never came back, which is a thing you will now recognise in your own codebases.

Recap

Reading is where the tool earns its keep, and a narrow question that ends somewhere you can check is worth five broad ones. git log and git blame on a confusing file usually explain more than the file does. @ puts a specific file in front of it instead of making it search.

Three ways an explanation goes wrong: answering from the name instead of the body, tidying up inconsistency that is there in the code, and trusting documentation over code. All three are invisible unless you check, so check the parts you are about to change.

Next: the mode where it is not allowed to change anything at all, and when that is worth the extra step.