domain-driven-designbounded-contexts

Always valid domain model entails prefixing a bunch of Value Objects. Doesn't that break the ubiquitous language?


The principle of always valid domain model dictates that value object and entities should be self validating to never be in an invalid state.

This requires creating some kind of wrapper, sometimes, for primitive values. However it seem to me that this might break the ubiquitous language.

For instance say I have 2 entities: Hotel and House. Each of those entities has images associated with it which respect the following rules:

This to me entails the following classes

class House {
  HouseImages images;
  // ...
}
class Hotel {
  HotelImages images;
}

class HouseImages {
  final List<Image> images;
  HouseImages(this.images) : assert(images.length >= 1), 
                            assert(images.length <= 10);
}

class HotelImages {
  final List<Image> images;
  HotelImages(this.images) : assert(images.length >= 5), 
                            assert(images.length <= 20);
}

Doesn't that break the ubiquitous languages a bit ? It just feels a bit off to have all those classes that are essentially prefixed (HotelName vs HouseName, HotelImages vs HouseImages, and so on). In other words, my value object folder that once consisted of x, y, z, where x, y and z where also documented in a lexicon document, now has house_x, hotel_x, house_y, hotel_y, house_z, hotel_z and it doesn't look quite as english as it was when it was x, y, z.

Is this common or is there something I misunderstood here maybe ? I do like the assurance it gives though, and it actually caught some bugs too.


Solution

  • There is some reasoning you can apply that usually helps me when deciding to introduce a value object or not. There are two very good blog articles concerning this topic I would like to recommend:

    I would like to address your concrete example based on the heuristics taken from the mentioned article:

    1. Are there more than one primitive values that encapsulate a concept, i.e. things that always belong together?

    For instance, a Coordinate value object would contain Latitude and Longitude, it would not make sense to have different places of your application knowing that these need to be instantiated and validated together as a whole. A Money value object with an amount and a currency identifier would be another example. On the other hand I would usually not have a separate value object for the amount field as the Money object would already take care of making sure it is a reasonable value (e.g. positive value).

    1. Is there complexity and logic (like validation) that is worth being hidden behind a value object?

    For instance, your HotelImages value object that defines a specific collection type caught my attention. If HotelImages would not be used in different spots and the logic is rather simple as in your sample I would not mind adding such a collection type but rather do the validation inside the Hotel entity. Otherwise you would blow up your application with custom value objects for basically everything.

    On the other hand, if there was some concept like an image collection which has its meaning in the business domain and a set of business rules and if that type is used in different places, for instance, having a ImageCollection value object that is used by both Hotel and House it could make sense to have such a value object.

    I would apply the same thinking concerning your question for HouseName and HotelName. If these have no special meaning and complexity outside of the Hotel and House entity but are just seen as some simple properties of those entities in my opinion having value objects for these would be an overkill. Having something like BuildingName with a set of rules what this name has to follow or if it even is consisting of several primitive values then it would make sense again to use a value object.

    This relates to the third point:

    1. Is there actual behaviour duplication that could be avoided with a value object?

    Coming from the last point thinking of actual duplication (not code duplication but behaviour duplication) that can be avoided with extracting things into a custom value object can also make sense. But in this case you always have to be careful not to fall into the trap of incidental duplication, see also [here].1

    1. Does your overall project complexity justify the additional work?

    This needs to be answered from your side of course but I think it's good to always consider if the benefits outweigh the costs. If you have a simple CRUD like application that is not expected to change a lot and will not be long lived all the mentioned heuristics also have to be used with the project complexity in mind.