← Technical series

Systems & solution architecture

Design modules before distributing services

Work through boundaries, data ownership, and deployment choices using an illustrative booking system. Extract a service when the trade-off is justified.

A service boundary should solve a delivery or operating problem. Start by identifying responsibilities and data ownership; decide how many processes to deploy after those boundaries are clear.

Take a fictional appointment platform with availability, reservations, payments, and notifications. “Book this slot” crosses several responsibilities, but that does not mean the first release needs four independently deployed services.

Reference architecture Modules first, asynchronous delivery where needed

A reference design for the fictional booking platform. Logical module boundaries do not require separate deployments.

Modules first, asynchronous delivery where needed. The flow is described below.
Open full-size diagram Scroll the diagram on smaller screens.
Read the flow
  1. Availability, reservations and payments own their rules and data; other modules use their contracts.
  2. Within one local transaction, protect the slot, save the reservation and record a notification intent in the outbox.
  3. A worker delivers the notification separately. Delivery may repeat, so record attempts and handle duplicates. Payment-provider state and recovery remain separate.

1. Name the rules that must hold

Availability owns whether a slot can be reserved. Reservations own the booking lifecycle. Payments own provider references and payment outcomes. Notifications describe communication attempts. Write down which component may change each record and which decisions must remain consistent.

For example, two requests must not both confirm the final slot. Enforce that rule with an appropriate transaction and database constraint, rather than relying on the screen's last availability check. An email failure should not silently undo a confirmed reservation.

2. Compare deployment choices against constraints

Questions for a design review
QuestionA modular applicationSeparate services
How does the team release?One deployable unit can keep coordination simple.Independent releases need stable contracts and clear ownership.
Which rules need transactions?Local transactions can protect related changes.Cross-service work needs explicit intermediate states and recovery.
What must scale separately?Measure contention before adding a network boundary.A specific workload may justify its own capacity and failure isolation.

A modular .NET application can separate responsibilities using projects, interfaces, and controlled data access while sharing one deployment. This still requires discipline: bypassing another module's API to edit its tables makes future changes harder, even when everything runs in one process.

3. Design the asynchronous part explicitly

After a reservation is committed, a worker can send a confirmation. A transactional outbox is one possible design: store the reservation and the notification intent together, then deliver the intent separately. The worker must still handle duplicate processing, timeouts, and uncertain provider outcomes.

Carry a correlation identifier through the request, queued work, and delivery attempt. Record business state separately from transport state so an operator can tell “reservation confirmed” from “confirmation message accepted.”

4. Extract gradually when there is a reason

If notifications need independent scaling or ownership, define a contract, route a limited workload to the new component, compare outcomes, and keep a recovery path. Microsoft's Strangler Fig pattern describes incremental replacement at a routing boundary. It is an option for suitable systems, not a requirement for every modernization.

Write a one-page architecture decision

Record the problem, current load, team ownership, consistency requirements, alternatives, and evidence that would justify extraction. Include the cost of operating the proposed design and how its data changes could be recovered.

Work together

Resolve the next decision
in your system.

Discuss your current design, the risks you see, and what needs to move forward.

Discuss your requirements