Name the independence you need
A SaaS team wants report generation to scale without adding more web servers. That requirement justifies separating execution capacity. It does not yet justify giving reporting its own database, API versioning policy and on-call responsibility.
Begin by naming the independence the change must buy. Is the team trying to deploy a business capability without coordinating every release? Contain a failing workload? Assign a different owner? Scale a CPU-heavy worker? These are different architectural jobs. Several can be addressed inside a modular application or by running another process from the same codebase.
For the fictional reporting product used here, the first proposal is a separately scalable worker that consumes an explicit export-job contract while the core application retains job acceptance and tenant authorization. Service extraction becomes a later option if independent ownership and release requirements emerge. The worksheet records what evidence would change that decision.
Put the transaction boundary on the diagram
Our example contains workspace administration, report definitions and export execution. Accepting an export requires a valid tenant context and a committed job record. Rendering the file can happen later. This gives the team an execution boundary without requiring every participant in request acceptance to become a network service.
| Responsibility | Proposed initial owner | Consistency requirement |
|---|---|---|
| Workspace membership and permissions | Core application | Evaluate current access at protected operations |
| Report definition and accepted input reference | Core application | Bind the job to the intended definition or snapshot |
| Job acceptance and visible status | Core application | Commit accepted work before acknowledging it |
| File rendering | Export worker process | Consume a defined job input and report a terminal outcome |
| Result access | Core application | Check current access before exposing the file |
If the renderer reads arbitrary core tables, calls internal helper functions through an unrestricted package dependency and writes status fields directly, the proposed boundary is mostly decorative. It may still provide useful CPU separation, but the team has not established an independently evolvable service contract. Write the permitted interface first. An export job should identify the tenant, the input version or snapshot and the requested output. The completion interface should identify the job and its outcome. Decide how schema changes remain compatible with queued work. A job created by yesterday's application can be consumed by today's worker, so even a shared repository needs a compatibility policy at that boundary.
Pay for the new failure modes explicitly
A function call becoming a remote call changes its failure behavior. The caller can time out while the callee continues. A response can be lost after a mutation succeeds. A rolling deployment can put different contract versions on either side. The extraction proposal must show where those cases are handled.
Martin Fowler's Microservice Premium describes the additional deployment, monitoring and distributed-data work that accompanies service separation. His Monolith First argues for learning useful boundaries before making them expensive to move, while acknowledging that this route also requires modular discipline. These are architectural arguments, not a benchmark establishing a universal team-size threshold.
For the reporting example, a worker crash should leave a job inspectable and recoverable under a defined ownership policy. A storage outage should produce an observable processing outcome without disabling workspace administration. A new report-definition field should not require an emergency synchronized release just to keep old queued jobs readable. Each statement needs a concrete implementation and a check against the actual deployment process.
The asynchronous job contract provides a worked starting point for status and cancellation semantics. The deadline calculation covers time accounting for remote calls. Extracting a service does not remove those responsibilities from the product team.
Compare three candidate shapes
A module boundary, a process boundary and a service boundary are not interchangeable. The terminology varies across organizations, so the table defines the practical distinctions used in this decision.
| Shape | What can change independently | Obligations that remain |
|---|---|---|
| Module in one application process | Internal implementation behind a controlled interface | Shared process resources and a coordinated application release |
| Separate worker process with shared product ownership | Worker capacity and, if packaging permits, worker rollout | Job compatibility, ownership recovery and explicit shared-data rules |
| Independently owned service | Its contract implementation, release and resources within compatibility rules | Network failures, service operations, data ownership and consumer migration |
The middle option is useful when the immediate problem is execution capacity. It can keep one product team responsible for the whole workflow while allowing worker concurrency to change. It still needs deployment and failure testing. A process launched separately is not automatically operationally independent.
The third option becomes more persuasive when reporting has a stable contract, a distinct owner and a release cadence that repeatedly conflicts with the core application's. It becomes less persuasive when ordinary feature work still requires coordinated changes to both databases and both APIs.
Splitting repositories does not make that coordination disappear.
Fill the boundary worksheet with evidence
Download the service-boundary worksheet and decision comparison. They contain proposed questions and the reporting example's provisional decision. Empty evidence fields are intentional: there are no invented incident counts, deployment frequencies or cost estimates behind this recommendation.
Review the candidate using these questions:
- Which measured constraint does separation remove, and how will the team detect that improvement?
- Which records have one authoritative owner after the change, and which cross-boundary transaction must be redesigned?
- Can the new unit deploy while existing producers and consumers remain compatible?
- What happens when its request, acknowledgment or completion notification is lost?
- Who owns its alerts, restoration procedure and consumer support?
Treat an unanswered ownership question as a design gap rather than assigning a reassuring score. A candidate with an independent deployment pipeline but shared, uncontrolled writes to the same business records still has a coupled data boundary. Conversely, a module with a clear owner and strict interfaces may already deliver much of the organizational clarity the team needs.
Keep workload evidence separate from architectural judgment. Queue age, worker utilization and web-request latency can establish whether rendering competes with interactive work. They cannot by themselves prove that a separate database or a new organizational team is necessary.
Make extraction a reversible sequence
First constrain the module's dependencies and introduce the explicit job interface. Then run the worker as a separately controlled process and check compatibility with queued work. Measure whether the original capacity or release constraint improves. Only after that evidence exists should the team decide whether separate service ownership and storage solve an additional problem.
Data separation requires its own migration plan. Shared-table access cannot be removed merely by changing an import statement. Define the authoritative owner, migrate consumers and verify that old write paths no longer operate before retiring them. The expand-contract migration walkthrough explains how compatibility can survive a staged schema change.
Revisit the provisional decision if report execution acquires a distinct business lifecycle, if multiple products need the same stable capability or if a shared release repeatedly blocks independently owned work. Keep the evidence with the decision record. The reason to extract is an independence requirement the team can demonstrate, not the number of services on the architecture diagram.
Sources
Documentation checked .
