Thursday, September 20, 2007

Domain Modeling with JPA - The Gotchas - Part 1 - Immutable Entities

Working on rich domain models, how many times have we wondered if we had a cookbook of best practices that discussed some of the common gotchas that we face everyday. With this post, I would like to start a mini series of such discussions, which will center around issues in rich domain modeling using JPA and Hibernate. In course of this series, I will discuss many of the problems, for which I have no satisfactory solution. I would love to have the feedback from the community for the best practices and what they feel should be done to address such issues.

Each installment of this series will discuss a single issue relevant only to designing rich domain models using JPA and Hibernate. With enough reader feedback, we should be able to have a healthy discussion on how to address it in the real world of domain modeling using the principles of Domain Driven Design. The topic of today's post is Immutability of Domain Entities and how to address this issue in the context of modeling persistent entities. While no one denies the fact that immutability is a virtue that a model should maximally possess, still there are practical concerns and reasons to act otherwise in many situations. The domain model is only one of the layers in the application architecture stack - we need to interact with other layers as well. And this is where things start getting interesting and often deviate from the ideal world.

Immutability (aka public setter methods)

There are two aspects to immutability of entities.

#1 : Making an Entity intrisically Immutable

An entity is immutable in the sense that *no* update or delete are allowed for that entity. Once created the entity is truly *immutable*. The Hibernate annotation @Immutable can be used to indicate that the entity may not be updated or deleted by the application. This also allows Hibernate to make some minor performance optimizations.

@Immutable
public class Bid implements Serializable {
  // ..
  // ..
}


Needless to say, we do not have any setter methods exposed for this entity.

Immutability can also be ensured for selective columns or properties. In that case the setter method is not exposed for this property and the ORM generated update statement also does not include any of these columns.


@Entity
public class Flight implements Serializable {
  // ..
  @Column(updatable = false, name = "flight_name", nullable = false, length=50)
  public String getName() { ... }
  // ..
}



For the above entity, the name property is mapped to the flight_name column, which is not nullable, has a length of 50 and is not updatable (making the property immutable).

#2 : Immutable in the domain layer

This is one of the most debated areas in domain modeling. Should you allow public setters to be exposed for all entities ? Or you would like to handle all mutations through domain methods only. Either way there are some issues to consider :

If we expose public setters, then we risk exposing the domain model. Any component in the layers above (e.g. Web layer) can invoke the setter on the entity and make the domain model inconsistent. e.g. the Web layer may invoke account.setOpeningBalance(0), despite the fact that there is a minimum balance check associated with the domain logic. We can have that validation within the setter itself, but ideally that domain logic should be there in the domain method, which is named following the Ubiquitous Language. In the current case, we should have a method named account.open(..), which should encapsulate all the domain logic associated with the opening of an account. This is one of the fundamental tenets of rich domain models. From this point of view, smart setters are an anti-pattern in domain modeling.

If we do not have setters exposed, then how will the Web MVC framework transport data from the Form objects to the domain objects ? The usual way frameworks like Spring MVC works is to use the public setter methods to set the command object values. One solution is to use DTOs (or one of its variants), but that is again one of the dark corners which needs a separate post of its own. We would definitely like to make a maximal reuse of our domain model and try to use them throughout the application architecture stack. One of the options that I have used is to have public setters exposed but control the usage of setters only in the Web MVC layer through development aspects. Another option may be to introduce public setters through Inter Type Declaration using aspects and use the introduced interface in the Web MVC layer only. Both of these options, while not very intuitive, deliver the goods in practice. You can do away with exposing setters *globally* from the domain model.

What about getters ? Should we have

Collection<Employee> getEmployees() {
    return employees;
}


or

Collection<Employee> getEmployees() {
    return Collections.unmodifiableList(employees);
}


In the former case, the collection returned is not immutable and we have the convenience of doing the following ..

Employee emp = ...  // make an employee
office.getEmployees().add(emp);  // add him to the office


while all such logic will have to be routed through specific domain methods in case of the enforced immutability of the returned collection for the second option. While this looks more ideal, the first approach also has lots of valid use cases and pragmatic usage.

Use the comments section of the post to discuss what approach you take when designing rich domain models. There may not be one single golden rule to follow in all scenarios, but we can know about some of the best practices followed in the community.

13 comments:

bge said...

Here's what I do. Forget about using setters for data transfer from JPA to your domain model; annotate the fields directly. Alternatively, if you need to mess around with the data coming from the database, create a private setter with a different name (say, the name of the property + Internal).

Then you are free to provide setters or not in the domain model. Those can validate incoming data, do extra work, etc. etc. without interfering with JPA's work.

My point of view is that JPA's persistence of your objects is similar to Java serialization, and thus there is no concern of violating encapsulation.

The same reasoning applies to getters.

Unknown said...

@bge: Direct field access decouples the setters from JPA - agreed. But exposing public setters put your domain model at risk. Ideally domain logic should be within domain methods (i.e. methods which speak the domain language), e.g. account.setBalance(..) is an implementation setter for setting balance. While the public api for actual setting of balance should be methods like account.debit() or account.credit(). Smart setters may not be the best idea around.

However, as I mentioned in the post, without exposing setters, you cannot reuse the domain model as command objects to web frameworks like Spring MVC. Your take on that ?

Anand said...

hi Deb,

This is a really interesting topic especially with a resurging interest in domain driven development. Keep the topics coming. I think another big topic could (perhaps at a more fundamental level) what kind of business methods would you like to see okn your domains.

To the current topic my 2 cents

(first cent) I think immutability is going to be of less concern in your enterprise applications.
In most enterprise application you package your domain and service together and expose it as a package. So even though the domain offer mutuable entities it is your service layer which is going to be responsbile for fetching / modifying the domain objects. By opening and closing sessions in the view you have more control over which layer is going to modify the domain objects. Hence in this case you effectively prevent modifications on your domain model from your web tier. Surely you will have issues when people modify the domain model in the service layer but they will be caught during testing and fixed

(2 cent) people do look at apis. While you provide mutuable properties if you also provide an additional domain methods to add a Bid to an Item or say adding an employee to a role I am thinking that developers would be inclined to use such an approach

Cheers
anand raman
http://scattered-tidbits.blogspot.com/

Anonymous said...

The web application layer should not impose or dictate any constraints or contracts on the domain model. This includes the mandating of public setters. If the domain model does not need setters, then it's best to not introduce them. The same goes for getters. If the domain model was designed to operate on mutable collections returned by getters then so be it.

Inter-type declarations and any other forms of AOP magic is the way to go. Especially given that in your experience it "delivers the goods". Spring and all other DI frameworks provide these mechanisms for this very purpose. This gives us the ability to morph domain objects into DTO's and value objects in the layers of concern. This indirect approach may not be the most intuitive but it does localize the risks associated with exposing public setters and mutable getters globally and eliminates the need for boilerplate code. Domain objects can be used across multiple layers on an "as is" basis. The root entities in the domain layer will ultimately validate their state and check the invariants.

Unknown said...

@warpedjavaguy: I agree with you on most of your points. Having domain entities NOT exposing public setters is always the way to go, since it takes a lot of headache away from your concern that the domain model may be inadvertently mutated. The concern here is to have the MVC framework have access to the setters. I am all for using the domain model across all layers and using the domain entity as the Command Object in Spring MVC. In fact that is what has been recommended in the flagship book on Spring MVC as well. Hence I suggested using the AOP magic. Anand in his comments have suggested relying on programmer discipline to enforce this constraint. While it may work in some situations, but for a large project, it is difficult to scale.

Anonymous said...

>Anand in his comments has suggested relying on programmer discipline to enforce this constraint.

A rich domain model should comprise of both services and entities in a single domain layer. I hope that one day with DDD, more (if not all) programmer discipline is focused on programming the domain and less (if any) is focused on other layers and concerns. In the ideal scenario we would be able to independently program the domain layer in isolation and then integrate it with all other layers (including Spring MVC web layers) in the most declarative and/or indirect ways possible.

Looks like you've been doing some interesting DDD work Debasish. I've only just recently started reading about DDD. It's good and inspiring to read about your experiences.

Unknown said...

A rich domain model should comprise of both services and entities in a single domain layer.

+1. The most important part of this layering is to protect the domain model from inadvertent mutation, which is very much possible in the presence of public setters. I used various AOP tricks in one project, and it worked. Just wondering what are the best practices in the community today. I do not want to expose public setters in my domain model just for the sake of the MVC framework transporting data to forms using them. At the same time I do not want to go back to the DTOs and have an additional behaviorless layer in my architecture. Recently there has been some discussions regarding ROO in the Spring community. ROO uses dozer for automatic generation of DTOs. Personally I do not like this approach, since we still are having these additional objects polluting the model.

Anand said...

hi all,

In my opinion the service layer should be on top of the domain layer. You wouldnt like every external client direct access to your domain model. You would either like to restrict access or expose the service in a different way. I am not arguing the fact that the domain model shouldnt be rich and functional. That goes without saying. However the service layer helps as entry points into the domain model especially when you would like to do remote calls.

One additional use case where the service layer could complement the domain model is by assembling the results by filtering with an external source. Assume that while you have a functional domain model you need to filter the results from a query with the results from a webservice. I would ideally like such result assembly to happen in the service layer rather than the domain layer.

thanks
anand raman

Anonymous said...

Debasish,
In support of your ideas about the direct reuse of domain objects, I have posted some of my thoughts about grasping DDD (normally I'd trackback but it seems your blog doesn't support it).

Anonymous said...

@debasish

In advance: very, very nice work so far! You solved a lot of my problems!

But the problem with eg. spring mvc remains, am I right? I haven't found a solution either. Did you in the meantime?

Unknown said...

@logan
For collocated business and view layers I use the strategy of using development aspects that prohibit using setters in layers other than the MVC one. This has worked out nicely for me so far.

Cheers.

Ashkan said...

Hi debasish,
Thanks for nice mini series. Why not using interfaces (contract that contains only legal mutator biz methods) for introducing entities to upper layers? This way they won't know about setters so can't misuse setters too.

Unknown said...

@ashkan: Hiding every entity behind an interface often leads to too many spurious interfaces and a bloated design. But, you are correct, for specific cases I do use interfaces to hide some of the setters in entities. But my interfaces are often at the level of aggregate roots, rather than individual entities. But still u need some ways to prevent usage of public setters in upper layers.