Backend Development 21 min read

Applying Domain-Driven Design (DDD) in a High‑Throughput E‑Commerce System: Concepts, Layers, and Practical Code

The article explains how a WeChat e‑commerce team adopted Domain‑Driven Design, reorganizing a fast‑paced, multi‑team project into a four‑layer onion architecture with strategic sub‑domains, bounded contexts, anti‑corruption layers, domain events, aggregates, repositories and services, to achieve maintainability, extensibility, cohesion and loose coupling.

Tencent Cloud Developer
Tencent Cloud Developer
Tencent Cloud Developer
Applying Domain-Driven Design (DDD) in a High‑Throughput E‑Commerce System: Concepts, Layers, and Practical Code

This article describes how a WeChat team applied Domain‑Driven Design (DDD) to a fast‑paced, multi‑team e‑commerce project in order to keep the system maintainable, extensible, highly cohesive, loosely coupled, and stable.

What is DDD? DDD (Domain‑Driven Design) is an object‑oriented modeling methodology introduced by Eric Evans in 2003 and popularized after Martin Fowler’s 2014 micro‑services paper. It provides a set of strategic and tactical tools for tackling complex software systems.

Problems observed in the project :

Code layer: Core RPC logic grew to several hundred lines in a single function, becoming unreadable and a “technical moat”.

Micro‑service layer: Some services (e.g., the mp module) accumulated over 200 RPCs, causing slow builds, single points of failure, and heavy coupling.

Business team layer: Shared interfaces with other systems caused hidden dependencies and difficult cross‑team changes.

To address these issues, the team chose DDD as a guiding rule rather than relying on a single “decision‑maker”.

DDD Layered Architecture

The traditional three‑tier model is transformed into a four‑layer model (User Interface, Application, Domain, Infrastructure). The four layers are:

User Interface Layer – network protocol conversion, authentication, session management, rate limiting, caching, exception translation.

Application Layer – orchestrates business processes (no business logic) and handles DTO conversion.

Domain Layer – defines domain models, domain services, repositories, and anti‑corruption interfaces.

Infrastructure Layer – implements repository and anti‑corruption interfaces, provides storage and external system access.

The four layers can be split logically within a single micro‑service or physically across services. The architecture follows the Onion (or Hexagonal) principle, emphasizing Dependency Inversion (DIP): high‑level modules depend on abstractions, and details depend on abstractions.

Dependency Inversion (DIP)

1. High‑level modules should not depend on low‑level modules; both depend on abstractions. 2. Abstractions should not depend on details; details depend on abstractions.

In the example, the domain layer defines a gen_id_gateway interface, and the infrastructure layer implements it via gen_id_gateway_impl to obtain IDs from another bounded context.

productdomainsvr (商品限界上下文) ├── domain │ ├── aggregate │ │ ├── spu.cpp // 1) spu领域对象需要调用其他限界上下文生成id │ │ └── spu.h │ └── gateway │ └── gen_id_gateway.h // 2) 领域层定义调用其他限界上下文生成id的防腐接口 ├── infrastructure │ └── gatewayimpl │ └── acl │ ├── gen_id_gateway_impl.cpp // 3) 基础设施层实现防腐接口,真实调用其他上下文 │ └── gen_id_gateway_impl.h

Strategic and Tactical Modeling

Strategic modeling splits the business into sub‑domains and bounded contexts, defining a ubiquitous language. Tactical modeling implements the domain layer, aggregates, entities, value objects, and domain services.

Sub‑domains

Three types of sub‑domains are identified:

Core sub‑domain – the source of competitive advantage.

Generic sub‑domain – used across the system but not core.

Supporting sub‑domain – necessary capabilities not used system‑wide.

Prioritizing resources for core sub‑domains is essential.

Bounded Contexts

Bounded contexts provide clear boundaries where each term has a single meaning. Rules for defining them include:

Conceptual ambiguity – split if a model is ambiguous.

External system interaction – isolate external dependencies.

Organizational structure – align with team boundaries (Conway’s Law).

Examples show how the same “product” concept is modeled differently in the product and transaction contexts, with anti‑corruption layers mediating between them.

// Example of anti‑corruption layer implementation class ProductGatewayImpl : public ProductGateway { public: ProductId GenerateId() override { /* call other context */ } };

Domain Events

Domain events capture business‑valuable occurrences (e.g., “PaymentSucceeded”) and are typically propagated via Kafka or similar messaging systems, decoupling bounded contexts.

Entities and Value Objects

Entities have a stable identity (e.g., SPU, SKU, Discount) while value objects lack identity and are embedded within entities. A table in the source lists entities, their descriptions, and key value objects.

Aggregates and Aggregate Roots

Aggregates group tightly related entities; only the aggregate root is referenced externally. Small aggregates facilitate micro‑service extraction.

// Aggregate definition example class SpuAggregateRoot { public: SpuId id; std::vector skus; // non‑root entities };

DTO ↔ Domain Object ↔ Data Object

Requests flow from DTOs (external contracts) to domain objects (rich behavior) to data objects (persistence). Excessive conversion can add complexity, so CQRS is often used to keep simple queries lightweight.

Repository

Repositories are domain‑level abstractions for persisting aggregates. They are defined in the domain layer but implemented in the infrastructure layer. They may also publish domain events as part of a save operation.

// Repository interface in domain layer class DetailRecordRepository { public: virtual int Save(DetailRecord& entity) = 0; }; // Implementation in infrastructure layer class DetailRecordRepositoryImpl : public DetailRecordRepository { public: int Save(DetailRecord& entity) override { DetailRecordDO doObj; entity.ConvertToDO(doObj); kvMapper.insert(doObj); eventMapper.publish(doObj); return 0; } };

Domain Services

When behavior does not belong to a single entity, it is extracted into a domain service, which is invoked by the application layer.

Code Scaffold

The article concludes with a suggested project skeleton that separates adapters, domain services, aggregates, gateways, and infrastructure, providing a concrete starting point for teams adopting DDD.

Software ArchitecturemicroservicesBackend DevelopmentDomain-Driven DesignCDDDCQRS
Tencent Cloud Developer
Written by

Tencent Cloud Developer

Official Tencent Cloud community account that brings together developers, shares practical tech insights, and fosters an influential tech exchange community.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.