WRITING / ESSAY

How I read a codebase I didn’t write

What fifteen years of inheriting other people’s systems taught me about judging one in ten days.

JUNE 2026 · 8 MIN · HARIVANSH

I have never been the diligence firm. I have been the engineer who inherited what the diligence firm missed.

That is my qualification for writing this, and I think it is the better one. A review that ends with a report ends before the interesting part. The engineer who arrives afterwards, who has to make the thing work on a Tuesday with customers on it, finds out which of the report’s concerns were real. I have been that engineer more times than I can count, across a dozen industries, on systems whose authors were long gone. Everything below is what that taught me.

Do not read it. Run it.

The first thing I do with an unfamiliar codebase is not open a file. It is clone it onto a clean machine and try to get it running, with a timer going.

Time to first successful run is the densest single signal available. In one number it measures the documentation, the environment discipline, the hidden dependencies, whether secrets are handled or scattered, and whether anyone has onboarded a new engineer recently enough for the instructions to still be true. It is also the only diligence measurement that maps directly onto a cost the buyer will pay: every future hire pays that same startup tax, every time.

Twenty minutes is excellent. An afternoon is normal. Two days, and you have learned that nobody has joined this team in a long while, or that the person who knows how to do it has never had to write it down. That second finding is usually more important than anything in the code.

I keep notes on what went wrong rather than just how long it took. A missing environment variable with no error message. A service that only runs against a staging database somebody has to grant you access to. A seed script that fails silently. None of these is a defect. Together they describe a team’s relationship with its own system.

What I read, and in what order

Once it runs, I go through the same sequence, and the order matters more than the list.

The commit history first. Not the code, the history. How many distinct authors, and how is the work distributed among them? Are commits atomic and described, or are there long runs of “fix”, “fix again”, “wip”? Where are the hotspots, the files touched every week for three years? Change concentration is an x-ray. It shows you where the pain is without anyone having to tell you.

Then the shape. The directory tree at two levels deep, and one question: does this structure describe the business, or does it describe the framework? Folders named for what the company does are a sign that somebody modelled the domain. Folders named for technical categories, with a utils or common that has quietly swallowed a third of the codebase, are a sign that nobody did.

Then the dependencies. Not to count how many are out of date. To find out whether an upgrade path exists at all, whether anything has been abandoned upstream, whether anything has been forked and patched in place, and what the licences actually permit. That last one is the least glamorous check in diligence and one of the very few that can change a deal.

Then the tests, but not the coverage number. I read the test names. Test names are honest documentation, because nobody writes them for an audience. They tell you what the team believed was worth protecting. A suite that covers the payment path thoroughly and the integrations not at all is telling you exactly where this team has been burned before.

Then the schema. The schema is the truest document in any codebase. Code describes what somebody intended; the database records what actually happened, including every compromise, every column added under deadline, every status field that became free text because a decision was deferred. Read the schema and the migration history together and you have the company’s engineering history in chronological order.

Then one path, end to end. Just one, and it should be the one the business is paid for. I follow it from the interface to the storage layer and back, reading everything it touches. One traced path tells you whether the architecture is real or decorative, and it is worth more than a week of browsing.

What I deliberately do not look at

This is the part that most technical reviews get wrong, and it costs their clients real money.

I do not care about formatting, lint configuration, or whether the naming convention is one I would have chosen. I do not care that it is written in an unfashionable language. Boring technology that a team understands is an asset, not a finding. I do not report the coverage percentage as though it were a grade, because a codebase can be ninety per cent covered by tests that assert nothing. I do not paste static analysis output into a report and call it diligence. And I do not treat “it is a monolith” as a finding, because it usually is not one: what matters is whether the internal boundaries are real, and plenty of monoliths have better boundaries than plenty of microservice estates.

The reason to be strict about this is not taste. Every one of those items can be dressed up as a risk, given a remediation budget, and totalled into an impressive-looking number. The report then reads as thorough, and the buyer funds a programme to solve problems they did not have, while the finding that would actually have cost them money sits three pages further down with the same weight as a linting rule.

The half that nobody does properly

A codebase is evidence of an organisation. You can learn its shape from the commit history, but you can only understand it by talking to people, and the conversations are more useful than the code review.

I want two people in particular: whoever performs deployments, and the most junior engineer who has been there longest. The first knows what actually breaks. The second remembers what was confusing before it became normal, which is knowledge that evaporates within a year of joining.

The questions that earn their time:

What was the last thing that broke in production, and what did you do? This tells you about incident response, monitoring, and psychological safety in one answer.

If nobody asked you for a feature for two weeks, what would you fix? Every engineer has this answer ready. It is the internal risk register, and it is free.

What can you not change? The honest answer is a map of the system’s frozen parts.

Who is the only person who understands a given subsystem? Ask it about several, and watch whether the same name keeps coming up.

Would you deploy on a Friday afternoon? Nobody lies about this one.

One more, which I use as a check on everything else: I ask two engineers separately to define the same core business term. If the answers differ, the domain model exists in nobody’s head, and every specification written in that company is quietly ambiguous.

Where the line actually falls

After all of it, one distinction decides what goes in the report:

Code is cheap to fix. Data and contracts are not.

Everything else is a special case of that. Ugly code with clear boundaries is a budget line. A missing test suite is a budget line, and a smaller one than people expect. But five years of accumulated bad data behind a schema with no integrity is not a refactor, because you can rewrite code and you cannot rewrite history. A licence obligation attached to your core differentiator is not a roadmap item. A key person leaving with knowledge that was never written down is a countdown, not a cost.

PRICE IT IN REPRICE, OR WALK
Ugly code behind clear boundaries Years of bad data behind a schema with no integrity
A missing or thin test suite A copyleft licence inside the core differentiator
No documentation The only person who understands it is leaving
Dependencies behind, with an upgrade path A build nobody can reproduce from source
A coherent monolith Regulatory failure modelled into the data
Performance issues with headroom left A half-finished rewrite, both systems live
Figure — twelve findings, and the two columns a buyer needs them sorted into.

The tell is not how bad something looks. It is whether money can undo it.

Nobody earns this by reading

The most useful judgment I ever formed about a system came after eighteen months of maintaining it.

It was a working product with clinical users depending on it daily, built fast by people under pressure, on a foundation that could not carry where the company was going. I could have said that in week one. I would have been right in the way that a stopped clock is right. It took a year and a half inside it, fixing things at inconvenient hours, watching which assumptions held and which quietly cost us every time we touched them, before I could say which parts had to be replaced and which merely offended me.

Then we replaced the foundation, and it worked, and it worked because the proposal had been earned rather than assumed.

Ten days is not eighteen months. That is exactly why the method has to be disciplined about what it can and cannot establish, and honest in the report about the difference. What ten days can do is find what is systematically wrong, price it, and separate the parts that money fixes from the parts it does not. What it cannot do is tell you everything. Any review that claims otherwise is selling you confidence rather than judgment.

I have written out what that looks like as a finished document: a full sample assessment (opens in a new tab), twenty-three sheets, with a real method. It is in the services block on the front page, and you do not need to give me your email to read it.

If you are wiring money into a businessbuilt on software you have not read,write to me.

x@harivansh.dev

I reply within one business day.