i've been assigned a quite simple project as an exam and i had the idea to develop it using the Domain Driven Design.
Many of you might say that the application is so simple that going with repositories and UoW is just a waste of time, and you probably be correct but i think of it as an opportunity to learn something more.
The application is a "Flight tickets" system and from the following image you could probably well guess it's functionality.
The thing is that i am not sure if i am correctly seperating the aggregates and their roots.
EDIT:
I presented the data model so anyone can spot the whole functionality easily.
The thing is that from an employe perspective the flight as "Rad" said encapsulates the whole functionality and is the aggregate root.
However from an admin perspective, flights are none his bussiness.
He just want to update or add new planes-companies, etc..
So then there is a new aggregate root which is the Airplane which encapsulates the Airplane seats(Entity), the seatType(value object) and the company(Entity) as a new aggregate.
This tends to confuses me as i have an aggregate root(Airplane) inside another aggregate(Flight Aggregate).
Since the aggregate root is consider to be the "CORE" entity which without it the other entities inside it will not make any sense without it, i am thinking about Company. And i conclude that company makes sense without the airplane.
To explain more i think of the scenario where the admin want to just insert a new Company, or want to first load a company and then its airplanes.
DDD principles say that any entities inside the aggregate may only be loaded from the root itself.
So here is the confusion.
Mmm, where is the Aggregate and Aggregate roots here ? This is only Data Model... Not Domain Model.
Aggregate is a cluster of items (Domain Object) that are gathered together, and Aggregate Root are the entity root... (If you consider the Flight Aggregate encapsulates Seats, Location... The Aggregate Root should be Flight entity).
[Edit]
You have to ignore the persistent. In your app you can have many aggregate it depends in your Domain, maybe Flight is an Aggregate and Company another one ;), don't confuse entity and Aggregate...
An aggregate is a group of entities (objects with identity) and maybe value objects (objects without identity, immutable). There is exactly one entity in an aggregate that is the aggregate root. You can easily identify it by checking if the other objects in the aggregate depend on it, for example, if you delete an object of the aggregate root type, the remaining objects don't make sense anymore (in database terms, you'd cascade delete the dependent objects).
The aggregate root is the sole object in the aggregate that gives access to the other types in the aggregate, hence you'll have one repository per aggregate and it returns instances of aggregate root type.
Related
If we are working on a sub-domain where we're only dealing with a read-only scenario, meaning that our entities and value objects will not be changed, does it make sense to create aggregates composed by roots and its children or should each entity of this context map to a single aggregate?
Imagine that we've entity A and entity B.
In a context where modifications are made, we create an aggregate composed by entity A and entity B, where A is the aggregate root (let's say that B can't live without A and there are some invariants involved).
If we move the same entities to a different context where no modifications are made, does it make sense to keep this aggregate or should we create an aggregate for entity A and a different one for entity B?
In 2019, there's fairly large support for the idea that in a read only scenario, you don't bother with the domain model at all.
Just load the data directly into whatever read only data structure makes sense to support the use case.
See also: cqrs.
The first thing is if B cant live without A and there are some invariants involved, to me A is an Aggregate root, with B being an entity that belongs to it.
Aggregate roots represent a real world concept and dont just exist for the convenience of modification. In many of our applications, we don't modify state of our aggregate roots once created - i.e. we in effect have immutable aggregate roots. These would have some logic for design by contract checks/invariant checks etc but they are in effect anaemic as there is no "Update" methods due to its immutability. Since the "blue book" was written by Eric Evans, alot of things have changed, e.g. the concept of NoSql database have become very popular, functional programming concepts have become very influential rising to more advanced DDD style architectures being recommended such as CQRS. So for example, rather than doing updates to a database I can append (i.e. insert) instead. This leads to aggregates no longer having to be "updated". This leads to leaner anaemic types but this is what we want in this context. The issue before with anaemic types was that "update logic" for a given type was put elsewhere in the codebase instead of being put into the type itself. However if you do not require "update logic" in the first place then you dont have that problem!
If for example there is an Order with many OrderItems, we would create an Order aggregate root and an OrderItem entity. Its a very important concept to distill your domain to properly identify what are aggregates, entities and value types.
Then creation of domain services, repositories etc just flows naturally. For example, aggregate roots and repositories are 1 to 1 i.e. in the example above we would have an Order repository and not have an OrderItem repository. That way your main domain concepts are spread throughout your code in a predictable and easy to understand way.
Finally, in your specific question I would not treat them as the same entities. In one context, you seem to need modification logic - in the other they you dont - they are separate domain concepts to me.
In context where modifications are made: A=agg root, B=entity.
In context without modifications: A=agg root (immutable), B=entity(immutable)
Sometimes I come to this case when I have a bunch of entity domain models which should be transactionally persisted but there is no logical domain model which could become an aggregate root of all these entity domain models.
Is it a good idea in these cases to have a fictitious aggregate root domain model which will have NO analogical database entity and will not be persisted in the database but will store in itself only logic for transactionally persisting entity domain models ?
P.S. I tought about that because having a database table storing only a single column of aggregate root ids seems wrong to me.
Is it a good idea in these cases to have a fictitious aggregate root domain model which will have NO analogical database entity and will not be persisted in the database but will store in itself only logic for transactionally persisting entity domain models ?
Sort of.
It's perfectly fine to have a PurpleMonkeyDishwasher that joins together composes together the entities that make up your aggregate, so that you can be sure that your data remains consistent and satisfies your domain invariant.
But it's really suspicious that it doesn't have a name. That suggests that you don't really understand the problem that you are modeling.
It's the modeling equivalent of a code smell. There's probably a theme that arranges these entities to be modeled together, exclusive of the others, rather than in some other arrangement. There's probably a noun that your domain experts use when talking about these entities together. Go find it. That's part of the job.
An "aggregate root domain model which will have NO analogical database entity and will not be persisted in the database" is not a "fictitious aggregate"; it is a standard aggregate just like another aggregate that it needs to be persisted. The purpose of an aggregate is to control the changes following domain rules to ensure consistency and invariants.
Sometimes the aggregate is the change (and need to be persisted) but sometimes it is not and the things to be persisted after the change are parts/full entities and/or VOs that changed inside the aggregate and are mapped in persistence at its own without the needed of composing a persistence concept (table/s, document, etc). This is a implementation detail about how you decided to persist your domain data.
First premise of DDD: There is no DataBase. This helps you to not think too biased about trying to mapping persistence concepts in your domain.
Mike in his blog explain it better than me.
The purpose of our aggregate is to control change, not be the change.
Yes, we have data there organized as Value Objects or Entity
references but that’s because it’s the easiest and most maintainable
way to enforce the business rules. We’re not interested in the state
itself, we’re interested in ensuring that the intended changes respect
the rules and for that we’re ‘borrowing’ the domain mindset i.e we
look at things as if WE were part of the business.
An aggregate instance communicates that everything is ok for a
specific business state change to happen. And, yes, we need to persist
the busines state changes. But that doesn’t mean the aggregate itself
needs to be persisted (a possible implementation detail). Remember
that the aggregate is just a construct to organize business rules,
it’s not a meant to be a representation of state.
So, if the aggregate is not the change itself, what is it? The change
is expressed as one or more relevant Domain Events that are generated
by the aggregate. And those need to be recorded (persisted) and
applied (interpreted). When we apply an event we “process” the
business implications of it. This means some value has changed or a
business scenario can be triggered.
I have seen lot of discussions regarding this topic but i couldn't get a convincing answer. The general advice is not to have repository inside a domain object. What about an aggregate root? Isnt it right to give the root the responsibility to manipulate the composed objects?
For example, i have a microservice which takes care of invoices. Invoice is an aggregate root which has the different products. There is no requirement for this service to give details about individual products. I have 2 tables, one to store invoice details and other to store products of those invoices. I have two repositories corresponding to the tables. I have injected product repository inside the invoice domain object. Is it wrong to do so?
I see some mistakes according to DDD principles in your question. Let me try to clarify some concepts to give you hand.
First, you mentioned you have an Aggregate Root which is Invoice, and then two different repositories. Having an Aggregate Root means that any change on the Entities that the Aggregate consists of should be performed via the Aggregate Root. Why? That's because you need to satisfy some business rule (invariant) that applies on the relation of those Entities. For instance, given the next business rule:
Winning auction bids must always be placed before the auction ends. If a winning bid is placed after an auction ends, the domain is in an invalid state because an invariant has been broken and the model has failed to correctly apply domain rules.
Here there is an aggregate consisting of Auction and Bids where the Auction is the Aggregate Root.
If you have a BidsRepository, you could easily do:
var newBid = new Bid(money);
BidsRepository->save(newBid);
And you were saving a Bid without passing the defined business rule. However, having the repository just for the Aggregate Root you are enforcing your design because you need to do something like:
var newBid = new Bid(money);
auction.placeBid(newBid);
auctionRepository.save(auction);
Therefore, you can check your invariant within the method placeBid and nobody can skip it if they want to place a new Bid. Afterwards you can save the info into as many tables as you want, that is an implementation detail.
Second, you said if it's wrong injecting the repository into a Domain class. Here a quick explanation:
The repository should depend on the object it returns, not the other way around. The reason for this is that your "domain object" (more on that later) can exist (and should be testable) without being loaded or saved (that is, having a dependency on a repository).
Basically your design says that in order to have an invoice, you need to provide a MySQL/Mongo/XXX instance connection which is an infrastructure detail. Your domain should not know anything about how it is persisted. Your domain knows about the behavior like in the scenario of the Auction and Bids.
These concepts just help you to create code easier to maintain as well as help you to apply best practices such as SRP (Single Responsibility Principle).
Yes, I think it is wrong.
Domain should match real business model and should not care how data is persisted. Even if data internally are stored in multiple tables, this should not affect domain objects in any way.
When you are loading aggregate root, you should load related entities as well in one go. For example, this can easily be achieved with Include keyword in Entity Framework if you are on .NET. By loading all the data you ensure that you have full representation of business entity at any given time and you don't have to query database anymore.
Any changes in related entities should be persisted together with aggregate root in one atomic operation (usually using transactions).
Ive heard a lots that aggregate roots depend on the use case. But what does that mean in coding context ?
You have a service class which offcourse hold methods (use cases) that gonna accomplish something in a repository. Great, so you use a repository which is equal to an aggregate root to perform your querying.
Now you need to perform some other kind of operation which use totally different use case than the first service class but use the same entities.
Here the representation :
Entities: Customer, Orders, LineOrder
Service 1: Add new customers, Delete some customers, retrieve customer orders
Here the aggregate root seem to be Customer because you need this repository to perform thoses use cases.
Service 2: Retrieve customer from an actual order
Here the aggregate root seem to be Order because you need this repository to perform this use case.
If i am wrong please correct me. Now that mean you have 2 aggregates roots.
Now my question is, since aggregate roots depend on the use case does that mean that we might end up with really a lots of repositories if you end up having lots of use cases ?
The above example was probably not the best example... so lets say we have a Journal which hold JournalEntries which each entries hold Tasks, Problems and Notes. (This is in the context of telling to a system what have been done to a project)
Does that mean that im gonna end up with 2 repository ? (Journal, JournalEntry)
In the use cases where i need to add new tasks, problems and notes from an journal entry ?
(Can be seen as a service)
Or might end up with 4 repository. (Journal, Task, Problems, Notes)
In the use cases where i need to access directment task, problems and notes ?
(Can be seen as another service)
But that would mean if i need both of theses services (that actually hold the use cases) that i actually need 5 repository to be able to perform use cases in both of them ?
Thanks.
Hi I saw your post and thought I may give you my opion. First I must say I've been doing DDD in project for three years now, so I'm not an expert. But I'm currently working in a project as an architect an coaching developers in DDD, and I must say it isn't a walk in the park... I don't know how many times I've refactored the model and Entity relationships.
But my experience is that you endup with some repositories (more than few but not many). My Aggregates usually contains a few classes and the Aggregate object graph isn't that deep (if you know what I mean).
But I try to be concrete:
1) Aggregate roots are defined by your needs. I mean if you feel that you need that Tasks object through Journal to often, then maybe thats a sign for it to be upgraded as a aggregate root.
2) But everything cannot be aggregate roots, so try to capsulate object that are tight related. Notes seems like a candidate for being own by a root object. You'd probably always relate Notes to the root or it loses its context. Notes cannot live by itself.
3) Remember that Aggregates are used for splitting up large complex domains into smaller "islands" that take care of thier inhabbitants. Its important to not make your domain more complex than it is.
4) You don't know how your model look likes before you've reached far into the project implementation phase. If you realize that some repositories aren't used that much, they may be candidates for merging into other root object (if they have that kind of relationship). You can break out objects that are used so much through root object without its context. I mean for example if Journal are aggregate root and contains Notes and Tasks. After a while you model grows and maybe Tasks
have assoications to Action and ActionHistory and User and Rule and Permission. Now I just throw out a bunch om common objects in a rule/action/user permission functionality. Maybe this result in usecases that approach Tasks from another angle, "View all Tasks performed by this User" etc. Tasks get more involved in some kind of State/Workflow engine and therefor candidates for being an aggregate root itself.
Okey. Not the best example but it maybe gives you the idea. A root object can contain children where some of its children can also be root object because we need it in another context (than journal).
But I have myself banged my head against the wall everytime you startup with a fresh model. Just go with the flow and let the model evolve itself through its clients/subsribers. You refine the model through its usage. The Services (application services and not domain services) are of course extended with methods that respond to UI and usecases (often one-to-one).
I hope I helped you in someway...or not :D
Yes, you would most likely end up with 5 repositories (Journal, JournalEntry, Task, Problems, Notes). Your services would then use these repositories to perform CRUD for each type of entity.
Your reaction of "wow so many repositories" is not uncommon for developers new to DDD.
However, your repositories are usually light weight assuming your model and DB schema are fairly evenly matched which is often the case. If you use an ORM such as nHibernate or a tool such as codesmith generator then it gets even easier to create your repositories.
At first you need to define what is aggregate. I don't know about use case aggregates.
I know about aggregates following...
Aggregates are union of several entities. One of the entities is the aggregate root, the rest entities (or value types) have sense only in selected aggregate root context. For example you can define Order and OrderLine as an aggregate if you don't need to do any independent actions with OrderLine entities. It means that OrderLine makes sense in Order context only.
Why to define aggregates at all? It is required to reduce references between objects. That will simplify you domain model.
And of course you don't need to have OrderLineRepository if OrderLine is a part of Order aggregate.
Here is a link with more information. You can read Eric Evans DDD book. He explains aggregates very well.
I have Category and Product entities. The relationship between the two is one to many. Since, Category is aggregate root I think I should only make a single repository ICategoryRepository which should also handle products.
Ideas?
I'm without my copy of Domain Driven Design by Evans at the moment, which is where I'd turn for the definitive answer, but this reference at dddstepbystep states that:
Within an Aggregate there is an
Aggregate Root. The Aggregate Root is
the parent Entity to all other
Entities and Value Objects within the
Aggregate.
A Repository operates upon an
Aggregate Root
So yes, going by this definition, your Category Repository should be responsibly for persisting all entities within the Category aggregate.
That said though, my question from my comment still stands - are you sure that Category really is a useful aggregate root? The fact that you are asking this question about persisting products indicates that you often consider them seperate from their Category, or at least would like to be able to deal with some product aside from their category.