In the wake of the DDD EU conference we felt an urge to gather the DDD community in Stockholm and create a place where we can share thoughts and insights. Together with Dan Bergh Johnsson we created the Meetup-group Domain-Driven Design Stockholm. The Inaugural Meetup last week was hosted at Citerus and Patrik Fredriksson, Christoffer Hellgren and Dan Eidmark took the stage to share their thoughts on the subject of Domain-Driven Design and the combination of DDD & Microservices.
The first presentation was an introduction to Domain-Driven Design by Patrik, who is a certified DDD trainer by Eric Evans. As this was the first meeting of the new DDD Stockholm Meetup group the presentation was there to help guide new members curios of Domain-Driven Design, but with little or no prior knowledge on the topic, into the community.
DDD is based on a couple of assumptions; first that we work in a complex domain, and secondly that our primary tool for managing this complexity is using models.
A few key concepts were defined:
Domain – the subject area to which the user applies a program is the domain of the software.
This could be stuff as disparate as DNA sequencing, financial transaction, real estate maps, etc. The typically domain is non-technical in the meaning that it has nothing inherent to do with software, but software can be immensely useful in solving problems or exploring opportunities in the domain. The core foundation of Domain-Driven Design is the tenet that the critical complexity of most software projects is in understanding the domain itself.
Model – A system of abstractions representing selected aspects of the domain, a distilled form of domain knowledge, assumptions, rules and choices.
The models are iteratively and incrementally formed through creative collaboration between domain experts and software practitioners. It is not about realism, the model is designed to solve a specific set of problems well; problems that to some extent should be defined before modelling starts. As new scenarios and requirements are discovered the software development process must allow for updating and changing (sometimes radically so) the model to incorporate new knowledge and findings. The model must be intimately connected to the code, test it regularly by use of code probes. If the model is hard or impossible to implement in code, it fails to meet our requirements; go look for a new model.
Bounded Context – The conditions under which a particular model is defined and applicable.
The bounded context can be made explicit as a system or a service, and must be small enough to allow for continuous integration of the model concepts it contains. Continuous integration includes implemented code but also joint understanding of model concepts by all members of the development team – developers, domain experts alike. Making the bounded context tangible can be hard, but the concept of microservices shows promise as help to make the bounded contexts explicit in our code in new ways.
Ubiquitous Language – A language structured around the domain model and used by all team members to connect all the activities of the team with the software.
This is a language that grows out of modelling work and is intimately connected to the model. A language we wish to see exercised throughout the development team. We want to hear it used when domain experts talk to domain experts about the software, when developers talk to domain experts, we want to see it in the code, in the structures of our data store where applicable, in our reference scenarios, etc. We want to see it everywhere. By disciplined use of the ubiquitous language as we talk about the features and business rules of our system we will discover where the language lacks nuances, where concepts are missing and where the language just feels awkward. These are the places to look when we work to extend and change our model to better suit the needs of our software.
Patrik wrapped up the presentation by talking about the benefits of DDD and really getting domain experts and software developers collaborating on complex and critical core parts of the software systems we build.
Microservices <3 DDD
During the second talk of the day Christoffer and Dan shared their view of how microservices and DDD complement each other in different beneficial ways.
The talk started off with the subject of boundaries and how Strategic design can help us when we define service boundaries. Depending on the complexity of the business we can either create boundaries that encapsulate a generalization that is meant to be reused or we can define boundaries that encapsulate a challenge within the business. The former is perhaps preferable in more generic subdomains whereas the latter way is more appropriate when we are close to the core domain where it helps us to be as explicit as possible. Domain-driven Design helps us to identify these boundaries and the microservices architecture helps us enforce them by separating them in isolated runtimes.
Microservices are by their nature not living in isolation, they need to communicate. Quite a lot. But in order for us to protect the models Christoffer and Dan suggested that we can create a Context map identifying which models are in play and how they relate to each other. If you find yourself being downstream from from another model you need to decide if you want to be conformist and bring in concepts from the other model or if you should use anti corruption layers to protect your model.
The expectations and contracts between the models also need to be tested and teams need early feedback if a change to a microservice violates these expectations. Microservices creates some extra pressure on testing given the number of services in play and the tendency to use Continuous Delivery which creates an ever changing landscape of services with versions being upgraded. End-to-end testing can get very expensive and does not give immediate feedback on which service (and version) is misbehaving. Instead Christoffer and Dan suggested to look into breaking down the problem and test with pacts between microservices. The Pact testing tools are excellent for verifying behaviour during build time.
They did also discuss the weakness of the layered architecture where it is too easy to cheat and move things between layers. One common problem they addressed was the tendency to let infrastructural components influence how we create our domain model. As a substitute to layered architecture they suggested the Hexagonal architecture that could help you to organize your code by considering the domain model in the center and expose a set of ports where adapters can be connected that should encapsulate the technical details of an integration, eg. REST or Kafka-related code.
Domain-Driven Design helps us to remain autonomous as teams by guiding us in how to organize our microservices. Microservices helps us implement this in practice and creates clear technical boundaries between services. The development team are the masters of their craft and they should own the entire lifecycle of a service. Build, test, deploy and maintenance. When working with microservice architectures the team needs to take care of monitoring, build pipelines, repositories, deploy scripts and a lot more non-coding responsibilities and they need to do this for each new service they deploy. Hence, it is important to automate as much as possible.
We like to share
Do you want a brown bag at your company? Discuss DDD over a lunch? Have some other related questions regarding DDD?
And of course, if you haven’t already; Join us at Domain-Driven Design Stockholm.