0

I was talking to a Business Analyst about our Domain Model a few weeks ago. I used a class diagram to facilitate communication. She understands UML at a high level and this worked out quite well. She only asked two questions: what is an Entity and what is a Value Object? I explained.

I have two base classes i.e. Entity (http://enterprisecraftsmanship.com/2014/11/08/domain-object-base-class/) and Value Object (https://lostechies.com/jimmybogard/2007/06/25/generic-value-object-equality/). This seems to be working very well today.

However, a couple of people criticized this approach earlier on my other question here: Should I handle all nine comparisons?. They argued that these bases classes:

1) Make the Domain Model anaemic as another class is responsible for comparisons. 2) Entity and Value Object are not part of the Ubiquitous language

Point two has some bearing for me because of the conversation I had with the Business Analyst. Therefore I have looked at examples of DDD apps on GitHub with this in mind and I can't find any real life examples that use this approach. However, some tutorial type apps use it like this one: https://github.com/vkhorikov/DddInAction/tree/master/DddInPractice.Logic/Common

Therefore I have to ask if this is a valid approach for a real life application or whether it is just a thought exercise?

It does not really matter whether or not I use these base types at the moment. However, I don't want to introduce problems now that only become apparent when the application scales more in future.

  • why do you create a 'value object' when c# has structs? – Ewan Jan 29 '18 at 20:17
  • @Ewan, I am talking about a Value Object rather than a Value Type. Please see the second link in my question. – w0051977 Jan 29 '18 at 20:19
  • I have read the 2007 blog post you link to. It just mentions the 16byte limit. which is out of date and not really a limit in any case. Why do you require a 'value object'? – Ewan Jan 29 '18 at 20:24
  • That article is 11 years old! Do not trust such ancient articles to advise on important things like how to implement a concept in a language. C# struct can be any size, declared read-only and even passed around by reference these days. – David Arno Jan 29 '18 at 20:29
  • @Ewan, I am just following advice from a few courses I have recently done mainly on Pluralsight. Having base types allows you to create default implementations for comparisons e.g. .equals, ==, != etc. All the value objects I have created so far and all the entities I have created so far seem suited to this approach. – w0051977 Jan 29 '18 at 20:44
5

If I'm understanding you right, every class in your domain is based on on of two classes.

  1. Entity which enforces a single type Id field, tightly coupled to your database and various equality overrides and reflection of classes

  2. Value which emulates a value type and attempts to enforce immutably

I am struggling to understand the motivations for this idea.

The Entity suggestion seems to be a throw back to the Active record pattern, with its tight coupling to Nhibernate, assumption that your primary key can be a long int for all objects and that a value of 0 means the object isn't 'real' because the database needs to generate ids.

The Value object seems like a clumsy attempt to replace struct. You are worried about > 16byte structs being slow and replacing them with reflection?

Both override operators, something that it rarely advisable.

There are some edge cases where you will lament that you business object is a reference class and want to create a copy constructor.

There are some rare edge cases where you want to compare objects and simply comparing the Id isn't enough.

But these aren't the kind of massive unforeseen 'gotchas' that require you to plan the entire structure of your code ahead incase they turn up.

The distinction between Value and Reference Types shouldn't be something that comes up in a discussion with a Business Analyst.

Update : Summary of the comments

When comparing domain objects in your application my recommendation is to compare the Id fields ie.

var cust1 = repo.GetCustomerByName(name);
var cust2 = repo.GetCustomerByLastName(lastname);

var areCustomersTheSame = cust1.Id == cust2.Id

rather than comparing the objects directly. ie.

var cust1 = repo.GetCustomerByName(name);
var cust2 = repo.GetCustomerByLastName(lastname);

var areCustomersTheSame = cust1 == cust2

The second method requires that you override the default operators which is more work and will not be expected. Additionally it means you cant do the default compare to see if the reference is the same.

There is a third complication where the Ids may match but some other fields on the object have changed, or you have no Id field at all. Here I would encapsulate that logic in another class.

CustomerComparer.IsAllFieldsMatch(cust1,cust2)

My General feeling is that if you are having to check whether objects are the same often in your Business Logic. You are doing something wrong somewhere. Get Objects once, do your thing and dispose of them.

| improve this answer | |
  • Mark Seeman talks about it more here: stackoverflow.com/questions/2326288/… and it is also talked about here: stackoverflow.com/questions/6656050/… – w0051977 Jan 29 '18 at 21:04
  • 1
    jeeze that question is even older than your blog post. I go back to my initial comment. why do YOU need it? What does it achieve in YOUR code. – Ewan Jan 29 '18 at 21:44
  • 1
    no its just compare the id. if(cust1.Id == cust2.Id) {...} – Ewan Jan 29 '18 at 22:17
  • 1
    dont define it. leave equals alone – Ewan Jan 29 '18 at 22:38
  • 1
    @w0051977 that sounds like the worst of both worlds – Caleth Jan 30 '18 at 10:42
4

Entity and Value Object are not part of the Ubiqtious language. Should this stop me from using them?

You shouldn't be using terms from the implementation domain to try to explain what's going on in the business domain.

Entity and Value Object are names for implementation patterns, much like Iterator, Command, Domain Model....

Another way of thinking of Entity and ValueObjects is that they describe roles that the implementations can play. For instance, if CustomerProfile is an Entity, then that could mean that it implements an identity() method that returns some identifier that is a Value Object, which in turn promises that the identifier is immutable, and suitable for use as key into a data structure. So you can build a generic Repository that can act like an in memory collection of an object that implements the Entity role by providing an identifier that supports the Value Object role

interface Entity<Id implements ValueObject> {...}

interface CustomerProfile {...}

HibernateCustomerProfile implements CustomerProfile, Entity<HibernateCustomerId> {...}

class HibernateCustomerProfileRepository extends Repository<CustomerProfile> {...}

But these conveniences are almost always down in the plumbing, not part of implementing the domain behaviors.

Is it suitable to use ValueObject and Entity bases classes in a real implementation or is it just a thought exercise? Do you use them?

I don't use them as base classes; I normally work in languages where I'm restricted to a single base class for any given implementation, and the value of a common base class doesn't offset the costs.

As interfaces, they are just metadata. They don't have any state of their own.

In an implementation language with mixins, they might be useful. I'm skeptical, but I don't have enough experience with them to advertise an informed opinion.

| improve this answer | |
  • Thanks. Is it suitable to use ValueObject and Entity bases classes in a real implementation or is it just a thought exercise? Do you use them? – w0051977 Jan 30 '18 at 0:17
  • Can you answer the question in my comment above before I mark the answer? – w0051977 Jan 30 '18 at 14:16
  • @w0051977 Note that VoiceOfUnreason, more or less, has answered the same I commented to you couple days ago in a different question. Base classes like these barely offset the costs. However I see you exceptical to believe it. I encourage you to find it out. Do implement these base classes and Interfaces and after several development iterations make your own conclusions. You might have modeled the cases where these makes a lot of sense and are valuable. But if during the iterations you find yourself refactoring the hierarchy of classes due to the constraints imposed by the base classes... – Laiv Jan 31 '18 at 20:41
  • You will understand the feeling VoiceOfUnreason and me have regarding these classes. You have to get into the conclusion by your own experience. This can not be learnt reading books, posts or forums. – Laiv Jan 31 '18 at 20:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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