Back to insights

Inheriting a Codebase: What I Check in the First Two Days, Before I Change a Line

Roy LevyRoy LevyOctober 202610 min readSystems & architecture
The first two days are for reading the system, not improving it. Every fix you make before you understand it is a guess.

A founder sends me a repository and says: "We need someone to take this over."

The temptation, for any developer in that position, is to start fixing. You open the code, see the things you would have done differently, and your hands start moving. Rename this. Extract that. Upgrade the thing that is two major versions behind.

It feels productive. It is usually the most expensive thing you can do in week one.

An inherited codebase is a system you do not understand yet. Some of the ugliness in it is real debt. Some of it is the scar tissue from a customer problem somebody solved at 11pm. From the outside, you cannot tell which is which, and you will not find out by tidying.

So I spend the first two days reading, running, and measuring. I do not change anything. Here is what I look at, in order, and what each step tells the person who is paying for it.

Rule zero: touching nothing is the point

The audit has one constraint. I am allowed to run the code, read the code, and ask questions. I am not allowed to improve it.

That constraint does two things. It protects the product, because nothing I do on day one can break production. And it forces me to build a real map of the system before I start imposing my own opinions on it.

The first two days

Understand it before you improve it.

  • 01

    Day one

    Can it run, deploy, and roll back?

  • 02

    Day two

    Where is the risk, and where is the money?

Day one: can this thing actually be operated?

Before I judge the quality of the code, I want to know if the system is healthy. A beautiful codebase nobody can deploy is worth less than an ugly one that ships on demand.

1. Can I run it from scratch?

I clone the repository onto a clean machine and try to get it running using only what is written down. No messages to the previous developer, no tribal knowledge.

How far I get is the first real signal. Typical outcomes:

  • It runs in minutes. Someone cared about onboarding. This is a good sign about everything else.
  • It runs after an hour of guessing. Missing environment variables, an undocumented service, a database that needs to be seeded in a specific order. This is common and fixable, and every one of those steps is a hidden cost the next developer will also pay.
  • It does not run. Now we know the knowledge lived in one person's head. That changes the risk profile of the entire project.

For a founder, the translation is simple: if I cannot run it, a new hire cannot either, and neither can anyone you hire after them.

2. Can it be deployed, and can the deploy be undone?

I want to see how a change gets from a laptop to production, and I want to know what happens when it goes wrong.

The questions are boring and decisive. Is there a repeatable deploy, or is it somebody running commands by hand? Is production configuration stored anywhere other than a person's memory? And the one I weigh most heavily: if this afternoon's deploy is bad, how do we go back?

If the answer involves the words "database migration" and a long silence, I have just found the most dangerous part of the project. Code can be rolled back by redeploying the old version. Data usually cannot.

3. Where are the secrets, and who has them?

Next I check how credentials are handled. Are API keys in the repository history? Are production keys shared across environments? Does a former contractor still have access to the hosting account, the database, or the payment provider?

This is rarely a code problem. It is an access problem, and it is the one most likely to cause real damage before I have written a line. I list every service the product depends on, who owns each account, and whether the founder can log in to all of them.

If the founder cannot, that goes to the top of the list, above any bug.

4. Read the git history before the code

The history tells you things the code cannot.

I look at how often the project changed and when it slowed down. I look at commit messages: are they explanations, or are they "fix", "fix 2", "final fix"? I look for the files that change constantly, because those are where the pain is. And I look for the long gaps, which usually line up with a team change or a budget problem.

A file that has been edited three hundred times is not necessarily bad. But it is where I will spend my attention, because it is where every feature collides.

Day two: where is the risk, and where is the money?

Once I know the system can be operated, I look for the places where being wrong is expensive. I do not try to read everything. I read the paths that matter most.

5. Follow the money

Anywhere the product charges, refunds, credits, or calculates a price gets read line by line. The questions are narrow:

  • Is each pricing rule defined in one place, or copied into several?
  • What happens when a payment fails halfway through an order?
  • What happens when the same request arrives twice?
  • Do the numbers shown to the customer always match the numbers stored?

The reason is not that payment code is more interesting than other code. It is that mistakes here are the only ones that cost money directly and quietly. A broken button gets reported. A rounding rule that is off by a cent on one code path can run for a year.

6. Follow the data

I read the database schema as a whole, before looking at any single table. A schema tells the real story of the product, including the parts the code is embarrassed about.

I am looking for status fields that hold free text, columns that are mostly empty, the same concept stored in two places, and relationships enforced only by hope. I also check for the unglamorous essentials: are there backups, and has anyone ever restored one?

An untested backup is a wish. I would rather find that out on day two than on the worst day of the project.

7. Follow the permissions

Who can see and do what? I read how authentication works and, more importantly, how authorization is enforced. A common finding is that the interface hides a button from regular users but the underlying endpoint will still happily accept the request.

Anything touching personal data, admin functions, or other customers' records gets extra attention here, because that is where an oversight becomes a breach rather than a bug.

8. Check what the tests actually protect

I do not look at coverage numbers first. I pick a piece of important behavior, such as applying a discount, and ask which test would fail if I broke it.

Sometimes the answer is a real test that fails for the right reason. Sometimes the tests exist but only confirm that mocked functions return what the mocks were told to return. And sometimes there are none.

All three are useful to know. The point is to understand how much safety the next developer actually has, not how much the dashboard claims.

9. Look at the dependencies

Last, I look at what the project is built on. How outdated are the packages? Are any abandoned? Is there anything in the tree that nobody can explain? Dependencies are decisions that someone made once and everyone has been living with since.

I also note anything pinned to an old version "because upgrading broke something." That sentence usually marks a problem that has been avoided for a long time, and it deserves a place on the map.

What I hand back after two days

At the end I do not give the founder a lecture about code quality. I give them a short document with three parts.

What is healthy. Things that work and should be left alone. This matters more than people expect, because an audit that only lists problems pushes everyone toward a rewrite.

What is risky. The specific places where being wrong is expensive: money, data, access, and deployment. Each one gets a plain-language description and a rough size of fix.

What to do first, and what to leave. A proposed order of work, plus an explicit list of things I recommend not touching yet, with the reason.

That last list is the one founders find most useful. Knowing what not to spend money on is half of managing a technical budget.

The audit also answers the rewrite question

Most founders who hand me a codebase are quietly wondering whether it should be thrown away. The audit is how that question gets answered with evidence instead of frustration.

If the code is messy but runs, deploys, and holds its data in a sane shape, the answer is almost always a focused refactor of the few areas that hurt most. I wrote about that trade-off in the rewrite or refactor decision, and the audit is what turns that argument into a concrete list.

If the audit shows something genuinely foundational, such as a stack that is no longer supported or a data model that fights every feature, then a rewrite becomes a reasonable conversation. But it becomes a conversation with a map attached, and it can be run as a careful migration rather than a leap.

The same applies to code that was generated quickly. The patterns I described in what breaks in AI-generated codebases are exactly the things this audit is designed to surface, only earlier and cheaper.

What you can do before you hire anyone

If you are a founder and you are about to hand your product to a new developer, you can do some of the first-day work yourself, without reading any code.

  • Write down every service the product depends on and who holds each login.
  • Ask your current developer to deploy a trivial change in front of you.
  • Ask what happens if that deploy needs to be undone.
  • Ask when the database was last restored from a backup, not just backed up.
  • Ask where the price is calculated.

If those answers come quickly and clearly, you are in better shape than most. If they do not, you have just learned the most useful thing about your product, and you learned it for free.

Final thought

The first two days of working on someone else's code are the cheapest days of the whole engagement and the ones that shape every decision after them. Skipping them feels fast. It is how a small fix turns into a three-week surprise.

Read first. Run it. Find out what is load-bearing. Then start improving.

Taking over a codebase and not sure where to start?

If you have inherited a product, or you are about to hand yours to someone new, the safest first step is a short audit that maps what is healthy, what is risky, and what to do in what order.

That is the kind of work I do with founders who need their product stabilized without stopping it.

See how I approach web app rescue and product development

Questions about something you read here, or a project you want to move forward? I work with teams on full-stack builds, AWS and serverless consolidation, migrations, and messy systems.

Contact me