‘Disappeared’ DAO layers

I might agree that for simple enough systems, it could end up being that in fact the service layers end up with PersistenceManager logic directly in their methods. But then I might say a language and framework like Ruby on Rails could suit your application better in that case. For any sufficiently complex Java-based enterprise system, a POJO-style data persistence layer naturally evolves, in order to reduce as far as possible the responsibilities the service layer must carry out.

As mentioned by commentators on his blog, the discipline of test-driven design is usually a strong driver of having a separated set of components that deal with persistence and other data concerns. Not just from the issue over mocking the PersistenceManager, which is certainly a strong driver, but also from design principles.

Service layers marshall requests from clients, and decompose them to call various component layers. Data access layers typically form part of these component layers. A TDD discipline means these data access layers usually end up with more than just CRUD operations.

Furthermore, as a matter of discipline, in any sufficiently complex service layer I prefer not to work directly with database abstractions (i.e. entities that are modelled on database tables and their relationships) but on first-class objects designed to fit directly with the modelled domain. I want those objects to have rich behaviour – the service layer is actually part of their behaviour. I want to start the design of the system by directly modelling those actions, e.g.

I do not want these objects to know about database semantics. That is a responsibility of a separated persistence layer, which we may for convienience sake, called the DAO. Even if internally we end up with;

DispatchCentre at this level, is a service, but we will model it as part of the domain of passengers, locations, and vehicles. Behind that service, it will have a database layer with the semantics as to how it saves and loads the data concerning passengers, locations, and vehicles. I don’t necessarily want the client objects (e.g. the web action) to have to deal with JPA annotated objects. They just deal with objects as much as possible. And I don’t see there’s anything served with developing possibly complex persistence logic directly in the DispatchCentre. In fact, taking a top-down approach, I know pretty much I won’t do that.

Only after I’ve done this initial part of the modelling, will I be concerned as to which of these components can be directly JPA or Hibernate annotated, which are Spring-injected services, which are Session EJBs, and the like. I think starting your modelling from the point of view of having a persistence framework like JPA or Session EJBs or any other ‘archtectural artifact’ leads to an unnatural design.

11 Comments

“I might agree that for simple enough systems, it could end up being that in fact the service layers end up with PersistenceManager logic directly in their methods. But then I might say a language and framework like Ruby on Rails could suit your application better in that case.”

Does it mean: all Rails applications are either simple or not maintainable/testable?

“Does it mean: all Rails applications are either simple or not maintainable/testable”

Certain not! Rails apps are very testable. I just mean they are suited more simple architectures than Java web apps.

What I mean overall, and what I probably should have just said, is that as developers we should follow are standard set of practices and disciplines and build our apps with TDD, programming-by-intent and so forth until we are finished. I find When I use these methods that ‘infrastructure’ issues (such as where JPA fits) tends to recede into the background. I don’t like putting persistence methods on my service classes, otherwise the service class becomes very quickly cluttered. So a natural ‘DAO’ object layer emerges from this. I also have a strong prejudice against JPA or hibernate annotated objects ‘escaping’ the persistence layer. I find it disconcerting that the client layer would require a dependency on persistence infrastructure.

Not having persistence logic abstracted => Mixing different concerns in one big service => makes it hard to test the service, because the databse abstraction must be there and cannot be simply mocked away => as the system grows applying this pattern leads to unmaintainable and untestable messy code that will drive you into unhappiness, kill your productivity and will make the project fail

Search for “Misko Hevery” (a Test Engineer at Google) on Google Video to have your eyes opened. Those videos made me a TDD-guy, because I finally saw what was wrong with my code structuring.

No being able to replace an implementation of a specific concern e.g. by using DI and interface-driven-design, with a ‘seam’/mock/test-spy is the dead end for testability. This is exactly what happens when you use EntityManager inside your services. Mixing Services with EntityManager-data-access leads to untestable code. No excuse, end of story.

I think it’s a mistake that any client of a service layer has to also import, for example, org.hibernate.* – javax.persistence is a little bit less pernicious than hibernate, but only slightly. I really don’t like such persistence artifacts escaping the layers that are directly dealing with them. Why should a Struts action or a Tapestry page class (etc) be concerned about hibernate or any other database semantic? The point of layering is to isolate concerns. So for me, this means, if you want domain classes to also be your persistence model, no annotations (generally speaking). Cfg files I can live with, and in fact, over the past while I have increasingly leaned towards using e.g. .xbm configuration to map the domain classes to the database and have moved very much away from annotations to do it (this is also to do with what I see as the poor readability of the Java 5 extensions).

I also think, that it’s a huge mistake to assume that a domain model will exactly match the most performant or otherwise optimum relational model of the data. There is a fundamental mismatch – sometimes (and sometimes it’s not, in which case I’ll lean to the solution above). Also sometimes, you might have a relational persistence model forced on you by an already-existing database. To just assume, that the model that you can use to describe the functioning of the system (as for example illustrated in my rather twee taxi-ordering example above) is the same one as storage of the data is a big mistake (again, sometimes, not always). I find, as you develop a system, driven by its domain description, you want to be able to rapidly evolve the domain model in ways that may be incompatible with the slower evolution of a database structure and it’s normalised form (or for example, its highly optimised and specialised, relational form – especially if the database is already ‘legacy’ and can’t be changed as easily as the OO domain model).

I use xml mappings in place of annotations too, but mostly because of preference. I can’t see how using annotations would make the client import javax.persistence stuff though.

For your next point, I haven’t been so far imposed a legacy schema to work on, yet still I think that that is exactly the value ORMs should be providing. The mapping of the database relational data to the actual application model. If a whole another layer of classes, in addition to the metadata, has to fit between the ORM and the model then IMHO something is not very right.

To make myself clear, I don’t say that I always use pure entities in the client. It depends on the use case. For example if I had to display a complex grid of entities along with some of their relations and other computed details, I would probrably use a wrapper object (DTO if you will)..

As I state in the article, I prefer to work (though not always – depends if I’ve got a ‘clean slate’ or not among other things) by modeling the target domain first in a TDD fashion. The main reason is that you can usually actually model (i.e. test then write) a surprising amount of behavior in the system before you even have to consider an actual functioning persistence mechanism!

I guess that’s maybe another reason why I think declaring the-service-does-the-persistence to be the wrong idea – it’s putting the persistence methods ahead of the business problem domain.