SlamData

Practice

Reading Code You Did Not Write

Reading a large unfamiliar system top-down does not work. What does: start from behaviour, follow one path, and write down what you learn.

The instinct with an unfamiliar system is to read it — start at the top, work down, build a picture. It does not work. A hundred thousand lines do not fit in anyone's head, and reading in file order teaches you the file order.

For a separate people-operations perspective, this external reference covers using external systems to reduce working-memory load.

What works is narrower and more deliberate.

Start from behaviour, not from structure

Run it. Whatever the system does, do it. Place the order, submit the form, process the file. You now have a concrete thing that happened, which is far more useful than a diagram.

Then find where that happened in the code, working backwards from something observable: a log line, an error message, a database row, an HTTP endpoint.

Searching for a literal string from the interface is the fastest way in. An error message, a label, a column name. It lands you in the middle of the relevant code rather than at the top of the wrong file.

Follow exactly one path. From entry to exit, for one operation. Do not detour into interesting-looking code. One complete path through a system teaches more than partial knowledge of ten.

Use the tools rather than reading

A debugger, with a breakpoint, on the running system. The call stack tells you the actual path — including the parts that dependency injection, event dispatch or reflection make invisible in the source. Ten minutes with a debugger beats an afternoon of reading in a system with any indirection.

A tracing or profiling tool shows what actually executes and in what order, and it reveals the calls to external systems that reading tends to miss.

Version control history, which is under-used and is the only source for why:

git log -p path/to/file        # how it changed and why
git log -S "some_string"       # when a thing was introduced
git blame -w path/to/file      # who, when, and which commit

A strange piece of code with a commit message explaining the bug it fixes stops being strange. This is the single most useful technique for legacy code, and it is why deleting "weird" code without checking its history is dangerous.

Look at the tests, which are executable documentation of intended behaviour and of the edge cases someone hit.

Make a map, not a model

You are not trying to understand the whole system. You are trying to know where things are.

Write down, as you go:

The entry points. HTTP routes, message consumers, scheduled jobs, command-line entry.

The data stores, and which parts of the code own which tables.

The external dependencies — every outbound call.

The names for domain concepts, especially where the code uses a different word from the business. This mismatch is a reliable source of bugs and confusion, and writing down the translation is immediately useful to everyone.

Where the surprises are. The place where two subsystems interact unexpectedly, the function that has a side effect its name does not suggest.

Write this down where others can read it. You will forget it in a month, and the next person will otherwise repeat the work. See what you learn in week one — this is the same principle as recording what looks strange while you can still see it.

Change something small and safe

Reading has diminishing returns quickly. Understanding arrives through changing.

Pick something trivial — a log message, a validation message — and take it all the way through build, test and deploy. You learn the toolchain, the test setup and the deployment path, which is a large part of what slows people down.

Then pick something small and real, and watch what breaks. What breaks tells you about the coupling, which is the part no document describes.

Add a test before changing behaviour. In code without tests, a characterisation test — one that records what the code currently does, correct or not — gives you a safety net without requiring you to know whether the behaviour is right.

Reading strange code charitably

Most odd code had a reason. The reason may be gone; it existed.

Assume competence under different constraints. A different deadline, a different platform version, a requirement that has since been dropped, a bug in a dependency.

Check the history before removing anything. The most expensive mistakes in legacy systems are deletions of things that turned out to be load-bearing.

Look for the workaround shape: a redundant null check, an odd ordering, a sleep, a retry around something that should not need one. Each one is usually a scar from a real incident.

Where the history is silent and the code is inexplicable, that is a finding worth recording rather than a puzzle to solve immediately.

Signals worth noting as you read

Duplicated logic with small differences. Usually means a change has to be made in several places, and someone will miss one.

Comments that contradict the code. Trust the code; note the comment as evidence of a change nobody documented.

Dead code, which costs attention every time someone reads it. Confirm with usage data and delete.

Configuration that is actually logic — long conditional chains in a settings file.

Very large functions, which are where the undocumented coupling usually lives.

None of these are tasks yet. They are notes. Fixing things while you are still learning the system is how people break things they did not know were connected.

The things worth asking a person

Some knowledge is not in the code at all, and half an hour with someone who was there saves days.

What breaks most often?

What is everyone afraid to touch, and why?

What is the part that looks wrong and is actually deliberate?

Where does the code disagree with what the business calls things?

What would you fix if you had a week?

If nobody is left, the incident record and the commit history are the substitutes, and they are surprisingly good ones.

The summary

Start from something observable and follow one path all the way.

Use the debugger and the commit history, which answer questions reading cannot — the actual path, and the reason.

Build a map of where things are, not a model of how everything works.

Change something small early, because understanding arrives through changing rather than through reading.

And assume the strange code had a reason — check the history before removing it, because the ones that look most pointless are frequently the ones holding something up.

For primary background on this topic, consult Software Engineering Institute.