I'm working on a project where I had a value object (called SkillProfile) within an aggregate. Aggregate root is the User entity and the User has a unidirectional one-to-one association to it's SkillProfile. There is use case in the business where a SkillProfile can be shared with another User, but always as a copy (so modifying one of the profile won't change any of the other users profile). So far so good.
Now the business has the new requirement that it should be possible to see in reports which users share the same skill profile. This requirement cannot be fulfilled by the equals method on the skill profile, since there are skill profiles which coincidentally have the same values but weren't "shared" in terms of explicitly doing it. Of course the old requirement that skill profiles have to be immutable is still valid.
So here my question: Is it a good idea to invent a new field "Id" or "SharingCode" on the SkillProfile class and therefore give it some sort of identity although it's still a value object and not an entity since it has no state or lifecycle?
First,
so modifying one of the profile won't change any of the other users profile
If SkillProfile is indeed a value object, there should be no possibility to modify one! Replacing it within the User is fine of course. (just to have this clear before discussing your question)
With the new requirements, SkillProfile needs an identity - whether explicit or implicit - because it can no longer be compared by just looking at its value. Thus, it is now an entity.
Note that you don't need to treat it much differently than you were the value object before - it's a good idea to keep the entity immutable, for example, because this is still in the nature of the concept. So it shouldn't be a big step to make it an entity.
Related
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.
I have recently dived into DDD and this question started bothering me. For example, take a look at the scenario mentioned in the following article:
Let's say that a user made a mistake while adding an EstimationLogEntry to the Task aggregate, and now wants to correct that mistake. What would be the correct way of doing this? Value objects by nature don't have identifiers, they are identified by their structure. If this was a Web application, we would have to send the whole EstimationLogEntry value object as a request parameter, along with the new values, just so we could replace the old value object with the new one. Should EstimationLogEntry be an entity?
It really depends. If it's a sequence of estimations, which you append every time, you can quite possibly envision an operation which updates the value only of the VO. This would use VO semantics (the VO is called to clone itself in-mem with the updated value on the specific property), and the command can just be the estimation (along with a Task id).
If you have an array of VO's which all semantically apply to Task (instead of just the "latest" or something)... it's a different matter. In that case, you'd probably have to send all of them in the request, and you'd have to include all properties too, but I'd say that the need to change just one, probably implies a need to reference them, which in turn implies a need to have an Entity instead of a VO.
DDD emphasizes the Ubiquitous language and many modelling questions like this ones will derive their answer straight from that language.
First things first, if there's an aggregate that contains a value object, there's a good chance that the value object isn't directly created by the user. That is, the factory that creates the value object lives on the aggregates API. The value object(s) might even be derived directly from the aggregates state instead of from any direct method call. In this case, do you want to just discard the aggregate and create a new one? That might make sense depending on your UL.
In some cases, like if you have immutable value objects (based on your UL), you could simply add a new entry into the log entry that "reverses" the old entry. An example of this would be bank accounts and transactions. If bank accounts are aggregate roots and transactions are the value objects. If a transaction is erroneously entered, you can simply write a reversing transaction to void it.
It is definitely possible that you want to update the value object but that must make sense in your UL and it's implementation must also be framed around your UL. For example, if you have a scheduling application and an aggregate root is a person's schedule while the value objects are meetings. If a user erroneously enters a meeting, what your aggregate root should do would be to invalidate the old meeting (flip a flag, mark its state cancelled e.t.c) and create a new one. These actions fit the UL for your scheduling app. The same thing as what you are calling "updating the entry" above.
I am trying to get to grips with the ideas behind DDD and apply them to a pet project we have, and I am having some questions that I hope that someone here would be able to answer.
The project is a document management system. The particular problem we have regards two notions that our system handles: That of a Document and that of a DocumentStatus.
A Document has a number of properties (such as title, author, etc). Users can change any of the Document's properties through out its life time.
A Document may be, at any time, be at a particular state such as NEW, UNDER_REVISION, REVISED, APPROVED etc. For each state we need to know who made that change to that state.
We need to be able to query the system based on a document status. An example query would be "Get me all documents that are in the REVISED state".
"Get me all documents whose status has been changed by user X"
The only time that a Document and a DocumentStatus need to be changed in the same transaction is when the Document is created (create the document and at the same time assign it a status of NEW).
For all other times, the UI allows the update of either but not both (i.e. you may change a document's property such as the author, but not its state.) Or you can update its state (from NEW to UNDER_REVISION) but not its properties.
I think we are safe to consider that a Document is an Entity and an Aggregate Root.
We are buffled about what DocumentStatus is. One option is to make it a Value Object part of the Document's aggregate.
The other option is to make it an Entity and be the root of its own aggregate.
We would also liked to mention that we considered CQRS as described in various DDD documents, but we think it is too much of a hassle, especially given the fact that we need to perform queries on the DocumentStatus.
Any pointers or ideas would be welcomed.
Domain
You say you need to be able to see past status changes, so the status history becomes a domain concept. A simple solution would then be the following:
Define a StatusHistory within the Document entity.
The StatusHistory is a list of StatusUpdate value objects.
The first element in the StatusHistory always reflects the current state - make sure you add the initial state as StatusUpdate value object when creating Document entities.
Depending on how much additional logic you need for the status history, consider creating a dedicated value object (or even entity) for the history itself.
Persistence
You don't really say how your persistence layer looks like, but I think creating queries against the first element of the StatusHistory list should be possible with every persistence mechanism. With a map-reduce data store, for example, create a view that is indexed by Document.StatusHistory[0] and use that view to realize the queries you need.
If you were only to record the current status, then that could well be a value object.
Since you're composing more qualifying - if not identifying - data into it, for which you also intend to query, then that sounds to me as if no DocumentStatus is like another, so a value object doesn't make much sense, does it?
It is identified by
the document
the author
the time it occurred
Furthermore, it makes even more sense in the context of the previous DocumentStatus (if you consider more states than just NEW and UNDER_REVISION).
To me, this clearly rules out modeling DocumentStatus as a value object.
In terms of the state as a property of DocumentStatus, and following the notion of everything is an object (currently reading David West's Object Thinking), then that could of course be modeled as a value object.
Follows How to model an entity's current status in DDD.
Recently I was thinking about some issues I had in the past while attempting to design a particular domain model, lets just say Address, that can be editable with a given context but non-editable within another. My current way of thinking is that I would have both a Value Object version of the Address and an Entity for the Address perhaps attached to something like a customer account in order to derive it's identity.
Now I'm realizing that if I'm ever creating a new Address, such as when one is entered in by the user, that I most likely also need to be able to continue to edit that Address and perhaps edit any preexisting Addresses as well within that same bounded context. For this reason I could assume that within this context Address should be modeled as Entity and not a Value Object. This leads me to my main question which is that if you should always be using entities when modifying an existing set of data or creating a new data then does it ever make sense to have a Factory for creating any Value Object?
The rule that is beginning to emerge for me as I follow this line of thinking is that value objects should only be created to represent things that are either static to the application or things that have already been persisted into the database but not things that are transient within the current domain context. So the only place I should any type of creation of value objects would be when they are re-hydrated/materialized within or on the behalf of aggregate root repositories for persistent values or within a service in the case of static values. This is beginning to seem pretty clear to me however it concerns me that I haven't read anywhere else where somebody is drawing the same conclusions. Either way, I'm hoping that somebody can confirm my conclusions or set me straight.
that can be editable with a given context but non-editable within
another
Differences in mutability settings for an entity within different contexts can also be represented in the application tier. It is an operational concern, possibly involving authentication and authorization and an application service is a convenient location for this logic. The distinction between a VO and an entity does not address these concerns directly. Just because a VO should be immutable, does not mean that an entity cannot change the value of a VO that it references. For instance, a user can reference an immutable address value, however an edit operation can update the user to reference a new value. Allowing a user to edit an address in one context and not in another can be represented as permission values associated with the corresponding context.
This leads me to my main question which is that if you should always
be using entities when modifying an existing set of data or creating a
new data then does it ever make sense to have a Factory for creating
any Value Object?
It can certainly make sense to have a factory for creating VO instances. This can be a static method on the VO class or a dedicated object, depending on your preference. However, a VO should not be used to address mutability requirements of the domain model. Instead, as specified above, this should be handled at the application tier.
I am working on an application where users can follow each other, in a similar fashion to Twitter.
After reading up on DDD, I understand that my users are Entity Objects - I refer to them using their unique ID.
When one user 'follows' another (i.e. forms a Connection), the relationship is stored in a many-to-many table. Its fields include FollowerID, TargetID, and Status. There can be only two records for each Follower/Target combination (one Active, the other Inactive), so I can safely identify objects based on their attributes.
So, I think my Connection objects are Value Objects, not Entity Objects, but I'm not sure. Can you help me with this decision?
You are correct that entities are unique and carry the notion of having an identity (i.e. only one unique user can exist). A Connection is dependent on other User entities. It represents some aspect between two users. That aspect is whether there is an active or inactive connection. Without containing the data of which users are connecting, a connection has no identity. It may even have it's own primary key in the database, but from a domain perspective, it has no identity of it's own.
Therefore, I would say that Connection is a value object.
To support my conclusion, Microsoft.Net Architecting Applications for the Enterprise, page 187, says:
A value object class represents an entity in the domain that mostly
contains data and lives for the data it contains. A value object is
fully identified by a combination of values it contains. An entity
object, on the other hand, has its own life and rich behavior
regardless of the data it contains. Entity objects are usually objects
with a longer lifetime. A value object represents an aspect of an
entity and can live only in relation to an entity.
And also on page 189:
One further comment is needed to explain the difference between
entities and value objects. You don’t need a repository or a data
mapper for a value object. You need a repository only for an entity.
The repository (or the mapper) for a given entity will certainly take
care of all value objects that depend on a given entity.
Some time ago, I saw a cartoon about scientist that had invented cloning. Every time he cloned himself, he destroyed previous version. Then person that was watching demonstration decided to interrupt and sabotaged destruction part so there were two scientists. Cartoon ended with some interesting existential questioning.
Values vs entities is not about having or not having id fields in one or another form. Point is - how we are looking at those objects through our domain perspective. If they are value objects, then only their value matters - 1st, 3rd and 53rd scientist are the same. If we care about identity, if we think that cloning 3rd scientist will never be like 1st one, then our object is an entity.