What you will learn What legacy becomes once code is derived, and what you must protect instead.
Until now legacy meant this:
Old code nobody dares touch.
Why was it frightening? Because of the cost of understanding it.
Legacy was what you left alone because the cost of fixing exceeded the cost of leaving it.
When code is derived, that arithmetic changes.
When understanding costs more than regenerating, not understanding and rebuilding is the rational move.
graph TD
A["Old part found"] --> B{"Do intent and tests exist?"}
B -->|"yes"| C["Regenerate from the same intent"]
B -->|"no"| D["Read and fix it the old way"]
C --> E["Confirm identical behaviour via tests"]The branch is "do intent and tests exist?" Without them, fluid software does not hold.
| Before | Fluid software | |
|---|---|---|
| The asset | code | specification + tests |
| What to back up | the repository | the repository (the intent lives there) |
| What is reviewed | code changes | intent changes |
| Technical debt | bad code | thin tests |
The last row matters. The definition of technical debt changes.
Where tests are thin, that area cannot be regenerated — there is no way to confirm the regeneration is correct. So that area alone calcifies the old way.
Honestly, few organisations regenerate everything. The realistic picture:
| Area | Reality |
|---|---|
| New features | start with intent + tests. Regenerable |
| Code from the last 1–2 years | partially regenerable if tests exist |
| Old core logic | leave it alone. Do not touch |
| External integrations | contracts are fixed, so little room to regenerate |
Starting with new work is the realistic entry point. Try to convert all existing code and you never start.
When you have to change language or framework, intent and tests let you rebuild. That used to be a multi-month project.
"Same behaviour, better performance" becomes unambiguous. Tests pin the behaviour, so you can change anything within them.
Review moves to intent. Instead of reading implementation line by line, you ask "is this intent right, are the tests sufficient?"
Behaviour not written in the tests is not guaranteed. It can disappear on regeneration.
These implicit contracts break after regeneration. So in practice, before regenerating, you check "what does everything else assume about this area?"
For a small change, just fixing it is faster. Regeneration is a tool for areas that have aged into being hard to understand.
1. What was the old definition of legacy and why did it come about?
Old code nobody dares touch. The cost of understanding it — reading it, guessing why, checking what breaks — exceeded the cost of leaving it alone.
2. What does technical debt become under fluid software?
Areas with thin test coverage. Without tests there is no way to confirm a regeneration is correct, so that area alone calcifies the old way.
3. What must you watch most carefully when regenerating?
Implicit contracts not written in the tests. Response field presence, sort order, error wording — behaviour others depend on but which no test covers can break after regeneration.
That is the three concepts. Now into the actual process → Map of the four processes
To change five-year-old code: 1. read it to work out what it does (days) 2. guess why it was built this way (no documentation) 3. check what breaks when you change it (no tests) 4. eventually: "let's leave it" ← most stop hereInstead of struggling to understand the old part→ rebuild it from the intentOld technical debt: hard-to-read code, duplication, tangled dependenciesNew technical debt: areas with thin test coverageBehaviour depended on but never tested: - a certain field was always present in the response - sorting was always in the same order - the error message had specific wording