Applying Domain‑Driven Design in Microservice Architecture: Practices and Principles
The article explains how monolithic drawbacks—complexity, technical debt, and scaling issues—drive the shift to microservices, then details applying Domain‑Driven Design principles such as bounded contexts, aggregates, and layered architecture to design cohesive, loosely‑coupled services, illustrated with e‑commerce examples and code snippets.
This article is the fourth part of the “Domain‑Driven Design Practice” series. It introduces the drawbacks of monolithic architecture, then presents a microservice architecture combined with DDD concepts, showing how to split microservices, design domain models, and overall system architecture.
1. Drawbacks of Monolithic Architecture
In the early stage of a project the application is simple, easy to deploy, test and scale horizontally. As requirements increase, more developers join, and the codebase grows rapidly, the monolith becomes bulky, hard to maintain, and loses flexibility. The main problems are:
High complexity – developers can no longer understand every feature and business flow.
Accumulating technical debt – the stack becomes locked, making it hard to adopt new frameworks or languages.
Errors are hard to isolate – a failure in any module can crash the whole application.
High coordination cost among teams – merging code, resolving conflicts and releasing become slower.
High scaling cost – scaling the whole instance cannot target hot‑spot modules.
Because of these pain points many Internet companies have moved to microservice architecture.
2. Microservice Design
Microservices are an evolution of SOA. They follow the DDD principle of high cohesion and low coupling. A domain is defined as the set of business activities an organization performs. Sub‑domains and bounded contexts map naturally to microservices.
Using an e‑commerce resource‑ordering system as an example, the business is divided into four sub‑domains: User Management, Resource Management, Order Management, and Payment Management. Each sub‑domain corresponds to a bounded context and typically to a microservice.
Key design principles for aggregates:
Only reference the aggregate root.
Reference other aggregates by their unique identifiers.
One transaction should create or modify only one aggregate.
Use eventual consistency outside aggregate boundaries.
When a special case requires direct access to an entity inside an aggregate, the entity can be returned to the application layer.
3. Domain Model and Aggregates
An aggregate is a cluster of domain objects treated as a single unit. It consists of a root entity and possibly other entities or value objects. The aggregate root is the only entry point for external code.
Aggregates should be kept small to avoid large transactional scopes and to improve performance and scalability.
Example of a value object vs. entity decision is also discussed.
4. Facade Module
The facade belongs to the same layer as the domain model and provides APIs for third‑party consumption. It hides internal domain objects by exposing DTOs.
5. Application Layer
The application layer is the entry point for business logic, invoked by inbound adapters (e.g., REST controllers, message listeners). It coordinates use‑cases, invokes domain services, handles authentication, caching, and DTO‑entity conversion.
6. Infrastructure Layer
The infrastructure layer provides technical support such as database access, caching, RPC clients, and message publishing. Domain services may depend on infrastructure implementations for persistence.
Code Example – Resource Service Implementation
/**
* description: 资源领域服务
* @author Gao Ju
* @date 2020/7/27
*/
public class ResourceServiceImpl implements ResourceService {
/**
* 创建资源聚合模型
* @param resourceCreateCommand 创建资源命令
* @return
*/
@Override
public ResourceModel createResourceModel(ResourceCreateCommand resourceCreateCommand) {
ResourceModel resourceModel = new ResourceModel();
Long resId = SequenceUtil.generateUuid();
resourceModel.setResId(resId);
resourceModel.setName(resourceCreateCommand.getName());
resourceModel.setAuthor(resourceCreateCommand.getAuthor());
List
packageItemList = new ArrayList<>();
...
resourceModel.setPackageItemList(packageItemList);
return resourceModel;
}
}Code Example – Order Created Event
/**
* description: 订单创建事件
* @author Gao Ju
* @date 2020/8/24
*/
public class OrderCreatedEvent extends BaseEvent {
private String userId;
private String orderId;
private Integer payPrice;
}The article concludes that whether it is SOA, microservices, DDD, or a middle‑platform, the goal is to start from the business perspective, split the system into high‑cohesion, low‑coupling modules, and achieve reusable, stable services that support sustainable business growth.
vivo Internet Technology
Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.
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.