As many other developers, I’ve been used to the fat service layer and the anemic domain model of the transaction script pattern. In that programming model, immutability is pretty much as rare as a Dodo. However, I have been investigating the rich domain model pattern lately (as you can read in my previous post) and more importantly, a good migration path for “transaction script” developers to get acquainted with the rich Domain Model, a design pattern that has been heavily underrated (and misunderstood) by many.

In this post, I will explain some of the advantages that immutable domain objects bring us, while showing that some of the seemingly problematic side effects aren’t really that problematic.

A practical example is often the easiest way to explain these kind of things. Since the banking world has received enough discredit in these times, I will use another example than the infamous “withdrawal” example. Instead, we will use the almost-as-infamous product and order example.

Imagine an application where you can browse trough products and place an order for one or more of those products. Our simple domain will contain three entities: product, order and order line. A UML class diagram for this domain is shown below.

power_of_immutability_class_diagram_1

The anemic approach

A commonly seen approach to implement this domain model is the following. The Order is implemented containing some delivery details and a list of order lines. The Order exposes getters and setters to modify each of those properties, including a getter that provides access to the list of order lines. The implementation of the OrderLine class is similar; it might contain a reference to a Product instance as well as a property to indicate the quantity ordered, resulting in the following code:

public class OrderLine {
    private Product product;
    private int quantity; 

    public Product getProduct() {
        return product;
    } 

    public void setProduct(final Product product) {
        this.product = product;
    } 

    public int getQuantity() {
        return quantity;
    } 

    public void setQuantity(final int quantity) {
        this.quantity = quantity;
    }
}

This code has a few problems, some functional and some technical

  • What happens if the price of the product changes? Invoices will probably show the new price (which is always higher, for some reason).
  • It’s no longer possible to delete a product, since you won’t be able to see what somebody ordered
  • You allow every other class in your application to modify the OrderLine at will. What if you have a discount for customers that order for a certain amount? Each time an order line was modified, your code would have to call a calculateDiscount in your order
  • If you want to calculate the total price of an order, you would have to iterate through all OrderLine and Product instances.

Of course, each of those problems can be solved some way or another, but whatever you do to solve them, it only adds to the complexity already there.

The immutable approach

Making the OrderLine immutable will solve some of the problems outlined above. The state of immutable objects is exclusively set in the constructor, meaning that both the Product and quantity will have to be passed as constructor parameters.

To solve the problem of the Product changing state, we can copy some of the important fields into the OrderLine. Good candidates for copying are the product identifier, the product name and its price. In fact, we don’t need any reference to the original Product instance at all after the OrderLine has been constructed.

The implementation of the immutable OrderLine is then changed into the following:

public class OrderLine {

    private final String productIndentifier;
    private final String productName;
    private final Price itemPrice;
    private final Price totalPrice;
    private final int amount;

    public OrderLine(Product product, int amount) {
        this.productIndentifier = product.getIdentifier();
        this.productName = product.getName();
        this.itemPrice = product.getPrice();
        this.totalPrice = itemPrice.multiply(amount);
        this.amount = amount;
    }

    /* getters not shown for brevity */
}

All problems solved? Well, no, not really. For starters, the last two problems enumerated above are still not solved. And then there is persistence. I use hibernate for nearly every project that requires persistence. Hibernate and immutable objects are not the best friends possible. Hibernate requires a non-private default constructor. Doesn’t seem like a problem, just add a no-argument constructor to you class. But then the final keyword ruins the game. You’ve got no other choice than to remove it. This removed the guaranteed visibility when your class is accessed by different threads at the same time. Solving that is a totally different ballgame and would carry me way off topic.

Using an aggregate root

We still have the problem that our discount is not updated when OrderLine instances are added or removed from an order. Making an order immutable in the same fashion would solve the problems. But let’s assume that a user is allowed to update and modify his orders as long they haven’t been processed by the system.

Exposing the list of OrderLine entries inside an order is not a good way to go, since your order is not in charge of its own lifecycle. If you take a close look at the UML diagram above, you will notice there is a composite relationship between the Order and OrderLine classes. This means that the Order class is responsible for the lifecycle of the OrderLine items that belong to it. In Domain Model terms, this means that Order is the Aggregate Root of these components.

The order would then be implemented as follows:

public class Order {

    private final List<orderline> orderLines = new ArrayList<orderline>();
    private final Customer customer;
    private Address shippingAddress;
    private Price totalAmount;

    public Order(Customer customer) {
        this.customer = customer;
    }

    public List<orderline> getOrderLines() {
        return Collections.unmodifiableList(orderLines);
    }

    public void addToOrder(Product product, int amount) {
        removeFromOrder(product);
        final OrderLine orderLine = new OrderLine(product, amount);
        orderLines.add(orderLine);
        totalAmount = totalAmount.add(orderLine.getTotalPrice());
        calculateDiscount();
    }

    public void removeFromOrder(Product product) {
        // implementation left to your imagination
    }

    /* rest of implementation left out for brevity */
}

As you can see, a high level of encapsulation has been applied. It is now impossible to change any state of the Order or OrderLine without the Order knowing it. The list of OrderLine items that the Order exposes is made immutable using the utility method in the Collections class.

With this implementation, it the latter two of the problems enumerated above have been solved. Since the order is in charge of making the changes to its own state, it is rather easy to discover state changes that might impact applicable discounts or change the total amount of the order. Now, getting access to the amount of the order is as easy as returning the totalAmount property from the Order.

Conclusion

In this post, I’ve introduced a very powerful concept to manage the state of complex domain models: immutability. By preventing the application to change state directly, you gain more control over the the actions that need to be taken when the state changes. Especially in aggregates, immutability reduces the complexity of state management.

However, when using Hibernate, it is impossible to make an entity completely immutable using the final keywords. In that case it is sufficient to create a default constructor with package visibility and removing the final keywords.

Tagged on:         

12 thoughts on “The power of immutability in a Rich Domain Model

  • March 15, 2014 at 7:25 am
    Permalink

    How about cyclical/bidirectional dependencies, such as representing a tree(parent/child) structure ?

  • November 9, 2010 at 1:22 pm
    Permalink

    Now, with new versions of hibernate you can use final fields and private default constructors, consequently, in private default constructor final fields can be set to null or any arbitrary default. because constructor is private, no ordinary code can call it, just hibernate.
    After calling private default constructor by hibernate , hibernate will directly set final fields from Data source. data source already contains valid data and thus entity created by hibernate is already valid.
    hibernate ability to set final variables, calling private constructors, and directly accessing field. are good features which enables rich domain model.

  • March 27, 2010 at 10:46 pm
    Permalink

    Well i have hibernate in my domain model. But im shifting to remove hibernate in the future. It breaks the domain model, even if i have the annotations on the field level. Besides letting hibernate inject and clutter the entities with freamwork specific annotations well annotations is a dependency in disguise! I can rabble on why not to use Hibernate (and annotations)in a big size application but that is another post ;)

    But this post gives a very good understanding about the power of domain models and aggregates and hey immutibility is the way to go for in all code :)

  • June 2, 2009 at 8:41 pm
    Permalink

    I just did a little quick research. Hibernate doesn’t have any trouble changing the value of a final field. In fact, you can just make persisted fields final and set them to null or 0 in the default constructor.
    However, I have no idea what this does to the multi-threading guarantees that final field provide. Typically, these objects are only “shared” among thread after they have been fully constructed and initialized by Hibernate.

  • May 19, 2009 at 5:23 pm
    Permalink

    I have an existing immutable domain model (immutable for a highly concurrent problem). I’m replacing the data layer with Hibernate (NHibernate) actually and have the same problem as you. As far as I can see my options, they are: treat Hibernate as the Data Access layer and load my existing immutable domain model from the Hibernate entities (treating Hibernate as the Data Access layer). Alternatively (and related), make my immutable domain model “wrap” the Hibernate entities, making them immutable.

  • May 17, 2009 at 9:35 am
    Permalink

    Zoran,

    thanks for your pointers. The problem I encountered (and I always use the field access method) is that Hibernate needs a no-argument constructor. I’ll try to see if I can initialize the final fields to some default values (0 or null) and see if hibernate can change the values even though the fields are final.

  • May 16, 2009 at 11:18 pm
    Permalink

    It is well worth to note that Hibernate (and possibly other ORM frameworks) do in fact work with immutable objects, but you have to set the access method to ‘field’. You may be wondering how can this help if your fields are final, well, since Java 1.5 they are not really final, checkout http://www.javaspecialists.eu/archive/Issue096.html .

  • April 12, 2009 at 11:00 pm
    Permalink

    Allard,

    Excellent post (as usual). It’s good to see good people paying attention to proper domain modeling again — perhaps we can start to get away from people being “Java” developers or “Ruby” developers or “Popular flavor of the day” developers and back to being software engineers for whom the exact implementation platform is a secondary concern.

    You are correct as well about the important role immutability can and should play in design. Not because immutability is a “cool” idea or a “best practice” (i.e. the consulting reason for doing things). But because, as your example shows, sometimes things simply shouldn’t change anymore. It is sometimes possible for an object to reach a terminal state after some time and in that case developers shouldn’t be so afraid to incorporate that fact into their software design.

    It is indeed a pity that frameworks like Hibernate and JPA don’t offer direct support for value objects or (semi-)immutable objects. This is, of course, the drawback of the fundamental choice such frameworks make to base themselves on JavaBeans (even if they call themselves POJO frameworks). As dlemoing points out, you can get part of the way in Hibernate (use a CompositeUserType implementation to persist or recreate your immutable object). Unfortunately that means having to embed the immutable object in a dedicated container object that is then itself a JavaBean. You can hide that detail within your repository implementation (to use Evans’ terminology), but it’s an awful lot of work.

    In any case, good stuff once again. Keep it coming!

  • April 7, 2009 at 4:03 pm
    Permalink

    Hi dlemoing,

    Thanks for you remark and links to Evans’ pages. Perhaps in Evan’s terms the OrderLine would be called a ValueObject, since it is fully immutable.

    However, you can imagine a state field on a line item to indicate the processing state of that item. In that case, part of the entity is immutable, the other part isn’t.

    My key point is that immutability is, in my opinion, often overlooked as an option to reach certain goals.

  • April 7, 2009 at 1:58 pm
    Permalink

    Sorry did not read the conclusion

  • April 7, 2009 at 1:58 pm
    Permalink

    Nice article. Will hibernate work with a immutable rich domain model ?

  • April 7, 2009 at 1:16 pm
    Permalink

    “However, when using Hibernate, it is impossible to make an entity completely immutable using the final keywords. In that case it is sufficient to create a default constructor with package visibility and removing the final keywords.”

    This is true for entities, not for components if you use a CompositeUserType :
    http://www.hibernate.org/hib_docs/v3/api/org/hibernate/usertype/CompositeUserType.html

    If you read Eric Evans book, you will see that Value Objects (components in Hibernate) should be immutable, not entities :
    http://domaindrivendesign.org/discussion/messageboardarchive/Entities.html
    http://domaindrivendesign.org/discussion/messageboardarchive/ValueObjects.html

Comments are closed.