Short answer
#What legacy actually means
- Legacy system
- A system whose behaviour is not understood by anybody currently available to the organisation. The defining property is the absence of an answerable question, not the age of the technology, the state of the code or the framework version.
- In plain terms Software the company depends on and cannot ask anybody about.
This definition is more useful than the usual one because it points at the fix. If the problem were old technology, the fix would be a migration. If the problem is that nobody can answer questions, the fix is to make the system answer them — and that is achievable in days rather than quarters.
It also explains a thing that confuses people: new systems can be legacy on delivery. A product built quickly by contractors who then left has every property of a legacy system on its first day of production. So does a system assembled largely by coding agents that nobody read closely — see AI-built software.
#Why it feels impossible
Four specific difficulties, each of which has a specific counter-move.
| Difficulty | Why it stalls people | Counter-move |
|---|---|---|
| No obvious starting point | Every question leads to three more, and none of them feels like the first one | Start with the inventory, not with behaviour. What is it made of — then what talks to what |
| Unknown unknowns | You cannot list what you have not thought of, and the dangerous things are all in that set | Derive the picture from the system rather than from a conversation. Machines are unimpressed by what nobody mentioned |
| No safe way to experiment | Understanding by changing things is the natural method and is unavailable here | Static analysis first. Nothing is executed, so nothing breaks |
| Nobody wants to own it | Whoever touches it is now responsible for it, so people route around it | A written, shared picture makes it a company asset instead of one person's liability |
#The order that works
-
Establish what runs, and where
Before any code: which environments exist, what is deployed to each, what runs on a schedule, and what runs that is not in the repository at all.
The last one catches people. Cron on a server, a Lambda created in a console, a script on a laptop, a spreadsheet somebody maintains by hand.
-
Get an inventory of the parts
Every component, with a type and a readable purpose. This is the flattest possible artefact and it is the one that makes every subsequent conversation possible.
It is also the moment most owners find something they did not know existed.
-
Map the outside edges
What external services does it need? What talks to it from outside? Whose account is each of those in? These are the dependencies that fail on somebody else's schedule.
-
Follow the data
Where does customer data live, how does it get there, where does it go? This is where regulatory obligation, business risk and the parts you must not break all overlap.
-
Write down what could not be established
Explicitly, with priorities. This list is the actual output of the exercise — the map is what makes the list credible.
-
Work the list down, and only then change things
Each answered question is a small piece of control recovered. Do this before any restructuring, and the restructuring becomes a normal engineering task instead of an act of faith.
#What to stop doing
Reading the code, file by file, hoping for a picture to emerge.
Instead Derive the structure first and read selectively. A month of reading produces a worse map than one analysis, and produces it in the reader's head where nobody else can use it.
Cleaning up as you go.
Instead Change nothing until the picture exists. Tidying code you do not understand is how a system that worked stops working, and the change will not be the suspect because it “did not do anything”.
Waiting for a documentation project.
Instead Documentation projects on legacy systems almost never finish, because they are unbounded and nobody can tell how much is left. A derived picture is bounded and completes.
Treating comments and READMEs as facts.
Instead Treat them as declarations — worth recording, not the same as observed behaviour. A README describing a system as it was in 2021 is not neutral; it is actively misleading.
Deciding to rewrite before you can describe it.
Instead Describe it first. The description usually changes the decision, and always changes the estimate.
#Finding the risky parts
Not all of a legacy system is equally dangerous, and knowing which parts are is most of the value.
Four signals, each of which is visible from a structural picture rather than from reading:
- Concentration. One component that many others depend on. Changing it is expensive; not being able to change it is worse.
- Unknowns clustered together. Six open questions about one subsystem is a different situation from six spread evenly. Clustering marks the part nobody has ever understood.
- An external edge with no confirmed behaviour. An outbound integration whose retry, timeout and failure handling could not be established is a live business risk, not a technical debt item.
- A gap between declared and observed. Where a document or comment says one thing and the code does another, that discrepancy is where somebody's mental model is already wrong.
#The rewrite question
Somebody will propose rewriting it. That proposal is sometimes correct. It is almost never possible to evaluate at the moment it is made, because the argument for it usually rests on the same absence of understanding that created the problem.
Two things change the conversation:
- An inventory. "Rewrite it" means something different when the thing has six components than when it has thirty-one, four of which nobody can explain.
- The unknowns list. Every unresolved question is a behaviour the rewrite might silently drop. That list is the most accurate risk register a rewrite proposal can have — and it is the reason failed rewrites fail.
A rewrite decided after both exist is an engineering decision. One decided before is a bet on somebody's memory.
#Where 1ADK helps, and where it does not
Where it helps
- The structural picture, derived rather than remembered.
- Open questions written down and prioritised instead of feared.
- Evidence, so a new team can check rather than trust.
- The declared-versus-observed gap made visible.
- A record of what changes as you work on it.
Where it does not
- Explaining why it is like this. Nothing can recover that from code.
- Telling you whether to rewrite. It gives you the inputs, not the decision.
- Judging code quality or finding vulnerabilities.
- Runtime behaviour — nothing is executed.
- Anything configured only outside the repository, beyond flagging it as unknown.
Questions people actually ask
Age has almost nothing to do with it. A system written eight months ago by contractors who have gone is legacy; a fifteen-year-old system with three engineers who understand it thoroughly is not. The determining property is whether anybody available can answer questions about it.
Not until you can describe it. Almost every failed rewrite began before anybody had established what the existing system actually did — and the parts that get missed are always the ones nobody remembered, which is the definition of the problem you started with.
No. Structure and behaviour are properties of the code and are recoverable by anybody with access to it. What is not recoverable is reasoning. Practically, that means you will end up with a good picture of what the system does and a permanent list of decisions nobody can explain — which is a workable position, and far better than the one you are in now.
Getting a structural picture is hours to days. Getting to the point where a team is comfortable changing the risky parts is months. The value of doing the first step properly is that it tells you which parts are the risky ones, instead of finding out by changing one.