Legacy Java Modernisation

Modernise the monolith without stopping the business.

The failure mode in legacy modernisation isn't the migration itself — it's the freeze. Teams stop shipping features for a year to “do the rewrite”, and the business stalls while engineering pays down technical debt nobody outside the team can see.

We use strangler-fig decomposition instead: route by route, the old monolith keeps serving traffic while new capabilities peel off into services, so the business never has to choose between modernising and shipping.

01  In practice

What this looks like in practice

01

An inventory of the monolith's actual routes and their traffic/risk profile, not a guess.

02

A strangler-fig routing layer so old and new code paths coexist safely.

03

Java 8/11 → 21 upgrade path sequenced around your actual dependency graph, not “upgrade everything at once and pray”.

04

Data ownership boundaries drawn before code is split, so you don't end up with two services fighting over one table.

05

Regression coverage on the routes being extracted, before they're extracted.

02  Deliverables

What you get

  • Migration sequencing plan
  • Strangler-fig routing implementation
  • Before/after performance comparison
  • Rollback plan per phase
03  Proof

Modernisation, in production

The order-processing platform has been in continuous evolution under this approach for 2+ years. Ask us about the modernisation work specifically if you want architecture-level detail beyond what's in the public case study.

04  FAQ

Legacy Java modernisation — frequently asked questions

What is the strangler-fig pattern?
A routing layer sits in front of the monolith and decides, per route, whether a request goes to the old code or to a new service. You extract one capability at a time behind that facade, and the monolith keeps serving everything you have not moved yet. The name comes from the strangler fig, which grows around a host tree and gradually replaces it. The practical benefit is that there is never a big-bang cutover to get wrong.
Do we have to stop shipping features during modernisation?
No, and that is the whole point of working this way. The failure mode in legacy modernisation is not the migration itself — it is the freeze. Teams stop shipping for a year to do the rewrite, and the business stalls while engineering pays down debt nobody outside the team can see. Route-by-route decomposition means the old system keeps serving traffic while new capabilities peel off, so you never have to choose between modernising and shipping.
Why upgrade to Java 21 specifically?
Java 21 is a long-term support release, which matters more than any single feature: it is the version you can stay on. Java 8 and 11 are increasingly expensive to stay on — security patching, library support and hiring all get harder. We sequence the upgrade around your actual dependency graph rather than upgrading everything at once, so the blockers surface one at a time and each step is independently releasable.
How do you decide what to extract first?
By traffic and risk profile, from the route inventory rather than from intuition. The best first extraction is usually a capability with clear data ownership, meaningful traffic and low blast radius — enough to prove the routing layer and the deployment path work, without betting the business on the first attempt. Tightly coupled, high-risk areas come later, once the pattern is established.
What happens if an extraction goes wrong?
You route back. Every phase ships with a rollback plan, and because the old code path still exists behind the routing layer, reverting is a routing change rather than a redeploy-and-pray. That is why we draw data ownership boundaries before splitting code — the hard part of rolling back is usually data, not traffic.

Talk to an architect about your monolith.

Tell us what the monolith does and what it's blocking — we'll map a sequencing plan that doesn't freeze delivery.

Talk to an architect