What can you honestly know about a code base after one day with it? Not how it should be rewritten, and not whether the last developer was any good. But you can know how to start it, where work enters it, what one real request does from end to end, what the data looks like and what frightens you. That is enough to make the next decision well, and it fits in eight hours if you keep to the order.
This is the first day of a rescue job as I would plan it: a build that stalled, or a system that works but that nobody left in the building can explain. One rule holds all day. Fix nothing. A fix made before you understand the system is a guess with commit rights.
Hour one: make it run
Follow the README, if there is one, and write down every step it leaves out. Read the dependency files (composer.json, package.json, requirements.txt) for what the code needs and how old it is. Run it against a copy of the data, never against production, and check what the config file points at before you start anything.
If it will not run within the hour, stop and note why. “Nobody can start this system from scratch” is a finding, and often the most important one of the day.
Hour two: read the history
Git remembers what nobody wrote down: who worked on the code, when they stopped, which files change most often and what the last few months of commit messages sound like. Files that change constantly are where the trouble lives. A run of messages saying “fix”, “hotfix” and “temp” describes a system being held together by hand. These are the commands for the whole day, history first:
# Who built it, and when did the work stop?
git shortlog -sn --all
git log -30 --date=short --pretty=format:'%ad %an %s'
# The files that change most often
git log --pretty=format: --name-only | grep -v '^$' | sort | uniq -c | sort -rn | head -20
# The doors: routes, scheduled jobs, queues, webhooks
grep -rnE 'Route::|@app\.route|router\.(get|post)' --exclude-dir={vendor,node_modules,.git} .
grep -rliE 'cron|schedule|queue|webhook' --exclude-dir={vendor,node_modules,.git} .
crontab -l # on the server, as the user the application runs as
# Secrets in the code, now or anywhere in its history
grep -rniE 'password|secret|api_?key' --exclude-dir={vendor,node_modules,.git} . | head -40
git log -p | grep -iE '^\+.*(password|secret|api_?key)' | head -20
# The data model: structure only, no rows
mysqldump --no-data -u readonly -p appdb > schema.sql
pg_dump --schema-only -d appdb -f schema.sql
Run the database dumps with a read-only account, or against a copy. Structure is all you need today; leave the rows where they are.
Hour three: find every door
Work enters a system through more doors than its pages. List every one: routes and controllers, scheduled jobs, queue workers, webhooks that other services call, and the script somebody runs by hand on the first of the month. The grep lines find most of them. The crontab finds the rest, and it is worth reading even when the code insists there are no scheduled jobs. Background jobs are where the surprises live, because nobody watches them run.
Hours four and five: follow one real request
Pick one thing the business depends on: placing an order, raising an invoice, sending the payment reminders. Not the simplest path; the one that brings in money. Follow it from the button to the database and back: the route, the controller, each function it calls, each query it runs, each file it writes and each email it sends. Add a log line at every step, or walk through with a debugger, until you could describe the path without looking.
Write it down as a list of files and functions, in order. It will be the most useful page you produce today, because the next person to open this code can follow it in minutes. On the way you will see the code’s habits too: how it checks input, what it does with errors, whether it talks to the database in one place or in forty.
Hour six: read the data model
Code changes; data stays. Read the schema the way an auditor reads a chart of accounts (I spent years in audit and accounting systems before this work, and the habit stuck): what are the nouns of this business, how do they connect, and where could a number go missing? Note the tables with no foreign keys, the columns called status, type or flag2 whose meaning lives in somebody’s head, money stored as floating point and dates stored as text. Get rough row counts (MySQL keeps an estimate in information_schema.tables, PostgreSQL in pg_stat_user_tables) so you know which tables are big enough to hurt.
Hour seven: list what scares you
Now write down everything that worried you, one line each, with where you saw it. The usual entries: passwords in the repository; no backups, or backups nobody has ever restored; deployment by copying files from one person’s laptop; SQL built by gluing strings together; no tests around the code that touches money; one scheduled job doing six unrelated things.
Still fix nothing. But if data is leaking now, or there are no working backups, tell the owner today, in writing, rather than in tomorrow’s document. Everything else waits until it has been ranked.
Hour eight: write it down
End the day with one document for two readers. At the top, a paragraph in plain English for the owner: can the system be run, how risky is it, and what should happen first. Below it, for whoever touches the code next: how to run it, the doors, the request you traced, the data model in a few paragraphs, the list of worries ranked by how much damage each could do and what it would cost to fix, and the questions only the owner can answer.
A day’s notes will get some things wrong, and they should mark which parts are guesses. That is fine. Wrong in writing on day one is cheap to correct. Wrong in someone’s head on day thirty is how a rescue job ends up needing a rescue of its own.