/////
Search
Duplicate
4️⃣

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

: 한 객체가 다른 객체를 참조하는 것처럼 애그리거트도 다른 애그리거트를 참조, 애그리거트 관리는 애그리거트 루트가 하므로 다른 애그리거트를 참조한다는 건 다른 애그리거트의 루트를 참조한다는 것과 같다.
: 애그리거트 간의 참조는 필드를 통해 쉽게 구현할 수 있다.
ex) 주문 애그리거트에 속해 있는 Orderer는 주문한 회원을 참조하기 위해 회원 애그리거트 루트인 Member를 필드로 참조할 수 있다.
: 필드를 이용해서 다른 애그리거트를 직접 참조하는 것은 개발자에게 구현의 편리함을 제공, 예를 들어 주문 정보 조회 화면에서 회원 ID를 이용해 링크를 제공해야할 경우, 다음과 같이 Order로부터 시작해서 회원 ID를 구할 수 있다. order.getOrderer().gerMember().getId()
: JPA는 @ManyToOne, @OneToOne과 같은 애너테이션을 이용해서 연관된 객체를 로딩하는 기능을 제공하고 있으므로 필드를 이용해 다른 애그리거트를 쉽게 참조할 수 있다.
1.
하나의 애그리거트에서 다른 애그리거트를 직접 참조할 때 발생할 수 있는 가장 큰 문제는 편리함을 오용할 수 있다는 것, 한 애그리거트의 내부에서 다른 애그리거트 객체에 접근할 수 있게되면 다른 애그리거트의 상태를 쉽게 변경할 수 있게 된다. 이는 앞서 말했듯 한 애그리거트가 관리하는 범위를 자칫 의도치않게 확장시켜버릴 위험이 있다.
⇒ 한 애그리거트에서 다른 애그리거트의 상태를 변경하는 것은 애그리거트 간의 의존 결합도를 높여서 결과적으로 애그리거트의 변경을 어렵게 만든다.
2.
두 번째 문제는 애그리거트를 직접 참조할 경우, 성능과 관련된 여러 가지 고민을 해야 한다는 것, JPA를 사용하면 참조한 객체를 지연 로딩과 즉시 로딩의 두 가지 방식으로 로딩할 수 있는데, 두 로딩 방식 중 무엇을 사용할지는 애그리거트의 어떤 기능을 사용하느냐에 따라 달라짐, 연관된 객체의 데이터를 함께 화면에 보여줘야 한다면 즉시 로딩이 조회 성능에 유리하지만 단순히 애그리거트의 상태를 변경하는 기능을 수행하는 경우에는 불필요한 객체를 로딩할 필요가 없으므로 지연 로딩이 유리할 수 있음, 상황에 맞게 잘 선택하는 것이 중요하다.
3.
세 번째 문제는 확장, 초기에는 단일 DBMS로 서비스를 구축했다. 점차 도메인 모델이 늘어나면서 각 도메인마다 다른 RDBMS를 사용해야하는 환경이 생긴다면? 이것은 더 이상 다른 애그리거트 루트를 참조하기 위해 JPA와 같은 단일 기술을 사용할 수 없음을 뜻한다.
: 이런 세 가지 문제를 완화할 때 사용할 수 있는 것이 ID를 이용해서 다른 애그리거트를 참조하는 것, DB 테이블에서 외래키로 참조하는 것과 유사하게 ID를 이용한 참조는 다른 애그리거트를 참조할 때 ID를 사용한다. 이 경우 모든 객체가 참조로 연결되지 않고 한 애그리거트에 속한 객체들만 참조로 연결된다. 이는 애그리거트의 경계를 명확히하고 물리적인 연결을 제거하므로 응집도를 높여주고 결합도를 낮춰준다.
: 이런 간접 참조를 통해 복잡도를 낮추는 것 외에도 하나의 애그리거트가 다른 애그리거트를 수정하는 것을 방지할 수 있다. 이는 직접적으로 접근하지 않기 때문, 또한 애그리거트별로 다른 구현 기술을 사용하는 것도 가능하게 해준다. 안정성이 중요한 데이터인 주문 애그리거트는 RDBMS에 저장하고 속도가 중요한 상품 애그리거트는 NoSQL에 저장하는 식으로 할 수 있다.
1.
ID를 이용한 참조와 조회 성능
: 다른 애그리거트를 ID로 참조하면 참조하는 여러 애그리거트를 읽을 때 조회 속도가 문제될 수 있다. 주문 목록을 보여줄 때, 회원 정보와 상품을 모두 가져와야한다면 이를 처리할 때, 각 주문마다 회원과 상품 애그리거트를 각각 읽어와야한다. 한 DBMS에 데이터가 있다면 조인을 이용해서 한 번에 모든 데이터를 가져올 수 있음에도 불구하고 주문마다 상품 정보를 읽어오는 쿼리를 실행하게 된다.
: 즉, 먼저 주문 목록을 쿼리로 읽어온 후, 각 주문 목록의 상품 ID를 토대로 상품 정보를 가져오는 쿼리를 다시 수행한다. 이처럼 ID를 이용한 애그리거트 참조는 지연 로딩과 같은 효과를 만드는 데, 지연 로딩과 관련된 대표적인 문제가 N+1 문제다.
: N+1 조회 문제는 더 많은 쿼리를 실행하기 때문에 전체 조회 속도가 느려지는 원인이 된다. 이 문제가 발생하지 않도록 하려면 조인을 사용해야 하는데, 조인을 사용하는 가장 간단한 방법은 ID 참조 방식을 객체 참조 방식으로 바꾸고 즉시 로딩을 사용하도록 매핑 설정을 바꾸는 것, 하지만 이는 애그리거트 간 참조를 ID에서 객체 참조로 다시 바꾸는 방법이다.
: ID 참조 방식을 유지하면서 N+1과 같은 문제를 발생하지 않도록 하려면 조회 전용 쿼리를 사용하면 된다. 즉 데이터 조회를 위한 별도의 DAO를 만들고 DAO의 조회 메서드에서 조인을 이용한 한 번의 쿼리로 필요한 데이터를 로딩하면 된다.