Industry Insights 10 min read

How Domain‑Driven Design Turns Complex Business Logic into Clear Code

This article explains why domain models are needed, walks through DDD's strategic and tactical design concepts, demonstrates a full knowledge‑payment platform case with bounded contexts, aggregates, and ubiquitous language, and outlines practical guidelines and limitations for applying DDD in real projects.

IT Architects Alliance
IT Architects Alliance
IT Architects Alliance
How Domain‑Driven Design Turns Complex Business Logic into Clear Code

Why a Domain Model?

Traditional MVC works for simple use‑cases but quickly shows three problems as business complexity grows: the code lacks a shared business language, data and behavior are split across layers, and the system’s boundaries become fuzzy. A domain model solves these issues by providing:

Unified language – product, design and development teams use the same terminology.

Business‑technical decoupling – the domain model is independent from the persistence model, allowing the core business to evolve without data‑layer constraints.

Knowledge retention – the model encodes business rules, making them explicit and transferable.

DDD Core Concepts Overview

Strategic Design – System Partitioning

Strategic design answers “how to split the system”. The main concepts are:

Domain : the whole set of activities an organization performs (e.g., a knowledge‑payment platform).

Sub‑domain : an independent business section within the domain (e.g., Subscription, Column, Finance).

Core sub‑domain : the part that provides competitive advantage (e.g., Subscription).

Generic sub‑domain : reusable functions used by many sub‑domains (e.g., Authentication, Authorization).

Supporting sub‑domain : enterprise‑specific features that support other business areas (e.g., Comments, Columns).

Bounded Context : a clear business boundary that typically maps to a microservice (e.g., Column‑Subscription Context).

Tactical Design – Building the Model

Entity : an object with a unique identity and lifecycle (e.g., Subscription, Column).

Value Object : an immutable set of attributes without identity (e.g., Address, Money).

Aggregate : a cluster of entities and value objects that share a consistency boundary.

Aggregate Root : the single entry point to an aggregate.

Domain Service : business behavior that does not naturally belong to any entity.

Repository : abstraction over data‑access logic.

Domain Event : a significant occurrence inside the domain.

Practical Case – RabbitTech Knowledge‑Payment Platform

Business Scenario

Author creates a column.

User browses columns.

User pays for a subscription.

User reads content.

Company shares revenue with the author.

Domain Partition

Knowledge‑payment domain
├── Subscription (core) – subscription, order
├── Column (support) – column, article
├── Finance (support) – revenue share, settlement
├── User (generic) – user, permission
└── Comment (support) – comment, like

Bounded Context Partition

┌─────────────────────────────────────┐
│ Column‑Subscription Context (MS1)   │
│   Subscription  ←── Order          │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│ Column‑Management Context (MS2)     │
│   Column  ←── Article               │
└─────────────────────────────────────┘

Aggregate Design Example – Subscription

Subscription Aggregate
├── Subscription (Aggregate Root)
│   ├── id: SubscriptionId
│   ├── userId: UserId
│   ├── columnId: ColumnId
│   ├── status: SubscriptionStatus
│   └── subscribedAt: DateTime
├── SubscriptionItem (Entity)
│   └── ArticleReadRecord
└── Value Objects
    ├── SubscriptionPeriod
    └── PaymentAmount

Ubiquitous Language – The Collaboration Foundation

Key Terms for “User subscribes to a column”

User : a person registered in the platform.

Column : a collection of content created by an author.

Subscription : a record that a user has paid for a column.

Order : the payment transaction that creates a subscription.

Applying the Language in Code

public class Subscription {
    private SubscriptionId id;
    private UserId userId;
    private ColumnId columnId;
    private SubscriptionStatus status;
    private DateTime subscribedAt;

    public void activate() {
        if (this.status != SubscriptionStatus.PENDING) {
            throw new IllegalStateException("Only pending subscriptions can be activated");
        }
        this.status = SubscriptionStatus.ACTIVE;
    }
}

Key Practices for DDD Implementation

Choosing an Entity Model

Four common model shapes are described below. The recommended approach for most DDD projects is the Passive (anemic) model , where entities contain the essential state and domain services hold the business logic.

Anemic Model : only fields and getters/setters – suitable for simple CRUD.

Passive Model : entities hold state; domain services implement behavior – DDD‑recommended.

Rich Model : entities encapsulate all business logic – used for very complex core domains.

Fat Model : mixes non‑business concerns – generally discouraged.

Aggregate Design Principles

Consistency boundary : all objects inside an aggregate must remain consistent.

Access through the root : external code may only reach members via the aggregate root.

Prefer small aggregates : smaller aggregates reduce concurrency conflicts.

Eventual consistency : aggregates communicate through domain events to achieve eventual consistency.

Bounded Context ↔ Microservice Mapping

One bounded context ≈ one microservice

Partitioning principles:
- Supports a complete business process
- Enables team autonomy
- Allows independent deployment

When DDD Is Appropriate

Complex business rules and frequent changes.

Large development teams with dedicated domain experts.

Products that evolve over time.

When DDD Is Not Recommended

Simple CRUD applications.

Rapid prototypes or short‑term projects.

Small teams where the focus is technology rather than business.

Summary

Strategic design defines how to split the system into bounded contexts.

Tactical design shows how to implement entities, value objects, aggregates and services.

Ubiquitous language ensures the whole team speaks the same terms.

Domain model captures and preserves business knowledge.

Code examples referenced in this article are available in the following repositories: Backend microservices: https://github.com/eyebluecn/smart-classroom-misc Frontend project: https://github.com/eyebluecn/smart-classroom-front
Domain-Driven DesignStrategic DesignTactical DesignUbiquitous LanguageAggregate
IT Architects Alliance
Written by

IT Architects Alliance

Discussion and exchange on system, internet, large‑scale distributed, high‑availability, and high‑performance architectures, as well as big data, machine learning, AI, and architecture adjustments with internet technologies. Includes real‑world large‑scale architecture case studies. Open to architects who have ideas and enjoy sharing.

0 followers
Reader feedback

How this landed with the community

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.