Reading a strange codebase in a day
AI · Aug 2026 · 7 min read
Inheriting 200k lines used to be a week of grep and optimism. The goal was never to have the code explained — it was to get a map you can be wrong about quickly.
Most of my consulting work starts the same way: a codebase I have never seen, a team that is tired of explaining it, and a question I am expected to answer by Friday. The first day used to be grep and optimism. It is now a fairly mechanical hour, and the change is larger than any productivity claim I would normally believe.
The order the questions go in
The mistake is asking what the code does. That gets you a summary, and a summary is exactly the thing you cannot verify. Ask for structure instead, in an order that builds a map rather than a narrative.
1. list every entry point: http routes, consumers, cron, cli
2. the data model as tables and relations, nothing else
3. trace the one flow that makes the money, end to end
4. where does this codebase disagree with its own conventions?
# 4 is the one that pays. the disagreements are where the
# history is, and the history is what nobody will tell you.
Question four consistently returns the most valuable thing in the room. Every codebase has three or four places where it stops following its own rules, and each one is a decision somebody made under pressure that is still load-bearing. Those are the places that will bite a newcomer, and they are precisely what an experienced engineer would have taken a month to notice.
The goal is not to have the code explained. It is to get a map you can be wrong about quickly.
Verify against the thing, never the summary
A confidently wrong call graph is worse than no call graph, because you will build on it. So every structural claim gets checked against the code itself before it enters my model: run the test, follow the import, add a log line. I treat the output as a set of leads, and leads are cheap to disprove — which is the entire reason this works.
The two failures I now expect: a caller that no longer exists because a refactor left the function orphaned, and a relationship inferred from naming rather than from a foreign key. Both look completely reasonable. Both take about ninety seconds to check.
- First useful question to the team went from day three to hour two — and it was a better question.
- The map is wrong in two or three places, which I now expect and go looking for.
- What I stopped spending: the two days of reading required before I could ask anything without embarrassing myself.
The part I did not anticipate is what this does to the incumbent team. Turning up on the second morning with a diagram they have never had and asking whether the odd bit in the billing module was deliberate is a very different conversation from asking them to walk you through the app. They correct the diagram, and the corrections are the good stuff.
Takeaways
- Ask for structure — entry points, data model, the flow that earns — not for an explanation.
- Ask where the codebase disagrees with itself; that is where the undocumented history lives.
- Treat every structural claim as a lead to disprove against the code, not as a fact.
All notes · Shehzad Aslam