Case study - monolith to microservices
Three people finished a two-year-stalled lending migration in two months
Smava, one of Germany's largest consumer-loan marketplaces, tried twice to move a single loan-review workflow out of a monolith shared by ~10 teams into its own microservice — and failed twice. Here's the order of operations that finally worked.
What had already been tried
Two teams. Two years. Two dead ends.
The first attempt cleaned up the domain before the team understood all the production rules. The second got further, but cutover still exposed bugs users could see.
Attempt one
Refactored the domain first
>10x slower
Cleaned up the data model before touching infrastructure. The new service was correct — and an order of magnitude slower than the system it replaced.
Attempt two
Rewrote it, then tried to cut over
Rollbacks
Bugs only surfaced in production. Every cutover attempt was reverted, and the fix on the table was a full frontend rewrite.
The diagnosis
Both teams tried to improve the system before they understood it.
Ten teams had spent years adding one-off business rules to this workflow — rate exceptions, regional overrides, edge cases nobody wrote down. Rewriting the domain model first meant rewriting rules nobody could fully enumerate.
The insight that unstuck it: don't try to know the rules in advance. Build a new service that mimics the old one exactly, then let production traffic itself tell you where the two disagree.
The fix
Match the old API exactly. Clean up later.
No frontend changes, ever. The new microservice had to be a silent, drop-in double for the workflow still living inside the monolith — then the internals could get prettier in peace.
01
Copy the request
Every real request still goes to the monolith. A copy is mirrored to the new service.
02
Run it for real
The new service processes the mirrored copy end-to-end — same inputs, same rules it knows about.
03
Diff the two answers
Old response vs. new response, compared automatically. The customer only ever sees the old one.
04
Fix the gap
Every difference is a missing business rule. Patch the new service, not the old one.
05
Repeat, then cut over
Reads first, queue by queue, then writes — until a queue runs with zero diffs, then cut over for real.
The core mechanism
Shadow-testing turned the migration into a comparison loop.
The monolith keeps serving every live request — and quietly checks the new service against itself in the background.
The outcome
Two months. Three people. Zero drama.
“The important part was that our users never became the test plan. We proved the new service against the old behaviour in production before the final switch — so cutover was a formality, not a gamble.”
- Engineering lead, Smava
If this sounds familiar
You may not need a bigger migration team.
You may need a smaller proof: API compatibility first, shadow traffic second, cutover only when the differences stop.
- 01A migration off the monolith has already failed once or twice.
- 02The next plan keeps expanding into UI, data, and domain redesign.
- 03Tests pass, but production keeps revealing missing edge cases.
- 04Cutover depends on users finding fewer bugs than last time.
- 05The monolith changes faster than the migration team can isolate it.
Stuck on a legacy migration of your own?
We take on the migrations other teams have already tried and stalled on. Shadow-testing works for more than lending — API-compatible cutover paths, comparison loops, and the engineering to replace risky monolith workflows safely.
Plan a migration audit