The application still runs. The person who understood it does not work here anymore. And every change you now make carries a risk nobody left on the team can size. That is the situation this page is written for: a business-critical custom application whose author has gone, with no documentation behind it, and a business that still depends on it every day.

The decision in front of you is not sentimental attachment to old code. It is which path costs you less risk over the next three years: rewriting the application, maintaining it, or replacing it. This page walks through how to make that call defensibly, and how to take ownership safely no matter which way it goes.

Quick Answer: How to Decide Whether to Rewrite Legacy Code

Whether to rewrite legacy code turns on four readable factors, not on the age of the code:

  1. Recoverability. Can the business logic be recovered from the system itself, or did it live only in the head of the person who left?
  2. Change frequency. How often does the application actually have to change? A system that changes monthly carries a very different risk profile from one that has run untouched for two years.
  3. Cost of failure while unowned. What does an outage or a wrong result cost the business right now, while nobody can confidently judge a fix?
  4. Platform future. Does the platform the application runs on still have a supported, patchable future, or is it heading toward end of support?

The sequence matters as much as the criteria: stabilize and document first, decide second. A rewrite chosen before the logic has been recovered does not remove the unknowns. It simply moves them into a new codebase, where they cost more to rediscover. Take ownership of what you have, make it safe to touch, and only then choose rewrite, maintain, or replace.

What Actually Broke When the Owner Left

When the developer who built and maintained an application leaves, the code does not change. What changes is that the only working model of how it behaves has walked out the door. The exposure is not the software. It is everything the software depended on that was never written down.

Four things typically break at once:

  • The logic is undocumented. The rules the business runs on, why a calculation rounds the way it does, which edge case a strange-looking branch exists to handle, lived in one person’s memory. The code encodes what it does. It rarely records why, and the why is what you need to change it safely.
  • Credentials and access are unowned. Service accounts, API keys, scheduled jobs, and the one machine that runs a nightly process are often tied to an individual rather than to a role. When that person leaves, you inherit systems you may not be able to fully see into, let alone modify.
  • There is no test coverage. A common and fair definition of legacy code is code without tests. Without them, you have no way to know whether a change you make preserves the behavior the business relies on. Every edit becomes a gamble, and the person best placed to judge the odds is gone.
  • No one can judge a change. This is the real cost. It is not that the application is old. It is that your team can no longer distinguish a safe change from a dangerous one, so every request, however small, is either blocked or shipped on faith.

This is what a key-person-risk failure looks like in practice, and it is why the honest answer to “should we just rewrite it?” is “not yet.” You cannot make a sound rewrite-versus-maintain decision from inside a system you cannot see. First you make it visible.

Stabilize Before You Decide: Taking Ownership of Code Nobody Understands

Taking over an undocumented custom application is a defined sequence, and it comes before the rewrite decision, not after it. The goal of this stage is narrow and worth stating plainly: make the application safe to operate and safe to touch, so that the decision you make next is made on evidence rather than on fear. Work it in this order.

  1. Inventory what exists. Enumerate the application’s parts: the codebase and where it lives, the databases, the integrations it calls and that call it, the scheduled jobs, and the environments it runs in. You cannot own what you have not listed.
  2. Establish access. Move credentials and ownership from the departed individual to named roles. Rotate secrets, reclaim service accounts, and confirm you can deploy and roll back through a path the team controls, not one that ran off a former employee’s laptop.
  3. Map dependencies. Trace what the application depends on and what depends on it. This is where hidden risk lives: an undocumented integration or a downstream report that silently breaks the moment you change something upstream.
  4. Recover the logic from the running system. Where documentation does not exist, the system itself is your source of truth. Read the code, observe the running behavior, capture the actual inputs and outputs, and write down the business rules you recover as you confirm them. This is the step that converts a black box into something a team can reason about.
  5. Establish a safe change path. Stand up a way to make a change, test it against recovered behavior, and roll it back if it misbehaves. Even a modest characterization test suite, one that pins down current behavior so you can tell when you have altered it, changes the risk profile of every future edit.

This stabilization work is valuable whether you ultimately rewrite, maintain, or replace, because all three paths require that you first understand what the application does. i3solutions runs this kind of takeover as a structured stabilization sequence in its legacy system integration consulting, where dependency mapping and a tested change path come before any migration or rewrite commitment.

The Rewrite-Versus-Maintain Decision, With Criteria

Once the application is stabilized and its logic is recovered, the decision becomes tractable. Apply the four factors from the Quick Answer as explicit criteria rather than as a gut feel.

Lean toward a rewrite (or replacement) when:

  • The platform is at or near end of support, so staying put means running unpatched, or the required skills have become genuinely scarce to hire for.
  • The application must change often, and each change is expensive and risky because of how it is built. High change frequency is what pays back the cost of a rewrite. Low change frequency almost never does.
  • The recovered business logic is well understood and can be carried into a new implementation with confidence. You are rebuilding a known thing, not rediscovering an unknown one.
  • The cost of a failure on the current system is high and the current architecture actively works against reducing that risk.

Lean toward maintaining when:

  • The application is stable and changes rarely. There is little to gain from rebuilding something that is not being touched.
  • The logic is only partly recovered. Rewriting now would move unresolved unknowns into new code, which is the most expensive place to discover them.
  • The platform still has a supported future and the real problem was ownership, not the technology. Once the application is documented and owned, the original pressure to rewrite often disappears.

A note on technical debt, because it is usually the word attached to these systems. Identify technical debt by its interest rate, not its age: debt that matters is debt you keep paying for, in the form of slow changes, repeated incidents, and workarounds that beget workarounds. When technical debt increases unaddressed, the effect is compounding, each change gets slower and riskier than the last, until routine maintenance consumes the capacity that should go to new work. That trajectory, not the calendar age of the code, is what should push a maintain decision toward a rewrite. A stable application with high notional debt that nobody is paying interest on is a weaker rewrite candidate than a younger one you fight every week.

Two guardrails on the decision itself. First, decide against a defined baseline: the recovered logic, the real change frequency, and the measured cost of failure, not an estimate you cannot defend to finance. Second, keep the paths distinct. If the honest problem is a stalled or failed delivery rather than an inherited unowned system, that is a different play, covered in rescuing a failed Microsoft modernization. If the question is broader modernization strategy across a portfolio, start from the application and legacy modernization service view instead.

Can AI Rewrite It For You?

The honest answer: AI is a real accelerator for the parts of this problem that are about reading, and it is not a substitute for the parts that are about judgment. Treat it as a tool for the stabilization stage, not as a shortcut around the decision.

Can AI rewrite legacy code? In the literal sense of translating source from one language or framework to another, assisted tooling can produce a draft. But a mechanical translation of undocumented code reproduces the behavior you already could not explain, now in a new language, and you still cannot explain it. The translation does not recover intent. It preserves the black box.

Where AI genuinely helps:

  • Comprehension. Can AI understand legacy code? It can summarize what a function appears to do, surface call graphs, and flag likely dependencies far faster than a human reading cold. That accelerates the logic-recovery step, as a first pass a human then verifies.
  • Documentation. It can draft the documentation that never existed, from the code and observed behavior, giving your team a reviewable starting point instead of a blank page.
  • Test generation. It can propose characterization tests that pin down current behavior, which is exactly the safety net an unowned application lacks.

Where it does not help, and where relying on it is dangerous:

  • Recovering intent that was never written down. If the reason a rule exists lived only in the departed developer’s head, it is not in the code for a model to find. AI can tell you what the code does. It cannot tell you which of those behaviors are requirements and which are accidents.
  • Regulated validation. In regulated environments, a plausible output is not an accepted one. Behavior has to be validated and evidenced against controls, and that accountability cannot be delegated to a generator.

Used well, AI shortens the path to a system you understand. It does not make the rewrite-versus-maintain decision for you, and it does not excuse skipping the stabilization work that makes any decision safe.

When Maintaining Is the Right Call

Sometimes the disciplined answer is to not rewrite at all, and it is worth saying so plainly. If an application is stable, changes rarely, runs on a platform with a supported future, and its real problem was that nobody owned it, then the right move is to document it, test it, name an owner, and leave it alone.

How to maintain legacy code in that situation is a matter of turning the stabilization work into a durable, low-cost standing state rather than a one-time scramble:

  • Keep the recovered documentation current, and treat it as part of the application rather than a side artifact.
  • Keep the characterization tests running, so the next change, whenever it comes, is judged against known behavior.
  • Keep access role-based and credentials rotated, so ownership never again depends on one individual.
  • Patch the platform on its normal cadence and watch for its end-of-support horizon, which is the signal that reopens the decision.

A rewrite is a large, risky investment. Spending it on an application that is not asking for change is how organizations manufacture the very risk they were trying to avoid. Maintaining a well-owned, well-documented, low-change system is not deferring the problem. For that class of application, it is the answer.

What Ownership Looks Like Once It Is Fixed

Whichever path you choose, the exit state is the same: the application is owned. You know you are done when four things are true.

  1. The logic is documented. The business rules the application enforces are written down, reviewable, and current, not held in one person’s memory.
  2. There is a named owner. A specific role, not a departed individual, is accountable for the application, its access, and its changes.
  3. There is a safe change path. The team can make a change, verify it against known behavior, and roll it back, without holding its breath.
  4. There is a decision record. The choice to rewrite, maintain, or replace is written down with the reasoning behind it, so the next person who inherits the system inherits the thinking too, and does not start this cycle over.

That last point is what breaks the key-person-risk cycle for good. The failure was never that a developer left. It was that everything they knew left with them. A decision record and living documentation mean the next departure is a staffing event, not a crisis. This continuity-through-ownership approach is the same one behind i3’s work with a national professional-standards board, whose legacy platform was migrated and integrated while day-to-day operations continued without interruption, documented in the FSBPT case study. For modernization programs where security and compliance evidence are part of the exit criteria, the same discipline is framed in security-aware Microsoft modernization, and the broader trade-off between moving fast and governing well is treated in governance-first versus speed-first modernization.

Key Takeaways

  • The trigger is key-person risk, not old code. What broke when the developer left is your team’s ability to judge a safe change, not the software itself.
  • Stabilize and document first, decide second. Inventory, secure access, map dependencies, recover the logic from the running system, and establish a tested change path before choosing a direction.
  • The rewrite-versus-maintain decision turns on four factors: recoverability of the logic, change frequency, cost of failure while unowned, and the platform’s supported future. Not the age of the code.
  • A rewrite chosen before the logic is recovered just moves the unknowns into new code. Recover intent first.
  • AI accelerates comprehension, documentation, and test generation. It does not recover intent that was never written down, and it does not carry accountability in regulated validation.
  • Maintaining is the right call for a stable, low-change application on a supported platform. Document it, test it, name an owner, and leave it alone.
  • Ownership is reached when the logic is documented, an owner is named, a safe change path exists, and the decision is recorded. That is what stops the cycle from repeating on the next departure.

Frequently Asked Questions

When should you rewrite legacy code?

Rewrite when the platform is near end of support or its skills are scarce, when the application must change often and each change is expensive because of how it is built, and when the business logic has already been recovered so you are rebuilding a known thing rather than a black box. Rewriting is rarely justified for a stable application that changes rarely, and it should never begin before the existing logic is understood, because an unrecovered rewrite simply relocates the unknowns into new code.

Can AI rewrite legacy code?

AI can draft a translation of code from one language or framework to another, and it genuinely accelerates comprehension, documentation, and test generation. What it cannot do is recover intent that was never written down or carry accountability for validation in a regulated environment. A mechanical AI translation of undocumented code reproduces behavior you still cannot explain, now in a new language. Use AI to help you understand the system faster, not to skip understanding it.

Why is legacy code so hard to change?

Because the code records what it does but rarely why, and the why is what you need to change it safely. When the person who held that context has left, and there are no tests to tell you whether a change preserved the behavior the business relies on, every edit becomes a gamble that no one on the team is positioned to judge. The difficulty is missing knowledge and missing safety nets, not the syntax of the code.

What are common legacy code problems?

The most common are undocumented business logic, credentials and access tied to individuals rather than roles, no automated test coverage, and hidden dependencies that break silently when something upstream changes. Underneath all of them sits the core problem in an inherited system: no one remaining can reliably tell a safe change from a dangerous one, so change either stops or ships on faith.

How do you handle legacy code?

Take ownership before you make decisions. Inventory the application’s parts, move access to named roles, map what depends on it, recover the business logic from the running system, and establish a tested change path with characterization tests. Only once the system is visible and safe to touch should you decide whether to rewrite, maintain, or replace it, and then record that decision with its reasoning so the knowledge does not leave again with the next person.

Talk to a senior architect