Coding Architect at ThoughtWorks. Java, Kotlin, Nodejs, Clojure, Ruby, Scala, C#.
Have you been finding it difficult to model boundaries of your system’s microservices? Have you been slowed down by the Technical complexity of your codebase? Has your team been stepping on each other’s toes ?
If answers to any or many of such questions are yes, then Domain Driven Design is likely to be useful to your Team!
What is Domain Driven Design aka DDD
Domain-Driven Design is a language and domain-centric approach to software design for complex problem domains.
It consists of collective wisdom from Software Industry, collection of patterns, principles and practices that will enable teams to focus on what is core to the success of the business while crafting software that manages complexity in both the technical and business spaces.
The term was coined by Eric Evans in his seminal book “Domain-Driven Design: Tackling Complexity in the Heart of Software” written in 2003 and was well ahead of its time!
It started becoming very relevant with microservices architecture era. It was relevant in 2003 for designing modular monolith and today as well! Modular monolith is a topic for my other blog!
Tactical and Strategic patterns of DDD
We will use example of retail e-commerce domain to explain the following concepts. Everything in this Domain resolves around the “Product”being sold.
If you want to see some code related to this, please do checkout:
Let’s talk about some strategic patterns like bounded context, ubiquitous language and context map.
Building just one domain model for entire e-commerce will be very hard to comprehend and implement in the code. Bounded context helps in splitting e-commerce domain into smaller subdomains. E.g. Inventory, Shopping Cart, Product Catalog, Fulfilment & Shipment and Payment. We can use technics like event-storming to identify such subdomains and bounded contexts. So we now have Inventory bounded context, Product Catalog bounded Context, and so on…
It is important to note that Product in each bounded context has a very different behaviour. In Inventory Context Product is concerned about weight, expiry date, supplier, whereas in Shopping Cart bounded context, the expiry, the Supplier of the Product are not in picture. So it is better to model different Product class in each bounded context instead of having a common Product class across bounded context.
So bounded context is a linguistic boundary! Any time you see that the Product is acting differently, it is a clue that there are different bounded contexts in the play.
One bounded context typically has few (or one) micro-services
Ubiquitous language applies within bounded context. Each bounded context has its own ubiquitous language. It is a language which is spoken both by the Business Teams and the Development teams. Its helps them to communicate better.
If your Business team is talking in terms of Database tables then as the Development Team you have influenced them incorrectly.
Business and development team should communicate with each other using DDD tactical patterns like Domain Event, Domain Service, Entity, Value Object. More on that later (in this blog).
Context Map defines relationship between different bounded contexts.
How different bounded contexts communicate with each other and how they influence each other.
Now, let’s talk about some tactical patterns like Domain Event, Entity, Value object, Domain service and Aggregate.
Domain events indicate something important that has happened in the system from the perspective of the Business Team. Let’s take a example of Cart Entity in the Shopping cart bounded context. Events like ProductAddedToCart, ProductRemovedFromCart, CartCheckedOut are important to business teams.
Domain Events can not be updated or deleted once they happen. They can be used as communication mechanism between different bounded contexts. So CartCheckoutEvent, when generated by Cart, can be used by Payment bounded context in e-commerce to initiate payment from User.
Domain Events helps with building loosely coupled, scalable systems.
They are also the basis for designing Event Sourced systems.
In Shopping Cart bounded context Cart is Entity. Cart has different behaviours such as add product, remove product, checkout, etc. Cart also has Identity and life cycle associated with it. You can identify one cart from another cart!
Many objects are not fundamentally defined by their attributes but rather by the thread of continuity and Identity. Fundamental concept of Entity is continuity threading through life cycle and even passing through multiple forms.
Object defined primarily by its identity is called an Entity.
E.g. A person, city, car, lottery ticket or a bank transaction.
Example of seat booking in stadium, Seat and Attendee as Entities. If it is general admission then Seat need not be an Entity but a Value object.
Price of Product in Cart is a Value Object.
Many objects have no conceptual identity. These objects describe the characteristic of the thing. E.g. two markers of same color and the same shape. If one is lost, a drawing can continue by replacing it with the other marker.
Value objects describe the things. They are elements of design that we care about only for what they are and not who or which they are.
Code Value objects as Immutable.
Aggregate is a logical concept. At the root of aggregate there is Entity!
In Shopping cart bounded context Cart is Aggregate and at root of it there is the Cart Entity.
Aggregate is a cluster of associated objects that we treat as a unit for purpose of data changes. Aggregate root is at the top and is the only entity through which Aggregate can be accessed and has the global identifier.
Other Objects inside aggregate can have local identifiers and are NOT accessible outside aggregate directly. Aggregate root controls access to them from the outside world.
One microservice typically has one Aggregate
Invariants/consistency rules/business rules applied within an Aggregate will be enforced with the completion of each transaction like adding product to the cart, removing product from cart, etc. Example — Cart total price should match with the sum of all the product prices in the cart.
Within an aggregate Strong Consistency (Semantics of ACID properties of transaction) apply.
Sometimes it is not just a thing or a noun. You can model verbs or business processes as Domain Service, too.
ProductPricer which uses different pricing algorithms by taking other inputs in e-commerce can be modelled as Domain Service.
If you want to see some code related to this, please do checkout:
Create your free account to unlock your custom reading experience.