Self-Development/Study

DDD의 Repository Pattern은 왜 사용할까

JeongKyun 2024. 6. 8.
반응형

# 서론

최근 많은 개발자분들이 Spring Data Jpa에서 제공하는 `JpaRepository`를 사용하면서 자연스럽게 DDD의 리포지토리 패턴을 사용하고있다. 이번글에서는 DDD의 Repository Pattern의 등장 배경과 개념, 그리고 적용시 얻는 이점들에 대해서 소개해보고자 한다.

 

# 본론

리포지토리 패턴이란?

리포지토리 패턴은 도메인 주도설계에서 중요한 역할을 하는 설계 패턴 중 하나이다. 이 패턴은 도메인 객체를 영속화하는 작업을 추상화하여 도메인 모델과 데이터베이스 접근 로직을 분리하는것을 목표로 한다.

 

등장 배경은?

DDD의 리포지토리 패턴은 복잡한 어플리케이션에서 다음과 같은 문제를 해결하기 위해 등장했다고한다.

 

1. 도메인 로직과 데이터 접근 로직의 분리

도메인 모델은 비지니스 로직을 담고 있게된다. 이 때, 데이터베이스와의 직접적인 상호 자굥이 도메인 모델에 포함하게 될 수 있는데, 비지니스 로직에 인프라 영역에 속한 기술적 관심사들이 많이 내포될 수 있게된다. 점점 복잡해져가는 도메인일수록 비지니스 로직에 기술적 접근으로 오염되어 코드가 복잡해지고 유지보수성이 떨어질 수 있다.

 

 

2. 테스트 용이성

데이터 접근 로직이 분리되면, 리포지토리를 테스트 대역을 통해 가짜 객체로 테스트할 수 있기때문에 도메인 로직을 독립적으로 테스트하기 쉬워진다.

 

 

3. 영속성의 투명성 (도메인 모델의 순수성 유지)

리포지토리를 통해 도메인 모델이 어떻게 영속화되는지 알 필요 없어진다.

이로써 순수한 도메인 모델을 (POJO) 형식으로 유지할 수 있게된다.

 

리포지토리 사용 방법은?

리포지토리 패턴을 사용하는 방법은 다음과 같다.

 

1. 리포지토리 순수 인터페이스 정의

도메인 객체를 저장, 검색, 삭제하는 메서드를 포함한 도메인 논리에 필요한 인터페이스를 정의한다.

public interface UserRepository {
    User findById(Long id);
    List<User> findAll();
    void save(User user);
    void delete(User user);
}

 

2. 리포지토리 구현 클래스 작성

인터페이스를 구현하여 실제 데이터베이스와 상호작용을 처리하는 데이터 엑세스 구현체를 만든다.

public class UserRepositoryImpl implements UserRepository {
    // 데이터 소스와의 상호작용을 위한 코드 (예: JPA, JDBC 등)
    // 예: EntityManager 등

    @Override
    public User findById(Long id) {
        // 데이터베이스에서 사용자 조회 로직
    }

    @Override
    public List<User> findAll() {
        // 모든 사용자 조회 로직
    }

    @Override
    public void save(User user) {
        // 사용자 저장 로직
    }

    @Override
    public void delete(User user) {
        // 사용자 삭제 로직
    }
}

 

 

3. 서비스 레이어에서 사용

서비스 도메인 로직은 순수 인터페이스의 리포지토리에 접근하여 구현한다.

public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User getUser(Long id) {
        return userRepository.findById(id);
    }

    public void createUser(User user) {
        userRepository.save(user);
    }

    // 그 외 도메인 로직
}

 

위와 같이 도메인 서비스에서 순수 인터페이스를 의존하여 필요한 제어 논리들을 정의하여 사용한다.

기존 서비스에서 JPA, Mongo 등 데이터 접근 기술을 사용하는 방식과의 차이는 의존 방향이다.

 

일반적인 방식을 도식화하면 아래와 같다.

 

이를 위 처럼 순수 인터페이스를 정의하여 구현체에서 데이터 접근 논리를 가져가게되면 아래와 같은 형식으로 변경된다.

위와 같이 기존 도메인 논리에서 데이터 접근 논리를 갖고있던것을 SOLID의 DIP를 이용하여 역전시킨 형태로 변경된다.

 

# 마무리

지금까지 리포지토리 패턴에 대해 정리해보았다.

현재 속한 조직에서는 저장소 패턴을 사용하며, 실제로 등장 배경에 나왔던 3가지 이점 모두 취하고있다.

 

마지막으로 리포지토리 패턴을 사용한다하면, Jpa나 Mongo 등만 떠올릴 수 있는데, 실제론 Elastic Search, SQS, Redis 등 저장소의 구현체로 만들어질 수 있다.

 

이제 시스템을 설계할 때 리포지토리 패턴의 개념처럼 순수한 도메인 모델을 유지하기위해 외부 계층(persistence, infra 등)으로부터 지켜내보자.

댓글

💲 많이 본 글