Back home

Modernizing old code requires archeology first

Before putting AI into old projects, separate the era layer, build layer and test layer

Modernizing old code requires archeology first

The most difficult thing about old code is never the old syntax, but the old times. A project is stuffed with build.xml, old JDK, old testing framework, and old packaging methods. On the surface, it looks like several piles of files, but it is actually layers of historical assumptions stacked on top of each other. The code itself is only the outermost layer. What really blocks delivery is often whether these assumptions are still there, whether they can be reproduced, and whether the old behavior will be lost after changes.

This is why “archaeology” precedes “transformation”. Look at the build file first, then the dependencies, then the running environment, then the tests. The order cannot be reversed. The build.xml is still there, but the pom.xml does not exist. Such signals are enough to indicate that the project is living in the Ant era; whether the code can be compiled, whether the tests can run, and whether the product can be rebuilt are the first evidence. The most useful part of the model here is not to immediately write new code for the old code, but to identify these evidences from a pile of fragments.

The environment must also be pinned first. Old code often comes with old JVMs, old containers, and old architectural assumptions. Throw it directly onto today’s machines, especially in a cross-architecture environment, and it is easy to mix in new noise when problems occur: is the code inherently broken, or is it emulation, mirroring, and tool chains that are causing trouble? If you can’t even achieve “the same code can be stably reproduced in the same environment” at this stage, all subsequent modernization actions will be just guesswork.

The value of AI in this step is clear: it can help with character-level and structure-level translation. Converting Ant to Gradle, converting old build scripts into a now maintainable form, moving a bunch of repetitive XML and boilerplate to a clearer location are all things that are good candidates for leaving to models. It’s fast, willing to try again and again, and not too trivial. But it is not suitable for refereeing. Which warnings can be kept first, which tests are actually lying, which modules should be cut off first, and which classes should only be packaged and adapted. In the end, it still has to be decided by people.

Testing is the easiest way to fool people. Passing the tests in the old project does not mean that the system is understood, it may only mean that some old behaviors are just wrapped in the current environment. That “all green” feeling is dangerous because it often masks a larger problem: what the test verifies is the implementation details of a certain era, not the business semantics that need to be preserved now. If you really want to reform, the first thing to do is to take these tests out of the “decorative sense of security” and re-judge what they are protecting.

Therefore, the most stable way for this type of project is usually not to rewrite it in one go, but to first create a time capsule to fix the old environment, old behaviors, and old dependencies, and then remove it along the narrowest cracks. First make the system reproducible, then hand over the repetitive work to AI for translation, and then peel off the boundaries layer by layer. If the order is out of order, the model will accelerate the old project and push it into deeper chaos; if the order is correct, the model will be like a truly useful archaeological assistant, responsible for moving bricks, cleaning dust, and comparing evidence, freeing people from dirty work and leaving judgment in their hands.