Microservice Governance: Service Split Extremes, Debt Triage & Strangler Fig Refactoring
This article analyzes two extremes of microservice splitting—overly coarse services that become monoliths and overly fine services that explode call chains—details a three-tier technical debt classification (P0/P1/P2), and presents a four-step Strangler Fig Pattern for zero-downtime progressive refactoring based on real e-commerce production experience.
Two Extremes of Service Splitting
Microservice architectures often degrade after 6–12 months of rapid iteration. The article identifies two failure modes:
Extreme 1: Overly Coarse Splitting (Pseudo-Microservices)
Resource waste: A coupon traffic spike forces scaling the entire user service.
Iteration blocking: All business logic coupled in one service; any small change requires full deployment.
Failure blast radius: A slow SQL or memory leak in one module brings down the whole service.
Extreme 2: Overly Fine Splitting (Over-DDD Granularity Explosion)
Call chain explosion: An order flow spans 10+ layers; any intermediate jitter causes global timeouts.
Operational cost explosion: Service count, config, container instances, and monitoring costs double.
A comparison table summarizes the trade-offs:
Service count: Coarse 3–5, Fine 30+, Balanced 8–15.
Resource utilization: Coarse wastes scaling, Fine fragments severely, Balanced scales independently.
Call depth: Coarse internal coupling, Fine long chains, Balanced 3–5 layers.
Applicable stage: Coarse for startup, Fine for mature large orgs, Balanced for growth-to-mature.
Architectural heuristic: Startups tolerate coarse granularity to ship fast; mature businesses with high traffic and specialized teams gradually refine by business domain, change frequency, and traffic profile.
DDD Domain Model Corrosion: The Hidden Technical Debt
Real e-commerce case: the Product service, originally responsible only for listing, pricing, and inventory, absorbed coupon, discount, and promotion logic from marketing iterations, violating its domain boundary.
Four Classic Symptoms of Domain Corrosion
Anemic model: Entities are mere getters/setters; business logic leaks into Service layer.
Cross-domain invasion: A single service hosts multiple unrelated domain logics, blurring boundaries.
Aggregate root failure: Data associations become chaotic; aggregate roots lose ability to enforce consistency invariants.
Scattered enums and rules: No unified ownership; duplicate definitions, naming conflicts, maintenance burden.
Three-Level Technical Debt Governance
The team adopts a tiered framework:
P0 (Immediate, halt other work): Threatens production stability, risk of data loss or cascade failure. Example: core paths missing circuit breakers and fallbacks.
P1 (Opportunistic during iterations): Hurts maintainability but not stability. Examples: anemic models, cross-domain intrusion, code duplication.
P2 (Long-term tolerable): Pure style, legacy compatibility. Examples: naming violations, outdated comments, deprecated methods.
Architect mindset: Governance is a cost-benefit game; do not sacrifice business velocity or system stability for "code perfection."
Progressive Refactoring: Strangler Fig Pattern (The Only Viable Path for Brownfield Systems)
Most tutorials teach greenfield DDD design; enterprises need to rescue rotting live systems. The answer is the Strangler Fig Pattern—new and old coexist, incremental migration, zero-downtime cutover.
Step 1: Layer Isolation – New Domain Layer Beside Old Code
Leave legacy code untouched. Build a new independent domain layer; all new requirements go into new code.
// Old code: tangled transaction logic, scattered rules (kept as-is)
@Service
public class OldOrderService {
// massive piled-up business logic, unmaintainable
}
// New code: independent domain layer, rich model implemented
public class OrderAggregate {
// Order aggregate root, encapsulates state transitions, validation, business behavior
public void createOrder(OrderCreateDTO dto) {
// unified order creation domain rules
checkStock();
checkPrice();
initOrderStatus();
}
public void paySuccess() {
// unified post-payment domain behavior
changeStatus();
sendPayEvent();
}
}
@Service
public class NewOrderDomainService {
// thin application service, only orchestrates, no business logic
public void createOrder(OrderCreateDTO dto) {
OrderAggregate order = new OrderAggregate();
order.createOrder(dto);
// repository & event dispatch
}
}Step 2: Traffic Gradual Migration – Controlled Risk
Phase 1 (5% traffic): Canary new logic; observe stability, performance, data consistency.
Phase 2 (50% traffic): Expand canary scope; continue monitoring.
Phase 3 (100% traffic): Full cutover; mark old code deprecated, enter cleanup.
Step 3: Boundary Clarification – Peel Off Cross-Domain Logic Per Scenario
Map each service's actual responsibilities; migrate non-domain logic to its rightful service. Example: coupon calculation moved from Product service to Marketing service; inventory deduction moved from Order service to Product service.
Step 4: Event-Driven Decoupling – Eliminate Circular Dependencies
Replace synchronous calls with domain events. Example: on order creation, publish OrderCreatedEvent; downstream services (Points, Marketing) subscribe asynchronously instead of being called synchronously.
Core value of Strangler Fig: No iteration freeze, no business halt, no stop-the-world—architecture evolves while the system runs.
Four Hard Criteria for Splitting Decisions
When facing a messy brownfield system, use these four signals to decide split vs. keep:
Business responsibility: Split if completely different domains that must not couple; keep if same domain with strong cohesion.
Change frequency: Split if a module changes so often it drags down overall release cadence; keep if change rates align and co-deployment works.
Traffic profile: Split if traffic patterns differ wildly and need independent scaling; keep if traffic is uniform and scales together.
Team structure: Split if multi-person collaboration causes severe conflicts and demands independent ownership; keep if a small team owns the whole module.
Reverse test: If business is highly cohesive and tightly coupled, splitting would explode distributed complexity—firmly keep as a monolith.
P7 Interview High-Frequency Q&A
Q1: Production microservice domain model corrupted—how to govern?
High-score answer: Target service boundary chaos and cross-domain intrusion; peel off non-domain logic per business scenario, combine with event-driven async decoupling to break circular dependencies, ultimately achieving high-cohesion low-coupling microservice architecture.
Q2: How to gauge service split granularity? Consequences of too coarse vs. too fine?
High-score answer: Too coarse creates pseudo-microservices: iteration blocking, failure blast radius, resource waste—losing core microservice benefits. Too fine causes call chain explosion, amplified distributed risks, transaction consistency pain, operational cost surge. Right granularity depends on business stage: startup coarse for speed, mature gradual refinement by domain, change frequency, traffic profile.
Summary: Core Architect Mindset
No silver bullet for service splitting; both extremes are disasters; right granularity follows business stage.
DDD domain model corrosion is the biggest hidden technical debt—regular health checks and timely treatment are mandatory.
Technical debt must be triaged; trade-off judgment is the architect's core skill—no blind refactoring, no blind neglect.
Progressive refactoring (Strangler Fig) is the only viable path for brownfield: coexist, canary, zero-downtime switch.
Four splitting verdicts: business responsibility, change frequency, traffic profile, team structure.
A true senior architect doesn't just design perfect greenfield systems—they continuously optimize chaotic brownfield systems at lowest cost and risk, keeping architecture healthy while supporting high-velocity business iteration.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Internet Backend Architecture Stack
Over ten years of hands-on Java backend architecture experience, focusing on sharing mainstream internet technologies such as Java backend, microservices, distributed systems, high concurrency, performance optimization, and source code analysis. Building a platform for Java technologists to exchange and grow, collaborating with peers to advance together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
