Chapter 14: Service-Based Architecture
fsa architecture-styles service-based-architecture
Status: Notes complete
Overview
Service-based architecture is a distributed architecture style that sits between a monolith and microservices on the complexity/granularity spectrum. It partitions the system into a relatively small number of coarse-grained, domain-scoped services (typically 4–12 per system), each of which handles all the business logic for an entire business domain. Services share a common database (often a single monolithic database, though partitioning is possible), and a user interface layer communicates with the services directly or via an API gateway. Service-based architecture is considered the most pragmatic distributed style: it delivers most of microservices’ agility benefits with far less operational complexity.
Topology
┌────────────────────────────────────────────────────────────┐
│ USER INTERFACE │
│ (Monolithic SPA / Modular UI / Micro-frontend) │
└─────────────────────┬──────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ API GATEWAY (optional) │
│ Auth / Rate Limiting / Routing / Aggregation │
└────┬──────────────┬──────────────┬───────────────┬─────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐
│ Service │ │ Service │ │ Service │ │ Service │
│ (User │ │ (Order / │ │(Inventory│ │ (Notif. / │
│ Mgmt) │ │ Checkout)│ │/Catalog) │ │ Reporting) │
└────┬────┘ └────┬─────┘ └────┬─────┘ └──────┬───────┘
│ │ │ │
└──────────────┴──────────────┴───────────────┘
│
┌───────────────▼────────────────┐
│ SHARED DATABASE │
│ (or domain-partitioned / per- │
│ service DB — see topologies) │
└─────────────────────────────────┘
The architecture has three layers: the UI, an optional API gateway, and a set of coarse-grained domain services, all sharing persistent storage. Services are typically deployed as separately runnable processes (not functions, not containers-per-endpoint like microservices).
Style Specifics
Service Design and Granularity
Services in service-based architecture are domain-scoped, not function-scoped. Each service owns all the business logic for a complete business domain:
| Dimension | Service-Based | Microservices | Monolith |
|---|---|---|---|
| Granularity | Coarse (domain) | Fine (subdomain/function) | N/A (one unit) |
| Typical count | 4–12 per system | Dozens to hundreds | 1 |
| Team alignment | 1–3 services per team | 1 service per team (often) | Whole team on one codebase |
| Business logic ownership | Full domain in one service | Distributed across services | All in one place |
| Data isolation | Optional (often shared DB) | Required (per-service DB) | One DB |
The 4–12 service count guideline is significant: it’s enough to get team autonomy and independent deployability, but few enough to avoid the operational complexity of managing hundreds of microservices. If a system has 2 services, it’s effectively a modular monolith. If it has 50, it’s drifting toward microservices.
User Interface Options
Three approaches to the UI layer:
| UI Approach | Description | When to Use |
|---|---|---|
| Monolithic SPA | Single frontend application (React/Angular/Vue) talks to all services via API gateway | Simplest; good for small teams; UI team is separate |
| Modular UI | Single application divided into domain-aligned modules; each module owned by its service team | Good balance; reduces UI team bottleneck |
| Micro-frontend | Each service team owns its domain’s UI fragment; composed at runtime (module federation, iframes, web components) | Maximum team autonomy; complex runtime composition |
The choice of UI approach affects team topology: a monolithic SPA creates a UI team that becomes a dependency for all service teams; micro-frontends shift that dependency away but add composition complexity.
API Gateway Options
The API gateway is optional but commonly used:
| Approach | Description | Trade-off |
|---|---|---|
| Single API gateway | One gateway handles all routing, auth, rate limiting, and aggregation for all services | Centralized control; single point of failure; can become bottleneck |
| Direct UI-to-service calls | UI calls each service directly (CORS-aware); no gateway | Simpler; less infrastructure; services must each handle auth |
| BFF (Backend for Frontend) | One gateway per UI surface (web BFF, mobile BFF) | Better optimization per client; more gateways to maintain |
| Domain gateways | Gateway per domain cluster (e.g., one for commerce services, one for user services) | Reduces blast radius; more operational overhead |
The API gateway handles cross-cutting concerns: authentication/authorization, rate limiting, request routing, SSL termination, request/response transformation, and logging. Services should not need to re-implement these concerns.
Data Topologies
Data topology is the most consequential architecture decision in service-based architecture. Four patterns from simplest to most isolated:
1. Shared Monolithic Database (Most Common Starting Point)
[Service A] [Service B] [Service C] [Service D]
│ │ │ │
└────────────┴───────────┴───────────┘
│
┌─────────▼──────────┐
│ Single Database │
│ (all tables, all │
│ services read) │
└────────────────────┘
- Pros: Simple to start; familiar; easy cross-service queries; no data duplication; no distributed transactions needed
- Cons: Schema coupling — changing a table impacts all services that use it; the database becomes a coordination bottleneck; harder to evolve services independently; single point of failure for data
2. Domain-Partitioned Database
[Service A] [Service B] [Service C]
│ │ │
▼ ▼ ▼
┌────────────┐ ┌─────────────┐ ┌─────────────┐
│ Schema: A │ │ Schema: B │ │ Schema: C │
└────────────┘ └─────────────┘ └─────────────┘
│ │ │
└──────────────────┴──────────────────┘
│
┌──────────▼──────────┐
│ Single DB Instance │
│ (multiple schemas) │
└──────────────────────┘
- Pros: Schema-level ownership; clear table ownership; services can evolve their schema without impacting others; one DB instance (simpler ops)
- Cons: Still one DB instance (availability and performance coupling); cross-service queries require joins across schemas or API calls
3. Dedicated Service Database (Highest Isolation)
[Service A] [Service B] [Service C] [Service D]
│ │ │ │
▼ ▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ DB: A │ │ DB: B │ │ DB: C │ │ DB: D │
│(Postgres│ │ (MongoDB)│ │ (MySQL) │ │ (Redis) │
└─────────┘ └──────────┘ └──────────┘ └──────────┘
- Pros: Maximum isolation; each service can use the best database technology for its domain (polyglot persistence); no schema coupling; independent scaling
- Cons: Cross-service data queries require API calls or event-driven replication; distributed transactions become necessary; operational complexity of many DB instances; data duplication
4. Shared Libraries for Shared Logic
When multiple services share the same database-access code or domain entities (e.g., a Customer entity), shared libraries provide a middle path:
- Shared database library: encapsulates ORM entities for the shared schema; all services import the library
- Risk: versioning discipline required — a library update that changes a schema entity must be deployed to all dependent services simultaneously (a distributed monolith antipattern if done carelessly)
Read Replicas and Materialized Views
For reporting or cross-service query needs without coupling service databases:
- Read replicas: services push data to a read replica; a reporting service queries the replica (no impact on operational service databases)
- Materialized views: pre-aggregated views maintained by the reporting layer; updated via change data capture (CDC) from source service databases
Cloud Considerations
- Containerizing services: each service runs as one or more containers (Docker/Kubernetes); services are deployed independently; horizontal scaling per service
- Managed API gateways: AWS API Gateway, Azure API Management, Kong, Apigee — managed infrastructure that handles routing, auth, rate limiting, caching, and observability without custom code
- Service discovery: in cloud environments, service instances are ephemeral; service discovery (AWS Cloud Map, Consul, Kubernetes Service) enables services to find each other without hardcoded endpoints
- Managed databases: RDS (relational), DynamoDB, Cosmos DB, Aurora — cloud-managed DB instances reduce operational overhead for dedicated-service-database topology
- CI/CD per service: each service has its own pipeline; independent deployment is a core benefit; teams deploy their service without coordinating with other service teams
- Secrets management: API keys, DB credentials, and service-to-service tokens managed via AWS Secrets Manager, Azure Key Vault, or HashiCorp Vault — not baked into container images
Common Risks
Database Coupling (Shared Database Bottleneck): When all services share one database, schema changes require coordinating across all service teams. The database becomes the hidden coupling point that negates the independence of the services. Over time, the fear of breaking a shared table leads teams to add columns rather than redesigning, causing schema decay. Mitigation: move toward domain-partitioned or dedicated databases as the system matures; enforce schema ownership policies.
Service Granularity Drift — Too Fine: Services gradually get split into smaller and smaller units as teams apply single-responsibility pressure, eventually reaching microservices granularity without the microservices infrastructure (service mesh, distributed tracing, orchestration). The result is microservices complexity with monolithic-database coupling. Mitigation: define explicit service count targets; require architecture review before adding a new service.
Service Granularity Drift — Too Coarse: A system starts with two or three very large services that effectively become mini-monoliths. The services are independently deployable, but each one is so large that internal agility within a service suffers. Mitigation: target the 4–12 range; a service that cannot be reasonably owned by a team of 5–8 people is probably too large.
Distributed Monolith: Services that are nominally independent but have so many runtime dependencies (synchronous calls chains, shared DB tables, shared libraries that change together) that they must be deployed simultaneously. This is the worst outcome — all the complexity of distributed systems with none of the independence benefits. Mitigation: minimize synchronous service-to-service calls; enforce deployment independence via contract tests.
Governance
Service API contracts: Each service must publish and version its API contract (OpenAPI spec, Protobuf schema). Contract tests (consumer-driven contract testing with Pact) verify that both provider and consumer agree on the interface. Breaking changes require versioning the API endpoint (/v1/orders, /v2/orders).
Shared library governance: Shared libraries (database entities, common utilities, authentication helpers) must be versioned with semantic versioning. Changes to shared libraries follow a coordinated release process; patch updates can be adopted asynchronously, minor updates at next opportunity, major (breaking) updates require a migration window.
Database ownership policy: Each database schema or database instance has a single designated service owner. No other service reads from or writes to that schema without going through the owning service’s API. This must be enforced at the database level (separate DB users per schema) and monitored.
Service count policy: The target service count (e.g., “this system should have 6–10 services”) is an architectural governance decision. Adding a new service requires an architecture decision record (ADR) justifying the split. Without this, granularity drift is inevitable.
Team Topology
| Team Structure | Description |
|---|---|
| One team per service | Ideal for larger organizations; each team is fully autonomous for their domain (own service, own database, own pipeline) |
| 2–3 services per team | Common in mid-size organizations; one team owns multiple closely related domains |
| Shared platform team | Owns the API gateway, shared libraries, CI/CD infrastructure, and observability platform |
| UI team (if monolithic UI) | Separate team for the frontend; receives contracts from service teams; bottleneck risk |
Service-based architecture aligns naturally with domain-driven design (DDD) bounded contexts — each service corresponds to a bounded context, and the team owns that bounded context end-to-end.
The key team-topology benefit: independent deployment — a service team can plan, build, test, and deploy their service without waiting for any other service team. This eliminates the “big bang release” coordination problem of the monolith.
Architectural Characteristics Ratings
| Characteristic | Rating | Notes |
|---|---|---|
| Overall agility | ★★★★☆ | Independent service deployment enables fast iteration per domain; shared DB is the main agility drag |
| Ease of deployment | ★★★★☆ | Each service deploys independently; fewer services than microservices = manageable deployment complexity |
| Testability | ★★★★☆ | Services can be tested independently; integration testing simpler than microservices because fewer services; contract testing with API gateway |
| Performance | ★★★★☆ | Coarse-grained services reduce inter-service network hops vs. microservices; shared DB provides fast joins; acceptable for most use cases |
| Scalability | ★★★★☆ | Individual services can be scaled independently (horizontal scaling per service); better than monolith but coarser than microservices |
| Ease of development | ★★★★☆ | Simpler than microservices (fewer services to manage, simpler data model); more complex than monolith but familiar tooling; good sweet spot |
| Simplicity | ★★★★☆ | Much simpler than microservices operationally; more complex than monolith; the pragmatic middle ground |
| Overall cost | ★★★★☆ | Lower infrastructure cost than microservices (fewer deployment units, fewer databases, simpler service mesh needs); higher than monolith |
When to Use
- Teams too large for a monolith: when a single codebase creates merge conflicts, coordination overhead, and deployment bottlenecks, service-based architecture provides team autonomy without microservices complexity
- Need more agility than a monolith but not ready for microservices: the most common “step up” from a monolith — adds independent deployability without requiring service mesh, distributed tracing, and per-service databases
- Domain-aligned teams exist: when business units or product teams already align with natural domain boundaries, service-based architecture maps teams to services cleanly
- Moderate scalability requirements: when some domains need to scale independently but not at the granularity or scale requiring microservices
- Pragmatic distributed architecture: when the engineering organization doesn’t have the operational maturity to run hundreds of microservices but needs to move beyond a monolith
When Not to Use
- Simple applications with low team count: a monolith is simpler, cheaper, and easier to operate; don’t distribute prematurely
- Extreme fine-grained scalability requirements: microservices provide independent scaling at the function/subdomain level; service-based architecture’s coarser granularity is insufficient for systems where individual operations (e.g., search vs. checkout) have radically different scaling needs
- Very high performance requirements with low-latency constraints: network hops between services add latency; an in-process monolith will always be faster for tightly integrated processing
- Organizations lacking distributed systems maturity: service-based architecture still requires understanding of network partitions, eventual consistency, and distributed transactions; if the team is not ready, a monolith is safer
Examples and Use Cases
E-Commerce Platform: A natural service-based fit. Services: User Management (registration, auth, profiles), Product Catalog (SKUs, search, categories), Order Management (cart, checkout, order lifecycle), Inventory (stock levels, reservations, warehouse), Payment (processing, refunds), Notification (email, SMS, push). 6 services, each owned by a team, sharing a relational database (or domain-partitioned schemas). The API gateway handles authentication and routes web/mobile traffic to services.
Healthcare Patient Portal: Services: Patient Records, Scheduling, Billing, Pharmacy, Lab Results. Regulatory requirements (HIPAA) may push toward dedicated-service databases for stronger data isolation. Each service has its own audit trail. The API gateway enforces authentication and role-based access control.
SaaS B2B Platform (Mid-Scale): A CRM or ERP with services for: Accounts, Contacts, Opportunities, Reporting, Integrations, Billing. The reporting service uses read replicas and materialized views to aggregate data from other service domains without coupling to their operational databases. Teams of 4–6 engineers each own 1–2 services.
Key Takeaways
- Service Granularity: Service-based uses coarse-grained, domain-scoped services (4–12 per system); this is the defining difference from microservices (fine-grained, subdomain/function-scoped, dozens to hundreds) and the source of its pragmatic simplicity.
- The Pragmatic Middle Ground: Service-based sits between monolith and microservices; it delivers independent deployability and team autonomy at a fraction of the operational complexity of microservices — the right trade-off for most organizations.
- Shared Database is the Starting Point: Most service-based systems start with a shared monolithic database; this is acceptable but creates schema coupling; the architecture matures by moving toward domain-partitioned or dedicated databases.
- Data Topology Progression: The four data topologies (shared DB → domain-partitioned → dedicated-service DB) represent increasing isolation and autonomy at increasing operational cost; choose the topology that matches your current organizational maturity.
- API Gateway: Optional but strongly recommended — centralizes cross-cutting concerns (auth, rate limiting, routing) so services don’t need to re-implement them; managed cloud gateways (AWS API GW, Kong) make this low-cost.
- Distributed Monolith Risk: Services that share a database and make many synchronous calls become a distributed monolith — all the complexity of distribution with none of the independence benefits; avoid by minimizing synchronous inter-service calls and enforcing schema ownership.
- UI Strategy Matters: The choice of monolithic SPA vs. modular UI vs. micro-frontends directly affects team bottlenecks; a monolithic UI creates a UI team that becomes a dependency for all service teams.
- Team Autonomy is the Primary Benefit: The ability for a service team to plan, build, test, and deploy their service without coordinating with other teams is the key value proposition — governance must protect this independence.
- 4–12 Service Count is a Guardrail: Too few (1–2) = effectively a modular monolith; too many (50+) = effectively microservices without the infrastructure; the 4–12 range maximizes the style’s agility-vs-complexity trade-off.
- Better Ratings Than Microservices on Simplicity and Cost: Service-based consistently outperforms microservices on simplicity, cost, and ease of development — making it the preferred style when extreme scalability or granularity are not required.
Related Resources
- ch09-architecture-styles-foundations — monolith vs. distributed trade-offs; the 8 fallacies of distributed computing
- ch11-modular-monolith-architecture — the style one step below service-based on the distribution spectrum
- ch18-microservices-architecture — the style one step above; compare granularity, data isolation, and operational complexity
- ch19-choosing-architecture-style — decision framework for choosing between service-based, microservices, and monolith
- ch20-architectural-patterns — CQRS and choreography/orchestration patterns applicable to service-based systems
Last Updated: 2026-05-29