MicroNotes X: Migrating to Microservices — Changing the Wheels While the Car Is Moving
Notes from Sam Newman’s Microservices Workshop — Bangkok 2025
MicroNotes X: Migrating to Microservices — Changing the Wheels While the Car Is Moving
Notes from Sam Newman’s Microservices Workshop — Bangkok 2025

You’ve got your testing strategy sorted. You know how to test microservices. But here’s the thing: most of us aren’t starting from scratch. We’re working with existing systems. Monoliths. Big applications that have been around for years.
Migrating from a monolith to microservices is one challenge. Doing it without stopping the world is another. That’s where the real skill comes in.
The answer isn’t a big bang rewrite. It’s not “freeze all features for six months while we rebuild.”
It’s about changing the wheels while the car is still moving.
The Realities of Migration
Before we get into the patterns, let’s talk about what you’re actually dealing with.
Priorities change. The business will change their mind. That’s not a bug, it’s a feature. If you’re focused on an outcome, and the business changes direction, you can pivot. If you’re focused on the activity (doing microservices), you might not notice you’re going the wrong way.
The world doesn’t stop. You can’t say “no features for six months while we fix our architecture.” That conversation doesn’t go well. You have to find ways to modernize while still delivering value.
You learn by doing. No plan survives first contact with production. Mike Tyson said it better: “Everybody’s got a plan until they get punched in the face.” Production is that punch. You don’t really know what’s going to happen until you start doing it.

**Small changes reduce risk. **If you make a mistake, you want it to be a small mistake. If you invest 18 months in a rewrite and it gets cancelled, that’s a lot of wasted effort. If you deliver something after three months and priorities change, you’ve still delivered value.

Sam told us about a complete replatforming project he was involved in. They spent 18 months rebuilding a financial services system. They were three weeks away from going live when they killed the project.
They needed to make the cash flow look better for a potential takeover that never actually occurred. About 40 to 50 people’s worth of work for 18 months. Just got mothballed, never used. That stuff is depressing.
If they had delivered something three months in, or six months in, they might have been able to return on that investment. That might have made the cash flow better. But they didn’t. They went all in, and when priorities changed, they had nothing to show for it.
These realities shape how you approach migration. You can’t do big bang rewrites. You can’t freeze features. You have to work incrementally. But that raises a question:
where do you actually start?
Where Do You Start?
You’ve got a monolith. You’ve identified the functional areas.
Maybe you’ve done some domain modeling. Now what?
You need to decide what to extract first. There are two forces at play:
- What’s beneficial?
- What’s easy?
You want to balance these. For your first extraction, you probably want something that’s relatively easy. You want to build confidence. You want to prove this is possible.
But you also want it to be beneficial. If it’s easy but doesn’t help you achieve your goal, there’s no point.
So you create a list of candidates. You prioritize them.
You involve your product owner in this discussion because they might have context you’re missing. The outcome you’re trying to achieve is something that’s going to be achieved for the business. So involving them in that discussion is useful because they might bring in some really interesting context that you might be missing.
You might think “Okay, well, we don’t actually think that invoicing is a massive scaling problem right now.” But they might say “We’re about to launch a big campaign around invoices, so if you could extract it, that might make our lives easier.”
Having that, involving your product owner in this prioritization exercise, can be really useful because they’re now part of the process. They understand the migration is happening. They get to be informed rather than maybe consulted. Then you pick one and start.
Once you’ve done that, you come back and look at this again and say
“What did we learn?”
Maybe the things we thought were easy are no longer easy.
Maybe the things we thought were hard aren’t as hard.
We may have learned some valuable new skills.
We may have seen some actions. We really think we can extract those notifications much easier. We thought that was going to be difficult, but we reckon we’ve got some new tools and techniques. We can make that easier. Likewise, the business might have changed their mind.
So you redo this. You go back in, you extract it once, and go back. Let’s do this exercise again. Just keep doing it. Constantly reprioritizing. Adjusting the plan once you hit production, but revisiting it. Changing your mind is not a problem. Not changing your mind often enough is.
Once you’ve picked what to extract, there’s an important question: do you extract the code first, or the data?
Extracting Code First
When you extract a microservice, you’re doing two things:
extracting code and extracting data. Do the code first.
Extracting code is easier. If it turns out to be a disaster, you haven’t done the hardest part yet. You can pull the plug. Data migration is always painful. If you start there and it fails, you’re stuck.
And when you extract the code, you learn what data you’re actually using. This helps shape the data migration later.
Sam recommends going a bit further. Create a database account for this service that only has access to read from the tables it can read from and to write to the tables it can write to. This is just the principle of least privilege security concept. But the other benefit you have of creating a database account like that is while you’re doing your work, you don’t want the developer working on the service to add more database integrations while you’re trying to get this work done.
So having that database account there becomes a hard break. Then, putting more code that reads from maybe more tables, you can move up here to make those an API that you can call into.
Now, depending on where the functionality sits, you have different patterns.
The Strangler Fig Pattern

https://dennylesmana.medium.com/what-is-the-strangler-fig-pattern-1560443b8459
This is for extracting functionality that sits at the edge of your system — things with entry points you can intercept.
How it works:
1. Deploy a proxy.
Put something between your users and your monolith that can intercept and redirect calls. This could be an API gateway, an HTTP proxy, or something else. Deploy it to production. Make sure it still works. You’ve added a network hop. That’s the only change. If that breaks things, you want to know now.
Sam mentioned working with a German investment bank that no longer exists. When they first deployed their system, they saw massive latency spikes. Service A in London was communicating with Service B in the same data center, in fact in the same rack. They were seeing, on average, 250 milliseconds overhead compared to their QA environment. It took them a week to figure out that calls between Service A and Service B in London were being routed through Luxembourg.
For reasons they never fully understood, the network configuration was routing traffic all the way to Luxembourg and back. If you find out at this point that your network absolutely sucks and adding a single network hop is going to cause all kinds of issues, you want to know that early. Then you can have those conversations about what’s going on.
2. Deploy an empty service.
Create your new microservice. It doesn’t do anything yet. It just returns a “Not Implemented” error. Deploy it to production. This is safe because no traffic is going to it. You’ve separated deployment from release. This is a crucial concept.
3. Implement the functionality.
Build out your service. Deploy it. Test it. Iterate. All while it’s not handling any real traffic. You can smoke test it. You can verify your deployment process works. You can check your logging. You can do all of this safely.
4. Release it.
When you’re ready, change your proxy configuration to route some traffic to the new service. Start small. Maybe 1% of traffic. See how it goes. If there’s a problem, flip it back. You’ve got both implementations running. You can switch between them.
5. Complete the migration.
Once you’re confident, route all traffic to the new service. Keep the old code around for a bit, just in case. Then clean it up.

https://www.geeksforgeeks.org/system-design/strangler-pattern-in-micro-services-system-design/
Key insight: You can deploy code that doesn’t work yet. As long as no one is using it, it’s safe. This opens up a whole world of possibilities.
You might be thinking this is irresponsible. But think about it: every single one of you deploys millions of lines of code with every single release that you don’t use. Think about the third-party libraries you depend on. What portion of those libraries are you actually using? 10–15%, maybe 20%. Those libraries have dependencies, transitive dependencies. What portion of that are you using? Think about all the common libraries, your runtime, your language. What portion of that are you using? An absolute tiny fraction.
So you’re doing this with every single deployment anyway. This is just a very explicit version over which you have way more fine-grained control. You don’t have any code to do it. Therefore, of course, it’s safe.
The Strangler Fig pattern works great for functionality at the edge of your system. But some functionality sits deep inside your monolith.
You can’t intercept it at the edge. For that, you need a different pattern.
Variations on the Strangler Fig pattern
The interception point doesn’t have to be HTTP. Sam worked with a real estate firm in Zurich. They had clients who would upload real estate listings via FTP. So they wrote an FTP interceptor. You can intercept calls and siphon them off.
At the Guardian, they used this technique to help switch over to a new stack. The Guardian uses static site rendering. They generate templates on the server side and send mostly rendered HTML pages. Their interception point was actually the template rendering. They used the template server’s include conditional, and based on a flag, it would either pull that content from the existing stack or pull that content from the new stack. With a single flip of a switch, they could change how those pages got rendered.
At a bank, they did this with a messaging system. They had a big queue where all the work arrived. They were slowly siphoning off jobs for different types of financial trades. They created a message filter, a queue, and put their program which works as a filter. The old system ran off one queue. They changed the name of the queues so that clients all put stuff into this queue. Their filter would look through the messages, pull the messages out, and go “Okay, that’s for the old system. That’s for the new system.” Then route them to the appropriate places.
One thing to note: if you can change the monolith, you can tend to use the Strangler Fig pattern to make smaller migratory steps. If you can’t change your system (like vendor-based software), then you have to take bigger slices. If you can change the monolith, you could expose some kind of service interface so that the new service can call that endpoint and make use of the existing functionality. That can allow you to make a small change. If you can’t change the monolith, then you’re going to have to take thicker slices of functionality with you, and that’s going to make your migration a bit more difficult.
Branch by Abstraction
**“Branch by Abstraction”** is a technique for making a large-scale change to a software system in gradual way that allows you to release the system regularly while the change is still in-progress.
Perfect for deeper internal logic.

https://martinfowler.com/bliki/BranchByAbstraction.html
How it works:
- Create an abstraction. Find all the places where you use this functionality. Extract it into an interface or abstraction. This is just refactoring. You’re not changing behavior, just structure. This could be hundreds of tiny commits. That’s fine.
- Create a new implementation. Build your new microservice. Create an implementation of that abstraction that delegates to your new service. You can check this in even if it’s not done yet. The reason is that you’re not using it. The abstraction point protects you.
- Switch over. When your new service is ready, change which implementation you use. You can do this with a feature toggle. Read the toggle value once. Switch between implementations. If something goes wrong, flip the toggle back.
- Clean up. Once you’re confident, remove the old code. Keep the abstraction if it’s still useful.

https://martinfowler.com/bliki/BranchByAbstraction.html
Benefit: You can have work in progress checked into your main branch. You can deploy it. It’s safe because the abstraction point hides it. No feature branches needed.
Once you’ve separated deployment from release, you’ve opened up a whole world of rollout strategies.
Progressive Delivery
**Canary releases** Route a small percentage of traffic to the new version. If something goes wrong, only a small group is affected. The term comes from miners using canaries to detect toxic gas. If the canary dies, you know to get out.

https://martinfowler.com/bliki/CanaryRelease.html
**Dark launches** Deploy the infrastructure, but don’t show it to users. Facebook did this with Messenger. They launched all the backend, but the UI wasn’t visible. The infrastructure was being used, just not in a way users could see.

https://martinfowler.com/bliki/DarkLaunching.html
**Blue-green deployments** Have two identical environments. One is live. Deploy to the other. Switch traffic over. If something goes wrong, switch back.

https://martinfowler.com/bliki/BlueGreenDeployment.html
Parallel runs Run both implementations. Compare the results. This is useful for critical functionality where you need to be absolutely sure the new implementation is correct. You run both, but only use one. You compare outputs. If they match, you’re good. If they don’t, you’ve found a bug.
All of these rely on that same idea: separating deployment from release. Once you can do that, you have options.
What to Remember
So what does this mean for you? Think of migration like turning a dial, not flipping a switch. You don’t go from monolith to microservices overnight. You extract one piece. You learn from it. Then you extract another.
Start with the code, not the data. Extracting code is easier. If something goes wrong, you haven’t wasted as much effort. Data migration is the hard part. Do that after you’ve proven the code extraction works.
The most important concept here is separating deployment from release. Once you can do that, everything else becomes possible. You can deploy code that doesn’t work yet. You can test in production safely. You can roll back quickly if something goes wrong.
When picking what to extract first, balance two things: what will help you achieve your goal, and what’s relatively easy to extract. For your first extraction, you probably want something that’s a bit easier. You want to build confidence. You want to prove this is possible.
Remember, the world doesn’t stop. You have to modernize while still delivering features. That’s the reality. These patterns help you do both. You’re refactoring at the architectural level. You’re changing structure without changing behavior, at least initially.
Every step should be deployable. Every step should be reversible. Every step should teach you something. That’s how you migrate safely.
“You can’t stop the car to change the wheels. But you can change them one at a time, while it’s still moving.”
That’s migration in a nutshell.
https://unsplash.com/photos/geese-flying-in-v-formation-against-blue-sky-muAm910Yu6w
***All Notes
***I: What Are Microservices? II: Forget Service Size — Focus on What Your Team Can Manage III: Microservices Aren’t About Technology — They’re About Team Autonomy IV: Nobody Cares About Your Microservices — Only the Outcome V: Information Hiding — The Discipline That Makes Microservices Work VI: Request-Response vs Event-Driven — Choosing How Services Talk VII: Distributed Transactions Are Sad — Use Sagas Instead VIII: Designing Microservices for the Edge — Lessons from Fish Farming IX: Testing Microservices — Beyond the Test Pyramid X: Migrating to Microservices — Changing the Wheels While the Car Is Moving XI: Domain-Driven Design — Speaking the Same Language XII: Breaking Apart Databases — When Data Becomes the Problem XIII: Resiliency, Observability, and the Reality of Distributed Systems
메타데이터
- post_id
- f2bfb1029c5d
- slug
- micronotes-x-migrating-to-microservices-changing-the-wheels-while-the-car-is-moving-f2bfb1029c5d
- url
- https://medium.com/@vortj/micronotes-x-migrating-to-microservices-changing-the-wheels-while-the-car-is-moving-f2bfb1029c5d
- canonical_url
- https://medium.com/@vortj/micronotes-x-migrating-to-microservices-changing-the-wheels-while-the-car-is-moving-f2bfb1029c5d
- author_url
- https://medium.com/@vortj
- status
- ok
- fetched_at
- 2026-06-12 18:14:10