HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
♥️
2기 최종 프로젝트 팀별 공간
/
💸
10원모아10조❗️
/
🏝️
Back End
/
🗑️
메모
/
😂
일별 상세 내역 Flow - 0801 리팩터 필요
😂

일별 상세 내역 Flow - 0801 리팩터 필요

 
내가 레거시를 낳았다…
 
현재 코드는 유지보수 관점을 떠나서, 네이밍, 가독성 측면에서도 너무 안좋은 코드임을 인지하고 있습니다.
제가 생각한 로직을 공유하고, 인지하고 있는 문제점, 그리고 윌리엄이 남겨주신 피드백의 대한 생각 및 공유로 작성해보겠습니다. 리팩터 후에 메모도 따로 남길게요!
 

💧 로직

notion image
우선 일일 상세내역을 조회하기 위해서
저희가 필요한 테이블은 expenditure와 income입니다.
 
  • 제가 여기서 겪었던 문제는 income과 expenditure에 대해서 페이징 처리가 아니라
    • 일일 상세내역에 대한 페이징을 작성해야한다는 것이었어요.
    • 즉, 사용자가 2022-08월에 작성한 expenditure와 income의 날짜의 합집합에 해당하는 일일 상세 내역을 보여주어야합니다.
    • 예를 들어 사용자가 지출을 20~11 10개, 수입을 15에서 6일 작성하였고, page=1&size=10으로 페이징 요청을하였다면 최신날짜 20~11일에 대한 상세내역을 보여주어야합니다.
    •  
 
  • 고민
    • 이때 어차피 한달을 10일씩 자르면 페이징이 최대 4개(31일) 보통 3개(30,29,28)로 짤리니까 그냥 고정된 날짜로 짜를까했는데!!!, 이경우 유저가 30~21일 중 30일만 작성했다면… 30일에 데이터만 볼 수 있어요.. 그리고 페이징의 개념과 맞지 않는다고 생각했습니다.
    • 날짜를 합집합하려고 했는데… querydsl과 jpa는 union을 지원하지 않습니다 …
    • 저는 상세내역을 페이징하기 위해 사용자가 2022-08월에 작성한 expenditure와 income의 모든 날짜를 불러온 후 합집합하였습니다.
    • 그후 프론트에서 요청한 페이징과 오프셋을 사용하여 필요한 날짜 데이터들을 추출하였습니다.
    •  
      private List<LocalDate> getPageDate(PageCustomRequest pageCustomRequest, Long userId, LocalDate date) { long offset = pageCustomRequest.getOffset(); int size = pageCustomRequest.getSize(); int year = date.getYear(); int month = date.getMonthValue(); List<LocalDateTime> expenditureTimes = queryFactory.select(expenditure.registerDate) .from(expenditure) .where( expenditure.user.id.eq(userId), expenditure.registerDate.year().eq(year), expenditure.registerDate.month().eq(month) ) .fetch(); List<LocalDateTime> incomeTimes = queryFactory.select(income.registerDate) .from(income) .where( income.user.id.eq(userId), income.registerDate.year().eq(year), income.registerDate.month().eq(month) ) .fetch(); List<LocalDate> expenditureDate = expenditureTimes.stream() .map(LocalDateTime::toLocalDate) .collect(Collectors.toList()); List<LocalDate> incomeDate = incomeTimes.stream() .map(LocalDateTime::toLocalDate) .collect(Collectors.toList()); expenditureDate.addAll(incomeDate); List<LocalDate> dates = expenditureDate.stream() .distinct() .collect(Collectors.toList()); Collections.sort(dates, (d1, d2) -> d1.isAfter(d2) ? -1 : 1); int end = (int)offset + size > dates.size() ? dates.size() : (int)offset + size; return dates.subList(((int)offset), end); }
    • 제가 생각하는 문제는 지금.. 코드에서 모든것을 해결하려 하고 있어여..
    • 로직은 맞다고 보는데
      • 제가 생각하는 해결 방안은 지금처럼 코드에서 좀더 깔끔하게 개선하려고 노력한다.
      • union이 지원안되니까 native쿼리로 불러와서 정렬한다.
        • 네이티브 쿼리는 db vendor 종속적이어서 반대하실 수도 있는데 이부분 고려해보시면 좋을 것같아요, JPA가 추상화가 잘 되어있다고 하지만, JPA도 저는 어차피 벤더 종속적이라고 생각합니다..
 
  • 가장 최악 - 개선 무조건…
 
public PageCustomImpl<FindDayAccountResponse> findDailyAccount(Long userId, PageCustomRequest pageRequest, LocalDate date) { List<LocalDate> dates = getPageDate(pageRequest, userId, date); List<FindDayAccountResponse> responses = new ArrayList<>(); dates.iterator().forEachRemaining( d -> responses.add(new FindDayAccountResponse(d, getDayIncomeAmount(d), getDayExpenditureAmount(d), getDayDetails(userId, d))) ); Collections.sort(responses, (o1, o2) -> o2.getRegisterDate().getDayOfMonth() - o1.getRegisterDate().getDayOfMonth()); return new PageCustomImpl<>(pageRequest.getPage(), pageRequest, responses); }
 
  • 지금 iterator를 돌려서 getDayDetails가 돌아가고 있습니다.
  • 20~11일의 날짜가 있으면 각자의 데이터마다 쿼리를 쏘는거죠.
  • 이부분 쿼리 개선해서 between 날짜 이용해서 한 번에 데이터를 쏘도록 개선할 예정입니다.
 
 

👍 윌리엄 리뷰 + 사랑해여

  • 지금 계층을 보면, service는 정말 단순히 데이터 서빙만 하고 있습니다. 그건 둘째치고 repository에서 service로 넘겨주는 dto를 controller로 반환하는 문제져.
  • 이렇게라도 구현한 이유
    • 현재 화면에 맞춘 쿼리 작성입니다.
      • notion image
         
      • 원래 사용자 정의 커스텀으로 QueryDsl을 사용하는 class를 만듭니다.
      • MemberRepositoryImpl이 SimpleJpaRepository 구현체의 역할을 하는 거죠?
      • 근데 현재 AccountBookQueryRepository는 Jpa interface와 묶지 않았습니다 저는
        • 쿼리가 화면 종속적이라고 생각했습니다.
        • 쿼리를 재사용하기 어렵다고 생각했고, 특정 엔티티 하나의 종속되어 있는 repository가 아니라고 판단했습니다.
         
    • 개선의 의지가 없는이유
      • 추후 서비스에서 여러번 끌고 가서 사용할 가능성이 적다고 생각했습니다.
      • 현재 우리의 기한으로 오버엔지니어링이라고 생각합니다.
      •  

가슴 아픈 코드를 낳아 죄송합니다.