본문 바로가기
개발 이론/MSA & DDD

[MSA & DDD] 애그리거트?? 간접참조

by dal_been 2023. 11. 13.
728x90

아 다른 분들의 코드를 보다보면 내가 공부할께 너무 많이 생긴다... 좋은데... 너무 많아... 모르는게...하하하

간접참조라는 단어를 보았고 간접참조에 대해서 알아보다보니 애그리거트??라는 단어가 나와서 알아보기로 한다

 

 

 애그리거트??

 

애그리거트는 관련 도메인을 하나의 군집으로 묶은 것이라고 한다.

음 조금더 자세하게 말하자면 연관된 것들끼리의 묶음이다.

 

 

위 사진은 객체 상위 수준 관점에서의 개별객체 단위의 관계이다

 

위 사진은 애그리거크 단위로 도메인을 나눈 것이다

 

이렇게 애그리거트 단위로 하나의 군으로 묶으면 좀더 상위 수준에서 도메인 모델간의 관계를 파악할 수 있다

 

  • 애그리거트는 관련된 모델을 하나로 모은 것이기때문에 한 애그리거트에 속한 객체는 유사하거나 동일한 라이플 사이클을 갖는다
    • 주문 관련 애그리거트를 만들려면 OrderLIne,Order, Orderer 관련 객체를 함께 생성해야한다
    • Order를 생성하는데 Shipping INfo를 만들지 않는 경우는 없다
  • 애그리거트는 경계를 갖는다. 한 애그러기트에 속한 객체는 다른 애그리거트에 속하지 않는다
    • 애그리거트는 독립된 객체군이며, 각 애그리거트는 자기 자신을 관리하지 다른 애그리거트를 관리하지 않는다
    • 주문쪽에서 배송지 수정, 주문 상품에 대한 수정은 할 수 있지만 갑자기 회원 비밀번호 변경, 상품 이름 변경과 같은 다른 애그리거트의 변경은 하지 않는다

 

 

애그리거트 루트

 

위의 사진을 보면 Order, Product,Member가 루트가 된다

 

즉 루트란 애그리거트 전체를 관리할 주체를 의미한다.

- 애그리거트 루트는 애그리거트의 일관성이 깨지지 않도록 하는 것이다(예를 들어 구매상품의 개수를 변경하면 Orde의 합계 금액도 변경해야한다)

- 애그리거트에 속한 객체는 애그리거트 루트 엔티티에 직접 또는 간접적으로 속한다

 

 

1. 도메인 규칙과 일관성

→ 애그리거트 루트가 아닌 다른 객체가 애그리거트에 속한 객체를 직접 변경하면 안된다

  • 단순히 필드를 변경하는 setter를 만들지 않는다. (외부에서 내부 상태를 함부로 바꾸지 못하도록 차단한다.)
  • 벨류 타입은 불변을 한다 → 외부에서 내부 상태를 함부로 바꾸지 못하게(변경하는 방법은 애그리거트 루트를 통해서나 새로운 밸류 개체를 할당는 것 뿐)

 

2. 트랜젝션 범위

→ 한 트랜젝션에서 한 애그리거트를 변경하는 것을 권장한다. 한 애그리거트에서 다른 애그리거트를 수정하면 두개의 애그리거트의 소통으로 내부 애그리거트에서 다른 애그리거부를 변경하는 꼴이 된다

 

만약 한 트랜젝션에서 두개이상의 애그리거트를 수정해야한다면 응용 서비스 계층에서 두 애그리거트를 수정하도록 구현하자

 

 

애그리거트와 리포지토리

 

애그리거트는 완전한 한개의 도메인 모델을 표현하므로 객체의 영속성을 처리하는 리포지터리는 애그리거트 단위로 존재한다

→ 각 도메인 모델이 물리적으로 각각 별도의 DB테이블에 저장한다고 해서 리포지토리를 각각 만들지 않는다. 애그리거트 루트를 위한 리포지터리만 존재한다

 

또한 애그리거트는 리포지터리 메서드에 완전한 에그리거트를 제공해야한다

Order order=orderRepository.findById(orderId);

 

위의 코드를 실행하면 order에는 OrderLine과 Orderer등 모든 구성요소를포함해야한다. 그렇지 않으면 완전하지 않는 애그리거트이므로 NPE같은 문제가 발생하게 된다

 

 

ID를 이용한 애그리거트 참조

 

한 객체가 다른 객체를 참조하는 것처럼 애그리거트도 다른 애그리거트를 참조한다

→ 애그리거트에서 다른 애그리거트를 참조한 다는 것은 애그리거트의 루트를 참조한다는 것과 같다

order.getOrderer().getMember().getId()

 

다만 합성을(필드를 통해 다른 애그리거트 직접 참조) 이용한 애그리거트 참조는 문제를 야기한다

 

1. 편한 탐색 오용

  • 한 애그리거틍에서 다른 애그리거트 상태를 변경하는 것은 애그리트간의 의존 결합도를 높여 결과적으로 애그리거트의 변경을 어렵게 만든다

2. 성능에 대한 고민

  • JPA를 사용하는 경우 참조한 객체를 지연로딩과 즉시 로딩할지에 대해 애그리거트의 어떤 기능을 사용하느냐에 달렸다
  • 단순히 객체의 데이터와 함께 화면에 보여줘야한다면 즉시 로딩이 조회성능에 유리하지만 애그리거트의 상태를 변경하는 기능을 실행하는 경우 불필요한 객체를 함께 로딩할 필요가 없으므로 지연로딩이 유리하다

3. 확장

  • 사용자가 늘고 트래픽이 증가하면 이에 따라 도메인별로 시스템을 분리시킬것이다. 만약 도메인마다 다른 종류의 저장소를 사용한다면
  • 더이상 다른 애그리거트 루트를 참조하기 위해 JPA와 같은 단일 기술을 사용할 수 없다

 

위의 세가지 문제를 완화하기 위해서는 ID값을 이용해서 다른 애그리거트 참조해야한다

 

 

db테이블의 외래키를 사용해서 참조하는 것과 비슷하다. ID를 통해 참조하면 모든객체가 참조로 연결되지 않고 한 애그리거트에 속한 객체들만 참조로 연결된다.

→ 다른 애그리거트를 직접 참조하지 않으므로 애그리거트 간 참조를 지연로딩을 할지, 즉시로딩으로 할지 고민하지 않아도 된다. 참조하는 애그리거트가 필요하면 응용서비스에서 아이디를 이용해서 로딩하면 된다

→ 한 애그리거트에서 다른 애그리거트를 수정하는 문제를 방지

→ 애그리트 별로 다른 구현 기술 사용가능(주문 애그리거트에서는 RDBMS에 저장, 상품 조회에서는 NOSQL에 저장)

 

 

 

ID를 이용한 참조와 조회 성능

 

다른 애그리거크의 iD로 참조하면 참조하는 여러 애그리거트를 읽어야할때 조회속도가 문제가 될 수 있다

예를 들어 주문 목록을 보여주려면 상품과 회원을 함께 읽어야하는데 한 DBMS에 데이터가 있다면 조인을 통해 한번에 모든 데이터를 가져올 수 있지만 다른 DBMS에 있는 경우 주문마다 정보를 읽어오는 쿼리를 실행해야한다

→ 지연로딩과 같은 효과를 낳으면서 지연로딩과 관련된 N+1 조회문제가 발새한다

 

그렇다면 다시 객체 참조 방식으로 바꿔야하나..?? 아니다 이건 애그리거트가 다시 다른 애그리거트에 객체 참조로 바뀌는 것이고 수정에 대한 문제가 생긴다

 

그러면 어떻게...??

전용 조회 쿼리를 사용해야한다

 

전용 조회쿼리?? 그니까 sql쿼리를 사용하라 아니 JPQL를 사용하면 된다. 즉시 로딩이나 지연로딩과 같은 고민없이 한번의 쿼리로 조회가능하다

 

 


일단 간단하게 애그리거트에 대한 소개는 끝났다.. 그럼 간접 참조는 무엇이냐??

 

일단 직접참조는

@Entity
public class Order{

   ......
   
   
   @OneToOne
   private Member member;
	
    
}

 정말 간단한 예제이다

이렇게 Order 엔티티가 Member를 직접 참조한다

이렇게 되면 Order 쪽에서 Member를 수정할 수도 잇다...

 

엥 수정하면 안되냥..??

 

조금 말이 안될 수 도  있지만

 

Member member=new Member("test","1234","ADMIN");

Order order=Order.Builder().
				member(member)
                .....
                .build();
                

order.getMember().setName("test1");

 

위와 같이 Member엔티티가 오염될 수 잇다

 

이때 사용하는 것이 간접 참조이다

 

다른 루트 애그리거트의 식별값을 참조하는 방식이다. 즉 위에서 이야기해던 ID를 통한 참조이다

 

@Entity
public class Order{

   ......
   
   
  
   private Long member;
	
    
}

 

Long 타입으로 변경하므로써 Member의 식별자 값만 받도록 하였다. 이렇게 하면 Member애그리거트를 안전하게 보호할 수 있고 Order 애그리거트에만 집중할 수 있다

 

다만 간접참조는 N+1문제가 남아잇다. Order리스트를 보여줄때 Order마다 Member 정보를 호출해야한다.

 

이와 같은 문제는 CQRS 패턴을 사용하여 명령과 조회에 대한 책임을 분리하면 된다. 이 패턴에 대해서는 다음 블로그에서 남기도록 하겠다.!

'개발 이론 > MSA & DDD' 카테고리의 다른 글

[MSA & DDD] DDD??  (0) 2023.11.12