04.07 (Refactoring)

2023. 4. 7. 23:01개발일지

우리가 런칭하는 사이트에 검색 기능 로딩 시간이 길어서 Refactoring을 하기로 결정을 하였습니다.

@Transactional(readOnly = true)
public Page<PostResponseDto> getPosts(String category, Sort sort, String lat, String lng, int page, int size, Member member) {

    List<PostResponseDto> postResponseDtos = new ArrayList<>();
    Pageable pageable = PageRequest.of(page, size);
    List<Post> posts = postRepository.findByCategory(category);
    //  위도, 경도
    Double usrtLat = Double.parseDouble(lat);
    Double usrtLng = Double.parseDouble(lng);

    // PostResponseDto 생성
    buildResponseDtos(member, postResponseDtos, posts, usrtLat, usrtLng ,sort);

    // 정렬 메서드
    sort(sort, postResponseDtos);

    // 페이지네이션
    int start = (int) pageable.getOffset();
    int end = Math.min((start + pageable.getPageSize()), postResponseDtos.size());
    return new PageImpl<>(postResponseDtos.subList(start, end), pageable, postResponseDtos.size());
}

검색 기능에 공통적으로 쓰고있는

// PostResponseDto 셍성
private void buildResponseDtos(Member member, List<PostResponseDto> postResponseDtos, List<Post> posts, Double usrtLat, Double usrtLng, Sort sort) {
    for (Post p : posts) {
        Double postLat = Double.parseDouble(p.getLat());
        Double postLng = Double.parseDouble(p.getLng());
        double distance = distance(usrtLat, usrtLng, postLat, postLng);
        p.getReviews().sort(Comparator.comparing(Review::getCreatedAt).reversed());
        log.info("정렬 완료");
        List<ReviewResponseDto> reviewResponseDtos = new ArrayList<>();
        Integer reviewStar = 0;
        int count = 0;
        for (Review r : p.getReviews()) {
            reviewResponseDtos.add(ReviewResponseDto.from(r));
            reviewStar += r.getStar();
            count += 1;
            log.info(p.getCategory(),"for문 성공");
        }
        int starAvr = 0;
        if (count != 0) {
            starAvr = Math.round(reviewStar / count);
            log.info("if문 count 가 0이 아닐때");
        }

        Likes likes = likesRepository.findByPostIdAndMemberId(p.getId(), member.getId());
        boolean isLike = likes != null;
        postResponseDtos.add(PostResponseDto.builder()
                .post(p)
                .star(starAvr)
                .distance(distance)
                .reviewCount(count)
                .isLike(isLike)
                .build());
    }
    sort(sort , postResponseDtos);
    log.info("sort 성공");

}

이 메서드를 시간복잡도를 줄여보려고 QueryDSL로 Refactoring을 시도하였습니다. 우선 Repository 아래와 같이 로직을 짜고

@Override
public List<Post> find(String category){
    return queryFactory.selectFrom(post)
            .leftJoin(post.reviews, review1).fetchJoin()
            .where(post.category.eq(category))
            .distinct()
            .fetch();
}

Service에 가서

private void buildResponseDtos(Member member, List<PostResponseDto> postResponseDtos, List<Post> posts, Double usrtLat, Double usrtLng, Sort sort) {
    log.info("buildResponseDtos() 메서드 시작");
    for (Post p : posts) {
        Double postLat = Double.parseDouble(p.getLat());
        Double postLng = Double.parseDouble(p.getLng());
        double distance = distance(usrtLat, usrtLng, postLat, postLng);
        p.getReviews().sort(Comparator.comparing(Review::getCreatedAt).reversed());
        int reviewStar = p.getReviews().stream()
                .mapToInt(Review::getStar)
                .sum();
        int count = p.getReviews().size();
        int starAvr = 0;
        if (count != 0) {
            starAvr = Math.round(reviewStar / count);
        }
        Likes likes = likesRepository.findByPostIdAndMemberId(p.getId(), member.getId());
        boolean isLike = likes != null;
        postResponseDtos.add(PostResponseDto.builder()
                .post(p)
                .star(starAvr)
                .distance(distance)
                .reviewCount(count)
                .isLike(isLike)
                .build());
    }
    sort(sort , postResponseDtos);
    log.info("buildResponseDtos() 메서드 종료");
}

for문을 빼버리니 시간복잡도가 굉장히 짧아졌습니다. 항상 리팩토링을 해서 서버에서 작동하는 쿼리를 최대한 최소화를 시켜서 속도 및 서버가 터지지 않게 계속 고민하고 시도해봐야 되는 도전정신을 배웠습니다!

'개발일지' 카테고리의 다른 글

04.09 TIL (테스트 코드)  (0) 2023.04.09
04.08 TIL (테스트 코드)  (0) 2023.04.09
04.06 TIL (Nginx)  (0) 2023.04.07
04.04 TIL (SSE)  (0) 2023.04.07
04.03 TIL  (0) 2023.04.03