0

I have an Entity type, let's say Car for example. There is a Value Object type Tire for it. Each car has a set of tires with certain properties. Sometimes tires are replaced, which is communicated by a Bounded Context via Domain Events. There are some other BCs that record a Read Model of the cars and tires.

Now there is a new requirement. In the future, a BC should measure the tire pressure for each tire and display it to the user (i.e. also store it). This property is not interesting for the rest of the system, so there is no change to the Domain Events.

So the tires are Value Objects so far, but at a single point, the identity (not global, but per car) becomes relevant after all. I now see the following options:

  1. Make Tire an Entity type. So the BC that generates the tire change Domain Events has to come up with an ID and communicate it to the entire system, even though it is not relevant to it and almost anyone else.
  2. The tire pressure BC identifies the tires by their position in the car's tire list (which in the Read Model is derived from the Domain Events). Let's assume this is technically possible in my particular case.

Variant 1 would be very robust, but a small detail of a BC is extended to the whole system. Variant 2 could be realized as an implementation detail of the single BC, but it feels wrong somehow. It would work currently, as I said, but I'm concerned that I'll always have to keep an eye on it to make sure it continues to always work in the future since something like a tire order doesn't exist explicitly in the Domain Events model.

I suspect it's a lot like banknotes. For 99% it's a Value Object, but there's still a serial number on every note, which is usually ignored. Ignoring doesn't work that well in the software, because technically you have to deal with entities differently than with value objects, but you can't avoid that completely.

What do you think about this? Is it a general principle, that if the identity of something is relevant in any place, you have to use an Entity everywhere up the chain?

1 Answer 1

3

Horribly tautological but factually accurate: a value object's value is inherently defined by its values, not some arbitrary identity.

For example, a person cannot be a value object, as every person called "John Smith" would effectively be considered the "same" person (assuming the name is the person's only property for the sake of example).

Maybe it's a strained example, but what I'm trying to get at is that value objects are considered interchangeable when they have the same values, and tracking instance-specific data such as pressure goes against that idea.

  1. Make Tire an Entity type. So the BC that generates the tire change Domain Events has to come up with an ID and communicate it to the entire system, even though it is not relevant to it and almost anyone else.

You're adding a global identifier to a tire, for the sole purpose of tracking it in the scope of a given car. That's overkill.

  1. The tire pressure BC identifies the tires by their position in the car's tire list (which in the Read Model is derived from the Domain Events). Let's assume this is technically possible in my particular case.

This makes more sense. The added identity (position in car) is scoped to what you're using it for.

However, I believe this should not be part of the tire, but rather in how the car stores its tires. You mentioned "the car's tire list", but maybe you should consider if a list is right for you here.

The simplest solution for the current problem would be to store each tire individually, e.g. in FrontLeftTire, RearRightTire, ... properties. This solves the problem at hand. However, this may run into other issues for cases where you do want to iterate over tires, so it might be worth it to add a calculated property (or method) which returns a list of all of the tires.

However, then we get into some more advanced discussions, such as what about cars with more/less than 4 tires? What about a car that usually has 4 tires but is missing some of them? ... I can't anticipate every possible edge case for you.

ALternatively, maybe you need an indirection inbetween Car and Tire, e.g. TireInstallation, which tracks any data not related to the tire itself but rather how it is installed in the car. Location in the vehicle and pressure would belong there.

The point I'm trying to get across is that you don't need to tie yourself to your current implementation of how a car stores its tires. Re-evaluate what makes the most sense for your use case.

I suspect it's a lot like banknotes. For 99% it's a Value Object, but there's still a serial number on every note, which is usually ignored.

Good analogy, but remember that in most software there is simply no tracking of the serial number. A cash register doesn't care which $100 bill is in the register, it only cares that the right amount of money is in there.

By keeping the tire's location outside of the tire value object itself, like I suggested above, you get the best of both worlds. The tire itself remains an interchangeable value object, but the data is still registered on some level so that the part which doesn't treat tires as interchangeably can track non-interchangeable information such as a tire's pressure.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.