Fundamentals 21 min read

Modeling Domain‑Driven Design with ContextMapper DSL: From Subdomains to Bounded Contexts

This article explains how to use ContextMapper's DSL to express Domain‑Driven Design concepts—such as strategic and tactical design, subdomains, bounded contexts, context maps, user stories, and use cases—through concrete code examples, illustrating the benefits for architecture standardization and microservice integration.

Qunar Tech Salon
Qunar Tech Salon
Qunar Tech Salon
Modeling Domain‑Driven Design with ContextMapper DSL: From Subdomains to Bounded Contexts

Compared with traditional MVC, Domain‑Driven Design (DDD) is more abstract and harder to understand, leading to inconsistent documentation; the article proposes using a "DDD as Code" approach with a DSL to unify design thinking.

It introduces the distinction between tactical DDD (entities, value objects, aggregates, services, factories, repositories) and strategic DDD (bounded contexts, context maps, shared kernels, etc.), and explains how ContextMapper provides DSL support for both.

Subdomains are classified as Generic, Supporting, or Core, with examples of a membership system where domains like Account, UserTag, PaymentProfile, SnsProfile, and Profiles are defined. The following DSL snippet models the overall domain:

Domain User {
    domainVisionStatement = "User domain to manage account, tags, profiles and payment profile."
    Subdomain AccountDomain {
       type = CORE_DOMAIN
       domainVisionStatement = "Account domain to save sensitive data and authentication"
    }
    Subdomain UserTagDomain {
       type = GENERIC_SUBDOMAIN
       domainVisionStatement = "UserTag domain manage user's KV and Boolean tag"
    }
    Subdomain PaymentProfileDomain {
        type = CORE_DOMAIN
        domainVisionStatement = "User payment profile domain to manage credit/debit card, Alipay payment information"
    }
    Subdomain SnsProfileDomain {
        type = CORE_DOMAIN
        domainVisionStatement = "User Sns profile domain to manage user Sns profile for Weibo, Wechat, Facebook and Twitter."
    }
    Subdomain ProfilesDomain {
        type = CORE_DOMAIN
        domainVisionStatement = "User profiles domain to manage user basic profile, interest profile etc"
    }
}

For each subdomain, detailed DSL can describe entities and services, e.g., the Account subdomain:

Subdomain AccountDomain {
       type = CORE_DOMAIN
       domainVisionStatement = "Account domain to save sensitive data and authentication"
       Entity Account {
         long id
         String nick
         String mobile
         String ^email
         String name
         String salt
         String passwd
         int status
         Date createdAt
         Date updatedAt
       }
      Service AccountService {
          void updatePassword(long accountId, String oldPassword, String newPassword);
          void resetPassword(long acountId);
          boolean authByEmail(String email, String password);
          boolean authBySmsCode(String mobile, String code);
      }
    }

The ContextMap DSL describes relationships between bounded contexts, using notations like partnership, shared kernel, and anticorruption layer. An example ContextMap definition:

ContextMap UserContextMap {
   type = SYSTEM_LANDSCAPE
   state = TO_BE
   contains AccountContext
   contains UserTagContext
   contains PaymentProfileContext
   contains SnsProfileContext
   contains ProfilesContext
   contains UserLoginContext
   contains UserRegistrationContext
    UserLoginContext [D]<-[U] AccountContext {
        implementationTechnology = "RSocket"
        exposedAggregates = AccountFacadeAggregate
    }
    ProfilesContext [D]<-[U] UserTagContext {
        implementationTechnology = "RSocket"
        exposedAggregates = UserTags
    }
    UserRegistrationContext [D,C]<-[U,S] UserTagContext {
        implementationTechnology = "RSocket"
        exposedAggregates = UserTags
    }
    UserRegistrationContext [D,C]<-[U,S] SnsProfileContext {
        implementationTechnology = "RSocket"
    }
}

BoundedContext definitions include type, vision statements, implementation technology, responsibilities, and aggregates. Example for the Account context:

BoundedContext AccountContext implements AccountDomain {
    type = APPLICATION
    domainVisionStatement = "Managing account basic data"
    implementationTechnology = "Kotlin, Spring Boot, MySQL, Memcached"
    responsibilities = "Account", "Authentication"
    Aggregate AccountFacadeAggregate {
       ValueObject AccountDTO {
          long id
          String nick
          String name
          int status
          Date createdAt
          def toJson();
       }
       Service AccountFacade {
          @AccountDTO findById(Integer id);
       }
    }
    Aggregate Accounts {
         Entity Account {
            long id
            String nick
            String mobile
            String ^email
            String name
            String salt
            String passwd
            int status
            Date createdAt
            Date updatedAt
         }
   }
}

The article also shows DSL for UserStory and UseCase, demonstrating how to capture requirements in a structured way.

UserStory Customers {
    As a "Login User"
        I want to update a "Avatar"
        I want to update an "Address"
    so that "I can manage the personal data."
}
UseCase UC1_Example {
  actor = "Insurance Employee"
  interactions = create a "Customer", update a "Customer", "offer" a "Contract"
  benefit = "I am able to manage the customers data and offer them insurance contracts."
}

Benefits of using the DSL include clear, unambiguous architecture documentation, support for code generators, and easy integration with tools like PlantUML. The article discusses the relationship between DDD and microservices, emphasizing that DDD provides the conceptual foundation for service boundaries while microservice communication can be realized with REST, gRPC, or event‑driven messaging.

In conclusion, ContextMapper's DSL helps reduce ambiguity in DDD modeling, lowers the entry barrier for newcomers, and enables automated generation of documentation and code artifacts, though practical effectiveness still depends on real‑world adoption.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DSLDomain-Driven DesignBounded ContextContextMapper
Qunar Tech Salon
Written by

Qunar Tech Salon

Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.

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.