DDD: University as an aggregate root - domain-driven-design

For some time I am dealing with Domain-Driven Design. Unfortunately I have some problems regarding the Aggregate.
Say, I like to model the structure of an university. The university has some departments (faculties) and every department has some classes. There is a rule that every department needs to be unique and so every class in it. For instance the names of the classes needs to be unique. If I understand it right, then "University" seems to be my aggregate root and "department" and "class" are entities within this aggregate.
There is another aggregate root "Professor", because they are globally accessible. They will be assigned to a class. I´m unsure if it is allowed because an aggregate root should only point to another aggregate root and not to its content.
How to handle this?
Appreciate your help,
thanks in advance!

Say, I like to model the structure of an university. The university has some departments (faculties) and every department has some classes. There is a rule that every department needs to be unique and so every class in it. For instance the names of the classes needs to be unique.
Really? why? What's the business value of that rule? What does it cost the business (the university) if there happen to be two classes with the same name. Does that mean the same name across all time, or just during a given semester?
Part of the point of DDD is that the design of the solution requires exploration of the "ubiquitous language" to get a full understanding of the requirement.
In other words, you may be having trouble finding a good fit for this requirement in the design because you haven't yet discovered all of the entities that you need to make it work the way the business experts expect.
Udi Dahan points out that the uniqueness rule may not belong in the domain at all:
Rules that are not part of genuine domain logic do not have to be implemented in the domain model, suggested he, because they do not model the domain.
So if you have a constraint like this, but the constraint isn't a consequence of the domain itself, then the constraint can be correctly implemented elsewhere.
Greg Young has also written about set validation, specifically addressing concerns about eventual consistency.
But broadly, yes -- if you really have a collection of entities, and a domain rules that span multiple elements in the collection, then you need some aggregate that maintains the integrity of the boundary that the collection lives in.
The entities aren't necessarily what you think. For instance, if you need names to be unique, and the rest of the class entity is just along for the ride, then you may be able to simplify the rules by creating a name registry aggregate; Professors reserve names for their classes, and if the reservation is available, then the reserved name can be applied to the class entity.
If your core business really were naming things, with lots of special invariants to consider, you might build out a big model around this. But that's not particularly likely; perhaps you can just slap a table or two into a relational database -- that's a good solution for a set validation problem -- and get on with the valuable part of the project.
There is another aggregate root "Professor", because they are globally accessible. They will be assigned to a class. I´m unsure if it is allowed because an aggregate root should only point to another aggregate root and not to its content.
class.assign(professorId);
is the usual sort of answer here -- you pass around the surrogate key that identifies the aggregate root. Every entity in your domain should have one.
A couple of cautions here: I have found that real world entities (people, in particular) aren't a useful starting point for figuring out what aggregates are for. Primarily, because they end up being representations, primarily, of data where the invariant is enforced outside the domain model.
Also, I've found that starting from the nouns - class, department, professor - tends to put the focus on CRUD, which generally isn't a very interesting problem.
Instead, I recommend thinking about doing something useful -- a use case where there are business rules to enforce, when the business model gets to say "no, the business won't let you do that right now".

Ask yourself these questions:
How many universities will be in your system? If this is only one, it is not your aggregate root.
If you have multiple universities in your system, would be someone working across universities? May be universities are your system tenants?
What happens with a class if some department is dissolved? Will it immediately disappear? I doubt it.
The same as above with university to department relationship
It is not a problem with a Department to hold reference to its classes as a list of value objects that will contain the Class aggregate root id and the class name. The same is valid for departments dealing with their classes.
Vernon's Effective Aggregate Design might help too.

I'm not very experienced in DDD either but here some tips I use to use:
Is it possible to have a Class without a Department assigned? If that is the case then the Department is the aggregate root and Class is another aggregate with a reference to the root, the Department. You can even define a factory method "addClass()" within your Department with the info that a Class needs to be created, so nobody should be allowed to create a Class without a Department.
Why defining a Class a an Aggregate instead of a Value Object? Because Value Objects are distinguished by their properties' value rather than an ID. I would say that even having two Classes with the same name, same students, same info, etc, etc. the business would still want to differentiate each one. It is not the same with a 1 cent coin which with you only care about the value (given by the color, size, weight,...) but you can always replace it with another one with same attributes' value, that is 1 cent. Also assigning another Professor to the class, the class remains the same, it is not immutable as a Value Object should be.
I guess a Professor must be uniquely identified, and he can maybe be assigned to different Classes or even Departments. So to me it is another Aggregate root separated from the department.

Related

DDD: Domain Objects Structure

I'm new to DDD and I want to clearly understand each domain object structure and role:
Aggregate Root:
1.1. The only contact point the client can interact with the domain objects, the client should not be able to modify or create new Entities or value objects whiteout the aggregate root? (Yes/No)
1.2. Can an aggregate root contain only value objects ? for example User root, it contain only address, phone, things which are value objects as far as I understand. So is it a sign of bad design when your aggregate root contain only value objects? shall it contain only entities and via entities interact with value objects?
Entities: Shall the entities contain only value objects? or it can also contain other entities? can you give me a simple example please ?
Value Objects: shall I go ahead and encapsulate every primitive type in an value object? I can go deep and make every primitive type as an value object, for example: PhoneNumber can be a string or an value object which contains country code, number. the same thing can be applied to all other primitive type value such as name, email. So where to draw the line ? where to say "Ok I'm going to deep", or going deep is the right way of doing DDD?
Factories: Do I really need them? I can go ahead and write an static method within the domain object which knows more precisely how to construct it, am I doing wrong ?
Sorry for the long questions, but I'm feeling little lost despite of continues reading, if you can help me I would be glad.
I'll try to answer all your questions:
1.1. The only contact point the client can interact with the domain objects, the client should not be able to modify or create new Entities or value objects whiteout the aggregate root? (Yes/No)
Entities live within ARs and allowing the client to create them would violate encapsulation, so for entities you are correct, ARs create their own entities which don't get exposed to the outside (copies/immutable views could be).
On the other hand, value objects are generally immutable and therefore there's no harm in having them supplied to the AR as data inputs.
In general all modifications needs to go through the AR so that the AR is aware of the modification. In special situations the AR could detect modifications within it's cluster by listening to events raised by internal entities when it's impractical to go through the root.
1.2. Can an aggregate root contain only value objects ? for example User root, it contain only address, phone, things which are value objects as far as I understand. So is it a sign of bad design when your aggregate root contain only value objects? shall it contain only entities and via entities interact with value objects?
Favor value objects as much as you can. It's not unusual for all parts of an AR being modeled as values. However, there's no limitation or law stating whether or not an AR should have only values or entities, use the composition that's fit to your use case.
Entities: Shall the entities contain only value objects? or it can also contain other entities? can you give me a simple example please ?
Same answer as above, no limitation nor law.
Value Objects: shall I go ahead and encapsulate every primitive type in an value object? I can go deep and make every primitive type as an value object, for example: PhoneNumber can be a string or an value object which contains country code, number. the same thing can be applied to all other primitive type value such as name, email. So where to draw the line ? where to say "Ok I'm going to deep", or going deep is the right way of doing DDD?
Primitive obsession is worst than value object obsession in my experience. The cost of wrapping a value is quite low in general, so when in doubt I'd model an explicit type. This could save you a lot of refactoring down the road.
Factories: Do I really need them? I can go ahead and write an static method within the domain object which knows more precisely how to construct it, am I doing wrong ?
Static factory methods on ARs are quite common as a mean to be more expressive and follow the UL more closely. For instance, I just modeled as use case today where we had to "start a group audit". Implemented a GroupAudit.start static factory method.
Factory methods on ARs for other ARs are also quite common, such as var post = forum.post(author, content) for instance, where Post is a seperate AR than Forum.
When the process requires some complex collaborators then you may consider a standalone factory though since you may not want clients to know how to provide and setup those collaborators.
I'm new to DDD and I want to clearly understand each domain object structure and role
Your best starting point is "the blue book" (Evans, 2003).
For this question, the two important chapters to review are chapter 5 ("A model expressed in software") and chapter 6 ("the life cycle of a domain object").
ENTITIES and VALUE OBJECTS are two patterns described in chapter 5, which is to say that they are patterns that commonly arise when we are modeling a domain. The TL;DR version: ENTITIES are used to represent relationships in the domain that change over time. VALUE OBJECTS are domain specific data structures.
AGGREGATES and FACTORIES are patterns described in chapter 6, which is to say that they are patterns that commonly arise when we are trying to manage the life cycle of the domain object. It's common that modifications to domain entities may be distributed across multiple sessions, so we need to think about how we store information in the past and reload that information in the future.
The only contact point the client can interact with the domain objects, the client should not be able to modify or create new Entities or value objects whiteout the aggregate root?
Gray area. "Creation patterns are weird." The theory is that you always copy information into the domain model via an aggregate root. But when the aggregate root you need doesn't exist yet, then what? There are a number of different patterns that people use here to create the new root entity from nothing.
That said - we don't expect the application to be directly coupled to the internal design of the aggregate. This is standard "best practice" OO, with the application code coupled to the model's interface without being coupled to the model's implementation/data structure.
Can an aggregate root contain only value objects ?
The definition of the root entity in the aggregate may include references to other entities in the same aggregate. Evans explicitly refers to "entities other than the root"; in order to share information with an entity other than the root, there must be some way to traverse references from the root to these non-root entities.
Shall the entities contain only value objects?
The definition of an entity may include references to other entities (including the root entity) in the same aggregate.
shall I go ahead and encapsulate every primitive type in an value object?
"It depends" - in a language like java, value objects are an affordance that make it easy for the compiler to give you early feed back about certain kinds of mistakes.
This is especially true if you have validation concerns. We'd like to validate (or parse) information once, rather than repeating the same check every where (duplication), and having validated vs unvalidated data be detectably different reduces the risk that unvalidated data leaks into code paths where it is not handled correctly.
Having a value object also reduces the number of places that need to change if you decide the underlying data structure needs improvement, and the value object gives you an easily guessed place to put functions/methods relating to that value.
Factories: Do I really need them?
Yes, and...
I can go ahead and write an static method within the domain object
... that's fine. Basic idea: if creating a domain object from so sufficient set of information is complicated, we want that complexity in one place, which can be invoked where we need it. That doesn't necessarily mean we need a NOUN. A function is fine.
And, of course, if your domain objects are not complicated, then "just" use the objects constructor/initializer.

What is an Aggregate Root?

No, it is not a duplication question.
I have red many sources on the subject, but still I feel like I don't fully understand it.
This is the information I have so far (from multiple sources, be it articles, videos, etc...) about what is an Aggregate and Aggregate Root:
Aggregate is a collection of multiple Value Objects\Entity references and rules.
An Aggregate is always a command model (meant to change business state).
An Aggregate represents a single unit of (database - because essentialy the changes will be persisted) work, meaning it has to be consistent.
The Aggregate Root is the interface to the external world.
An Aggregate Root must have a globally unique identifier within the system
DDD suggests to have a Repository per Aggregate Root
A simple object from an aggregate can't be changed without its AR(Aggregate Root) knowing it
So with all that in mind, lets get to the part where I get confused:
in this site it says
The Aggregate Root is the interface to the external world. All interaction with an Aggregate is via the Aggregate Root. As such, an Aggregate Root MUST have a globally unique identifier within the system. Other Entites that are present in the Aggregate but are not Aggregate Roots require only a locally unique identifier, that is, an Id that is unique within the Aggregate.
But then, in this example I can see that an Aggregate Root is implemented by a static class called Transfer that acts as an Aggregate and a static function inside called TransferedRegistered that acts as an AR.
So the questions are:
How can it be that the function is an AR, if there must be a globaly unique identifier to it, and there isn't, reason being that its a function. what does have a globaly unique identifier is the Domain Event that this function produces.
Following question - How does an Aggregate Root looks like in code? is it the event? is it the entity that is returned? is it the function of the Aggregate class itself?
In the case that the Domain Event that the function returns is the AR (As stated that it has to have that globaly unique identifier), then how can we interact with this Aggregate? the first article clearly stated that all interaction with an Aggregate is by the AR, if the AR is an event, then we can do nothing but react on it.
Is it right to say that the aggregate has two main jobs:
Apply the needed changes based on the input it received and rules it knows
Return the needed data to be persisted from AR and/or need to be raised in a Domain Event from the AR
Please correct me on any of the bullet points in the beginning if some/all of them are wrong is some way or another and feel free to add more of them if I have missed any!
Thanks for clarifying things out!
I feel like I don't fully understand it.
That's not your fault. The literature sucks.
As best I can tell, the core ideas of implementing solutions using domain driven design came out of the world of Java circa 2003. So the patterns described by Evans in chapters 5 and six of the blue book were understood to be object oriented (in the Java sense) domain modeling done right.
Chapter 6, which discusses the aggregate pattern, is specifically about life cycle management; how do you create new entities in the domain model, how does the application find the right entity to interact with, and so on.
And so we have Factories, that allow you to create instances of domain entities, and Repositories, that provide an abstraction for retrieving a reference to a domain entity.
But there's a third riddle, which is this: what happens when you have some rule in your domain that requires synchronization between two entities in the domain? If you allow applications to talk to the entities in an uncoordinated fashion, then you may end up with inconsistencies in the data.
So the aggregate pattern is an answer to that; we organize the coordinated entities into graphs. With respect to change (and storage), the graph of entities becomes a single unit that the application is allowed to interact with.
The notion of the aggregate root is that the interface between the application and the graph should be one of the members of the graph. So the application shares information with the root entity, and then the root entity shares that information with the other members of the aggregate.
The aggregate root, being the entry point into the aggregate, plays the role of a coarse grained lock, ensuring that all of the changes to the aggregate members happen together.
It's not entirely wrong to think of this as a form of encapsulation -- to the application, the aggregate looks like a single entity (the root), with the rest of the complexity of the aggregate being hidden from view.
Now, over the past 15 years, there's been some semantic drift; people trying to adapt the pattern in ways that it better fits their problems, or better fits their preferred designs. So you have to exercise some care in designing how to translate the labels that they are using.
In simple terms an aggregate root (AR) is an entity that has a life-cycle of its own. To me this is the most important point. One AR cannot contain another AR but can reference it by Id or some value object (VO) containing at least the Id of the referenced AR. I tend to prefer to have an AR contain only other VOs instead of entities (YMMV). To this end the AR is responsible for consistency and variants w.r.t. the AR. Each VO can have its own invariants such as an EMailAddress requiring a valid e-mail format. Even if one were to call contained classes entities I will call that semantics since one could get the same thing done with a VO. A repository is responsible for AR persistence.
The example implementation you linked to is not something I would do or recommend. I followed some of the comments and I too, as one commenter alluded to, would rather use a domain service to perform something like a Transfer between two accounts. The registration of the transfer is not something that may necessarily be permitted and, as such, the domain service would be required to ensure the validity of the transfer. In fact, the registration of a transfer request would probably be a Journal in an accounting sense as that is my experience. Once the journal is approved it may attempt the actual transfer.
At some point in my DDD journey I thought that there has to be something wrong since it shouldn't be so difficult to understand aggregates. There are many opinions and interpretations w.r.t. to DDD and aggregates which is why it can get confusing. The other aspect is, in IMHO, that there is a fair amount of design involved that requires some creativity and which is based on an understanding of the domain itself. Creativity cannot be taught and design falls into the realm of tacit knowledge. The popular example of tacit knowledge is learning to ride a bike. Now, we can read all we want about how to ride a bike and it may or may not help much. Once we are on the bike and we teach ourselves to balance then we can make progress. Then there are people who end up doing absolutely crazy things on a bike and even if I read how to I don't think that I'll try :)
Keep practicing and modelling until it starts to make sense or until you feel comfortable with the model. If I recall correctly Eric Evans mentions in the Blue Book that it may take a couple of designs to get the model closer to what we need.
Keep in mind that Mike Mogosanu is using a event sourcing approach but in any case (without ES) his approach is very good to avoid unwanted artifacts in mainstream OOP languages.
How can it be that the function is an AR, if there must be a globaly unique identifier to it, and there isn't, reason being that
its a function. what does have a globaly unique identifier is the
Domain Event that this function produces.
TransferNumber acts as natural unique ID; there is also a GUID to avoid the need a full Value Object in some cases.
There is no unique ID state in the computer memory because it is an argument but think about it; why you want a globaly unique ID? It is just to locate the root element and its (non unique ID) childrens for persistence purposes (find, modify or delete it).
Order A has 2 order lines (1 and 2) while Order B has 4 order lines (1,2,3,4); the unique identifier of order lines is a composition of its ID and the Order ID: A1, B3, etc. It is just like relational schemas in relational databases.
So you need that ID just for persistence and the element that goes to persistence is a domain event expressing the changes; all the changes needed to keep consistency, so if you persist the domain event using the global unique ID to find in persistence what you have to modify the system will be in a consistent state.
You could do
var newTransfer = New Transfer(TransferNumber); //newTransfer is now an AG with a global unique ID
var changes = t.RegisterTransfer(Debit debit, Credit credit)
persistence.applyChanges(changes);
but what is the point of instantiate a object to create state in the computer memory if you are not going to do more than one thing with this object? It is pointless and most of OOP detractors use this kind of bad OOP design to criticize OOP and lean to functional programming.
Following question - How does an Aggregate Root looks like in code? is it the event? is it the entity that is returned? is it the function
of the Aggregate class itself?
It is the function itself. You can read in the post:
AR is a role , and the function is the implementation.
An Aggregate represents a single unit of work, meaning it has to be consistent. You can see how the function honors this. It is a single unit of work that keeps the system in a consistent state.
In the case that the Domain Event that the function returns is the AR (As stated that it has to have that globaly unique identifier),
then how can we interact with this Aggregate? the first article
clearly stated that all interaction with an Aggregate is by the AR, if
the AR is an event, then we can do nothing but react on it.
Answered above because the domain event is not the AR.
4 Is it right to say that the aggregate has two main jobs: Apply the
needed changes based on the input it received and rules it knows
Return the needed data to be persisted from AR and/or need to be
raised in a Domain Event from the AR
Yes; again, you can see how the static function honors this.
You could try to contat Mike Mogosanu. I am sure he could explain his approach better than me.

DDD - Aggregates for read-only

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)

Relationships between multiple aggregate roots

In many applications, I deal with users and finance companies (as an example) and I have long been struggling to model the relationship between the two according to Domain Driven Design principles.
In my system I can do the following:
Add a user to an existing finance company.
Add a finance company to an existing user.
I believe both are aggregate roots... Finance Company and User.
How do I model the relationship between the 2? Is it FinanceCompany.Users? or User.FinanceCompanies? Is it neither? Or am I missing knowledge of some key DDD concept(s)? The problem is if I choose one way over the other, the code is more understandable / clear from one aggregate root entry point, but not the other. Sometimes there are cases where it makes more sense to navigate to a Finance Company and add users to it, and other times there are cases where it makes more sense to navigate to a specific user and add finance companies to the user.
Is there some better way to approach this, maybe through repository methods? Is there some key concept I am not getting or understanding here? It doesn't feel right to assume the relationship between Finance Company and User belongs under either of the 2 ARs. When I store the relationship I have to store it in a table named FinanceCompanyUsers or UserFinanceCompanies, but it still doesn't seem clear.
Would I have code such as FinanceCompany.AddUser() and User.AddFinanceCompany()? or is there some completely different approach for relationships such as this?
You have already determined that both User and FinanceCompany are aggregates so each has its own life-cycle.
The problem with many domains is that we don't have a complete understanding of the relationships. As another example we can take an Order and a Product. Both are aggregates but would we have Order.AddProduct() or Product.AddOrder()? In this case it seems pretty obvious in that an Order contains a limited subset of Product entries whereas a Product may very well contain many orders and we are not really too interested in that relationship since it is a rather weak relationship. A Product can exist and be valid without any orders attached but an Order is pretty useless without at least one product entry. This means that the Order has an invariant imposed in terms of its OrderItem entries. In addition to this we have enough knowledge about this hackneyed example that we know we are going to need an associative entity (in relational theory speak) since we need additional information regarding the relationship and entering the fray would be our OrderItem table. Curiously I have not seen it called OrderProduct.
The guidance I would suggest is to pick the most appropriate side.
However, if no side is a true winner and both aggregates can exist without a relationship to the other in terms of an invariant perhaps the relationship itself is an aggregate as you have certainly alluded to. Perhaps it isn't only a UserFinanceCompany aggregate but perhaps there is a concept that is missing from the ubiquitous language that the domain experts refer to. Perhaps something like Auditor or some such that represents that relationship. This is akin to the OrderItem or OrderLine concept as opposed to OrderProduct.

Designing a class diagram for a domain model

First, don't think i'm trying to get the job done by someone else, but i'm trying to design a class diagram for a domain model and something I do is probably wrong because I'm stuck, so I just want to get hints about what i'm not doing correctly to continue...
For example, the user needs to search products by categories from a product list. Each category may have subcategories which may have subcategories, etc.
The first diagram I made was this (simplified):
The user also needs to get a tree list of categories which have at least one product.
For example, if this is all the categories tree:
Music instruments
Wind
String
Guitars
Violins
Percussion
Books
Comics
Fiction
Romance
I can't return a tree of Category which have at least one product because I would also get all subCategories, but not each sub category has a product associated to it.
I also can't remove items from the Category.subCategories collection to keep only items which have associated products because it would alter the Category entity, which may be shared elsewhere, this is not what I want.
I thought of doing a copy, but than I would get 2 different instances of the same entity in the same context, isn't it a bad thing ?
So I redesigned to this:
Now I don't get a collection of child categories I don't want with each Category, I only know about its parent category, which is ok.
However, this creates a tree of categories which is navigable only from the bottom to the top, it makes no sense for the client of ProductList who will always need a top -> bottom navigation of categories.
As a solution I think of the diagram below, but i'm not sure it is very good because it kinda dupplicates things, also the CategoryTreeItem does not seems very meaningful in the domain language.
What am I doing wrong ?
This is rather an algorithmic question than a model question. Your first approach is totally ok, unless you were silent about constraints. So you can assign a category or a sub-category to any product. If you assign a sub-category, this means as per this model, the product will also have the parent category. To make it clear I would attach a constraint that tells that a product needs to be assigned to the most finest know category grain. E.g. the guitar products would be assigned to the Guitar category. As more strange instrument like the Stick would get the Strings category (which not would mean its a guitar and a violin but just in the higher category.
Now when you will implement Category you might think of a method to return a collection of assignedInstruments() which for Guitar would return Fender, Alhambra, etc. You might augment this assignedInstruments(levelUp:BOOL) to get also those instruments of the category above.
Generally you must be clear about what the category assignment basically means. If you change the assignment the product will end up in another list.
It depends on the purpose of the diagram. Do you apply a certain software development method that defines the purpose of this diagram in a certain context and the intended readers audience?
Because you talk about a 'domain model', I guess your goal is to provide a kind of conceptual model, i.e. a model of the concepts needed to communicate the application's functionality to end users, testers etc. In that case, the first and the second diagram are both valid, but without the operations (FilterByCategory and GetCategories), because these are not relevant for that audience. The fact that the GUI only displays a subset of the full category tree is usually not expressed in a UML diagram, but in plain text.
On the other hand, if your intention is to provide a technical design for developers, then the third diagram is valid. The developers probably need a class to persist categories in the database ('Category') and a separate class to supply categories to the GUI ('CategoryTreeItem'). You are right that this distinction is not meaningful in the domain language, but in a technical design, it is common to have such additional classes. Please check with the developers if your model is compatible with the programming language and libraries/frameworks they use.
One final remark:
In the first diagram, you specified multiplicity=1 on the parent side. This would mean that every Category has a parent, which is obviously not true. The second diagram has the correct multiplicity: 0..1. The third diagram has an incorrect multiplicity=1 on the composition of CategoryTreeItem.
From my perspective your design is overly complex.
Crafting a domain model around querying needs is usually the wrong approach. Domain models are most useful to express domain behaviors. In other words, to process commands and protect invariants within the correct boundaries.
If your Product Aggregate Root (AR) references a Category AR by id and this relationship is stored in a relationnal DB then you can easily fulfill any of the mentionned querying use cases with a simple DB query. You'd start by gathering a flat representation of the tree which could then be used to construct an in-memory tree.
These queries could be exposed through a ProductQueryService that is part of the application layer, not the domain as those aren't used to enforce domain rules or invariants: I assumed they are used to fullfil reporting or UI display needs. It is there you could have a concept such as ProductCategoryTreeItemDTO for the in-memory representation.
You are also using the wrong terms according to DDD tactical patterns in your diagrams which is very misleading. An AR is an Entity, but an Entity is not necessarily an AR. The Entity term is mostly used to refer to a concept that is uniquely identified within the boundary of it's AR only, but not globally.

Resources