I wanna model Order and Product concept with the help of DDD but I wonder how to deal with it.
Suppose you have Order class that has OrderItem class as it's child and Order is Aggregate Root, and Order class has list of OrderItems and every OrderItem has a reference to Product Class. Product is Aggregate Root of course.
I mean some thing like this :
public class Order{
...
public list<OrderItem> OrderItems {get;set;}
}
public class OrderItems{
...
public int Qty {get; set;}
public Product {get; set;}
}
public class Product{
...
}
but as far as i know I can't have a reference from child of Order Aggregate to Product Aggregate. how to deal with this ?
Tnx in forward.
At the page 202 of book Architecting application for the enterprise you could see an image. There are various bounded context, two of them are really simialr to what you need. Order is an aggregate root, having Order Detail as its child. Order Detail in turn has a relationship with Product that is the aggegate root of an aggregate in a different bounded context.
So the first thought is that Product belongs to Order aggregate.
However, next you might find out that use-case exist to treat products
outside of orders-for example for the catalog of products. This makes
up for another aggergate rooted in Product.
So... yes, a child of an aggregate can hold a reference to another aggregate root (even in different bounded context).
Is this a right choice? The right answer in a case like that is always: depends.
On what? On business rules, and how you have to handle the aggregate that will be "swallowed" (Product) by another bigger aggregate (Order).
Related
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.
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.
I know there are a million questions like this. I'm sorry. I think mine is different but it may not seems so. I am new to DDD and trying to get a grip.
Part of my domain is like this.
Location 1-* Field
Field 1-* Event
Field 1-* Task
Task - Employee
now it would seem that the AR is the Location. and if I wanted to get a particular task I would have to traverse down to the task through the collection of fields in to the collection of tasks.
This sounds pretty laborious since I am dealing with tasks and events a lot and almost never with a location per say. The location serves to segregate a group of fields and their corresponding entities. So in the ui, I may pick a location and get a list of fields. I then would pick a field. From there I might edit one of it's tasks. So I have a collection of tasks and I pick one so I have the Id of the task. I then need to traverse up to location and get his Id so I can get the AR and traverse back down to the task. Or rather I would be keeping the Id of the AR around so that I could get it. So should I be keeping the Id of the Field around too? so what I return to the server would be the AR.Id, the Field.Id and the Task.Id that I want to look at?
Secondly, an employee of course could not be an Entity it would most likely be an AR. Is it ok for an Entity on an AR to have a collection of ARs?
So perhaps the way it should be structured is like this?
public class Location // is an aggregate Root
{
public IEnumerable<Field> Fields {get;set;} //in real code encapsulated. not here for brevity
}
public class Field // is an Aggregate Root
{
public Location Location {get;set;} //reference to AR
public IEnumerable<Task> Tasks {get;set;}
public IEnumerable<Events> Events {get;set;}
}
public class Task // is an Aggregate Root
{
public Field Field {get;set;} // reference to AR
public IEnumerable<Employee> Employees {get;set;}
public TaskType TaskType {get;set;} // probably Value Object
public IEnumerable<Equipment> Equipment {get;set;} // maybe Entity or AR
}
This makes it much easier to deal with the objects that are modified the most and to traverse their relationships, but it also feels sort of like plain old OOP and that AR doesn't really mean anything.
Again I'm new to DDD and don't have anyone to run this by for a sanity check. Please help me get a grip on how these boundaries are drawn, and if it is the first way, is there an easier way to handle dealing with the Entities then carrying around the AR.id, ParentParent.Id, ParentId and finally the object of interest Entity.Id
Thanks for any thoughts
R
Ok, upon some more googling I found this great series of articles.
https://dddcommunity.org/wp-content/uploads/files/pdf_articles/Vernon_2011_1.pdf
to get to part 2 and so on just change the last didgit in the url.
Here I discovered that, much like Yves points out, I was misunderstanding the purpose of Aggregates and Aggregate Roots. Turns out they are about maintaining consistency between related entities rather then just bundling up a bunch of entities that have relations to each other.
So if a Field could only have 3 Tasks on any given day, then a Field would be a good candidate for an AR since if you were just adding Tasks willy nilly you could easily create an invalid state in the system, where as if you had to add a Task via a method on Field, then it could easily be checked whether that is acceptable.
Further one wants to avoid giant aggregate roots because they take a lot of resources to load, and can cause concurrency problems. etc etc read the articles they address my above question beautifully
I currently create a Repository for each database table and a corresponding data class for the column values (object to pass around data).
I recently started using some 1 to 1 relationships and I'm not sure what would be the best way to implement them.
For example
If I have a User table and a UserSettings Table in a 1:1 relationship.
// Data classes (Holds all the field value for the table)
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
}
public class UserSettings
{
public int UserId { get; set; }
public bool SomeSetting { get; set; }
}
Questions:
Should I always go through the User object to manipulate the UserSettings object, or should I be able to manipulate them
independently?
Should I include the primary key field in the UserSettings object?
Should I store a reference to the USerSettings object in the User object?
Do I make two repo's one for User and one UserSettings, or do I handle everything in the Users Repo.
The only time I've ever found a 1:1 relationship between aggregate roots to be useful is when the aggregate roots on either side of the relationship are managed by different domains. They must share the same primary key, and therefore if they are both managed by the same domain then they are by definition parts of the same aggregate root. I think you need to approach this question from a different angle:
Is the User object only going to exist for this application?
Do you expect that to always be the case?
If the User is a concept that resides entirely inside of this domain, then there's no reason to have a UserSettings aggretate root that has a 1:1 relationship with a User; you simply make User.Settings a way to retrieve the UserSettings for that User. (And of course that obviates the need for a repository - it becomes the responsibility of the UserRepository to hydrate the UserSettings when it hydrates everything else on the User.)
But, if the User will eventually inform sessions for multiple domains, then User needs to represent its own domain, the services of which your application will consume. Then, you gain a very real need to separate the UserSettings of this application from those of a different application. The User is not specific to this application, but the UserSettings for that User is.
NOTE - In the interest of not refactoring your project at this point, if the answer to either question 1 or 2 above is "no", then you should make UserSettings a separate aggregate root within the same domain, in order to create a seamless transition when you eventually do move User into its own domain.
What exactly do you mean by 'going through the user object' ?
IMHO, no.
You can, but I do not think you should. Is there any reason why you'd want to know to which User the settings belong to ? The only time you'd want to know that -imho- is when you persist it. In your database, you need to know to which User, the UserSettings belong to. In your model, I think you can suffice by a uni-directional relationship
You should only create a repository per aggregate root, in your case 'User' can be an aggregate root. UserSettings is -imho- not even an entity but a value object.
I currently create a Repository for each database table
...
// Data classes (Holds all the field value for the table)
It seems you're adopting a bottom-up (database first/database centric) approach which is uncommon in DDD. As the name Domain Driven Design implies, you usually rather start by modelling your domain, fleshing out your Aggregates, Aggregate Roots and Entities.
Aggregate roots usually have their own Repository while regular entities most often don't. To know whether an entity should be an Aggregate root, you have to ask yourself if that object is going to be one of the main entry points in the application, with a group of related objects gravitating around it and only obtainable through traversal of it.
User is an obvious candidate for an Aggregate root. User Settings in contrast isn't IMO a root, it belongs in the sphere of influence of a User. I'd make it a part of the User Aggregate and only obtainable through traversal of a User. It means having a reference to UserSettings in User but not necessarily the other way around.
I would ask yourself if a UserSettings can exist with out an associated user, and/or does a User always have an associated UserSettings. If so then the UserSettings could easily be made part of the User aggregate rather then being a separate aggregate itself. Yes in the database they will most likely be in different tables with 1:1 relationship between them, but this is a specific concern of the implementation of the repository. Your domain model could consider the UserSettings part of the user.
I'm currently working a lot with DDD, and I'm facing a problem when loading/operating on aggregate roots from other aggregate roots.
For each aggregate root in my model, I also have a repository. The repository is responsible for handling persistence operations for the root.
Let's say that I have two aggregate roots, with some members (entities and value objects).
AggregateRoot1 and AggregateRoot2.
AggregateRoot1 has an entity member which references AggregateRoot2.
When I load AggregateRoot1, should I load AggregateRoot2 as well?
Should the repository for AggregateRoot2 be responsible for this?
If so, is it okay for the entity in AggregateRoot1 to call the repository of AggregateRoot2 for loading?
Also, when I create an association between the entity in AggregateRoot1 to AggregateRoot2, should that be done through the entity, or through the repository for AggregateRoot2?
Hope my question makes sense.
[EDIT]
CURRENT SOLUTION
With help from Twith2Sugars I've come up with the following solution:
As described in the question, an aggregate root can have children that have references to other roots. When assigning root2 to one of the members of root1, the repository for root1 will be responsible for detecting this change, and delegating this to the repository for root2.
public void SomeMethod()
{
AggregateRoot1 root1 = AggregateRoot1Repository.GetById("someIdentification");
root1.EntityMember1.AggregateRoot2 = new AggregateRoot2();
AggregateRoot1Repository.Update(root1);
}
public class AggregateRoot1Repository
{
public static void Update(AggregateRoot1 root1)
{
//Implement some mechanism to detect changes to referenced roots
AggregateRoot2Repository.HandleReference(root1.EntityMember1, root1.EntityMember1.AggregateRoot2)
}
}
This is just a simple example, no Law of Demeter or other best principles/practices included :-)
Further comments appreciated.
I've been in this situation myself and came to a conclusion that it's too much of a head ache to make child aggregates work in an elegant way. Instead, I'd consider whether you actually need to reference the second aggregate as child of the first. It makes life much easier if you just keep a reference of the aggregate's ID rather than the actual aggregate itself. Then, if there is domain logic that involves both aggregates this can be extracted to a domain service and look something like this:
public class DomainService
{
private readonly IAggregate1Repository _aggregate1Repository;
private readonly IAggregate2Repository _aggregate2Repository;
public void DoSomething(Guid aggregateID)
{
Aggregate1 agg1 = _aggregate1Repository.Get(aggregateID);
Aggregate2 agg2 = _aggregate2Repository.Get(agg1.Aggregate2ID);
agg1.DoSomething(agg2);
}
}
EDIT:
I REALLY recommend these articles on the subject: https://vaughnvernon.co/?p=838
This approach have some issues. first, you should have one repository to each aggregate and its done. having one repository that calls another one is a break on this rule. second, a good practice about aggregate relationship is that one root aggregate should communicate with another root aggregate by its id, not having its reference. doing so, you keep each aggregate independent of another aggregate. keep reference in root aggregate only of the classes that compose the same aggregate.
Perhaps the AggregateRoot1 repository could call AggregateRoot2 repository when it's constructing the the AggregateRoot1 entity.
I don't think this invalidates ddd since the repositories are still in charge of getting/creating their own entities.