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.
How would you improve this Java class? #elegantobjects
— Yegor Bugayenko (@yegor256) March 31, 2019
class BooksDAO {
Book find(int id);
void save(Book book);
}