Advanced · Distribute
Find Service Boundaries Before Adding Spring Cloud
Use business ownership, data authority, and change coupling to decide whether a split earns its distributed cost.
Primary source: Spring Cloud 2024 Reference Documentation
Lesson 1 of 4
1d streakThe Architectural Question
Premature splits convert in-process method calls into network hops that nobody owns, and the failure modes arrive before the benefits.
What this guide proves
- Give each service authority over its own data
- Keep synchronous dependency depth shallow
- Prefer platform-native discovery on Kubernetes unless a registry solves a real need
Microservice Decomposition & Bounded Contexts
Decomposing an application into microservices should be driven by business domain capabilities and Domain-Driven Design (DDD) Bounded Contexts, not technical layers. A common anti-pattern is creating an "Entity Service" or "Database Microservice", which creates a distributed monolith with all the operational complexity of microservices and none of the benefits.
A microservice boundary is legitimate only if it provides:
1. Autonomous Deployability: A microservice team can build, test, and deploy without coordinating deployments with other service teams.
2. Shared-Nothing Persistence: Every microservice owns its private database. Microservices NEVER share database tables or schemas directly.
The Shared Database Trap
Spring Cloud Release Train Compatibility & Starter Hierarchy
Spring Cloud releases use alphabetical release train codenames. For Spring Boot 3.5.x, align with Spring Cloud 2025.0.x (codename Northfields). For reference, 2024.0.x is Moorgate (for Boot 3.4.x), and 2023.0.x is Leyton (for Boot 3.2.x/3.3.x). Unlike standard independent libraries, Spring Cloud dependencies must align strictly with your Spring Boot version using the Spring Cloud Dependency Management BOM.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2025.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>Distributed Data Management: Sagas vs Two-Phase Commit
In a microservices architecture with private databases, atomic multi-service transactions (XA / 2PC) do not scale across network boundaries and cloud availability zones.
Instead, systems embrace eventual consistency using the Saga pattern: a sequence of local transactions where each step updates data within a single service and publishes an event or message to trigger the next local transaction. If a step fails, compensating transactions undo preceding steps.
Contract Testing and Service Boundary Verification
Verify service boundaries and prevent breaking API changes between independent services using consumer-driven contract testing (Spring Cloud Contract or Pact):
# Run consumer-driven contract verification against stub runner
./mvnw clean test -Dtest=OrderContractVerificationTest
# Verifies producer API response matches consumer expectations exactlyActive Recall Checkpoint
Why must two microservices never share a single database schema?
Hint: Consider team independence and deployment isolation.
Show answer & explanation
Sharing a database couples the services at the persistence layer, destroying autonomous deployability and causing breaking changes whenever one service alters a table column.
Runtime Architecture & Flow
Dependency direction
Boundaries follow ownership
A microservice boundary buys independent ownership and deployment by introducing network, consistency, and operational failure modes.
Give each service authority over its own data
B1Keep synchronous dependency depth shallow
B2Prefer platform-native discovery on Kubernetes unless a registry solves a real need
B3Read these as design constraints. The arrows belong in the implementation only after the dependency rule is chosen.
Working Implementation
Code Walkthrough
Write an architecture decision record for keeping or splitting catalog and ordering.
package com.example.microservices;
import org.springframework.stereotype.Service;
import java.util.UUID;
@Service
public class ServiceBoundariesLab {
public record SagaCommand(UUID sagaId, String customerId, int amountCents, String status) {}
// Each microservice owns its private database schema; transactions coordinate via Saga steps
public SagaCommand startOrderSaga(String customerId, int amountCents) {
return new SagaCommand(UUID.randomUUID(), customerId, amountCents, "PENDING_PAYMENT");
}
public SagaCommand compensateOrder(SagaCommand state) {
// Compensating step executes if downstream inventory or payment fails
return new SagaCommand(state.sagaId(), state.customerId(), state.amountCents(), "CANCELLED_COMPENSATED");
}
}Synthesis & Production Verification
Production Acceptance Criteria
- Assign data authority per service with no shared tables
- Map synchronous dependencies and cap their depth
- Record split-versus-keep reasoning in an ADR others can challenge
Key Takeaway
Autonomous microservice boundaries are defined by business bounded contexts and shared-nothing persistence, coordinating cross-service workflows via the Saga pattern.
Architectural & Technical Review
Core Interview Questions
Q01Why is the shared database pattern considered an anti-pattern in microservices architecture?Show answer
Sharing database tables tightly couples services at the schema level, destroying autonomous deployability. A column change by one service breaks dependent services at runtime and introduces database locking contention.
Q02How does the Saga pattern manage distributed transactions without two-phase commit (XA)?Show answer
A Saga executes a sequence of local database transactions across services. Each local transaction updates state and publishes an event; if a step fails, the saga triggers compensating transactions to roll back previous changes.
Q03How does Spring Cloud release train BOM management prevent dependency version conflicts?Show answer
Importing the spring-cloud-dependencies BOM ensures that compatible versions of Spring Cloud Gateway, Config, Eureka, and OpenFeign are aligned with the host Spring Boot version automatically.
Production Pitfalls
Critical Anti-Patterns
- Pitfall: Creating fine-grained entity microservices that share a single database schema — Creates an operational distributed monolith with high latency, complex deployments, and zero autonomy.
- Pitfall: Attempting distributed two-phase commit (XA) across cloud availability zones — Introduces blocking coordinator locks and high latency, crashing availability during network partitions.
Primary Documentation & Specifications
Lesson Primary References
Supplementary Module Resources