SyncTrix logoSyncTrix
All articles
Platform11 min read

Service boundaries that hold: splitting by data ownership, not by noun

Most microservice pain comes from boundaries drawn in the wrong place. Here's how to find seams that survive, and the signals that you split too early.

By Lena Voss
Service boundaries that hold: splitting by data ownership, not by noun

Microservices fail most often not because distribution is hard but because the boundaries were drawn in the wrong place. Services split by noun - a user service, an order service, a product service - look tidy on a diagram and produce a system where every feature touches four services and no team can ship independently. The boundary is the whole decision. Getting it right is central to our digital engineering work.

01The distributed monolith

The characteristic failure is a set of services that must be deployed together, share a database, and cannot be changed independently. You have taken on every cost of distribution - network calls, partial failure, distributed debugging, deployment coordination - and retained every constraint of a monolith.

The diagnostic is simple: can each service be deployed independently, without coordinating with another team, without a synchronised release? If not, the boundaries are not real, and adding more services will make it worse rather than better.

  • Services that must deploy together are one service in disguise.
  • Shared database tables across services means shared ownership, not a boundary.
  • A change requiring simultaneous edits in three repos is a boundary failure.
  • If teams block on each other constantly, the split does not match the work.

02Split by data ownership

The most reliable heuristic is that a service owns its data exclusively. No other service reads its tables directly; access happens through its interface. If two services need write access to the same table, they are one service and the boundary is in the wrong place.

This forces the boundary to follow genuine cohesion. Data that changes together, is validated together, and must be transactionally consistent belongs in one service. When a proposed split would require a distributed transaction to maintain an invariant, that is strong evidence the split is wrong - not a signal to reach for a saga.

03Follow the change patterns, not the diagram

The strongest evidence for where boundaries belong is in your commit history. Which parts of the codebase change together? Those are cohesive and belong on the same side of a boundary. Which parts have not changed together in a year? Those are candidates for separation.

This empirical approach outperforms domain modelling done in a room, because it reflects how the system actually evolves rather than how someone imagined it would. It also explains why extracting services from a working monolith produces better boundaries than designing them upfront - you have the evidence.

SignalSuggestsAction
Modules always change togetherSame bounded contextKeep together
Independent release cadenceGenuine separationCandidate for extraction
Different scaling profileDistinct resource needsCandidate for extraction
Shared write access to tablesFalse boundaryMerge or redesign ownership
Chatty synchronous callsBoundary cuts a cohesive flowReconsider the split
Different compliance scopeReal isolation requirementStrong case for separation
Boundary signals

04Start with a modular monolith

For most teams the right sequence is a well-structured monolith with enforced internal module boundaries, extracting services only where a specific need justifies it. Modules with explicit interfaces and no cross-module database access give you most of the organisational benefit without network partitions.

Crucially, this preserves the ability to be wrong. Moving a boundary within a monolith is a refactor. Moving it between services is a migration involving data, contracts, deployment and probably downtime. Since early boundary decisions are made with the least information you will ever have, keeping them cheap to change is worth a great deal.

05Legitimate reasons to extract

There are genuinely good reasons, and they share a property: something specific about the component differs from the rest of the system in a way that the shared deployment constrains.

Independent scaling when one component's resource profile differs sharply. Team autonomy when a distinct team needs to ship without coordination. Technology fit when a component genuinely needs a different runtime. Fault isolation when a component's failure must not affect the core. Compliance isolation when data handling requirements differ materially. Notice that 'we are adopting microservices' is not on that list - each extraction should have a specific reason that would be visible if you did not do it.

  • Extract for a specific, articulable constraint - not as a default.
  • Prove the boundary as a module before making it a network hop.
  • Move the data with the service; shared databases defeat the purpose.
  • Expect to get some boundaries wrong and plan for merging them back.

Topics

microservicesservice boundariesdomain driven designdistributed monolithbounded contextservice decomposition

Lena Voss

Lead Architect · SyncTrix

Writes about the engineering decisions behind production systems - architecture, delivery and the trade-offs that only show up at scale.

Building something like this?

SyncTrix engineers AI, SaaS, platform and cloud systems for enterprises and high-growth teams. Tell us what you're shipping and we'll scope it with you.