A great way to design Event Sourced Domain Models following a DDD approach is Alberto Brandolini's EventStorming. In an EventStorming workshop, Software Developers and Domain Experts talk about the Domain and map it out using sticky notes. They start by adding an Orange sticky note for each event that occurs in the Domain on a timeline. Further sticky notes are added to each Orange one to indicate the Command that triggers the Event, the Role that runs the Command, the ReadModels that show the details that the Role needs to make the decision to run the Command, and Policies that describe other Events that are triggered by each Event.
Each event in the timeline is represented by a model that looks like this:
- Orange – Events
- Blue – Commands
- Purple – Policies
- Pastel Pink – External Systems
- Green – ReadModels
EventStorming Domain Model
The output of an EventStorming workshop is a Domain Model represented by sticky notes centred around each Event that happens in each Entity's Thread of Continuity. This truly is Domain Driven Design and gives a Domain Model that can be implemented directly in code using Event Sourcing and CQRS.
Once all the Events are modelled on the timeline, they are then moved around into groups of related events and a Bounded Context is drawn around them. Bounded Contexts define functionality that will be implemented as a Microservice.
Coupling and Cohesion
Coupling and cohesion are two concepts that are often talked about in Software Development. The goal is to have high cohesion and low coupling to make it easier to maintain software.
Coupling and cohesion are often referred to when talking about modularity of code. Code modules are units of code that can be independently worked on and deployed. Modules are normally components, class libraries, jar files, executables etc. The concept of modularity is very relevant to Microservices where the end goal is to create services that can be worked on, tested and deployed independently.
Coupling refers to interactions between modules. If one module calls out to another module, or changes to one module require changes to another module for the system to carry on working, those modules are coupled. Coupling reduces the ability to change, test and deploy a module independently. The higher the coupling between modules the higher the cost and effort to make future changes, so we aim to keep coupling between modules low.
In Eric Evans' original book on DDD, he talks about encapsulation of functionality in Standalone Classes as a way to reduce coupling.
Cohesion refers to functional elements within the same module sharing some relationship. When cohesion is high, elements that interact often are in the same module. This reduces coupling as interaction for related functionality is contained to a single module, reducing interaction between different modules. High cohesion increases the ability to change, test and deploy a module independently, which lowers the cost and effort of maintenance.
In DDD, Eric Evans talks about cohesion in terms of Conceptual Contours as themes that emerge during discussions about the domain model. Evan's also introduced the concept of the Bounded Context to group related Events together.
Measuring Modularity at the Domain Modelling Phase
Events are where the complexity is in software so getting the high level design of them right early in the SDLC reduces the cost and effort of implementation and maintenance later on. If we can measure the coupling and cohesion, and therefore the effective modularity, of the Bounded Contexts on an EventStorming domain model we can shift left architectural decisions that would otherwise require re-engineering once the resulting Microservices have been implemented.
While we often anecdotally talk about how high, or low, the coupling and cohesion is in the software we work on, we rarely measure it in quantifiable numbers.
A Metrics Suite for Object Oriented Design (OOD)
In 1994, Chidamber and Kemerer proposed a metrics suite for Object Oriented Design (OOD). Their suite can be used to reduce a UML diagram, or implemented modules of code, to measurements of coupling, cohesion, complexity, reuse and testing effort. The suite comprised of the following 6 metrics:
OOD Metric 1 – Weighted Methods per Class (WMC)
WMC measures how many methods there are in a class and considers all methods to be of equal complexity. The more methods there are in a class, the more complex the class is, the higher the impact to child classes as all methods are inherited, and the ability to reuse a class is reduced as it is likely to be very specific.
OOD Metric 2 – Depth of Inheritance Tree (DIT)
DIT is a measurement of how many levels of inheritance a class is at in the inheritance tree. The higher the DIT, the more complex a class is as it will inherit more methods and functionality, which in itself reflects high reuse.
OOD Metric 3 – Number of Children (NOC)
NOC measure the number of direct children a class has. A high NOC for a class indicates high reuse, but could indicate improper subclassing if it is surprisingly high based on the functionality to inherit from the class. High NOC indicates high testing effort as a change to the class would impact all child classes.
OOD Metric 4 – Coupling Between Object Classes (CBO)
CBO is a count of the number of other classes to which a class is coupled. Classes are coupled if one class calls a method or sets instance variables on another class. A high CBO indicates high coupling, low independence and low reuse. Classes with a high CBO are likely to be difficult to change and costly to test.
OOD Metric 5 – Response for Classes (RFC)
RFC measures the size of the set of methods that can possibly be executed when a method is called on an instance of a class. High RFC indicates high complexity and a class that is difficult to debug and test. Methods executed in the chain can be outside of the class itself which indicates even higher complexity.
OOD Metric 6 – Lack of Cohesion in Methods (LCM)
LCM considers the overlap of parameters that different methods of a class have in common. A high LCM is the result of a class having methods that do not have overlap in their parameters, indicating unrelated functionality existing in the same class. High LCM could reveal opportunities to split a class down further, or to reconsider which class related functionality should be included in.
A Metrics Suite for Domain Driven Design (DDD)
Now we have a way to measure coupling and cohesion but the existing metrics suite requires a UML diagram or implemented code, which we don't have yet at the EventStorming Domain Modelling stage. We can draw some similarities between OOD and DDD though. For instance in terms of modularity, a Bounded Context, or Microservice, is an independently maintainable, testable and deployable component so we can equate it to an OOD object or class that encapsulates certain functionality. Similarly, we can compare an Event within a Bounded Context to a Method on a Class. There are two metrics in the existing suite that are difficult to draw comparisons on, DIT and NOC, which are based on inheritance which has no equal in an EventStorming domain model. That still leaves us with 4 metrics that we can evolve to reduce an EventStorming domain model to measurements of coupling, cohesion, complexity, reuse and testing effort.
DDD Metric 1 – Weighted Events per Microservice (WEM)
WEM measures how many events there are in a Microservice, or Bounded Context, and considers all events to be of equal complexity. The more events there are in a Microservice, the larger and more complex the Microservice is.
DDD Metric 2 – Coupling Between Microservices (CBM)
CBM is a count of the number of other Microservices to which a Microservice is coupled. Microservices are coupled if a policy or command in one Microservice triggers an event in another Microservice. A high CBM indicates high coupling and low independence. Microservices with a high CBM are likely to be difficult to change and costly to test.
DDD Metric 3 – Response for Microservices (RFM)
RFM measures the size of the set of events that can possibly be triggered when an event is called in a Microservice. High RFM indicates high complexity and a Microservice that is difficult to debug and test. Events triggered in the chain can be outside of the Microservice itself which indicates even higher complexity.
DDD Metric 4 – Lack of Cohesion in Events (LCE)
LCE considers the overlap of ReadModel members that different events of a Microservice have in common. A high LCE is the result of a Microservice having ReadModels that do not have overlap in their members, indicating unrelated functionality existing in the same Microservice. High LCE could reveal opportunities to split a Microservice down further, or to reconsider which Microservice related functionality should be included in.
By measuring, or at the very least considering, coupling and cohesion in Bounded Contexts in an EventStorming session, we have an early opportunity to make architectural decisions that can make future maintenance of Microservices easier and less costly.
- Alberto Brandolini's EventStorming
- Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans
- Hands-On Domain-Driven Design with .NET Core: Tackling complexity in the heart of software by putting DDD principles into practice by Alexey Zimarev
- Chidamber & Kemerer object-oriented metrics suite
- Events are Complex