Separate what is known from what still needs verification
When a business acquires, inherits or considers modernising a legacy web application, the codebase itself holds the answers to questions that no amount of stakeholder interviews can resolve. The audit process establishes what the system does and how it is deployed; examining the codebase reveals how it was actually built, where the hidden risks sit and what it would take to change it safely.
A codebase review is not a line-by-line inspection. For a business owner or operations manager, the goal is to identify structural indicators that affect cost, risk and feasibility of future work. Developers can argue about style preferences indefinitely, but certain patterns have direct, measurable consequences for maintenance burden, security exposure and the realistic scope of any modernisation project.
The distinction matters because a system that looks functional on the surface can harbour problems that make even modest changes expensive or unpredictable. Understanding what to look for allows non-technical decision-makers to ask the right questions, interpret what a technical review uncovers and compare supplier assessments on a meaningful basis rather than vague reassurances.
Why Codebase Health Differs from System Functionality
A legacy application can run reliably for years and still be deeply problematic to modify. Functionality and maintainability are separate qualities. A system that processes orders correctly today might still be built in a way that makes adding a new payment method, changing a tax rule or connecting to a new integration disproportionately expensive. The codebase review targets that second dimension: not whether the system works, but what it would cost to change.
Dependency Age and Patch Status
Every web application relies on external libraries, frameworks and packages. The first practical check is the age and maintenance status of these dependencies. A framework that stopped receiving security updates several years ago represents a concrete, quantifiable risk. It does not necessarily mean the application is immediately exploitable, but it means any newly discovered vulnerability in that framework will not be fixed by its maintainers, leaving your supplier to patch it independently or accept the exposure.
Ask for a dependency inventory showing each library, its version, its last update date and whether that version is still within the supported lifecycle. If a supplier cannot produce this quickly, that in itself is a useful signal about how the system has been managed.
Code Organisation and Separation of Concerns
How the code is structured affects how quickly someone unfamiliar with it can make safe changes. Look for whether business logic, database queries, user-interface rendering and configuration are mixed together in large files or separated into distinct layers. When a single file handles receiving a web request, validating input, running business rules, updating the database and generating the HTML response, even a small change carries a higher risk of unintended side effects.
This is not about architectural purity for its own sake. Poor separation directly increases the time a developer spends reading code before writing it, which directly increases the cost of any change request.
Database Access Patterns
How the application talks to its database reveals a great deal about long-term maintainability. Look for whether database queries are scattered throughout the codebase or consolidated into a defined data-access layer. When SQL queries are embedded directly in dozens of different files, changing a table structure or migrating to a different database engine becomes a far larger task because every occurrence must be found, understood and modified individually.
Also check whether the application constructs queries by concatenating strings with user input. This is a well-known source of SQL injection vulnerabilities and suggests that security was not treated as a structural concern during development.
Error Handling and Logging
Examine how the application handles things that go wrong. Consistent error handling with meaningful logging allows problems to be diagnosed quickly. The absence of structured error handling often means that failures produce generic messages, hide the real cause and leave operations staff guessing. Look for whether errors are caught at appropriate levels, whether logging includes enough context to trace a problem back to a specific user action or data record, and whether sensitive information is being written to logs inadvertently.
Configuration Management
Check whether configuration values such as database connection strings, API keys, file paths and environment-specific settings are stored in code files, in configuration files separate from the code, or in environment variables. Hardcoded configuration in source code means every environment—development, staging, production—must be changed by editing code, which increases the risk of accidental deployment of development settings to a live system.
Authentication and Session Handling
Even without conducting a formal security assessment, certain patterns in the codebase are visible red flags. Look for whether authentication logic is implemented from scratch rather than using established libraries, whether passwords are stored using modern hashing algorithms, and whether session management follows standard patterns. Custom-built authentication is a recurring source of serious vulnerabilities in legacy applications.
Treating Code Quality as Subjective
One of the most common mistakes is dismissing codebase assessment as purely opinion-based. While judgements about readability have a subjective element, the indicators listed above—dependency patch status, separation of concerns, database access patterns, error handling, configuration management and authentication approaches—are structural facts that can be documented and compared. A supplier who characterises all code quality feedback as mere preference is not giving you an accurate picture.
Confusing Code Volume with Complexity
A large codebase is not inherently problematic, and a small one is not inherently healthy. A well-structured 200,000-line application can be easier to maintain than a 20,000-line one where everything is tightly coupled. When evaluating a legacy system, focus on how the code is organised and how changes propagate, not on the raw line count.
Assuming Modern Tooling Implies Modern Code
The presence of contemporary build tools, package managers or deployment pipelines does not guarantee that the application code itself follows current practices. It is possible to run a ten-year-old codebase through a modern deployment pipeline. Verify that the tooling reflects the code, not just the infrastructure around it.
Key Checks to Request from a Technical Reviewer
- Dependency inventory: A list of all third-party libraries, their versions and current support status.
- Coupling assessment: Identification of areas where changing one module forces changes in unrelated modules.
- Data-access pattern summary: Whether database interactions are centralised or distributed, and whether parameterised queries are used consistently.
- Configuration audit: Where settings live and whether environment-specific values are properly separated from code.
- Authentication approach: Whether the application uses established libraries or custom implementations, and how sessions are managed.
- Test coverage: Whether automated tests exist, what they cover and whether they still pass. The absence of tests does not make a codebase unusable, but it does increase the cost and risk of any modification.
Limitations of a Codebase Review
A codebase review has clear boundaries. It can reveal structural risks and maintenance cost drivers, but it cannot reliably predict exact effort for future changes without more detailed scoping. It also cannot substitute for a dedicated security penetration test, which examines the running system rather than the source code. Similarly, the codebase review should be read alongside the system documentation assessment and the broader operational audit, each of which addresses questions the code alone cannot answer.
Record the current state and unresolved risks
For business owners, the practical value of understanding what to look for in a legacy codebase is the ability to have informed conversations with technical suppliers, challenge vague assurances and make decisions about modernisation, takeover or replacement on the basis of structural evidence rather than surface-level demonstrations.