├── .github ├── FUNDING.yml └── workflows │ └── build.yml ├── .gitignore ├── .gitpod.Dockerfile ├── .gitpod.yml ├── .java-version ├── .servicecutter.yml ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main └── cml ├── architectural-refactorings ├── AR-01-Split-Aggregate-by-Entities │ ├── README.md │ ├── example-input.cml │ └── example-output.cml ├── AR-02-Split-Bounded-Context-by-Features │ ├── README.md │ ├── example-input.cml │ └── example-output.cml ├── AR-03-Split-Bounded-Context-by-Owner │ ├── README.md │ ├── example-input.cml │ └── example-output.cml ├── AR-04-Extract-Aggregates-by-Volatility │ ├── README.md │ ├── example-input.cml │ └── example-output.cml ├── AR-05-Extract-Aggregates-by-Cohesion │ ├── README.md │ ├── example-input.cml │ └── example-output.cml ├── AR-06-Merge-Aggregates │ ├── README.md │ ├── example-input.cml │ └── example-output.cml ├── AR-07-Merge-Bounded-Contexts │ ├── README.md │ ├── example-input.cml │ └── example-output.cml ├── AR-08-Extract-Shared-Kernel │ ├── README.md │ ├── example-input.cml │ └── example-output.cml ├── AR-09-Suspend-Partnership │ ├── README.md │ ├── example-input.cml │ ├── example-output-a.cml │ ├── example-output-b.cml │ └── example-output-c.cml ├── AR-10-Change-Shared-Kernel-To-Partnership │ ├── README.md │ ├── example-input.cml │ └── example-output.cml ├── AR-11-Change-Partnership-To-Shared-Kernel │ ├── README.md │ ├── example-input.cml │ └── example-output.cml └── README.md ├── bounded-context-canvas-example ├── Bounded-Context-Canvas-Example-Stage-1.cml └── README.md ├── context-mapper-example ├── ContextMapper-Example-Stage-1.cml ├── ContextMapper-Example-Stage-2.cml ├── ContextMapper-Example-Stage-3.cml ├── ContextMapper-Example-Stage-4.cml ├── README.md ├── ServiceCutterLibraryContract.mdsl └── images │ ├── ContextMapper-Example-Simple_ComponentDiagram.puml │ └── ContextMapper-Example-Simple_ContextMap.png ├── ddd-sample ├── DDD-Sample-Stage-1.cml ├── DDD-Sample-Stage-2.cml ├── DDD-Sample-Stage-3.cml ├── DDD-Sample-Stage-4.cml ├── DDD-Sample-Stage-5.cml ├── DDD-Sample_Alternative-Relationship-Syntax.cml ├── README.md └── images │ ├── DDD-Cargo-Tracking-ContextMap-Illustration.png │ └── DDD-Cargo-Tracking-ContextMap-Illustration.svg ├── ddd-service-cutting-sample ├── DDD-Sample.cml └── DDD-Sample.scl ├── insurance-example ├── Insurance-Example-Stage-1.cml ├── Insurance-Example-Stage-2.cml ├── Insurance-Example-Stage-3.cml ├── Insurance-Example-Stage-4.cml ├── Insurance-Example-Stage-5.cml ├── Insurance-Example_Alternative-Relationship-Syntax.cml ├── Insurance-Example_Team-Map.cml ├── README.md └── images │ ├── ContextMap-Illustration.png │ ├── ContextMap-Illustration.svg │ ├── TeamMap-Illustration-1.png │ └── TeamMap-Illustration-2.png ├── lakeside-mutual ├── LakesideMutual.cml ├── QuoteRequestFlow.cml ├── README.md ├── images │ ├── ContextMap-Illustration.png │ └── event-storming-result.jpg └── ooad-example.cml ├── microservice-generation └── JDL-example │ ├── generated-insurance-microservices.jdl │ ├── generated-insurance-microservices.png │ └── insurance-example-for-JDL-generation.cml ├── ooad-sample-claims ├── README.md ├── claims-use-case-entities.jdl ├── claims-use-case-entities.png └── claims-use-case.cml ├── same-day-delivery-shop └── stakeholders-and-values.cml ├── service-coordination-example └── InsuranceClaimCoordination.cml └── workflow-samples ├── ClaimsManagement_with_Commands.cml ├── ClaimsManagement_with_ServiceOperations.cml ├── InsuranceQuoteRequest.cml ├── InsuranceQuoteRequest_StateMachineWithoutEventsAndCommands.cml └── InsuranceQuoteRequest_StateMachineWithoutEventsAndCommands_Entity.cml /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: stefan-ka 2 | 3 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '0 0 * * 0' # weekly 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Set up JDK 16 | uses: actions/setup-java@v4 17 | with: 18 | java-version: 17 19 | distribution: 'temurin' 20 | - name: Build with Gradle 21 | run: ./gradlew clean build 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | /bin 4 | /src-gen 5 | /out 6 | 7 | # Log file 8 | *.log 9 | 10 | # BlueJ files 11 | *.ctxt 12 | 13 | # Mobile Tools for Java (J2ME) 14 | .mtj.tmp/ 15 | 16 | # Package Files # 17 | *.jar 18 | *.war 19 | *.nar 20 | *.ear 21 | *.zip 22 | *.tar.gz 23 | *.rar 24 | 25 | # Gradle # 26 | .gradle 27 | build 28 | 29 | # Eclipse # 30 | *.project 31 | *.classpath 32 | **/.settings 33 | 34 | # IntelliJ # 35 | **/.idea 36 | 37 | # VS Code # 38 | **/.vscode 39 | 40 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 41 | hs_err_pid* 42 | 43 | #MacOS 44 | .DS_Store 45 | -------------------------------------------------------------------------------- /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-full 2 | 3 | # Install Graphviz 4 | RUN sudo apt-get update \ 5 | && sudo apt-get -y install graphviz 6 | 7 | # Install Java 8 | RUN bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh && \ 9 | sdk install java 17.0.8-tem && \ 10 | sdk default java 17.0.8-tem" 11 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - init: ./gradlew build 3 | image: 4 | file: .gitpod.Dockerfile 5 | vscode: 6 | extensions: 7 | - jebbs.plantuml 8 | - contextmapper.context-mapper-vscode-extension 9 | - vscjava.vscode-java-pack 10 | - asciidoctor.asciidoctor-vscode 11 | -------------------------------------------------------------------------------- /.java-version: -------------------------------------------------------------------------------- 1 | 11.0 2 | -------------------------------------------------------------------------------- /.servicecutter.yml: -------------------------------------------------------------------------------- 1 | algorithm: MARKOV_CLUSTERING 2 | algorithmParams: 3 | leungDelta: 0.55 4 | mclExpansionOperations: 2.0 5 | mclPowerCoefficient: 2.0 6 | leungM: 0.1 7 | cwNodeWeighting: 0.0 8 | priorities: 9 | Identity & Lifecycle Commonality: M 10 | Security Constraint: M 11 | Storage Similarity: XS 12 | Security Criticality: XS 13 | Latency: M 14 | Structural Volatility: XS 15 | Consistency Criticality: XS 16 | Predefined Service Constraint: M 17 | Availability Criticality: XS 18 | Semantic Proximity: M 19 | Consistency Constraint: M 20 | Shared Owner: M 21 | Content Volatility: XS 22 | Security Contextuality: M 23 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "java" 3 | id "org.xtext.builder" version "4.0.0" 4 | } 5 | 6 | group 'org.contextmapper.dsl' 7 | version '1.0-SNAPSHOT' 8 | 9 | sourceCompatibility = '11' 10 | targetCompatibility = '11' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | xtextLanguages "org.contextmapper:context-mapper-dsl:${cmlVersion}" 18 | 19 | implementation "org.eclipse.xtend:org.eclipse.xtend.lib:${xtendLibVersion}" 20 | implementation "org.contextmapper:context-mapper-dsl:${cmlVersion}" 21 | 22 | testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}") 23 | testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}") 24 | } 25 | 26 | xtext { 27 | languages { 28 | cml { 29 | fileExtensions = [ 'cml' ] 30 | setup = 'org.contextmapper.dsl.ContextMappingDSLStandaloneSetup' 31 | generator.outlet.producesJava = true 32 | } 33 | } 34 | 35 | sourceSets { 36 | main { 37 | srcDir 'src/main/cml' 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # dependency versions 2 | cmlVersion=6.12.0 3 | junitVersion=5.5.2 4 | xtendLibVersion=2.19.0 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-mapper-examples/0854134a15fa70384c4e192cd5e32485ca0d22b5/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Oct 10 14:46:22 CEST 2019 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'context-mapper-examples' 2 | 3 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-01-Split-Aggregate-by-Entities/README.md: -------------------------------------------------------------------------------- 1 | # AR-1: Split Aggregate by Entities 2 | Splits an aggregate which contains multiple entities and produces one aggregate per entity. 3 | 4 | ## Context & Rationales 5 | On the level of entities we typically try to group attributes or [nanoentities in the terminology of ServiceCutter](https://servicecutter.github.io/) 6 | together, which belong to the same identity and share a common lifecycle. Thereby we aim to reduce the coupling between the entities 7 | and increase the cohesion within the entities. 8 | 9 | * **See also**: Coupling criterion [Identity and Lifecycle Commonality](https://github.com/ServiceCutter/ServiceCutter/wiki/CC-1-Identity-and-Lifecycle-Commonality) 10 | of [ServiceCutter](https://servicecutter.github.io/). 11 | 12 | The same approach can be applied on the aggregate level. The aggregates within one bounded context shall be structured in a way which 13 | reduces coupling between the aggregates and increases the cohesion within them. 14 | 15 | As your bounded context develops you may face the problem that an aggregate contains entities which exhibit an unsatisfying 16 | cohesiveness. In such a case you may want to split your aggregate into multiple aggregates in order to improve coupling and cohesion. 17 | 18 | ## Goal 19 | This Architectural Refactoring (AR) splits an aggregate and creates one aggregate for each entity. This AR can be applied when 20 | the entities within an aggregate exhibit unsatisfying cohesiveness and you decide to create multiple aggregates for the single 21 | entities. 22 | 23 | **Inverse AR's:** 24 | * [AR-6: Merge Aggregates](./../AR-6-Merge-Aggregates) 25 | 26 | ## Preconditions 27 | * The input aggregate must contain **at least two entities**. 28 | 29 | ## Input 30 | * The aggregate which shall be split. 31 | 32 | ## Output 33 | * Multiple aggregates which contain one entity each. 34 | * All entities become **aggregate roots** within their own aggregates. 35 | 36 | ## Example 37 | The following two CML snippets show an example _input_ and _output_ illustrating how this AR works. 38 | 39 | ### Input 40 | The following bounded context contains one aggregate with two entities: 41 | ``` 42 | BoundedContext CustomerManagementContext { 43 | type = FEATURE 44 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 45 | implementationTechnology = "Java, JEE Application" 46 | responsibilities = "Customers, Addresses" 47 | 48 | /* With a Right-Click on the 'Customers' aggregate you can call the 'Split Aggregate by Entities' refactoring in the 49 | * 'Context Mapper: Refactor' context menu. The refactoring will create a new aggregate and move one of the two entities 50 | * to the new aggregate (see the result in the 'split-aggregate-by-entities-output-example.cml' file). 51 | */ 52 | Aggregate Customers { 53 | Entity Customer { 54 | aggregateRoot 55 | 56 | String firstname 57 | String lastname 58 | - List
addresses 59 | } 60 | Entity Address { 61 | String street 62 | int postalCode 63 | String city 64 | } 65 | } 66 | } 67 | ``` 68 | 69 | ### Output 70 | Applying the AR **Split Aggregate by Entities** produces two aggregates, one for each entity: 71 | ``` 72 | BoundedContext CustomerManagementContext { 73 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 74 | responsibilities = "Customers, Addresses" implementationTechnology = "Java, JEE Application" 75 | Aggregate Customers { 76 | Entity Address { 77 | aggregateRoot 78 | 79 | String street 80 | int postalCode 81 | String city 82 | } 83 | } 84 | /* The newly created aggregate after applying 'Split Aggregate by Entities' on the aggregate in the input file 85 | * 'example-input.cml'. 86 | * 87 | * Note that the refactoring does not produce meaningful aggregate names. You can use the 'Rename Element' 88 | * refactoring (SHIFT-ALT-R) to rename the new aggregate. 89 | */ 90 | Aggregate NewAggregate1 { 91 | Entity Customer { 92 | aggregateRoot 93 | 94 | String firstname 95 | String lastname 96 | - List
addresses 97 | } 98 | } 99 | } 100 | ``` 101 | 102 | ### Example Sources 103 | * Example input source: [example-input.cml](./example-input.cml) 104 | * Example output source: [example-output.cml](./example-output.cml) 105 | 106 | ## Further documentation 107 | * Context Mapper [Architectural Refactorings (ARs)](https://contextmapper.org/docs/architectural-refactorings/) 108 | * [AR-1: Split Aggregate by Entities](https://contextmapper.org/docs/ar-split-aggregate-by-entities/) 109 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-01-Split-Aggregate-by-Entities/example-input.cml: -------------------------------------------------------------------------------- 1 | /* This is an example input file for the 'Split Aggregate by Entities' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains CustomerManagementContext 4 | 5 | } 6 | 7 | BoundedContext CustomerManagementContext { 8 | type = FEATURE 9 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 10 | implementationTechnology = "Java, JEE Application" 11 | responsibilities = "Customers, Addresses" 12 | 13 | /* With a Right-Click on the 'Customers' aggregate you can call the 'Split Aggregate by Entities' refactoring in the 14 | * 'Context Mapper: Refactor' context menu. The refactoring will create a new aggregate and move one of the two entities 15 | * to the new aggregate (see the result in the 'split-aggregate-by-entities-output-example.cml' file). 16 | */ 17 | Aggregate Customers { 18 | Entity Customer { 19 | aggregateRoot 20 | 21 | SocialInsuranceNumber sin 22 | String firstname 23 | String lastname 24 | - List
addresses 25 | } 26 | Entity Address { 27 | String street 28 | int postalCode 29 | String city 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-01-Split-Aggregate-by-Entities/example-output.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Split Aggregate by Entities' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains CustomerManagementContext 4 | 5 | } 6 | 7 | BoundedContext CustomerManagementContext { 8 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 9 | responsibilities = "Customers, Addresses" implementationTechnology = "Java, JEE Application" 10 | Aggregate Customers { 11 | Entity Address { 12 | aggregateRoot 13 | 14 | String street 15 | int postalCode 16 | String city 17 | } 18 | } 19 | /* The newly created aggregate after applying 'Split Aggregate by Entities' on the aggregate in the input file 20 | * 'example-input.cml'. 21 | * 22 | * Note that the refactoring does not produce meaningful aggregate names. You can use the 'Rename Element' 23 | * refactoring (SHIFT-ALT-R) to rename the new aggregate. 24 | */ 25 | Aggregate NewAggregate1 { 26 | Entity Customer { 27 | aggregateRoot 28 | 29 | SocialInsuranceNumber sin 30 | String firstname 31 | String lastname 32 | - List
addresses 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-02-Split-Bounded-Context-by-Features/README.md: -------------------------------------------------------------------------------- 1 | # AR-2: Split Bounded Context by Features 2 | Splits a bounded context by grouping those aggregates together into one bounded context which are used by the same feature: use case(s) and/or user stories. 3 | 4 | **Hint:** An aggregate in CML can belong to multiple use cases and/or user stories (therefore the plural _Features_ in the AR name). 5 | 6 | ## Context & Rationales 7 | By decomposing a system into multiple bounded contexts we aim for loose coupling between the bounded context and a high cohesion 8 | within them. One approach to achieve this and to decompose a system into components or (micro-) services is to split by use cases and/or user stories. 9 | 10 | **See also:** 11 | * Coupling criterion [Semantic Proximity](https://github.com/ServiceCutter/ServiceCutter/wiki/CC-2-Semantic-Proximity) of [ServiceCutter](https://servicecutter.github.io/) 12 | * [How to decompose the application into services?](https://microservices.io/patterns/microservices.html#how-to-decompose-the-application-into-services) by [Chris Richardson](https://microservices.io/book) 13 | * [Single responsibility principle](https://en.wikipedia.org/wiki/Single_responsibility_principle) 14 | 15 | In Context Mapper you can assign multiple use cases and/or user stories to an aggregate, which allows you to model by which features an aggregate 16 | is used. Consult our [aggregate documentation page](https://contextmapper.org/docs/aggregate/#aggregate-use-cases) to see 17 | how this can be modeled in CML. The [user requirements](https://contextmapper.org/docs/user-requirements/) page documents how you specify your user stories and/or use cases. 18 | 19 | ## Goal 20 | This Architectural Refactoring (AR) splits a bounded context by use cases and/or user stories. This means, it creates bounded contexts containing 21 | aggregates which are used by the same cases/stories. It can be applied if your model exhibits a bounded contexts with aggregates which 22 | are used by different features. 23 | 24 | **Inverse AR's:** 25 | * [AR-7: Merge Bounded Contexts](./../AR-7-Merge-Bounded-Contexts) 26 | 27 | ## Preconditions 28 | * The bounded context must contain **at least two aggregates**. 29 | * The aggregates must be **assigned to different use cases and/or user stories**. 30 | 31 | ## Input 32 | * One bounded context. 33 | 34 | ## Output 35 | * The AR creates multiple bounded contexts. Each bounded context contains one or more aggregates which are used by the same 36 | use cases and/or user stories. 37 | 38 | ## Example 39 | The following two CML snippets show an example _input_ and _output_ illustrating how this AR works. 40 | 41 | ### Input 42 | The following bounded context three aggregates which are used by two different use cases: 43 | ``` 44 | /* With a right-click on the 'PolicyManagementContext' bounded context you can execute the 'Split Bounded Context by Features' refactoring. 45 | * It will split the existing bounded context and group the two aggregates of the 'CreateOffer4Customer' use case together. The 'Contract' 46 | * aggregate used by the 'UpdateContract' use case will be separated. 47 | */ 48 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 49 | type = FEATURE 50 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 51 | responsibilities = "Offers, Contracts, Policies" 52 | implementationTechnology = "Java, Spring App" 53 | 54 | Aggregate Offers { 55 | useCases = CreateOffer4Customer 56 | 57 | Entity Offer { 58 | aggregateRoot 59 | 60 | int offerId 61 | - Customer client 62 | - List products 63 | BigDecimal price 64 | } 65 | } 66 | Aggregate Products { 67 | useCases = CreateOffer4Customer 68 | 69 | Entity Product { 70 | aggregateRoot 71 | 72 | - ProductId identifier 73 | String productName 74 | } 75 | ValueObject ProductId { 76 | int productId key 77 | } 78 | } 79 | Aggregate Contract { 80 | useCases = UpdateContract 81 | 82 | Entity Contract { 83 | aggregateRoot 84 | 85 | - ContractId identifier 86 | - Customer client 87 | - List products 88 | } 89 | ValueObject ContractId { 90 | int contractId key 91 | } 92 | 93 | Entity Policy { 94 | int policyNr 95 | - Contract contract 96 | BigDecimal price 97 | } 98 | } 99 | } 100 | ``` 101 | 102 | ### Output 103 | Applying the AR **Split Bounded Context by Features** produces two bounded context, one for each use case: 104 | ``` 105 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 106 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 107 | responsibilities = "Offers, Contracts, Policies" 108 | implementationTechnology = "Java, Spring App" 109 | 110 | Aggregate Contract { 111 | useCases = UpdateContract 112 | 113 | Entity Contract { 114 | aggregateRoot 115 | 116 | - ContractId identifier 117 | - Customer client 118 | - List products 119 | } 120 | ValueObject ContractId { 121 | int contractId key 122 | } 123 | 124 | Entity Policy { 125 | int policyNr 126 | - Contract contract 127 | BigDecimal price 128 | } 129 | } 130 | } 131 | 132 | /** 133 | * A new bounded context created by the 'Split Bounded Context by Features' refactoring applied to 'example-input.cml'. 134 | * 135 | * Note that the refactoring does not produce meaningful bounded context names. You can use the 'Rename Element' refactoring (SHIFT-ALT-R) 136 | * to rename the new aggregate. 137 | */ 138 | BoundedContext NewBoundedContext1 { 139 | Aggregate Offers { 140 | useCases = CreateOffer4Customer 141 | 142 | Entity Offer { 143 | aggregateRoot 144 | 145 | int offerId 146 | - Customer client 147 | - List products 148 | BigDecimal price 149 | } 150 | } 151 | Aggregate Products { 152 | useCases = CreateOffer4Customer 153 | 154 | Entity Product { 155 | aggregateRoot 156 | 157 | - ProductId identifier 158 | String productName 159 | } 160 | ValueObject ProductId { 161 | int productId key 162 | } 163 | } 164 | } 165 | ``` 166 | 167 | ### Example Sources 168 | * Example input source: [example-input.cml](./example-input.cml) 169 | * Example output source: [example-output.cml](./example-output.cml) 170 | 171 | ## Further documentation 172 | * Context Mapper [Architectural Refactorings (ARs)](https://contextmapper.org/docs/architectural-refactorings/) 173 | * [AR-2: Split Bounded Context by Features](https://contextmapper.org/docs/ar-split-bounded-context-by-use-cases/) 174 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-02-Split-Bounded-Context-by-Features/example-input.cml: -------------------------------------------------------------------------------- 1 | /* This is an example input file for the 'Split Bounded Context by Features' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains PolicyManagementContext 4 | 5 | } 6 | 7 | /* With a right-click on the 'PolicyManagementContext' bounded context you can execute the 'Split Bounded Context by Features' refactoring. 8 | * It will split the existing bounded context and group the two aggregates of the 'CreateOffer4Customer' use case together. The 'Contract' 9 | * aggregate used by the 'UpdateContract' use case will be separated. 10 | */ 11 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 12 | type = FEATURE 13 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 14 | responsibilities = "Offers, Contracts, Policies" 15 | implementationTechnology = "Java, Spring App" 16 | 17 | Aggregate Offers { 18 | useCases = CreateOffer4Customer 19 | 20 | Entity Offer { 21 | aggregateRoot 22 | 23 | int offerId 24 | Customer client 25 | - List products 26 | BigDecimal price 27 | } 28 | } 29 | Aggregate Products { 30 | useCases = CreateOffer4Customer 31 | 32 | Entity Product { 33 | aggregateRoot 34 | 35 | - ProductId identifier 36 | String productName 37 | } 38 | ValueObject ProductId { 39 | int productId key 40 | } 41 | } 42 | Aggregate Contract { 43 | useCases = UpdateContract 44 | 45 | Entity Contract { 46 | aggregateRoot 47 | 48 | - ContractId identifier 49 | Customer client 50 | - List products 51 | } 52 | ValueObject ContractId { 53 | int contractId key 54 | } 55 | 56 | Entity Policy { 57 | int policyNr 58 | - Contract contract 59 | BigDecimal price 60 | } 61 | } 62 | } 63 | 64 | /* Domain & Subdomain Definitions */ 65 | Domain InsuranceDomain { 66 | Subdomain PolicyManagementDomain { 67 | type = CORE_DOMAIN 68 | domainVisionStatement = "Subdomain managing contracts and policies." 69 | } 70 | } 71 | 72 | UseCase UpdateContract 73 | UseCase CreateOffer4Customer 74 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-02-Split-Bounded-Context-by-Features/example-output.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Split Bounded Context by Features' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains PolicyManagementContext 4 | 5 | } 6 | 7 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 8 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 9 | responsibilities = "Offers, Contracts, Policies" 10 | implementationTechnology = "Java, Spring App" 11 | 12 | Aggregate Contract { 13 | useCases = UpdateContract 14 | 15 | Entity Contract { 16 | aggregateRoot 17 | 18 | - ContractId identifier 19 | Customer client 20 | - List products 21 | } 22 | ValueObject ContractId { 23 | int contractId key 24 | } 25 | 26 | Entity Policy { 27 | int policyNr 28 | - Contract contract 29 | BigDecimal price 30 | } 31 | } 32 | } 33 | 34 | /** 35 | * A new bounded context created by the 'Split Bounded Context by Features' refactoring applied to 'example-input.cml'. 36 | * 37 | * Note that the refactoring does not produce meaningful bounded context names. You can use the 'Rename Element' refactoring (SHIFT-ALT-R) 38 | * to rename the new aggregate. 39 | */ 40 | BoundedContext NewBoundedContext1 { 41 | Aggregate Offers { 42 | useCases = CreateOffer4Customer 43 | 44 | Entity Offer { 45 | aggregateRoot 46 | 47 | int offerId 48 | Customer client 49 | - List products 50 | BigDecimal price 51 | } 52 | } 53 | Aggregate Products { 54 | useCases = CreateOffer4Customer 55 | 56 | Entity Product { 57 | aggregateRoot 58 | 59 | - ProductId identifier 60 | String productName 61 | } 62 | ValueObject ProductId { 63 | int productId key 64 | } 65 | } 66 | } 67 | 68 | /* Domain & Subdomain Definitions */ 69 | Domain InsuranceDomain { 70 | Subdomain PolicyManagementDomain { 71 | type = CORE_DOMAIN 72 | domainVisionStatement = "Subdomain managing contracts and policies." 73 | } 74 | } 75 | 76 | UseCase UpdateContract 77 | UseCase CreateOffer4Customer 78 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-03-Split-Bounded-Context-by-Owner/README.md: -------------------------------------------------------------------------------- 1 | # AR-3: Split Bounded Context by Owner 2 | Splits a bounded context by grouping those aggregates together into one bounded context which belong to the same team. 3 | 4 | **Hint:** An aggregate in CML can belong to one owner/team (therefore the singular _owner_ in the AR name). 5 | 6 | ## Context & Rationales 7 | By decomposing a system into multiple bounded contexts we aim for loose coupling between the bounded context and a high cohesion 8 | within them. One approach to achieve this and to decompose a system into components or (micro-) services is to split by owner (team). 9 | 10 | **See also:** 11 | * Coupling criterion [Shared Owner](https://github.com/ServiceCutter/ServiceCutter/wiki/CC-3-Shared-Owner) of [ServiceCutter](https://servicecutter.github.io/) 12 | * [Conway's Law](https://en.wikipedia.org/wiki/Conway's_law) 13 | * ["Bounded contexts decouple PARTS. Parts are code **and teams**."](http://ntcoding.co.uk/speaking/talks/domain-driven-design-hidden-lessons-from-the-big-blue-book/craft-conf-budapest-may-2019) 14 | by [Nick Tune](http://www.ntcoding.co.uk/) 15 | 16 | In Context Mapper you can assign an aggregate the owning team. Consult our 17 | [aggregate documentation page](https://contextmapper.org/docs/aggregate/#aggregate-owner) to see 18 | how this can be modeled in CML. 19 | 20 | ## Goal 21 | This Architectural Refactoring (AR) splits a bounded context by the owners of the aggregates. This means, it creates bounded contexts 22 | containing aggregates which all belong to the same team. It can be applied if your model exhibits a bounded contexts with 23 | aggregates which are owned by different teams. 24 | 25 | **Inverse AR's:** 26 | * [AR-7: Merge Bounded Contexts](./../AR-7-Merge-Bounded-Contexts) 27 | 28 | ## Preconditions 29 | * The bounded context must contain **at least two aggregates**. 30 | * The aggregates must be **assigned to different teams**. 31 | 32 | ## Input 33 | * One bounded context. 34 | 35 | ## Output 36 | * The AR creates multiple bounded contexts. Each bounded context contains one or more aggregates which are owned by the same 37 | team. 38 | 39 | ## Example 40 | The following two CML snippets show an example _input_ and _output_ illustrating how this AR works. 41 | 42 | ### Input 43 | The following bounded context contains two aggregates which are owend by two different teams: 44 | ``` 45 | /* With a right-click on the 'CustomerSelfServiceContext' bounded context you can execute the 'Split Bounded Context by Owners' refactoring. 46 | * It will split the existing bounded context according to the two owning teams 'CustomerBackendTeam' and 'CustomerFrontendTeam'. 47 | */ 48 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 49 | type = APPLICATION 50 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 51 | responsibilities = "AddressChange" 52 | implementationTechnology = "PHP Web Application" 53 | 54 | Aggregate CustomerFrontend { 55 | owner = CustomerFrontendTeam 56 | 57 | DomainEvent CustomerAddressChange { 58 | aggregateRoot 59 | 60 | - UserAccount issuer 61 | - Address changedAddress 62 | } 63 | } 64 | Aggregate Acounts { 65 | owner = CustomerBackendTeam 66 | 67 | Entity UserAccount { 68 | aggregateRoot 69 | 70 | String username 71 | - Customer accountCustomer 72 | } 73 | } 74 | } 75 | ``` 76 | 77 | ### Output 78 | Applying the AR **Split Bounded Context by Owner** produces two bounded contexts, one for each team: 79 | ``` 80 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 81 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 82 | type = APPLICATION 83 | responsibilities = "AddressChange" 84 | implementationTechnology = "PHP Web Application" 85 | 86 | Aggregate CustomerFrontend { 87 | owner = CustomerFrontendTeam 88 | 89 | DomainEvent CustomerAddressChange { 90 | aggregateRoot 91 | 92 | - UserAccount issuer 93 | - Address changedAddress 94 | } 95 | } 96 | } 97 | 98 | /** 99 | * The new bounded context created by the 'Split Bounded Context by Owners' refactoring applied to 'example-input.cml'. 100 | * 101 | * Note that the refactoring does not produce meaningful bounded context names. You can use the 'Rename Element' refactoring (SHIFT-ALT-R) 102 | * to rename the new aggregate. 103 | * 104 | * The automated refactorings add newly created bounded contexts at the end of the 'bounded context' block, which might not always be the 105 | * desired order. You may change the order after the refactoring manually. 106 | */ 107 | BoundedContext NewBoundedContext1 { 108 | Aggregate Acounts { 109 | owner = CustomerBackendTeam 110 | 111 | Entity UserAccount { 112 | aggregateRoot 113 | 114 | String username 115 | - Customer accountCustomer 116 | } 117 | } 118 | } 119 | ``` 120 | 121 | ### Example Sources 122 | * Example input source: [example-input.cml](./example-input.cml) 123 | * Example output source: [example-output.cml](./example-output.cml) 124 | 125 | ## Further documentation 126 | * Context Mapper [Architectural Refactorings (ARs)](https://contextmapper.org/docs/architectural-refactorings/) 127 | * [AR-3: Split Bounded Context by Owner](https://contextmapper.org/docs/ar-split-bounded-context-by-owners/) 128 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-03-Split-Bounded-Context-by-Owner/example-input.cml: -------------------------------------------------------------------------------- 1 | /* This is an example input file for the 'Split Bounded Context by Owner' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains CustomerSelfServiceContext 4 | 5 | } 6 | 7 | /* With a right-click on the 'CustomerSelfServiceContext' bounded context you can execute the 'Split Bounded Context by Owners' refactoring. 8 | * It will split the existing bounded context according to the two owning teams 'CustomerBackendTeam' and 'CustomerFrontendTeam'. 9 | */ 10 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 11 | type = APPLICATION 12 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 13 | responsibilities = "AddressChange" 14 | implementationTechnology = "PHP Web Application" 15 | 16 | Aggregate CustomerFrontend { 17 | owner = CustomerFrontendTeam 18 | 19 | Entity CustomerAddressChange { 20 | aggregateRoot 21 | 22 | - UserAccount issuer 23 | Address changedAddress 24 | } 25 | } 26 | Aggregate Acounts { 27 | owner = CustomerBackendTeam 28 | 29 | Entity UserAccount { 30 | aggregateRoot 31 | 32 | String username 33 | Customer accountCustomer 34 | } 35 | } 36 | } 37 | 38 | /* Team Definitions */ 39 | BoundedContext CustomerBackendTeam { 40 | type = TEAM 41 | } 42 | 43 | BoundedContext CustomerFrontendTeam { 44 | type = TEAM 45 | } 46 | 47 | /* Domain & Subdomain Definitions */ 48 | Domain InsuranceDomain { 49 | Subdomain CustomerManagementDomain { 50 | type = CORE_DOMAIN 51 | domainVisionStatement = "Subdomain managing everything customer-related." 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-03-Split-Bounded-Context-by-Owner/example-output.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Split Bounded Context by Owner' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains CustomerSelfServiceContext 4 | 5 | } 6 | 7 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 8 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 9 | type = APPLICATION 10 | responsibilities = "AddressChange" 11 | implementationTechnology = "PHP Web Application" 12 | 13 | Aggregate CustomerFrontend { 14 | owner = CustomerFrontendTeam 15 | 16 | Entity CustomerAddressChange { 17 | aggregateRoot 18 | 19 | - UserAccount issuer 20 | Address changedAddress 21 | } 22 | } 23 | } 24 | 25 | /* Team Definitions */ 26 | BoundedContext CustomerBackendTeam { 27 | type = TEAM 28 | } 29 | 30 | BoundedContext CustomerFrontendTeam { 31 | type = TEAM 32 | } 33 | 34 | /** 35 | * The new bounded context created by the 'Split Bounded Context by Owners' refactoring applied to 'example-input.cml'. 36 | * 37 | * Note that the refactoring does not produce meaningful bounded context names. You can use the 'Rename Element' refactoring (SHIFT-ALT-R) 38 | * to rename the new aggregate. 39 | * 40 | * The automated refactorings add newly created bounded contexts at the end of the 'bounded context' block, which might not always be the 41 | * desired order. You may change the order after the refactoring manually. 42 | */ 43 | BoundedContext NewBoundedContext1 { 44 | Aggregate Acounts { 45 | owner = CustomerBackendTeam 46 | 47 | Entity UserAccount { 48 | aggregateRoot 49 | 50 | String username 51 | Customer accountCustomer 52 | } 53 | } 54 | } 55 | 56 | /* Domain & Subdomain Definitions */ 57 | Domain InsuranceDomain { 58 | Subdomain CustomerManagementDomain { 59 | type = CORE_DOMAIN 60 | domainVisionStatement = "Subdomain managing everything customer-related." 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-04-Extract-Aggregates-by-Volatility/README.md: -------------------------------------------------------------------------------- 1 | # AR-4: Extract Aggregates by Volatility 2 | Extracts all aggregates from a bounded context by a given volatility, or likelihood for change 3 | (RARELY, NORMAL or OFTEN), and moves them to a separate context. 4 | 5 | ## Context & Rationales 6 | By decomposing a system into multiple bounded contexts we aim for loose coupling between the bounded context and a high cohesion 7 | within them. One approach of decomposing components is to isolate parts which are likely to change. 8 | 9 | **See also:** 10 | * Coupling criterion [Structural Volatility](https://github.com/ServiceCutter/ServiceCutter/wiki/CC-4-Structural-Volatility) of [ServiceCutter](https://servicecutter.github.io/) 11 | * [On the criteria to be used in decomposing systems into modules](https://dl.acm.org/citation.cfm?id=361623) by D. L. Parnas 12 | 13 | In the Context Mapper DSL you can specify how often an aggregate changes with the _likelihoodForChange_ attribute. 14 | See our page [aggregate documentation page](https://contextmapper.org/docs/aggregate/#likelihood-for-change) for more 15 | details. 16 | 17 | ## Goal 18 | This Architectural Refactoring (AR) extracts all aggregates with a given volatility which is provided as input parameter 19 | (RARELY, NORMAL or OFTEN) and moves those aggregates into a new bounded context. Thereby you are able to isolate aggregates with 20 | a certain likelihood for change in one bounded context. This AR can be applied if your model exhibits a bounded context with 21 | aggregates which have different likelihoods for change. 22 | 23 | **Inverse AR's:** 24 | * [AR-7: Merge Bounded Contexts](./../AR-7-Merge-Bounded-Contexts) 25 | 26 | ## Preconditions 27 | * The selected bounded context must contain **at least two aggregates**. 28 | * The aggregates of the selected bounded context must have **different likelihoods for change**. 29 | 30 | ## Input 31 | * One bounded context. 32 | 33 | ## Output 34 | * Another bounded context containing all the aggregates with the selected volatility. 35 | 36 | ## Example 37 | The following two CML snippets show an example _input_ and _output_ illustrating how this AR works. 38 | 39 | ### Input 40 | The following bounded context contains two aggregates with different likelihoods for change: 41 | ``` 42 | /* With a right-click on the 'CustomerSelfServiceContext' bounded context you can execute the 'Extract Aggregates by Volatility' 43 | * refactoring. If you choose the volatility 'OFTEN', it will extract the volatile 'CustomerFrontend' aggregate and create a new bounded context for it. 44 | */ 45 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 46 | type = APPLICATION 47 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 48 | responsibilities = "AddressChange" 49 | implementationTechnology = "PHP Web Application" 50 | 51 | Aggregate CustomerFrontend { 52 | likelihoodForChange = OFTEN 53 | 54 | DomainEvent CustomerAddressChange { 55 | aggregateRoot 56 | 57 | - UserAccount issuer 58 | - Address changedAddress 59 | } 60 | } 61 | Aggregate Acounts { 62 | Entity UserAccount { 63 | aggregateRoot 64 | 65 | String username 66 | - Customer accountCustomer 67 | } 68 | } 69 | } 70 | 71 | ``` 72 | 73 | ### Output 74 | Applying the AR **Extract Aggregates by Volatility** with the volatility parameter **OFTEN** produces another 75 | bounded context containing the _CustomerFrontend_ aggregate: 76 | ``` 77 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 78 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 79 | type = APPLICATION 80 | responsibilities = "AddressChange" 81 | implementationTechnology = "PHP Web Application" 82 | 83 | Aggregate Acounts { 84 | Entity UserAccount { 85 | aggregateRoot 86 | 87 | String username 88 | - Customer accountCustomer 89 | } 90 | } 91 | } 92 | 93 | /** 94 | * The extracted bounded context after applying 'Extract Aggregates by Volatility' 95 | * to 'example-input.cml'. The chosen volatility was 'OFTEN'. 96 | * 97 | * You may want to change the name of newly created bounded contexts after applying refactorings. 98 | */ 99 | BoundedContext CustomerSelfServiceContext_Volatility_OFTEN { 100 | Aggregate CustomerFrontend { 101 | likelihoodForChange = OFTEN 102 | 103 | DomainEvent CustomerAddressChange { 104 | aggregateRoot 105 | 106 | - UserAccount issuer 107 | - Address changedAddress 108 | } 109 | } 110 | } 111 | ``` 112 | 113 | ### Example Sources 114 | * Example input source: [example-input.cml](./example-input.cml) 115 | * Example output source: [example-output.cml](./example-output.cml) 116 | 117 | ## Further documentation 118 | * Context Mapper [Architectural Refactorings (ARs)](https://contextmapper.org/docs/architectural-refactorings/) 119 | * [AR-4: Extract Aggregates by Volatility](https://contextmapper.org/docs/ar-extract-aggregates-by-volatility/) 120 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-04-Extract-Aggregates-by-Volatility/example-input.cml: -------------------------------------------------------------------------------- 1 | /* This is an example input file for the 'Extract Aggregates by Volatility' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains CustomerSelfServiceContext 4 | 5 | } 6 | 7 | /* With a right-click on the 'CustomerSelfServiceContext' bounded context you can execute the 'Extract Aggregates by Volatility' 8 | * refactoring. If you choose the volatility 'OFTEN', it will extract the volatile 'CustomerFrontend' aggregate and create a new bounded context for it. 9 | */ 10 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 11 | type = APPLICATION 12 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 13 | responsibilities = "AddressChange" 14 | implementationTechnology = "PHP Web Application" 15 | 16 | Aggregate CustomerFrontend { 17 | likelihoodForChange = OFTEN 18 | 19 | Entity CustomerAddressChange { 20 | aggregateRoot 21 | 22 | - UserAccount issuer 23 | Address changedAddress 24 | } 25 | } 26 | Aggregate Acounts { 27 | Entity UserAccount { 28 | aggregateRoot 29 | 30 | String username 31 | Customer accountCustomer 32 | } 33 | } 34 | } 35 | 36 | /* Domain & Subdomain Definitions */ 37 | Domain InsuranceDomain { 38 | Subdomain CustomerManagementDomain { 39 | type = CORE_DOMAIN 40 | domainVisionStatement = "Subdomain managing everything customer-related." 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-04-Extract-Aggregates-by-Volatility/example-output.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Extract Aggregates by Volatility' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains CustomerSelfServiceContext 4 | 5 | } 6 | 7 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 8 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 9 | type = APPLICATION 10 | responsibilities = "AddressChange" 11 | implementationTechnology = "PHP Web Application" 12 | 13 | Aggregate Acounts { 14 | Entity UserAccount { 15 | aggregateRoot 16 | 17 | String username 18 | Customer accountCustomer 19 | } 20 | } 21 | } 22 | 23 | /** 24 | * The extracted bounded context after applying 'Extract Aggregates by Volatility' 25 | * to 'example-input.cml'. The chosen volatility was 'OFTEN'. 26 | * 27 | * You may want to change the name of newly created bounded contexts after applying refactorings. 28 | */ 29 | BoundedContext CustomerSelfServiceContext_Volatility_OFTEN { 30 | Aggregate CustomerFrontend { 31 | likelihoodForChange = OFTEN 32 | 33 | Entity CustomerAddressChange { 34 | aggregateRoot 35 | 36 | - UserAccount issuer 37 | Address changedAddress 38 | } 39 | } 40 | } 41 | 42 | /* Domain & Subdomain Definitions */ 43 | Domain InsuranceDomain { 44 | Subdomain CustomerManagementDomain { 45 | type = CORE_DOMAIN 46 | domainVisionStatement = "Subdomain managing everything customer-related." 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-05-Extract-Aggregates-by-Cohesion/README.md: -------------------------------------------------------------------------------- 1 | # AR-5: Extract Aggregates by Cohesion 2 | Extracts a set of aggregates which are chosen by certain cohesion criteria and moves them to a separate bounded context. 3 | 4 | ## Context & Rationales 5 | By decomposing a system into multiple bounded contexts we aim for loose coupling between the bounded context and a high cohesion 6 | within them. There are many different approaches and different coupling criteria by which the software architect may want 7 | to decompose a system into components. 8 | 9 | **See also:** 10 | * [Coupling criteria catalog](https://github.com/ServiceCutter/ServiceCutter/wiki/Coupling-Criteria) of [ServiceCutter](https://servicecutter.github.io/) 11 | 12 | ## Goal 13 | This Architectural Refactoring (AR) allows to manually select the aggregates which should be extracted by any coupling criteria 14 | or Non-functional Requirements (NFR). The goal of this AR is to isolate a set of aggregates within a new bounded context by 15 | an individual criterion. 16 | 17 | **Inverse AR's:** 18 | * [AR-7: Merge Bounded Contexts](./../AR-7-Merge-Bounded-Contexts) 19 | 20 | ## Preconditions 21 | * The selected bounded context must contain **at least two aggregates**. 22 | 23 | ## Input 24 | * One bounded context. 25 | * A selection of aggregates which shall be extracted to a new bounded context. 26 | 27 | ## Output 28 | * A new bounded context containing the selected aggregates. 29 | 30 | ## Example 31 | The following two CML snippets show an example _input_ and _output_ illustrating how this AR works. 32 | 33 | ### Input 34 | The following bounded context contains three aggregates: 35 | ``` 36 | /* With a right-click on the 'PolicyManagementContext' bounded context you can execute the 'Extract Aggregates by Cohesion' 37 | * refactoring. A dialog will pop up which allows you to select the aggregates to be extracted. You can further specify 38 | * the name of the new bounded context. For example: As architect you may want to extract the 'Offers' aggregate due 39 | * to other differing availability requirements. 40 | */ 41 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 42 | type = FEATURE 43 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 44 | responsibilities = "Offers, Contracts, Policies" 45 | implementationTechnology = "Java, Spring App" 46 | 47 | Aggregate Offers { 48 | Entity Offer { 49 | aggregateRoot 50 | 51 | int offerId 52 | - Customer client 53 | - List products 54 | BigDecimal price 55 | } 56 | } 57 | Aggregate Products { 58 | Entity Product { 59 | aggregateRoot 60 | 61 | - ProductId identifier 62 | String productName 63 | } 64 | ValueObject ProductId { 65 | int productId key 66 | } 67 | } 68 | Aggregate Contract { 69 | Entity Contract { 70 | aggregateRoot 71 | 72 | - ContractId identifier 73 | - Customer client 74 | - List products 75 | } 76 | ValueObject ContractId { 77 | int contractId key 78 | } 79 | 80 | Entity Policy { 81 | int policyNr 82 | - Contract contract 83 | BigDecimal price 84 | } 85 | } 86 | } 87 | ``` 88 | 89 | ### Output 90 | Applying the AR **Extract Aggregates by Cohesion** with the aggregate selection **[ Offers ]** produces 91 | a new bounded context with the _Offers_ aggregate: 92 | ``` 93 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 94 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 95 | responsibilities = "Offers, Contracts, Policies" 96 | implementationTechnology = "Java, Spring App" 97 | 98 | Aggregate Products { 99 | Entity Product { 100 | aggregateRoot 101 | 102 | - ProductId identifier 103 | String productName 104 | } 105 | ValueObject ProductId { 106 | int productId key 107 | } 108 | } 109 | Aggregate Contract { 110 | Entity Contract { 111 | aggregateRoot 112 | 113 | - ContractId identifier 114 | - Customer client 115 | - List products 116 | } 117 | ValueObject ContractId { 118 | int contractId key 119 | } 120 | 121 | Entity Policy { 122 | int policyNr 123 | - Contract contract 124 | BigDecimal price 125 | } 126 | } 127 | } 128 | 129 | /** 130 | * New bounded context after applying 'Extract Aggregates by Cohesion' to 'example-input.cml' 131 | * with the following parameters: 132 | * - New bounded context name: 'SalesBoundedContext' 133 | * - Selected aggregates: 'Offers' 134 | */ 135 | BoundedContext SalesBoundedContext { 136 | Aggregate Offers { 137 | Entity Offer { 138 | aggregateRoot 139 | 140 | int offerId 141 | - Customer client 142 | - List products 143 | BigDecimal price 144 | } 145 | } 146 | } 147 | ``` 148 | 149 | ### Example Sources 150 | * Example input source: [example-input.cml](./example-input.cml) 151 | * Example output source: [example-output.cml](./example-output.cml) 152 | 153 | ## Further documentation 154 | * Context Mapper [Architectural Refactorings (ARs)](https://contextmapper.org/docs/architectural-refactorings/) 155 | * [AR-5: Extract Aggregates by Cohesion](https://contextmapper.org/docs/ar-extract-aggregates-by-cohesion/) 156 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-05-Extract-Aggregates-by-Cohesion/example-input.cml: -------------------------------------------------------------------------------- 1 | /* This is an example input file for the 'Extract Aggregates by Cohesion' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains PolicyManagementContext 4 | 5 | } 6 | 7 | /* With a right-click on the 'PolicyManagementContext' bounded context you can execute the 'Extract Aggregates by Cohesion' 8 | * refactoring. A dialog will pop up which allows you to select the aggregates to be extracted. You can further specify 9 | * the name of the new bounded context. For example: As architect you may want to extract the 'Offers' aggregate due 10 | * to other differing availability requirements. 11 | */ 12 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 13 | type = FEATURE 14 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 15 | responsibilities = "Offers, Contracts, Policies" 16 | implementationTechnology = "Java, Spring App" 17 | 18 | Aggregate Offers { 19 | Entity Offer { 20 | aggregateRoot 21 | 22 | int offerId 23 | Customer client 24 | - List products 25 | BigDecimal price 26 | } 27 | } 28 | Aggregate Products { 29 | Entity Product { 30 | aggregateRoot 31 | 32 | - ProductId identifier 33 | String productName 34 | } 35 | ValueObject ProductId { 36 | int productId key 37 | } 38 | } 39 | Aggregate Contract { 40 | Entity Contract { 41 | aggregateRoot 42 | 43 | - ContractId identifier 44 | Customer client 45 | - List products 46 | } 47 | ValueObject ContractId { 48 | int contractId key 49 | } 50 | 51 | Entity Policy { 52 | int policyNr 53 | - Contract contract 54 | BigDecimal price 55 | } 56 | } 57 | } 58 | 59 | /* Domain & Subdomain Definitions */ 60 | Domain InsuranceDomain { 61 | Subdomain PolicyManagementDomain { 62 | type = CORE_DOMAIN 63 | domainVisionStatement = "Subdomain managing contracts and policies." 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-05-Extract-Aggregates-by-Cohesion/example-output.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Extract Aggregates by Cohesion' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains PolicyManagementContext 4 | 5 | } 6 | 7 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 8 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 9 | responsibilities = "Offers, Contracts, Policies" 10 | implementationTechnology = "Java, Spring App" 11 | 12 | Aggregate Products { 13 | Entity Product { 14 | aggregateRoot 15 | 16 | - ProductId identifier 17 | String productName 18 | } 19 | ValueObject ProductId { 20 | int productId key 21 | } 22 | } 23 | Aggregate Contract { 24 | Entity Contract { 25 | aggregateRoot 26 | 27 | - ContractId identifier 28 | Customer client 29 | - List products 30 | } 31 | ValueObject ContractId { 32 | int contractId key 33 | } 34 | 35 | Entity Policy { 36 | int policyNr 37 | - Contract contract 38 | BigDecimal price 39 | } 40 | } 41 | } 42 | 43 | /** 44 | * New bounded context after applying 'Extract Aggregates by Cohesion' to 'example-input.cml' 45 | * with the following parameters: 46 | * - New bounded context name: 'SalesBoundedContext' 47 | * - Selected aggregates: 'Offers' 48 | */ 49 | BoundedContext SalesBoundedContext { 50 | Aggregate Offers { 51 | Entity Offer { 52 | aggregateRoot 53 | 54 | int offerId 55 | Customer client 56 | - List products 57 | BigDecimal price 58 | } 59 | } 60 | } 61 | 62 | /* Domain & Subdomain Definitions */ 63 | Domain InsuranceDomain { 64 | Subdomain PolicyManagementDomain { 65 | type = CORE_DOMAIN 66 | domainVisionStatement = "Subdomain managing contracts and policies." 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-06-Merge-Aggregates/README.md: -------------------------------------------------------------------------------- 1 | # AR-6: Merge Aggregates 2 | Merges two aggregates within a bounded context together to one aggregate. 3 | 4 | ## Context & Rationales 5 | On the level of entities we typically try to group attributes or [nanoentities in the terminology of ServiceCutter](https://servicecutter.github.io/) 6 | together, which belong to the same identity and share a common lifecycle. Thereby we aim to reduce the coupling between the entities 7 | and increase the cohesion within the entities. 8 | 9 | * **See also**: Coupling criterion [Identity and Lifecycle Commonality](https://github.com/ServiceCutter/ServiceCutter/wiki/CC-1-Identity-and-Lifecycle-Commonality) 10 | of [ServiceCutter](https://servicecutter.github.io/). 11 | 12 | The same approach can be applied on the aggregate level. The aggregates within one bounded context shall be structured in a way which 13 | reduces coupling between the aggregates and increases the cohesion within them. 14 | 15 | During the evolution of your bounded context you may find multiple aggregates containing entities which belong together (for 16 | example because they share a common lifecycle) and merging the aggregates together improves coupling and cohesion. 17 | 18 | ## Goal 19 | This Architectural Refactoring (AR) merges two aggregates in a bounded context together into one aggregate. It can be applied 20 | in a situation where the entities in the two aggregates somehow belong together and a merge of the aggregates improves the 21 | coupling and cohesion. 22 | 23 | **Inverse AR's:** 24 | * [AR-1: Split Aggregate by Entities](./../AR-1-Split-Aggregate-by-Entities) 25 | 26 | ## Preconditions 27 | * Your bounded context must contain **at least two aggregates** which can be merged. 28 | 29 | ## Input 30 | * Two aggregates which belong to the same bounded context. 31 | 32 | ## Output 33 | * One aggregate containing all objects (entities, value objects, etc.) of the two input aggregates. 34 | 35 | ## Example 36 | The following two CML snippets show an example _input_ and _output_ illustrating how this AR works. 37 | 38 | ### Input 39 | The following bounded context contains two aggregates: 40 | ``` 41 | /* With a right-click on the 'Customers' aggregate (or on the 'Addresses' aggregate, as you wish) 42 | * you can execute the 'Merge Aggregates' refactoring. A dialog will show up and ask you with 43 | * which other aggregate you want to merge. Choose the other aggregate and the refactoring will merge them. 44 | */ 45 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 46 | type = FEATURE 47 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 48 | implementationTechnology = "Java, JEE Application" 49 | responsibilities = "Customers, Addresses" 50 | 51 | Aggregate Customers { 52 | Entity Customer { 53 | aggregateRoot 54 | - SocialInsuranceNumber sin 55 | String firstname 56 | String lastname 57 | - List
addresses 58 | } 59 | ValueObject SocialInsuranceNumber { 60 | String sin key 61 | } 62 | } 63 | Aggregate Addresses { 64 | Entity Address { 65 | String street 66 | int postalCode 67 | String city 68 | } 69 | } 70 | } 71 | ``` 72 | 73 | ### Output 74 | Applying the AR **Merge Aggregates** with the aggregate selection **[ Customers, Addresses ]** 75 | merges the objects of both aggregates into the _Customers_ aggregate: 76 | ``` 77 | /* 78 | * The resulting bounded context after applying 'Merge Aggregates' to the file 'example-input.cml'. 79 | * The 'Addresses' aggregate has been merged into the 'Customers' aggregate. 80 | */ 81 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 82 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 83 | responsibilities = "Customers, Addresses" 84 | implementationTechnology = "Java, JEE Application" 85 | Aggregate Customers { 86 | Entity Customer { 87 | aggregateRoot 88 | - SocialInsuranceNumber sin 89 | String firstname 90 | String lastname 91 | - List
addresses 92 | } 93 | ValueObject SocialInsuranceNumber { 94 | String sin key 95 | } 96 | Entity Address { 97 | String street 98 | int postalCode 99 | String city 100 | } 101 | } 102 | } 103 | ``` 104 | 105 | ### Example Sources 106 | * Example input source: [example-input.cml](./example-input.cml) 107 | * Example output source: [example-output.cml](./example-output.cml) 108 | 109 | ## Further documentation 110 | * Context Mapper [Architectural Refactorings (ARs)](https://contextmapper.org/docs/architectural-refactorings/) 111 | * [AR-6: Merge Aggregates](https://contextmapper.org/docs/ar-merge-aggregates/) 112 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-06-Merge-Aggregates/example-input.cml: -------------------------------------------------------------------------------- 1 | /* This is an example input file for the 'Merge Aggregates' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains CustomerManagementContext 4 | contains CustomerSelfServiceContext 5 | 6 | CustomerSelfServiceContext [D,C]<-[U,S] CustomerManagementContext { 7 | exposedAggregates = Customers, Addresses 8 | } 9 | 10 | } 11 | 12 | /* With a right-click on the 'Customers' aggregate (or on the 'Addresses' aggregate, as you wish) 13 | * you can execute the 'Merge Aggregates' refactoring. A dialog will show up and ask you with 14 | * which other aggregate you want to merge. Choose the other aggregate and the refactoring will merge them. 15 | */ 16 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 17 | type = FEATURE 18 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 19 | implementationTechnology = "Java, JEE Application" 20 | responsibilities = "Customers, Addresses" 21 | 22 | Aggregate Customers { 23 | Entity Customer { 24 | aggregateRoot 25 | - SocialInsuranceNumber sin 26 | String firstname 27 | String lastname 28 | - List
addresses 29 | } 30 | ValueObject SocialInsuranceNumber { 31 | String sin key 32 | } 33 | } 34 | Aggregate Addresses { 35 | Entity Address { 36 | String street 37 | int postalCode 38 | String city 39 | } 40 | } 41 | } 42 | 43 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 44 | type = APPLICATION 45 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 46 | responsibilities = "AddressChange" 47 | implementationTechnology = "PHP Web Application" 48 | 49 | Aggregate CustomerFrontend { 50 | Entity CustomerAddressChange { 51 | aggregateRoot 52 | - UserAccount issuer 53 | - Address changedAddress 54 | } 55 | } 56 | Aggregate Acounts { 57 | Entity UserAccount { 58 | aggregateRoot 59 | String username 60 | - Customer accountCustomer 61 | } 62 | } 63 | } 64 | 65 | /* Domain & Subdomain Definitions */ 66 | Domain InsuranceDomain { 67 | Subdomain CustomerManagementDomain { 68 | type = CORE_DOMAIN 69 | domainVisionStatement = "Subdomain managing everything customer-related." 70 | } 71 | } 72 | 73 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-06-Merge-Aggregates/example-output.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Merge Aggregates' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains CustomerManagementContext 4 | contains CustomerSelfServiceContext 5 | 6 | CustomerSelfServiceContext [D,C]<-[U,S] CustomerManagementContext { 7 | exposedAggregates = Customers 8 | } 9 | 10 | } 11 | 12 | /* 13 | * The resulting bounded context after applying 'Merge Aggregates' to the file 'example-input.cml'. 14 | * The 'Addresses' aggregate has been merged into the 'Customers' aggregate. 15 | */ 16 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 17 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 18 | responsibilities = "Customers, Addresses" 19 | implementationTechnology = "Java, JEE Application" 20 | Aggregate Customers { 21 | Entity Customer { 22 | aggregateRoot 23 | - SocialInsuranceNumber sin 24 | String firstname 25 | String lastname 26 | - List
addresses 27 | } 28 | ValueObject SocialInsuranceNumber { 29 | String sin key 30 | } 31 | Entity Address { 32 | String street 33 | int postalCode 34 | String city 35 | } 36 | } 37 | } 38 | 39 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 40 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 41 | type = APPLICATION 42 | responsibilities = "AddressChange" 43 | implementationTechnology = "PHP Web Application" 44 | 45 | Aggregate CustomerFrontend { 46 | Entity CustomerAddressChange { 47 | aggregateRoot 48 | - UserAccount issuer 49 | - Address changedAddress 50 | } 51 | } 52 | Aggregate Acounts { 53 | Entity UserAccount { 54 | aggregateRoot 55 | String username 56 | - Customer accountCustomer 57 | } 58 | } 59 | } 60 | 61 | /* Domain & Subdomain Definitions */ 62 | Domain InsuranceDomain { 63 | Subdomain CustomerManagementDomain { 64 | type = CORE_DOMAIN 65 | domainVisionStatement = "Subdomain managing everything customer-related." 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-07-Merge-Bounded-Contexts/README.md: -------------------------------------------------------------------------------- 1 | # AR-7 Merge Bounded Contexts 2 | Merges two bounded contexts together. The result is one bounded context containing all the aggregates of the two input bounded 3 | contexts. 4 | 5 | ## Context & Rationales 6 | By decomposing a system into multiple bounded contexts we aim for loose coupling between the bounded context and a high cohesion 7 | within them. However, sometimes a decomposition may be too fine-granular and merging bounded contexts with a high 8 | coupling together improves the cohesion within the corresponding resulting bounded context. 9 | 10 | ## Goal 11 | This Architectural Refactoring (AR) merges two bounded contexts together. The resulting bounded context contains all aggregates 12 | of the two input bounded contexts. It can be applied if two bounded context are tightly coupled and the aggregates somehow 13 | belong together. This may improve the cohesion within the resulting bounded context. 14 | 15 | **Notes:** 16 | * By applying this AR multiple times you may end with one single Bounded Context and an empty Context Map (no relationships). 17 | 18 | **Inverse AR's:** 19 | * [AR-4: Extract Aggregates by Volatility](./../AR-4-Extract-Aggregates-by-Volatility) 20 | * [AR-5: Extract Aggregates by Cohesion](./../AR-5-Extract-Aggregates-by-Cohesion) 21 | * [AR-2: Split Bounded Context by Use Cases](./../AR-2-Split-Bounded-Context-by-Use-Cases) (may need multiple merges to completely revert) 22 | * [AR-3: Split Bounded Context by Owner](./../AR-3-Split-Bounded-Context-by-Owner) (may need multiple merges to completely revert) 23 | 24 | ## Preconditions 25 | * Your model needs **at least two bounded contexts** to merge. 26 | 27 | ## Input 28 | * Two bounded contexts. 29 | 30 | ## Output 31 | * One bounded context containing all aggregates of the two input bounded contexts. 32 | 33 | ## Example 34 | The following two CML snippets show an example _input_ and _output_ illustrating how this AR works. 35 | 36 | ### Input 37 | Two input bounded contexts: 38 | ``` 39 | /* With a right-click on the 'CustomerManagementContext' (or one of the other contexts, as you wish) 40 | * bounded context you can execute the 'Merge Bounded Contexts' refactoring. A dialog will show up and ask you with 41 | * which other bounded context you want to merge. Choose a second bounded context and the refactoring will merge them. 42 | */ 43 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 44 | type = FEATURE 45 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 46 | implementationTechnology = "Java, JEE Application" 47 | responsibilities = "Customers, Addresses" 48 | 49 | Aggregate Customers { 50 | Entity Customer { 51 | aggregateRoot 52 | 53 | - SocialInsuranceNumber sin 54 | String firstname 55 | String lastname 56 | - List
addresses 57 | } 58 | Entity Address { 59 | String street 60 | int postalCode 61 | String city 62 | } 63 | ValueObject SocialInsuranceNumber { 64 | String sin key 65 | } 66 | } 67 | } 68 | 69 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 70 | type = APPLICATION 71 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 72 | responsibilities = "AddressChange" 73 | implementationTechnology = "PHP Web Application" 74 | 75 | Aggregate CustomerFrontend { 76 | DomainEvent CustomerAddressChange { 77 | aggregateRoot 78 | 79 | - UserAccount issuer 80 | - Address changedAddress 81 | } 82 | } 83 | Aggregate Acounts { 84 | Entity UserAccount { 85 | aggregateRoot 86 | 87 | String username 88 | - Customer accountCustomer 89 | } 90 | } 91 | } 92 | ``` 93 | 94 | ### Output 95 | Applying the AR **Merge Bounded Contexts** merges all aggregates of the _CustomerSelfServiceContext_ bounded context 96 | into the _CustomerManagementContext_ bounded context: 97 | ``` 98 | /** 99 | * The merged bounded context after applying 'Merge Bounded Contexts' to 'example-input.cml'. 100 | * We selected the 'CustomerSelfServiceContext' context as second bounded context. 101 | */ 102 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 103 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 104 | responsibilities = "Customers, Addresses" , "AddressChange" 105 | implementationTechnology = "Java, JEE Application" 106 | Aggregate Customers { 107 | Entity Customer { 108 | aggregateRoot 109 | 110 | - SocialInsuranceNumber sin 111 | String firstname 112 | String lastname 113 | - List
addresses 114 | } 115 | Entity Address { 116 | String street 117 | int postalCode 118 | String city 119 | } 120 | ValueObject SocialInsuranceNumber { 121 | String sin key 122 | } 123 | } 124 | Aggregate CustomerFrontend { 125 | DomainEvent CustomerAddressChange { 126 | aggregateRoot 127 | 128 | - UserAccount issuer 129 | - Address changedAddress 130 | } 131 | } 132 | Aggregate Acounts { 133 | Entity UserAccount { 134 | aggregateRoot 135 | 136 | String username 137 | - Customer accountCustomer 138 | } 139 | } 140 | } 141 | ``` 142 | 143 | ### Example Sources 144 | * Example input source: [example-input.cml](./example-input.cml) 145 | * Example output source: [example-output.cml](./example-output.cml) 146 | 147 | ## Further documentation 148 | * Context Mapper [Architectural Refactorings (ARs)](https://contextmapper.org/docs/architectural-refactorings/) 149 | * [AR-7 Merge Bounded Contexts](https://contextmapper.org/docs/ar-merge-bounded-contexts/) 150 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-07-Merge-Bounded-Contexts/example-input.cml: -------------------------------------------------------------------------------- 1 | /* This is an example input file for the 'Merge Bounded Contexts' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains CustomerManagementContext 4 | contains CustomerSelfServiceContext 5 | contains PrintingContext 6 | 7 | CustomerSelfServiceContext [D,C]<-[U,S] CustomerManagementContext : Customer_Frontend_Backend_Relationship { // Relationship name is optional 8 | exposedAggregates = Customers 9 | } 10 | 11 | CustomerManagementContext [D,ACL]<-[U,OHS,PL] PrintingContext { 12 | implementationTechnology = "SOAP" 13 | downstreamRights = INFLUENCER 14 | exposedAggregates = Printing 15 | } 16 | 17 | } 18 | 19 | /* With a right-click on the 'CustomerManagementContext' (or one of the other contexts, as you wish) 20 | * bounded context you can execute the 'Merge Bounded Contexts' refactoring. A dialog will show up and ask you with 21 | * which other bounded context you want to merge. Choose a second bounded context and the refactoring will merge them. 22 | */ 23 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 24 | type = FEATURE 25 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 26 | implementationTechnology = "Java, JEE Application" 27 | responsibilities = "Customers, Addresses" 28 | 29 | Aggregate Customers { 30 | Entity Customer { 31 | aggregateRoot 32 | 33 | - SocialInsuranceNumber sin 34 | String firstname 35 | String lastname 36 | - List
addresses 37 | } 38 | Entity Address { 39 | String street 40 | int postalCode 41 | String city 42 | } 43 | ValueObject SocialInsuranceNumber { 44 | String sin key 45 | } 46 | } 47 | } 48 | 49 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 50 | type = APPLICATION 51 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 52 | responsibilities = "AddressChange" 53 | implementationTechnology = "PHP Web Application" 54 | 55 | Aggregate CustomerFrontend { 56 | Entity CustomerAddressChange { 57 | aggregateRoot 58 | 59 | - UserAccount issuer 60 | - Address changedAddress 61 | } 62 | } 63 | Aggregate Acounts { 64 | Entity UserAccount { 65 | aggregateRoot 66 | 67 | String username 68 | - Customer accountCustomer 69 | } 70 | } 71 | } 72 | 73 | BoundedContext PrintingContext implements PrintingDomain { 74 | type = SYSTEM 75 | responsibilities = "Document Printing" 76 | domainVisionStatement = "An external system which provides printing services to the other Bounded Contexts." 77 | 78 | Aggregate Printing { 79 | Entity PrintingJob { 80 | aggregateRoot 81 | 82 | int printingId 83 | - Document document 84 | - Template template 85 | } 86 | 87 | Entity Document { 88 | DomainObject source 89 | String template 90 | } 91 | } 92 | Aggregate Templating { 93 | Entity Template { 94 | aggregateRoot 95 | 96 | int templateId 97 | String templateName 98 | } 99 | } 100 | } 101 | 102 | /* Domain & Subdomain Definitions */ 103 | Domain InsuranceDomain { 104 | Subdomain CustomerManagementDomain { 105 | type = CORE_DOMAIN 106 | domainVisionStatement = "Subdomain managing everything customer-related." 107 | } 108 | Subdomain PrintingDomain { 109 | type = SUPPORTING_DOMAIN 110 | domainVisionStatement = "Service (external system) to solve printing for all kinds of documents (debts, policies, etc.)" 111 | } 112 | } 113 | 114 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-07-Merge-Bounded-Contexts/example-output.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Merge Bounded Contexts' refactoring and shows a small part of the insurance example. */ 2 | ContextMap { 3 | contains CustomerManagementContext 4 | contains PrintingContext 5 | 6 | CustomerManagementContext [D,ACL]<-[U,OHS,PL] PrintingContext { 7 | implementationTechnology = "SOAP" 8 | exposedAggregates = Printing 9 | } 10 | 11 | } 12 | 13 | /** 14 | * The merged bounded context after applying 'Merge Bounded Contexts' to 'example-input.cml'. 15 | * We selected the 'CustomerSelfServiceContext' context as second bounded context. 16 | */ 17 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 18 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 19 | responsibilities = "Customers, Addresses" , "AddressChange" 20 | implementationTechnology = "Java, JEE Application" 21 | Aggregate Customers { 22 | Entity Customer { 23 | aggregateRoot 24 | 25 | - SocialInsuranceNumber sin 26 | String firstname 27 | String lastname 28 | - List
addresses 29 | } 30 | Entity Address { 31 | String street 32 | int postalCode 33 | String city 34 | } 35 | ValueObject SocialInsuranceNumber { 36 | String sin key 37 | } 38 | } 39 | Aggregate CustomerFrontend { 40 | Entity CustomerAddressChange { 41 | aggregateRoot 42 | 43 | - UserAccount issuer 44 | - Address changedAddress 45 | } 46 | } 47 | Aggregate Acounts { 48 | Entity UserAccount { 49 | aggregateRoot 50 | 51 | String username 52 | - Customer accountCustomer 53 | } 54 | } 55 | } 56 | 57 | BoundedContext PrintingContext implements PrintingDomain { 58 | domainVisionStatement = "An external system which provides printing services to the other Bounded Contexts." 59 | type = SYSTEM 60 | responsibilities = "Document Printing" 61 | Aggregate Printing { 62 | Entity PrintingJob { 63 | aggregateRoot 64 | 65 | int printingId 66 | - Document document 67 | - Template template 68 | } 69 | 70 | Entity Document { 71 | DomainObject source 72 | String template 73 | } 74 | } 75 | Aggregate Templating { 76 | Entity Template { 77 | aggregateRoot 78 | 79 | int templateId 80 | String templateName 81 | } 82 | } 83 | } 84 | 85 | /* Domain & Subdomain Definitions */ 86 | Domain InsuranceDomain { 87 | Subdomain CustomerManagementDomain { 88 | type = CORE_DOMAIN 89 | domainVisionStatement = "Subdomain managing everything customer-related." 90 | } 91 | Subdomain PrintingDomain { 92 | type = SUPPORTING_DOMAIN 93 | domainVisionStatement = "Service (external system) to solve printing for all kinds of documents (debts, policies, etc.)" 94 | } 95 | } 96 | 97 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-08-Extract-Shared-Kernel/README.md: -------------------------------------------------------------------------------- 1 | # AR-8 Extract Shared Kernel 2 | Extracts a new Bounded Context from a Shared Kernel relationship. It further established two upstream-downstream relationships 3 | so that the existing Bounded Context can use the 'shared' functionality. 4 | 5 | ## Context & Rationales 6 | The Shared Kernel pattern describes a close relationship between two Bounded Contexts which share a certain part of their domain 7 | models. The pattern is typically implemented as a shared library which is maintained by both teams. However, both teams depend on 8 | that shared code and each team has to deal with changes of the other one. If such a shared library gets very big and difficult to 9 | maintain it may be better to create a separate Bounded Context for it. A dedicated team may maintain the model within this new 10 | Bounded Context. 11 | 12 | ## Goal 13 | This Architectural Refactoring (AR) extracts a Shared Kernel into a new Bounded Context. The resulting Context Map will no 14 | longer contain the Shared Kernel relationship, but two new upstream-downstream relationships between the new and the existing 15 | two Bounded Contexts. This AR can be applied if a Shared Kernel gets big, difficult to maintain, and it may be better to have 16 | a new team maintaining this shared part of the domain model in a separate Bounded Context. This may increase the autonomy of 17 | all involved teams. 18 | 19 | ## Preconditions 20 | * Your model needs **at least two bounded contexts** which are in a **Shared Kernel** relationship. 21 | 22 | ## Input 23 | * The Shared Kernel relationship. 24 | 25 | ## Output 26 | * A new Bounded Context for the shared domain model parts and two new upstream-downstream relationships between the new and the 27 | existing two Bounded Contexts. 28 | 29 | ## Example 30 | The following two CML snippets show an example _input_ and _output_ illustrating how this AR works. 31 | 32 | ### Input 33 | The input Context Map: 34 | ``` 35 | ContextMap InsuranceContextMap { 36 | type = SYSTEM_LANDSCAPE 37 | state = TO_BE 38 | 39 | contains PolicyManagementContext 40 | contains DebtCollection 41 | 42 | /* With a right-click on the Shared Kernel relationship ([SK]<->[SK]) you can execute the 'Extract Shared Kernel' 43 | * refactoring. It will create a new Bounded Context for the shared code (content of new Bounded Context has to 44 | * specified manually). Two new upstream-downstream relationships will be created to connect the existing Bounded 45 | * Contexts with the new one. After applying this AR, you can use the 'Rename Element' refactoring to change 46 | * the generated name of the new Bounded Context. 47 | */ 48 | PolicyManagementContext [SK]<->[SK] DebtCollection { 49 | implementationTechnology = "Shared Java Library, Communication over RESTful HTTP" 50 | } 51 | 52 | } 53 | 54 | BoundedContext PolicyManagementContext { 55 | /* ... */ 56 | } 57 | 58 | BoundedContext DebtCollection { 59 | /* ... */ 60 | } 61 | ``` 62 | 63 | ### Output 64 | Applying the AR **Extract Shared Kernel** removes the Shared Kernel relationship, creates a new Bounded Context for 65 | the shared domain model parts, and establishes two new upstream-downstream relationships between the new and the 66 | existing Bounded Contexts: 67 | ``` 68 | ContextMap InsuranceContextMap { 69 | type = SYSTEM_LANDSCAPE 70 | state = TO_BE 71 | 72 | contains PolicyManagementContext 73 | contains DebtCollection 74 | contains PolicyManagementContext_DebtCollection_SharedKernel 75 | 76 | /* New relationships generated by the 'Extract Shared Kernel' AR: */ 77 | 78 | PolicyManagementContext_DebtCollection_SharedKernel [ U ] -> [ D ] PolicyManagementContext 79 | 80 | PolicyManagementContext_DebtCollection_SharedKernel [ U ] -> [ D ] DebtCollection 81 | 82 | } 83 | 84 | BoundedContext PolicyManagementContext { 85 | /* ... */ 86 | } 87 | 88 | BoundedContext DebtCollection { 89 | /* ... */ 90 | } 91 | 92 | /* New Bounded Context generated by the 'Extract Shared Kernel' AR. After applying the AR, the Bounded Context can 93 | * be renamed with the 'Rename Element' refactoring. The user can further specify the comment parts here after applying 94 | * the AR (create new Aggregates and entities or move them from existing contexts to this one). 95 | */ 96 | BoundedContext PolicyManagementContext_DebtCollection_SharedKernel 97 | ``` 98 | 99 | ### Example Sources 100 | * Example input source: [example-input.cml](./example-input.cml) 101 | * Example output source: [example-output.cml](./example-output.cml) 102 | 103 | ## Further documentation 104 | * Context Mapper [Architectural Refactorings (ARs)](https://contextmapper.org/docs/architectural-refactorings/) 105 | * [AR-8 Extract Shared Kernel](https://contextmapper.org/docs/ar-extract-shared-kernel/) 106 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-08-Extract-Shared-Kernel/example-input.cml: -------------------------------------------------------------------------------- 1 | /* This is an example input file for the 'Extract Shared Kernel' refactoring and shows a small part of the insurance example. */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | 6 | contains PolicyManagementContext 7 | contains DebtCollection 8 | 9 | /* With a right-click on the Shared Kernel relationship ([SK]<->[SK]) you can execute the 'Extract Shared Kernel' 10 | * refactoring. It will create a new Bounded Context for the shared code (content of new Bounded Context has to 11 | * specified manually). Two new upstream-downstream relationships will be created to connect the existing Bounded 12 | * Contexts with the new one. After applying this AR, you can use the 'Rename Element' refactoring to change 13 | * the generated name of the new Bounded Context. 14 | */ 15 | PolicyManagementContext [SK]<->[SK] DebtCollection { 16 | implementationTechnology = "Shared Java Library, Communication over RESTful HTTP" 17 | } 18 | 19 | } 20 | 21 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 22 | type = FEATURE 23 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 24 | responsibilities = "Offers, Contracts, Policies" 25 | implementationTechnology = "Java, Spring App" 26 | 27 | Aggregate Offers { 28 | Entity Offer { 29 | aggregateRoot 30 | int offerId 31 | Customer client 32 | - List products 33 | BigDecimal price 34 | } 35 | } 36 | Aggregate Products { 37 | Entity Product { 38 | aggregateRoot 39 | - ProductId identifier 40 | String productName 41 | } 42 | ValueObject ProductId { 43 | int productId key 44 | } 45 | } 46 | Aggregate Contract { 47 | Entity Contract { 48 | aggregateRoot 49 | - ContractId identifier 50 | Customer client 51 | - List products 52 | } 53 | ValueObject ContractId { 54 | int contractId key 55 | } 56 | 57 | Entity Policy { 58 | int policyNr 59 | - Contract contract 60 | BigDecimal price 61 | } 62 | } 63 | } 64 | 65 | BoundedContext DebtCollection implements DebtsDomain { 66 | type = FEATURE 67 | domainVisionStatement = "The debt collection context is responsible for the financial income of the insurance company (the debts) which depend on the corresponding contracts and policies." 68 | responsibilities = "Debts, Dunning" 69 | implementationTechnology = "JEE" 70 | 71 | Aggregate Debts { 72 | Entity Debt { 73 | aggregateRoot 74 | int debtNr 75 | - Policy policy 76 | Date creationDate 77 | Date paymentDate 78 | Date paymentDeadline 79 | BigDecimal price 80 | PaymentStatus status 81 | - List dunnigs 82 | } 83 | Entity Dunning { 84 | int dunningNr 85 | - Debt debt 86 | Date dunningDate 87 | Date paymentDeadline 88 | } 89 | } 90 | } 91 | 92 | /* Domain & Subdomain Definitions */ 93 | Domain InsuranceDomain { 94 | Subdomain PolicyManagementDomain { 95 | type = CORE_DOMAIN 96 | domainVisionStatement = "Subdomain managing contracts and policies." 97 | } 98 | Subdomain DebtsDomain { 99 | type = GENERIC_SUBDOMAIN 100 | domainVisionStatement = "Subomain including everything related to the incoming money (debts, dunning, etc.)" 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-08-Extract-Shared-Kernel/example-output.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Extract Shared Kernel' refactoring and shows a small part of the insurance example. */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | 6 | contains PolicyManagementContext 7 | contains DebtCollection 8 | contains PolicyManagementContext_DebtCollection_SharedKernel 9 | 10 | /* New relationships generated by the 'Extract Shared Kernel' AR: */ 11 | 12 | PolicyManagementContext_DebtCollection_SharedKernel [ U ] -> [ D ] PolicyManagementContext 13 | 14 | PolicyManagementContext_DebtCollection_SharedKernel [ U ] -> [ D ] DebtCollection 15 | 16 | } 17 | 18 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 19 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 20 | responsibilities = "Offers, Contracts, Policies" 21 | implementationTechnology = "Java, Spring App" 22 | 23 | Aggregate Offers { 24 | Entity Offer { 25 | aggregateRoot 26 | int offerId 27 | Customer client 28 | - List products 29 | BigDecimal price 30 | } 31 | } 32 | Aggregate Products { 33 | Entity Product { 34 | aggregateRoot 35 | - ProductId identifier 36 | String productName 37 | } 38 | ValueObject ProductId { 39 | int productId key 40 | } 41 | } 42 | Aggregate Contract { 43 | Entity Contract { 44 | aggregateRoot 45 | - ContractId identifier 46 | Customer client 47 | - List products 48 | } 49 | ValueObject ContractId { 50 | int contractId key 51 | } 52 | 53 | Entity Policy { 54 | int policyNr 55 | - Contract contract 56 | BigDecimal price 57 | } 58 | } 59 | } 60 | 61 | BoundedContext DebtCollection implements DebtsDomain { 62 | domainVisionStatement = "The debt collection context is responsible for the financial income of the insurance company (the debts) which depend on the corresponding contracts and policies." 63 | responsibilities = "Debts, Dunning" 64 | implementationTechnology = "JEE" 65 | 66 | Aggregate Debts { 67 | Entity Debt { 68 | aggregateRoot 69 | int debtNr 70 | - Policy policy 71 | Date creationDate 72 | Date paymentDate 73 | Date paymentDeadline 74 | BigDecimal price 75 | PaymentStatus status 76 | - List dunnigs 77 | } 78 | Entity Dunning { 79 | int dunningNr 80 | - Debt debt 81 | Date dunningDate 82 | Date paymentDeadline 83 | } 84 | } 85 | } 86 | 87 | /* New Bounded Context generated by the 'Extract Shared Kernel' AR. After applying the AR, the Bounded Context can 88 | * be renamed with the 'Rename Element' refactoring. The user can further specify the comment parts here after applying 89 | * the AR (create new Aggregates and entities or move them from existing contexts to this one). 90 | */ 91 | // Extracted Bounded Context for Shared Kernel. Please specify the kernel model here: 92 | BoundedContext PolicyManagementContext_DebtCollection_SharedKernel { 93 | Aggregate SharedKernelAggregate { 94 | Entity SharedKernelRoot { 95 | aggregateRoot 96 | } 97 | } 98 | } 99 | 100 | /* Domain & Subdomain Definitions */ 101 | Domain InsuranceDomain { 102 | Subdomain PolicyManagementDomain { 103 | type = CORE_DOMAIN 104 | domainVisionStatement = "Subdomain managing contracts and policies." 105 | } 106 | Subdomain DebtsDomain { 107 | type = GENERIC_SUBDOMAIN 108 | domainVisionStatement = "Subomain including everything related to the incoming money (debts, dunning, etc.)" 109 | } 110 | } 111 | 112 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-09-Suspend-Partnership/example-input.cml: -------------------------------------------------------------------------------- 1 | /* This is an example input file for the 'Suspend Partnership' refactoring and shows a small part of the insurance example. */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | 6 | contains PolicyManagementContext 7 | contains RiskManagementContext 8 | 9 | /* With a right-click on the Partnership relationship ([P]<->[P]) you can execute the 'Suspend Partnership' 10 | * refactoring. On a dialog you can then choose between three modes how to suspend the partnership: 11 | * a) Merge the two Bounded Contexts (executes 'AR-7 Merge Bounded Contexts'). 12 | * b) Extract a new Bounded Context for commonalities and establish upstream-downstream relationships between 13 | * the new and the existing two Bounded Contexts. 14 | * c) Simply replace the Partnership relationship with an upstream-downstream relationship (in this case 15 | * you have to choose which Bounded Context becomes upstream context). 16 | */ 17 | RiskManagementContext [P]<->[P] PolicyManagementContext { 18 | implementationTechnology = "RabbitMQ" 19 | } 20 | 21 | } 22 | 23 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 24 | type = FEATURE 25 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 26 | responsibilities = "Offers, Contracts, Policies" 27 | implementationTechnology = "Java, Spring App" 28 | 29 | Aggregate Offers { 30 | Entity Offer { 31 | aggregateRoot 32 | int offerId 33 | Customer client 34 | - List products 35 | BigDecimal price 36 | } 37 | } 38 | Aggregate Products { 39 | Entity Product { 40 | aggregateRoot 41 | - ProductId identifier 42 | String productName 43 | } 44 | ValueObject ProductId { 45 | int productId key 46 | } 47 | } 48 | Aggregate Contract { 49 | Entity Contract { 50 | aggregateRoot 51 | - ContractId identifier 52 | Customer client 53 | - List products 54 | } 55 | ValueObject ContractId { 56 | int contractId key 57 | } 58 | 59 | Entity Policy { 60 | int policyNr 61 | - Contract contract 62 | BigDecimal price 63 | } 64 | } 65 | } 66 | 67 | BoundedContext RiskManagementContext implements RiskManagementDomain { 68 | type = FEATURE 69 | domainVisionStatement = "Uses data from PolicyManagement context to calculate risks." 70 | responsibilities = "Customer Risk Calculation" 71 | implementationTechnology = "Java, Spring App" 72 | 73 | Aggregate Risks { 74 | Entity CustomerRiskFactor { 75 | aggregateRoot 76 | int totalRiskFactor 77 | - List risks 78 | Customer client 79 | } 80 | ValueObject Risk { 81 | int likelihood 82 | String risk 83 | } 84 | } 85 | } 86 | 87 | /* Domain & Subdomain Definitions */ 88 | Domain InsuranceDomain { 89 | Subdomain PolicyManagementDomain { 90 | type = CORE_DOMAIN 91 | domainVisionStatement = "Subdomain managing contracts and policies." 92 | } 93 | Subdomain RiskManagementDomain { 94 | type = GENERIC_SUBDOMAIN 95 | domainVisionStatement = "Subdomain supporting everything which relates to risk management." 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-09-Suspend-Partnership/example-output-a.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Suspend Partnership' refactoring and shows a small part of the insurance example. 2 | * 3 | * In this case we selected to MERGE the Bounded Contexts to suspend the partnership. 4 | */ 5 | ContextMap InsuranceContextMap { 6 | type = SYSTEM_LANDSCAPE 7 | state = TO_BE 8 | 9 | contains RiskManagementContext 10 | 11 | /* Since the AR merged the two Bounded Context, the relationship has been removed. */ 12 | } 13 | 14 | /* The merged Bounded Context contains all Aggregates of both contexts now. It further implements both Subdomains. */ 15 | BoundedContext RiskManagementContext implements RiskManagementDomain , PolicyManagementDomain { 16 | domainVisionStatement "Uses data from PolicyManagement context to calculate risks." 17 | responsibilities = "Customer Risk Calculation", "Offers, Contracts, Policies" 18 | implementationTechnology "Java, Spring App" 19 | 20 | Aggregate Risks { 21 | Entity CustomerRiskFactor { 22 | aggregateRoot 23 | int totalRiskFactor 24 | - List risks 25 | Customer client 26 | } 27 | ValueObject Risk { 28 | int likelihood 29 | String risk 30 | } 31 | } 32 | Aggregate Offers { 33 | Entity Offer { 34 | aggregateRoot 35 | int offerId 36 | Customer client 37 | - List products 38 | BigDecimal price 39 | } 40 | } 41 | Aggregate Products { 42 | Entity Product { 43 | aggregateRoot 44 | - ProductId identifier 45 | String productName 46 | } 47 | ValueObject ProductId { 48 | int productId key 49 | } 50 | } 51 | Aggregate Contract { 52 | Entity Contract { 53 | aggregateRoot 54 | - ContractId identifier 55 | Customer client 56 | - List products 57 | } 58 | ValueObject ContractId { 59 | int contractId key 60 | } 61 | 62 | Entity Policy { 63 | int policyNr 64 | - Contract contract 65 | BigDecimal price 66 | } 67 | } 68 | } 69 | 70 | /* Domain & Subdomain Definitions */ 71 | Domain InsuranceDomain { 72 | Subdomain PolicyManagementDomain { 73 | type = CORE_DOMAIN 74 | domainVisionStatement = "Subdomain managing contracts and policies." 75 | } 76 | Subdomain RiskManagementDomain { 77 | type = GENERIC_SUBDOMAIN 78 | domainVisionStatement = "Subdomain supporting everything which relates to risk management." 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-09-Suspend-Partnership/example-output-b.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Suspend Partnership' refactoring and shows a small part of the insurance example. 2 | * 3 | * In this case we selected to EXTRACT a new Bounded Contexts for commonalities to suspend the partnership. 4 | */ 5 | ContextMap InsuranceContextMap { 6 | type = SYSTEM_LANDSCAPE 7 | state = TO_BE 8 | 9 | contains PolicyManagementContext 10 | contains RiskManagementContext 11 | contains RiskManagementContext_PolicyManagementContext_Partnership 12 | 13 | /* New upstream-downstream relationships between the new and the existing two Bounded Contexts: */ 14 | 15 | RiskManagementContext_PolicyManagementContext_Partnership [ U ] -> [ D ] RiskManagementContext 16 | 17 | RiskManagementContext_PolicyManagementContext_Partnership [ U ] -> [ D ] PolicyManagementContext 18 | 19 | } 20 | 21 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 22 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 23 | responsibilities = "Offers, Contracts, Policies" 24 | implementationTechnology = "Java, Spring App" 25 | 26 | Aggregate Offers { 27 | Entity Offer { 28 | aggregateRoot 29 | int offerId 30 | Customer client 31 | - List products 32 | BigDecimal price 33 | } 34 | } 35 | Aggregate Products { 36 | Entity Product { 37 | aggregateRoot 38 | - ProductId identifier 39 | String productName 40 | } 41 | ValueObject ProductId { 42 | int productId key 43 | } 44 | } 45 | Aggregate Contract { 46 | Entity Contract { 47 | aggregateRoot 48 | - ContractId identifier 49 | Customer client 50 | - List products 51 | } 52 | ValueObject ContractId { 53 | int contractId key 54 | } 55 | 56 | Entity Policy { 57 | int policyNr 58 | - Contract contract 59 | BigDecimal price 60 | } 61 | } 62 | } 63 | 64 | BoundedContext RiskManagementContext implements RiskManagementDomain { 65 | domainVisionStatement = "Uses data from PolicyManagement context to calculate risks." 66 | responsibilities = "Customer Risk Calculation" 67 | implementationTechnology = "Java, Spring App" 68 | 69 | Aggregate Risks { 70 | Entity CustomerRiskFactor { 71 | aggregateRoot 72 | int totalRiskFactor 73 | - List risks 74 | Customer client 75 | } 76 | ValueObject Risk { 77 | int likelihood 78 | String risk 79 | } 80 | } 81 | } 82 | 83 | /* The new Bounded Context created by the 'Suspend Partnership' refactoring: 84 | * (can be renamed with the 'Rename Element' refactoring) 85 | */ 86 | // Extracted Bounded Context for common model parts. Please specify the common model here: 87 | BoundedContext RiskManagementContext_PolicyManagementContext_Partnership { 88 | Aggregate CommonModelAggregate { 89 | Entity CommonModelPartRoot { 90 | aggregateRoot 91 | } 92 | } 93 | } 94 | 95 | /* Domain & Subdomain Definitions */ 96 | Domain InsuranceDomain { 97 | Subdomain PolicyManagementDomain { 98 | type = CORE_DOMAIN 99 | domainVisionStatement = "Subdomain managing contracts and policies." 100 | } 101 | Subdomain RiskManagementDomain { 102 | type = GENERIC_SUBDOMAIN 103 | domainVisionStatement = "Subdomain supporting everything which relates to risk management." 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-09-Suspend-Partnership/example-output-c.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Suspend Partnership' refactoring and shows a small part of the insurance example. 2 | * 3 | * In this case we selected to REPLACE the partnership with an upstream-downstream relationship. 4 | */ 5 | ContextMap InsuranceContextMap { 6 | type = SYSTEM_LANDSCAPE 7 | state = TO_BE 8 | 9 | contains PolicyManagementContext 10 | contains RiskManagementContext 11 | 12 | /* The new upstream-downstream relationship replacing the original Partnership relationship: */ 13 | 14 | PolicyManagementContext [ U ] -> [ D ] RiskManagementContext 15 | 16 | } 17 | 18 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 19 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 20 | responsibilities = "Offers, Contracts, Policies" 21 | implementationTechnology = "Java, Spring App" 22 | 23 | Aggregate Offers { 24 | Entity Offer { 25 | aggregateRoot 26 | int offerId 27 | Customer client 28 | - List products 29 | BigDecimal price 30 | } 31 | } 32 | Aggregate Products { 33 | Entity Product { 34 | aggregateRoot 35 | - ProductId identifier 36 | String productName 37 | } 38 | ValueObject ProductId { 39 | int productId key 40 | } 41 | } 42 | Aggregate Contract { 43 | Entity Contract { 44 | aggregateRoot 45 | - ContractId identifier 46 | Customer client 47 | - List products 48 | } 49 | ValueObject ContractId { 50 | int contractId key 51 | } 52 | 53 | Entity Policy { 54 | int policyNr 55 | - Contract contract 56 | BigDecimal price 57 | } 58 | } 59 | } 60 | 61 | BoundedContext RiskManagementContext implements RiskManagementDomain { 62 | domainVisionStatement = "Uses data from PolicyManagement context to calculate risks." 63 | responsibilities = "Customer Risk Calculation" 64 | implementationTechnology = "Java, Spring App" 65 | 66 | Aggregate Risks { 67 | Entity CustomerRiskFactor { 68 | aggregateRoot 69 | int totalRiskFactor 70 | - List risks 71 | Customer client 72 | } 73 | ValueObject Risk { 74 | int likelihood 75 | String risk 76 | } 77 | } 78 | } 79 | 80 | /* Domain & Subdomain Definitions */ 81 | Domain InsuranceDomain { 82 | Subdomain PolicyManagementDomain { 83 | type = CORE_DOMAIN 84 | domainVisionStatement = "Subdomain managing contracts and policies." 85 | } 86 | Subdomain RiskManagementDomain { 87 | type = GENERIC_SUBDOMAIN 88 | domainVisionStatement = "Subdomain supporting everything which relates to risk management." 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-10-Change-Shared-Kernel-To-Partnership/README.md: -------------------------------------------------------------------------------- 1 | # AR-10 Change Shared Kernel to Partnership 2 | This simple relationship refactoring changes a Shared Kernel relationship on a Context Map to a Partnership relationship. 3 | 4 | ## Summary 5 | Our relationship refactorings allow the user/modeller to change the type of a relationship on a Context Map easily without manual work. 6 | The symmetric relationships according to our [semantic model](/docs/language-model/), Shared Kernel and Partnership, are interchangeable without impacts 7 | to the structure of the decomposition. This refactoring changes a Shared Kernel relationship to a Partnership relationship. 8 | 9 | **Inverse AR:** 10 | * [AR-11: Change Partnership to Shared Kernel](./../AR-11-Change-Partnership-To-Shared-Kernel) 11 | 12 | ## Example 13 | The following two CML snippets show an example _input_ and _output_ illustrating how this AR works. 14 | 15 | ### Input 16 | The input Context Map: 17 | ``` 18 | ContextMap InsuranceContextMap { 19 | type = SYSTEM_LANDSCAPE 20 | state = TO_BE 21 | contains PolicyManagementContext 22 | contains DebtCollection 23 | 24 | /* With a right-click on the Shared Kernel relationship ([SK]<->[SK]) you can execute the 'Change to Partnership' 25 | * refactoring. It will replace the Shared Kernel relationship below with a corresponding Partnership relationship 26 | * between the two Bounded Contexts. 27 | */ 28 | PolicyManagementContext [SK]<->[SK] DebtCollection 29 | 30 | } 31 | 32 | BoundedContext PolicyManagementContext 33 | 34 | BoundedContext DebtCollection 35 | ``` 36 | 37 | ### Output 38 | Applying the AR **Change Shared Kernel to Partnership** replaces the existing Shared Kernel relationship with a 39 | Partnership relationship: 40 | ``` 41 | ContextMap InsuranceContextMap { 42 | type = SYSTEM_LANDSCAPE 43 | state = TO_BE 44 | contains PolicyManagementContext 45 | contains DebtCollection 46 | 47 | /* The new Partnership relationship after applying the 'Change Shared Kernel to Partnership' refactoring to the 48 | * Shared Kernel within the 'example-input.cml' file: 49 | */ 50 | PolicyManagementContext [P] <-> [P] DebtCollection 51 | 52 | } 53 | 54 | BoundedContext PolicyManagementContext 55 | 56 | BoundedContext DebtCollection 57 | ``` 58 | 59 | ### Example Sources 60 | * Example input source: [example-input.cml](./example-input.cml) 61 | * Example output source: [example-output.cml](./example-output.cml) 62 | 63 | ## Further documentation 64 | * Context Mapper [Architectural Refactorings (ARs)](https://contextmapper.org/docs/architectural-refactorings/) 65 | * [AR-10 Change Shared Kernel to Partnership](https://contextmapper.org/docs/ar-change-shared-kernel-to-partnership/) 66 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-10-Change-Shared-Kernel-To-Partnership/example-input.cml: -------------------------------------------------------------------------------- 1 | /* This is an example input file for the 'Change Shared Kernel to Partnership' refactoring and shows a small part of the insurance example. */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | contains PolicyManagementContext 6 | contains DebtCollection 7 | 8 | /* With a right-click on the Shared Kernel relationship ([SK]<->[SK]) you can execute the 'Change to Partnership' 9 | * refactoring. It will replace the Shared Kernel relationship below with a corresponding Partnership relationship 10 | * between the two Bounded Contexts. 11 | */ 12 | PolicyManagementContext [SK]<->[SK] DebtCollection 13 | 14 | } 15 | 16 | BoundedContext PolicyManagementContext 17 | 18 | BoundedContext DebtCollection 19 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-10-Change-Shared-Kernel-To-Partnership/example-output.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Change Shared Kernel to Partnership' refactoring and shows a small part of the insurance example. */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | contains PolicyManagementContext 6 | contains DebtCollection 7 | 8 | /* The new Partnership relationship after applying the 'Change Shared Kernel to Partnership' refactoring to the 9 | * Shared Kernel within the 'example-input.cml' file: 10 | */ 11 | PolicyManagementContext [P] <-> [P] DebtCollection 12 | 13 | } 14 | 15 | BoundedContext PolicyManagementContext 16 | 17 | BoundedContext DebtCollection 18 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-11-Change-Partnership-To-Shared-Kernel/README.md: -------------------------------------------------------------------------------- 1 | # AR-11 Change Partnership to Shared Kernel 2 | This simple relationship refactoring changes a Partnership relationship on a Context Map to a Shared Kernel relationship. 3 | 4 | ## Summary 5 | Our relationship refactorings allow the user/modeller to change the type of a relationship on a Context Map easily without manual work. 6 | The symmetric relationships according to our [semantic model](/docs/language-model/), Shared Kernel and Partnership, are interchangeable without impacts 7 | to the structure of the decomposition. This refactoring changes a Partnership relationship to a Shared Kernel relationship. 8 | 9 | **Inverse AR:** 10 | * [AR-10: Change Shared Kernel to Partnership](./../AR-10-Change-Shared-Kernel-To-Partnership) 11 | 12 | ## Example 13 | The following two CML snippets show an example _input_ and _output_ illustrating how this AR works. 14 | 15 | ### Input 16 | The input Context Map: 17 | ``` 18 | ContextMap InsuranceContextMap { 19 | type = SYSTEM_LANDSCAPE 20 | state = TO_BE 21 | contains PolicyManagementContext 22 | contains RiskManagementContext 23 | 24 | /* With a right-click on the Partnership relationship ([P]<->[P]) you can execute the 'Change to Shared Kernel' 25 | * refactoring. It will replace the Partnership relationship below with a corresponding Shared Kernel relationship 26 | * between the two Bounded Contexts. 27 | */ 28 | RiskManagementContext [P]<->[P] PolicyManagementContext 29 | 30 | } 31 | 32 | BoundedContext PolicyManagementContext 33 | 34 | BoundedContext RiskManagementContext 35 | ``` 36 | 37 | ### Output 38 | Applying the AR **Change Partnership to Shared Kernel** replaces the existing Partnership relationship with a 39 | Shared Kernel relationship: 40 | ``` 41 | ContextMap InsuranceContextMap { 42 | type = SYSTEM_LANDSCAPE 43 | state = TO_BE 44 | contains PolicyManagementContext 45 | contains RiskManagementContext 46 | 47 | /* The new Shared Kernel relationship after applying the 'Change Partnership to Shared Kernel' refactoring to the 48 | * Partnership within the 'example-input.cml' file: 49 | */ 50 | RiskManagementContext [SK] <-> [SK] PolicyManagementContext 51 | 52 | } 53 | 54 | BoundedContext PolicyManagementContext 55 | 56 | BoundedContext RiskManagementContext 57 | ``` 58 | 59 | ### Example Sources 60 | * Example input source: [example-input.cml](./example-input.cml) 61 | * Example output source: [example-output.cml](./example-output.cml) 62 | 63 | ## Further documentation 64 | * Context Mapper [Architectural Refactorings (ARs)](https://contextmapper.org/docs/architectural-refactorings/) 65 | * [AR-11 Change Partnership to Shared Kernel](https://contextmapper.org/docs/ar-change-partnership-to-shared-kernel/) 66 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-11-Change-Partnership-To-Shared-Kernel/example-input.cml: -------------------------------------------------------------------------------- 1 | /* This is an example input file for the 'Change Partnership to Shared Kernel' refactoring and shows a small part of the insurance example. */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | contains PolicyManagementContext 6 | contains RiskManagementContext 7 | 8 | /* With a right-click on the Partnership relationship ([P]<->[P]) you can execute the 'Change to Shared Kernel' 9 | * refactoring. It will replace the Partnership relationship below with a corresponding Shared Kernel relationship 10 | * between the two Bounded Contexts. 11 | */ 12 | RiskManagementContext [P]<->[P] PolicyManagementContext 13 | 14 | } 15 | 16 | BoundedContext PolicyManagementContext 17 | 18 | BoundedContext RiskManagementContext 19 | -------------------------------------------------------------------------------- /src/main/cml/architectural-refactorings/AR-11-Change-Partnership-To-Shared-Kernel/example-output.cml: -------------------------------------------------------------------------------- 1 | /* This is an example output file for the 'Change Partnership to Shared Kernel' refactoring and shows a small part of the insurance example. */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | contains PolicyManagementContext 6 | contains RiskManagementContext 7 | 8 | /* The new Shared Kernel relationship after applying the 'Change Partnership to Shared Kernel' refactoring to the 9 | * Partnership within the 'example-input.cml' file: 10 | */ 11 | RiskManagementContext [SK] <-> [SK] PolicyManagementContext 12 | 13 | } 14 | 15 | BoundedContext PolicyManagementContext 16 | 17 | BoundedContext RiskManagementContext 18 | -------------------------------------------------------------------------------- /src/main/cml/bounded-context-canvas-example/Bounded-Context-Canvas-Example-Stage-1.cml: -------------------------------------------------------------------------------- 1 | /* Example Context Map written using a Bounded Context Canvas. */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | 6 | /* Add bounded contexts to this context map: */ 7 | contains CustomerManagementContext 8 | } 9 | 10 | /* Domain & Subdomain Definitions */ 11 | Domain InsuranceDomain { 12 | Subdomain CustomerManagementDomain { 13 | type = CORE_DOMAIN 14 | domainVisionStatement = "Subdomain managing everything customer-related." 15 | } 16 | } 17 | 18 | /* Bounded Context Definitions */ 19 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 20 | businessModel = "ENGAGEMENT" 21 | evolution = CUSTOM_BUILT 22 | } 23 | -------------------------------------------------------------------------------- /src/main/cml/bounded-context-canvas-example/README.md: -------------------------------------------------------------------------------- 1 | # Bounded Context Canvas Example 2 | 3 | This example illustrates the Context Mapper DSL capabilities to support Bounded Context canvases. 4 | Full support is a _work in progress_. 5 | 6 | 7 | Please see the [bounded context canvas example](Bounded-Context-Canvas-Example-Stage-1.cml). 8 | -------------------------------------------------------------------------------- /src/main/cml/context-mapper-example/ContextMapper-Example-Stage-1.cml: -------------------------------------------------------------------------------- 1 | ContextMap ContextMapper { 2 | contains LanguageCore, ArchitecturalRefactorings, StructuredServiceDecomposition, DiscoveryLibrary, Generators 3 | 4 | LanguageCore -> DiscoveryLibrary 5 | 6 | LanguageCore <- StructuredServiceDecomposition 7 | 8 | LanguageCore -> Generators 9 | 10 | LanguageCore <-> ArchitecturalRefactorings 11 | 12 | } 13 | 14 | BoundedContext LanguageCore 15 | 16 | BoundedContext ArchitecturalRefactorings 17 | 18 | BoundedContext StructuredServiceDecomposition 19 | 20 | BoundedContext DiscoveryLibrary 21 | 22 | BoundedContext Generators 23 | -------------------------------------------------------------------------------- /src/main/cml/context-mapper-example/ContextMapper-Example-Stage-2.cml: -------------------------------------------------------------------------------- 1 | ContextMap ContextMapper { 2 | contains LanguageCore, ArchitecturalRefactorings, StructuredServiceDecomposition, DiscoveryLibrary, Generators 3 | 4 | /** 5 | * Pattern selection: 6 | * ================== 7 | * 8 | * The language core (CML language) provides a Published Language (PL) allowing to describe software systems 9 | * in terms of DDD patterns. This PL is used by the other components. Since its not a public API (REST, Messaging, 10 | * or similar) we haven't added the Open Host Service (OHS) pattern. 11 | * 12 | * 13 | * The discovery library conforms to the model provided by the language core (we always generate CML models 14 | * according to the core). The generators and on the other hand may also influence the language sometimes. 15 | * The core further uses the API of our Service Cutter library to generate new decompositions. 16 | */ 17 | 18 | LanguageCore [PL]->[CF] DiscoveryLibrary 19 | 20 | LanguageCore [ACL]<-[OHS,PL] StructuredServiceDecomposition 21 | 22 | LanguageCore [PL]-> Generators 23 | 24 | /* The refactorings are tightly coupled with the language. In this case the semantic model of the language 25 | * can be seen as a Shared Kernel: 26 | */ 27 | LanguageCore [SK]<->[SK] ArchitecturalRefactorings 28 | 29 | } 30 | 31 | BoundedContext LanguageCore 32 | 33 | BoundedContext ArchitecturalRefactorings 34 | 35 | BoundedContext StructuredServiceDecomposition 36 | 37 | BoundedContext DiscoveryLibrary 38 | 39 | BoundedContext Generators 40 | -------------------------------------------------------------------------------- /src/main/cml/context-mapper-example/ContextMapper-Example-Stage-3.cml: -------------------------------------------------------------------------------- 1 | ContextMap ContextMapper { 2 | contains LanguageCore, ArchitecturalRefactorings, StructuredServiceDecomposition, DiscoveryLibrary, Generators 3 | 4 | /** 5 | * Pattern selection: 6 | * ================== 7 | * 8 | * The language core (CML language) provides a Published Language (PL) allowing to describe software systems 9 | * in terms of DDD patterns. This PL is used by the other components. Since its not a public API (REST, Messaging, 10 | * or similar) we haven't added the Open Host Service (OHS) pattern. 11 | * 12 | * 13 | * The discovery library conforms to the model provided by the language core (we always generate CML models 14 | * according to the core). The generators and on the other hand may also influence the language sometimes. 15 | * The core further uses the API of our Service Cutter library to generate new decompositions. 16 | */ 17 | 18 | LanguageCore [PL]->[CF] DiscoveryLibrary 19 | 20 | LanguageCore [ACL]<-[OHS,PL] StructuredServiceDecomposition 21 | 22 | LanguageCore [PL]-> Generators 23 | 24 | /* The refactorings are tightly coupled with the language. In this case the semantic model of the language 25 | * can be seen as a Shared Kernel: 26 | */ 27 | LanguageCore [SK]<->[SK] ArchitecturalRefactorings 28 | 29 | } 30 | 31 | BoundedContext LanguageCore { 32 | domainVisionStatement "Provides the Context Mapper DSL (CML) modeling language to express architectures on the basis of Strategic Domain-driven Design (DDD) patterns." 33 | 34 | Aggregate StrategicDesign 35 | 36 | Aggregate TacticDesign 37 | 38 | } 39 | 40 | BoundedContext ArchitecturalRefactorings { 41 | domainVisionStatement "Architectural Refactorings (ARs) allow to improve the architecture model iteratively." 42 | 43 | Aggregate StructuralRefactorings 44 | 45 | Aggregate RelationshipRefactorings 46 | } 47 | 48 | BoundedContext StructuredServiceDecomposition { 49 | domainVisionStatement "The Service Cutter integration into Context Mapper allows to analyze the Context Map with respect to coupling criteria and supports to suggest improved Context Maps." 50 | 51 | Aggregate ERDModel // input 52 | 53 | Aggregate UserRepresentations // input 54 | 55 | Aggregate CouplingCriteria // service decomposition process 56 | 57 | Aggregate GraphClusteringAlgorithms // service decomposition process 58 | 59 | Aggregate ServiceDecompositions // output 60 | 61 | } 62 | 63 | BoundedContext DiscoveryLibrary { 64 | domainVisionStatement "The reverse engineering component can generate CML Context Maps from existing source code. This allows to reverse engineer the architecture model in projects with existing monoliths or microservices." 65 | 66 | Aggregate BoundedContextDiscoveryStrategies 67 | 68 | Aggregate RelationshipDiscoveryStrategies 69 | } 70 | 71 | BoundedContext Generators { 72 | domainVisionStatement "The generators allow to generate other representations of the architecture derived by a given CML Context Map." 73 | 74 | Aggregate GraphicalGenerators 75 | 76 | Aggregate ServiceContractsGenerators // generate (micro-)service generators 77 | 78 | Aggregate ServiceCutterGenerators // generate ServiceCutter input files 79 | } 80 | -------------------------------------------------------------------------------- /src/main/cml/context-mapper-example/README.md: -------------------------------------------------------------------------------- 1 | # Context Mapper Example 2 | 3 | This example is illustrates the Context Mapper DSL capabilities on the basis of the [Context Mapper framework](https://contextmapper.org/docs/home/) itself. 4 | 5 | Within this folder we modeled our own tool with the CML language as part of our validation activities. The following figure (generated with our [Context Map generator](https://contextmapper.org/docs/context-map-generator/)) illustrates the context map of our framework: 6 | 7 | Context Mapper Context Map 8 | 9 | Here you can find the corresponding context map in CML (Context Mapper Language) in different versions and levels of detail (stages): 10 | 11 | * [ContextMapper-Example-Stage-1](./ContextMapper-Example-Stage-1.cml): A simple context map without relationship patterns in upstream-downstream relationships and without details of the bounded contexts. 12 | * [ContextMapper-Example-Stage-2](./ContextMapper-Example-Stage-2.cml): This stage refines the relationships on the context map and adds the corresponding DDD relationship patterns. 13 | * [ContextMapper-Example-Stage-3](./ContextMapper-Example-Stage-3.cml): In stage three we added first details to the bounded contexts and specified the aggregates. 14 | * [ContextMapper-Example-Stage-4](./ContextMapper-Example-Stage-4.cml): A simple version including all domain objects but no attributes. This stage should still be understandable for users without technical knowledge. 15 | -------------------------------------------------------------------------------- /src/main/cml/context-mapper-example/ServiceCutterLibraryContract.mdsl: -------------------------------------------------------------------------------- 1 | API description ServiceCutterLibraryAPI 2 | usage context PUBLIC_API for BACKEND_INTEGRATION 3 | 4 | // input model (Entity Relation Diagram & User Representations) 5 | data type EntityRelationshipDiagram { "name":D, "entities":{ "name":D, "nanoentities":D* }*, "relations":{ "origin":{ "name":D, "nanoentities":D* }, "destination":{ "name":D, "nanoentities":D* }, "relationType":RelationType }* } 6 | data type UserRepresentations { "useCases":{ "name":D, "nanoentitiesRead":D*, "nanoentitiesWritten":D*, "latencyCritical":D }*, "compatibilities":{ "contentVolatility":{ "characteristic":D, "nanoentities":D* }*, "structuralVolatility":{ "characteristic":D, "nanoentities":D* }*, "availabilityCriticality":{ "characteristic":D, "nanoentities":D* }*, "consistencyCriticality":{ "characteristic":D, "nanoentities":D* }*, "storageSimilarity":{ "characteristic":D, "nanoentities":D* }*, "securityCriticality":{ "characteristic":D, "nanoentities":D* }* }* } 7 | data type RelationType { "AGGREGATION" | "COMPOSITION" | "INHERITANCE" } 8 | 9 | // Service cutting context built by input and coupling criteria 10 | data type ServiceCutterContext { "systemName":D, "criteriaCatalog":CouplingCriteriaCatalog, "couplingInstances":CouplingInstance*, "nanoEntities":D*, "solverConfiguration":SolverConfiguration } 11 | data type CouplingCriteriaCatalog P // not specified in detail due to complexity 12 | data type CouplingInstance P // not specified in detail due to complexity 13 | 14 | // Solver configuration provided by user (algorithm and priorities) 15 | data type SolverConfiguration { "algorithm":D, "solverPriorities":{ "criterion":D, "priority":SolverPriority }* } 16 | data type SolverPriority { "IGNORE" | "XS" | "S" | "M" | "L" | "XL" | "XXL" } 17 | 18 | // Cutting result provided by Service Cutter 19 | data type SolverResult { "services":{ "nanoentities":D*, "id":Char }*, "relations":{ "serviceA":D, "serviceB":D, "sharedEntities":D*, "direction":Direction }* } 20 | data type Direction { "OUTGOING" | "INCOMING" | "BIDIRECTIONAL" } 21 | data type Char P // no char primitive type in MDSL 22 | 23 | endpoint type ServiceCutterContextBuilder // stateful type 24 | exposes 25 | operation ServiceCutterContextBuilder // constructor 26 | expecting 27 | payload EntityRelationshipDiagram 28 | operation withUserRepresentations // provide user representations (optionally) 29 | expecting 30 | payload UserRepresentations 31 | operation withCustomSolverConfiguration // change solver configuration (optionally) 32 | expecting 33 | payload SolverConfiguration 34 | operation build // build the context 35 | delivering 36 | payload ServiceCutterContext 37 | 38 | endpoint type SolverConfigurationFactory 39 | exposes 40 | operation createDefaultConfiguration // create initial/default solver configuration 41 | delivering 42 | payload SolverConfiguration 43 | 44 | endpoint type ServiceCutter 45 | exposes 46 | operation generateDecomposition // decompose the system with the provided context 47 | expecting 48 | payload ServiceCutterContext 49 | delivering 50 | payload SolverResult 51 | 52 | 53 | API provider ServiceCutterLibrary 54 | offers ServiceCutterContextBuilder 55 | offers SolverConfigurationFactory 56 | offers ServiceCutter 57 | 58 | API client LanguageCore 59 | consumes ServiceCutterContextBuilder 60 | consumes SolverConfigurationFactory 61 | consumes ServiceCutter 62 | 63 | IPA -------------------------------------------------------------------------------- /src/main/cml/context-mapper-example/images/ContextMapper-Example-Simple_ComponentDiagram.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | skinparam componentStyle uml2 3 | 4 | component [LanguageCore] 5 | note top of [LanguageCore] 6 | Provides the Context Mapper DSL 7 | (CML) modeling language to express 8 | architectures on the basis of 9 | Strategic Domain-driven Design 10 | (DDD) patterns. 11 | end note 12 | 13 | component [ArchitecturalRefactorings] 14 | note bottom of [ArchitecturalRefactorings] 15 | Architectural Refactorings (ARs) 16 | allow to improve the architecture 17 | model iteratively. 18 | end note 19 | 20 | component [StructuredServiceDecomposition] 21 | note bottom of [StructuredServiceDecomposition] 22 | The Service Cutter integration into Context 23 | Mapper allows to analyze the Context Map 24 | with respect to coupling criteria and 25 | supports to suggest improved Context Maps. 26 | The Service Cutter library exposes an API 27 | (Open Host Service and Published Language) 28 | used by Context Mapper to generate the 29 | new decompositions. 30 | end note 31 | 32 | component [DiscoveryLibrary] 33 | note left of [DiscoveryLibrary] 34 | The reverse engineering and discovery 35 | component can generate CML Context Maps 36 | from existing source code. This allows 37 | to reverse engineer the architecture 38 | model in projects with existing monoliths 39 | or microservices. 40 | end note 41 | 42 | component [Generators] 43 | note right of [Generators] 44 | The generators allow to generate 45 | other representations of the architecture 46 | derived by a given CML Context 47 | Map. 48 | end note 49 | 50 | interface "Upstream-Downstream" as DiscoveryLibrary_to_LanguageCore 51 | [LanguageCore] -up-> DiscoveryLibrary_to_LanguageCore : "PUBLISHED_LANGUAGE (PL)" 52 | [DiscoveryLibrary] ..> DiscoveryLibrary_to_LanguageCore : " use as CONFORMIST (CF)" 53 | 54 | interface "Upstream-Downstream" as LanguageCore_to_StructuredServiceDecomposition 55 | [StructuredServiceDecomposition] -right-> LanguageCore_to_StructuredServiceDecomposition : "OHS, PL" 56 | LanguageCore_to_StructuredServiceDecomposition <. [LanguageCore] : "use via ACL" 57 | 58 | [LanguageCore] <-> [ArchitecturalRefactorings] : " Shared Kernel " 59 | 60 | interface "Upstream-Downstream" as Generators_to_LanguageCore 61 | [LanguageCore] -down-> Generators_to_LanguageCore : " PUBLISHED_LANGUAGE (PL)" 62 | Generators_to_LanguageCore <.. [Generators] : " use" 63 | @enduml -------------------------------------------------------------------------------- /src/main/cml/context-mapper-example/images/ContextMapper-Example-Simple_ContextMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-mapper-examples/0854134a15fa70384c4e192cd5e32485ca0d22b5/src/main/cml/context-mapper-example/images/ContextMapper-Example-Simple_ContextMap.png -------------------------------------------------------------------------------- /src/main/cml/ddd-sample/DDD-Sample-Stage-1.cml: -------------------------------------------------------------------------------- 1 | /* The DDD Cargo sample application modeled in CML. Note that we split the application into multiple bounded contexts. */ 2 | ContextMap DDDSampleMap { 3 | contains CargoBookingContext 4 | contains VoyagePlanningContext 5 | contains LocationContext 6 | 7 | /* As Evans mentions in his book (Bounded Context chapter): The voyage planning can be seen as 8 | * separated bounded context. However, it still shares code with the booking application (CargoBookingContext). 9 | * Thus, they are in a 'Shared-Kernel' relationship. 10 | */ 11 | CargoBookingContext [SK]<->[SK] VoyagePlanningContext 12 | 13 | /* Note that the splitting of the LocationContext is not mentioned in the original DDD sample of Evans. 14 | * However, locations and the management around them, can somehow be seen as a separated concept which is used by other 15 | * bounded contexts. But this is just an example, since we want to demonstrate our DSL with multiple bounded contexts. 16 | */ 17 | CargoBookingContext <- LocationContext 18 | 19 | VoyagePlanningContext <- LocationContext 20 | 21 | } 22 | 23 | /* The original booking application context */ 24 | BoundedContext CargoBookingContext 25 | 26 | /* We split the Voyage Planning into a separate bounded context as Evans proposes it in his book. */ 27 | BoundedContext VoyagePlanningContext 28 | 29 | /* Separate bounded context for managing the locations. */ 30 | BoundedContext LocationContext 31 | -------------------------------------------------------------------------------- /src/main/cml/ddd-sample/DDD-Sample-Stage-2.cml: -------------------------------------------------------------------------------- 1 | /* The DDD Cargo sample application modeled in CML. Note that we split the application into multiple bounded contexts. */ 2 | ContextMap DDDSampleMap { 3 | contains CargoBookingContext 4 | contains VoyagePlanningContext 5 | contains LocationContext 6 | 7 | /* As Evans mentions in his book (Bounded Context chapter): The voyage planning can be seen as 8 | * separated bounded context. However, it still shares code with the booking application (CargoBookingContext). 9 | * Thus, they are in a 'Shared-Kernel' relationship. 10 | */ 11 | CargoBookingContext [SK]<->[SK] VoyagePlanningContext 12 | 13 | /* Note that the splitting of the LocationContext is not mentioned in the original DDD sample of Evans. 14 | * However, locations and the management around them, can somehow be seen as a separated concept which is used by other 15 | * bounded contexts. But this is just an example, since we want to demonstrate our DSL with multiple bounded contexts. 16 | */ 17 | CargoBookingContext [D]<-[U,OHS,PL] LocationContext 18 | 19 | VoyagePlanningContext [D]<-[U,OHS,PL] LocationContext 20 | 21 | } 22 | 23 | /* The original booking application context */ 24 | BoundedContext CargoBookingContext 25 | 26 | /* We split the Voyage Planning into a separate bounded context as Evans proposes it in his book. */ 27 | BoundedContext VoyagePlanningContext 28 | 29 | /* Separate bounded context for managing the locations. */ 30 | BoundedContext LocationContext 31 | -------------------------------------------------------------------------------- /src/main/cml/ddd-sample/DDD-Sample-Stage-3.cml: -------------------------------------------------------------------------------- 1 | /* The DDD Cargo sample application modeled in CML. Note that we split the application into multiple bounded contexts. */ 2 | ContextMap DDDSampleMap { 3 | contains CargoBookingContext 4 | contains VoyagePlanningContext 5 | contains LocationContext 6 | 7 | /* As Evans mentions in his book (Bounded Context chapter): The voyage planning can be seen as 8 | * separated bounded context. However, it still shares code with the booking application (CargoBookingContext). 9 | * Thus, they are in a 'Shared-Kernel' relationship. 10 | */ 11 | CargoBookingContext [SK]<->[SK] VoyagePlanningContext 12 | 13 | /* Note that the splitting of the LocationContext is not mentioned in the original DDD sample of Evans. 14 | * However, locations and the management around them, can somehow be seen as a separated concept which is used by other 15 | * bounded contexts. But this is just an example, since we want to demonstrate our DSL with multiple bounded contexts. 16 | */ 17 | CargoBookingContext [D]<-[U,OHS,PL] LocationContext 18 | 19 | VoyagePlanningContext [D]<-[U,OHS,PL] LocationContext 20 | 21 | } 22 | 23 | /* The original booking application context */ 24 | BoundedContext CargoBookingContext { 25 | Module cargo { 26 | basePackage = se.citerus.dddsample.domain.model 27 | 28 | Aggregate CargoItineraryLegDeliveryRouteSpecification 29 | } 30 | Module handling { 31 | basePackage = se.citerus.dddsample.domain.model 32 | 33 | Aggregate Handling 34 | } 35 | } 36 | 37 | /* We split the Voyage Planning into a separate bounded context as Evans proposes it in his book. */ 38 | BoundedContext VoyagePlanningContext { 39 | Module voyage { 40 | basePackage = se.citerus.dddsample.domain.model 41 | 42 | Aggregate Voyage 43 | } 44 | } 45 | 46 | /* Separate bounded context for managing the locations. */ 47 | BoundedContext LocationContext { 48 | Module location { 49 | basePackage = se.citerus.dddsample.domain.model 50 | 51 | Aggregate Location 52 | } 53 | } -------------------------------------------------------------------------------- /src/main/cml/ddd-sample/DDD-Sample-Stage-4.cml: -------------------------------------------------------------------------------- 1 | /* The DDD Cargo sample application modeled in CML. Note that we split the application into multiple bounded contexts. */ 2 | ContextMap DDDSampleMap { 3 | contains CargoBookingContext 4 | contains VoyagePlanningContext 5 | contains LocationContext 6 | 7 | /* As Evans mentions in his book (Bounded Context chapter): The voyage planning can be seen as 8 | * separated bounded context. However, it still shares code with the booking application (CargoBookingContext). 9 | * Thus, they are in a 'Shared-Kernel' relationship. 10 | */ 11 | CargoBookingContext [SK]<->[SK] VoyagePlanningContext 12 | 13 | /* Note that the splitting of the LocationContext is not mentioned in the original DDD sample of Evans. 14 | * However, locations and the management around them, can somehow be seen as a separated concept which is used by other 15 | * bounded contexts. But this is just an example, since we want to demonstrate our DSL with multiple bounded contexts. 16 | */ 17 | CargoBookingContext [D]<-[U,OHS,PL] LocationContext 18 | 19 | VoyagePlanningContext [D]<-[U,OHS,PL] LocationContext 20 | 21 | } 22 | 23 | /* The original booking application context */ 24 | BoundedContext CargoBookingContext { 25 | Module cargo { 26 | basePackage = se.citerus.dddsample.domain.model 27 | 28 | Aggregate CargoItineraryLegDeliveryRouteSpecification { 29 | Entity Cargo 30 | ValueObject Delivery 31 | ValueObject HandlingActivity 32 | ValueObject Itinerary 33 | ValueObject Leg 34 | ValueObject RouteSpecification 35 | enum TransportStatus { 36 | NOT_RECEIVED, IN_PORT, ONBOARD_CARRIER, CLAIMED, UNKNOWN 37 | } 38 | enum RoutingStatus { 39 | NOT_ROUTED, ROUTED, MISROUTED 40 | } 41 | } 42 | } 43 | 44 | Module handling { 45 | basePackage = se.citerus.dddsample.domain.model 46 | 47 | Aggregate Handling { 48 | DomainEvent HandlingEvent 49 | ValueObject HandlingHistory 50 | } 51 | } 52 | } 53 | 54 | /* We split the Voyage Planning into a separate bounded context as Evans proposes it in his book. */ 55 | BoundedContext VoyagePlanningContext { 56 | Module voyage { 57 | basePackage = se.citerus.dddsample.domain.model 58 | 59 | Aggregate Voyage { 60 | Entity Voyage 61 | ValueObject CarrierMovement 62 | ValueObject Schedule 63 | ValueObject VoyageNumber 64 | } 65 | } 66 | } 67 | 68 | /* Separate bounded context for managing the locations. */ 69 | BoundedContext LocationContext { 70 | Module location { 71 | basePackage = se.citerus.dddsample.domain.model 72 | 73 | Aggregate Location { 74 | Entity Location 75 | ValueObject UnLocode 76 | ValueObject LocationShared 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/main/cml/ddd-sample/DDD-Sample-Stage-5.cml: -------------------------------------------------------------------------------- 1 | /* The DDD Cargo sample application modeled in CML. Note that we split the application into multiple bounded contexts. */ 2 | ContextMap DDDSampleMap { 3 | contains CargoBookingContext 4 | contains VoyagePlanningContext 5 | contains LocationContext 6 | 7 | /* As Evans mentions in his book (Bounded Context chapter): The voyage planning can be seen as 8 | * separated bounded context. However, it still shares code with the booking application (CargoBookingContext). 9 | * Thus, they are in a 'Shared-Kernel' relationship. 10 | */ 11 | CargoBookingContext [SK]<->[SK] VoyagePlanningContext 12 | 13 | /* Note that the splitting of the LocationContext is not mentioned in the original DDD sample of Evans. 14 | * However, locations and the management around them, can somehow be seen as a separated concept which is used by other 15 | * bounded contexts. But this is just an example, since we want to demonstrate our DSL with multiple bounded contexts. 16 | */ 17 | CargoBookingContext [D]<-[U,OHS,PL] LocationContext 18 | 19 | VoyagePlanningContext [D]<-[U,OHS,PL] LocationContext 20 | 21 | } 22 | 23 | /* The original booking application context */ 24 | BoundedContext CargoBookingContext { 25 | Module cargo { 26 | basePackage = se.citerus.dddsample.domain.model 27 | 28 | Aggregate CargoItineraryLegDeliveryRouteSpecification { 29 | Entity Cargo { 30 | aggregateRoot 31 | 32 | TrackingId trackingId 33 | - LocationShared origin 34 | - RouteSpecification routeSpecification 35 | - Itinerary itinerary 36 | - Delivery delivery 37 | 38 | Repository CargoRepository { 39 | @Cargo find(TrackingId trackingId) throws CargoNotFoundException; 40 | List<@Cargo> findAll; 41 | store(@Cargo cargo); 42 | TrackingId nextTrackingId(); 43 | } 44 | } 45 | 46 | ValueObject Delivery { 47 | - TransportStatus transportStatus; 48 | - LocationShared lastKnownLocation; 49 | - Voyage currentVoyage; 50 | boolean misdirected; 51 | Date eta; 52 | - HandlingActivity nextExpectedActivity; 53 | boolean isUnloadedAtDestination; 54 | - RoutingStatus routingStatus; 55 | Date calculatedAt; 56 | - HandlingEvent lastEvent; 57 | } 58 | 59 | ValueObject HandlingActivity { 60 | HandlingEvent.Type handlingEventType 61 | - LocationShared location 62 | - Voyage voyage 63 | } 64 | 65 | ValueObject Itinerary { 66 | ItineraryNumber itineraryNumber 67 | - List legs 68 | } 69 | 70 | ValueObject Leg { 71 | - Voyage voyage 72 | - LocationShared loadLocation 73 | - LocationShared unloadLocation 74 | Date loadTime 75 | Date unloadTime 76 | } 77 | 78 | ValueObject RouteSpecification { 79 | - LocationShared origin 80 | - LocationShared destination 81 | Date arrivalDeadline 82 | } 83 | 84 | enum TransportStatus { 85 | NOT_RECEIVED, IN_PORT, ONBOARD_CARRIER, CLAIMED, UNKNOWN 86 | } 87 | 88 | enum RoutingStatus { 89 | NOT_ROUTED, ROUTED, MISROUTED 90 | } 91 | 92 | Service RoutingService { 93 | List<@Itinerary> fetchRoutesForSpecification(@RouteSpecification routeSpecification) throws LocationNotFoundException; 94 | } 95 | 96 | } 97 | } 98 | 99 | Module handling { 100 | basePackage = se.citerus.dddsample.domain.model 101 | 102 | Aggregate Handling { 103 | DomainEvent HandlingEvent { 104 | aggregateRoot 105 | persistent 106 | 107 | Type handlingType; 108 | - Voyage voyage; 109 | - LocationShared location; 110 | Date completionTime; 111 | Date registrationTime; 112 | - Cargo cargo; 113 | 114 | Repository HandlingEventRepository { 115 | @HandlingHistory lookupHandlingHistoryOfCargo(TrackingId trackingId); 116 | } 117 | } 118 | 119 | ValueObject HandlingHistory { 120 | - List handlingEvents 121 | } 122 | } 123 | } 124 | } 125 | 126 | /* We split the Voyage Planning into a separate bounded context as Evans proposes it in his book. */ 127 | BoundedContext VoyagePlanningContext { 128 | Module voyage { 129 | basePackage = se.citerus.dddsample.domain.model 130 | 131 | Aggregate Voyage { 132 | Entity Voyage { 133 | aggregateRoot 134 | 135 | - VoyageNumber voyageNumber; 136 | - Schedule schedule; 137 | 138 | Repository VoyageRepository { 139 | 140 | } 141 | } 142 | 143 | ValueObject CarrierMovement { 144 | - LocationShared departureLocation; 145 | - LocationShared arrivalLocation; 146 | Date departureTime; 147 | Date arrivalTime; 148 | } 149 | 150 | ValueObject Schedule { 151 | - List carrierMovements 152 | } 153 | 154 | ValueObject VoyageNumber { 155 | String number 156 | } 157 | } 158 | } 159 | } 160 | 161 | /* Separate bounded context for managing the locations. */ 162 | BoundedContext LocationContext { 163 | Module location { 164 | basePackage = se.citerus.dddsample.domain.model 165 | 166 | Aggregate Location { 167 | Entity Location { 168 | aggregateRoot 169 | 170 | PortCode portcode 171 | - UnLocode unLocode; 172 | String name; 173 | 174 | Repository LocationRepository { 175 | @Location find(@UnLocode unLocode); 176 | List<@Location> findAll(); 177 | } 178 | } 179 | 180 | ValueObject UnLocode { 181 | String unLocode 182 | } 183 | 184 | ValueObject LocationShared { 185 | PortCode portCode 186 | - Location location 187 | } 188 | } 189 | } 190 | } -------------------------------------------------------------------------------- /src/main/cml/ddd-sample/DDD-Sample_Alternative-Relationship-Syntax.cml: -------------------------------------------------------------------------------- 1 | /* The DDD Cargo sample application modeled in CML. Note that we split the application into multiple bounded contexts. */ 2 | ContextMap { 3 | contains CargoBookingContext 4 | contains VoyagePlanningContext 5 | contains LocationContext 6 | 7 | /* As Evans mentions in his book (Bounded Context chapter): The voyage planning can be seen as 8 | * separated bounded context. However, it still shares code with the booking application (CargoBookingContext). 9 | * Thus, they are in a 'Shared-Kernel' relationship. 10 | */ 11 | CargoBookingContext Shared-Kernel VoyagePlanningContext 12 | 13 | /* Note that the splitting of the LocationContext is not mentioned in the original DDD sample of Evans. 14 | * However, locations and the management around them, can somehow be seen as a separated concept which is used by other 15 | * bounded contexts. But this is just an example, since we want to demonstrate our DSL with multiple bounded contexts. 16 | */ 17 | CargoBookingContext Downstream-Upstream [OHS,PL]LocationContext 18 | 19 | LocationContext[OHS,PL] Upstream-Downstream VoyagePlanningContext 20 | 21 | } 22 | 23 | 24 | /* The original booking application context */ 25 | BoundedContext CargoBookingContext 26 | 27 | /* We split the Voyage Planning into a separate bounded context as Evans proposes it in his book. */ 28 | BoundedContext VoyagePlanningContext 29 | 30 | /* Separate bounded context for managing the locations. */ 31 | BoundedContext LocationContext 32 | -------------------------------------------------------------------------------- /src/main/cml/ddd-sample/README.md: -------------------------------------------------------------------------------- 1 | # DDD "Cargo" Sample Application 2 | 3 | This example is illustrates the Context Mapper DSL capabilities on the basis the [DDD "Cargo" sample application](https://github.com/citerus/dddsample-core). 4 | 5 | Since CML is dealing with context maps, we divided the application into three bounded contexts. [Evans][1] already mentioned in his book, that the voyage scheduling part is a candidate for a possible bounded contexts. Thus, we made a separate bounded context for this part. Since they still share code, they are in shared kernel relationship. Further we proposed the idea of splitting the locations into a separate bounded context, inspired by the example of [Rademacher][2]. This context could provide everything related to locations as an OPEN HOST SERVICE. Note that this is just an example in order to have another bounded context and must not be a good solution necessarily. 6 | 7 | The following figure illustrates the example. 8 | 9 | DDD Sample Context Map 10 | 11 | Here you can find the corresponding context map in CML (Context Mapper Language) in different versions and levels of detail (stages). The first four stages do 12 | not contain detailed domain models and should be understandable for users without technical knowledge (business analysis only). The last stage contains details of 13 | the domain models including attributes for all domain objects and are designed for software engineers and architects. 14 | 15 | * [DDD-Sample-Stage-1](./DDD-Sample-Stage-1.cml): A simple context map without relationship patterns in upstream-downstream relationships and without details of the bounded contexts. 16 | * [DDD-Sample-Stage-2](./DDD-Sample-Stage-2.cml): This stage refines the relationships on the context map and adds the corresponding DDD relationship patterns. 17 | * [DDD-Sample-Stage-3](./DDD-Sample-Stage-3.cml): In stage three we added first details to the bounded contexts and specified the modules and aggregates. 18 | * [DDD-Sample-Stage-4](./DDD-Sample-Stage-4.cml): A simple version including all domain objects but no attributes. This stage should still be understandable for users without technical knowledge. 19 | * [DDD-Sample-Stage-5](./DDD-Sample-Stage-5.cml): Finally, a detailed context map on the architect and engineering level. All domain objects are specified in detail (including attributes). This example further contains the repositories and services of the DDD sample app. 20 | * [DDD-Sample_Alternative-Relationship-Syntax](./DDD-Sample_Alternative-Relationship-Syntax.cml): The simple context map example in stage two, but illustrating the alternative relationship syntax. 21 | * [DDD-Sample_User-Representations](./DDD-Sample_User-Representations.scl): Service Cutter user representations file (for Service Cutter integration) to generate new service cuts 22 | 23 | [1]: https://www.oreilly.com/library/view/domain-driven-design-tackling/0321125215/ 24 | [2]: https://link.springer.com/chapter/10.1007/978-3-319-74781-1_17 25 | -------------------------------------------------------------------------------- /src/main/cml/ddd-sample/images/DDD-Cargo-Tracking-ContextMap-Illustration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-mapper-examples/0854134a15fa70384c4e192cd5e32485ca0d22b5/src/main/cml/ddd-sample/images/DDD-Cargo-Tracking-ContextMap-Illustration.png -------------------------------------------------------------------------------- /src/main/cml/ddd-service-cutting-sample/DDD-Sample.cml: -------------------------------------------------------------------------------- 1 | /** 2 | * The CargoTracking context contains the domain model of the DDD Sample application with all its Aggregates: 3 | */ 4 | BoundedContext CargoTracking { 5 | Aggregate Cargo { 6 | owner CargoPlaner 7 | 8 | Entity Cargo { 9 | aggregateRoot 10 | - TrackingId trackingId 11 | - Location origin 12 | - RouteSpecification routeSpecification 13 | - Itinerary itinerary 14 | - Delivery delivery 15 | } 16 | ValueObject TrackingId { 17 | String id 18 | } 19 | ValueObject RouteSpecification { 20 | - Location origin 21 | - Location destination 22 | Date arrivalDeadline 23 | } 24 | ValueObject Delivery { 25 | - TransportStatus transportStatus 26 | - Location lastKnownLocation 27 | - Voyage currentVoyage 28 | boolean misdirected 29 | Date eta 30 | Date estimatedArrivalTime 31 | - HandlingActivity nextExpectedActivity 32 | boolean isUnloadedAtDestination 33 | - RoutingStatus routingStatus 34 | Date calculatedAt 35 | - HandlingEvent lastEvent 36 | } 37 | ValueObject HandlingActivity { 38 | Type handlingActivityType 39 | - Location location 40 | - Voyage voyage 41 | } 42 | ValueObject Itinerary { 43 | - List legs 44 | } 45 | ValueObject Leg { 46 | - Voyage voyage 47 | - Location loadLocation 48 | - Location unloadLocation 49 | Date loadTime 50 | Date unloadTime 51 | } 52 | enum RoutingStatus { 53 | NOT_ROUTED, ROUTED, MISROUTED; 54 | } 55 | enum TransportStatus { 56 | NOT_RECEIVED, IN_PORT, ONBOARD_CARRIER, CLAIMED, UNKNOWN; 57 | } 58 | } 59 | Aggregate Location { 60 | owner Administrators 61 | 62 | Entity Location { 63 | aggregateRoot 64 | - UnLocode unLocode 65 | String name 66 | } 67 | ValueObject UnLocode { 68 | String unlocode 69 | } 70 | } 71 | Aggregate Handling { 72 | owner CargoTracker 73 | 74 | DomainEvent HandlingEvent { 75 | - HandlingEventType handlingEventType 76 | - Voyage voyage 77 | - Location location 78 | Date completionTime 79 | Date registrationTime 80 | - Cargo cargo 81 | } 82 | enum HandlingEventType { 83 | LOAD, UNLOAD, RECEIVE, CLAIM, CUSTOMS 84 | } 85 | ValueObject HandlingHistory { 86 | - List handlingEvents 87 | } 88 | } 89 | Aggregate Voyage { 90 | owner VoyageManager 91 | 92 | Entity Voyage { 93 | aggregateRoot 94 | - VoyageNumber voyageNumber 95 | - Schedule schedule 96 | } 97 | ValueObject CarrierMovement { 98 | - Location departureLocation 99 | - Location arrivalLocation 100 | Date departureTime 101 | Date arrivalTime 102 | } 103 | ValueObject Schedule { 104 | - List carrierMovements 105 | } 106 | ValueObject VoyageNumber { 107 | String number 108 | } 109 | } 110 | } 111 | 112 | BoundedContext CargoPlaner { type TEAM } 113 | BoundedContext CargoTracker { type TEAM } 114 | BoundedContext VoyageManager { type TEAM } 115 | BoundedContext Administrators { type TEAM } 116 | 117 | /* Use Cases (taken from Service Cutter examples) */ 118 | UseCase ViewTracking { 119 | interactions 120 | read "Cargo" with its "trackindId", 121 | read "HandlingEvent" with its "handlingEventType", "location", "completionTime", 122 | read "Delivery" with its "transportStatus", "estimatedArrivalTime", "misdirected", 123 | read "Voyage" with its "voyageNumber", 124 | read "RouteSpecification" with its "destination" 125 | } 126 | 127 | UseCase ViewCargos { 128 | interactions 129 | read "Cargo" with its "trackingId", 130 | read "RouteSpecification" with its "destination", "arrivalDeadline", 131 | read "Delivery" with its "routingStatus" 132 | } 133 | 134 | UseCase BookCargo { 135 | interactions 136 | read "Location" with its "unLocode", 137 | update "Cargo" with its "trackingId", 138 | update "RouteSpecification" with its "origin", "arrivalDeadline", "destination" 139 | } 140 | 141 | UseCase ChangeCargoDestination { 142 | interactions 143 | read "Cargo" with its "trackingId", 144 | read "RouteSpecification" with its "destination", 145 | update "RouteSpecification" with its "destination" 146 | } 147 | 148 | UseCase RouteCargo { 149 | interactions 150 | read "Cargo" with its "trackingId", 151 | read "RouteSpecification" with its "destination", "origin", "arrivalDeadline", 152 | read "Location" with its "unLocode", 153 | read "Voyage" with its "voyageNumber", 154 | read "CarrierMovement" with its "departureLocation", "arrivalLocation", "departureTime", "arrivalTime", 155 | update "Leg" with its "loadLocation", "unloadLocation", "loadTime", "unloadTime" 156 | } 157 | 158 | UseCase CreateLocation { 159 | interactions 160 | create "Location" with its "unLocode", "name" 161 | } 162 | 163 | UseCase CreateVoyage { 164 | interactions 165 | create "Voyage" with its "voyageNumber" 166 | } 167 | 168 | UseCase AddCarrierMovement { 169 | interactions 170 | read "Voyage" with its "voyageNumber", 171 | create "CarrierMovement" with its "departureLocation", "arrivalLocation", "departureTime", "arrivalTime" 172 | } 173 | 174 | UseCase HandleCargoEvent { 175 | interactions 176 | read "Voyage" with its "voyageNumber", 177 | read "Cargo" with its "trackingId", 178 | update "HandlingEvent" with its "handlingEventType", "completionTime", "registrationTime", "location", 179 | update "Delivery" with its "transportStatus", "misdirected", "estimatedArrivalTime", "isUnloadedAtDestination", "routingStatus" 180 | } 181 | -------------------------------------------------------------------------------- /src/main/cml/ddd-service-cutting-sample/DDD-Sample.scl: -------------------------------------------------------------------------------- 1 | 2 | UseCase ViewTracking { 3 | reads "HandlingEvent.completionTime" "Delivery.estimatedArrivalTime" "Cargo.trackindId" "HandlingEvent.handlingEventType" "Delivery.misdirected" "Delivery.transportStatus" "Voyage.voyageNumber" "RouteSpecification.destination" "HandlingEvent.location" 4 | } 5 | UseCase ViewCargos { 6 | reads "Cargo.trackingId" "RouteSpecification.arrivalDeadline" "RouteSpecification.destination" "Delivery.routingStatus" 7 | } 8 | UseCase BookCargo { 9 | reads "Location.unLocode" 10 | writes "Cargo.trackingId" "RouteSpecification.arrivalDeadline" "RouteSpecification.destination" "RouteSpecification.origin" 11 | } 12 | UseCase ChangeCargoDestination { 13 | reads "Cargo.trackingId" "RouteSpecification.destination" 14 | writes "RouteSpecification.destination" 15 | } 16 | UseCase RouteCargo { 17 | reads "Location.unLocode" "CarrierMovement.arrivalTime" "Cargo.trackingId" "CarrierMovement.departureLocation" "RouteSpecification.arrivalDeadline" "Voyage.voyageNumber" "RouteSpecification.destination" "CarrierMovement.arrivalLocation" "CarrierMovement.departureTime" "RouteSpecification.origin" 18 | writes "Leg.loadLocation" "Leg.loadTime" "Leg.unloadTime" "Leg.unloadLocation" 19 | } 20 | UseCase CreateLocation { 21 | writes "Location.unLocode" "Location.name" 22 | } 23 | UseCase CreateVoyage { 24 | writes "Voyage.voyageNumber" 25 | } 26 | UseCase AddCarrierMovement { 27 | reads "Voyage.voyageNumber" 28 | writes "CarrierMovement.arrivalTime" "CarrierMovement.departureLocation" "CarrierMovement.arrivalLocation" "CarrierMovement.departureTime" 29 | } 30 | UseCase HandleCargoEvent { 31 | reads "Cargo.trackingId" "Voyage.voyageNumber" 32 | writes "HandlingEvent.completionTime" "Delivery.estimatedArrivalTime" "Delivery.isUnloadedAtDestination" "HandlingEvent.handlingEventType" "Delivery.misdirected" "Delivery.transportStatus" "HandlingEvent.registrationTime" "HandlingEvent.location" "Delivery.routingStatus" 33 | } 34 | Compatibilities { 35 | } 36 | /* These Aggregates are generated from the CML model. Note that they are overwritten each time you use the service cut generator! */ 37 | Aggregate "Cargo" { 38 | "Leg.loadLocation" , "Delivery.currentVoyage" , "Leg.loadTime" , "HandlingActivity.location" , "Delivery.transportStatus" , "RouteSpecification.destination" , "Cargo.delivery" , "Cargo.trackingId" , "RouteSpecification.origin" , "Cargo.routeSpecification" , "Cargo.itinerary" , "Delivery.routingStatus" , "Delivery.estimatedArrivalTime" , "Delivery.lastKnownLocation" , "Delivery.calculatedAt" , "Delivery.isUnloadedAtDestination" , "Delivery.eta" , "RouteSpecification.arrivalDeadline" , "Leg.voyage" , "HandlingActivity.voyage" , "Delivery.nextExpectedActivity" , "TrackingId.id" , "Itinerary.legs" , "Delivery.lastEvent" , "Leg.unloadTime" , "Delivery.misdirected" , "Leg.unloadLocation" , "HandlingActivity.handlingActivityType" , "Cargo.origin" 39 | } 40 | Aggregate "Location" { 41 | "Location.unLocode" , "UnLocode.unlocode" , "Location.name" 42 | } 43 | Aggregate "Handling" { 44 | "HandlingHistory.handlingEvents" , "HandlingEvent.completionTime" , "HandlingEvent.handlingEventType" , "HandlingEvent.voyage" , "HandlingEvent.cargo" , "HandlingEvent.registrationTime" , "HandlingEvent.location" 45 | } 46 | Aggregate "Voyage" { 47 | "CarrierMovement.arrivalTime" , "VoyageNumber.number" , "CarrierMovement.departureLocation" , "Voyage.voyageNumber" , "Voyage.schedule" , "CarrierMovement.arrivalLocation" , "CarrierMovement.departureTime" , "Schedule.carrierMovements" 48 | } 49 | /* These Entities are generated from the CML model. Note that they are overwritten each time you use the service cut generator! */ 50 | Entity "Cargo" { 51 | "Cargo.trackingId" , "Cargo.origin" , "Cargo.routeSpecification" , "Cargo.itinerary" , "Cargo.delivery" 52 | } 53 | Entity "Location" { 54 | "Location.unLocode" , "Location.name" 55 | } 56 | Entity "Voyage" { 57 | "Voyage.voyageNumber" , "Voyage.schedule" 58 | } 59 | /* These predefined services are generated from the CML model. Note that they are overwritten each time you use the service cut generator! */ 60 | PredefinedService "CargoTracking" { 61 | "Location.unLocode" , "Leg.loadLocation" , "Delivery.currentVoyage" , "Leg.loadTime" , "HandlingActivity.location" , "HandlingEvent.cargo" , "Delivery.transportStatus" , "RouteSpecification.destination" , "HandlingEvent.registrationTime" , "CarrierMovement.departureTime" , "Cargo.delivery" , "Schedule.carrierMovements" , "HandlingEvent.completionTime" , "UnLocode.unlocode" , "Cargo.trackingId" , "HandlingEvent.handlingEventType" , "Location.name" , "CarrierMovement.arrivalLocation" , "RouteSpecification.origin" , "Cargo.routeSpecification" , "Cargo.itinerary" , "Delivery.routingStatus" , "HandlingHistory.handlingEvents" , "CarrierMovement.arrivalTime" , "Delivery.estimatedArrivalTime" , "Delivery.lastKnownLocation" , "VoyageNumber.number" , "Delivery.calculatedAt" , "Delivery.isUnloadedAtDestination" , "CarrierMovement.departureLocation" , "Delivery.eta" , "RouteSpecification.arrivalDeadline" , "Leg.voyage" , "Voyage.voyageNumber" , "Voyage.schedule" , "HandlingActivity.voyage" , "HandlingEvent.location" , "Delivery.nextExpectedActivity" , "TrackingId.id" , "HandlingEvent.voyage" , "Itinerary.legs" , "Delivery.lastEvent" , "Leg.unloadTime" , "Delivery.misdirected" , "Leg.unloadLocation" , "HandlingActivity.handlingActivityType" , "Cargo.origin" 62 | } 63 | /* These shared owner groups are generated from the CML model. Note that they are overwritten each time you use the service cut generator! */ 64 | SharedOwnerGroup "CargoTracker" { 65 | "HandlingHistory.handlingEvents" , "HandlingEvent.completionTime" , "HandlingEvent.handlingEventType" , "HandlingEvent.voyage" , "HandlingEvent.cargo" , "HandlingEvent.registrationTime" , "HandlingEvent.location" 66 | } 67 | SharedOwnerGroup "VoyageManager" { 68 | "CarrierMovement.arrivalTime" , "VoyageNumber.number" , "CarrierMovement.departureLocation" , "Voyage.voyageNumber" , "Voyage.schedule" , "CarrierMovement.arrivalLocation" , "CarrierMovement.departureTime" , "Schedule.carrierMovements" 69 | } 70 | SharedOwnerGroup "Administrators" { 71 | "Location.unLocode" , "UnLocode.unlocode" , "Location.name" 72 | } 73 | SharedOwnerGroup "CargoPlaner" { 74 | "Leg.loadLocation" , "Delivery.currentVoyage" , "Leg.loadTime" , "HandlingActivity.location" , "Delivery.transportStatus" , "RouteSpecification.destination" , "Cargo.delivery" , "Cargo.trackingId" , "RouteSpecification.origin" , "Cargo.routeSpecification" , "Cargo.itinerary" , "Delivery.routingStatus" , "Delivery.estimatedArrivalTime" , "Delivery.lastKnownLocation" , "Delivery.calculatedAt" , "Delivery.isUnloadedAtDestination" , "Delivery.eta" , "RouteSpecification.arrivalDeadline" , "Leg.voyage" , "HandlingActivity.voyage" , "Delivery.nextExpectedActivity" , "TrackingId.id" , "Itinerary.legs" , "Delivery.lastEvent" , "Leg.unloadTime" , "Delivery.misdirected" , "Leg.unloadLocation" , "HandlingActivity.handlingActivityType" , "Cargo.origin" 75 | } 76 | -------------------------------------------------------------------------------- /src/main/cml/insurance-example/Insurance-Example-Stage-1.cml: -------------------------------------------------------------------------------- 1 | /* Example Context Map written with 'ContextMapper DSL' */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | 6 | /* Add bounded contexts to this context map: */ 7 | contains CustomerManagementContext 8 | contains CustomerSelfServiceContext 9 | contains PrintingContext 10 | contains PolicyManagementContext 11 | contains RiskManagementContext 12 | contains DebtCollection 13 | 14 | /* Define the context relationships: */ 15 | 16 | CustomerSelfServiceContext <- CustomerManagementContext 17 | 18 | CustomerManagementContext <- PrintingContext 19 | 20 | PrintingContext -> PolicyManagementContext 21 | 22 | RiskManagementContext <-> PolicyManagementContext 23 | 24 | PolicyManagementContext <- CustomerManagementContext 25 | 26 | DebtCollection <- PrintingContext 27 | 28 | PolicyManagementContext <-> DebtCollection 29 | } 30 | 31 | /* Bounded Context Definitions */ 32 | BoundedContext CustomerManagementContext implements CustomerManagementDomain 33 | 34 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain 35 | 36 | BoundedContext PrintingContext implements PrintingDomain 37 | 38 | BoundedContext PolicyManagementContext implements PolicyManagementDomain 39 | 40 | BoundedContext RiskManagementContext implements RiskManagementDomain 41 | 42 | BoundedContext DebtCollection implements DebtsDomain 43 | 44 | /* Domain & Subdomain Definitions */ 45 | Domain InsuranceDomain { 46 | Subdomain CustomerManagementDomain { 47 | type = CORE_DOMAIN 48 | domainVisionStatement = "Subdomain managing everything customer-related." 49 | } 50 | Subdomain PolicyManagementDomain { 51 | type = CORE_DOMAIN 52 | domainVisionStatement = "Subdomain managing contracts and policies." 53 | } 54 | Subdomain PrintingDomain { 55 | type = SUPPORTING_DOMAIN 56 | domainVisionStatement = "Service (external system) to solve printing for all kinds of documents (debts, policies, etc.)" 57 | } 58 | Subdomain RiskManagementDomain { 59 | type = GENERIC_SUBDOMAIN 60 | domainVisionStatement = "Subdomain supporting everything which relates to risk management." 61 | } 62 | Subdomain DebtsDomain { 63 | type = GENERIC_SUBDOMAIN 64 | domainVisionStatement = "Subomain including everything related to the incoming money (debts, dunning, etc.)" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/cml/insurance-example/Insurance-Example-Stage-2.cml: -------------------------------------------------------------------------------- 1 | /* Example Context Map written with 'ContextMapper DSL' */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | 6 | /* Add bounded contexts to this context map: */ 7 | contains CustomerManagementContext 8 | contains CustomerSelfServiceContext 9 | contains PrintingContext 10 | contains PolicyManagementContext 11 | contains RiskManagementContext 12 | contains DebtCollection 13 | 14 | /* Define the context relationships: */ 15 | 16 | CustomerSelfServiceContext [D,C]<-[U,S] CustomerManagementContext 17 | 18 | CustomerManagementContext [D,ACL]<-[U,OHS,PL] PrintingContext 19 | 20 | PrintingContext [U,OHS,PL]->[D,ACL] PolicyManagementContext 21 | 22 | RiskManagementContext [P]<->[P] PolicyManagementContext 23 | 24 | PolicyManagementContext [D,CF]<-[U,OHS,PL] CustomerManagementContext 25 | 26 | DebtCollection [D,ACL]<-[U,OHS,PL] PrintingContext 27 | 28 | PolicyManagementContext [SK]<->[SK] DebtCollection 29 | } 30 | 31 | /* Bounded Context Definitions */ 32 | BoundedContext CustomerManagementContext implements CustomerManagementDomain 33 | 34 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain 35 | 36 | BoundedContext PrintingContext implements PrintingDomain 37 | 38 | BoundedContext PolicyManagementContext implements PolicyManagementDomain 39 | 40 | BoundedContext RiskManagementContext implements RiskManagementDomain 41 | 42 | BoundedContext DebtCollection implements DebtsDomain 43 | 44 | /* Domain & Subdomain Definitions */ 45 | Domain InsuranceDomain { 46 | Subdomain CustomerManagementDomain { 47 | type = CORE_DOMAIN 48 | domainVisionStatement = "Subdomain managing everything customer-related." 49 | } 50 | Subdomain PolicyManagementDomain { 51 | type = CORE_DOMAIN 52 | domainVisionStatement = "Subdomain managing contracts and policies." 53 | } 54 | Subdomain PrintingDomain { 55 | type = SUPPORTING_DOMAIN 56 | domainVisionStatement = "Service (external system) to solve printing for all kinds of documents (debts, policies, etc.)" 57 | } 58 | Subdomain RiskManagementDomain { 59 | type = GENERIC_SUBDOMAIN 60 | domainVisionStatement = "Subdomain supporting everything which relates to risk management." 61 | } 62 | Subdomain DebtsDomain { 63 | type = GENERIC_SUBDOMAIN 64 | domainVisionStatement = "Subomain including everything related to the incoming money (debts, dunning, etc.)" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/cml/insurance-example/Insurance-Example-Stage-3.cml: -------------------------------------------------------------------------------- 1 | /* Example Context Map written with 'ContextMapper DSL' */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | 6 | /* Add bounded contexts to this context map: */ 7 | contains CustomerManagementContext 8 | contains CustomerSelfServiceContext 9 | contains PrintingContext 10 | contains PolicyManagementContext 11 | contains RiskManagementContext 12 | contains DebtCollection 13 | 14 | /* Define the context relationships: */ 15 | 16 | CustomerSelfServiceContext [D,C]<-[U,S] CustomerManagementContext 17 | 18 | CustomerManagementContext [D,ACL]<-[U,OHS,PL] PrintingContext 19 | 20 | PrintingContext [U,OHS,PL]->[D,ACL] PolicyManagementContext 21 | 22 | RiskManagementContext [P]<->[P] PolicyManagementContext 23 | 24 | PolicyManagementContext [D,CF]<-[U,OHS,PL] CustomerManagementContext 25 | 26 | DebtCollection [D,ACL]<-[U,OHS,PL] PrintingContext 27 | 28 | PolicyManagementContext [SK]<->[SK] DebtCollection 29 | } 30 | 31 | /* Bounded Context Definitions */ 32 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 33 | type = FEATURE 34 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 35 | implementationTechnology = "Java, JEE Application" 36 | responsibilities = "Customers, Addresses" 37 | 38 | Aggregate Customers 39 | 40 | } 41 | 42 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 43 | type = APPLICATION 44 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 45 | responsibilities = "AddressChange" 46 | implementationTechnology = "PHP Web Application" 47 | 48 | Aggregate CustomerFrontend 49 | 50 | Aggregate Acounts 51 | } 52 | 53 | BoundedContext PrintingContext implements PrintingDomain { 54 | type = SYSTEM 55 | responsibilities = "Document Printing" 56 | domainVisionStatement = "An external system which provides printing services to the other Bounded Contexts." 57 | 58 | Aggregate Printing 59 | 60 | Aggregate Templating 61 | } 62 | 63 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 64 | type = FEATURE 65 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 66 | responsibilities = "Offers, Contracts, Policies" 67 | implementationTechnology = "Java, Spring App" 68 | 69 | Aggregate Offers 70 | 71 | Aggregate Products 72 | 73 | Aggregate Contract 74 | } 75 | 76 | BoundedContext RiskManagementContext implements RiskManagementDomain { 77 | type = FEATURE 78 | domainVisionStatement = "Uses data from PolicyManagement context to calculate risks." 79 | responsibilities = "Customer Risk Calculation" 80 | implementationTechnology = "Java, Spring App" 81 | 82 | Aggregate Risks 83 | } 84 | 85 | BoundedContext DebtCollection implements DebtsDomain { 86 | type = FEATURE 87 | domainVisionStatement = "The debt collection context is responsible for the financial income of the insurance company (the debts) which depend on the corresponding contracts and policies." 88 | responsibilities = "Debts, Dunning" 89 | implementationTechnology = "JEE" 90 | 91 | Aggregate Debts 92 | } 93 | 94 | /* Domain & Subdomain Definitions */ 95 | Domain InsuranceDomain { 96 | Subdomain CustomerManagementDomain { 97 | type = CORE_DOMAIN 98 | domainVisionStatement = "Subdomain managing everything customer-related." 99 | } 100 | Subdomain PolicyManagementDomain { 101 | type = CORE_DOMAIN 102 | domainVisionStatement = "Subdomain managing contracts and policies." 103 | } 104 | Subdomain PrintingDomain { 105 | type = SUPPORTING_DOMAIN 106 | domainVisionStatement = "Service (external system) to solve printing for all kinds of documents (debts, policies, etc.)" 107 | } 108 | Subdomain RiskManagementDomain { 109 | type = GENERIC_SUBDOMAIN 110 | domainVisionStatement = "Subdomain supporting everything which relates to risk management." 111 | } 112 | Subdomain DebtsDomain { 113 | type = GENERIC_SUBDOMAIN 114 | domainVisionStatement = "Subomain including everything related to the incoming money (debts, dunning, etc.)" 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/cml/insurance-example/Insurance-Example-Stage-4.cml: -------------------------------------------------------------------------------- 1 | /* Example Context Map written with 'ContextMapper DSL' */ 2 | ContextMap InsuranceContextMap { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | 6 | /* Add bounded contexts to this context map: */ 7 | contains CustomerManagementContext 8 | contains CustomerSelfServiceContext 9 | contains PrintingContext 10 | contains PolicyManagementContext 11 | contains RiskManagementContext 12 | contains DebtCollection 13 | 14 | /* Define the context relationships: */ 15 | 16 | CustomerSelfServiceContext [D,C]<-[U,S] CustomerManagementContext 17 | 18 | CustomerManagementContext [D,ACL]<-[U,OHS,PL] PrintingContext 19 | 20 | PrintingContext [U,OHS,PL]->[D,ACL] PolicyManagementContext 21 | 22 | RiskManagementContext [P]<->[P] PolicyManagementContext 23 | 24 | PolicyManagementContext [D,CF]<-[U,OHS,PL] CustomerManagementContext 25 | 26 | DebtCollection [D,ACL]<-[U,OHS,PL] PrintingContext 27 | 28 | PolicyManagementContext [SK]<->[SK] DebtCollection 29 | } 30 | 31 | /* Bounded Context Definitions */ 32 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 33 | type = FEATURE 34 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 35 | implementationTechnology = "Java, JEE Application" 36 | responsibilities = "Customers, Addresses" 37 | 38 | Aggregate Customers { 39 | Entity Customer 40 | Entity Address 41 | ValueObject SocialInsuranceNumber 42 | } 43 | 44 | } 45 | 46 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 47 | type = APPLICATION 48 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 49 | responsibilities = "AddressChange" 50 | implementationTechnology = "PHP Web Application" 51 | 52 | Aggregate CustomerFrontend { 53 | Entity CustomerAddressChange 54 | } 55 | 56 | Aggregate Acounts { 57 | Entity UserAccount 58 | } 59 | } 60 | 61 | BoundedContext PrintingContext implements PrintingDomain { 62 | type = SYSTEM 63 | responsibilities = "Document Printing" 64 | domainVisionStatement = "An external system which provides printing services to the other Bounded Contexts." 65 | 66 | Aggregate Printing { 67 | Entity PrintingJob 68 | Entity Document 69 | } 70 | 71 | Aggregate Templating { 72 | Entity Template 73 | } 74 | } 75 | 76 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 77 | type = FEATURE 78 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 79 | responsibilities = "Offers, Contracts, Policies" 80 | implementationTechnology = "Java, Spring App" 81 | 82 | Aggregate Offers { 83 | Entity Offer 84 | } 85 | 86 | Aggregate Products { 87 | Entity Product 88 | ValueObject ProductId 89 | } 90 | 91 | Aggregate Contract { 92 | Entity Contract 93 | ValueObject ContractId 94 | Entity Policy 95 | } 96 | } 97 | 98 | BoundedContext RiskManagementContext implements RiskManagementDomain { 99 | type = FEATURE 100 | domainVisionStatement = "Uses data from PolicyManagement context to calculate risks." 101 | responsibilities = "Customer Risk Calculation" 102 | implementationTechnology = "Java, Spring App" 103 | 104 | Aggregate Risks { 105 | Entity CustomerRiskFactor 106 | ValueObject Risk 107 | } 108 | } 109 | 110 | BoundedContext DebtCollection implements DebtsDomain { 111 | type = FEATURE 112 | domainVisionStatement = "The debt collection context is responsible for the financial income of the insurance company (the debts) which depend on the corresponding contracts and policies." 113 | responsibilities = "Debts, Dunning" 114 | implementationTechnology = "JEE" 115 | 116 | Aggregate Debts { 117 | Entity Debt 118 | Entity Dunning 119 | } 120 | } 121 | 122 | /* Domain & Subdomain Definitions */ 123 | Domain InsuranceDomain { 124 | Subdomain CustomerManagementDomain { 125 | type = CORE_DOMAIN 126 | domainVisionStatement = "Subdomain managing everything customer-related." 127 | } 128 | Subdomain PolicyManagementDomain { 129 | type = CORE_DOMAIN 130 | domainVisionStatement = "Subdomain managing contracts and policies." 131 | } 132 | Subdomain PrintingDomain { 133 | type = SUPPORTING_DOMAIN 134 | domainVisionStatement = "Service (external system) to solve printing for all kinds of documents (debts, policies, etc.)" 135 | } 136 | Subdomain RiskManagementDomain { 137 | type = GENERIC_SUBDOMAIN 138 | domainVisionStatement = "Subdomain supporting everything which relates to risk management." 139 | } 140 | Subdomain DebtsDomain { 141 | type = GENERIC_SUBDOMAIN 142 | domainVisionStatement = "Subomain including everything related to the incoming money (debts, dunning, etc.)" 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/cml/insurance-example/Insurance-Example_Alternative-Relationship-Syntax.cml: -------------------------------------------------------------------------------- 1 | /* Example Context Map written with 'ContextMapper DSL' */ 2 | ContextMap InsuranceContextMapAlternative { 3 | type = SYSTEM_LANDSCAPE 4 | state = TO_BE 5 | 6 | /* Add bounded contexts to this context map: */ 7 | contains CustomerManagementContext 8 | contains CustomerSelfServiceContext 9 | contains PrintingContext 10 | contains PolicyManagementContext 11 | contains RiskManagementContext 12 | contains DebtCollection 13 | 14 | /* Define the context relationships: */ 15 | 16 | CustomerSelfServiceContext Customer-Supplier CustomerManagementContext 17 | 18 | PrintingContext[OHS,PL] Upstream-Downstream [ACL]CustomerManagementContext 19 | 20 | PolicyManagementContext[ACL] Downstream-Upstream [OHS,PL]PrintingContext 21 | 22 | RiskManagementContext Partnership PolicyManagementContext 23 | 24 | CustomerManagementContext[OHS,PL] Upstream-Downstream [CF]PolicyManagementContext 25 | 26 | DebtCollection[ACL] Downstream-Upstream [OHS,PL]PrintingContext 27 | 28 | PolicyManagementContext Shared-Kernel DebtCollection 29 | } 30 | 31 | /* Bounded Context Definitions */ 32 | BoundedContext CustomerManagementContext implements CustomerManagementDomain 33 | 34 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain 35 | 36 | BoundedContext PrintingContext implements PrintingDomain 37 | 38 | BoundedContext PolicyManagementContext implements PolicyManagementDomain 39 | 40 | BoundedContext RiskManagementContext implements RiskManagementDomain 41 | 42 | BoundedContext DebtCollection implements DebtsDomain 43 | 44 | /* Domain & Subdomain Definitions */ 45 | Domain InsuranceDomain { 46 | Subdomain CustomerManagementDomain { 47 | type = CORE_DOMAIN 48 | domainVisionStatement = "Subdomain managing everything customer-related." 49 | } 50 | Subdomain PolicyManagementDomain { 51 | type = CORE_DOMAIN 52 | domainVisionStatement = "Subdomain managing contracts and policies." 53 | } 54 | Subdomain PrintingDomain { 55 | type = SUPPORTING_DOMAIN 56 | domainVisionStatement = "Service (external system) to solve printing for all kinds of documents (debts, policies, etc.)" 57 | } 58 | Subdomain RiskManagementDomain { 59 | type = GENERIC_SUBDOMAIN 60 | domainVisionStatement = "Subdomain supporting everything which relates to risk management." 61 | } 62 | Subdomain DebtsDomain { 63 | type = GENERIC_SUBDOMAIN 64 | domainVisionStatement = "Subomain including everything related to the incoming money (debts, dunning, etc.)" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/cml/insurance-example/Insurance-Example_Team-Map.cml: -------------------------------------------------------------------------------- 1 | /* Example Context Map written with 'ContextMapper DSL' */ 2 | ContextMap InsuranceTeamMap { 3 | type = ORGANIZATIONAL 4 | state = TO_BE 5 | 6 | /* Add contexts that represent subsystems/components to this organizational map: */ 7 | contains CustomerManagementContext, CustomerSelfServiceContext, PolicyManagementContext, RiskManagementContext 8 | 9 | /* Add teams to this organizational map: */ 10 | contains CustomersBackofficeTeam, CustomersFrontofficeTeam, ContractsTeam 11 | 12 | /* Define the subsystem/component relationships: */ 13 | 14 | CustomerSelfServiceContext [D,C]<-[U,S] CustomerManagementContext 15 | 16 | PolicyManagementContext [D,CF]<-[U,OHS,PL] CustomerManagementContext 17 | 18 | PolicyManagementContext [P]<->[P] RiskManagementContext 19 | 20 | /* Define the team relationships: */ 21 | 22 | CustomersBackofficeTeam [U,S]->[D,C] CustomersFrontofficeTeam 23 | 24 | CustomersBackofficeTeam [U]->[D] ContractsTeam 25 | 26 | } 27 | 28 | /* Team Definitions */ 29 | BoundedContext CustomersBackofficeTeam implements CustomerManagementDomain realizes CustomerManagementContext { 30 | type = TEAM 31 | domainVisionStatement = "This team is responsible for implementing the customers module in the back-office system." 32 | } 33 | 34 | BoundedContext CustomersFrontofficeTeam implements CustomerManagementDomain realizes CustomerSelfServiceContext { 35 | type = TEAM 36 | domainVisionStatement = "This team is responsible for implementing the front-office application for the insurance customers." 37 | } 38 | 39 | BoundedContext ContractsTeam implements PolicyManagementDomain, RiskManagementDomain realizes PolicyManagementContext, RiskManagementContext { 40 | type = TEAM 41 | domainVisionStatement = "This team is responsible for implementing the contract-, policy-, and risk-management modules in the back-office system." 42 | } 43 | 44 | /* Bounded Context Definitions */ 45 | BoundedContext CustomerManagementContext implements CustomerManagementDomain { 46 | type = FEATURE 47 | domainVisionStatement = "The customer management context is responsible for managing all the data of the insurance companies customers." 48 | implementationTechnology = "Java, JEE Application" 49 | responsibilities = "Customers, Addresses" 50 | 51 | Aggregate Customers { 52 | Entity Customer { 53 | aggregateRoot 54 | 55 | - SocialInsuranceNumber sin 56 | String firstname 57 | String lastname 58 | - List
addresses 59 | } 60 | 61 | Entity Address { 62 | String street 63 | int postalCode 64 | String city 65 | } 66 | 67 | ValueObject SocialInsuranceNumber { 68 | String sin key 69 | } 70 | } 71 | 72 | } 73 | 74 | BoundedContext CustomerSelfServiceContext implements CustomerManagementDomain { 75 | type = APPLICATION 76 | domainVisionStatement = "This context represents a web application which allows the customer to login and change basic data records like the address." 77 | responsibilities = "Address Change" 78 | implementationTechnology = "PHP Web Application" 79 | 80 | Aggregate CustomerFrontend { 81 | Entity CustomerAddressChange { 82 | aggregateRoot 83 | 84 | - UserAccount issuer 85 | - Address changedAddress 86 | } 87 | } 88 | 89 | Aggregate Acounts { 90 | Entity UserAccount { 91 | aggregateRoot 92 | 93 | String username 94 | - Customer accountCustomer 95 | } 96 | } 97 | } 98 | 99 | BoundedContext PolicyManagementContext implements PolicyManagementDomain { 100 | type = FEATURE 101 | domainVisionStatement = "This bounded context manages the contracts and policies of the customers." 102 | responsibilities = "Offers, Contracts, Policies" 103 | implementationTechnology = "Java, Spring App" 104 | 105 | Aggregate Offers { 106 | Entity Offer { 107 | aggregateRoot 108 | 109 | int offerId 110 | - Customer client 111 | - List products 112 | BigDecimal price 113 | } 114 | } 115 | 116 | Aggregate Products { 117 | Entity Product { 118 | aggregateRoot 119 | 120 | - ProductId identifier 121 | String productName 122 | } 123 | 124 | ValueObject ProductId { 125 | int productId key 126 | } 127 | } 128 | 129 | Aggregate Contract { 130 | Entity Contract { 131 | aggregateRoot 132 | 133 | - ContractId identifier 134 | - Customer client 135 | - List products 136 | } 137 | 138 | ValueObject ContractId { 139 | int contractId key 140 | } 141 | 142 | Entity Policy { 143 | int policyNr 144 | - Contract contract 145 | BigDecimal price 146 | } 147 | } 148 | } 149 | 150 | BoundedContext RiskManagementContext implements RiskManagementDomain { 151 | type = FEATURE 152 | domainVisionStatement = "Uses data from PolicyManagement context to calculate risks." 153 | responsibilities = "Customer Risk Calculation" 154 | implementationTechnology = "Java, Spring App" 155 | 156 | Aggregate Risks { 157 | Entity CustomerRiskFactor { 158 | aggregateRoot 159 | 160 | int totalRiskFactor 161 | - List risks 162 | - Customer client 163 | } 164 | 165 | ValueObject Risk { 166 | int likelihood 167 | String risk 168 | } 169 | } 170 | } 171 | 172 | /* Domain & Subdomain Definitions */ 173 | Domain InsuranceDomain { 174 | Subdomain CustomerManagementDomain { 175 | type = CORE_DOMAIN 176 | domainVisionStatement = "Subdomain managing everything customer-related." 177 | } 178 | Subdomain PolicyManagementDomain { 179 | type = CORE_DOMAIN 180 | domainVisionStatement = "Subdomain managing contracts and policies." 181 | } 182 | Subdomain RiskManagementDomain { 183 | type = GENERIC_SUBDOMAIN 184 | domainVisionStatement = "Subdomain supporting everything which relates to risk management." 185 | } 186 | Subdomain DebtsDomain { 187 | type = GENERIC_SUBDOMAIN 188 | domainVisionStatement = "Subomain including everything related to the incoming money (debts, dunning, etc.)" 189 | } 190 | } 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /src/main/cml/insurance-example/README.md: -------------------------------------------------------------------------------- 1 | # Insurance Company Example 2 | This example illustrates the Context Mapper DSL capabilities on the basis of a fictitious insurance company scenario. The bounded contexts are partially inspired by the [Lakeside Mutual](https://github.com/Microservice-API-Patterns/LakesideMutual) project. 3 | Note that the goal of the example is to give a representative overview over the DSL's context mapping features. The contexts and their relationships may differ considerably in a real-world insurance company. 4 | 5 | ## Context Map 6 | The following figure illustrates the Context Map in a graphical representation inspired by [Vernon][1] and [Brandolini][2]. 7 | 8 | Insurance Company Example Context Map 9 | 10 | You can find the corresponding context map in CML (Context Mapper Language) here in different versions and levels of detail (stages). The first four stages do 11 | not contain detailed domain models and should be understandable for users without technical knowledge (business analysis only). The last stage contains details of 12 | the domain models including attributes for all domain objects and are designed for software engineers and architects. 13 | 14 | * [Insurance-Example-Stage-1](./Insurance-Example-Stage-1.cml): A simple context map without relationship patterns in upstream-downstream relationships and without details of the bounded contexts. 15 | * [Insurance-Example-Stage-2](./Insurance-Example-Stage-2.cml): This stage refines the relationships on the context map and adds the corresponding DDD relationship patterns. 16 | * [Insurance-Example-Stage-3](./Insurance-Example-Stage-3.cml): In stage three we added first details to the bounded contexts and specified the aggregates. 17 | * [Insurance-Example-Stage-4](./Insurance-Example-Stage-4.cml): A simple version including all domain objects but no attributes. This stage should still be understandable for users without technical knowledge. 18 | * [Insurance-Example-Stage-5](./Insurance-Example-Stage-5.cml): Finally, a detailed context map on the architect and engineering level. All domain objects are specified in detail (including attributes). This example further contains methods in aggregate root entities. 19 | * [Insurance-Example_Alternative-Relationship-Syntax](./Insurance-Example_Alternative-Relationship-Syntax.cml): The simple context map example in stage two, but illustrating the alternative relationship syntax. 20 | * [Insurance-Example_User_Representations](./Insurance-Example_User_Representations.scl): Service Cutter user representations file (for Service Cutter integration) to generate new service cuts 21 | 22 | The following bounded contexts are involved in the system: 23 | * Customer Management 24 | * Customer Self-Service Management 25 | * Policy Management 26 | * Debt Collection 27 | * Risk Management 28 | * Printing Context 29 | 30 | ## Team Map 31 | Besides classic context maps with bounded contexts, CML supports modeling teams and their relationships as it is possible with bounded contexts. This is done by simply change the type of a bounded context from SYSTEM, FEATURE or APPLICATION to TEAM. Note that the type of the context map is ORGANIZATIONAL in this case. 32 | 33 | * [Insurance-Example_Team-Map](./Insurance-Example_Team-Map.cml): A team map example for the insurance scenario 34 | 35 | As you can see in the example linked above, you can further use the _realizes_ to define which teams work on which systems, applications, or features. By using the graphical Context Map generator, you can then generate team maps that illustrate the relations between development teams and system bounded contexts. 36 | 37 | Depending how you parameterize the generator, the produced illustrations will be unclustered... 38 | 39 | Insurance Company Example Team Map (Unclustered) 40 | 41 | ... or clustered: 42 | 43 | Insurance Company Example Team Map (Clustered) 44 | 45 | ## Bounded Contexts 46 | 47 | ### Customer Management 48 | The customer management context is responsible for managing all the data of the insurance companies customers. Thus, it is typically a central bounded context which has relationships to many other contexts. 49 | 50 | ### Customer Self-Service Management 51 | This context represents a web application which allows the customer to login and change basic data records like the address. 52 | 53 | ### Policy Management 54 | This bounded context manages the contracts and policies of the customers. It works in a _partnership_ together with the risk management context, since it needs the customer risk data for calculating the customer rates. Further, it has a _shared kernel_ with the debt collection context. 55 | 56 | ### Debt Collection 57 | The debt collection context is responsible for the financial income of the insurance company (the debts) which depend on the corresponding contracts and policies. 58 | 59 | ### Risk Management 60 | The risk management context works in a close _relationship_ with the policy management context and calculates risks which influence contracts and policies. 61 | 62 | ### Printing Context 63 | This context represents an external system which is accessed by an API by many internal contexts. It handles documents which have to be printed, as for example debts, policies, etc. 64 | 65 | [1]: https://www.amazon.de/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577 66 | [2]: https://www.infoq.com/articles/ddd-contextmapping 67 | -------------------------------------------------------------------------------- /src/main/cml/insurance-example/images/ContextMap-Illustration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-mapper-examples/0854134a15fa70384c4e192cd5e32485ca0d22b5/src/main/cml/insurance-example/images/ContextMap-Illustration.png -------------------------------------------------------------------------------- /src/main/cml/insurance-example/images/TeamMap-Illustration-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-mapper-examples/0854134a15fa70384c4e192cd5e32485ca0d22b5/src/main/cml/insurance-example/images/TeamMap-Illustration-1.png -------------------------------------------------------------------------------- /src/main/cml/insurance-example/images/TeamMap-Illustration-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-mapper-examples/0854134a15fa70384c4e192cd5e32485ca0d22b5/src/main/cml/insurance-example/images/TeamMap-Illustration-2.png -------------------------------------------------------------------------------- /src/main/cml/lakeside-mutual/QuoteRequestFlow.cml: -------------------------------------------------------------------------------- 1 | /** 2 | * A RequestStatus is a value object that is used to represent 3 | * the current status of an insurance quote request. 4 | * 5 | * The following diagram shows the possible state transitions: 6 | * 7 | *
 8 |  * 
 9 |  *                                               │
10 |  *                                               ▼
11 |  *                                        ┌────────────┐
12 |  *                                        │  REQUEST_  │
13 |  *                                        │ SUBMITTED  │
14 |  *                                        └────────────┘
15 |  *                                               │
16 |  *                             ┌─────────────────┴────────────────┐
17 |  *                             │                                  │
18 |  *                             ▼                                  ▼
19 |  *                      ┌────────────┐                     ╔════════════╗
20 |  *                      │   QUOTE_   │                     ║  REQUEST_  ║
21 |  *          ┌───────────│  RECEIVED  │─────────────┐       ║  REJECTED  ║
22 |  *          │           └────────────┘             │       ╚════════════╝
23 |  *          │                  │                   │
24 |  *          │                  │                   │
25 |  *          ▼                  ▼                   ▼
26 |  *   ╔════════════╗     ┌────────────┐      ╔════════════╗
27 |  *   ║   QUOTE_   ║     │   QUOTE_   │      ║   QUOTE_   ║
28 |  *   ║  REJECTED  ║     │  ACCEPTED  │─────▶║  EXPIRED   ║
29 |  *   ╚════════════╝     └────────────┘      ╚════════════╝
30 |  *                             │
31 |  *                             │
32 |  *                             ▼
33 |  *                      ╔════════════╗
34 |  *                      ║  POLICY_   ║
35 |  *                      ║  CREATED   ║
36 |  *                      ╚════════════╝
37 |  * 
38 |  * 
39 | */ 40 | 41 | BoundedContext InsuranceQuotes { 42 | Application { 43 | Command SubmitRequest 44 | Flow QuoteRequestFlow { 45 | command SubmitRequest delegates to QuoteRequest[-> SUBMITTED] emits event RequestSubmitted 46 | event RequestSubmitted + RequestSubmitted triggers operation checkRequest 47 | operation checkRequest delegates to QuoteRequest[SUBMITTED -> RECEIVED X REJECTED] emits event QuoteReceived X RequestRejected 48 | event QuoteReceived triggers operation receiveAndCheckQuote 49 | operation receiveAndCheckQuote delegates to QuoteRequest[RECEIVED -> REJECTED X ACCEPTED X EXPIRED] emits event QuoteRejected X QuoteAccepted X QuoteExpired 50 | event QuoteAccepted triggers operation accept 51 | operation accept delegates to QuoteRequest[ACCEPTED -> POLICY_CREATED X EXPIRED] emits event PolicyCreated X QuoteExpired 52 | } 53 | } 54 | Aggregate QuoteRequest { 55 | Entity Request { 56 | aggregateRoot 57 | } 58 | DomainEvent RequestSubmitted 59 | DomainEvent QuoteReceived 60 | DomainEvent RequestRejected 61 | DomainEvent QuoteRejected 62 | DomainEvent QuoteAccepted 63 | DomainEvent QuoteExpired 64 | DomainEvent PolicyCreated 65 | Service QuoteRequestService { 66 | void checkRequest(@Request request); 67 | void receiveAndCheckQuote(@Request request); 68 | void reject(@Request request); 69 | void accept(@Request request); 70 | } 71 | enum RequestState { 72 | aggregateLifecycle 73 | SUBMITTED, RECEIVED, REJECTED, ACCEPTED, EXPIRED, POLICY_CREATED 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/cml/lakeside-mutual/README.md: -------------------------------------------------------------------------------- 1 | # Lakeside Mutual Example 2 | This example illustrates Context Mapper capabilities on the basis of a fictitious insurance project called [Lakeside Mutual](https://github.com/Microservice-API-Patterns/LakesideMutual) project. The CML model of this example has been reverse engineered with our [discovery library](https://github.com/ContextMapper/context-map-discovery). With an Event Storming we have enhanced the model for a future feature that could be realized in the project (claim processing). 3 | 4 | ## Context Map 5 | The following figure illustrates the Context Map in a graphical representation generated with our [Context Map generator](https://contextmapper.org/docs/context-map-generator/): 6 | 7 | Lakeside Mutual Example Context Map 8 | 9 | The complete CML model of the system can be found in the following file: [LakesideMutual.cml](./LakesideMutual.cml) 10 | 11 | ## Event Storming 12 | We extended the reverse engineered CML model of the Lakeside Mutual to support claim processing as a future feature. We conducted an Event Storming to 13 | analyze the subdomain for the new feature. The example shall illustrate how Event Storming results can be modeled in Context Mapper. 14 | 15 | (a tutorial how Context Mapper can be used to model Event Storming results will be published on our website soon) 16 | 17 | The following graphic shows the [result of our Event Storming](https://raw.githubusercontent.com/ContextMapper/context-mapper-examples/master/src/main/cml/lakeside-mutual/images/event-storming-result.jpg): 18 | 19 | Lakeside Mutual Claim Processing Event Storming 20 | -------------------------------------------------------------------------------- /src/main/cml/lakeside-mutual/images/ContextMap-Illustration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-mapper-examples/0854134a15fa70384c4e192cd5e32485ca0d22b5/src/main/cml/lakeside-mutual/images/ContextMap-Illustration.png -------------------------------------------------------------------------------- /src/main/cml/lakeside-mutual/images/event-storming-result.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-mapper-examples/0854134a15fa70384c4e192cd5e32485ca0d22b5/src/main/cml/lakeside-mutual/images/event-storming-result.jpg -------------------------------------------------------------------------------- /src/main/cml/microservice-generation/JDL-example/generated-insurance-microservices.jdl: -------------------------------------------------------------------------------- 1 | 2 | /* Bounded Context CustomerManagement */ 3 | 4 | entity Customer { 5 | firstname String 6 | lastname String 7 | } 8 | 9 | 10 | entity Address { 11 | street String 12 | postalCode Integer 13 | city String 14 | } 15 | 16 | microservice Customer, Address with CustomerManagement 17 | 18 | application { 19 | config { 20 | baseName CustomerManagement, 21 | packageName org.contextmapper.generated.customermanagement, 22 | applicationType microservice 23 | serverPort 8081 24 | } 25 | entities Customer, Address 26 | } 27 | 28 | /* Bounded Context CustomerSelfService */ 29 | 30 | entity CustomerAddressChange { 31 | } 32 | 33 | 34 | entity UserAccount { 35 | username String 36 | } 37 | 38 | microservice CustomerAddressChange, UserAccount with CustomerSelfService 39 | 40 | application { 41 | config { 42 | baseName CustomerSelfService, 43 | packageName org.contextmapper.generated.customerselfservice, 44 | applicationType microservice 45 | serverPort 8082 46 | } 47 | entities CustomerAddressChange, UserAccount 48 | } 49 | 50 | /* Bounded Context Printing */ 51 | 52 | entity PrintingJob { 53 | printingId Integer 54 | } 55 | 56 | 57 | entity Document { 58 | source Blob 59 | template String 60 | } 61 | 62 | 63 | entity Template { 64 | templateId Integer 65 | templateName String 66 | } 67 | 68 | microservice PrintingJob, Document, Template with Printing 69 | 70 | application { 71 | config { 72 | baseName Printing, 73 | packageName org.contextmapper.generated.printing, 74 | applicationType microservice 75 | serverPort 8083 76 | } 77 | entities PrintingJob, Document, Template 78 | } 79 | 80 | /* Bounded Context PolicyManagement */ 81 | 82 | entity Offer { 83 | offerId Integer 84 | price BigDecimal 85 | } 86 | 87 | 88 | entity Product { 89 | productName String 90 | } 91 | 92 | 93 | entity Contract { 94 | } 95 | 96 | 97 | entity Policy { 98 | policyNr Integer 99 | price BigDecimal 100 | } 101 | 102 | microservice Offer, Product, Contract, Policy with PolicyManagement 103 | 104 | application { 105 | config { 106 | baseName PolicyManagement, 107 | packageName org.contextmapper.generated.policymanagement, 108 | applicationType microservice 109 | serverPort 8084 110 | } 111 | entities Offer, Product, Contract, Policy 112 | } 113 | 114 | /* Bounded Context RiskManagement */ 115 | 116 | entity CustomerRiskFactor { 117 | totalRiskFactor Integer 118 | } 119 | 120 | microservice CustomerRiskFactor with RiskManagement 121 | 122 | application { 123 | config { 124 | baseName RiskManagement, 125 | packageName org.contextmapper.generated.riskmanagement, 126 | applicationType microservice 127 | serverPort 8085 128 | } 129 | entities CustomerRiskFactor 130 | } 131 | 132 | /* Bounded Context DebtCollection */ 133 | 134 | entity Debt { 135 | debtNr Integer 136 | creationDate LocalDate 137 | paymentDate LocalDate 138 | paymentDeadline LocalDate 139 | price BigDecimal 140 | status Blob 141 | } 142 | 143 | 144 | entity Dunning { 145 | dunningNr Integer 146 | dunningDate LocalDate 147 | paymentDeadline LocalDate 148 | } 149 | 150 | microservice Debt, Dunning with DebtCollection 151 | 152 | application { 153 | config { 154 | baseName DebtCollection, 155 | packageName org.contextmapper.generated.debtcollection, 156 | applicationType microservice 157 | serverPort 8086 158 | } 159 | entities Debt, Dunning 160 | } 161 | 162 | /* relationships */ 163 | relationship OneToMany { 164 | Customer{addresses} to Address 165 | Offer{products} to Product 166 | Contract{products} to Product 167 | Debt{dunnigs} to Dunning 168 | } 169 | relationship OneToOne { 170 | CustomerAddressChange{issuer} to UserAccount 171 | PrintingJob{document} to Document 172 | PrintingJob{template} to Template 173 | Policy{contract} to Contract 174 | } 175 | 176 | /* microservice gateyway app */ 177 | application { 178 | config { 179 | baseName gateway, 180 | packageName org.contextmapper.generated.gateway, 181 | applicationType gateway 182 | serverPort 8080 183 | } 184 | entities Customer, Address, CustomerAddressChange, UserAccount, PrintingJob, Document, Template, Offer, Product, Contract, Policy, CustomerRiskFactor, Debt, Dunning 185 | } 186 | 187 | /* additional options */ 188 | dto * with mapstruct 189 | service * with serviceImpl 190 | 191 | -------------------------------------------------------------------------------- /src/main/cml/microservice-generation/JDL-example/generated-insurance-microservices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-mapper-examples/0854134a15fa70384c4e192cd5e32485ca0d22b5/src/main/cml/microservice-generation/JDL-example/generated-insurance-microservices.png -------------------------------------------------------------------------------- /src/main/cml/ooad-sample-claims/README.md: -------------------------------------------------------------------------------- 1 | # OOAD Transformations Applied 2 | On our [Rapid Object-oriented Analysis and Design](https://contextmapper.org/docs/rapid-ooad/) we explain how you can prototype an application with our OOAD 3 | transformations rapidly. This folder contains another example on which we applied this concept. 4 | 5 | ## Use Case: Get Paid for Car Accident 6 | The [example model](./claims-use-case.cml) contains a Use Case of Alistair Cockburn's book on [Writing Effective Use Cases](https://www.amazon.com/Writing-Effective-Cases-Alistair-Cockburn/dp/0201702258). 7 | 8 | ## Application Generation 9 | From the given Use Case we automatically derived the subdomain and the Bounded Context. Then, we generated the [JDL file](./claims-use-case-entities.jdl) from which we are able to generate 10 | a microservice application. 11 | -------------------------------------------------------------------------------- /src/main/cml/ooad-sample-claims/claims-use-case-entities.jdl: -------------------------------------------------------------------------------- 1 | 2 | /* Bounded Context ClaimsManagement */ 3 | 4 | entity Claim { 5 | date LocalDate 6 | amountClaimed Double 7 | description String 8 | claimId Blob 9 | } 10 | 11 | 12 | entity Policy { 13 | startDate LocalDate 14 | endDate LocalDate 15 | policyId Blob 16 | } 17 | 18 | 19 | entity Contract { 20 | contractId Blob 21 | } 22 | 23 | 24 | entity Agent { 25 | personalID Long 26 | firstName String 27 | lastName String 28 | agentId Blob 29 | } 30 | 31 | 32 | entity Claimant { 33 | firstName String 34 | lastName String 35 | claimantId Blob 36 | } 37 | 38 | microservice Claim, Policy, Contract, Agent, Claimant with ClaimsManagement 39 | 40 | application { 41 | config { 42 | baseName ClaimsManagement, 43 | packageName org.contextmapper.generated.claimsmanagement, 44 | applicationType microservice 45 | serverPort 8081 46 | } 47 | entities Claim, Policy, Contract, Agent, Claimant 48 | } 49 | 50 | /* relationships */ 51 | relationship OneToMany { 52 | Policy{claims} to Claim 53 | Contract{policies} to Policy 54 | Claimant{claims} to Claim 55 | } 56 | relationship OneToOne { 57 | Claim{agent} to Agent 58 | } 59 | 60 | /* microservice gateway app */ 61 | application { 62 | config { 63 | baseName gateway, 64 | packageName org.contextmapper.generated.gateway, 65 | applicationType gateway 66 | serverPort 8080 67 | } 68 | entities Claim, Policy, Contract, Agent, Claimant 69 | } 70 | 71 | /* additional options */ 72 | dto * with mapstruct 73 | service * with serviceImpl 74 | 75 | -------------------------------------------------------------------------------- /src/main/cml/ooad-sample-claims/claims-use-case-entities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextMapper/context-mapper-examples/0854134a15fa70384c4e192cd5e32485ca0d22b5/src/main/cml/ooad-sample-claims/claims-use-case-entities.png -------------------------------------------------------------------------------- /src/main/cml/ooad-sample-claims/claims-use-case.cml: -------------------------------------------------------------------------------- 1 | /** 2 | * Automatically derived with the OOAD step 3 transformation: 3 | * (adjusted data types in services manually) 4 | * 5 | * After having derived this BC, we generated the claims-use-case-entities.jdl file using our generic generator: 6 | * https://contextmapper.org/docs/generic-freemarker-generator/ 7 | */ 8 | BoundedContext ClaimsManagement implements ClaimsManagement { 9 | domainVisionStatement "This Bounded Context realizes the following subdomains: ClaimsManagement" 10 | type FEATURE 11 | /* This Aggregate contains the entities and services of the 'ClaimsManagement' subdomain. 12 | * TODO: You can now refactor the Aggregate, for example by using the 'Split Aggregate by Entities' architectural refactoring. 13 | * TODO: Add attributes and operations to the entities. 14 | * TODO: Add operations to the services. 15 | * Find examples and further instructions on our website: https://contextmapper.org/docs/rapid-ooad/ */ 16 | Aggregate ClaimsManagementAggregate { 17 | Service AccidentService { 18 | void submitClaim (@Claim claim); 19 | PolicyExistanceVerification verifyExistanceOfPolicy (@Claim claim); 20 | void assignAgent (@Claim claim, @Agent agent); 21 | PolicyVerification verifyPolicy (@Claim claim); 22 | void payClaimant (@Claim claim); 23 | void closeClaim (@Claim claim); 24 | } 25 | Entity Claim { 26 | Date date 27 | Double amountClaimed 28 | String ^description 29 | ClaimID claimId 30 | - Agent agent 31 | } 32 | Entity Policy { 33 | Date startDate 34 | Date endDate 35 | PolicyID policyId 36 | - List claims 37 | } 38 | Entity Contract { 39 | ContractID contractId 40 | - List policies 41 | } 42 | Entity Agent { 43 | Long personalID 44 | String firstName 45 | String lastName 46 | AgentID agentId 47 | } 48 | Entity Claimant { 49 | String firstName 50 | String lastName 51 | ClaimantID claimantId 52 | - List claims 53 | } 54 | } 55 | } 56 | 57 | /** 58 | * Automatically derived with the OOAD step 2 transformation: 59 | * (manually concretized some datatypes) 60 | */ 61 | Domain Insurance_Application { 62 | Subdomain ClaimsManagement { 63 | domainVisionStatement "Aims at promoting the following benefit for a Claimant: A claimant submits a claim and and gets paid from the insurance company." 64 | Entity Claim { 65 | Date date 66 | Double amountClaimed 67 | String ^description 68 | - Agent agent 69 | } 70 | Entity Policy { 71 | Date startDate 72 | Date endDate 73 | - List claims 74 | } 75 | Entity Contract { 76 | - List policies 77 | } 78 | Entity Agent { 79 | Long personalID 80 | String firstName 81 | String lastName 82 | } 83 | Entity Claimant { 84 | String firstName 85 | String lastName 86 | - List claims 87 | } 88 | Service AccidentService { 89 | submitClaim; 90 | verifyExistanceOfPolicy; 91 | assignAgent; 92 | verifyPolicy; 93 | payClaimant; 94 | closeClaim; 95 | } 96 | } 97 | 98 | } 99 | 100 | /** 101 | * The following Use Case "Get paid for car accident" has been taken out of Alistair Cockburn's book on "Writing Effective Use Cases". 102 | * Step 1: This is the part of this CML file which has been modeled manually: (all the parts above are generated by our OOAD transformations) 103 | */ 104 | UseCase Get_paid_for_car_accident { // title 105 | actor "Claimant" // primary actor 106 | interactions 107 | "submit" a "Claim" with its "date", "amountClaimed", "description" for a "Policy", // step 1: claimant submits claim 108 | "verifyExistanceOf" "Policy" with its "startDate", "endDate" for a "Contract", // step 2: insurance company verifies that valid policy exists 109 | "assign" an "Agent" with its "personalID", "firstName", "lastName" for "Claim", // step 3: agent is assigned to claim 110 | "verify" "Policy" for a "Contract", // step 4: agent verifies all details are within policy guidelines 111 | "pay" "Claimant" with its "firstName", "lastName", // step 5 (1): claimant gets paid 112 | "close" "Claim" for "Claimant" // step 5 (2): file/claim gets closed 113 | benefit "A claimant submits a claim and and gets paid from the insurance company." // story (brief summary) 114 | scope "Insurance company" // scope 115 | level "Summary" // level 116 | } 117 | -------------------------------------------------------------------------------- /src/main/cml/same-day-delivery-shop/stakeholders-and-values.cml: -------------------------------------------------------------------------------- 1 | 2 | 3 | BoundedContext SameDayDelivery 4 | 5 | 6 | Stakeholders of SameDayDelivery { 7 | StakeholderGroup Online_Shopping_Company { 8 | Stakeholder Development_Team { 9 | influence MEDIUM 10 | interest HIGH 11 | } 12 | Stakeholder Product_Management { 13 | influence HIGH 14 | interest HIGH 15 | } 16 | Stakeholder Customer_Relationship_Manager { 17 | influence HIGH 18 | interest MEDIUM 19 | } 20 | } 21 | StakeholderGroup Product_Suppliers { 22 | Stakeholder Managers 23 | Stakeholder Logistics_Warehouse_Staff_of_Suppliers 24 | Stakeholder Delivery_Staff_of_Suppliers 25 | } 26 | StakeholderGroup Delivery_Partners { 27 | Stakeholder Route_Planners 28 | Stakeholder Drivers 29 | } 30 | StakeholderGroup Competing_Companies 31 | 32 | StakeholderGroup Logistics_Team { 33 | Stakeholder Logistics_Manager 34 | Stakeholder Warehouse_Staff 35 | } 36 | Stakeholder Government 37 | 38 | StakeholderGroup Customers_and_Shoppers { 39 | Stakeholder Shoppers_in_Emergency_Situations 40 | Stakeholder Others 41 | } 42 | } 43 | ValueRegister SD_Values for SameDayDelivery { 44 | ValueCluster Autonomy { 45 | core AUTONOMY 46 | demonstrator "customer values potentially increased freedom" 47 | demonstrator "delivery staff's freedom might suffer because of work-life-balance" 48 | Value Freedom { 49 | Stakeholder Customers_and_Shoppers { 50 | priority HIGH 51 | impact MEDIUM 52 | consequences 53 | good "increased freedom" 54 | } 55 | } 56 | Value Quality_of_Life { 57 | Stakeholder Customers_and_Shoppers { 58 | consequences 59 | good "less stress in emergendy situations" 60 | } 61 | } 62 | Value Sustainability { 63 | Stakeholder Customers_and_Shoppers { 64 | priority HIGH 65 | impact LOW 66 | consequences 67 | bad "fostering unsustainable behavior (always ordering last minute)" 68 | action "Limit Availability of Feature" ACT 69 | } 70 | } 71 | Value Ability_to_be_patient { 72 | Stakeholder Customers_and_Shoppers { 73 | priority MEDIUM 74 | impact HIGH 75 | consequences 76 | bad "patience of customer will further increase" 77 | action "Only allow feature for emergency (don't make it the default)" ACT 78 | } 79 | } 80 | } 81 | Value WorkLifeBalance { 82 | isCore 83 | demonstrator "Drivers value a healthy work-life-balance" 84 | Stakeholder Drivers { 85 | priority HIGH 86 | impact HIGH 87 | consequences 88 | bad "SDD will harm work-life-balance of drivers" 89 | action "hire more drivers, adjust availability to workload" ACT 90 | } 91 | } 92 | Value Revenue { 93 | demonstrator "Online shopping company needs revenue" 94 | Stakeholder Online_Shopping_Company { 95 | priority HIGH 96 | impact MEDIUM 97 | consequences 98 | good "increased number of customers" 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/cml/service-coordination-example/InsuranceClaimCoordination.cml: -------------------------------------------------------------------------------- 1 | /** 2 | * Example coordination of services between three Bounded Contexts. 3 | * 4 | */ 5 | ContextMap { 6 | contains ClaimsManagement 7 | contains InsuranceManagement 8 | contains PaymentManagement 9 | 10 | ClaimsManagement <-> InsuranceManagement 11 | 12 | ClaimsManagement <-> PaymentManagement 13 | } 14 | 15 | BoundedContext ClaimsManagement { 16 | Application { 17 | 18 | Coordination SubmitValidClaimCoordination { 19 | ClaimsManagement::ClaimsApplicationService::submitClaim; 20 | InsuranceManagement::InsuranceApplicationService::checkInsurance; 21 | ClaimsManagement::ClaimsApplicationService::acceptClaim; 22 | PaymentManagement::PaymentApplicationService::performPayment; 23 | } 24 | 25 | Service ClaimsApplicationService { 26 | void submitClaim(@Claim claim); 27 | void acceptClaim(@Claim claim); 28 | } 29 | } 30 | 31 | Aggregate Claims { 32 | Entity Claim 33 | } 34 | } 35 | 36 | BoundedContext InsuranceManagement { 37 | Application { 38 | Service InsuranceApplicationService { 39 | void checkInsurance(@Claim claim); 40 | } 41 | } 42 | } 43 | 44 | BoundedContext PaymentManagement { 45 | Application { 46 | Service PaymentApplicationService { 47 | void performPayment(@Claim claim); 48 | } 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/main/cml/workflow-samples/ClaimsManagement_with_Commands.cml: -------------------------------------------------------------------------------- 1 | BoundedContext ClaimsManagement { 2 | Application { 3 | Command SubmitClaim 4 | Command CheckClaimDocumentation 5 | Command CheckInsurance 6 | Command AcceptClaim 7 | Command RejectClaim 8 | Command SchedulePayment 9 | Command NofifyCustomer 10 | 11 | Flow ClaimsFlow { 12 | command SubmitClaim emits event ClaimSubmitted 13 | event ClaimSubmitted triggers command CheckClaimDocumentation 14 | 15 | command CheckClaimDocumentation emits event ClaimRegistered 16 | event ClaimRegistered triggers command CheckInsurance 17 | command CheckInsurance emits event AssessmentPerformed 18 | event AssessmentPerformed triggers command AcceptClaim X RejectClaim // X: alternative command invokation (exclusive; only one); 19 | // +: concurrent command invokation (all commands called); 20 | // O: alternative command invokation (inclusive; one or multiple) 21 | 22 | command AcceptClaim delegates to Claims [OPEN -> ACCEPTED] emits event ClaimAccepted // optional: define state transition that is done on command invokation 23 | command RejectClaim delegates to Claims [OPEN -> REJECTED] emits event ClaimRejected 24 | 25 | event ClaimAccepted triggers command SchedulePayment 26 | command SchedulePayment emits event PaymentPerformed 27 | 28 | event PaymentPerformed triggers command NofifyCustomer 29 | event ClaimRejected triggers command NofifyCustomer 30 | 31 | command NofifyCustomer delegates to Claims [ACCEPTED, REJECTED -> CUSTOMER_NOTIFIED] emits event CustomerNotified 32 | } 33 | } 34 | 35 | Aggregate Claims { 36 | Entity Claim { 37 | aggregateRoot 38 | long claimId 39 | CustomerId customer 40 | String ^description 41 | Blob requestDocument 42 | boolean isComplete 43 | boolean isAssessed 44 | - ClaimState claimState 45 | } 46 | enum ClaimState { 47 | aggregateLifecycle // enum marked as "state defining" for this aggregate 48 | OPEN, REJECTED, ACCEPTED, CUSTOMER_NOTIFIED 49 | } 50 | 51 | DomainEvent ClaimSubmitted 52 | DomainEvent ClaimRegistered 53 | DomainEvent AssessmentPerformed 54 | DomainEvent ClaimAccepted 55 | DomainEvent ClaimRejected 56 | DomainEvent PaymentPerformed 57 | DomainEvent CustomerNotified 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/main/cml/workflow-samples/ClaimsManagement_with_ServiceOperations.cml: -------------------------------------------------------------------------------- 1 | BoundedContext ClaimsManagement { 2 | Application { 3 | Service ClaimsApplicationService { 4 | void submitClaim(@Claim claim); 5 | void checkClaimDocumentation(@Claim claim); 6 | void checkInsurance(@Claim claim); 7 | void acceptClaim(@Claim claim); 8 | void rejectClaim(@Claim claim); 9 | void schedulePayment(@Claim claim); 10 | void nofifyCustomer(@Claim claim); 11 | } 12 | 13 | Flow ClaimsFlow { 14 | operation submitClaim emits event ClaimSubmitted 15 | event ClaimSubmitted triggers operation checkClaimDocumentation 16 | 17 | operation checkClaimDocumentation emits event ClaimRegistered 18 | event ClaimRegistered triggers operation checkInsurance 19 | operation checkInsurance emits event AssessmentPerformed 20 | event AssessmentPerformed triggers operation acceptClaim X rejectClaim // X: alternative command invokation (exclusive; only one); 21 | // +: concurrent command invokation (all commands called); 22 | // O: alternative command invokation (inclusive; one or multiple) 23 | 24 | operation acceptClaim delegates to Claims [OPEN -> ACCEPTED] emits event ClaimAccepted // optional: define state transition that is done on command invokation 25 | operation rejectClaim delegates to Claims [OPEN -> REJECTED] emits event ClaimRejected 26 | 27 | event ClaimAccepted triggers operation schedulePayment 28 | operation schedulePayment emits event PaymentPerformed 29 | 30 | event PaymentPerformed triggers operation nofifyCustomer 31 | event ClaimRejected triggers operation nofifyCustomer 32 | 33 | operation nofifyCustomer delegates to Claims[ACCEPTED, REJECTED -> CUSTOMER_NOTIFIED] emits event CustomerNotified 34 | } 35 | } 36 | 37 | Aggregate Claims { 38 | Entity Claim { 39 | aggregateRoot 40 | long claimId 41 | CustomerId customer 42 | String ^description 43 | Blob requestDocument 44 | boolean isComplete 45 | boolean isAssessed 46 | - ClaimState claimState 47 | } 48 | enum ClaimState { 49 | aggregateLifecycle 50 | OPEN, REJECTED, ACCEPTED, CUSTOMER_NOTIFIED 51 | } 52 | 53 | DomainEvent ClaimSubmitted 54 | DomainEvent ClaimRegistered 55 | DomainEvent AssessmentPerformed 56 | DomainEvent ClaimAccepted 57 | DomainEvent ClaimRejected 58 | DomainEvent PaymentPerformed 59 | DomainEvent CustomerNotified 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/main/cml/workflow-samples/InsuranceQuoteRequest.cml: -------------------------------------------------------------------------------- 1 | /** 2 | * A RequestStatus is a value object that is used to represent 3 | * the current status of an insurance quote request. 4 | * 5 | * The following diagram shows the possible state transitions: 6 | * 7 | *
 8 |  *
 9 |  *                                               │
10 |  *                                               ▼
11 |  *                                        ┌────────────┐
12 |  *                                        │  REQUEST_  │
13 |  *                                        │ SUBMITTED  │
14 |  *                                        └────────────┘
15 |  *                                               │
16 |  *                             ┌─────────────────┴────────────────┐
17 |  *                             │                                  │
18 |  *                             ▼                                  ▼
19 |  *                      ┌────────────┐                     ╔════════════╗
20 |  *                      │   QUOTE_   │                     ║  REQUEST_  ║
21 |  *          ┌───────────│  RECEIVED  │─────────────┐       ║  REJECTED  ║
22 |  *          │           └────────────┘             │       ╚════════════╝
23 |  *          │                  │                   │
24 |  *          │                  │                   │
25 |  *          ▼                  ▼                   ▼
26 |  *   ╔════════════╗     ┌────────────┐      ╔════════════╗
27 |  *   ║   QUOTE_   ║     │   QUOTE_   │      ║   QUOTE_   ║
28 |  *   ║  REJECTED  ║     │  ACCEPTED  │─────▶║  EXPIRED   ║
29 |  *   ╚════════════╝     └────────────┘      ╚════════════╝
30 |  *                             │
31 |  *                             │
32 |  *                             ▼
33 |  *                      ╔════════════╗
34 |  *                      ║  POLICY_   ║
35 |  *                      ║  CREATED   ║
36 |  *                      ╚════════════╝
37 |  *
38 |  * 
39 | */ 40 | BoundedContext InsuranceQuotes { 41 | 42 | Aggregate QuoteRequest { 43 | Entity Request { 44 | aggregateRoot 45 | } 46 | 47 | DomainEvent RequestSubmitted 48 | DomainEvent QuoteReceived 49 | DomainEvent RequestRejected 50 | DomainEvent QuoteRejected 51 | DomainEvent QuoteAccepted 52 | DomainEvent QuoteExpired 53 | DomainEvent PolicyCreated 54 | 55 | Service QuoteRequestService { 56 | void checkRequest(@Request request); 57 | void receiveAndCheckQuote(@Request request); 58 | void reject(@Request request); 59 | void accept(@Request request); 60 | } 61 | 62 | enum RequestState { 63 | aggregateLifecycle 64 | SUBMITTED, RECEIVED, REJECTED, ACCEPTED, EXPIRED, POLICY_CREATED 65 | } 66 | } 67 | 68 | Application { 69 | Command SubmitRequest // command triggered by user 70 | 71 | Flow QuoteFlow { 72 | command SubmitRequest delegates to QuoteRequest[-> SUBMITTED] emits event RequestSubmitted 73 | event RequestSubmitted triggers operation checkRequest 74 | operation checkRequest delegates to QuoteRequest[SUBMITTED -> RECEIVED X REJECTED] emits event QuoteReceived X RequestRejected 75 | event QuoteReceived triggers operation receiveAndCheckQuote 76 | operation receiveAndCheckQuote delegates to QuoteRequest[RECEIVED -> REJECTED X ACCEPTED X EXPIRED] emits event QuoteRejected X QuoteAccepted X QuoteExpired 77 | event QuoteAccepted triggers operation accept 78 | operation accept delegates to QuoteRequest[ACCEPTED -> POLICY_CREATED X EXPIRED] emits event PolicyCreated X QuoteExpired 79 | } 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /src/main/cml/workflow-samples/InsuranceQuoteRequest_StateMachineWithoutEventsAndCommands.cml: -------------------------------------------------------------------------------- 1 | /** 2 | * A RequestStatus is a value object that is used to represent 3 | * the current status of an insurance quote request. 4 | * 5 | * The following diagram shows the possible state transitions: 6 | * 7 | *
 8 |  *
 9 |  *                                               │
10 |  *                                               ▼
11 |  *                                        ┌────────────┐
12 |  *                                        │  REQUEST_  │
13 |  *                                        │ SUBMITTED  │
14 |  *                                        └────────────┘
15 |  *                                               │
16 |  *                             ┌─────────────────┴────────────────┐
17 |  *                             │                                  │
18 |  *                             ▼                                  ▼
19 |  *                      ┌────────────┐                     ╔════════════╗
20 |  *                      │   QUOTE_   │                     ║  REQUEST_  ║
21 |  *          ┌───────────│  RECEIVED  │─────────────┐       ║  REJECTED  ║
22 |  *          │           └────────────┘             │       ╚════════════╝
23 |  *          │                  │                   │
24 |  *          │                  │                   │
25 |  *          ▼                  ▼                   ▼
26 |  *   ╔════════════╗     ┌────────────┐      ╔════════════╗
27 |  *   ║   QUOTE_   ║     │   QUOTE_   │      ║   QUOTE_   ║
28 |  *   ║  REJECTED  ║     │  ACCEPTED  │─────▶║  EXPIRED   ║
29 |  *   ╚════════════╝     └────────────┘      ╚════════════╝
30 |  *                             │
31 |  *                             │
32 |  *                             ▼
33 |  *                      ╔════════════╗
34 |  *                      ║  POLICY_   ║
35 |  *                      ║  CREATED   ║
36 |  *                      ╚════════════╝
37 |  *
38 |  * 
39 | */ 40 | BoundedContext InsuranceQuotes { 41 | 42 | Aggregate QuoteRequest { 43 | Entity QuoteRequest { 44 | aggregateRoot 45 | } 46 | 47 | Service QuoteRequestService { 48 | // just grammar examples: 49 | // @Object readOperation() : read-only; 50 | // void writeOperation(@Object param) : write; 51 | // void writeOperation(@Object param) : write [STATE1 -> STATE2]; 52 | // void writeOperation(@Object param) : write [STATE1 -> STATE2 X STATE3]; 53 | 54 | void submitRequest(@QuoteRequest request) : write [-> REQUEST_SUBMITTED]; 55 | void rejectRequest(@QuoteRequest request): write [REQUEST_SUBMITTED -> REQUEST_REJECTED]; 56 | void receiveQuote(@QuoteRequest request) : write [REQUEST_SUBMITTED -> QUOTE_RECEIVED]; 57 | void checkQuote(@QuoteRequest request) : write [QUOTE_RECEIVED -> QUOTE_REJECTED X QUOTE_ACCEPTED X QUOTE_EXPIRED]; 58 | void createPolicy(@QuoteRequest request) : write [QUOTE_ACCEPTED -> POLICY_CREATED X QUOTE_EXPIRED]; 59 | 60 | // void getRequest(RequestId requestId) : read-only; 61 | 62 | // + : parallel gateway (AND) 63 | // X : exclusive gateway (XOR) 64 | // O : inclusive gateway (OR) 65 | } 66 | 67 | enum RequestState { 68 | aggregateLifecycle 69 | REQUEST_SUBMITTED, QUOTE_RECEIVED, REQUEST_REJECTED, QUOTE_ACCEPTED, QUOTE_REJECTED, QUOTE_EXPIRED, POLICY_CREATED 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/cml/workflow-samples/InsuranceQuoteRequest_StateMachineWithoutEventsAndCommands_Entity.cml: -------------------------------------------------------------------------------- 1 | /** 2 | * A RequestStatus is a value object that is used to represent 3 | * the current status of an insurance quote request. 4 | * 5 | * The following diagram shows the possible state transitions: 6 | * 7 | *
 8 |  *
 9 |  *                                               │
10 |  *                                               ▼
11 |  *                                        ┌────────────┐
12 |  *                                        │  REQUEST_  │
13 |  *                                        │ SUBMITTED  │
14 |  *                                        └────────────┘
15 |  *                                               │
16 |  *                             ┌─────────────────┴────────────────┐
17 |  *                             │                                  │
18 |  *                             ▼                                  ▼
19 |  *                      ┌────────────┐                     ╔════════════╗
20 |  *                      │   QUOTE_   │                     ║  REQUEST_  ║
21 |  *          ┌───────────│  RECEIVED  │─────────────┐       ║  REJECTED  ║
22 |  *          │           └────────────┘             │       ╚════════════╝
23 |  *          │                  │                   │
24 |  *          │                  │                   │
25 |  *          ▼                  ▼                   ▼
26 |  *   ╔════════════╗     ┌────────────┐      ╔════════════╗
27 |  *   ║   QUOTE_   ║     │   QUOTE_   │      ║   QUOTE_   ║
28 |  *   ║  REJECTED  ║     │  ACCEPTED  │─────▶║  EXPIRED   ║
29 |  *   ╚════════════╝     └────────────┘      ╚════════════╝
30 |  *                             │
31 |  *                             │
32 |  *                             ▼
33 |  *                      ╔════════════╗
34 |  *                      ║  POLICY_   ║
35 |  *                      ║  CREATED   ║
36 |  *                      ╚════════════╝
37 |  *
38 |  * 
39 | */ 40 | BoundedContext InsuranceQuotes { 41 | 42 | Aggregate QuoteRequest { 43 | 44 | // also possible on Entity operations: 45 | Entity QuoteRequest { 46 | aggregateRoot 47 | 48 | // just grammar examples: 49 | // def @Object readOperation() : read-only; 50 | // def void writeOperation(@Object param) : write; 51 | // def void writeOperation(@Object param) : write [STATE1 -> STATE2]; 52 | // def void writeOperation(@Object param) : write [STATE1 -> STATE2 X STATE3]; 53 | 54 | def void submit() : write [-> REQUEST_SUBMITTED]; 55 | def void reject(): write [REQUEST_SUBMITTED -> REQUEST_REJECTED]; 56 | def void receiveQuote() : write [REQUEST_SUBMITTED -> QUOTE_RECEIVED]; 57 | def void checkQuote() : write [QUOTE_RECEIVED -> QUOTE_REJECTED X QUOTE_ACCEPTED X QUOTE_EXPIRED]; 58 | def void createPolicy() : write [QUOTE_ACCEPTED -> POLICY_CREATED X QUOTE_EXPIRED]; 59 | } 60 | 61 | enum RequestState { 62 | aggregateLifecycle 63 | REQUEST_SUBMITTED, QUOTE_RECEIVED, REQUEST_REJECTED, QUOTE_ACCEPTED, QUOTE_REJECTED, QUOTE_EXPIRED, POLICY_CREATED 64 | } 65 | } 66 | 67 | } 68 | --------------------------------------------------------------------------------