애그리거트 간의 참조

직접 참조의 문제점

  • 편한 탐색 요용
    • 한 애그리거트 내부에서 다른 애그리거트에 접근하여 상태를 변경할 수 있게,
    • 애그리거트의 경계가 모호해지고 의존성이 증가한다.
  • 성능적 고민
    • JPA 사용하는 경우 지연 로딩과 즉시 로딩 중 어떤 것을 사용할지 결정해야한다.
    • 애그리거트의 기능에 따라 달라짐.
  • 확장성의 문제
    • 시스템이 성장하면서 하위 도메인별로 분리하고,
    • 다양한 저장소를 사용하게됨.
public class Order {
    private Orderer orderer;

    public void changeShippingInfo(ShippingInfo newShippingInfo, boolean useNewShippingAddrAsMemberAddr) {
        if (useNewShippingAddrAsMemberAddr) {
            orderer.getMember().changeAddress(newShippingInfo.getAddress()); // 직접 참조
        }
    }
}

public class Orderer {
    private Member member;
    private String name;
}

public class Member {
    // Member details
}

ID를 이용한 간접 참조

  • ID 참조의 장점
    • 애그리거트의 경계를 명확히 하고, 애그리거트 간의 물리적 연결 제거
    • 모델의 복잡도 DOWN , 응집도 UP
  • 구현 복잡도의 감소
    • 다른 애그리거트를 직접 참조 X
    • 로딩 전략에 대한 고민이 필요가 없어짐
    • 필요한 애그리거트는 응용 서비스에서 ID로 로딩’
  • 코드
    public class Order {
        private Orderer orderer;
    }
    
    public class Orderer {
        private MemberId memberId;
        private String name;
    }
    
    public class Member {
        private MemberId id;
    }
    
    public class ChangeOrderService {
        @Transactional
        public void changeShippingInfo(OrderId id, ShippingInfo newShippingInfo, boolean useNewShippingAddrAsMemberAddr) {
            Order order = orderRepository.findById(id);
            if (order == null) throw new OrderNotFoundException();
            order.changeShippingInfo(newShippingInfo);
    
            if (useNewShippingAddrAsMemberAddr) {
    						//order  에서 ID 값을 가져와서 간접 참조
                Member member = memberRepository.findById(order.getOrderer().getMemberId());
                member.changeAddress(newShippingInfo.getAddress());
            }
        }
    }

조회 성능과 N+1 문제의 발생

  • N+1 조회 문제
    • ID를 이용한 참조는 지연 로딩과 유사한 효과를 가지지만
    • N+1 조회 문제로 인해 전체 조회 속도가 느려질 수 있다.
  • 조회 전용 쿼리 사용
    • 조회 성능을 향상시키기 위해 조회 전용 쿼리를 사용하며, JPA의 JPQL이나 마이바티스와 같은 기술을 이용해 구현할 수 있다.
    • JPQL사용 코드 예시
      @Repository
      public class JpaOrderViewDao implements OrderViewDao {
          @PersistenceContext
          private EntityManager em;
      
          @Override
          public List<OrderView> selectByOrderer(String ordererId) {
              String selectQuery = "select new com.myshop.order.application.dto.OrderView(o, m, p) " +
                                   "from Order o join o.orderLines ol, Member m, Product p " +
                                   "where o.orderer.memberId.id = :ordererId " +
                                   "and o.orderer.memberId = m.id " +
                                   "and index(ol) = 0 " +
                                   "and ol.productId = p.id " +
                                   "order by o.number.number desc";
              TypedQuery<OrderView> query = em.createQuery(selectQuery, OrderView.class);
              query.setParameter("ordererId", ordererId);
              return query.getResultList();
          }
      }

Uploaded by N2T

'도메인주도개발' 카테고리의 다른 글

Image 생성 관련 최적화  (0) 2024.01.05
애그리거트?  (0) 2024.01.02
애그리거트를 팩토리를 사용하기  (0) 2024.01.02
도메인 전문가와 개발자 간 지식 공유  (0) 2023.12.30
도메인 모델  (0) 2023.12.30