DDD START! (6)

이유진·2023년 12월 2일
post-thumbnail

Aggregate 간 참조

Aggregate 관리 주체: Aggregate Root
다른 Aggregate를 참조한다 == 다른 Aggregate Root를 참조한다
Aggregate간 참조는 필드를 통해 구현한다

ex) 주문 Aggreagate에서 회원 Aggregate 참조

public class Orderer {
	private Member member; // 회원 Aggregate 참조
    private String name;
}

문제

getter로 다른 Aggregate 데이터를 쉽게 가져올 수 있다.
하지만 다음과 같은 문제가 발생할 수 있다

  • 편한 탐색 오용
  • 성능에 대한 고민
  • 확장 어려움

편한 탐색 오용

쉽게 가져다 쓴다 ➡️ 쉽게 다른 Aggregate의 상태를 변경할 수 있다
Aggregate에서 다른 Aggregate의 상태를 변경하면 안된다! 내가 나의 상태를 바꿔야 한다.
왜? 상태를 변경한다는 것은 "의존" 이 생기기 때문

성능에 대한 고민

사실 실무에서 잘 안쓰지만 (우리회사에선 안씀) @ManyToOne, @OneToMany 를 사용하면 지연(lazy)로딩과 즉시(eager) 로딩 방식을 사용하게 된다.

다른 Aggregate에서 상태를 바꾸게 된다면 이러한 상황도 고려하여 로딩 전략을 결정해야 한다

확장 어려움

모든 Aggregate이 같은 DBMS를 사용하지 않을 수 있다.
그런 경우 @ManyToOne, @OneToMany 요런 JPA로 데이터를 갖고오지 못할 수 있다.

해결방법은?

ID값만 갖고 있고, 데이터를 가져올 때 ID값을 기반으로 데이터를 가져온다 (간접참조)
물리적 연결을 끊어 모델의 복잡도를 낮춰준다.
그리고, 의존을 제거하므로 응집도를 높여준다.

ex) 주문 Aggregate에서 회원 Aggregate 간접참조

public class Orderer {
	private MemberId memberId; // 간접참조
    private String name;
}

위에서 Aggregate마다 DBMS가 달라질 수 있다고 했는데 이때 한번의 쿼리로 관련 Aggregate 조회가 불가능하므로 캐시를 적용하거나, 조회 전용 저장소를 따로 구성한다.
코드는 복잡해지지만, 처리량은 높일 수 있다.

Aggregate간 연관

Aggregate간 1:N 혹은 N:M 연관이 있을 수 있다.
ex) 카테고리 - 상품
하나의 카테고리에 여러 상품이 속할 수 있다 ➡️ 카테고리 : 상품 = 1 : N

public class Category { 
	private Set<Product> products; // 상품 N
}

카테고리에 속한 상품 전체를 보여줄 수 있지만, 보통은 "페이징" 처리 하여 보여준다

public class Category { 
	private Set<Product> products; // 상품 N
    
    public List<Product> getProducts (int page, int size) {
    	List<Product> sortedProducts = sortById(products);
        return sortedProducts.subList((page - 1) * size, page * size);
    }
}

➡️ 하지만 이 코드는 Set products를 위해 전체 products를 조회 해온다 (갯수가 많을 때 성능저하)
➡️ 그래서 1:N 연관이 있을 때 보통 실제 구현에 적용하지 않는다

그럼 어떻게 구현하죠? ➡️ 상품(Product)에 카테코리 ID 추가하기

  public Class Product {
  	private CategoryId categoryId;
  }

카테코리ID를 사용하여 Product를 조회한다.

N:M 연관일 경우엔?

  public Class Product {
  	private Set<CategoryId> categoryIds;
  }
profile
BackEnd Developer

0개의 댓글