This is a mobile version, full one is here.

Yegor Bugayenko
5 December 2017

DAO is Yet Another OOP Shame

Someone asked me what I think about DAO and I realized that, even though I wrote about ORM, DTO, and getters, I haven't had a chance yet to mention DAO. Here is my take on it: it's as much of a shame as its friends—ORM, DTO, and getters. In a nutshell, a Data Access Object is an object that "provides an abstract interface to some type of database or other persistence mechanism." The purpose is noble, but the implementation is terrible.

Here is how it may look:

class BookDAO {
  Book find(int id);
  void update(Book book);
  // Other methods here ...
}

The idea is simple—method find() creates a DTO Book, someone else injects new data into it and calls update():

BookDAO dao = BookDAOFactory.getBookDAO();
Book book = dao.find(123);
book.setTitle("Don Quixote");
dao.update(book);

What is wrong, you ask? Everything that was wrong with ORM, but instead of a "session" we have this DAO. The problem remains the same: the book is not an object, but a data container. I quote my own three-year-old statement from the ORM article, with a slight change in the name: "DAO, instead of encapsulating database interaction inside an object, extracts it away, literally tearing a solid and cohesive living organism apart." For more details, please check that article.

However, I have to say that I have something like DAOs in most of my pet projects, but they don't return or accept DTOs. Instead, they return objects and sometimes accept operations on them. Here are a few examples. Look at this Pipes interface from Wring.io:

interface Pipes {
  void add(String json);
  Pipe pipe(long number);
}

Its method add() creates a new item in the "collection" and method pipe() returns a single object from the collection. The Pipe is not a DTO, it is a normal object that is fully capable of doing all necessary database operations, without any help from a DAO. For example, there is Pipe.status(String) method to update its status. I'm not going to use Pipes for that, I just do pipe.status("Hello, world!).

Here is yet another example from Jare.io: interface Base which returns a list of objects of type Domain. Then, when we want to delete a domain, we just call domain.delete(). The domain is fully capable of doing all necessary database manipulations.

The problem with DAO is right in its name, I believe. It says that we are accessing "data" and does exactly that: goes to the database, retrieves some data, and returns data. Not an object, but data, also known as a "data transfer object." As we discussed before, direct data manipulations are what break encapsulation and make object-oriented code procedural and unmaintainable.