samedi 26 novembre 2016

Best practise to separate concerns when accessing database

I've been trying to improve the separation of concerns when it comes to applications that access a database (via Hibernate).

On one of the applications I've been using the following approach:

  • Create services with business logic that have no connection/awareness of the database. They only communicate with GeneralDAO (and with other services);
  • A GeneralDAO responsible for CRUD/find operations, and with methods that involve more complex database queries.

The problems I see with this approach are:

  • GeneralDAO slowly becomes a God Object, when your application grows and require lots of specific database queries.
  • Sometimes the more specific Services become only proxies to the GeneralDAO, since the method is simple and only requires a database query. See example 1.

Example 1: Service is just a proxy

BookService manages things related to books in the Library application. Let's consider 2 methods:

  • archiveBook(Book)
  • findByIsbn(String isbn)

In archiveBook(Book) there might be considerable business logic involved - we might imagine this involves calls to:

 distributionService.unbox(Book);
 archivalBook.archive(Book);
 librarianService.informNewBook(Book);

But findByIsbn(String isbn) is a lot more simple: it just needs to execute an SQL call to the database. So in this case I see two options:

  1. Redirect the call to an object that can speak to the database to execute the query. For example generalDAO.findByIsbn(String isbn), that uses a db communication layer (in Hibernate it would use a sessionFactory or EntityManager) to execute the query.
  2. Make that database layer available to the BookService, so that it executes the query itself

Questions/opinions (first number identifies the option above):

1.1. Isn't it strange to have 2 methods with the exact same signature, even if this is done to keep the BookService independent of the database layer (and ORM)?

1.2. How do you suggest avoiding The God anti-pattern? Would you suggest breaking the GeneralDAO into several DAOs depending on what the methods do? In this case, won't we risk needing to inject lots of DAOs into some Services, leading to a Service having too many objects injected into it?

2.1 What do you think of this alternative? Doesn't it break the "separation of concerns" by having the BookService be aware of objects at two different levels of abstraction (the DAO and the sessionFactory/EntityManager)?

3.1. Would you suggest any other approach/pattern/best practise?

Thanks!

Aucun commentaire:

Enregistrer un commentaire