Skip to content
CONTEXT MAPPER
  • Docs
  • Language Reference
  • Generators
  • News
  • Background
  • Get Involved
    Introduction
    • Welcome
    • Getting started
    • Create CML Project
    • Examples
    • Usage as Library
    • Frequently Asked Questions
    Language Reference (Core)
    • CML Reference - Introduction
    • Language Semantics
    • Context Map
    • Bounded Context
    • Domain and Subdomain
    • Domain Vision Statement
    • Partnership
    • Shared Kernel
    • Customer/Supplier
    • Conformist
    • Open Host Service
    • Anticorruption Layer
    • Published Language
    • Responsibility Layers
    • Knowledge Level
    • Aggregate
    • Tactic DDD Syntax
    • Application and Process Layer
    • User Requirements
    • Stakeholders
    • Value Registers
    • Imports
    Analysis and Design Transformations
    • Rapid Object-oriented Analysis and Design
    • Story Splitting (PoC)
    • Stakeholder and Value Modelling Transformations
    Architectural Refactorings (ARs)
    • Architectural Refactorings
    • AR-1: Split Aggregate by Entities
    • AR-2: Split Bounded Context by Features
    • AR-3: Split Bounded Context by Owner
    • AR-4: Extract Aggregates by Volatility
    • AR-5: Extract Aggregates by Cohesion
    • AR-6: Merge Aggregates
    • AR-7: Merge Bounded Contexts
    • AR-8: Extract Shared Kernel
    • AR-9: Suspend Partnership
    • AR-10: Change Shared Kernel to Partnership
    • AR-11: Change Partnership to Shared Kernel
    Value-Driven Analysis and Design
    • Value-Driven Analysis and Design (VDAD) Support
    Service Cutter
    • Context Map Suggestions with Service Cutter
    • Service Cutter Configuration File (.servicecutter.yml)
    Reverse Engineering
    • Context Map Discovery
    Generators
    • Generators Overview
    • Context Map Generator
    • PlantUML Generator
    • BPMN Sketch Miner Generator
    • MDSL (Micro-)Service Contracts Generator
    • Service Cutter Generators
    • Generic Generator (Templating)
    Tutorials
    • Model Event Storming Results in Context Mapper
    • Event Sourcing and CQRS Modeling in Context Mapper
    • Generate Microservices From Context Map Using JHipster
    • Systematic Service Decomposition with Context Mapper and Service Cutter
    • Validating the Implementation against the Model (with ArchUnit)
    IDE Plugins and Extensions
    • Visual Studio Code Extension
    • Online IDE (no longer supported)
    • Eclipse Plugin
    • Feature Support

    Event Sourcing and CQRS Modeling in Context Mapper

    Event sourcing and Command Query Responsibility Segregation (CQRS) are two different approaches, but they work together very well. Both concepts deal with application state. Event sourcing captures all changes to the state as a sequence of (or stream) of events so that state changes can be communicated flexibly without tightly coupling sender and receiver of the change message. This is one reason why this concept is interesting for microservice architectures. CQRS separates query processing from the create, update, delete business logic so that different Non-Functional Requirements (NFRs), for instance regarding performance, for read and write access can be satisfied in different ways. In complex domains, this is often desired.

    If you are not fully familiar with the concepts of event sourcing and CQRS yet, you may find the following resources helpful:

    • Event sourcing by Martin Fowler
    • Event sourcing workshop slides by Michael Plöd
    • Event sourcing pattern by Chris Richardson
    • CQRS and Event Sourcing (Video) by Greg Young
    • Command query separation and CQRS by Martin Fowler
    • Developing Transactional Microservices Using Aggregates, Event Sourcing and CQRS by Chris Richardson
    • Designing Event Sourced Microservices by Jan Stenberg

    Chapter 22 in “Patterns, Principles, and Practices of Domain-Driven Design” by Scott Millett and Nick Tune (Wrox 2015) is about event sourcing; Chapter 24 in that book features CQRS. “Implementing Domain-Driven Design” by Vaughn Vernon (Addison Wesley 2013) covers event sourcing and CQRS in Chapter 4 and Appendix A.

    Tutorial

    Context and Objectives

    This tutorial highlights the Context Mapper DSL (CML) concepts that support a) modeling event-sourced systems and b) CQRS.

    Within CML Bounded Contexts and Aggregates, we integrated the Sculptor DSL for tactic DDD that allows domain-driven designers to specify the domain model of Bounded Contexts. This tutorial features this DSL.

    Events

    As explained in the Sculptor documentation, the syntax of Sculptor supports modeling events.

    A domain event is something that happened that affects the application/resource state. Michael Plöd suggests that the scope of domain events should always be based on Aggregates. The names of domain events shall indicate that the event happened in the past.

    The following example illustrates how you can model domain events within your Aggregate:

    abstract DomainEvent AbstractDomainEvent {
      Date timestamp
    }
    
    DomainEvent CustomerVerifiedEvent extends AbstractDomainEvent {
      - CustomerId customer
    }
    
    DomainEvent AddressUpdatedEvent extends AbstractDomainEvent {
      - CustomerId customer  
      - AddressDto address
    }
    
    ValueObject AddressDto {
      String streetAddress
      String city
      String postalCode
    }
    

    You can also reference your events in services, repositories, or any other tactic DDD objects:

    Service AddressService {
      @AddressUpdatedEvent updateAddress(@AddressDto address);
    }
    

    CQRS Example

    Applying CQRS to a Bounded Context definition in Context Mapper can be expressed with the standard language constructs of Context Mapper and Sculptor: you can simply apply this architectural pattern by

    1. Separating the queries from the command methods and defining separate services
    2. Defining separate command and query models

    Step 1: Separating Queries and Commands

    Here is an example of a conventional service interface that exposes both create, read, update, delete, and search methods/operations:

    ValueObject CustomerDTO {
      String customerId
      CustomerProfileDto customerProfile
      List<Link> links
    }
    
    Service CustomerService {
      @CustomerId createCustomer(@CustomerDTO customer);
      void updateCustomer(@CustomerDTO customer);
      boolean deleteCustomer(@CustomerId customer);
      @CustomerDTO findCustomerById(@CustomerId customerId);
      List<@CustomerDTO> findCustomersByName(String name);
    }
    

    You can CQRS-ify the above interface by splitting it into two service interfaces:

    Service CustomerCommandService {
      @CustomerId createCustomer(@CustomerDTO customer);
      void updateCustomer(@CustomerDTO customer);
      boolean deleteCustomer(@CustomerId customer);
    }
    
    Service CustomerQueryService {
      @CustomerDTO findCustomerById(@CustomerId customerId);
      List<@CustomerDTO> findCustomersByName(String name);
    }
    

    Additionally, Sculptor introduces so-called command events to support CQRS explicitly (described here). In comparison to a domain event which describes something that has happened, a command event is something that the system is asked to perform. The following CML/Sculptor snippet illustrates an example how to model command events:

    CommandEvent RecordAddressChange {
      -AddressDto newAddress
      Date changeDate
    }	
    

    Step 2: Separating Read and Command Models

    In a second step you may want to define completely different models for read and command access. At present, the Context Mapper DSL does not have any specific language construct for read models; we suggest that you use the Michael’s Aggregate rule from above to specify read models. The following example illustrates how you could model your Aggregate (command model) and your read model:

    Aggregate CustomerAggregate {
      ValueObject CustomerId {
        UUID uniqueCustomerId
      }
    
      Entity Address // not designed in detail 
    
      Service CustomerCommandService {
        @CustomerId createCustomer(@CustomerDTO customer);
        void updateCustomer(@CustomerDTO customer);
        boolean deleteCustomer(@CustomerId customer);
      }
    }
    
    Aggregate CustomerReadModel {
      DataTransferObject CustomerDTO {
        String firstName
        String lastName
      }
    
      Service CustomerQueryService {
        @CustomerDTO findCustomerById(@CustomerId customerId);
        List<@CustomerDTO> findCustomersByName(String name);
      }
    }
    

    Note: If you initially create an Aggregate with separate Entities for reading and updating, you can also use our Architectural Refactoring (AR) Split Aggregate by Entities to separate the read model (Aggregate) from the command model Aggregate.

    Note: The two Aggregates representing the command model and the read model should probably be contained in the same Bounded Context; otherwise, two Bounded Contexts have to access a shared database, which is considered a microservices antipattern.

    Event Sourcing with Sculptor

    The Sculptor generator further supports event sourcing specifically as described here: Event Sourcing with Sculptor. However, the DSL syntax itself does not need additional concepts to support it. It is based on the DomainEvents, Repositories, and Services provided by the Sculptor and also CML.

    • Note: We only used the Sculptor syntax for the tactic DDD grammar of our CML language. Using the Sculptor generator in Context Mapper is currently not supported.

    Other Tutorials and Links

    • Tutorial: Document Event Storming Results with Context Mapper
    • Presentation on Context Mapper: Context Mapper: DSL and Tools for Domain-Driven Service Design - Bounded Context Modeling and Microservice Decomposition
    • Paper introducing the Context Mapper DSL (CML): Domain-specific Language and Tools for Strategic Domain-driven Design, Context Mapping and Bounded Context Modeling
    Improve this page on GitHub
    ← PreviousModel Event Storming Results in Context Mapper Next →Generate Microservices From Context Map Using JHipster
    © 2026 Context Mapper contributors
    • GitHub
    • Get Involved
    • Background & Publications
    • RSS