Applying Domain-Driven Design to Marketing System Architecture: Strategic, Tactical, and Code Practices
This article walks through the application of Domain-Driven Design (DDD) in a B‑side marketing platform, detailing how strategic design defines use cases and unified language, tactical design maps concepts to object models, and code architecture organizes implementations, illustrated with concrete examples, diagrams, and practical guidelines.
Background
Marketing activities are used to acquire, retain, and activate customers. Meituan's local commerce technology team built a B‑side marketing system to support merchant growth, facing challenges such as large business volume, diverse scenarios, complex customer structures, and constantly changing requirements. The article explores how Domain-Driven Design (DDD) addresses high business complexity, frequent requirement changes, and high maintenance cost.
Basic Concepts
Obscurity : abstract level (different perspectives) and implementation level (code diverges from real‑world concepts) increase understanding cost.
Coupling : code‑level coupling expands modification scope; module‑level coupling requires cross‑module interaction; system‑level coupling needs cross‑team collaboration, raising overall cost.
Change : business needs evolve, causing frequent functional adjustments and expanding the impact of changes.
Strategic Design Practice
Strategic design starts with defining use cases. Common methods include:
Use‑case diagram – visualizes user‑system interactions.
User story – describes requirements from Who, What, Why.
Interaction prototype – shows UI flow but may ignore business logic.
Event storming – focuses on deep business logic, suited for large complex domains.
After iterating the use‑case diagram, concepts are extracted from the use cases, refined by discarding noise and merging abstractions. Unified language is built from terms (English equivalents) and their meanings, forming a concept model that captures relationships (1‑to‑1, many‑to‑1, many‑to‑many) and core attributes.
Unified language enables product, business, and technical teams to align on requirements, reducing miscommunication. The article shows a concrete confusion around the “merchant” concept, where multiple terms (fund account, account ID, merchant ID, etc.) caused ID misuse and wrong coupon distribution. By consolidating to “fund account” and “merchant account,” the system avoided errors.
Strategic design is iterative, driven by three sources:
Use‑case refinement as requirements are explored.
Requirement changes that reshape concepts.
Solution selection when business or technical shifts demand a new implementation approach (e.g., moving from rule‑based participation to target‑audience segmentation).
Validation of the concept model uses scenario walk‑throughs and business impact forecasting.
Tactical Design Practice
Tactical design maps the concept model to an object model. The process includes:
Layered concepts: a generic “marketing activity” is specialized into recharge‑gift, consumption‑return, buy‑gift, etc., implemented via inheritance.
Concept relationships become object relationships (e.g., activity contains tier and inventory objects as attributes).
Attributes and behaviors of concepts become object fields and methods; state machines translate to object state machines.
Two object categories are identified: entities (with identity) and value objects (without identity). Aggregate roots encapsulate related objects. The article compares two aggregation strategies:
Small aggregate roots : each object is its own root, simplifying each root but requiring domain services to handle cross‑root business rules (e.g., inventory changes affecting activity status).
Large aggregate root : a single root (e.g., the activity) aggregates all related objects, increasing complexity but allowing lazy loading for large target audiences.
Aggregate‑root design follows three principles: business consistency and data integrity, technical constraints (e.g., large data volumes), and balancing business logic placement between the root and domain services.
Method naming should reflect business intent; generic method names like updateStatus() hide meaning, whereas names such as submitCampaign(), approveCampaign(), and cancelCampaign() convey clear intent.
Code Architecture Practice
After tactical design, the code architecture is organized using hexagonal, clean, or onion architecture principles, all centering on the domain model. The layers are:
Domain layer (core business logic).
Application layer (use‑case orchestration, also part of domain logic).
Infrastructure layer (persistence, external services).
User‑interface layer (APIs, UI).
Both infrastructure and interface layers depend on the domain and application layers, keeping the domain model independent of external concerns.
Summary
Most systems are not built from scratch; existing industry practices (CRM, HR, SCM) should be leveraged.
Unified language is essential; without it, concept models and reliable code models cannot be formed.
DDD is a team effort—any participant can become a domain expert, but the work must be grounded in product and business realities.
Embrace change and iterate continuously; models evolve as business understanding deepens.
Common Pitfalls
Over‑applying DDD terminology in code (e.g., obsessing over aggregates, value objects) increases complexity without benefit.
Attempting to design a perfect domain model upfront; the model should emerge from strategic design steps.
Assuming DDD guarantees a good model; it provides a method to avoid unnecessary detours.
Meituan Technology Team
Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.
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.
