The Architecture Reference

Sty distributed · Architecture Styles · Intermediate

Service-Based Architecture

The pragmatic distributed style — a separate UI, a handful of coarse-grained domain services, and a shared database, giving modularity and ACID without microservices' cost.

Sty distributed Intermediate ⏱ 5 min read Complete

🧭 Analogy

Service-based architecture is splitting one big restaurant into a few specialized stations — grill, bakery, bar — that share one pantry and one cash register. Each station works independently and can be replaced or scaled a bit, but they still draw from the same stock, so a recipe change rarely disrupts the others. It is far simpler than running a dozen separate food trucks.

Topology

Service-based is the most pragmatic distributed style — “a hybrid of microservices” without the cost. It consists of a separately deployed UI, a handful of coarse-grained, separately deployed domain services, and a (usually) shared monolithic database.

graph TD
UI["User interface<br/>(separately deployed)"] --> S1["Quoting service"]
UI --> S2["Receiving service"]
UI --> S3["Assessment service"]
S1 --> DB[("Shared database")]
S2 --> DB
S3 --> DB
  • Services deploy like a monolith (EAR/WAR/assembly — no containerization required) and usually number 4–12 (average ~7). Usually one instance per service, with more added for scale or failover.
  • The UI accesses services remotely (typically REST), often directly via a service locator pattern.
  • The shared database allows SQL joins; because there are few services, connections aren’t an issue — but schema changes can ripple.

Topology variants are very flexible: break the monolithic UI into domain UIs, split the DB into domain-scoped databases, or add an API layer (reverse proxy/gateway) for external exposure and shared cross-cutting concerns (metrics, security, auditing).

Service design and granularity

Each domain service is internally a layered architecture (API facade + business + persistence) or sub-domain-partitioned like a modular monolith. An API access facade orchestrates the request internally at the class level (e.g., place order = create order, generate ID, apply payment, update inventory) — versus microservices’ external orchestration across many services.

ACID is the headline advantage

Because services are coarse-grained, they can use ACID transactions (commit/rollback) for integrity. An expired card can roll back the entire order atomically — no sagas required. This is the best preservation of ACID among the distributed styles. The trade-off: a change to order placement requires testing and redeploying the whole coarse service (including payment).

Database partitioning

A shared DB means schema changes can ripple, so manage it deliberately:

  • Worst practice: a single shared entity library — any table change forces a change and redeploy of every service.
  • Better: logically partition the DB into data domains with federated shared libraries (e.g., common, customer, invoicing, order, tracking) so a table change only impacts services using that library. Lock common entity objects to the DB team.
graph TD
S1["Quoting service"] --> LC["lib: common"]
S1 --> LCu["lib: customer"]
S2["Invoicing service"] --> LC
S2 --> LI["lib: invoicing"]
LC --> DB[("Shared DB<br/>logical data domains")]
LCu --> DB
LI --> DB
  • Tip: make logical partitioning as fine-grained as possible while keeping well-defined data domains.

Don't redline the Ferrari

The book’s metaphor: service-based is “a Ferrari in rush-hour traffic” — don’t overbuy power you can’t use. If you reach for microservices when your data is tightly coupled and your scale is moderate, you pay for complexity you’ll never benefit from. Service-based gives modularity without the granularity pitfalls.

Characteristics

CharacteristicRating
PartitioningDomain
Overall costModerate (low for a distributed style)
Agility / Testability / Deployability4 / 5
Fault tolerance / Availability4 / 5
Scalability3 / 5
Elasticity2 / 5
SimplicityHigh (for a distributed style)

No five-star ratings, but many fours: small domain scope yields fast change, good test coverage, and frequent low-risk deploys. Self-contained services with little interservice communication give good fault tolerance — one service down doesn’t affect the others. Coarse granularity costs scalability and elasticity (more functionality replicates per instance). Quanta = 1 unless you federate both the UI and the database.

When to use it

  • You want modularity without microservices’ cost and complexity — a natural fit for DDD.
  • Your data is tightly coupled and can’t easily split into many schemas (if so, choose this over microservices).
  • You need to preserve ACID within coarse domain services.

When to avoid it

  • You need function-level scalability and elasticity.
  • You need hundreds of fine-grained, independently deployable units.
  • Every service must own a fully isolated database.

See also

When to use it — and when not

✅ Reach for it when

  • You want modularity and independent deployability without microservices' cost and complexity.
  • Your data is tightly coupled and cannot easily be split into many schemas.
  • You need to preserve ACID transactions within coarse-grained domain services.

⛔ Think twice when

  • You need function-level scalability and elasticity — coarse services replicate too much.
  • You need hundreds of independently deployable, fine-grained units.
  • Every service must own a fully isolated database.

Check your understanding

Score: 0 / 4

1. What is the typical topology of a service-based architecture?

Service-based is a distributed macro-layered style with a separately deployed UI, a handful (avg ~7) of coarse domain services, and a shared monolithic database.

2. What advantage does service-based have over microservices regarding transactions?

Because services are coarse-grained, a request like 'place order' is orchestrated internally at the class level inside one service, allowing atomic commit/rollback — microservices must fall back to BASE/sagas.

3. How does an API access facade orchestrate a request in service-based?

Unlike microservices' external orchestration across services, service-based orchestrates the workflow inside the coarse service at the class level.

4. How do you control the blast radius of a shared-database schema change?

A single shared entity library means any table change forces every service to redeploy; federated libraries (common, customer, order, etc.) limit a change to services using that library.

Comments

Sign in with GitHub to join the discussion.