diff --git a/_docs/generators/generators.md b/_docs/generators/generators.md index a770951..689675e 100644 --- a/_docs/generators/generators.md +++ b/_docs/generators/generators.md @@ -5,7 +5,8 @@ permalink: /docs/generators/ The Context Mapper generators provide transformations to derive graphical Context Maps, [PlantUML diagrams](http://plantuml.com/), [Microservice Domain-Specific Langauge (MDSL)](https://socadk.github.io/MDSL/) (micro-)service contracts, and -[Service Cutter](https://servicecutter.github.io/) input files from your CML context map. We also provide a [generic, template-based generator](/docs/generic-freemarker-generator/) based on Freemarker which allows to generate arbitrary textual files. +[Service Cutter](https://servicecutter.github.io/) input files from your CML context map. We also provide a [generic, template-based generator](/docs/generic-freemarker-generator/) +based on Freemarker which allows to generate arbitrary textual files. **Generators:** * [Graphical context maps](#graphical-context-maps) diff --git a/_docs/generators/service-cutter.md b/_docs/generators/service-cutter.md index 8d46347..443d314 100644 --- a/_docs/generators/service-cutter.md +++ b/_docs/generators/service-cutter.md @@ -63,6 +63,3 @@ Have fun with cutting your services :) *Note:* Service Cutter has not been updated in a while, and only intended to demonstrate the possibilities of criteria-based graph clustering in the context of service decomposition (and establish a method and a first catalog of criteria). So do not expect mature, production-ready cuts to be suggested, but view them as a discussion and design workshop input. Further research is required to harden the approach; such research is ongoing (evidence: [40+ citations of the Service Cutter paper presented at ESOCC 2016](https://www.researchgate.net/publication/307873263_Service_Cutter_A_Systematic_Approach_to_Service_Decomposition)). ![Service Cutter Insurance Example](/img/service-cutter-insurance-example.png) - - - diff --git a/_docs/tutorials/event-sourcing-and-cqrs-modeling.md b/_docs/tutorials/event-sourcing-and-cqrs-modeling.md index 03c0365..1aabff8 100644 --- a/_docs/tutorials/event-sourcing-and-cqrs-modeling.md +++ b/_docs/tutorials/event-sourcing-and-cqrs-modeling.md @@ -10,15 +10,14 @@ CQRS separates query processing from the create, update, delete business logic s If you are not fully familiar with the concepts of event sourcing and CQRS yet, you may find the following resources helpful: * [Event sourcing](https://martinfowler.com/eaaDev/EventSourcing.html) by Martin Fowler - * [CQRS and Event Sourcing (Video)](https://www.youtube.com/watch?v=JHGkaShoyNs) by Greg Young - * [Event sourcing pattern](https://microservices.io/patterns/data/event-sourcing.html) by Chris Richardson * [Event sourcing workshop slides](https://speakerdeck.com/mploed/event-sourcing-workshop-at-software-architecture-summit-2016) by Michael Plöd + * [Event sourcing pattern](https://microservices.io/patterns/data/event-sourcing.html) by Chris Richardson + * [CQRS and Event Sourcing (Video)](https://www.youtube.com/watch?v=JHGkaShoyNs) by Greg Young * [Command query separation](https://martinfowler.com/bliki/CommandQuerySeparation.html) and [CQRS](https://martinfowler.com/bliki/CQRS.html) by Martin Fowler * [Developing Transactional Microservices Using Aggregates, Event Sourcing and CQRS](https://www.infoq.com/articles/microservices-aggregates-events-cqrs-part-1-richardson/) by Chris Richardson * [Designing Event Sourced Microservices](https://www.infoq.com/news/2017/11/event-sourcing-microservices/) by Jan Stenberg ## Tutorial - ### Context and Objectives This tutorial highlights the [Context Mapper DSL (CML)](/docs/language-reference/) concepts that support a) modeling event-sourced systems and b) CQRS. @@ -32,6 +31,8 @@ suggests that the scope of domain events should always be based on Aggregates. T The following example illustrates how you can model domain events within your Aggregate: + + ```text abstract DomainEvent AbstractDomainEvent { Date timestamp @@ -43,7 +44,13 @@ DomainEvent CustomerVerifiedEvent extends AbstractDomainEvent { DomainEvent AddressUpdatedEvent extends AbstractDomainEvent { - CustomerId customer - - AddressId address + - AddressDto address +} + +ValueObject AddressDto { + String streetAddress + String city + String postalCode } ``` @@ -51,12 +58,13 @@ You can also reference your events in services, repositories, or any other tacti ```text Service AddressService { - @AddressUpdatedEvent updateAddress(@AddressId address); + @AddressUpdatedEvent updateAddress(@AddressDto address); } ``` ### CQRS Example -Applying CQRS to a Bounded Context definition in Context Mapper can be expressed with the standard language constructs of Context Mapper and Sculptor: you can simply apply this architectural pattern by +Applying CQRS to a Bounded Context definition in Context Mapper can be expressed with the standard language constructs of Context Mapper and Sculptor: you can simply apply +this architectural pattern by 1. Separating the queries from the command methods and defining separate services 2. Defining separate command and query models @@ -65,12 +73,18 @@ Applying CQRS to a Bounded Context definition in Context Mapper can be expressed Here is an example of a conventional service interface that exposes both create, read, update, delete, and search methods/operations: ```text +ValueObject CustomerDTO { + String customerId + CustomerProfileDto customerProfile + List links +} + Service CustomerService { - @CustomerId createCustomer(@Customer customer); - void updateCustomer(@Customer customer); + @CustomerId createCustomer(@CustomerDTO customer); + void updateCustomer(@CustomerDTO customer); boolean deleteCustomer(@CustomerId customer); - @Customer findCustomerById(@CustomerId customerId); - List<@Customer> findCustomersByName(String name); + @CustomerDTO findCustomerById(@CustomerId customerId); + List<@CustomerDTO> findCustomersByName(String name); } ``` @@ -78,14 +92,14 @@ You can CQRS-ify the above interface by splitting it into two service interfaces ```text Service CustomerCommandService { - @CustomerId createCustomer(@Customer customer); - void updateCustomer(@Customer customer); + @CustomerId createCustomer(@CustomerDTO customer); + void updateCustomer(@CustomerDTO customer); boolean deleteCustomer(@CustomerId customer); } Service CustomerQueryService { - @Customer findCustomerById(@CustomerId customerId); - List<@Customer> findCustomersByName(String name); + @CustomerDTO findCustomerById(@CustomerId customerId); + List<@CustomerDTO> findCustomersByName(String name); } ``` @@ -93,16 +107,14 @@ Additionally, Sculptor introduces so-called *command events* to support CQRS exp In comparison to a domain event which describes something that has happened, a command event is something that the system is asked to perform. The following CML/Sculptor snippet illustrates an example how to model command events: ```text -CommmandEvent RecordShipmentArrival { - - ShipmentId shipment - Date arrivalDate -} +CommandEvent RecordAddressChange { + -AddressDto newAddress + Date changeDate +} ``` #### Step 2: Separating Read and Command Models -In a second step you may want to define completely different models for read and command access. At present, the Context Mapper DSL does not -have any specific language construct for read models; we suggest that you use the Michael's Aggregate rule from above to specify read models. -The following example illustrates how you could model your Aggregate (command model) and your read model: +In a second step you may want to define completely different models for read and command access. At present, the Context Mapper DSL does not have any specific language construct for read models; we suggest that you use the Michael's Aggregate rule from above to specify read models. The following example illustrates how you could model your Aggregate (command model) and your read model: ```text Aggregate CustomerAggregate { @@ -110,20 +122,11 @@ Aggregate CustomerAggregate { UUID uniqueCustomerId } - Entity Customer { - aggregateRoot - - CustomerId customerId - String firstName - String lastName - List
addresses - } - Entity Address // not designed in detail Service CustomerCommandService { - @CustomerId createCustomer(@Customer customer); - void updateCustomer(@Customer customer); + @CustomerId createCustomer(@CustomerDTO customer); + void updateCustomer(@CustomerDTO customer); boolean deleteCustomer(@CustomerId customer); } } @@ -152,6 +155,39 @@ The [Sculptor generator](http://sculptorgenerator.org) further supports event so However, the DSL syntax itself does not need additional concepts to support it. It is based on the _DomainEvents_, _Repositories_, and _Services_ provided by the Sculptor and also CML. * *Note:* We only used the Sculptor syntax for the tactic DDD grammar of our CML language. Using the Sculptor generator in Context Mapper is currently not supported. + + + ## Other Tutorials and Links * Tutorial: [Document Event Storming Results with Context Mapper](/docs/event-storming/) * Presentation on Context Mapper: [Context Mapper: DSL and Tools for Domain-Driven Service Design - Bounded Context Modeling and Microservice Decomposition](https://contextmapper.org/media/ZIOSK-ContextMapper4JUGv10p.pdf)