The morning after

Sunday, June 18, 2006

Rich domain models: Immutability

Something which works well with rich domain models is immutability: don't allow client code to update an object instance, in other words: don't use any public setters on your domain objects (I recommend not using any setters at all, set your fields directly).

I've been thinking about this since a long time but I never dared to implement it because I somehow thought I would run into problems with this approach. When I attended SpringOne last week I saw a presentation where the speaker what advocating the same approach, this gave me the courage to go out and give it a try. I must say I was surprised how simple things were once I refactored all JUnit tests etc..

No setters ? Then what do I do when I want to update something ?

Well basically you would model a business operation returning a new object instance which has been constructed with the members set to the proper state. That way you don't update the current instance but simply copy (some of) its members over into a new one.

Note that you don't need such business operation for each member field, you should model an operation per use-case: if your application requires you to always change 3 fields at the same time then model a single operation which takes 3 arguments!

Tip: make sure you have a constructor taking the required properties and another constructor taking all properties so that it is easy for users to instantiate objects in a call.

Can my persistence engine handle objects without setters ?

It most likely can. In the case of Hibernate you can configure the access level in the mapping file, or by using the @AccessType annotation on your POJO (set it to 'field' instead of the default 'property'). Also: don't forget to have a (non-public) default constructor so that Hibernate can instantiate your POJOs.

Okay, my objects are immutable, now what ?

When using them you'll quickly see that working with immutable objects is actually simpler because you are sure client code cannot alter their state. This makes them thread-safe and avoids unnecessary validation checks throughout your code. Give it a try and see how it's more clear to work with them. Granted, you can't reuse an instance and call Session.update() (Hibernate) but you can still copy over the updated fields using Session.merge().

In my personal experience they are not simply straightforward but they also point out possible flaws in your architecture (too long to go into that right now, maybe in another post sometime), it seems that updating objects is more dangerous that one would think.

What about support for JavaBeans in other tools/APIs ?

You won't always be able to make use of them since they often rely on the explicit presence of paired getter/setter accessors. On the other hand, GUI frameworks such as JIDE support alternative implementations when using their bean forms, I've actually once worked with Map-based beans (no direct accessors, just getProperty(String) and setProperty(String,Object)) and adding support was as simple as implementing their Property interface and make sure it is used instead of their default BeanProperty implementation.

0 Comments:

Post a Comment

<< Home