Cushon
A platform heading for 250x its original scale, migrated runtime by runtime while it kept moving customers' money every night.
What was Cushon, and what did I walk into?
Cushon is a UK fintech in workplace savings and investments — pensions, ISAs, the kind of product where the numbers on the screen are somebody's actual retirement.
The platform had been built for around twenty thousand users and was heading for five million. It ran on a Yii monolith where the modules knew far too much about each other: changing the cash ledger meant touching things that had nothing to do with cash ledgers.
I joined the Scale team as a consultant to help take it apart safely.
Why couldn't they just rewrite it?
Because there were customers on it, regulators watching it, and a batch process moving real money every single night.
A rewrite means telling the business to stand still for a year while engineers rebuild what already works, and then hoping the new thing behaves identically on day one. For a platform handling pensions, "hoping" isn't a plan. The rewrite is the fantasy version of this job.
So the constraint was set before any code: whatever we did, the thing had to keep running the entire time.
How do you migrate a platform that can't stop?
You draw the seams before you cut anything.
We introduced Modular Monolith architecture with DDD and hexagonal principles inside the existing codebase. Cash Ledger, EventPublisher, EventConsumer, Balances, Returns — each became a real module with a real boundary, while still living in the same deployment. Nothing moved anywhere yet. We were just making it possible to move.
Then the modules went to Go one at a time. Each one moved on its own, proved itself in production, and only then did the next one start. There was never a single terrifying cutover date on a calendar.
The piece that made that work in practice was a PHP to Go communication framework over AWS SNS/SQS, so both runtimes could run side by side through the whole transition and talk to each other. Without that, phased migration is a nice idea you can't actually execute.
What did I actually own?
The modularisation work inside the monolith, pieces of the PHP to Go migration, and the communication layer between the two runtimes.
Outside the migration, I implemented Onfido for identity verification and led the move of transactional email to Blueshift using an abstract CDP event approach, with CloudMailin capturing copies back inside the app. I also refined the Docker and CircleCI pipeline so Go containers could be tested properly — new code deserves the same safety net as the code it replaces.
What was the hard part?
Batch processing. It ran every night, it moved money, and it could not be late.
Everything else in the migration could be scheduled, reverted, or argued about. The batch was the fixed point that the rest of the plan had to bend around. Most of the care in this project went into making sure that one thing never noticed what we were doing underneath it.
Why does this one matter?
Because it's the answer to the obvious question about someone who promises speed: does fast mean reckless?
It doesn't. Fast comes from deciding where the seams go before you start cutting. The reason a phased migration ships quickly is the same reason it's safe — every step is small enough to verify and small enough to undo.
- User growth the platform absorbed
- 250xUser growth the platform absorbed
- Interruptions to batch processing
- 0Interruptions to batch processing
- Runtimes live side by side in production
- 2Runtimes live side by side in production
- Users on the platform after the migration
- 5MUsers on the platform after the migration
This is the case I point at when someone assumes that moving fast means breaking things. It doesn't. It means deciding where the seams go before you start cutting.
Talk through your idea with someone who has built one before.
Tell me where you're up to. I'll tell you what it would take to get it live, what I'd build first, and whether I'm the right person for it.
Start with Week One