전술적 설계 - AGGREGATE 와 REPOSITORY

AGGREGATE

  • DDD 를 하게 되면 무수한!! VALUE OBJECT, ENTITY 가 등장하게 되고, 이는 분할의 결과물이다.

  • 관련 객체를 하나로 묶은 군집을 AGGREGATE 라고 부른다. (논리적 구조)

  • 애그리거트로 묶어서 바라보면 좀 더 상위 수준에서 도메인 모델 간의 관계를 파악할 수 있다.

  • 애그리거트에 속한 객체는 유사하거나 동일한 라이프사이클을 갖는다. (동일한 라이프사이클을 갖는 케이스는 많지 않다.. 그래서 헷갈린다)

    • 같은 애그리거트 내에서 소멸시점은 동일하나, 생성시점은 다른 케이스들이 많다.

    • 때문에, 비지니스 로직을 수행해야 할 단위라는 표현이 직관적으로 이해하기가 좋다.

      • 비지니스 로직 = 불변식 (불변식을 지켜야한다)

      • ex, 강의의 정원 25명, 수강생은 25명을 넘을 수 없다. (때문에, 수강생이 25명이 넘을 수 없도록 강의와 수강생은 같은 애그리거트로 묶어야 한다, 라이프 사이클은 다르다!)

  • 한 애그리거트에 속한 객체는 다른 애그리거트에 속하지 않는다.

  • 두 개 이상의 엔티티로 구성되는 애그리거트는 드물게 존재한다.

AGGREGATE ROOT

  • 애그리거트 루트의 핵심 역할은 애그리거트의 일관성이 깨지지 않도록 하는 것이다.

  • 애그리거트 루트는 애그리거트가 제공해야 할 도메인 기능을 구현한다.

    • 애그리거트 루트는 애그리커트 묶음에서 유일하게 외부에 노출된다.

    • ex, 학급에서 가정통신문을 분배할 때, 반장이 가정통신문을 나누어준다.

  • 이는 애그리거트의 내부 구현을 숨겨서 애그리거트 단위로 구현을 캡슐화할 수 있도록 돕는다.

  • 루트 엔티티는 애그리거트에 속해 있는 엔티티와 밸류 객체를 이용해서 애그리거트가 구현해야 할 기능을 제공한다.

  • 위와 같은 특징 때문에, 애그리거트 내부에 있는 엔티티나 밸류 오브젝트간에 협력은 이루어져서는 안된다.

    • 만약 애그리거트 내부에 있는 엔티티나 밸류 오브젝트간에 협력이 이루어진다면 캡슐화 위반!!

AGGREGATE 참조

  • 애그리거트는 애플리케이션 레벨에서 ACID 를 지키는 방법이다!

    • 애그리거트에서 다른 애그리거트와 직접 참조하게 되면 ACID 를 지키지 못하게 된다.

  • 애그리거트를 직접 참조할 때 발생할 수 있는 가장 큰 문제는 편리함을 오용한다는 것이다.

  • 애그리거트의 ACID 지키기 위해서는 간접 참조를 사용해야 한다.

    • 간접(ID) 참조를 사용하면 모든 객체가 참조로 연결되지 않고 한 애그리거트에 속한 객체들만 참조로 연결된다.

    • 간접 참조 방식을 사용하면 복잡도를 낮추는 것과 함께 한 애그리거트에서 다른 애그리거트를 수정하는 문제를 원칙적으로 방지할 수 있다.

DDD 에서는 간접참조만 사용한다?

  • DDD 에서는 애그리거트 간의 참조를 ID 로 간접참조 할 뿐이지, 애그리거트 내부에서는 엔티티와 밸류 오브젝트간 직접 참조가 이루어진다!

REPOSITORY

  • JPA 레포지토리, DDD 레포지토리는 다르다. (여기서는 DDD 레포지토리를 설명)

  • 레포지터리는 애그리거트 단위로 도메인 객체를 저장하고 조회하는 기능을 정의하는 클래스!

  • 때문에, 애그리거트를 구하는 레포지터리 메서드는 완전한 애그리거트를 제공해야 한다.

    • 애그리거트의 일부 필드가 빠지면, ACID 를 위반하게 된다!

    • 애그리거트의 일부 필드가 빠지면, 애그리거트 기능을 실행하는 도중에 NullPointerException 이 발생한다.

  • 레포지토리는 애그리거트(루트) 단위로 존재하며 테이블 단위로 존재하는 것이 아니다.

    • 만약 테이블 단위로 레포지토리가 존재한다면 DDD 레포지토리가 아닌 JPA 레포지토리이다.

Last updated