Wednesday, December 12, 2007

How do you model a Domain Entity ?

Steve Freeman recommends using an interface for every domain entity in order to have a clean layering in architecture and no dependency between the domain and the persistence model of implementation. He does not mind if there is a single implementation for every interface and recommends his paradigm for expressing the needs of the domain code more clearly by limiting its dependency to an interface that defines just the services it needs from other parts of the system.

I am not sure if I agree to his principles. While not being a fanboy of interfaces-even-for-single-implementations club, I do not think using concrete classes for domain entities will incur any dependency between the domain layer and the persistence services. Standards like JPA backed up by ORM implementations like Hibernate provide transparent persistence services today, which can be plugged in non-intrusively into your domain model. I have indicated the same in the comments to his post, but just thought of having a separate post to make my point more clear.

Regarding data access using JPA, Repositories provide a great abstraction to encapulate them. While repositories belong to the domain services layer, they use domain entities and value objects to transport data across the layers of your model. Repositories also abstract away specific query languages like EJB QL or Hibernate HQL behind intention-revealing interfaces, keeping your domain entities free of any such dependencies. I had blogged about generic repository implementations to abstract away transparent data access code from domain models using the Bridge design pattern. All configuration parameters including EntityManagerFactories can be injected into your repository implementations through DI containers like Spring, keeping the domain model clean from these dependencies.

And JPA provides a nice standardized set of contracts to map your relational data model into your object-oriented domain entity class. All the annotations are from JPA, where you do not have to import any non-standard stuff into your codebase - all imports are from javax.persistence.*. And if you think annotations couple your code with the data model, go ahead and use XML for a completely transparent and decoupled model mapping. I have talked about the virtues of JPA based domain modeling and repository abstraction some time back.

Using transparent data persistence backing up your domain model, I tend to follow the policy of having one concrete class for every domain entity. I use JPA annotations for mapping domain model to the relational data model. This way the implementation adheres to the standards, and I have one clean artifact as my domain entity abstraction.

7 comments:

WarpedJavaGuy said...

I have to admit that I sometimes toy with the idea of modeling entity abstractions as interfaces in my mind. Every time that I do though, I come to the conclusion that it is just not natural for me to have to implement an entity more than once.

Anonymous said...

I think it's easy to miss the point re implementing interfaces. An interface is a means of tagging your entity as a certain type, regardless of its place in an API/extension hierarchy. I can see how this might conflict with the notion of "interface as behaviour", but the benefits become evident when IOC, testing, and mocking/proxying comes into the fray.

An interface "tag" for entity objects is very little overhead for much benefit, and frees up your architecture to focus on the solution.

Anonymous said...
This comment has been removed by the author.
WarpedJavaGuy said...

@LSM,

A pure "tag" or "marker" interface should not have any methods on it, right?

Anonymous said...

I've encountered some cases which required entities to have a corresponding interface.

For example, with Hibernate, if you try to cast a proxy of type A (lazy entity) to one of its subclass (say B), you'll get a ClassCastException because Hibernate generates a subclass of A for its proxy which is incompatible with B. However, if A and B are defined by interfaces, the proxy will implement all of them and casting works fine.

I know this is very specific, purely technical and that casting is not a good practice =)

Anonymous said...
This comment has been removed by a blog administrator.
Unknown said...

Sometimes models are difficult to design,so anyone who can help me design a model entity.help guys,am writing a test about it.