← ./writing

Two legacy migrations, one lesson: prove it, then design it

· legacy modernisation · java · migrations

I’ve worked on two legacy migrations, about ten years apart. The first, early in my career at CGI, was a Visual Basic desktop application for an investment bank that we rebuilt as a Java web application. The second, at LTIMindtree, was moving a wealth-management platform’s legacy EGL code to Java and Spring Boot.

The technologies were a decade apart, but the hard parts were the same. These are the things I’d tell anyone starting a migration.

The real spec is in the old code

Neither system came with documentation that matched what it actually did. The business rules had built up over years inside the code, in places no document ever pointed to.

On the VB project I started writing each rule down as soon as I found it, before I wrote any Java for it. That habit helped a lot. It turned “the old app does something here” into a statement the client could confirm or correct, and it meant I wasn’t relying on my memory three screens later.

EGL was harder to read, because few people still know it. So I didn’t start with Java at all. I traced each program first: what came in, what went out, and every calculation in between. Only once that flow was mapped did I write the replacement.

Prove parity before you improve anything

Legacy code always tempts you to fix it as you go. Don’t, at least not yet.

Until the new system provably behaves like the old one, every “improvement” you make is a difference you’ll have to explain later, and you won’t be able to tell a deliberate change from a bug. So:

  • On the VB migration, we ran the old and new applications side by side with the same inputs and compared the results, screen by screen and report by report. The Jasper reports had to match the old output field for field, because people downstream relied on that exact layout.
  • On the EGL migration, the numbers were financial, so “close enough” didn’t count. We tested the Java implementation against golden data: known inputs with the outputs the legacy system had produced. A calculation wasn’t done until it matched.

Parity is boring work. It’s also what earns you the right to change things later.

But don’t transliterate

That might sound like “copy the old code into Java line by line”. It isn’t, and this is the balance I’ve come to.

Behaviour should match exactly, but structure doesn’t have to. On the EGL migration we designed the REST API contracts first: clean, resource-oriented Spring Boot endpoints. Then we fitted the traced and verified logic behind them. The old programs were large and monolithic. Turning them one-to-one into Java classes would have produced a Java codebase with all of EGL’s shape and none of its familiarity.

So the rule I follow is: match the behaviour, redesign the structure. The golden-data tests make that safe. As long as the outputs still match, you’re free to organise the code properly.

Ship in slices

On the VB project we migrated and signed off one screen or module at a time instead of switching everything over at once. Each slice was small enough to compare thoroughly and sign off before moving on. That mattered, because rebuilding desktop screens as browser-based JSF pages was one of the hardest parts of the project, and a big-bang switch would have left nowhere to catch mistakes.

How they turned out

The VB application went live on Java, and the client’s confidence in the work helped our team win a project renewal. On the EGL migration, the modules I worked on were delivered during my time there. It was a multi-year programme that continued after I moved on, which is normal for a migration of that size.

The short version

  1. Write down every hidden rule as you find it.
  2. Prove parity first, with side-by-side runs or golden data.
  3. Match the behaviour, but redesign the structure.
  4. Ship in slices.

Migrations rarely fail for technical reasons. They fail because nobody can say with confidence that the new system does what the old one did. Make that provable, and the rest gets much easier.