Domain-Driven Design Distilled notes

A cliff and the ocean

I started a new role in October that has a strong focus on event sourcing and domain driven design (DDD). One of the recommended books in our on-boarding materials is Domain-Driven Design Distilled by Vaughn Vernon. Below are my notes taken while reading the book, some will be specific to my context either at work or other applications I have worked on while others are more general. Regardless, I hope they are useful to you.

Before I begin, I have not worked with an event sourced application before, working with event sourcing has been an overall positive experience but did take some time to get my head around, instead of having a standard database table that you query for information you have an event store that is built up to create your state. Event sourcing is not required for domain driven design but it is a common pattern used alongside DDD and is called out by the book as being a good match. This is important because if I had not been using an event sourced application for the last six months some of the concepts in this book would have seemed odd to me, for example Event Storming is something I have participated in at work but if reading the book in isolation I would have assumed it is a standard project discovery process.

What do I think of DDD after reading this book? I did not see much value in DDD if we are just looking at bounded contexts and aggregates since the core of the philosophy is to talk to domain experts and break work down to the smallest piece, isn’t this what we do anyway? The most useful part of DDD for me is the splitting of work into bounded contexts including the core domain then mapping processes to events and commands. This combination of tools makes DDD far more useful than simply talking to business people and breaking work down.

Review of the book itself: This book is pretty thin and if you have not worked in either event sourcing or domain driven design you may get less value than I did. The book clarified some questions I had and has given me the ubiquitous language (ha!) of the style, after reading the book I do not feel I need to read further on the topic generally and if needed I will seek out specific information on single topics. I gave the book five stars on Goodreads but I agree with the negative reviews calling the book thin on content, confusing with the blur of the scrum application example and scrum itself as a DDD project management style and, contains many (many) references to Implementing Domain-Driven Design [IDDD] – Vaughn’s other book. Despite these negative aspects I think this is worth a read and at 130-odd pages you can get through it pretty quickly.

The notes:

General / Chapter 1

  • This seems like it’s just “ask the people who use your software what they think is required”
  • The discussion around splitting domains up to keep the architecture simpler is a good idea
  • Nothing revolutionary yet but let’s see!
  • DDD does not require a particular language or technologies like REST, RPC or Messaging
  • You can use DDD across any sort of technology
  • It really does just seem like splitting your blocks into smaller and smaller pieces. This seems like good architecture regardless however I suppose at some point someone had to name the idea
  • The book “Implementing Domain Driven Design” by the same author has details on using Event Sourcing, CQRS, REST, SOA, Actor Model etc
  • Other books recommended:
    • Reactive messaging patterns with the actor model
    • Building microservices
    • REST in Practice
    • Specification by example (Adzic)
    • User Story Mapping (Patton)

Chapter 2

  • The When/Then approach is useful when tied to event sourcing
  • A flow diagram should be made to map out the process with this diagram owned by the domain owner or domain expert. The diagram is not the actual state of the application, simply a diagram of it.
  • The diagram can then be used to make your application e.g. the entire flow starts as red 🔴 then you write code that eventually makes the full flow green 🟢
  • When naming functions and writing code it should map closely to the domain expert’s understanding of the application which in some cases means they are able to read the code themselves. Using explicit naming helps with this process.
  • The domain model should be technology free. We are focused on the processes and listing everything in the domain whether it uses a queue, stack or pub/sub is inconsequential to the domain itself. By separating domain and technology we can build both well.
  • Microservices work well for DDD since they already have a bounded context
  • If you split your microservices too deeply e.g. “Product” and “Backlog Item” then your bounded context will be wider than the microservice, not a problem just a consideration.
  • It is important to develop a ubiquitous language around your domain so that everyone is on the same page
  • Avoid creating a domain that is too large or you will end up with a big ball of mud

Chapter 3

  • The core domain makes up the actual interesting part of your application e.g. “Project Management tool” and does not include non-core items e.g. “Customers”, “Billing”, “Support Tickets”.
  • Each project will have many separate domains including subdomains
  • One subdomain per bounded context, one bounded context per subdomain. This is the optimal situation.
  • Core domain is the main part of your app
  • A subdomain is a clear area of expertise
  • The core domain dictates where your business must excel and put a limit on the things you become an experts in. You should not plan to become an expert in all areas, such as billing and authentication.
  • Draw dashed lines around your “big ball of mud” to start splitting off a complex legacy domain.
  • One bounded context means one goal. One bounded context should map to one subdomain

Chapter 4

  • Domains will inevitably need to talk to each other. This is called Context Mapping.
  • In our project management example the Discussion domain is the source of the discussion and the PM domain is the consumer of that discussion
  • We talk in terms of Source → Consumer
  • There are different kinds of mappings for teams that operate towards each other’s bounded contexts. Partnership, Shared Kernel, Customer-Supplier, Conformist, Anticorruption layer, Open Host Service, Published Language, Separate Ways, Big Ball of Mud
  • The Conformist layer is what I am most familiar with as a contractor. This is where the upstream domain dictates it’s behaviour out and as the downstream consumer you deal with whatever comes your way.
  • The Open Host Service is good if you have a messy domain under the hood. You create an open host service that exposes certain services with a consistent API, downstream consumers can then plug in easily and follow the conformist pattern. Your domain as the upstream does not need to be the cleanest or fully exposed since the OHS will be sharing the API
  • An anti-corruption layer is a good idea when working with upstream domain models since you can pull in whatever it is they are sharing and make it work for your context and ubiquitous language. The ACL operates as the translation layer between the upstream service to a specific downstream service.
  • REST APIs often reflect the Aggregate in a domain. As the aggregate changes the downstream consumers must follow the Conformer pattern and conform whatever the API sends out
  • Asynchronous messaging is good because you never expect immediate results and thus it is the most robust form of data transfer.
  • Domain events can be used to publish information out to other domains, think pub/sub
  • You are either a publisher or a subscriber or events and those roles will change depending on the event

Chapter 5

  • An aggregate is something like a Forum, Calendar, Calendar Entry, Discussion, Post etc. The Aggregate Root is the top level of that. The highest item in the relationship map. E.g. an Order is the aggregate root then line items, payment record, delivery etc are all aggregates stemming from that aggregate root. They are all considered aggregates.
  • An aggregate root and it’s child aggregates should be handled as a full transaction. If the persistence of an aggregate root fails then presumably the entire business logic has failed as per your domain logic and understanding.
  • Only one aggregate type should be committed per transaction.
  • We should aim to design small aggregates and reference other aggregates by identity only. When updating aggregates we should use eventual consistency
  • Designing small aggregates means they can be garbage collected faster
  • The language of the domain model must match the language of the domain experts
  • Do not try to define all terms in the domain for now and forever into the future. Model the things that exist today and expand when you need to tomorrow.
  • Consider how much time can elapse for eventual consistency. This will determine your aggregate boundaries e.g. if two items need to be updated immediately put them in the same aggregate boundary.
  • Eventual consistency is a business driven decision not a technical one.
  • Consider how the business would run on a paper based system which will help understand the technical requirements and consistency requirements

Chapter 6

  • Domain events should be in past tense
  • Ask yourself “What is the stimulus that causes this event to be published”. E.g. normally a command CreateProduct → ProductCreated event.
  • The corresponding event should contain all of the information that caused the action to happen ideally the information that was provided within the command.
  • You may choose to enrich your domain events with additional data to help downstream consumers. If you include additional context the downstream service does not need to query back to the upstream to get more information. It is advised to not add too much information to your events that they become cluttered. Domain events should be specific and useful to downstream consumers
  • Once your event has been saved to the event store it can be published to anyone that is interested. This allows flexibility from other aggregates, bounded contexts and services that may rely on your data.
  • It is discussing event sourcing. I will not take many notes here because I am familiar with the concept however it is describing a system that takes in events and uses that to create a current state rather than having a set table that has set values for something e.g. we calculate that “Inventory Increased by 1” was done 10 times rather than saying “We have 10 items”.
  • The best benefit of event sourcing is that you have a record of everything that was ever done. This means you can always rebuild your state to understand how you go to where you currently are.
  • Event Sourcing obliges you to use CQRS
  • It is important to identify and implement a common event interface
  • All events should follow the same interface and the content within is what can change

Chapter 7

  • Event Storming involves both developers and domain experts to view all of the possible events in a system
  • You can use UML if your domain experts are technical however sticky notes are a suitable replacement
  • Focus on events and business process over classes and database tables
  • This chapter is mostly dot points so far which is actually not a bad thing to read and is pretty smart as a way to write a book
  • Event storming can (and maybe should) be completed over multiple days. Give people time to think and build on what they have done
  • Don’t try and be correct quick in event storming. Write everything out and then remove errors later. It may be that an event named early that was thought to be in error is actually a core part of a subdomain elsewhere
  • Write down domain events first (past tense, verb). Start at the start and move to the end. Focus on the core domain and do not let modelling or data structures get in your way
  • Do not spend time modelling user registration. It is not important and part of your core domain. Spend your efforts modelling the core domain.
  • After modelling the domain events, model the commands that create those events
  • Associate everything in pairs of Command/Event
  • All commands should have an event but not all events will have a command. Some events may be generated by time passing or some other “non-command” action
  • The word “aggregate” can be confusing so use “entity” or “data” instead. This is in reference to talking with business people but it makes sense across the board.
  • The third step is to list all of the aggregates that are related to both commands and events.
  • The aggregate will be a noun that is acted upon
  • Commands and domain events belong to an aggregate
  • Recreate aggregate stickies instead of grouping all commands/events under a single aggregate. An aggregate can be acted on multiple times but all your events don’t fire at the same time. Focus on modelling process, which occurs over time, rather than entities happening at a single time.
  • Throughout the process continue adding domain events as they come up. These are the most important things to capture while you have the domain experts available.
  • Now that all commands, events, aggregates and processes are documented start to draw lines around each boundary. These will become your bounded contexts
  • When you see events coming across a bounded context have a think about what kind of publisher/consumer model you want to use and how much you can rely on the data being sent.
  • User-facing Views can be established at this point if required
  • Knowledge acquisition is a core focus of DDD
  • DDD is an advanced philosophy and requires above-average developers
    • Is this true? Anyone can say they are doing DDD to give the illusion of them being an “above-average developer”
  • You will need to “buy” knowledge about your project or domain and the payment is a “spike”
  • You cannot expect to have a perfect domain model at the start of your project. Even domain experts will not have a wholly accurate view of all the processes
  • Host sessions with developers to share learnings about the domain model when they are learned. Knowledge sharing and acquisition is the goal.
  • Break your estimations into Domain Event, Command, Aggregate. You can give a generic time for each of these from Easy, Moderate and Hard. This helps to give fast estimates to business users
  • Be careful about breaking the tasks down too granular. It may be best to use an aggregate as the body of work with command and event bundled within.
  • Create concrete scenarios that show how your software is actually created in the real world so that you can build scenarios that your completed functionality will be tested against
  • Be mindful of the time you are taking from domain experts. Respect their time. They are important for DDD so make it fun and engaging
  • Don’t underestimate domain experts. They are experts in their own domain and are smart enough to work alongside developers

You May Also Like