How to Take Over an Existing Codebase: An Audit Checklist
At some point you will inherit software you did not write: a previous vendor's app, a founder's prototype that became the product or a legacy system nobody wants to touch. The first week decides whether the take-over goes smoothly. This guide is a practical checklist for auditing an existing codebase, finding the real risks and agreeing a plan before you change anything.
Principles for the first week
- Do not start by rewriting. You do not yet know what the code does that nobody documented.
- Make it run first. If you cannot build and run it, you cannot safely change it.
- Separate facts from opinions. Write down what you observe, with evidence, before judging the previous team's choices.
- Stabilise before you improve. Backups, access and monitoring come before refactoring.
Step 1: Secure access and ownership
Before reading a line of code, confirm that you can actually operate the product:
- Source repositories and every branch that matters
- Cloud subscriptions and resource groups (Azure, AWS, Firebase and so on)
- Domains, DNS and certificates
- App Store Connect and Google Play Console, including signing keys and upload keys
- CI/CD pipelines and their secrets
- Third-party services: payments, email, analytics, push notifications
- Production databases and a way to restore them
If the previous vendor still owns an account, arrange a transfer now. Losing a signing key or domain later is far more expensive than a short conversation today.
Step 2: Get it running locally
Time how long it takes a new developer to run the system. The result is an audit finding in itself.
- Clone, install and run the app from a clean machine.
- Note every undocumented step, missing environment variable and hardcoded path.
- Write or fix the README as you go; this is your first deliverable.
- Create a local or staging environment with fake data so you never experiment on production.
Containerising the setup with Docker Compose is often the fastest way to make the project reproducible.
Step 3: Map the architecture
Draw the system as it actually exists, not as someone remembers it:
- Components: clients, APIs, background jobs, databases, queues and storage
- Data flow: where user data enters, where it is stored and who can read it
- External dependencies: every third-party API and SDK
- Environments: what exists in development, staging and production, and how they differ
- Deployment: how a change gets from a commit to users
A one-page diagram and a list of dependencies are enough. Compare the production cloud resources with the code; unused or untracked resources are common and often cost money.
Step 4: Measure code health with evidence
Use tools to produce numbers you can show the owner:
| Area | What to check | Example tools |
|---|---|---|
| Dependencies | Outdated or vulnerable packages | dotnet list package --vulnerable --outdated, npm audit, flutter pub outdated |
| Static analysis | Warnings, complexity, dead code | Roslyn analysers, ESLint, dart analyze, SonarQube |
| Tests | Count, pass rate, coverage of critical paths | Test runners and coverage reports |
| Build | Time and reliability of CI | Pipeline history |
| Repository | Commit history, bus factor, large files | git shortlog -sn, git log --stat |
| Secrets | Keys committed to history | gitleaks, trufflehog |
For .NET projects, unit testing in .NET explains how to add tests around the riskiest behaviour before you change it.
Step 5: Review security and data protection
Focus on issues with real consequences:
- Secrets in the repository or in client apps. Rotate anything that leaked.
- Authentication and authorisation. Can one user read another user's data by changing an ID?
- Input handling. SQL injection, file upload paths, unvalidated deep links.
- Transport and storage. HTTPS everywhere, encrypted backups, sensible retention.
- Personal data. What is collected, where it goes and whether the privacy policy matches reality.
- Admin surfaces. Default credentials, open dashboards, public storage containers.
Record severity and a concrete fix for each issue. Fix critical exposures immediately; schedule the rest.
Step 6: Check production health
Code quality means little if production is quietly failing:
- Error rates and crash-free sessions from existing monitoring, or add monitoring if none exists. Application Insights is a good start on Azure.
- Performance hot spots: slow queries, large payloads, startup time.
- Backups: confirm they exist and restore one to prove they work.
- Cost: compare cloud spend to usage and look for idle resources.
- Store status: rating trends, recent reviews, pending policy warnings.
Step 7: Identify the knowledge that exists only in people's heads
Interview the previous developers or the owner if you can. Ask:
- Which parts are fragile or were rushed?
- What manual steps happen on every release?
- What customer promises are not written down?
- What would they refactor first and why?
Capture the answers in the repository, not in chat history.
Step 8: Decide: fix, refactor or rebuild
Most rewrites fail because they underestimate hidden behaviour. A rewrite is justified only when several of these are true:
- The code cannot be understood or tested even with effort
- The platform or framework is end-of-life with no upgrade path
- Security or data problems are structural
- Every change causes regressions
- The product is small enough that rebuilding is cheap
Otherwise, prefer incremental improvement: add tests around critical flows, upgrade dependencies, extract modules and remove dead code in small steps. Principles from Clean Code and Clean Architecture help decide where boundaries should go.
Step 9: Write the audit report and a 30-60-90 day plan
A useful report is short and ordered by risk. Include:
- Summary: overall health and the top five risks in plain language
- Findings: each with evidence, impact, severity and a proposed fix
- Quick wins: low-effort changes that reduce risk this week
- Roadmap: 30, 60 and 90 day plan with priorities and estimates
- Open questions: things you could not verify
Example priority order:
- Days 1 to 30: access, backups, monitoring, secret rotation, reproducible build, critical security fixes
- Days 31 to 60: dependency upgrades, tests on core flows, CI/CD improvement, documentation
- Days 61 to 90: targeted refactoring, performance work, planned feature development
Take-over checklist
- All accounts, domains and signing keys transferred
- App builds and runs from a clean machine
- Architecture diagram and dependency list written
- Dependency, security and secret scans completed
- Backups restored successfully once
- Monitoring and crash reporting in place
- Audit report delivered with a 30-60-90 plan
Related guides
- How to outsource mobile app development to Vietnam
- Unit testing in .NET
- Clean code principles and practices
Conclusion
A good take-over starts with access, a reproducible build and an honest picture of risk, not with a rewrite. Audit the architecture, dependencies, security and production health, write down what you find with evidence and agree a staged plan with the owner. If you have inherited a codebase and want an independent review or a hand-over, the services page describes how I handle maintenance and rescue work.