도메인주도설계 - Aggregate와 Repository

600g (Kim Dong Geun)·2022년 1월 20일
1

오래만의 글이다 👨‍💻

Aggregate (집합체)

목적 : 여러객체로 구성된 객체의 일관성을 좀더 쉽게 유지하기 위해, 객체간의 범위를 묶는 것

  • 객체와 객체들간의 결합된 모델을 하기에는 많은 비용이 든다.
  • 여러 사용자가 객체를 동시에 접근할 경우 일관성을 유지하기가 쉽지 않다.
    • 예로들면 어떤 예제가 있을까?
  • 따라서 객체간의 어떠한 규약이나 법칙없이 일관성을 유지하려고 하면 많은 비용이 들 뿐만아니라, 유지보수를 하는데 있어 모델(도메인)에 집중하기가 힘들어진다.
  • 즉 도메인 객체의 생명주기를 관리하기가 매우 힘들어진다.

즉, Aggregate로 도메인을 설계한다면 다음과 같은 이점을 얻을 수 있다.

  1. 객체의 생명주기 동안의 무결성을 쉽게 유지할 수 있다.
  2. 생명주기 관리의 복잡성으로 모델이 난해해지는 것을 방지할 수 있다.
    • (= 도메인 모델에 좀더 집중할 수 있다.)

다시한번 즉, Aggregate = 데이터 변경의 단위로 다루는 연관 객체의 묶음

구성

  • Root : Aggregate의 주인, Aggregate내에 단 하나만 존재해야한다.
  • Boundary : Aggregate에 어떤 객체가 포함되어있는지를 가리킨다.

루트 이외의 Entity는 지역식별성(local identity)를 지니며, 지역식별성은 Aggregate내에서만 구별할 수 있으면 된다. (왜냐하면 Aggregate의 경계 밖에 위치한 객체는 루트말고는 Aggregate내부에 접근할 수 없기 때문이다.)

규칙

Aggregate는 다음과 같은 규칙성을 가지고 있다.

  • Root Entity는 전역식별성(어플리케이션 내에서 구별할 수 있어야 함)을 지니며, 불변식을 검사할 책임을 가지고 있다.
  • Root Entity는 전역식별성을, Boundary Entity는 지역식별성을 지니고 있다.
    • 여기서 지역식별성이란, Aggregate내에서 Entity간 구별이 가능해야 한다.
  • Aggregate 경계밖에서는 루트 Entity를 제외한 다른 Entity들은 내부의 Aggregate에 접근할 수 없다.
    • 루트 Entity가 다른 Entity에게 Aggregate내부의 Entity를 전달해줄 수 있지만, 그러한 객체는 전달받은 참조만 일시적으로 사용할 수 있음
    • 루트 Entity는 VO(혹은 복사본)를 다른 Entity에 전달할 수 있음 (VO는 불변객체이기 때문에 다른 Entity에서 수정되더라도 영향없다.) 영속성을 벗어났다와 비슷한 개념일드
  • 즉, 데이터베이스 질의를 이용하면 Aggregate의 루트만 직접적으로 획득 가능
    • 다른 Aggregate는 루트 Entity를 통해서 접근할 수 있다.
  • 삭제 연산은 Aggregate 경계안의 모든 요소를 한번에 제거해야 한다.
  • Aggregate 경계안의 어떤 객체를 변경하더라도 전체 Aggregate의 불변식은 모두 지켜져야한다.

Repository

역할 : 이미 있는 객체를 찾고 참조를 얻을 수 있도록 진입점을 제공함. 즉 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는 영속화 기술과 데이터베이스 전략 또는 심지어 다수의 데이터 소스로부터 어플리케이션과 도메인 설계를 분리해준다.
  • Repository는 객체 접근에 관한 설계 결정을 전해준다.
  • Repository를 이용하면 테스트에서 사용할 가짜 구현(Mock을 이용한 When을 말하는듯)을 손쉽게 대체할 수 있다

구현

저장, 조회, 질의 메커니즘을 캡슐화 하는 것은 Repository 구현의 가장 기본적인 기능이다. Repository의 개념은 여러상황에서 적용될 수 있기 때문에 명심할점 몇가지를 나열
1. 타입을 추상화한다.
Repository가 모든 인스턴스를 "담기는" 하지만 이것이 각 클래스마다 Repository가 필요하다는 말은 아니다. 타입은 추상적인 상위클래스가 될 수 있다.
2. 클라이언트와 분리를 활용한다.
(어떤 말인지 제대로 이해못했다.) 직접 메커니즘을 호출했을 때 보다 더 자유롭게 Repository의 구현을 변경할 수 있다고 한다. (Repositry의 내부구현이 클라이언트의 비즈니스 로직에 오염되지 않아야한다.) 정도로 나는 이해했다. 그렇게하면 영속화전략을 자유롭게 교체하고, 메모리상에 객체를 캐싱하는등 성능을 최적화할 수 있다고 한다.
3. 트랜잭션 제어를 클라이언트에 둔다.
데이터 베이스에 대한 삽입과 삭제를 Repository에서 수행하겠지만, Repository에서는 아무것도 커밋하지 않을 것이다.
실제로 Service단에 트랜잭션 제어를 둔다면, 다른 Repository의 작업등을 좀더 손쉽게 Atomic하게 처리가 가능할 것이다.

Factory와의 관계

  • Factory는 객체의 생성을 담당, Repository는 중간단계와 마지막 단계를 담당한다.
    그도 그럴것이 어플리케이션에서 객체를 생성할때 Factory를 사용하고, 이미 생성된 객체를 조회하는 작업과 작업을 마치고 DB나 객체를 영구적으로 보관할 장소에 저장(commit)하는 작업은 Repository가 담당할 것이다.
profile
수동적인 과신과 행운이 아닌, 능동적인 노력과 치열함

0개의 댓글