오래만의 글이다 👨💻
목적 : 여러객체로 구성된 객체의 일관성을 좀더 쉽게 유지하기 위해, 객체간의 범위를 묶는 것
즉, Aggregate로 도메인을 설계한다면 다음과 같은 이점을 얻을 수 있다.
다시한번 즉, Aggregate = 데이터 변경의 단위로 다루는 연관 객체의 묶음
루트 이외의 Entity는 지역식별성(local identity)를 지니며, 지역식별성은 Aggregate내에서만 구별할 수 있으면 된다. (왜냐하면 Aggregate의 경계 밖에 위치한 객체는 루트말고는 Aggregate내부에 접근할 수 없기 때문이다.)
Aggregate는 다음과 같은 규칙성을 가지고 있다.
역할 : 이미 있는 객체를 찾고 참조를 얻을 수 있도록 진입점을 제공함. 즉 DDD에서 Entity 생명주기의 중간점을 담당
여기서 중간점이란? : 객체의 생성은 Factory 나 Builder 등이 담당을 하고 있음. Repository는 주로 DB나 Record 형태로 저장된 데이터를 읽어들여 마치 어플리케이션 내에서 그 객체가 처음부터 존재하고 있었고 Repository가 그것을 참조할 수 있도록 도움을 주는 역할 이라 하여 생명주기의 중간지점을 담당하고 있다라고 해석할 수 있을 것 같다.
책에서는 이를 재구성(SubStitution) 이라고 한다.
목적 : DB나 자료구조와 같은 인프라스트럭쳐 계층에 질의를 던지고 객체를 가져오는 과정을 Repository에 맡길 수 있기 때문에, 우리는 보다 도메인에 중점적인 개발이 가능하다.
예를들어 Aggregate 루트로부터 데이터를 참조할 수 있게 하지 않고, 개발자가 그 상황에 맞춰 데이터를 가져오기 위해 질의를 참조한다면 도메인 모델은 엉망으로 참조가 될 것이고, 결과는 고스란히 유지보수 비용의 증가로 나타날 것이다.
따라서 Repository를 통해서 Aggregate의 루트로 들어갈 수 있는 길을 만들고, Aggregate내부에 존재하는 모든 객체들은 Aggregate의 루트 Entity를 통해 접근가능해야할 것이다.
Repository는 마치 전역적인 접근이 필요한 객체타입에 대해서 메모리상에 해당 타입의 객체로 구성된 컬렉션이 있다는 착각을 만든다.
-> 실제 데이터의 저장장소는 DB 혹은 어떠한 파일일지라도 어플리케이션 내에서 참조할시에는 마치 이미 어플리케이션에 존재하는 객체를 담고 있는 객체처럼 보인다 라고 해석할 수 있고, 전역적인 접근이므로 영속성을 유지 시킨다 라고 볼 수 있을 것 같다.
영속성을 유지시킨다 라는 말이 조금 와닿지 않을 수도 있는다.
예제로 보면 좀더 와닿을 수 있을 것 같다.
// 다음을 만족하면 영속성을 유지한다라고 볼 수 있을 것 같다.
Menu A = MenuRepository.findById(1L);
Menu A2 = MenuRepository.findById(1L);
A.setMenuName("육회비빔밥");
Asserts.assertTure("육회비빔밥",A2.getMenuName());
즉 Repository는 전역적으로 접근이 가능한 Entity를 보관하고 있다. Entity는 식별 가능해야 하기 때문에 어플리케이션내에서 유일한 존재이며, 식별가능한 속성값을 같은 값으로 불렀을 경우 A와 A2는 동일한 객체로 조회되어야 한다.
이러한 규칙을 만족시킬경우 영속성을 유지한다(?), 만족한다 라고 말할 수 있을 것 같다. 그래서 마치 메모리상에 컬렉션이 있다는 착각을 만든다고 한 것 같다 -> (아주 와닿는 표현이다.)
Repository에는 다음과 같은 이점이 있다.
저장, 조회, 질의 메커니즘을 캡슐화 하는 것은 Repository 구현의 가장 기본적인 기능이다. Repository의 개념은 여러상황에서 적용될 수 있기 때문에 명심할점 몇가지를 나열
1. 타입을 추상화한다.
Repository가 모든 인스턴스를 "담기는" 하지만 이것이 각 클래스마다 Repository가 필요하다는 말은 아니다. 타입은 추상적인 상위클래스가 될 수 있다.
2. 클라이언트와 분리를 활용한다.
(어떤 말인지 제대로 이해못했다.) 직접 메커니즘을 호출했을 때 보다 더 자유롭게 Repository의 구현을 변경할 수 있다고 한다. (Repositry의 내부구현이 클라이언트의 비즈니스 로직에 오염되지 않아야한다.) 정도로 나는 이해했다. 그렇게하면 영속화전략을 자유롭게 교체하고, 메모리상에 객체를 캐싱하는등 성능을 최적화할 수 있다고 한다.
3. 트랜잭션 제어를 클라이언트에 둔다.
데이터 베이스에 대한 삽입과 삭제를 Repository에서 수행하겠지만, Repository에서는 아무것도 커밋하지 않을 것이다.
실제로 Service단에 트랜잭션 제어를 둔다면, 다른 Repository의 작업등을 좀더 손쉽게 Atomic하게 처리가 가능할 것이다.