If my understanding of Aggregate Roots is correct, the root should be responsible also for deleting one of its "children". That would seemingly translate into something like this:
order.removeOrderLine(23);
Which would effectively remove it from the collection. However, how is this persisted? Is my ORM's UnitOfWork supposed to detect that something went missing in that collection, and then delete it from the database?
Should I have removeOrderLine a method of the OrderRepository instead?
Your Unit of Work should usually take care of this, but it depends on its implementation, specifically on the way it detects changes. Some unit of work implementations (i.e. Hibernate) keeps a copy of the aggregate before you changed it, so at the end of business transaction (when you call something like unitOfWork.PersistAll()), it tries to match current version of all objects (and collections) against the original version.
Other way is to have your domain entities more coupled with your unit of work so that the entity notified the unit of work when something changes (i.e. the order.removeOrderLine method would notify the unit of work about the change).
There are multiple ways how to implement UoW change detection. Have a look at several implementations for hibernat for inspiration.
Related
I am modeling a course app, trying to play with DDD and Clean Architecture. So I have Course, which has one or more modules, and each of them has one or more lessons
I created a ModuleLessons aggregate root which is a list of lessons that belongs to a module.
I have the use case where user can access the whole list of lessons within a module, so he access an url like myapp/lessons/{module-id} and this it will endup calling something like moduleLessonsRepository.getById({module-id}) and will render to user a list of lessons which compose that module
As I understand, repository should only deal with the whole aggregate root, not child entities directly. In other words, if Lesson is not an AR, I must not have a LessonRepository.getById()
But I have another use case where user can access something like myapp/lesson/{lesson-id}
But how could I implement if I cant have a repository which returns a lesson by it's id?
I could load the ModuleLessons aggregate and then find lesson within it, but I don't have it's id to query.
I could put module id and lesson id (or maybe just a 'lesson position within it's module) on the url and use that to find the ModuleLessons AR, but I'm puting extra data on the url just to fulfill architectural constraints, is that right?
Finaly, the lesson position within it's module does mater, but this piece of data dont belong to the lesson nor to the module, that's why I created the list itself as the AR, maybe it wasn't the right decision?
Your model sounds very structural, e.g. a course consists of modules, modules consist of one or more lessons being taught as part of it, etc. It's not really solving a problem (or at least you've not described one). Could be booking a course, could be attending the lessons of a course, etc ... The other observation is that you seem to be describing what are essentially queries. You will find that most models have a conflict of interest when it comes to reading and writing, one of the main reasons CQRS came about in the first place (not suggesting you adopt that, merely pointing out the obvious). Writing happens to align with use cases and rules that must be upheld at all times (or else). Reading, on the other hand, seems to happen far more liberally, without much consideration for the past use cases that brought the queryable data about. One easy step could be to undo yourself of the shackles that say you can't return lessons by id - simply add whatever code you need to make that happen and don't feel compelled to put that in a box like a repository. Consistency is to be considered, but if the writing imposes the proper transactional boundaries, the reading won't inadvertently observe something it shouldn't. Secondary indexes can help too - they're the sort of thing that can help you find the module id based on the lesson id if you choose to continue to go down the current path.
If it is just about reading data (e.g. showing data to a user), you can always bypass the whole aggregate repository and use whatever whatever appropriate read queries you need. Only, if your use case needs to manipulate data go through the aggregate repository to retrieve a full aggregate in order to make sure transactional consistency inside this aggregate as well as business rules are applied when changing said aggregate.
Also, it should be considered that if you do you have valid use cases where you would directly change (not read) an entity inside an aggregate without the need of considering business logic that needs to be owned by the parent aggregate root, you might have missed to discover this entity being modeled as an aggregate on it's own. See also, https://stackoverflow.com/a/67250062/7730554
I learned DDD recently, we used to encapsulate the creation, update, deletion in to the repository to persist the changes to the DB.
With ORM tools, we can ignore the detail of the persistence, usually the argument of the repository is an aggregate root object, and the ORM execute the conversion of the persistence(for example, it will update one field if there just one change).
But if without ORM, there is just a field of the aggregate root object changed and save it to DB, how to design this for repository? support a method to save this field? There is a method called update to save all properties, but with it, it will cause performance issue.
To persist changes only you need to know what changed, obviously. There are two common ways to achieve this:
Track changes as they occur. This strategy is easier to implement when the entity explicitely participates to the change tracking mecanism. For instance, with Event Sourcing the Aggregate Root would record uncommitted change event(s) in a collection for all commands it processed.
Dirty checking: compare the new state to the old state. Note that the old state may be cached for performance optimizations.
Generally you need another Repository. How it is implemented is up to you.
You can write the code so it is able to save/update just single fields when they change.
If you want to update single fields as they change one way to do this is to use an Observer to "observe mutations" in your objects. This approach can have two "operation modes"
Ad-hoc: When a field gets updated persist just this field's value right away.
Aggregate update: Gather the information of all updated fields (just the fact that they were updated not the data). Then update them all at once when the time comes
This approach can have other performance implications in a large system. You have to see if it suits you or not.
Another option would be to have your ORM recognize the changed fields at the time of the update via a comparison. This again has its own performance implications since you will have to fetch the DB object (aggregate) once more and compare it against the runtime changes.
How you actually implement any of these heavily depends on the language you're using and its utilities. Performance issues also heavily depend on the language/runtime platform/3rd party software and lots of other things.
Let's say we have a class Order (related to user) and it has property state. I want to prevent having more than one confirmed order in the same time so before I confirm any order I have to check if there is already some confirmed in it's time period.
I can make 2 approaches (I know of):
OrderRepository has a function changeState which search for conflicting confirmed orders before changing it and allows it only when nothing is found - the problem here is repository knows about logic of changing state.
OrderRespository is injected into Order and Order has function changeState which will use that repository to check for conflicts - here problem is the domain object know about persistence.
What is a right way to do?
Repositories are not in charge of domain invariants. Aggregates are. If no Aggregate has the needed info inside itself to check the invariant, try to question your aggregate design and maybe come up with a new one.
You can use a Domain Service, alternatively. As a weaker option, you could also degrade the domain invariant down to a simple use case precondition and have it checked by the Application Service/Command Handler. Note that the latter 2 options don't provide as strong a guarantee that domain entities will be in a consistent state at all times regarding that rule.
Another way to think about this would be from the point of view of a repository's responsibility. At the end of the day, a Repository is an abstraction to represent how to deal with a collection of objects, in your case, Orders.
Hence, it makes sense to keep rules around consistency and right state for the collection to be represented at the repository layer. Injecting repositories into entities is probably a code smell that something is not being modelled correctly. I'd go for your first version, but maybe you don't need to be specific about your state change, but simply embed those rules into the save() method. You can save the changes to an order iif there's no other confirmed at the same time.
I have a couple questions regarding the relationship between references between two aggregate roots in a DDD model. Refer to the typical Customer/Order model diagrammed below.
First, should references between the actual object implementation of aggregates always be done through ID values and not object references? For example if I want details on the customer of an Order I would need to take the CustomerId and pass it to a ICustomerRepository to get a Customer rather then setting up the Order object to return a Customer directly correct? I'm confused because returning a Customer directly seems like it would make writing code against the model easier, and is not much harder to setup if I am using an ORM like NHibernate. Yet I'm fairly certain this would be violating the boundaries between aggregate roots/repositories.
Second, where and how should a cascade on delete relationship be enforced for two aggregate roots? For example say I want all the associated orders to be deleted when a customer is deleted. The ICustomerRepository.DeleteCustomer() method should not be referencing the IOrderRepostiory should it? That seems like that would be breaking the boundaries between the aggregates/repositories? Should I instead have a CustomerManagment service which handles deleting Customers and their associated Orders which would references both a IOrderRepository and ICustomerRepository? In that case how can I be sure that people know to use the Service and not the repository to delete Customers. Is that just down to educating them on how to use the model correctly?
First, should references between aggregates always be done through ID values and not actual object references?
Not really - though some would make that change for performance reasons.
For example if I want details on the customer of an Order I would need to take the CustomerId and pass it to a ICustomerRepository to get a Customer rather then setting up the Order object to return a Customer directly correct?
Generally, you'd model 1 side of the relationship (eg., Customer.Orders or Order.Customer) for traversal. The other can be fetched from the appropriate Repository (eg., CustomerRepository.GetCustomerFor(Order) or OrderRepository.GetOrdersFor(Customer)).
Wouldn't that mean that the OrderRepository would have to know something about how to create a Customer? Wouldn't that be beyond what OrderRepository should be responsible for...
The OrderRepository would know how to use an ICustomerRepository.FindById(int). You can inject the ICustomerRepository. Some may be uncomfortable with that, and choose to put it into a service layer - but I think that's overkill. There's no particular reason repositories can't know about and use each other.
I'm confused because returning a Customer directly seems like it would make writing code against the model easier, and is not much harder to setup if I am using an ORM like NHibernate. Yet I'm fairly certain this would be violating the boundaries between aggregate roots/repositories.
Aggregate roots are allowed to hold references to other aggregate roots. In fact, anything is allowed to hold a reference to an aggregate root. An aggregate root cannot hold a reference to a non-aggregate root entity that doesn't belong to it, though.
Eg., Customer cannot hold a reference to OrderLines - since OrderLines properly belongs as an entity on the Order aggregate root.
Second, where and how should a cascade on delete relationship be enforced for two aggregate roots?
If (and I stress if, because it's a peculiar requirement) that's actually a use case, it's an indication that Customer should be your sole aggregate root. In most real-world systems, however, we wouldn't actually delete a Customer that has associated Orders - we may deactivate them, move their Orders to a merged Customer, etc. - but not out and out delete the Orders.
That being said, while I don't think it's pure-DDD, most folks will allow some leniency in following a unit of work pattern where you delete the Orders and then the Customer (which would fail if Orders still existed). You could even have the CustomerRepository do the work, if you like (though I'd prefer to make it more explicit myself). It's also acceptable to allow the orphaned Orders to be cleaned up later (or not). The use case makes all the difference here.
Should I instead have a CustomerManagment service which handles deleting Customers and their associated Orders which would references both a IOrderRepository and ICustomerRepository? In that case how can I be sure that people know to use the Service and not the repository to delete Customers. Is that just down to educating them on how to use the model correctly?
I probably wouldn't go a service route for something so intimately tied to the repository. As for how to make sure a service is used...you just don't put a public Delete on the CustomerRepository. Or, you throw an error if deleting a Customer would leave orphaned Orders.
Another option would be to have a ValueObject describing the association between the Order and the Customer ARs, VO which will contain the CustomerId and additional information you might need - name,address etc (something like ClientInfo or CustomerData).
This has several advantages:
Your ARs are decoupled - and now can be partitioned, stored as event streams etc.
In the Order ARs you usually need to keep the information you had about the customer at the time of the order creation and not reflect on it any future changes made to the customer.
In almost all the cases the information in the value object will be enough to perform the read operations ( display customer info with the order ).
To handle the Deletion/deactivation of a Customer you have the freedom to chose any behavior you like. You can use DomainEvents and publish a CustomerDeleted event for which you can have a handler that moves the Orders to an archive, or deletes them or whatever you need. You can also perform more than one operation on that event.
If for whatever reason DomainEvents are not your choice you can have the Delete operation implemented as a service operation and not as a repository operation and use a UOW to perform the operations on both ARs.
I have seen a lot of problems like this when trying to do DDD and i think that the source of the problems is that developers/modelers have a tendency to think in DB terms. You ( we :) ) have a natural tendency to remove redundancy and normalize the domain model. Once you get over it and allow your model to evolve and implicate the domain expert(s) in it's evolution you will see that it's not that complicated and it's quite natural.
UPDATE: and a similar VO - OrderInfo can be placed inside the Customer AR if needed, with only the needed information - order total, order items count etc.
Which is a better approach, create child entities first, then pass to the aggregate root to add them, or have the aggregate root create them? For example:
Order.AddOrderLine(new OrderLine(product, quantity, ...));
Or
Order.AddOrderLine(product, quanity, ...);
Which is a better approach? I'm sure this is purely subjective, but I want to see which has more pros vs cons.
Ok, so basically my opinion is that you should create an object before, because:
creating of the object is itself a separate concern, which can be a fairly complex by the way. And if, for instance, constructor of the OrderLine will be changed later you will need to change an Order type too. This is bad, cos you will need to change the Order only because of some changes in the OrderLine. So interface of the Order Root shouldn't depend on the OrderLine.
the second approach may be hard to test if you method will contain some additional logic exept of only calling this.OrderLines.Add(orderLine);
Edit
After discussing this with a friend of mine, I came up with the following opinion:
Order Root should control lifetime of his child, because this will be more clear for other person who uses this API and will minimize the possibility of an inappropriate usage. And also will better reveal intent.
Using this approach also allows us not to worry about validating incoming OrderLine, because if we are responsible of the OrderLine creation then we can create it properly.