영호
DAO(Data Access Object) 본문
개요
우테코 미션을 진행하면 dao에 대해 공부하면서 dao를 적용했을 때의 장점을 생각해봤습니다. 잘못된 내용에 대해 피드백 해주시면 감사하겠습니다 ㅎㅎ
DAO
baeldung의 dao관련 글을 보면 아래와 같은 문구로 시작한다.
The Data Access Object (DAO) pattern is a structural pattern that allows us to isolate the application/business layer from the persistence layer (usually a relational database but could be any other persistence mechanism) using an abstract API.
간단하게 요약해보면, “추상 API를 사용하여 business계층과 persistence계층을 분리할 수 있는 구조적패턴”이다.
핵심은 business계층과 persistence계층의 분리, 추상 API라고 생각한다. 이 2가지에 대해서 간단하게 내 생각을 정리해보려고 한다.
계층 분리
dao를 통해 영속성 관련 변경은 persistence계층에만 영향을 끼치게 된다.
나는 business계층의 관심사는 business로직 수행 + 데이터 영속화 요청이라고 생각한다. 그러나 데이터를 어떤 방식으로 영속화하는지 까지 알 필요는 없다고 생각한다. 단지 저장해줘, 조회해줘, 수정해줘, 삭제해줘의 요청만 해야지 구체적으로 sql을 이용해 저장하는 것은 너무 많은 책임을 가진다고 생각한다.
만약, business계층이 JdbcTemplate과 sql문을 정의해 직접 데이터를 저장하고 있다고 가정해보자. 테이블의 구조가 변경되면 이 영향은 persistence계층이 아닌 business계층에 영향을 끼친다. 그리고 business요구사항의 변경도 business계층에 영향을 끼친다.
그러나, dao를 이용해 계층분리가 이루어진 경우 테이블 구조의 변경으로 영향을 받는 것은 dao가 존재하는 persistence계층 뿐이다. 왜냐하면 구체적인 영속화 작업은 dao에서 이루어지기 때문에, 테이블 구조 변경으로 인한 query수정은 dao에서만 수행하면 된다. dao를 통해 business계층은 dao에게 ‘영속화해줘’라고 요청할 뿐 구체적인 방식은 모르게 된다. 이처럼 dao를 통해 고수준인 business계층과 저수준인 persistence계층을 분리해 영속성 관련 변경의 영향은 persistence계층에만 영향을 끼치게 된다.
추상 API
나는 baeldung 글을 보면서 추상 API라는 말이 마음에 걸렸다. 왜 추상화한 DAO를 통해 business계층과 persistence계층을 분리할까? 그냥 dao로만 분리해도 충분히 관심사의 분리가 이루어진 것 같기 때문이다.
만약, businiess계층이 MySQL을 이용한 구체 dao클래스에 의존하고 있는 상황에서 테스트를 위한 InMemoryDao가 필요하면 어떻게 될까? InMemoryDao를 추가 구현하고 business계층의 dao의존 코드에 수정이 필요하다. 또한, business계층은 persistence계층에게 “MySQL을 이용해 영속화 해줘”로 요청하게 된다. business계층은 persistence가 어떤 방식으로 데이터를 영속화하는지 알 필요가 있을까?
난 알 필요 없다고 생각한다. business계층은 데이터가 영속화되는 것만 궁금하지 MySQL벤더 사를 이용하든, PostgreSQL벤더 사를 이용하든, InMemory방식으로 영속화하든 관심이 없다.
그러나, 추상화된 DAO를 사용하지 않으면 business계층은 MySQL API를 사용하는 구체 클래스인 MySQLDao같은 것에 의존하게 될 것이다. 이것은 business계층이 persistence계층에 대해 과하게 알게 된다. 즉, 강하게 결합하게 된다. 이와 같은 구조는 확장성이 떨어진다는 단점이 있다.
위 구조를 추상화를 통해 service가 Dao인터페이스에 의존하게 한 뒤, 이를 구현한 클래스가 존재하면 확장성 측면에서 이점을 가져갈 수 있고, service는 구체적인 영속화 방법에 대해 모르게 된다.
예시 코드
GameDao.java
public interface GameDao {
public Long createGame(final GameSaveDto gameSaveDto);
public List<GameWinnerDto> findAllGames();
}
JdbcGameDao.java
public class JdbcGameDao implements GameDao{
@Override
public Long createGame(final GameSaveDto gameSaveDto) {
// 저장 로직
}
@Overrid
public List<GameWinnerDto> findAllGames() {
// 조회 로직
}
}
GameService.java
public class GameFindService {
private final GameDao gameDao;
public GameFindService(GameDao gameDao) {
this.gameDao = gameDao;
}
}
마무리
dao에 대해 고민해보면서 추상화된 API를 이용해 dao를 분리하면 위와 같은 장점이 있다는 생각이 들었다.
그러나 추상 API의 경우 아직 막 와닿지는 않는다. 과연 ‘데이터베이스 벤더 사를 변경하는 경우가 자주 있을까?’라는 생각이 들었고, 테스트를 위한 InMemoryDao역시 mock을 사용하면 되기 때문이다.
추상화를 적용하는데 비용이 들어가기 때문에, 아무 생각 없이 추상화를 하기 보단 변경 가능성을 따져야 하는데 아직까지는 추상화를 적용하는 이유가 벤더사의 변경이라는 생각이 든다. 그리고 해당 변경 가능성은 낮다는 생각이 든다.
그러나 첫 번째 장점이라고 생각한 계층분리는 확실한 장점이라고 생각한다. dao를 통한 계층 분리로 business계층은 business로직에만 집중하고, persistence계층은 CRUD에만 집중해 개발할 수 있다.
참고자료
'OOP' 카테고리의 다른 글
[OOP] EnumMap과 함수형 인터페이스로 커맨드 패턴 적용해보기 (0) | 2023.03.26 |
---|---|
다형성이란? (4) | 2023.03.11 |
[OOP] SOLID - DIP(의존성 역전 원칙) (2) | 2022.12.23 |
[SOLID] ISP(인터페이스 분리 원칙) (0) | 2022.06.07 |
[OOP] SOLID - LSP(리스코프 치환 원칙) (0) | 2022.06.05 |