Thursday, November 5, 2015

The Controversial DAO Pattern

A few years ago, after the Java EE 6 specification had been issued, a big discussion about DAO pattern was started. A lot of top software architects and developers are involved, i.e. Adam Bien (also you can read more: Data Access Object--Reader's Questions). The idea is: 'the DAO pattern has become antiquated and now we should just inject JPA EntityManager in our EJB'. Let's try to get more about the question.




DAO pattern's responsibility is the data storage actions and business logic separation. Entire data saving, deleting, updating and retrieving logic is shipped into separated DAO-classes. The classes that encapsulate business logic (aka services) should call the DAO classes instead of a data storage API. This way can bring additional flexibility in the application design, so we can change the data storage when need it, i.e. replace ORM to pure JDBC or leverage a web-services based API, just by getting another the DAO-classes implementation.

Sounds good, but on practice we must pay addition effort for the flexibility. Let's have a look on the process of support some based on the 'service interface - service implementation - DAO interface - DAO implementation' idiom code. If we have to add a new operation to a service the following actions will be needed:
  • Add a new method to the service interface;

  • Add method's body to the service implementation;

  • Add a method to the DAO interface;

  • Add method's body to one or many DAO implementations.


And the majority of methods from the service implementation would look like the following piece of code:



We can see no business logic here, but the developer must execute four routines! Sounds not so good, do you agree?

But a very important thing is the DAO pattern doesn't provide the data store changing transparency! Each data store changing the way (from ORM to bare JDBC, from a relational database to a NoSQL solution, or even from a database to a web-service) brings troubles and some changes in the business logic layer may be needed. Let me show.


1. The 'ORM to bare JDBC' replacement. Modern ORM frameworks bring transparent persistence, so when an object had been loaded into the session and then some it's properties were changed, the new properties values is automatically (transparently) mapped to the database. But the transparency is not available while bare JDBC is leveraged and any new object's properties values must be manually synchronized with the database by using the appropriate DAO methods. So the business logic has to be changed.

2. The 'traditional relational database to a NoSQL solution' replacement. Almost NoSQL solutions don't provide the ACID properties for transactions. Implemented business logic has to be adapted to non-transactional storage. I.e. developers have leveraged the constraints magic into the database because they were able to use ACID transactions and the database just rollbacked all inconsistent changes. But if there isn't a transaction, the changed data are persisted even if the constraint conflict occurs. So, the database can be in an inconsistent state.

3. The same consideration is valid during the 'traditional relational database to web-services' replacement. Special approaches like WS-AtomicTransaction must be leveraged for transaction contexts transmission using web-services, but the approaches may bring some significant performance leaks.

Conclusion

You can't replace a data storage just by change the DAO implementation. Usually, the business logic layer also has to be changed. I see only one thing - one relational database can be easy replaced by another one, i.e. Oracle by DB2. But while a modern ORM tool is used, you can do it just replace one dialect string to another one. If you want to replace Oracle by Cassandra it takes more efforts regardless of DAO pattern using.

From another point of view, the DAO pattern brings some values.

  • There is the complex data access layer and testability is an important property of the system. If the application can work on different databases we can execute all tests against the H2 database for example, but if there is a tight bound between the application and the used database the situation is not so easy. The DAO pattern provides testability for the data access layer: we can just mock a database layer and test the DAO-classes only.

  • The DAO pattern provides testability for the business logic layer. We can mock for DAO objects and test only business logic.

  • When logic is very similar for a lot of data types. I.e. for integration applications when logic is simple: load data from one application and save it to another one. The logic can be encapsulated onto one service, which gets two parameters: one DAO object for loading the data and another one for saving. There is a pair of DAOs for every operated data type. In the above example, we leverage DAO pattern's value: polymorphism and flexibility. You can meet the approach in the Collection-based DAO on bare JDBC and Java 8 without JPA or Hibernate. Do you wish a piece of functional magic? article.

Do you use the DAO pattern?

Would you like to give a 'Like'? Please follow me on Twitter!