Sharing Our Passion for Technology
& Continuous Learning
Rethinking the DAO-Service layer relationship
Lately I have been thinking that the standard service-calling-the-dao-layer architecture hasn't been working out as well as I would hope. The applications I have been working on have been using Spring and Hibernate with a dao object per model object. While this does provide a good separation between the two, I have been finding it increasingly difficult to write good tests for the service layer as the project matures. Past experience has shown that if writing tests is difficult, then it just isn't done. Follow along as I think about possible ways to address this issue.
Let's look at what I consider to be the 'standard' service layer object.
public class ServiceExample1 {
private FooDAO fooDAO;
private BarDAO barDAO;
public void searchForFooAndBar() {
//
// do some stuff
//
fooDAO.searchForFoo();
//
// do some more stuff
//
barDAO.searchForBar();
//
// finish up doing stuff
//
}
public void createANewFoo(Foo foo) {
fooDAO.createFoo(foo);
}
public void createANewBar(Bar bar) {
barDAO.createBar(bar);
}
}
A couple of methods are defined, and they use two difference dao objects. Writing a test for the searchForFooAndBar method would currently involve providing alternative implementations for both the FooDAO and BarDAO objects. While this initially wouldn't be too difficulty, it is easy to imagine how the number of dao dependencies could grow as the project goes on. It could also cause problems since we wouldn't know which methods in the dao needed to be stubbed out or mocked for testing. I also worry that it would be too easy to test implementation instead of behavior. A test failure would be reported if the service changed which dao methods were called.
Another issue I've run into is not knowing which dao's are involved in a method when writing the test. My initial thought was to not have the service object maintain references to the dao objects, but instead have each method require them as method parameters.
public class ServiceExample2 {
public void searchForFooAndBar(FooDAO fooDAO, BarDAO barDAO) {
//
// do some stuff
//
fooDAO.searchForFoo();
//
// do some more stuff
//
barDAO.searchForBar();
//
// finish up doing stuff
//
}
public void createANewFoo(FooDAO fooDAO, Foo foo) {
fooDAO.createFoo(foo);
}
public void createANewBar(BarDAO barDAO, Bar bar) {
barDAO.createBar(bar);
}
}
Looking over this code, I didn't care for it from the start. Maybe if the service layer objects were finer grained. Instead of three methods in the service from our first example, maybe there should be 3 service classes.
public void searchForFooAndBar() {
//
// do some stuff
//
fooDAO.searchForFoo();
//
// do some more stuff
//
barDAO.searchForBar();
//
// finish up doing stuff
//
}
I think this would help fix the problem of having too many dao references, but I still wasn't sure I liked the dependency on the dao's themselves. That brought me to the final solution I thought of, which involves creating an interface for each method that defines the operations it requires to be provided.
public interface FooCreationAdapter {
public void createFoo(Foo foo);
}
public interface BarCreationAdapter {
public void createBar(Bar bar);
}
public interface SearchAdapter {
public void searchForFoo();
public void searchForBar();
}
public class Service {
public void searchForFooAndBar(SearchAdapter searchAdapter) {
//
// do some stuff
//
searchAdapter.searchForFoo();
//
// do some more stuff
//
searchAdapter.searchForBar();
//
// finish up doing stuff
//
}
public void createANewFoo(FooCreationAdapter adapter, Foo foo) {
adapter.createFoo(foo);
}
public void createANewBar(BarCreationAdapter adapter, Bar bar) {
adapter.createBar(bar);
}
}
While I feel this is the cleanest solution that would be the easiest to test, I really don't think it is practical on a project level. Does anyone have a solution that has worked well for them?