The strangler-fig migration that saved FinCore
In 2017 we took on the biggest project of our young company's life: rebuilding the core platform of FinCore Banking. It was fifteen years old, part COBOL and part early Java, with 120,000 customers depending on it every day and a release cycle measured in weeks. Nobody wanted to touch it, which is exactly why it needed touching.
The obvious plan — build a shiny replacement, flip a switch one weekend, and pray — is also the plan that ends careers. A big-bang cutover on a live banking system is close to unthinkable. So we didn't do that. We used a strangler-fig migration, and it's still the approach we reach for when a legacy system has to change while it stays in service.
What "strangler fig" actually means
The name comes from a plant that grows around a host tree, gradually taking over until the original is gone but the shape remains. In software, you put a routing layer in front of the old system, then replace it one capability at a time. Each new piece takes over a slice of traffic. The old system keeps running until there's nothing left for it to do.
The customer never sees a cutover, because there isn't one. There are dozens of tiny ones, each small enough to reverse in minutes if it misbehaves.
How it went, in order
- We put a façade in front of the legacy core so every request could be routed old-path or new-path per feature.
- We started with the lowest-risk, highest-annoyance area — statements and read-only account views — where a bug was visible but not dangerous.
- Once a new service had run in production long enough to trust, we moved the next slice: transfers, then payments, then the harder transactional core.
- Every slice shipped behind a flag, with the old path one config change away for months after.
The goal was never to be fast. It was to make each step small enough that being wrong was survivable.
What we'd tell our 2017 selves
Instrument before you migrate. You cannot safely replace behaviour you can't observe. Weeks of the project were spent just making the old system's behaviour measurable, so we could prove the new path matched it.
Run both in parallel and compare. For the critical paths, we ran old and new side by side and diffed the outputs on real traffic before the new one served anyone. That caught edge cases no test suite would have imagined.
Resist the rewrite-everything urge. Some of that legacy code was ugly and correct. Correct beats pretty. We kept more of it, longer, than our instincts wanted.
Three years after we started, the last of the old core was switched off with almost nobody noticing — which was the entire point. FinCore is still a client today, and the approach we worked out on their platform has migrated a good few systems since.