Microservices Boundaries: Find the Transaction and Ownership Seams

Evaluate service boundaries through business invariants, change coupling and recovery ownership. Includes an order-flow worksheet and an extraction decision record.

A service boundary earns its cost when it lets a team change, operate or scale a capability without repeatedly coordinating the same decisions across the system. Moving code behind a network call does not establish that independence.

Start with a business operation that is difficult to change. Find the facts it must keep consistent, the data it owns, its failure consequences and the people accountable for recovery. Then compare keeping it inside a module with extracting a service. This guide is for that boundary decision, not for choosing a transport or reaching a target service count.

Collect evidence before drawing the new boxes

Repeated joint releases, cross-service writes and long synchronous call chains are reasons to investigate. None proves that a boundary is wrong by itself. A regulatory change may legitimately affect several capabilities; a shared identity service may be an intentional dependency.

Inspect representative changes and incidents. Record which components changed together and why. Distinguish a shared business rule from an incidental dependency, such as a logging-library upgrade. A count of files changed cannot make that distinction for you.

| Observation | Question to investigate | | --- | --- | | Two services change in the same releases | Is one business rule split between them, or are contracts unnecessarily rigid? | | A request waits on several services | Which answers must be current, and which could be prepared or omitted? | | Multiple services write the same tables | Who can enforce invariants and authorize schema changes? | | Teams negotiate every deployment | Is ownership unclear, or are incompatible interfaces forcing coordination? | | One workload needs different scaling | Can a worker or module be isolated without moving its data authority? |

Use traces, deployment records and actual change histories to test the answers. Interview the engineer who handles an interrupted operation as well as the person who designed its happy path.

Separate a domain model from a deployment unit

A bounded context defines where a model and its terms have a particular meaning. Sales may treat a customer as an account with a purchasing relationship; support may care about entitlement and ticket history. They can share a stable identifier without sharing every field or lifecycle rule.

Microsoft's domain-analysis guidance describes using business capabilities and context boundaries to find candidate services. A bounded context is a modeling tool, not a command to create another deployment.

Keep authority explicit when copying data. Support might receive an entitlement projection from the subscription owner, with a known freshness limit. It should not quietly become a second writer of subscription status. A projection also needs correction, deletion and replay behavior.

Some boundaries remain modules in one process. Others justify independent services because of workload isolation, security constraints or separate change patterns. The choice should explain what becomes easier and which operational responsibilities it adds.

Put the invariant beside its transaction

A monolith does not guarantee ACID transactions. A service can use a local database transaction, and several services can participate in a coordinated transaction where the technology and availability tradeoffs permit it. Consistency follows the actual storage and transaction design, not the architecture label.

Write invariants in business language. “Available stock cannot go below zero” is more useful than “Inventory owns a table.” Identify the transaction that enforces the rule and every path that can write the relevant state.

For a fictional order system, use this worksheet:

| Rule or fact | Authority and boundary decision | | --- | --- | | Available units cannot be over-reserved | Inventory atomically checks and records a reservation | | An order is not confirmed before required approvals | Orders owns the confirmation transition and checks recorded evidence | | A payment authorization has a known provider outcome | Payments records the attempt and reconciles uncertain responses | | A customer sees order progress | A read view may lag, with pending states made explicit | | Shipment follows fulfillment approval | Fulfillment owns the release decision and its irreversible effects |

These are candidate responsibilities, not a universal commerce architecture. If a product requires several facts to change atomically and cannot tolerate an intermediate state, moving them into separate stores may create an unacceptable problem. Keep them within one transaction boundary, change the business workflow, or evaluate coordination explicitly.

The database-per-service guide covers storage ownership. Avoid deciding database topology before identifying these rules.

Work through an interrupted order

Suppose Orders creates a pending order, Inventory reserves units and Payments requests authorization. Orders confirms only after receiving the required results. Each operation has a stable identifier so retries can refer to the same intended action.

If the payment request times out, the outcome is unknown. Do not assume payment failed and immediately start a second authorization with a new identifier. Query or reconcile the provider's recorded outcome using the supported contract. Keep the order pending while the uncertainty is resolved.

If payment is definitively declined, the workflow requests reservation release. That compensating action can also fail. The order needs a durable recovery state, an owner and a way to retry or intervene without releasing the wrong reservation.

A saga coordinates local transactions and compensating work. Microsoft's saga pattern guidance documents the lack of cross-service isolation and the possibility of failed compensation. Compensation is a new business action, not a time machine: it may incur fees or leave an audit trail.

Test competing cancellation and confirmation requests. Use the recorded workflow state and version checks to prevent an old message from reopening an already resolved order. Record what happens when a reservation expires while payment reconciliation is still pending.

If these recovery states are harder to operate than the original coupling, that is evidence against this extraction. A diagram of successful messages alone is not enough to approve it.

Evaluate ownership without copying the organization chart

Name an accountable service owner for contracts, deployment, incidents and data changes. Several teams can contribute through that owner's process. A shared operational responsibility does not automatically justify splitting the service.

Ask whether contributors change different concepts or repeatedly negotiate the same invariant. In the first case, a module or context boundary may help. In the second, splitting could add remote coordination without reducing shared decisions.

Ownership also needs capacity. An independently deployed service creates patching, dependency, access, telemetry and recovery work. A team that cannot maintain that work has gained a deployment unit without gaining autonomy.

Review both architecture and team responsibilities when a boundary causes persistent friction. Reorganizing the code to match a temporary reporting structure can make the next reorganization expensive.

Extract through a controlled migration

Splitting a service later is possible, but rarely trivial. Existing identifiers, cross-table queries, background jobs, permissions and client assumptions can make the boundary harder to move than the code suggests.

Choose a narrow operation and first enforce its interface inside the current system. Inventory all writers, including manual scripts and scheduled tasks. A proxy only controls traffic that passes through it.

During migration, define one write authority for each cohort. Backfill data with a reconciliation rule, track ongoing changes and specify how ownership transfers. Shadow reads can compare results, but must not trigger customer actions. Stop the cutover if unresolved differences affect business correctness.

Routing traffic back is safe only if the old path can understand the new state and no incompatible side effects have occurred. The legacy modernization guide develops that cutover and recovery boundary in more detail.

Retire the old path after checking consumers, retry queues, operational tools and retention obligations. Keeping two unowned write paths indefinitely leaves the migration unfinished.

Bring a decision record to the review

Complete this short record for one extraction candidate:

| Decision field | Evidence to bring | | --- | --- | | Reason to separate | A specific change, scale, isolation or ownership problem | | Invariants | Rules that must remain true and the transactions that enforce them | | Contracts | Callers, data authority, compatibility and tolerated staleness | | Failure handling | Unknown outcomes, retries, compensation and intervention owner | | Migration | All writers, reconciliation, cutover guard and recovery limit | | Operating cost | Deployment, support, observability and lifecycle responsibilities | | Decision | Keep as a module, extract, or hold for missing evidence |

Compare the proposed design with improving the module in place. Record what evidence would make you revisit the decision, rather than treating the first boundary as permanent.

For a focused review, bring the record and one representative change or incident to Ampity's system architecture design service. The useful output is an agreed boundary and implementation constraints, not a larger service inventory.