The vendor of your database changes?
You will have to replace your relational database with LDAP, flat files or object oriented storage?
You will have to replace JPA with iBatis or even plain JDBC?
You will have to replace your local storage with remote service calls?
The questions above are interesting and valid, but how likely is such a case? The architecture (even real live) is all about probability. If something is likely to happen, we react to it. If something is rather unlikely, we tend to ignore it. In my past projects, only in (very) few cases we had to switch the database vendor.We never switched from a relational database to a flat file or LDAP. I guess it is unlikely in the future as well. Interestingly the real problem during the migration from one relational DB to another was not the leaky encapsulation of SQL statements or hiding classes behind interfaces, rather than different locking behavior, which just cannot be hidden or abstracted with Java-means. Most projects are concerned about the answers for the questions above and introduce DAOs, which are especially leaky by nature. Locking behavior is one thing, semantic behavior is even harder to abstract. A typical DAOs operates "per Value", whereby OR-tools work with managed / attached objects. If you start to emulate such a behavior for e.g. flat files, you will either fail, or eventually implement Hibernate 5.0.
My post "JPA/EJB 3 Killed The DAO" was not precise enough. In some situations even the classic DAOs are still a good solution, but for the vast majority of all cases and projects are absolutely not. If you are developing a product, like e.g. a CMS software, it is essential to be as flexible as possible to survive in a heterogenous market. A DAO could help you to abstract from the particular data source, but such abstractions are leaky by nature. The variations of different data sources is already predefined by the system requirements of your product. You have to protect your business logic from being dependent on the particular data store implementation. DAO can help you to abstract from the variations. Even so, in most commercial products a particular database tend to be better supported, than the other. Just look at the Hibernate, Toplink or openJPA support for a particular database.
>> In a usual projects there is no need to introduce a DAO as as standalone component.
'usual project' for us means at least JUnit-Testable. And this (in my opinion) quite forces you (sooner or later) to introduce a DAO-layer, just because you need to 'delegate the calls to a class which encapsulates common queries'.
- no architecture overkill, it's just one more well defined class, with code, that'd be cluttered elsewhere anyway.
- totally in harmony with your article '15 tips on JPA Rich Domain Modelling' - if you really created such a domain model (JUnit-tests inclusive of course) you are forced to abstract the 'finding of objects' to a switchable class, to leave your higher level-tests without a db-connection.
"Your comment was marked as spam and will not be displayed. Comment has more than 1000 characters"
1. Yes, I have to disable the 1000 characters limitation somehow - it rollerweblogger default setting -> sorry for that.
3. I (mis)use JUnit to test the Service with inherited or standalone DAO, which access a local (Derby, H2 or an virtualized image). I do not mock out the EntityManager. Because it is injected, however, you could easily mock it out.
I have to agree with Stefan. Unit-Testing is a main reason for keeping the DAO.
Testing your Data-Access: It has value to test your data-access separately (as you say yourself in '15 tips on JPA Rich Domain Modelling'). This is cleanly possible by institutionalizing DAO-Components that have their own Unit-Tests.
Also I still believe in 'Separation of Concern' to get a grip on complexity. I would argue that separating data-access out of your business code does usually decrease complexity of your business code.
- object design principles : 1 class 1 responsability. If data access code is put in the service layer it can quickly become bloated. Testing is also easier.
I could live with a generic_crud_component for testing.
But then its matter of taste if you like to have a lot of constants for your named queries.
I always have the 'Repository' from DDD in mind as well when thinking about what is left of the DAO.
- all query-code naturally belongs to DAOs. This isn't any overhead, just some code structuring because we all like clean nice classes (interfaces are only introduced when really needed of course).
"all DAOs/Repositories are beans themselfes, a client just needing some data, doesn't need to ask some service ... it goes directly to the DAO (=fast lane reader adapted to ejb3)"
Exactly - this is why I used "collapsed" in the title. DAOs collapse with Services for simpler user cases. For complex business logic DAO become just the product of refactoring.
"...any architect demanding 3-tier-architecture will be happy as well"
"Then you could easily use the EntityManager directly in your Service layer and if you notice some repetition or duplication just to refactor the code into one place"
I tried this once and it killed testability. When I moved all data access code into DAOs, I was able to unit test my service layer in isolation. I use a GenericJpaDao, and for entities that had named queries I create a new DAO for them that extends the generic one, and adds methods for calling the named queries so that the caller doesn't see anything JPA.
is an EntityManager already a repository :-)?
@Adam: What do you mean? The service knows nothing about the technologies that provide data access, it just uses DAOs. In fact there are about 5 DAOs the service uses. One of them talks to a JCA connector to a legacy EIS, and there are several other DAOs to read/write data to tables in several databases. The transaction demarkation is managed by the service. By completely decoupling the service from JPA and JCA connector I am able to cleanly unit test the service.
BTW the service is pure business logic. It is the brains of the system.
in your case: perfect. The service has dedicated responsibility. What I often see in projects are "empty" services which mainly delegate all calls to a DAO. In this case DAO and Services can just collapse. Btw. it is always a good idea to introduce DAOs for accessing JPA incompatible resources. Then you will even need "integrational' logic. The responsibility of the DAO is decoupling from particular technology - what is perfect. EntityManager is already a DAO - it not only decouples from SQL but even different JPA-providers. You will have good reasons to encapsulate a generic DAO with more specific DAO.
and what is exaclty the business logic in CRUD usecases or simple masterdata management?
The business logic does many things. For example, you call into the service asking to find a reservation and it knows how to look through many data sources to locate it, load complete data from several other sources, translate error codes and exceptions, etc. so you have just one simple call to the service to load a reservation. It also has methods that performs business logic on input based on system settings and other live data.
One very important fact is missing here, what if you want to migrate from Java to .NET or maybe Ruby? dao wont have you, you better learn now .NET and Ruby, because you might migrate to it next month!!!!
What you say makes good sense. Right now I have a separate DAO layer purely for the sake of separation of concerns but moving on I plan to seriously revisit this separation and potentially blur the lines.
Frankly I think most of the problems with DAO and JPA comes from the use of the JavaBeans pattern. If JPA uses constructor injection we'd be able to do some major cleaning.
Our I.T. project simply uses Spring/JDBC API which maps to a Data Transfer Object (POJO JavaBean) and then gets displayed with JSTL tags (or Struts tags for one step further when using a form bean). It's a simple design with DAOs and DTOs - what's superfluous and outdated about that? I spent most of my career creating web applications this way. If you work in a big I.T. organization, they are so resistant to change, scenarios 1-4 are unlikely. Besides, all our DAO calls are to database stored procedures instead of SQL statements.
At first I think the idea not using DAO is extreme, but when think again it's possible to reduce DAO to reduce abstraction levels (especially when domain model is not much complex and the service is mostly delegation to DAOs) .
It's easy to grasp the whole architecture, also !
"" In fact there are about 5 DAOs the service uses. One of them talks to a JCA connector to a legacy EIS ""
It's all about services. What we call DAO or Repositories, are SERVICES. But with different responsabilities.
In case of Repositories, they are persistance services.
The "3-tier architecture" sent us in the wrong way. There is no such things as "layers". The fact that business services depend on persistance services, does not imply "layers".
And here it is : if your EIS does not expose a pure CRUD service, you should not suffix your class with *DAO/*Repositories !!