monolith split
Monolith to microservices: the first service out in 20 days
Eleven years of commits in one deployable, four hundred tables in one schema, a release train that leaves once a quarter. We find where the data actually separates, split the schema first, and cut out a service that builds, deploys and pages on its own. Rails, Django, Spring, .NET, PHP or Go: the method is the same, and the second service is faster because the hard part is behind you.
20 days for the first service, faster for the second
Two services and a library. The number of services should match the number of teams that can carry a pager for them.
One deployable
One repository, one schema, one release train, imports that go in circles.
- one deployable11 years of commits
- shared schema400+ tables
- release trainquarterly
- circular importscycles
Split
Two services with their own schemas, a library for what is shared, separate deploys.
- billingGo · own schema
- catalogueGo · own schema
- shared kernellibrary
- deploysper service
20 days for the first service, faster for the second
How the work goes
- 01days 1–4
Find the seams in the data
Query logs show which tables get read together in the same request. That is where the boundaries are, whatever the package structure claims.
- 02days 3–8
Separate the schema first
Split the tables and remove the cross-boundary joins while everything is still one deployable. Most of the risk lives in this step, and at this stage it is still reversible.
- 03days 8–15
Extract one service
The one with the fewest inbound dependencies, which is rarely the one that annoys people the most. It ships behind the same interface until running it stops being interesting.
- 04days 14–20
Give it its own pipeline
Own repository, own deploy, own on-call rota. A service whose releases still have to be coordinated with the monolith has gained you nothing, and that shows up on day fifteen rather than at the end.
What the platform does, what a person does
| What the platform does, what a person does | Who does it | Notes |
|---|---|---|
| Mapping table co-access and module coupling | Platform | From query logs and the call graph, over a period long enough to include month-end. |
| Proposing the seams | Both | The platform ranks candidates. A person checks them against your team boundaries. |
| Breaking the cross-boundary joins | Platform | Mechanical work, reviewed as pull requests, shipped in small pieces. |
| Choosing which service goes first | Engineer | Team ownership decides this more often than the code does. |
| Transaction boundaries | Engineer | Where one database transaction used to cross the seam, somebody has to decide what happens on failure. |
| CI, deploy and on-call | Both | A service without its own pipeline and rota is a module with extra network hops. |
Who cuts the seam
Dozens of migrations, more than ten years on systems built by people who have since left, and enough splits to know which ones pay off. Rails, Django, Spring, .NET, PHP and Go monoliths, schemas with four hundred tables and a decade of cross-boundary joins. The seam is never where the architecture diagram says it is, and finding the real one is most of what you are buying.
The first extraction is the test, and it is bounded: one service, its own schema, its own deploy, in production. You get a working answer for the price of one phase.
Questions we get from engineers
- How many services should we end up with?
- Fewer than the diagram in the architecture deck. Extract one, run it in production for a quarter, then decide about the next. Teams that plan twelve up front usually get four and a lot of shared database.
- Do we have to rewrite in Go?
- No. Extraction and rewriting are separate decisions, and plenty of splits stay in the original language. Where we do rewrite a service, it is because that module was going to be rewritten regardless of where it lived.
- What happens to shared code?
- It becomes a versioned library with a small surface. When the shared kernel starts growing every sprint, that is the signal your seam was in the wrong place, and it is much cheaper to move it in the third week than in year two.
- Can we do this while shipping features?
- Yes, and it will be slower for it. The step to protect is the schema separation: interleaving feature work there is how these projects stall for a year with the database half-split.
- What about the shared database everyone warns about?
- That is why the schema goes first. Two services on one schema are a distributed monolith with worse failure modes than what you started with, and it is the most common way this work gets done badly.
Start with one extraction
Size, release cadence and what is forcing the change are enough for a first answer. We come back with where the seams look like they are and what the first service would take.
An engineer replies, and the first question is normally about your release cadence.