Domain Entity as an Immutable Object (DDD, not ES)

1,001 views
Skip to first unread message

aakim...@gmail.com

unread,
Jun 12, 2018, 6:53:02 AM6/12/18
to DDD/CQRS
Hi all,
I would like to know your opinion on this topic.
Is making every domain entity immutable bring significant benefits or is it an example of over-engineering in most cases?
I am talking about entities that contain mutable state by design (not Value Objects or entities that are immutable by definition).

For instance:

class Person {
    private final String ssn;
    private final String position;
    // constructor omitted
   
    // mutable approach
    public void promote(String newPosition) {
        this.position = newPosition;
    }

    // vs immutable approach
    public Person promote(String newPosition) {
        return new Person(ssn, newPosition);
    }
}

In general making everything immutable let you worry less about the concurrency issues (and as a java developer I always tried to follow this way). 
But at the same time, the client code looks less attractive at times and I think that concurrency is not an issue in this case:

// somewhere in the application service
Person person = personRepository.find(ssn);
// the following lines are simplified but I hope you have get the idea of using "=" to be able to track changes
// because it is not always possible to make a chained "oneliner" like person.doOne().doTwo().doThree()
person = person.promote(position);
person = personRepository.save(person);

// do not return entity but convert it to some kind of DTO
return convert(person);

P.S. My post is about actions only. Because, IMHO, if the entity has a getter (no CQRS) that it should return only immutable representation of property (copy collections etc). 

Thank you in advance for responses.

Danil Suits

unread,
Jun 12, 2018, 10:27:49 AM6/12/18
to DDD/CQRS
I find the idea very appealing, with a slightly different spelling.


My translation: "entity" is a mutable reference to immutable state.  New information is introduced to the system by calculating a new immutable state that incorporates the new information, then updating the reference to point to the new state.

The calculation of immutable state is pure functional core; the updates of the reference are part of the imperative shell.

I'm not wholly convinced; as Fowler writes in Patterns of Enterprise Application Architecture, _reentrant_ code requires some care, and if you are in a space where you need rentrant code, you want idioms that make errors easy to identify and repair.


aakim...@gmail.com

unread,
Jun 12, 2018, 11:14:43 AM6/12/18
to DDD/CQRS
Danil, thank you for reply.
I will definitely look at this post in more detail but at first glance it seems to be no very relevant to the standard DDD approach that is widely used (especially in the java world).
Also mixing both functional and imperative paradigms in one project is probably not the best idea, especially considering that DDD is more about behavior-rich objects rather than managing bare data-structures in a functional way.

pagoda_5b

unread,
Jun 18, 2018, 7:40:44 PM6/18/18
to DDD/CQRS
Reply inline


On Tuesday, June 12, 2018 at 5:14:43 PM UTC+2, Alexander Akimov wrote:
Danil, thank you for reply.
I will definitely look at this post in more detail but at first glance it seems to be no very relevant to the standard DDD approach that is widely used (especially in the java world).

That is because it's a non-traditional approach when coming from java, but that doesn't imply that it's not relevant.
Considering in particular that sticking to immutability as much as possible is currently one of the main design adoption almost everywhere, I won't dismiss the idea that it could become the "standard DDD approach" sooner or later.
 
Also mixing both functional and imperative paradigms in one project is probably not the best idea, especially considering that DDD is more about behavior-rich objects rather than managing bare data-structures in a functional way.

Same as for the previous point, the idea of behaviour-rich objects is not intrinsic in DDD, as much as the fact that OOP was the main design approach when DDD started to gain traction.
DDD is focused on using the business language and concepts in the model, but that can be just as well be served by a totally functional approach where the domain is modeled with data (immutable) and functions (verbs from the UL).
Mixing imperative and functional is a de facto reality, since nobody seems to completely agree on what is actually "functional", and every language community sticks to his own gauge of what is functional code.
Unless you're using purely functional languages like clojure, haskell, F#, elm, everything else can be somehow considered a compromise of functional and imperative. It's just a matter of perspective.
YMMV
Reply all
Reply to author
Forward
0 new messages