Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cqrs plus #36

Merged
merged 10 commits into from
Mar 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion _docs/generators/generators.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 0 additions & 3 deletions _docs/generators/service-cutter.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)).

<a href="/img/service-cutter-insurance-example.png">![Service Cutter Insurance Example](/img/service-cutter-insurance-example.png)</a>



100 changes: 68 additions & 32 deletions _docs/tutorials/event-sourcing-and-cqrs-modeling.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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:

<!-- now using discovered AddressDto (tbd) -->

```text
abstract DomainEvent AbstractDomainEvent {
Date timestamp
Expand All @@ -43,20 +44,27 @@ DomainEvent CustomerVerifiedEvent extends AbstractDomainEvent {

DomainEvent AddressUpdatedEvent extends AbstractDomainEvent {
- CustomerId customer
- AddressId address
- AddressDto address
}

ValueObject AddressDto {
String streetAddress
String city
String postalCode
}
```

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

```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
Expand All @@ -65,65 +73,60 @@ 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<Link> 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);
}
```

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);
}
```

Additionally, Sculptor introduces so-called *command events* to support CQRS explicitly (described [here](http://sculptorgenerator.org/documentation/event-driven-tutorial#commandevent)).
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 {
ValueObject CustomerId {
UUID uniqueCustomerId
}

Entity Customer {
aggregateRoot

CustomerId customerId
String firstName
String lastName
List<Address> 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);
}
}
Expand Down Expand Up @@ -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.


<!-- You can also model the CQRS infrastructure in Sculptor:
Aggregate CQRS_CommonInfrastructure {
DomainEvent AbstractDomainEvent {
Date timestamp
}
ValueObject EventSequence {
-Set<@AbstractDomainEvent> events
}
}
Aggregate CQRS_CommandInfrastructure {
Service CommandDAO {
@EventSequence storeAndForwardEvents() publish to EventHandlerChannel;
// store in EventStore and let QueryInfrastructure know (via Handler)
}
Entity EventStore {
aggregateRoot
Repository EventStoreRepository {}
}
}
Aggregate CQRS_QueryInfrastructure {
Entity QueryDAO {
// talks to ReadStorage (BAU)
}
Entity ReadStorage {
aggregateRoot
Repository ReadStorageRepository {
subscribe to EventHandlerChannel
}
}
}
-->

## 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)
Expand Down