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

    Application and Process Layer

    The original “blue book” (by Evans) as well as the “red book” (by Vernon) talk about domain and application layers. Although Context Mapper is focused on strategic DDD and domain models (domain layer) inside Bounded Contexts, we support modeling services, commands, and events in an application layer. With the application layer concept in CML users have the possibility to declare which services and/or commands can be called/triggered from outside a Bounded Context and which events are published to the outside.

    In addition to that, the application layer offers a basic syntax to model processes or event/command flows. This can, for example, be helpful to bring events and commands (maybe outcome of an Event Storming) into a timeline and explicitly state which event are emitted by which commands (or service operations) and which commands are triggered by events.

    The application layer also provides an alternative way to model processes without relying on event/command syntax. This is achieved by defining a coordination between service operations.

    Application Services and Commands

    DDD practitioners and experts typically distinguish between domain services and application services. Therefore, CML offers the possibility to use the service construct both inside Aggregates (domain service) and inside the application layer (application service). Note that the grammar/syntax for application services is exactly the same as for the services inside the Aggregates.

    The following example illustrates how to model an application layer in a Bounded Context and add application services:

    BoundedContext ClaimsManagement {
      Application {
        Service ClaimsApplicationService {
          void submitClaim(@Claim claim);
          void checkInsurance(@Claim claim);
          void acceptClaim(@Claim claim);
          void rejectClaim(@Claim claim);
        }
      }
    
      Aggregate Claims {
        Entity Claim {
          aggregateRoot
          long claimId
          CustomerId customer
          String description
          Blob requestDocument
          boolean isComplete
          boolean isAssessed
          - ClaimState claimState
        }
        enum ClaimState {
          aggregateLifecycle
          OPEN, REJECTED, ACCEPTED
        }
    
        abstract DomainEvent ClaimEvent {
          long claimId
          Date timestamp
        }
        DomainEvent ClaimSubmitted extends ClaimEvent
        DomainEvent ClaimAccepted extends ClaimEvent
        DomainEvent ClaimRejected extends ClaimEvent
      }
    }
    

    Optionally, it is possible to name the application layer:

    Application ClaimsApplicationLayer {
      Service ClaimsApplicationService {
        void submitClaim(@Claim claim);
        void checkInsurance(@Claim claim);
        void acceptClaim(@Claim claim);
        void rejectClaim(@Claim claim);
      }
    }
    

    As documented on the Aggregate page, it is also possible to specify state transitions made by operations. Please consult the Aggregate documentation for the syntax of state transitions. The same syntax is available for the operations of application services:

    Application {
      Service ClaimsApplicationService {
        void submitClaim(@Claim claim) : write [ -> OPEN];
        void checkInsurance(@Claim claim);
        void acceptClaim(@Claim claim) : write [ OPEN -> ACCEPTED ];
        void rejectClaim(@Claim claim) : write [ OPEN -> REJECTED ];
      }
    }
    

    Hint: If you model processes/flows (see documentation of syntax below) you may want to declare the state transitions in the flow steps instead of service operations.

    As an alternative to “service operations” you can also create semantically equivalent commands and events in the application layer; maybe you work with Event Sourcing and/or CQRS, and these terms fit better.

    The syntax for domain events and commands is documented on the tactic DDD reference page. The following example illustrates how you can use those concepts in the application layer as well:

    Application {
      Command SubmitClaim {
        // attributes/body optional
      }
      Command AcceptClaim
      Command RejectClaim
    
      Event ClaimSubmitted {
        // attributes/body optional
      }
      Event ClaimAccepted
      Event ClaimRejected
    }
    

    Hint: Modeling commands that are triggered by users or external systems in the application layer may feel natural. Events, however, may be part of your domain model. Therefore you should decide consciously whether you want to model these events on the application layer or inside the corresponding domain layer Aggregate.

    Processes and Event/Command Flows

    In addition to application services and commands, the application layer offers language features to model event/command flows. Events typically occur in a certain order over time. For example in Event Stormings Events are typically ordered by the timeline from left to right. An example: (from our Event Storming tutorial)

    Lakeside Mutual Claim Processing Event Storming

    Our flow grammar supports Context Mapper users in modeling such event/command flows in CML. The following example models the event storming result illustrated above:

    Application {
    
      /* we removed commands and events here to keep the sample shorter */
    
      Flow ClaimsFlow {
        command SubmitClaim emits event ClaimSubmitted
        event ClaimSubmitted triggers command CheckClaimDocumentation
        command CheckClaimDocumentation emits event ClaimRegistered
        event ClaimRegistered triggers command CheckInsurance
        command CheckInsurance emits event AssessmentPerformed
    
        event AssessmentPerformed triggers command AcceptClaim X RejectClaim
        command AcceptClaim delegates to Claims [OPEN -> ACCEPTED] emits event ClaimAccepted
        command RejectClaim delegates to Claims [OPEN -> REJECTED] emits event ClaimRejected
    
        event ClaimAccepted triggers command SchedulePayment
        command SchedulePayment emits event PaymentPerformed
        event PaymentPerformed triggers command NofifyCustomer
        event ClaimRejected triggers command NofifyCustomer
        command NofifyCustomer delegates to Claims [ACCEPTED, REJECTED -> CUSTOMER_NOTIFIED] emits event CustomerNotified
      }
    }
    

    The example above works with commands. It is however possible to model the same flow with service operations:

    Application {
      Service ClaimsApplicationService {
        void submitClaim(@Claim claim);
        void checkClaimDocumentation(@Claim claim);
        void checkInsurance(@Claim claim);
        void acceptClaim(@Claim claim);
        void rejectClaim(@Claim claim);
        void schedulePayment(@Claim claim);
        void nofifyCustomer(@Claim claim);
      }
    
      Flow ClaimsFlow {
        operation submitClaim emits event ClaimSubmitted
        event ClaimSubmitted triggers operation checkClaimDocumentation
        operation checkClaimDocumentation emits event ClaimRegistered
        event ClaimRegistered triggers operation checkInsurance
        operation checkInsurance emits event AssessmentPerformed
    
        event AssessmentPerformed triggers operation acceptClaim X rejectClaim
        operation acceptClaim delegates to Claims [OPEN -> ACCEPTED] emits event ClaimAccepted
        operation rejectClaim delegates to Claims [OPEN -> REJECTED] emits event ClaimRejected
    
        event ClaimAccepted triggers operation schedulePayment
        operation schedulePayment emits event PaymentPerformed
        event PaymentPerformed triggers operation nofifyCustomer
        event ClaimRejected triggers operation nofifyCustomer
        operation nofifyCustomer delegates to Claims[ACCEPTED, REJECTED -> CUSTOMER_NOTIFIED] emits event CustomerNotified
      }
    }
    

    In the following we explain the grammar in detail and step by step…

    Flow Grammar

    There are basically two types of flow steps that are supported by CML:

    • Type 1: an event triggers an operation/command (command/operation invocation)
    • Type 2: a command/operation emits an event (event production)

    These types of steps are inspired by the Event Storming Cheat sheet of the DDD crew, the following illustration in particular:

    Event Storming Picture

    Illustration: EventStorming Glossary & Cheat sheet by the DDD Crew, licensed under CC BY-SA 4.0.

    Note: We do not support all of the concepts illustrated above! Especially policies and the “query model / information” sticky are not supported explicitly.

    The picture above illustrates the two main step types mentioned above.

    • Type 1: an event triggers (the DDD crew uses the term issues) a command (in CML without the policy in between)
    • Type 2: a command (CML: or operation) invoked on an Aggregate emits (the DDD crew uses the term produces) an event

    In the following we will see that we also support the Aggregate in Type 2; the actor that can trigger a command/operation.

    The following example illustrates the basic syntax of the two step types:

    Application {
    
      /* we removed commands and events here to keep the sample shorter */
    
      Flow ClaimsFlow {
        /* type 2: (event production) */
        command SubmitClaim emits event ClaimSubmitted
    
        /* type 2 alternative: (event production) */
        operation submitClaim emits event ClaimSubmitted
    
        /* type 1: (command invokation) */
        event ClaimSubmitted triggers command CheckClaimDocumentation
    
        /* type 1 alternative: (operation invokation) */
        event ClaimSubmitted triggers operation checkClaimDocumentation
      }
    }
    

    Emitting Events

    A command or operation can emit multiple events. This is expressed with the + sign as follows:

    command SubmitClaim emits event Event1 + Event2 + Event3 // and so on... (emit as many events as you want)
    
    // alternative
    operation submitClaim emits event Event1 + Event2
    

    The example above illustrates that an operation emits multiple events events, which means, all events are emitted!

    There are situations in which you want to express that one OR an other event is emitted. In this case, we distinguish between exclusive OR (XOR: only one of the listed events is emitted) and inclusive OR (multiple events can be thrown, but not necessarily all). For these two cases we use the symbols X and O, inspired by BPMN.

    Exclusive variant:

    command SubmitClaim emits event Event1 X Event2 X Event3
    
    // alternative
    operation submitClaim emits event Event1 X Event2
    

    Inclusive variant:

    command SubmitClaim emits event Event1 O Event2 O Event3
    
    // alternative
    operation submitClaim emits event Event1 O Event2
    

    Symbol Summary:

    The following table summarizes the three symbols that are supported here:

    Symbol Meaning Corresponding BPMN gateways (in German)
    + ALL listed events are emitted. Parallel Gateway
    X or x ONLY ONE of the listed events is emitted. Exclusive Gateway
    O or o ONE OR MULTIPLE, BUT NOT NECESSARILY ALL of the listed events are emitted. Inclusive Gateway

    Note: It is not possible to mix the symbols inside a single flow step (we do not implement operator precedence).

    Command/Operation triggered by multiple Events

    On the other hand a command or operation may only be triggered if multiple events happen. This is modelled as follows:

    event ClaimSubmitted + ContractChecked triggers command AssessClaim
    
    // alternative
    event ClaimSubmitted + ContractChecked triggers operation assessClaim
    

    This example expresses that both events (ClaimSubmitted as well as ContractChecked) must have been emitted so that AssessClaim is triggered.

    Note: At this point only the + symbol is supported.

    Triggering Commands/Operations

    Similar to the event productions explained above, it is possible that events trigger multiple commands/operations. This syntax works with the symbols +, X, and O again.

    Parallel variant:

    event ClaimSubmitted triggers command CheckClaim + CheckPolicy
    
    // operation alternative:
    event ClaimSubmitted triggers operation checkClaim + checkPolicy
    

    This example expresses that all listed operations/commands are triggered (parallel).

    Exclusive variant:

    event ClaimSubmitted triggers command CheckClaim X CheckPolicy
    
    // operation alternative:
    event ClaimSubmitted triggers operation checkClaim X checkPolicy
    

    This example means that only one of the commands/operations is triggered.

    Inclusive variant:

    event ClaimSubmitted triggers command CheckClaim O CheckPolicy
    
    // operation alternative:
    event ClaimSubmitted triggers operation checkClaim O checkPolicy
    

    This example expresses that one or multiple but not necessarily all commands/operations are triggered.

    Symbol summary:

    The following table summarizes the meaning of the supported symbols in the command/operation invokation steps:

    Symbol Meaning Corresponding BPMN gateways
    + ALL listed commands/operations are triggered. Parallel Gateway
    X or x ONLY ONE of the listed commands/operations is triggered. Exclusive Gateway
    O or o ONE OR MULTIPLE, BUT NOT NECESSARILY ALL of the listed commands/operations are triggered. Inclusive Gateway

    Commands/Operations delegating to Aggregates

    Commands and operations are typically delegated to an Aggregate. This also corresponds to the illustration of the DDD crew depicted above.

    In CML this means that you can optionally add the following reference to event production steps (Type 2 above):

    command SubmitClaim delegates to Claims emits event Event1 X Event2 X Event3
    
    // alternative
    operation submitClaim delegates to Claims emits event Event1 X Event2
    

    Note that this is a reference to an Aggregate that must actually exist in your Bounded Context. In the example above there must be an Aggregate called Claims in the same Bounded Context.

    State Transitions

    In case your flow step delegates to an Aggregate (contains part delegates to) as in the example above, it is possible to declare the state transition that is caused right here.

    Note: State transition can be modelled on service and domain object operations as documented on the Aggregate doc page.

    If you use flows you can add the state transitions to the flow steps instead of modeling them inside the Aggregate (operations). The state transitions can be added to the event production steps (type 2 above) as follows (optionally):

    command SubmitClaim delegates to Claims [ -> SUBMITTED ] emits event Event1 X Event2 X Event3
    
    // alternative
    operation submitClaim delegates to Claims [ -> SUBMITTED ] emits event Event1 X Event2
    

    For a complete documentation and examples for the state transition grammar we refer to the Aggregate page.

    Actors

    Commands or operations can be triggered by actors/users. In CML you can specify this (optionally) as follows:

    command SubmitClaim [ initiated by "Customer" ] delegates to Claims [ -> SUBMITTED ] emits event Event1
    
    // alternative
    operation submitClaim [ initiated by "Customer" ] delegates to Claims [ -> SUBMITTED ] emits event Event1
    

    Visualization with BPMN Sketch Miner

    Once you modelled an application flow you can visualize it in the BPMN Sketch Miner. Use Context Mapper’s BPMN Sketch Miner generator to generate the Sketch Miner DSL output or directly open the visualization in the browser.

    An example output: (visualization powered by BPMN Sketch Miner)

    BPMN Sketch Miner Example

    Note: This is a process we took (modeled) from the Lakeside Mutual project.

    Coordination between Application Services

    In case you want to model processes/workflows that span multiple Bounded Contexts without the use of event/command syntax, you can also do so by defining a coordination between application services. This language feature is based on the concept of Coordination from the “Software Architecture: The Hard Parts” book by Neal Ford and others. They define Coordination as a property of workflows, which can either be orchestrated (the workflow steps are coordinated by a central component) or choreographed (each step of the workflow shares coordination logic).

    To model these workflows in Context Mapper, you use the coordination construct inside the application layer of a Bounded Context. The following example illustrates this using an adaptation of the same claims processing concept from before:

    ContextMap {
      contains ClaimsManagement
      contains InsuranceManagement
      contains PaymentManagement
    
      ClaimsManagement <-> InsuranceManagement
      ClaimsManagement <-> PaymentManagement
    }
    
    BoundedContext ClaimsManagement {
      Application {
        Coordination SubmitValidClaimCoordination {
          ClaimsManagement::ClaimsApplicationService::submitClaim;
          InsuranceManagement::InsuranceApplicationService::checkInsurance;
          ClaimsManagement::ClaimsApplicationService::acceptClaim;
          PaymentManagement::PaymentApplicationService::performPayment;
        }
    
        Service ClaimsApplicationService {
          void submitClaim(@Claim claim);
          void acceptClaim(@Claim claim);
        }
      }
    }
    
    BoundedContext InsuranceManagement {
      Application {
        Service InsuranceApplicationService {
          void checkInsurance(@Claim claim);
        }
      }
    }
    
    BoundedContext PaymentManagement {
      Application {
        Service PaymentApplicationService {
          void performPayment(@Claim claim);
        }
      }
    }
    

    Note: The type of workflow coordination (orchestration or choreography) is not explicitly supported in the syntax, but can still be modeled by assuming that the Bounded Context where the coordination is defined serves as either the orchestrator, or the start of the choreography.

    Coordination Grammar

    In CML, coordinations are composed of coordination steps. Each coordination step represents a call to an application service operation, which can be defined inside the same Bounded Context or in an outer Bounded Context.

    To correctly reference an application service operation, a coordination step is divided into three segments, separated by the :: symbol:

    • The name of the Bounded Context where the operation is defined;
    • The name of the application service where the operation is defined;
    • And the name of the operation.

    The following is an example of a coordination step:

    // Bounded context name :: application service name :: service operation name
    ClaimsManagement::ClaimsApplicationService::submitClaim;
    

    Each of the three segments of a coordination step is also subject to certain syntax rules to maintain the integrity of the model. Respectively, these are:

    • A coordination step can only reference outer Bounded Contexts that are upstream (by means of an upstream/downstream relationship or a symmetrical relationship in a Context Map definition);
    • A coordination step can only reference services defined in the application layer of a Bounded Context (which means domain services defined inside aggregates are not applicable);
    • A reference to a service operation in a coordination step should be unique within the service.

    Coordination visualization in BPMN

    Like flows, coordinations can also be visualized with BPMN Sketch Miner. The following example shows the output when using Context Mapper’s BPMN Sketch Miner generator on coordinations:

    BPMN Sketch Miner Example

    Improve this page on GitHub
    ← PreviousTactic DDD Syntax Next →User Requirements
    © 2026 Context Mapper contributors
    • GitHub
    • Get Involved
    • Background & Publications
    • RSS