Modeling in Tracepaper: Concept overview
At the moment we are designing the visual client application, and now questions arise, how do concepts fit together? Not in a technical sense, but in a conceptual. At Draftsman we use two different models to describe applications, let's sum them up so we are on the same page.
- Conceptual model: This model describes the application and its behavior in ubiquitous therms. This means you will encounter concepts like Command, Behavior, Domain Event, and View. The stuff you could map out with sticky notes during an event storming workshop. This is the kind of modeling we should enable with aid of the Tracepaper GraphQL API and subsequently our user interface.
- Transfer model: an XML representation of the above model with a slight difference, the optimization goal for the conceptual model is to be human-readable or at least human-reasonable. While the Transfer Model is optimized to be machine-readable.
Our transfer model is XML based which we dubbed "Draftsman Modelling Language" it is nearly complete in the context of the MVP due to the fact we use this language to model the Tracepaper backend itself. And to be honest, this way you find the most urgent missing features in a timely manner. Features we probably wouldn't have envisioned if we tried to design it upfront.
Now for the API, we modeled a lot but we are not there yet... we have to figure out what data views we need, the best way to figure out what you need is to explain what you want to achieve. So here we go.
As stated in the introduction we want to optimize our modeling tool to fit with event storming and customer journeys and therefore we condensed our problem space to 5 core concepts.
A command is the starting point of a... let's call it a call stack to keep it simple. A command is considered a fat trigger composed of input fields. The command will trigger behavior in the domain, in this context behavior is the application of business rules on stateful data. The behavior may result in a domain event or also called a change event, the change events are persistent and used to reconstruct the state. You can see that we composed behavior and change-event right next to each other in this image, this is not a coincidence these concepts are strongly coupled, you could have multiple behavior-flows acting on a single event-log that is our implementation of an aggregate. But that is a topic for another post, because, the event is not only persisted it is also published within our domain. And then interesting things can happen, other components could react to the event "if this then that". We have a concept called notifier designed to do exactly that, notify another system, maybe you want to trigger an email using the AWS Simple Email Service, or store a document in AWS Simple Storage Service. A notifier is simply said, an event-to-command converter it invokes APIs from AWS, third party, your on-premise application, or even its own.
Another thing that could happen after an event, is triggering a state change in a view. You may have noticed the use of event sourcing for our persistence strategy, very powerful for storing aggregates, horrible for querying. Therefore we use another pattern called Command Query Responsibility Segragation to mitigate this hurdle. We literally use a different model for our query model, there are other reasons why we use this strict segregation, but this topic deserves a dedicated post.
Knowing the core concepts it is not difficult to see how a GraphQL API correlates to our model. Thanks for reading.
Here is a sneak preview, our generator will convert your model into something like this: