Aggregate with data - mutable or immutable ?

Hi,

I think I know the answer, and it might be opinionated and both could be correct to use while one solution might be better in performance.

Using Kotlin, data class, event sourcing for aggregates.
I usually always model those classes with val/List/Set -> so it is immutable.

For Aggregate I followed the same idea of immutable, meaning that a command is received, will check some business logic, throw or publish an event.
In case of event, then it will be processed by the aggregate, since my internal data in the aggregate is using classes that immutable, I usually call “.copy(…)” and apply necessary changes from the event to the aggregates fields (add new class instance in mutable list, modify some var fields, etc).

`
class MyAggregate {

@AggregateIdentifier
private var myId: MyId? = null // MyId is inline class

private var someField: Int = 0

private val someList1 = mutableListOf()

private lateinit var someDataButNotInList: SomeData

// … omitted constructor, cmds and events

}

data class SomeData(
val quantityTotal: Int,
val quantityUsedByTime: Int,
val someList2: List
)
`

In this example, we see that normal fields are mutable, that list is mutable but not in “SomeData”, etc.

What would be the best to do?

I guess it would be keep "someList1" as mutable list (and val); and make in "SomeData" mutable fields like "```quantityTotal" and "quantityUsedByTime" (use var); and make "```someList2" as MutableList<String> (keep val).
What are your opinions?

So far I have all my aggregate following this immutable idea but I start to think it was not the best approach as it will introduce a performance impact when "replaying" events to get the aggregate.
If indeed there is a big performance impact then I will change all my aggregates to follow a more mutable approach.

``

Since Aggregates and Entities are identified by their ID, the ID attribute(s) should be (functionally) immutable. On the other hand, Value Objects are identified by all of their attributes and should therefore be immutable, since their identity shouldn’t be changeable.

Further more, Aggregates and Entities are responsible to manage state and state transitions. They naturally need setters or methods that change their internal state(s). E.g. if you change the address of a customer, it is not needed to create a new customer for it. Only, a different CustomerID leads to a new customer.

This is just how I see it in the scope of Domain Driven Design.

This is the definition we mostly find online on DDD, but what is the actual best approach when developping may change.

“SomeData” is a value object in my case, I followed the immutable as supposed to be done but I think it brings overhead that could be avoided.
Furthermore, this value object is only internal to this aggregate, all public data is seen via events so I do not see any problem to transform “someData” to :

data class SomeData( val someIdThatComesFromAnotherAggregateThatShouldNotChangeOverTheLifeSpanOfThisValueObject: String var quantityTotal: Int, var quantityUsedByTime: Int, val someList2: MutableList<String> )

I added a "val" field to this value object, just to demonstrate that we can still keep some "immutable" data in it, that will never change in the business logic of this value object.
Let's suppose ```quantityTotal changes frequently, we will have performance and some garbage collection overhead due to creating "SomeData" intances if we keep all immutable, whereas we can make those as "var" and modify the value in the event handler.`` I see benefits doing so and it is not breaking the idea of DDD that value object are immutable, what really matters is that value objects are not entities (have no id, just data). Of course there are snapshots, but using loading time policy for snapshotting aggregate, I think it is better to use “mutable” in the value object since this is just an internal logic of the aggregate and limits overhead of object creation (and garbage collection).`


``

If the „SomeData“ Value-Object is not shared, used very locally (nearby the aggregate) and just a grouping of some attributes, then it might not be a problem to make it mutable. Since aggregates and events are made for this, this applies also to objects that are used inside of them.

Immutable objects are much easier to maintain and handle, if they are user wildly or shared e.g. via an API.
So, if „SomeData“ is used inside message types (api), then it should remain immutable.
In that case, you can have a separate mutable type inside your aggregate and mutate it (needs mapping) with the shared value object.

An object is either fully immutable (including all subtypes), or mutable.
It doesn’t matter, if there is only one attribute, that can be changed: it’s mutable.

If you change an object to be mutable, it must not have any static single-instance constants.

ok thanks, that’s what I thought, I wanted to have external opinions.

Yes “SomeData” is local, only used in the aggregate, I always design like that for aggregates.
I will then modify my code to use mutable value object locally for the aggregate as it reduces the over-head and is very specific to the aggregate logic.

Immutable are commands, events and queries, and part of a different module than the aggregate context.

The problem with validating your question is that it is arbitrary and abstract. There is nothing DDD about it. IMO, you will be better served to focus on your domain, using Value Object and Entity concepts as intended WRT immutability and identity. Also, worry about optimization later. If you start with good domain design many times you don’t end up with poor performance because you tackle the complexity of the domain more naturally. At least that is the idea.