Which level of communication is allowed between Aggregates Roots in DDD? - domain-driven-design

Depending on the example that vaughn vernon gave in his book about Agile.He designed Product as an Aggregate and BackLogItem as an aggregate which references Product AR by Id.
Now we need to plan new BackLogItem inside BackLogApplicationService as following:
public class ProductBacklogItemService
{
//...
public void planProductBacklogItem(
String aTenantId, String aProductId,
String aSummary, String aCategory,
String aBacklogItemType, String aStoryPoints)
{
Product product =
productRepository.productOfId(
new TenantId(aTenantId),
new ProductId(aProductId));
BacklogItem plannedBacklogItem =
BacklogItem.planBacklogItem(
aSummary,
aCategory,
BacklogItemType.valueOf(aBacklogItemType),
StoryPoints.valueOf(aStoryPoints),
product);
backlogItemRepository.add(plannedBacklogItem);
//commit the changes
}
//...
}
And the factory method will be like :
public static BacklogItem planBacklogItem(String aSummary, String aCategory,BacklogItemType aType, StoryPoints aStoryPoints,Product product)
{
if(product.Suspended)
//here prevent planning this backlogitem
//...
backLogItem.ProductId=product.Id
return backLogItem;
}
Did I violate the consistency boundary of the BackLogItem Aggregate inside the Factory method because I am using some information about Product state to decide planning new backLogItem into that Product, if so how I can prevent planning new backLogItems into that product in case that product is suspended or inactive?

Which level of communication is allowed between Aggregates Roots in DDD?
The core guideline is this: any given transaction modifies at most one aggregate in your model.
So if your model includes a relationship between a Product and a BacklogItem, then you can modify a Product using a stale copy of data from a BacklogItem, or you can modify a BackLogItem using a stale copy of data from a Product.
To help make this clear in code, we use interfaces to pass messages from one aggregate to another. In a use case where we are going to modify a Product, we have a product interface that supports mutations, and a back log item interface that only supports queries. If we are going to update the back log item, then the item has the mutable interface and the product interface is read only.
In other words, we use appropriate role interfaces to ensure that no code author inadvertently violates the rule of modifying more than one aggregate in a transaction.
our answer it means the above code it does not violate DDD because I don't here update the product aggregate(because of ddd it's not allowed to update more than one aggregate per transaction
Right - when Evans described DDD in 2003, he was working in a coding style that didn't rely upon interfaces; to have an instance of a product meant to have all of the capabilities of the product available at once.
Role interfaces help to reduce the number of errors made possible by this flexibility. Simply not making mistakes is also an option.

Related

How to properly define an aggregate in DDD?

What would be a rule of thumb when designing an aggregate in DDD?
According to Martin Fowler, aggregate is a cluster of domain objects that can be treated as a single unit. An aggregate will have one of its component objects be the aggregate root.
https://martinfowler.com/bliki/DDD_Aggregate.html
After designing aproximatelly 20 DDD projects I am still confused about the rule of thumb when choosing domain objects that would create an aggregate.
Martin Fowler uses order and line-items analogy and I don't think it is a good example, because order+line-items are really tightly bounded objects. Not much to think about in that example.
Lets try with car analogy where CarContent is a subdomain of a car dealer domain.
CarContent would consist of at least one or more aggregate/s.
For example we have this AggregateRoot (i am keeping it as simple as possible)
class CarStructureAggregate
{
public int Id {get; private set;}
public ModelType ModelType {get; private set;}
public int Year {get; private set;}
public List<EquipmentType> {get; private set;}
}
Alternative could be this (example B)
class CarStructureAggregate
{
public int Id {get; private set;}
public ModelType ModelType {get; private set;}
public int Year {get; private set;}
}
class CarEquipmentAggregate
{
public int Id {get; private set;}
public List<EquipmentType> {get; private set;}
}
Car can be created without equipment but it cannot be activated/published without the equipment (ie. this can be populated over two different transactions)
Equipment can be referenced trough CarStructureAggregate in example A or using CarEquipmentAggregate in example B.
EquipmentType could be an enum, or could be a complex class with many more classes, properties.
What is a rule of thumb when choosing between examples A and B?
Now imagine that car could have more information such as
photos
description
maybe more data about the engine
and CarStructureAggregate could be an extremely large class
So what is it that makes us split Aggregate into new Aggregates? Size? Atomicity of a transaction (although that would not be an issue since usually aggregates of a same sub domain are usually located on the same server)
Be careful about having too strong OO mindset. The blue book and Martin Fowler post are a little bit old and the vision it provides is too narrow.
An aggregate does not need to be a class. It does not need to be persisted. Theese are implementation details. Even, sometimes, the aggregate do things that does not implies a change, just implies a "OK this action may be done".
iTollu post give you a good start: What matters is transactional boundary. The job of an aggregate is just one. Ensure invariants and domain rules in an action that, in most of the cases (remember that not always), change data that must be persisted. The transactional boundary means that once the aggregate says that something may, and has, be done; nothing in the world should contradict it because, if contradiction occurs, your aggregate is badly designed and the rule that contradict the aggregate should be part of aggregate.
So, to design aggregates, I usualy start very simple and keep evolving. Think in a static function that recives all the VO's, entities and command data (almost DTO all of them except the unique ID of the entities) needed to check domain rules for the action and returns a domain event saying that something has be done. The data of the event must contain all data that your system needs to persist the changes, if needed, and to act in consequence when the event reach to other aggregates (in the same or different bounded context).
Now start to refactoring and OO designing. Supress primitive obsession antipattern. Add constraints to avoid incorrect states of entities and VO's. That piece of code to check or calculate someting related to a entity better goes into the entity. Put your events in a diet. Put static functions that need almost the same VO's and entities to check domain rules together creating a class as aggregate root. Use repositories to create the aggregates in an always valid state. And a long etc. You know; just good OOP design, going towards no DTO's, "tell, don't ask" premise, responsibility segregation and so on.
When you finish all that work you will find your aggregates, VO's and entities perfectly designed from a domain (bounded context related) and technical view.
Something to keep in mind when designing aggregates is that the same entity can be an aggregate in one use case and a normal entity in another. So you can have a CarStructureAggregate that owns a list of EquipmentTypes, but you can also have an EquipmentTypeAggregate that owns other things and has its own business rules.
Remember, though, that aggregates can update their own properties but not update the properties of owned objects. For example if your CarStructureAggregate owns the list of EquipmentType, you cannot change properties of one of the equipment types in the context of updating the CarStructureAggregate. You must query the EquipmentType in its aggregate role to make changes to it. CarStructureAggregate can only add EquipmentTypes to its internal list or remove them.
Another rule of thumb is only populate aggregates one level deep unless there is an overriding reason to go deeper. In your example you would instantiate the CarStructureAggregate and fill the list of EquipmentTypes, but you would not populate any lists that each EquipmentType might own.
I believe, what matters here is transactional boundary.
On one hand, you can't establish it more narrow than it is sufficient for preserving an aggregate's consistency.
On the other hand, you don't want to make it so large to lock your users from concurrent modifications.
In your example, if users should be able to modify CarStructure and CarEquipment concurrently - then I'd stick to implementation B. If not - it would be simpler to use A.
in a very simple sentence, I can say:
basically, a business use case that aims to change and consists of one or more relevant entities, value objects, and invariants based on the business in domain-driven design is aggregate. being a model command is important because if you only need to read, you don’t need an aggregate.

DDD Effective modelling of aggregates and root aggregation creation

We are starting a new project and we are keen to apply DDD principles. The project is using dotnet core, with EF core providing the persistence to SQL Server.
Initial view of the domain
I will use an example of a task tracker to illustrate our issues and challenges as this would follow a similar structure.
In the beginning we understand the following: -
We have a Project
Users can be associated to Projects
A Project has Workstreams
A Workstream has Tasks
Users can post Comments against a Task
A User is able to change the status of a Task (in progress, complete etc)
A Project, with associated Worksteams and Tasks is initially created from a Template
The initial design was a large cluster aggregate with the Project being the root aggregate holding a collection of ProjectUsers and Workstreams, Workstreams has a collection of Tasks etc etc
This approach was obviously going to lead to a number of contention and performance issues due to having to load the whole Project aggregate for any changes within that aggregate.
Rightly or wrongly our next revision was to break the Comments out of the aggregate and to form a new aggregate using Comment as a root. The motivation for this was that the business envisaged there being a significant number of Comments raised against each Task.
As each Comment is related to a Task a Comment needs to hold a foreign key back to the Task. However this isn't possible following the principle that you can only reference another aggregate via its root. To overcome this we broke the Task out to another aggregate. This also seemed to satisfy the need that the Tasks could be Completed by different people and again would reduce contention.
We then faced the same problem with the reference from the Task to the Workstream the Task belongs to leading to us creating a new Workstream aggregate with the foreign key in the Task back to the Workstream.
The result is: -
A Project aggregate which only contains a list of Users assigned to the project
A Workstream aggregate which contains a foreign key to the Project
A Task aggregate which contains a foreign key to the Project
A Comments aggregate which contains a foreign key back to the Task
The Project has a method to create a new instance of a Workstream, allow us to set the foreign key. I.e. slightly simplified version
public class Project()
{
string _name { get; private set;}
public Project(Name)
{
_name = Name;
}
public Workstream CreateWorkstream(string name)
{
return new Workstream(name, Id);
}
....+ Methods for managing user assignment to the project
}
In a similar way Workstream has a method to create a Task
public class Workstream()
{
string _name { get; private set;}
public int ProjectId { get; private set; }
public Workstream(Name, Id)
{
_name = Name;
_projectId = Id;
}
public Task CreateTask(string name)
{
return new Task(name, Id);
}
private readonly List<Task> _activities = new List<Task>();
public IEnumerable<Task> Activities => _activities.AsReadOnly();
}
The Activities property has been added purely to support navigation when using the entities to build the read models.
The team are not comfortable that this approach, something doesn't feel right. The main concerns are:-
it is felt that creating a project logically should be create project, add one or more workstreams to the project, add task to the workstreams, then let EF deal with persisting that object structure.
there is discomfort that the Project has to be created first and that the developer needs to ensure it is persisted so it gets an Id, ready for when the method to Create the template is called which is dependent on that Id for the foreign key. Is it okay to push the responsibility for this to a method in a domain service CreateProjectFromTemplate() to orchestrate the creation and persistence of the separate objects to each repository?
is the method to create the new Workstream even in the correct place?
the entities are used to form the queries (support by the navigation properties) which are used to create the read models. Maybe the concern is that the object structure is being influence by the how we need to present data in a read only
We are now at the point where we are just going around in circles and could really use some advice to give us some direction.
The team are not comfortable that this approach, something doesn't feel right.
That's a very good sign.
However this isn't possible following the principle that you can only reference another aggregate via its root.
You'll want to let go of this idea, it's getting in your way.
Short answer is that identifiers aren't references. Holding a copy of an identifier for another entity is fine.
Longer answer: DDD is based on the work of Eric Evans, who was describing a style that had worked for him on java projects at the beginning of the millennium.
The pain that he is strugging with is this: if the application is allowed object references to arbitrary data entities, then the behaviors of the domain end up getting scattered all over the code base. This increases the amount of work that you need to do to understand the domain, and it increases the cost of making (and testing!) change.
The reaction was to introduce a discipline; isolate the data from the application, by restricting the application's access to a few carefully constrained gate keepers (the "aggregate root" objects). The application can hold object references to the root objects, and can send messages to those root objects, but the application cannot hold a reference to, or send a message directly to, the objects hidden behind the api of the aggregate.
Instead, the application sends a message to the root object, and the root object can then forward the message to other entities within its own aggregate.
Thus, if we want to send a message to a Task inside of some Project, we need some mechanism to know which project to load, so that we can send the message to the project to send a message to the Task.
Effectively, this means you need a function somewhere that can take a TaskId, and return the corresponding ProjectId.
The simplest way to do this is to simply store the two fields together
{
taskId: 67890,
projectId: 12345
}
it is felt that creating a project logically should be create project, add one or more workstreams to the project, add task to the workstreams, then let EF deal with persisting that object structure.
Maybe the concern is that the object structure is being influence by the how we need to present data in a read only
There's a sort of smell here, which is that you are describing the relations of a data structure. Aggregates aren't defined by relations as much as they are changes.
Is it okay to push the responsibility for this to a method in a domain service CreateProjectFromTemplate
It's actually fairly normal to have a draft aggregate (which understands editing) that is separate from a Published aggregate (which understands use). Part of the point of domain driven design is to improve the business by noticing implicit boundaries between use cases and making them explicit.
You could use a domain service to create a project from a template, but in the common case, my guess is that you should do it "by hand" -- copy the state from the draft, and then send use that state to create the project; it avoids confusion when a publish and an edit are happening concurrently.
Here is a different perspective that might nudge you out of your deadlock.
I feel you are doing data modeling instead of real domain modeling. You are concerned with a relational model that will be directly persisted using ORM (EF) and less concerned with the actual problem domain. That is why you are concerned that the project will load too many things, or which objects will hold foreign keys to what.
An alternative approach would be to forget persistence for a moment and concentrate on what things might need what responsibilities. With responsibilities I don't mean technical things like save/load/search, but things that the domain defines. Like creating a task, completing a task, adding a comment, etc. This should give you an outline of things, like:
interface Task {
...
void CompleteBy(User user);
...
}
interface Project {
...
Workstream CreateWorkstreamFrom(Template template);
...
}
Also, don't concentrate too much on what is an Entity, Value Object, Aggregate Root. First, represent your business correctly in a way you and your colleagues are happy with. That is the important part. Try to talk to non-technical people about your model, see if the language you are using fits, whether you can have a conversation with it. You can decide later what objects are Entities or Value Objects, that part is purely technical and less important.
One other point: don't bind your model directly to an ORM. ORMs are blunt instruments that will probably force you into bad decisions. You can use an ORM inside your domain objects, but don't make them be a part of the ORM. This way you can do your domain the right way, and don't have to be afraid to load too much for a specific function. You can do exactly the right things for all the business functions.

Handling entity updates from a mapped object

I have my code first, SQL data models (using EF Core 1.1) that are used to model my schema/tables. However I also have domain objects which are partial or full mapped versions of these SQL data models, in essence they sort of have the same shape as the SQL data models.
Now I would like to know what is the best way to handle cascading updates when you have complex objects being altered outside of the context of its tracked context. When you consider that all my domain operations do not take place on the tracked entity, they take place on the domain object.
In Short, This is what I am trying to achieve.
1) Read entity from database.
2) Map entity to domain object.
3) Apply updates to domain object.
4) Map domain object back to entity.
5) Apply database update on mapped entity which results in the entity and its associated relative entities to be updated.
By the way the entities and domain object have the typical many to one relationships that one might run into. What is the best way to go about doing this?
What is the best way to go about doing this?
I think the best way to go about this is to avoid the problem in the first place by using an framework that is flexible enough to allow mapping the domain objects directly to the database without too many compromise in order to avoid having to model an explicit persistence model in code.
in essence they sort of have the same shape as the SQL data models
If you think about it means you would have the same impedance mismatch between your domain model (object model) and relational DB model than between your domain model and the explicit persistence model.
Still, there is an elegant way to perform the mapping which Vaughn Vernon describes in Modeling Aggregates with DDD and Entity Framework. Basically, it boils down to store state in explicit state objects which are bags of getters/setters that are encapsulated and maintained by real domain objects. These state objects are then mapped with EF.
E.g. taken from the above linked article
public class Product {
public Product(
TenantId tenantId,
ProductId productId,
ProductOwnerId productOwnerId,
string name,
string description) {
State = new ProductState();
State.ProductKey = tenantId.Id + ":" + productId.Id;
State.ProductOwnerId = productOwnerId;
State.Name = name;
State.Description = description;
State.BacklogItems = new List<ProductBacklogItemState>();
}
internal Product(ProductState state) {
State = state;
}
...
}

DDD Factory Responsibility

If have the following Code.
public class CountryFactory : IEntityFactory
{
private readonly IRepository<Country> countryRepository;
public CountryFactory(IRepository<Country> countryRepository)
{
this.countryRepository = countryRepository;
}
public Country CreateCountry(string name)
{
if (countryRepository.FindAll().Any(c => c.Name == name))
{
throw new ArgumentException("There is already a country with that name!");
}
return new Country(name);
}
}
From a DDD approach, is the the correct way to create a Country. Or is it better to have a CountryService which checks whether or not a country exists, then if it does not, just call the factory to return a new entity. This will then mean that the service will be responsible of persisting the Entity rather than the Factory.
I'm a bit confused as to where the responsibility should lay. Especially if more complex entities needs to be created which is not as simple as creating a country.
In DDD factories are used to encapsulate complex objects and aggregates creation. Usually, factories are not implemented as separate classes but rather static methods on the aggregate root class that returns the new aggregate.
Factory methods are better suited than constructors since you might need to have technical constructors for serialization purposes and var x = new Country(name) has very little meaning inside your Ubiquitous Language. What does it mean? Why do you need a name when you create a country? Do you really create countries, how often new countries appear, do you even need to model this process? All these questions arise if you start thinking about your model and ubiquitous language besides tactical pattern.
Factories must return valid objects (i.e. aggregates), checking all invariants inside it, but not outside. Factory might receive services and repositories as parameters but this is also not very common. Normally, you have an application service or command handler that does some validations and then creates a new aggregate using the factory method and adds it to the repository.
There is also a good answer by Lev Gorodinski here Factory Pattern where should this live in DDD?
Besides, implementation of Factories is extensively described in Chapter 11 of the Red Book.
Injecting a Repository into a Factory is OK, but it shouldn't be your first concern. The starting point should be : what kind of consistency does your business domain require ?
By checking Country name uniqueness in CountryFactory which is part of your Domain layer, you give yourself the impression that the countries will always be consistent. But the only aggregate is Country and since there is no AllCountries aggregate to act as a consistency boundary, respect of this invariant will not be guaranteed. Somebody could always sneak in a new Country that has exactly the same name as the one being added, just after you checked it. What you could do is wrap the CreateCountry operation into a transaction that would lock the entire set of Countries (and thus the entire table if you use an RDBMS) but this would hurt concurrency.
There are other options to consider.
Why not leverage a database unique constraint to enforce the Country name invariant ? As a complement, you could also have another checkpoint at the UI level to warn the user that the country name they typed in is already taken. This would necessitate another "query" service that just calls CountryRepository.GetByName() but where the returned Countries are not expected to be modified.
Soon you'll be realizing that there are really two kinds of models - ones that can give you some domain data at a given moment in time so that you can display it on a user interface, and ones that expose operations (AddCountry) and will guarantee that domain invariants always hold. This is a first step towards CQRS.
What is the frequency of Countries being added or modified ? If it is that high, do we really need a Country name to be unique at all times ? Wouldn't it solve a lot of problems if we loosened up the constraints and allowed a user to temporarily create a duplicate Country name ? A mechanism could detect the duplicates later on and take a compensating action, putting the newly added Country on hold and reaching out to the user to ask them to change the name. A.k.a eventual consistency instead of immediate consistency.
Does Country need to be an Aggregate ? What would be the cost if it was a Value Object and duplicated in each entity where it is used ?

Domain Driven Design modelling queries

I'm building a new application and am new to Domain Driven Design. I've been reading through the documentation and I've managed to model most of the domain model but I would like some advice about two queries:
I have two domain objects channel and program. I've modelled these both as entities as both can be accessed independantly. A channel can have a list of programs so I have put this as an attribute of channel. My query is how should I populate the program list. Is it OK for the getChannerById method in ChannelService to first get the channel information and then call the ProgramService to get the list of programs for the channels e.g:
Channel {
String channelId
List <Program> programList
}
Program {
String programId {
}
ChannelService {
Channel getChannelById(String channelId)
}
ProgramService {
Program getProgramById(String programId)
List <Program> getProgramsByChannelById(String channelId)
}
I have a product domain object but some of its attributes (e.g. specification and compatability) involve quite time consuming operations. These attributes are not required all the time so is it OK to put these as part of the domain object and have seperate service methods that populate these attributes when required e.g.
Product {
String productId
Specification specification
List <Product> compatibleProducts
}
ProductService {
Product getProduct(String productId);
void getProductSpecifications(Product product);
void getCompatibleProducts(Product product);
}
Any advice would be very much appreciated.
When designing entities in DDD you shouldn't create associations from one entity to another such that the association is used for display or query purposes alone. While it is true that a channel has a set of programs, is the association between channel and the set of its programs required for the channel entity? More importantly, if you're only considering the query aspect then you may not need be forcing DDD upon your code. Instead, when designing entities consider the behavior that these entities need to implement. If your entities have no behavior but are only used as data containers then you don't need DDD. To answer your question, I would use read model classes that satisfy requirements of each query. For example, for your product model, if one query requires the specification attribute and another doesn't, create distinct read-model classes for those queries. These classes are not entities, they are simple read-only value objects, they don't have any behavior and their job is to represent data. In regards to implementing the query you have several options. Calling both the ChannelService and the ProgramService is one option. However, if the data is all stored together in a single database, why not just create a repository that returns all required data with one call? Take a look at my post on read-models in DDD for more on this topic.

Resources