프로젝트 리팩토링 시작!

개발세발·2025년 6월 5일

프로젝트가 끝나고..

음식 추천 및 AI 식단 관리 프로젝트를 마치고 개선의 여지가 너무나도 많은 점...을 파악하고, 이를 만져보려고 한다.

기능 1. 일일 리포트 기능

문제

  • 쿼리가 너~~무 많이 생성된다.
    @Override
    @Transactional
    public ReportGetResponseDto getDailyReport(String email) {
        Member member = memberRepository.findByEmailAndDeletedIsNull(email)
                .orElseThrow(MemberNotFoundException::new);

        LocalDate today = LocalDate.now();
        MemberInfo memberInfo = memberInfoRepository.findByMemberAndDeletedIsNull(member).orElseThrow(MemberInfoNotFoundException::new);

        Report report = reportRepository
                .findByMemberAndDeletedIsNullAndReportDate(member, today)
                .orElseGet(() -> createDailyReport(member, today, memberInfo));

        LocalDateTime start = today.atStartOfDay();
        LocalDateTime end   = LocalDateTime.now();
        List<RecommendationResult> records = recommendationResultRepository
                .findRecommendationResult(member, start, end);

        if (records.isEmpty() || records == null) {
            throw new RecommendResultNotFoundException();
        }

        // 통계 계산
        Nutrient consumed = records.stream()
                .map(rr -> toNutrient(rr.getFood()))
                .reduce(new Nutrient(0,0,0,0,0,0,0,0), Nutrient::plus);
        Nutrient target = calculateTargetNutrient(memberInfo);
        double score = calculateHealthScore(consumed, target);

        // 코치 코멘트 생성
        String nutrientPrompt = String.format("""
            오늘의 영양 통계입니다.\n" +
            "- 평균 건강 점수     : %.2f\n" +
            "- 총 칼로리         : %.0f kcal\n" +
            "- 탄수화물          : %.0f g\n" +
            "- 단백질            : %.0f g\n" +
            "- 지방              : %.0f g\n" +
            "- 나트륨            : %.0f mg\n" +
            "- 당류              : %.0f g\n" +
            "- 식이섬유          : %.0f g\n" +
            "- 콜레스테롤        : %.0f mg",""",
                score,
                consumed.calories(),    target.calories(),
                consumed.carbohydrates(), target.carbohydrates(),
                consumed.protein(),     target.protein(),
                consumed.fat(),         target.fat(),
                consumed.sodium(),      target.sodium(),
                consumed.sugar(),       target.sugar(),
                consumed.fiber(),       target.fiber(),
                consumed.cholesterol(), target.cholesterol()
        );
        String prompt = "아래 통계를 참고하여, 수치별 평가와 개선 조언을 200자 이내로 작성해주세요.";
//        String comment = openAiChatModel.call(nutrientPrompt + prompt);
        report.updateComment("AI API 키 만료임");
        log.info("Updated daily comment: {}", "키 만료됨");

        // presignedUrl 변환 함수 적용
        return ReportGetResponseDto.of(report, records, consumed, target, s3Service::buildGetUrl);
    }
  • member와 memberInfo가 분리되어 있어서 여기서 벌써 2번
  • 기존에 작성된 리포트가 있다면 가져오고 -> 없으면 생성하니 최악의 경우 2번
  • 리포트 업데이트 해줘야 되니까 추천 기록 가져와야 하니 여기서 또 1번
  • 추천 기록 가져오고 통계 낼 때,
 Nutrient consumed = records.stream()
                .map(rr -> toNutrient(rr.getFood()))

이 부분에서 또 음식 조회하는 쿼리 N번

  • 그리고 마지막에 update 쿼리 날아가는 거 1번

접근

  1. memberInfo에 저장하는 컬럼의 수가 많지 않음 -> member로 분리하나?
  2. 음식 조회가 음식 개수만큼 되니까 fetch join으로 이거 한 번에 가져오나?

라고 생각했는데...

  • 연관관계도 다 fetchType=LAZY 로 설정하긴 했음.
  • 그리고 일일리포트를 만들기 위해서 다 필요한 기능들.
  • 굳이 하게 된다면 memberInfo를 member 테이블에 합치면 될듯

그래서 결론

  • 이건 우선 냅두자!

0개의 댓글