DDD Topic - Lesson association AggregateRoot - domain-driven-design

I'm new in DDD. I have a Topic entity and Lesson entity. Topic has many Lessons.
I need to add/remove Topics as well as Lessons. Should i create two different repositories for entities,
or just one TopicRepository which handles all the lessons? Is this a classic Order - OrderItem model?
Thanks

If both entites makes sense without eachother, then go for the two different repositories.
If you delete a topic, should you then delete all lessons associated with this topic?
If, yes .. then You got yourself a TopicRepository handling both topics and lessons.
If no, you have two repositories.

Do Lessons make any sense without Topics? if not, then yes, this is very much like Order - OrderItem.

Related

How to delete multiple aggregates in DDD?

I know in DDD that deleting the Aggregate Root must remove everything within the Aggregate boundary all at once.
But in the Agile example that vaughn vernon gave it here https://vaughnvernon.co/?p=838 the BackLogItem and Product Aggregates are exist in separate Aggregates and the BackLogItem Aggregate Root is referencing Product Aggregate Root by Id.So, If I want to delete the Product Aggregate Root wouldn't mean that I should delete its BackLogItems?
So, my question how to delete multiple Aggregates in DDD and if so would be that possible using Domain Services , Domain Event or whatever?
P.S
Depending on vaughn vernon that we should not modify more than one
aggregate in the same transaction(in some cases we are forced to use
eventual consistency).
The usual mechanism for behavior distributed across multiple aggregates is to use a process manager.
I recommend starting from Rinat's writeup, because it really does get to the core of the matter; a process manager is just a stand in for a human being that reacts to events by sending commands to other aggregates.
Oh look, the Product was removed
I should load a list of the BackLogItems that reference that Product
And remove each of them in turn
If your modeling of the back log items as belonging to a distinct aggregate from the product is correct, then it follows that the changes to the back log items can be separated in time from the changes to the product.
Also, see Udi Dahan: Don't Delete -- Just Don't.
Use Saga Pattern. It executes a scenario in the transaction and imitates clients work. Saga sends multiple commands just as client does.
I would argue that your problem is not only how to delete multiple aggregates, but also which aggregates you should delete. In your question, you mention that when you delete the Product Aggregate you should delete its Backlog Items, but is that all? What about the Kanban Board and its custom columns and workflow, and N other features associated with that Product Aggregate?
The point of having the BacklogItems knowing about the Product, but not the other way around is to avoid having a God object, which knows about everything because dozens of features can be attached to the Product Aggregate over time.
When deleting the Product Aggregate, there's not a single place that knows everything that needs to be deleted, but everything that needs to be deleted will know. Therefore, leave the responsibility to delete (or something else) to every other aggregate: From the ProductAggregate, publish a ProductDeletedEvent and subscribe to it from all the other aggregates that care about it.

Do we need another repo for each entity?

For example take an order entity. It's obvious that order lines don't exist without order. So we have to get them with the help of OrderRepository(throw an order entity). Ok. But what about other things that are loosely coupled with order? Should the customer info be available only from CustomerRepo and bank requisites of the seller available from BankRequisitesRepo, etc.? If it is correct, we should pass all these repositories to our Create Factory method I think.
Yes. In general, each major entity (aggregate root in domain driven design terminology) should have their own repositories. Child entities *like order lines) will generally not need one.
And yes. Define each repository as a service then inject them where needed.
You can even design things such that there is no direct coupling between Order and Customer in terms of an actual database link. This in turn allows customers and orders to live in completely independent databases. Which may or may not be useful for your applications.
You correctly understood that aggregate roots's (AR) child entities shall not have their own repository, unless they are themselves AR's. Having repositories for non-ARs would leave your invariants unprotected.
However you must also understand that entities should usually not be clustered together for convenience or just because the business states that some entity has one or many some other entity.
I strongly recommend that you read Effective Aggregate Design by Vaughn Vernon and this other blog post that Vaughn kindly wrote for a question I asked.
One of the aggregate design rule of thumb stated in Effective Aggregate Design is that you should usually reference other aggregates by identity only.
Therefore, you greatly reduce the number of AR instances needed in other AR's creationnal process since new Order(customer, ...) could become new Order(customerId, ...).
If you still find the need to query other AR's in one AR's creationnal process, then there's nothing wrong in injecting repositories as dependencies, but you should not depend on more than you need (e.g. let the client resolve the real dependencies and pass them directly rather than passing in a strategy allowing to resolve a dependency).

DDD, Aggregates and Repos

I have the following entities (example):
Book
Author
The Book entity is also an aggregate since it has related one or many Authors. Now I have a problem in how to fetch this aggregate from the repo. I have the following cases - and I also do need to take care of performance:
List all the Books. No need to fetch Authors.
List all the Bookss with Authors names. Obviously, we need to fetch the aggregate of Books and related Authors.
List all the Books with authors count. Similar to (2), except I do not want to fetch the Authors from the repo, just the count.
So how my repository should look like? Specific questions:
Should we have method like findBooks and findBooksWithAuthors and findBooksWithAuthorsCount? But this would lead to crazy amount of methods, since our entities have many relationships between each other.
Should we just have findBooks and then loadAuthors in AuthorsRepo, i.e. not doing the join, until we hit some performance issue, and then to refactor.
Should I create some aggregate-value-objects, like: BookAndAuthors that describes relationships?
Please note that this example is trivial - and you have to know that our models are more rich and have more relationships.
Do you need to fetch this kind of information to display on the UI ?,
I would encourage you to separate your read and write concerns, and keep your repository interface simple (similar to that of a collections interface).
Have a look at CQRS, it works very well with DDD and will help simplify your design to a great deal.
Once you get into CQRS, just keep in mind that CQRS does not necessarily involve Event Sourcing.
In your case I would recommend the simplest approach show in this article, basically have a read service (can call it Finder), which fires SQL and gets you a DTO/Map of whatever you need for the UI.

DDD: Do all aggregate roots require children?

Everything I have read thus far on DDD implies only entities which encapsulate other entities are root aggregates.
What about in situations like:
WorkOrder
- idManufacturer
- WONumber
- Description
Manufacturer
- idSelf
- Name
WorkOrder references Manufacturer but would not be a child of WorkOrder as other entities might reference WorkOrder, in this case I would consider both Root entities, but the Manufacturer is not an aggregate...
Is this correct?
I once had a lightbulb moment with DDD when someone told me that entities with no children can be though of as aggregate roots.
Particularly when someone says "persist only your aggregate roots".
In your example, your aggregate roots are WorkOrder and Manufacturer. You'd have a repository for WorkOrder and one for Manufacturer.
In fact, you will mostly have aggregates with value objects only. ARs with child entites are rare. Read red book (Implementing DDD Vaughn Vernon), there is described rule of small aggregates.
The job of an aggregate root is to encapsulate and enforce invariants. It may consist of other objects but they are all interacted with through the AR. The important thing to remember about an aggregate, is that is should be independent of your chosen persistence mechanism. The majority of your aggregates should have no dependencies at all!
I may be mistaken but it looks like the idManufacturer is a foreign key. This would suggest (not always the case) it is not encapsulated. The thing that took me a while to get my head around was that the fields within an aggregate are private. This raises the question of how you save it's state and how you get data to put on the UI. There are lots of ways to that. My preferred approach is to use Event Sourcing and CQRS. I can then build out UI's from the events that my aggregates produce. I can also persist those events and use them to rebuild my aggregate.
I've gone into a lot more depth on my blog, you may want to take a look at How to Build an Aggregate Root! . You may also find helpful a post on building a master details screen when using CQRS and Event sourcing, that can be found here!
I hope that helps.

How do you handle associations between aggregates in DDD?

I'm still wrapping my head around DDD, and one of the stumbling blocks I've encountered is in how to handle associations between separate aggregates. Say I've got one aggregate encapsulating Customers and another encapsulating Shipments.
For business reasons Shipments are their own aggregates, and yet they need to be explicitly tied to Customers. Should my Customer domain entity have a list of Shipments? If so, how do I populate this list at the repository level - given I'll have a CustomerRepository and a ShipmentRepository (one repo per aggregate)?
I'm saying 'association' rather than 'relationship' because I want to stress that this is a domain decision, not an infrastructure one - I'm designing the system from the model first.
Edit: I know I don't need to model tables directly to objects - that's the reason I'm designing the model first. At this point I don't care about the database at all - just the associations between these two aggregates.
There's no reason your ShipmentRepository can't aggregate customer data into your shipment models. Repositories do not have to have a 1-to-1 mapping with tables.
I have several repositories which combine multiple tables into a single domain model.
I think there's two levels of answering this question. At one level, the question is how do I populate the relationship between customer and shipment. I really like the "fill" semantics where your shipment repository can have a fillOrders( List customers, ....).
The other level is "how do I handle the denormalized domain models that are a part of DDD". And "Customer" is probably the best example of them all, because it simply shows up in such a lot of different contexts; almost all your processes have customer in them and the context of the customer is usually extremely varied. At max half the time you are interested in the "orders". If my understanding of the domain was perfect when starting, I'd never make a customer domain concept. But it's not, so I always end up making the Customer object. I still remember the project where I after 3 years felt that I was able to make the proper "Customer" domain model. I would be looking for the alternate and more detailed concepts that also represent the customer; PotentialCustomer, OrderingCustomer, CustomerWithOrders and probably a few others; sorry the names aren't better. I'll need some more time for that ;)
Shipment has relation many-to-one relationship with Customer.
If your are looking for the shipments of a client, add a query to your shipment repository that takes a client parameter.
In general, I don't create one-to-mane associations between entities when the many side is not limited.

Resources