v6.2.0 Release Notes

Dec 17, 2020 • Stefan Kapferer

Today we released version 6.2.0 of Context Mapper 🥳

This new Context Mapper version introduces new CML language features to model application layers with application services and commands, event/command flows (potentially as a result of an Event Storming), and the lifecycle of Aggregates. We further added a generator that visualizes the event flows powered by BPMN Sketch Miner and enhanced the PlantUML generator with state diagrams. The MDSL generator as well as the PlantUML class diagram generator have been enhanced to support the new application layer and flow features. Last but not least, this release contains a “proof of concept” for automated model transformations that support Story Splitting.

Summary of Changes

As always, if you have any issues or other feedback, please let us know.

Aggregate Lifecycle and State Transitions

The CML syntax can express the states of Aggregates now. States are defined as enums marked as follows:

Aggregate Contract {
  Entity Contract {
    aggregateRoot

    - State aggregateState
    - ContractId identifier
    - Customer client
    - List<Product> products
  }

  enum State {
    aggregateLifecycle
    CREATED, POLICE_CREATED, RECALLED
  }
}

Users can then specify whether an operation is a read-only or a write operation. For write operations, the state transition that the operation performs (supported on operations in services or domain objects such as entities) can be defined as well:

Service ContractService {
    @ContractId createContract(@Contract contrace) : write [ -> CREATED];
    @Contract getContract(@ContractId contractId) : read-only;
    boolean createPolicy(@ContractId contractId) : write [ CREATED -> POLICE_CREATED ];
    boolean recall(@ContractId contractId) : write [ CREATED, POLICE_CREATED -> RECALLED ];
  }

More details about the new syntax for Aggregate lifecycles and state transitions can be found here on the Aggregate page of the language reference.

Application Layer and Event Flows

DDD distinguishes between domain services and application services. Inside a Bounded Context you can now model an application layer in CML. Such an application layer can contain application services and commands that are initiated by users or external systems:

BoundedContext ClaimsManagement {
  Application {
    Service ClaimsApplicationService {
      void submitClaim(@Claim claim);
      void checkInsurance(@Claim claim);
    }

    Command AcceptClaim {
      - Claim claim
    }
    Command 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
    }
  }
}

In addition to that, the application layer can contain event/command flows. They can be used to model processes and bring events and commands into a timeline (for example as a result of an Event Storming).

An example:

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
  }
}

In this case the modeled flow is based on the output of our Event Storming tutorial:

Lakeside Mutual Claim Processing Event Storming

Checkout our Application and Process Layer language reference page for more details.

BPMN Sketch Miner Generator

The BPMN Sketch Miner generator visualizes the CML event/command flows introduced above powered by the BPMN Sketch Miner tool.

We modeled the following CML flow, as another example:

/**
 * A flow inspired by the Lakeside Mutual project (https://github.com/Microservice-API-Patterns/LakesideMutual).
 * Find the original process visualization here:
 * https://github.com/Microservice-API-Patterns/LakesideMutual/blob/master/policy-management-backend/src/main/java/com/lakesidemutual/policymanagement/domain/insurancequoterequest/RequestStatus.java
 **/
BoundedContext InsuranceQuotes {
  Application {
    Flow QuoteRequestFlow {
      operation submitRequest delegates to QuoteRequest[-> SUBMITTED] emits event RequestSubmitted
      event RequestSubmitted + RequestSubmitted triggers operation checkRequest
      operation checkRequest delegates to QuoteRequest[SUBMITTED -> RECEIVED X REJECTED] emits event QuoteReceived X RequestRejected
      event QuoteReceived triggers operation receiveAndCheckQuote
      operation receiveAndCheckQuote delegates to QuoteRequest[RECEIVED -> REJECTED X ACCEPTED X EXPIRED] emits event QuoteRejected X QuoteAccepted X QuoteExpired
      event QuoteAccepted triggers operation accept
      operation accept delegates to QuoteRequest[ACCEPTED -> POLICY_CREATED X EXPIRED] emits event PolicyCreated X QuoteExpired
    }
  }
  Aggregate QuoteRequest {
    Entity Request {
      aggregateRoot
    }
    DomainEvent RequestSubmitted
    DomainEvent QuoteReceived
    DomainEvent RequestRejected
    DomainEvent QuoteRejected
    DomainEvent QuoteAccepted
    DomainEvent QuoteExpired
    DomainEvent PolicyCreated
    Service QuoteRequestService {
      void submitRequest(@Request request);
      void checkRequest(@Request request);
      void receiveAndCheckQuote(@Request request);
      void reject(@Request request);
      void accept(@Request request);
    }
    enum RequestState {
      aggregateLifecycle
       SUBMITTED, RECEIVED, REJECTED, ACCEPTED, EXPIRED, POLICY_CREATED
    }
  }
}

By using this generator users can visualize this flow quickly and get the following output:
(powered by BPMN Sketch Miner)

BPMN Sketch Miner Output Example

More details on this generator and how to use it can be found on the BPMN Sketch Miner Generator page.

PlantUML Generator Adjustments

The PlantUML class diagram generator has been enhanced so that services and commands of the application layer are respected as well. An example output:

PlantUML: Enhanced class diagram generator

In addition to that, the generator now produces state diagrams that visualize the Aggregate lifecycles introduced above: (in case you modeled the corresponding states and state transitions)

PlantUML: Enhanced class diagram generator

MDSL Generator Adjustments

The MDSL generator has been enhanced as follows:

  • A new endpoint is generated for the application layer.
    • The endpoint contains the operations of the application services and/or commands.
  • Events and/or commands that are used as parameters or return types of operations in CML are now properly mapped to corresponding data types in MDSL.

Story Splitting (PoC)

With our story splitting proof-of-concept (PoC) we offer a first model transformation that can split a CML user story. We only implemented one exemplary transformation for now, but other splitting patterns could be supported in the future. This first PoC provides a transformation that can “split a story by its verb” quickly.

For example, a user may write the following user story in CML:

UserStory Account_Admin_Story {
    As an "Admin" I want to "manage" an "Account" so that "can enable users to work with the system."
}

By providing verbs to split the story, for example create, edit, and cancel, you can split this story very quickly: (one click and typing the verbs)

UserStory Account_Admin_Story split by Account_Admin_Story_Split {
	As an "Admin" I want to "manage" an "Account" so that "can enable users to work with the system."
}

UserStory Account_Admin_Story_Split {
	As an "Admin"
	I want to "cancel" an "Account"
	I want to "edit" an "Account"
	I want to create an "Account"
	so that "can enable users to work with the system."
}

You can find more details on how you can use this transformation on our documentation page.

Semantic Validator Changes

  • Domain names must be unique now (duplicate domain names no longer compile in CML models).
  • A subdomain can no longer have the same name as its domain.

Summary

That’s it for this new release of Context Mapper. As always, if you have any issues or other feedback, please let us know.