From Monolith to Microservices: A Practical Guide
By Carlos Diaz · October 10, 2024 · 3 min read
The technical work of extracting a microservice is usually the easy part. The hard part is that most teams try to solve an organizational problem - a growing engineering team stepping on each other's changes - with a purely technical solution, and end up with a distributed monolith that has all the operational complexity of microservices and none of the independence benefits.
Domain-driven design gives you the vocabulary to find real boundaries, but the practical exercise is more mundane: map out which tables get read and written together, which business capabilities change for the same reasons, and where your team's org chart already creates natural seams. Conway's Law is not a nice observation, it is a constraint - a service boundary that cuts across a single team's daily work will fight you every day, while one that matches how the team is already organized will feel almost invisible once it is in place.
The strangler fig pattern is the right extraction mechanism because it lets you validate the boundary before committing to it. Route a slice of traffic to the new service, keep the old code path as a fallback, and only remove the monolith's implementation once the new service has proven itself under real production load. This also means you never have a multi-week period where the system is in a half-migrated, doubly fragile state - it is either fully on the old path or fully on the new one for any given request.
The part that gets underestimated every time is operations. A single database transaction that enforced consistency in the monolith becomes a distributed transaction problem, or more realistically, an eventual-consistency problem that your application code now has to reason about explicitly. Distributed tracing stops being a nice-to-have the moment a single user request touches four services, because without it, a production incident becomes a scavenger hunt through four sets of logs instead of one.
The test I use before extracting any service is simple: can I name the specific, measurable benefit - independent deployability, the ability to scale one capability separately, a team no longer blocked by another team's release cycle? If the answer is 'better architecture' in the abstract, the boundary is not ready yet.
Key Takeaways
- Microservices usually solve an organizational problem first, a technical one second.
- Conway's Law is a constraint: service boundaries should match how the team is already organized.
- The strangler fig pattern lets you validate a boundary under real traffic before committing to it.
- Distributed tracing becomes mandatory the moment a single request touches multiple services.
- Every extraction needs a concrete, measurable benefit - not just architectural purity.

