장바구니 조회 로직을 수정하였다.
@Transactional(readOnly = true)
public CartForm readAllCart(User user) {
// 장바구니 조회
Cart oneCart = cartRepository.findWithMenus(user.getCart().getId());
CartForm cartForm = new CartForm(oneCart);
// 장바구니 목록의 Id 를 Key, 메뉴의 옵션들을 Value 로 갖는 Map 생성
Map<Long, List<CartMenuOption>> cartOptionMap = findCartOptionMap(oneCart.getCartMenus());
// 장바구니 목록 dto 생성
List<CartMenuForm> cartMenuForms = getCartMenuResponseDtos(oneCart, cartOptionMap);
cartForm.updateCartMenuForm(cartMenuForms);
return cartForm;
}
수정 전에는 위와 같이 코드가 구성되어 있었다.
마음에 들지 않았던 점은
CartForm cartForm = new CartForm(oneCart);
이와 같이 장바구니를 조회하고, 여기서 장바구니 목록을 추출하는데
Map<Long, List<CartMenuOption>> cartOptionMap = findCartOptionMap(oneCart.getCartMenus());
private Map<Long, List<CartMenuOption>> findCartOptionMap(List<CartMenu> cartMenus) {
List<Long> cartMenuIds = cartMenus.stream()
.map(CartMenu::getId)
.collect(Collectors.toList());
return cartMenuOptionQueryService.findCartOptionsByIds(cartMenuIds)
.stream()
.collect(Collectors.groupingBy(cmo -> cmo.getCartMenu().getId()));
}
옵션을 조회하기 위해서 장바구니 목록을 순회하여 Id 를 추출하고, 이를 통해서 옵션을 조회한다는 것이 복잡해 보였다.
그리고 무엇보다 장바구니 목록을 Dto 로 변환하는 부분에서
private List<CartMenuForm> getCartMenuResponseDtos(Cart oneCart, Map<Long, List<CartMenuOption>> cartOptionMap) {
return oneCart.getCartMenus().stream()
.map(cartMenu -> {
List<CartOptionForm> optionDtos = cartOptionMap.get(cartMenu.getId())
.stream()
.map(CartOptionForm::new)
.toList();
CartMenuForm cartMenuForm = new CartMenuForm(cartMenu);
cartMenuForm.setOptions(optionDtos);
return cartMenuForm;
})
.collect(Collectors.toList());
}
장바구니 목록과 옵션을 한 메서드에서 같이 수행하는 것이 유지보수성도 떨어지고, 중첩적으로 반복문을 사용하다 보니 성능도 썩 좋지 않을 거 같다는 생각이 들었다.
@Transactional(readOnly = true)
public CartForm readAllCart(User user) {
// 장바구니 조회
Cart findCart = cartRepository.findWithMenus(user.getCart().getId());
// 장바구니 폼 생성
CartForm cartForm = new CartForm(findCart);
// 장바구니 목록 폼 생성
List<CartMenuForm> cartMenusForm = getCartMenuForms(findCart);
// 장바구니 옵션 폼 생성
Map<Long, List<CartOptionForm>> cartOptionsMap = getCartOptionsMap(cartMenusForm);
// 최종 Dto 매핑
cartMenusForm.forEach(cartMenuForm -> cartMenuForm.updateCartOption(cartOptionsMap.get(cartMenuForm.getCartMenuId())));
cartForm.updateCartMenuForm(cartMenusForm);
return cartForm;
}
최종적으로는 위와 같이 수정하였다.
각 단계 별로 역할을 구분하여 메서드를 구현하였다.
각각 하나의 역할만 수행하는 것이다.
수정하고 나니 가독성이 확실히 상승했다고 느껴졌다.
1. Execution time: 83.13 ms
2. Execution time: 56.57 ms
3. Execution time: 41.18 ms
4. Execution time: 46.52 ms
5. Execution time: 44.60 ms
6. Execution time: 50.59 ms
7. Execution time: 39.86 ms
8. Execution time: 42.30 ms
9. Execution time: 38.85 ms
10. Execution time: 43.26 ms
1. Execution time: 66.05 ms
2. Execution time: 47.95 ms
3. Execution time: 52.53 ms
4. Execution time: 37.12 ms
5. Execution time: 36.18 ms
6. Execution time: 37.67 ms
7. Execution time: 42.16 ms
8. Execution time: 43.90 ms
9. Execution time: 32.48 ms
10. Execution time: 35.36 ms
첫 번째 세트의 평균 실행 시간은 약 48.69 ms이고, 두 번째 세트의 평균 실행 시간은 약 43.14 ms이다.
이는 약 11.39%의 개선된 것을 의미한다.
코드를 수정하면서 각 단계별로 역할을 구분하고 메서드를 분리함으로써, 코드의 가독성과 유지보수성이 크게 향상되었다.
또한 로직을 분리하고 효율화함으로써 실행 시간이 평균적으로 11.39% 개선되었다.
특히, 장바구니 목록과 옵션 정보를 분리하여 처리함으로써, 각 단계의 데이터 로딩과 처리 속도가 개선되었다고 생각한다.