코딩과 결혼합니다

[Game_Crew] 리팩토링 : 유저 평점 기능 본문

코딩과 매일매일♥/Game_Crew

[Game_Crew] 리팩토링 : 유저 평점 기능

코딩러버 2023. 11. 20. 14:43
728x90

https://coding-s2-chaewon.tistory.com/193

 

[Game_Crew] 유저 평점 기능

⭐게임크루 프로젝트의 핵심 기능 : 유저 평점 기능 WHY? 유저들이 보다 우수한 게임 경험을 가질 수 있도록 돕기 위해 유저들이 게임 파트너를 선택하는 데에 유용한 참고자료를 제공하려 한다.

coding-s2-chaewon.tistory.com

✔️ 이 전에 구현했던 유저 평점 기능의 경우에는 아래와 같은 문제점이 있었다.

그동안 꾸준히 좋은 점수를 받다가 나쁜 점수를 한 번 받은 유저와, 그동안 나쁜 점수만 받다가 한 번 좋은 점수를 받은 유저와의 차이가 나지 않게 된다. 계속해서 이전 점수와 새로운 점수를 더해서 2로 나눌 뿐이기 때문이다.

 

 

✔️ 이에 대한 해결 방안으로 아래의 방법들을 적용해 보았다.

1. RecordRatingRepository에 평가한 시간을 추가한다.
2. 최근 전적들 10개까지 모아 더한 후에 평균을 낸다.
3. 10개가 안 되는 전적을 가지고 있다면 (모든 점수들의 합 / 전적의 개수)를 해준다.

1. 평가한 시간을 추가

//RecordOfRatings(Entity)

@CreatedDate
@Column(updatable = false)
private LocalDateTime RecordedAt;

 

2. 최근 전적들 10개까지 모아 더한 후에 평균


이전에 평가받은 기록이 있다면 수행되는 로직이다.
size를 9로 하여 최신의 점수 기록 9개를 가져오고 입력받은 점수에 각각 더해서 나누기 10을 해준다.

    } else if (checkRating.isPresent()) {
        TotalRating existingTotalRating = checkRating.get();
        Long countedNumbers = recordOfRatingsRepository.countByUserId(evaluated_user);

        List<RecordOfRatings> allRatings = recordOfRatingsRepository.findByUserIdOrderByRecordedAtDesc(evaluated_user);
        List<RecordOfRatings> beforeRatings = allRatings.subList(0, Math.min(allRatings.size(), 9));

        double sumManner = manner;
        double sumParticipation = participation;
        double sumGamingSkill = gamingSkill;
        double sumEnjoyable = enjoyable;
        double sumSociability = sociability;

        for (RecordOfRatings rating : beforeRatings) {
            sumManner += rating.getManner();
            sumParticipation += rating.getParticipation();
            sumGamingSkill += rating.getGamingSkill();
            sumEnjoyable += rating.getEnjoyable();
            sumSociability += rating.getSociability();
        }

        double totalManner = sumManner / (1 + beforeRatings.size());
        double totalParticipation = sumParticipation / (1 + beforeRatings.size());
        double totalGamingSkill = sumGamingSkill / (1 + beforeRatings.size());
        double totalEnjoyable = sumEnjoyable / (1 + beforeRatings.size());
        double totalSociability = sumSociability / (1 + beforeRatings.size());
        double totalRating = (totalManner + totalParticipation + totalGamingSkill + totalEnjoyable + totalSociability) / 5;

        RecordOfRatings ratings = new RecordOfRatings(evaluated_user ,evaluatorId, manner, participation, gamingSkill, enjoyable, sociability, totalRating);
        recordOfRatingsRepository.save(ratings);
    }
}
public interface RecordOfRatingsRepository extends JpaRepository<RecordOfRatings, Long> {

	//...

    List<RecordOfRatings> findByUserIdOrderByRecordedAtDesc(Long userId);
}

 

문제 - 모든 데이터를 가져와야 하는 문제(성능 down)

 

 

 

2-2 해결 - 페이징 기능을 사용한다.

이 방법은 필요한 만큼의 데이터만 데이터베이스에서 읽어와 데이터가 많은 경우에도 효율적으로 처리할 수 있다.

내림차순으로 최신의 점수가 제일 앞의 페이지에 위치하게 한 다음 코드의 첫 페이지의 최대 9개의 항목을 가져온다.

 

이는 가져올 수 있는 점수가 9개가 되지 않더라도 똑같이 적용가능하다.

double totalManner = sumManner / (1 + beforeRatings.size());

이런 식으로 size의 수만큼만 더해주어 예를 들어 점수 5개를 합한 거면 5로 나누어준다.

public interface RecordOfRatingsRepository extends JpaRepository<RecordOfRatings, Long>{
    Page<RecordOfRatings> findByUserIdOrderByRecordedAtDesc(Long userId, Pageable pageable);
}
//전역변수
LocalDateTime now = LocalDateTime.now();

//...

}else if (checkRating.isPresent()) {
            PageRequest pageable = PageRequest.of(0, 9);
            List<RecordOfRatings> beforeRatings = recordOfRatingsRepository.findTop9ByUserIdOrderByRecordedAtDesc(evaluated_user, pageable);

            double sumManner = manner;
            double sumParticipation = participation;
            double sumGamingSkill = gamingSkill;
            double sumEnjoyable = enjoyable;
            double sumSociability = sociability;

            for (RecordOfRatings rating : beforeRatings) {
                sumManner += rating.getManner();
                sumParticipation += rating.getParticipation();
                sumGamingSkill += rating.getGamingSkill();
                sumEnjoyable += rating.getEnjoyable();
                sumSociability += rating.getSociability();
            }

            double totalManner = sumManner / (1.0 + beforeRatings.size());
            double totalParticipation = sumParticipation / (1.0 + beforeRatings.size());
            double totalGamingSkill = sumGamingSkill / (1.0 + beforeRatings.size());
            double totalEnjoyable = sumEnjoyable / (1.0 + beforeRatings.size());
            double totalSociability = sumSociability / (1.0 + beforeRatings.size());
            double totalRating = (totalManner + totalParticipation + totalGamingSkill + totalEnjoyable + totalSociability) / 5;

            RecordOfRatings ratings = new RecordOfRatings(evaluated_user ,evaluatorId, manner, participation, gamingSkill, enjoyable, sociability, totalRating, now);
            recordOfRatingsRepository.save(ratings);

            // Update TotalRating
            TotalRating totalRatingEntity = checkRating.get();
            totalRatingEntity.setTotalManner(totalManner);
            totalRatingEntity.setTotalParticipation(totalParticipation);
            //...
        }
    }
  • recordedAt을 저장해 주는 로직이 없어서 LocalDateTime now = LocalDateTime.now(); 를 추가해 주었다.
  • 정수끼리 나누면 정수가 나온다.  (1 + beforeRatings.size()) 에서 (1.0 + beforeRatings.size())로 실수로 나누어주었다.
  • 새로 업데이트된 점수를 저장해 주는 부분을 놓치고 있었다.. setTotalManner 등의 메서드로 DB를 업데이트해 주었다.

결과

20번의 유저 평점을 진행했으며 최근 평점 9개 + 새로 입력받은 평점 총 10개의 점수를 합산하여 10으로 나눈다.

 

total_enjoyable이 1로 잘 반영되었음을 확인하였다.

그리고 0.5 단위로 반올림도 잘 반영됨을 확인하였다.