Conversation
| public Map<SoptPart, Long> getCurrentGenerationPartMemberCounts(Long generation) { | ||
| String sql = """ | ||
| SELECT part, COUNT(*) AS member_count | ||
| FROM auth_prod.user_activity_histories | ||
| WHERE generation = ? | ||
| AND is_sopt = true | ||
| AND role = 'MEMBER' | ||
| AND part IN ('IOS', 'ANDROID', 'DESIGN', 'PLAN', 'SERVER', 'WEB') | ||
| GROUP BY part | ||
| """; | ||
|
|
||
| return jdbcTemplate.query(sql, rs -> { | ||
| Map<SoptPart, Long> result = new EnumMap<>(SoptPart.class); | ||
|
|
||
| while (rs.next()) { | ||
| result.put( | ||
| SoptPart.valueOf(rs.getString("part")), | ||
| rs.getLong("member_count") | ||
| ); | ||
| } | ||
|
|
||
| return result; | ||
| }, generation); | ||
| } |
There was a problem hiding this comment.
@table(schema = "auth_prod", name = "user_activity_histories") 로 엔티티 자체를 만들어서 JPA로 사용하는 방식보다 이렇게 JdbcTemplate을 사용하는 방식이 더 빠르게 작업할 수 있으셔서 이렇게 하신건가요??
There was a problem hiding this comment.
넵 맞습니다! 이번 조회가 auth_prod.user_activity_histories에 대한 단순 집계성 쿼리이고, 최종적으로 필요한 값도 엔티티 자체가 아니라 part별 count 값이라서JPA 엔티티/리포지토리를 추가하는 것보다 JdbcTemplate이 더 적절하다고 판단했습니다.
향후에 해당 값이나 auth의 데이터를 더 자주 활용하게 된다면 그때에 확장을 고려해보는 게 어떨까 해서 이렇게 작성해보았습니다.
There was a problem hiding this comment.
지금 다시 보면서 생각났는데, auth_prod를 하드 코딩할 경우 dev 환경에서 문제가 발생할 수 있겠네요,,,
| PartScores partScores = new PartScores(); | ||
| userInfos.forEach(userInfo -> addPartScore(userInfo, partScores)); | ||
|
|
||
| Map<Part, BigDecimal> averagePoints = calculateAveragePoints(partScores); | ||
| Map<Part, Integer> ranks = calculateRanks(averagePoints); | ||
|
|
||
| return Part.getPartsByReturnOrder().stream() | ||
| .map(part -> PartRank.builder() |
There was a problem hiding this comment.
userInfos.forEach(userInfo -> addPartScore(userInfo, partScores)); 에서 foreach로 상태를 변경하는 것이 좀 애매하다면 이렇게 할 수도 있겠네요
userInfos.stream()
.filter(userInfo -> SoptPart.toPart(userInfo.getPart()) != null)
.collect(Collectors.groupingBy(
userInfo -> SoptPart.toPart(userInfo.getPart()),
Collectors.summingInt(SoptampUserInfo::getTotalPoints)
));There was a problem hiding this comment.
오 좋은 의견 감사합니다 👀 말씀해주신 방식처럼 groupingBy로 바로 파트별 총점을 만드는 것도 가능할 것 같다고 생각했습니다.
다만 이번에는 기존 PartScores가 총점 누적 역할을 하고 있어서, 그 부분은 유지하고 평균 점수 계산과 rank 계산만 변경하는 쪽은 어떨까 싶었습니다. 또 groupingBy로 바꾸면 SoptPart -> Part 변환과 null 필터링이 collector 안에 함께 들어가게 되어서, 현재처럼 총점 누적 / 평균 점수 계산 / rank 계산 단계를 나누는 구조도 어떨까 하여 이렇게 구성해보았는데, 혹시 재헌님 생각은 어떠실까요?
There was a problem hiding this comment.
요게 가독성이 좀 떨어지시면 이 그룹핑 로직 자체를 메서드로 묶어서 처리할 수도 있을 것 같긴해요!
다만 이건 민경님이 보시기에 더 잘 읽힐 것 같은 방향으로 진행하셔도 될 것 같습니다!
| public class SoptampPartRankCalculator { | ||
|
|
||
| private final List<SoptampUserInfo> userInfos; | ||
| private static final BigDecimal ZERO_POINT = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); |
There was a problem hiding this comment.
소수점 몇째 자리까지 사용하는 지를 별도 상수로 빼서 관리해도 좋을 것 같아요! 하단의
BigDecimal averagePoint = memberCount == 0 ? ZERO_POINT
: BigDecimal.valueOf(totalScore)
.divide(BigDecimal.valueOf(memberCount), 2, RoundingMode.HALF_UP);
같은 부분도 상수로 컨트롤하면 정책 변경에 유연하게 대처하기 좋을 것 같습니다~
Related issue 🛠
Work Description ✏️
파트별 랭킹 점수를 총점 / 현재 기수 파트원 수 기준으로 계산하도록 수정했습니다.
user_activity_histories에서 조회하도록 했고,is_sopt = true,role = MEMBER조건으로 일반 파트원 수만 반영되도록 했습니다.Related ScreenShot 📷
To Reviewers 📢