Value Objects and Identity



Today’s article is an answer to a reader’s question about the use of Value Objects to represent the identity of an entity.

Value Objects and Identity: The Question

Here’s the question itself:

I’m understanding the core concepts of what a value object is such as immutability and equality and it occurs to me that I could represent the identity value of an entity using a value object.

I have an aggregate root called PlanningTool and it has many PlanningToolTabs and then that has many PlanningToolGroup.

My first design is on each of those entities I put an int Id property that Entity Framework maps in the database and is the primary key that is generated by the database:

Another way I could do this is to use my aggregate keys as a composite primary key:

Then the other way I could do this is I could model the identity values as value objects and the value objects would then become nested like this:

Which way do you think is the best and does it make sense using value objects for this?

Two Types of Identities

Before answering the direct question, let me step back and discuss the two types of identities. Or rather, the two ways they are used.

They are:

  • The entity’s own Id, and
  • The Id with which this entity references other entities.

You need to differentiate between the two. Entity’s own Id represents its inherent identity which we use to distinguish it from other instances of the same class. At the same time, it’s an internal implementation detail which other entities shouldn’t be aware of.

And so, it’s OK to use an Id for Case #1, but not for Case #2. When the entity references another entity, it shouldn’t know how that other entity represents its identity, this concern is ought to be encapsulated away. In other words, the entity can and should know about its own Id, but shouldn’t be aware of the Ids of other entities.

To read more about it, see Link to an aggregate: reference or Id?.

The corollary from this guidelines is this. If you have a many-to-one relation between entities in a single bounded context, it is better not to reference them by Id and instead use a direct link.

So instead of this:

it’s better to reference them like this:

And it makes sense if you look at it from the domain modeling perspective. Surrogate Ids like those generated by the database have no place in the ubiquitous language. When you are talking about a use case, you don’t describe it as:

“All customers of our organization have a dedicated manager Id assigned to them”.

If you do, the person you talk to would probably have a similar look:

Value Objects and Identity: Wat?

Wat?

When talking about a manager, you refer to it as that – a manager. No need to bring up these silly implementation details. And when it comes to Domain-Driven Design, one of the most important practices there is to align your code base along the lines of the ubiquitous language. At least when working on the core domain.

Of course, it’s not always feasible to entirely avoid the use of Ids when referencing other entities. After all, there are technical limitations to what we can do when modeling the domain. But still, this practice is applied not nearly as much as it should.

And to be frank, technical limitations is only part of the problem. The other part is that we, programmers, are so accustomed to Ids that we rarely even notice the disconnect with the real world. The good news is that this second part is fixable, which I’m trying to do here 🙂

Value Objects and Identity: The Answer

Alright, that was quite a digression. Let’s get back to the reader’s question. What is the best way to represent an entity Id? Note that we are talking about the entities’ own Ids here, not the Ids with which it references other entities.

In most cases, option #1 would be enough. Here it is again:

A nice benefit of this approach is that the presence of Id in each and every entity allows you to factor it and the comparison logic out to a base class, which I highly recommend doing. It would be even better if you could replace the following Ids with the respective entity references:

But let’s assume this is not an option for some reason.

The second option is not as good as the first one. Here it is once again:

Sure, we save ourselves additional field both in the code and in the database as we are getting rid of PlanningToolTab.Id but you lose this nice bonus of having a single base entity class.

Another drawback here is that ORMs generally don’t deal with composite primary keys very well. And so, I wouldn’t recommend this option.

The third one is quite elegant as it builds up upon functional programming principles. It avoids the primitive obsession by introducing a separate class for each Id in the domain model.

I have mixed fillings about this one, though. On one hand, it allows you to avoid the drawbacks that come with the primitive obsession, such as mistaking Id of one entity with the Id of another. If you try to undertake this operation:

the compiler will point its meaninglessness out by raising a compilation error and will be absolutely right to do so.

On the other hand, the good intentions are misplaced here. You shouldn’t deal with entities’ Ids directly anyway. In most cases, it’s a violation of the encapsulation principles (also known as Tell Don’t Ask). And so, there’s no need to create Value Objects around the identifiers. Hide them from the eyes of the client code, and you’ll be fine.

Therefore, I wouldn’t recommend Option #3 either. Go with the first one, it provides the best combination of simplicity and usefulness.

Related articles

Share




  • Michael Hodgson

    Another great post, but I have to admit it raises a lot of questions.

    Is an internal id practical for many systems? For a large group of applications (CQRS or REST web systems spring to mind) the id of aggregates is known well outside the domain. Indeed the clue is in the name Id, it’s used to identify things. As soon as Id has a life outside the domain then I see the advantages of the third approach increase. It provides all the advantages you discus with talking about avoiding primitive obsession and allows that logic to be centralized.

    For example if you want to use sequential GUIDs (COMB) style identifiers in order to decouple id generation from your persistence layer then this gives a common place to do this.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      >Is an internal id practical for many systems?
      This guideline of encapsulating the id away is only applicable when modeling the domain. The code outside the domain model can (and should) work with entities’ Ids. E.g. when the client requests information about a customer, the app service operates the customer’s Id in order to do that.

  • Joseph N. Musser II

    Potential typo: should be “represents its inherent identity”?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Good eye! Fixed, thanks 🙂

  • Anders Baumann

    Great article. As always. Keep up the good work!

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Thanks Anders!

  • Normand Bédard

    “it’s better to reference them like this –> public PlanningTool PlanningTool { get; private set; }”

    Having parent references in the object graph allows a child to call methods on it’s parent. We had a lot of debates about this where I work. We finally refuse to do this because we initially had this feeling that it does not make sense in a use case to have the possibility for an object deep in the graph to call a public method (use case) on the aggregate root. Could also lead to expose public methods that could be useful only to it’s graph.

    Any opinion about this?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      >Having parent references in the object graph allows a child to call methods on it’s parent.
      Not necessarily. If you’ve got, say, Order.Customer, customer itself doesn’t have to have a reference to the order (although it could).

      Also, I don’t think it’s feasible to avoid any possibility of inappropriate calls inside an aggregate. Things inside an aggregate are highly cohesive, which means that trying to separate them from each other would damage that cohesion. Ultimately, I believe it’s better to rely on code reviews in this case than to try to decouple classes inside an aggregate.

      Although, maybe your case is different. Feel free to provide some details here and I’ll try to give an answer based on the context.