작업 내용 : 목표 아래에 피드 구현하기
현재 특정 목표에 진입했을 때의 view
- 여기서 해당 목표에 도전중인 유저들의 활동내역 이벤트(DONE, SUPER-DONE, 도전 시작, 포기, 연속 수행 등)를 한번에 볼 수 있는 피드를 구현하고자 한다.
- 여러 이벤트들을 가져와서 각기 다른
고민
1. 기존에 있는 테이블인 Done, Super-Done객체를 그대로 가져와서 활용하면 그만일지
-> 처음 시도로는 Union해서 가져왔지만 단점이 많이 발견.
-> 추후에 여러 이벤트들이 추가될텐데 그 때 확장성이 좋지 않아 보임.
2. 여러 테이블에 있는 정보들이 하나의 리스트로 가져와야 한다.
-> 테이블의 튜플을 그대로 가져오는 것이 언제까지 유효할지?
-> 예를들어 연속 달성 이벤트를 표현하려면 기존의 튜플만으로는 바로 적용이 어려워보인다.
3. 우선은 최신순으로 페이징처리 예정이지만, 추후 추천순은 어떤식으로 구현해야할지
여러가지 검색하던 도중, 뉴스피드 구현이나 알림 구현과 결이 비슷하다는 생각이 들었다.
뉴스피드 시스템 구현, 알림 시스템 구현 등을 참고하기로 했다.
시도 1 : Done, SuperDone 테이블을 Union해서 최신순 정렬해서 가져오기
- 하나의 목표(goal)에 도전(promise_goal)하고 있는 정보를 포함한 done, super_done 테이블이 별도로 분리되어있다.
- 그렇기에, 각각의 최신순 5개씩 정보를 가져와서 정렬하게 되면 전체에서의 최신순 상위 데이터를 가져오지 못할 수 있다.
-> UNION 하여 createdAt으로 정렬 후 가져오기 시도
JPQL 사용
@Query("SELECT new com.wooin.dailyone.controller.response.FeedOfGoalResponse(" +
"com.wooin.dailyone.model.FeedType.DONE, d.id, d.createdAt as createdAt, d.promiseGoal.user.id, d.promiseGoal.user.nickname) " +
"FROM Done d WHERE d.promiseGoal.goal.id = :goalId " +
"UNION " +
"SELECT new com.wooin.dailyone.controller.response.FeedOfGoalResponse(" +
"com.wooin.dailyone.model.FeedType.SUPER_DONE, s.id, s.createdAt as createdAt, s.promiseGoal.user.id, s.promiseGoal.user.nickname) " +
"FROM SuperDone s WHERE s.promiseGoal.goal.id = :goalId " +
"ORDER BY createdAt DESC"
)
List<FeedOfGoalResponse> selectFeedOfGoal(Long goalId);
- JPQL에서 UNION이 구현이 되질 않는다. (애당초 UNION을 쓸 정도면 모델링이 옳지 못하다는 누군가의 지나가는 말도 들었다)
- 테이블 두개의 데이터 전체를 합치는 과정이 비효율적이다. 물론, 페이징을 통해서 줄일 수는 있지만 확장에 있어 한계가 명확하다.
- 타이핑시 휴먼에러의 리스크가 존재한다. (공백, 줄바꿈시 특수문자 등)
NativeQuery 사용
@Query(value = "SELECT 'DONE' as feed_type, d.id, d.created_at, u.id as user_id, u.nickname " +
"FROM done d " +
"JOIN promise_goal pg ON d.promise_goal_id = pg.id " +
"JOIN users u ON pg.user_id = u.id " +
"WHERE pg.goal_id = :goalId " +
"UNION " +
"SELECT 'SUPER_DONE' as feed_type, s.id, s.created_at, u.id as user_id, u.nickname " +
"FROM super_done s " +
"JOIN promise_goal pg ON s.promise_goal_id = pg.id " +
"JOIN users u ON pg.user_id = u.id " +
"WHERE pg.goal_id = :goalId " +
"ORDER BY created_at DESC " +
"LIMIT 10",
nativeQuery = true
)
List<FeedOfGoalResponse> selectFeedOfGoal(Long goalId);
- 우선 가독성이 현저히 떨어진다. (QueryDSL 도입시, 리팩토링은 가능하지만 성능이나 기능구현의 한계가 있다)
- 향후 done, super-done 이외에 다른 이벤트가 추가되었을 때, 코드 전체가 변할 수 있다.
참고링크
시도2 : 피드 객체 추가 구현
(8/27 진행중)
'Projects > D'ONE - 개인프로젝트' 카테고리의 다른 글
생애 첫 부하테스트 (nGrinder) (0) | 2024.09.23 |
---|---|
240820 : 간만의 업데이트 ('목표' 리스트 탭 추가) (0) | 2024.08.20 |
트러블슈팅 : 목표에 오늘의 DONE 기록시 중복요청 분산락으로 방지하기 (2/2) (0) | 2024.08.05 |
트러블슈팅 : 목표에 오늘의 DONE기록시 동시성 문제로 인한 중복 생성 (1/2) (0) | 2024.07.31 |
현재까지의 D'ONE (0) | 2024.07.19 |