본문 바로가기
도메인 주도 설계

반버논이 말하는 Repository 란?

by simplify-len 2020. 9. 15.

책, 이벤트 주도 설계 내용과 저의 의견을 섞어 내용을 적어내려갑니다.

들어가기

 저에게 Repository 라는 말은 Android 을 개발 할때도 MVVM 패턴을 언급하면서 Repository 라는 용어가 처음 등장했습니다. 이후에 JPA를 학습하면서 Repository 라는 용어에 대해서 좀 더 친숙하게 다가왔고, 처음에는 단순하게 '어떤 저장소' 라는 의미로 다가왔습니다. 

그러나, 도메인 주도 개발을 학습하면서 Repository 에 대해서 좀 더 깊이 있는 고찰을 할 수 있었습니다. 그럼 반버논의 책 DDD에서는 Repository 을 무엇이라 정의했을까요?

Repository? 무슨 의미인가?

 앞서 언급했던 Repository 라고 하면 딱 떠오르는, 그 의미 저장소. DDD에서도 Repository는 저장소의 의미를 가진다고 합니다. 우리가 흔히 알고 있는 DB와 유사한 성격을 띄고 있는 부분이라고 생각합니다. 데이터를 저장하고, 꺼내고- JPA를 먼저 학습했었던 입장에서 생각해보면 그런 것 같습니다.

 전역(global) 액세스가 필요한 각 객체의 타입마다, 해당 타입의 모든 객체가 담긴 인메모리 컬렉션이란 허상을 제공하는 객체를 생성하자. 잘 알려진 전역 인터페이스를 통해 액세스를 설정하자. 객체를 추가하거나 제거하는 메소드를 제공하자... 일정 조건에 부합되는 특성을 갖는 객체를 선택해 완전히 인스턴스화된 객체나 여러 객체의 컬렉션으로 반환하는 메소드를 제공하자... 애그리게잇에 대해서만 리파지토리를 제공하자... [Evans, 151쪽]

 에릭 에반스가 말하는 레포지토리에 대한 내용입니다. 처음드는 생각은 '음?' 허상을 제공하는 객체를 생성한다? 라는 말이 신기했습니다.

 그리고, Repository 는 컬렉션을 닮은 객체와 연관이 있다고 합니다. 그래서 애그리게잇만이 레파지토리를 갖게 되고, 대부분 1:1 로 맵핑 될 수 있지만, 1:다 로 맵핑 될 수 있다고 합니다.

만약 Repository가 없다면?

 만약에, Repository가 없다면 어떻게 구현될까? 아마도, 데이터 액세스 오브젝트(DAO) 또는 한 엔티티 안에 모든 값들을 저장해서 데이터를 가지고 있을 수 있을 것입니다.

 이 부분에 대한 좀 더 명확한 이해는 조영호님의 의존성 이용해 설계 진화시키기를 참조하면 좋을 것같아요. 해당 링크에서, 트랜잭션 관련된 부분을 찾아보면 좋을 듯합니다!

컬렉션 지향(persistence-oriented) Repository? 영속성 지향(collection-oriented) Repository? 

  책에서 이 둘의 대한 설명을 이어갑니다.  

컬렉션 지향 레포지터리

 왜 컬렉션 지향 설계가 DDD패턴에 나타난 기본적인 개념에 충실한 편일까? 이 설계에서는 하위의 영속성 메커니즘을 전혀 눈치채지 못하도록 리파지토리 인터페이스를 설계해서, 데이터를 저장소에 저장하거나 영속한다는 생각을 전혀 할 수 없다고 합니다. 

 이러한 설계 접근법은 하위 영속성 메커니즘의 기능 중 일부를 특정해 반드시 구현해야 하기 때문에 맞지 않을 수 있다고 합니다. 어떤 조건에서 컬렉션 지향 레포지터리를 써야 될까?

 먼저 책에서는 일반적인 객체 지향 언어에서 컬렉션이 어떻게 쓰이고 있는가를 생각해보라고 합니다. 우리가 흔히 알고 있는 Set, Map, List 등, 객체를 컬렉션에 추가되며 삭제될 때까지 그 컬렉션에 남아있게 되는데, 컬렉션에게 특정 객체로의 참조를 요청해 가져온 후에 해당 객체 자체의 상태를 수정하는 요청을 그 객체로 보내기만 하면, 컬렉션이 직접 객체에서 일어나는 변화를 인식하기 위한 추가적인 절차를 수행할 필요가 없습니다.

여전히 컬렉션은 이전과 같은 객체를 갖고 있는 가운데, 수정 전에 포함됐던 객체의 상태는 변경되게 될 것입니다.

 

 대표적인 Collection 으로 HashSet 에 같은 객체를 두번 Add 하더라도 한번만 저장되게 된다. 즉, 리파지토리가 흉내 내야 하는 Set과 같은 컬렉을 흉내 내야 한다고 주장하고 있습니다. 특정 영속성 메커니즘을 지탱하는 구현이 무엇이든, 같은 객체의 인스턴스는 두 번 추가되도록 허용해선 안되며, 또한 리파지토리로부터 객체를 가져오게 하고 수정할 때 이를 리파지토리에 '재저장'할 필요가 없다고 합니다.

 컬렉션 지향의 전반적인 장점은 영속성 객체의 변경이 암시적으로 추적되기 때문에, 영속성 메커니즘에게 변경을 인식하도록 하기 위해 명시적인 클라이언트 정보나 관여가 필요하지 않다는 것에 있습니다. 

 반대로, 위 말과 같이 암시적으로 복사해 변화를 추적하는 하이버네이트와 같은 영속성 메커니즘을 사용할 자유가 주어진다 하더라도, 이의 적용이 바람직하지 않거나 적절하지 않은 상황이 있을 수 있습니다. 

 예를 들어, 요구 사항이 아주 많은 객체를 메모리로 가져와야 하며 매우 고성능의 도메인이 필요하다면, 이런 종류의 메커니즘은 메모리와 실행 모두에 불필요한 오버헤드를 더하게 됩니다. 

영속성 지향의 레파지토리

 컬렉션 지향의 스타일이 맞지 않을 때는 영속성 지향(Persistence-oriented)의 저장기반 레포지토리를 사용해야 한다고 합니다. 즉, 영속성 메커니즘이 암묵적으로나 명시적으로나 객체의 변화를 감지하고 추적하지 못할 때가 바로 이러한 상황입니다. 

 컬렉션 지향 접근법을 지원하는 객체 관계적 매퍼를 사용한다고 할지라도 영속성 지향의 접근법을 선택할 때 고려해야 할 사항이 더 있다고 합니다. 예를 들어 컬렉션 지향의 레포지터리로 설계했다가, 키-값 형태의 저장소로 변경 한다면 어떤 문제가 발생할까? 

 책에서는 어플리케이션 계층에 많은 변화가 생길 것이라 말하는데, 왜냐하면, 애그리게잇 업데이트가 생기는 위치마다 save() 를 사용하도록 변경해야 하기 때문이라고 합니다. 즉, 컬렉션의 경우 암시적으로 변경이 일어나지만 영속성 지향의 경우, put() 을 호출해야 한다는 것을 의미합니다. 

또한 영속성 지향의 레파지토리의 경우 키-값 짝으로 데이터를 저장하는, 이는 Map과 유사한 효과적인 저장소이지만, 주 메모리 저장소의 도구로 메모리 대신 디스크를 사용한다고 합니다. 또한 변경된 객체가 논리적으로 이미 저장된 객체와 같은 객체더라도 그렇게 해야 하는데, 그 이유는 이들이 전형적으로 변화를 추적할 수 있는 형태의 작업 단위나, 트랜잭션 경계를 지원하지 않기 때문입니다.

그래서 뭐가 다르다는건데?

- save() 를 암묵적으로 하는가? 그렇지 않은가?

- 데이터를 어디에 저장하는가?

 

학습을 했지만, 여전히 이해되지 않은 부분들이 많다고 느껴진다. 다시 책을 읽고 생각해보자,

댓글