[DDD] REPOSITORY(리파지터리)

0️⃣1️⃣·2024년 2월 3일
0

DDD

목록 보기
4/22

필요성

우리는 연관관계를 토대로 다른 객체와의 관계에 근거해 특정 객체를 찾을 수 있다. 그러나 객체의 생명주기 중간에도 ENTITY나 VALUE를 탐색하기 위한 진입점이 있어야 한다.

데이터베이스 검색은 어디서든 이용할 수 있으며, 곧바로 어떠한 객체에도 접근하게 해준다. 모든 객체가 상호 연결돼 있을 필요는 없으며, 이로써 우리는 관리 가능한 객체망을 유지할 수 있다. 탐색을 제공할 것이냐, 검색에 의존할 것이냐가 설계 결정이 되며, 연관관계의 응집성과 검색의 분리는 상충 관계에 있다.

  • Customer 객체가 주문이 성사된 모든 Order에 대한 컬렉션을 갖고 있어야 하는가? 아니면 Customer ID 필드를 검색해서 데이터베이스에서 Order를 찾아야 하는가?

검색과 연관계를 알맞게 조합하면 설계를 이해하기가 쉬워진다.

주의할 점

개발자가 SQL 질의문을 구성해 인프라스트럭쳐 계층의 질의 서비스에 전달하고, 테이블 행의 결과집합을 획득한 다음 필요한 정보를 꺼내 그 정보를 생성자나 FACTORY에 전달할 때쯤이면 모델에 집중하기가 힘들어진다.

자연스럽게 객체를 질의를 통해 제공되는 데이터의 컨테이너로 여기게 되고, 전체 설계가 데이터 처리 방식으로 나아간다. 기술의 세부 사항은 다양하지만 클라이언트가 모델의 개념이 아닌 기술을 다루게 된다는 문제가 남는다.

직접적으로 데이터베이스를 사용할수록 개발자들은 AGGREGATE나 캡슐화와 같은 특징을 활요하는 것을 우회하려 하고, 그 대신 필요한 데이터를 직접 획득해서 조작하게 된다는 것이다. 점점 더 많은 도메인 규칙이 질의 코드로 들어가거나 그냥 사라져 버린다.

클라이언트는 이미 존재하는 도메인 개체의 참조를 획득하는 실용적인 수단을 필요로 한다. 인프라스트럭처에서 도메인 객체의 참조를 쉽게 획득할 수 있게 해준다면 클라이언트 측을 개발하는 개발자들이 좀더 탐색 가능한 연관관계를 추가해 모델을 엉망으로 만들어 버릴지도 모른다. 한편으로는 AGGREGATE 루트에서부터 순회하지 않고 정확히 필요한 데이터를 데이터베이스에서 뽑아내거나 몇 가지 특정한 객체를 가져오는 데 질의를 사용할 수도 있따. 도메인 로직은 질의와 클라이언트 코드로 들어가고, ENTITY와 VALUE OBJECT는 그저 데이터 컨터이너로 전락한다.

캡슐화

전역적인 접근이 필요한 각 객체 타입에 대해 메모리상에 해당 타입의 객체로 구성된 컬렉션이 있다는 착각을 불러 일으키는 객체를 만든다. 잘 알려진 전역 인터페이스를 토대로 한 접근 방법을 마련하라. 객체를 추가하고 제거하는 메서드를 제공하고, 이 메서드가 실제로 데이터 저장소에 데이터를 삽입하고 데이터 저장에서 제거하는 연산을 캡슐화하게 하라.

캡슐화 이점

  • REPOSITORY는 영속화된 객체를 획득하고 해당 객체의 생명주기를 관리하기 위한 단순한 모델을 클라이언트에게 제시

  • REPOSITORY는 영속화 기술과 다수의 데이터베이스 전략, 또는 심지어 다수의 데이터 소스로부터 애플리케이션과 도메인 설계를 분리

  • REPOSITORY는 객체 접근에 관한 설계 설정을 전해준다

  • REPOSTIORY를 이용하면 테스트에서 사용할 가짜 구현을 손쉽게 대체할 수 있다(보통 메모리상의 컬렉션을 이용)

영속화

  • 영속화 기술을 캡슐화하면 클라이언트가 매우 단순해지고 REPOSITORY 구현에서 완전히 분리

  • 그러나 캡슐화가 종종 그렇듯이 개발자들은 무슨 일이 일어나고 있는지 반드시 알고 있어야 함

  • REPOSITORY가 의도하지 않은 방식으로 사용되거나 작동한다면 REPOSITORY의 수행 성능이 극단에 치우칠 수 있음

구현

  • 타입(TradeOrder)을 추상화한다. REPOSITORY가 특정 타입의 모든 인스턴스를 담기는 하지만 이것이 각 클래스(BuyOrder, SellOrder)마다 하나의 REPOSITORY가 필요하다는 의미는 아니다.

  • 트랜잭션 제어를 클라이언트에 둔다. 데이터베이스에 대한 삽입과 삭제를 REPOSITORY에서 수행하겠지만 보통 REPOSITORY에서는 아무것도 커밋(commit)하지 않을 것이다. REPOSITORY에서 간섭하지 않는다면 트랜잭션 관리가 좀 더 단순해질 것이다.

@Service
@Transactional
class DomainApplicationService

FACTORY와의 관계

  • FACTORY가 새로운 객체를 만들어 내는 데 반해 REPOSITORY는 기존 객체를 찾아낸다.

  • REPOSITORY가 맨 처음으로 객체를 생성하는데도 사용할 수 있는 FACTORY로 객체 생성을 위임해서 일치시킬 수 있다.

  • FACTORY에서 영속화에 대한 모든 책임을 빼내는 것은 이러한 명확한 분리에도 도움이 된다.

  • FACTORY와 REPOSITORY가 결합하지 않아야 한다. 객체의 생성과 객체의 재구성를 구분하는 것은 도메인에서 중요하며, 투명하게 결합하는 프레임워크는 실제로 상황을 엉망으로 만들어버릴 수 있다.

관계형 데이터베이스

  • 기술적으로 관계형 테이블 설계에서 도메인 모델을 반영할 필요는 없다. 매핑 도구가 객체 모델과 관계형 모델 간의 중대한 차이를 서로 이어줄 만큼 충분히 정교하기 때문이다.

  • 데이터베이스가 하나의 객체 저장소로 보여진다면, 매핑 도구의 기능과는 상관없이 데이터 모델과 객체 모델이 서로 갈라지게 해서는 안 된다. 일부 객체 관계의 풍부함을 희생해서 관계 모델에 밀접하게 한다(비정규화).

  • 객체 시스템 외부의 프로세스는 이러한 객체 저장소에 접근해서는 안 된다. 그러한 프로세스는 객체에 적용된 불변식을 위반할 수 있기 때문이다. 그뿐만 아니라 그러한 프로세스가 접근하게 되면 데이터 모델을 고착화해서 객체를 리팩터링할 때 변경하기가 힘들어진다. (하나의 시스템이 하나의 관계형 데이터베이스를 바라보도록 설계)

  • 객체 모델과 데이터 모델이 서로 갈라지기 시작한다면 투명성이 빠르게 사라질 수도 있다. (혼란을 초래할 수 있음)

0개의 댓글