Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[YS-98] feat: 지역별 공고 게시글 개수 조회 API 구현 및 WebExceptionHandler 리팩터링 #29

Merged
merged 10 commits into from
Jan 13, 2025

Conversation

Ji-soo708
Copy link
Member

@Ji-soo708 Ji-soo708 commented Jan 13, 2025

💡 작업 내용

  • 지역별 공고 게시글 개수 조회 API 구현

파라미터가 입력 안 했을 때
스크린샷 2025-01-13 오후 3 49 33

파라미터 입력했을 때
스크린샷 2025-01-13 오후 3 49 23

  • 사용하지 않는 Exception 핸들러 관련 파일 삭제
  • WebExceptionHandler 리팩터링

✅ 셀프 체크리스트

  • PR 제목을 형식에 맞게 작성했나요?
  • 브랜치 전략에 맞는 브랜치에 PR을 올리고 있나요?
  • 테스트는 잘 통과했나요?
  • 빌드에 성공했나요?
  • 본인을 assign 해주세요.
  • 해당 PR에 맞는 label을 붙여주세요.

🙋🏻‍ 확인해주세요

  • 잘못된 파라미터 값에 대해서 예외가 발생하는지 확인했지만, 에러는 발생하는데 상태 코드가 200으로 반환되는 문제가 있었습니다. 프론트에서 API 연결하기 전에 빠르게 해결해야 한다고 생각해 해당 PR에서 사용하지 않는 Exception 핸들러 파일을 삭제하고, WebExceptionHandler를 리팩터링했습니다!

🔗 Jira 티켓


https://yappsocks.atlassian.net/browse/YS-98

@Ji-soo708 Ji-soo708 self-assigned this Jan 13, 2025
@github-actions github-actions bot changed the title feat: 지역별 공고 게시글 개수 조회 API 구현 및 WebExceptionHandler 리팩터링 [YS-98] feat: 지역별 공고 게시글 개수 조회 API 구현 및 WebExceptionHandler 리팩터링 Jan 13, 2025
Comment on lines +28 to +34
fun getExperimentPostCounts(input: Any): Any {
return when (input) {
is GetExperimentPostCountsByRegionUseCase.Input -> getExperimentPostCountsByRegionUseCase.execute(input)
is GetExperimentPostCountsByAreaUseCase.Input -> getExperimentPostCountsByAreaUseCase.execute(input)
else -> throw IllegalArgumentException("Invalid input type: ${input::class.java.simpleName}")
}
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번 기능은 하나의 유즈케이스에 모든 로직을 담기에는 규모가 크다고 판단하여, 두 유즈케이스로 나누어 구현했습니다. input으로 온 파라미터 유무에 따라 적합한 유즈케이스를 실행하도록 구현했습니다.

@Ji-soo708 Ji-soo708 added ♻️ REFACTORING 리팩토링 ✨ FEATURE 기능 추가 labels Jan 13, 2025
Comment on lines 31 to 49
val regionData = region.let { experimentPostGateway.countExperimentPostByRegionGroupedByArea(it) } ?: emptyList()
val areaCounts = getAreaCounts(region, regionData)

return Output(total, areaCounts)
}

private fun getAreaCounts(region: Region?, regionData: List<Tuple>): List<PostCountsByArea> {
return region?.getAreas()?.map { area ->
val areaCount = findAreaCount(regionData, area)
PostCountsByArea(name = area.displayName, count = areaCount)
} ?: emptyList()
}

private fun findAreaCount(regionData: List<Tuple>, area: Area): Int {
return regionData.find { tuple ->
val regionArea = tuple.get(0, Area::class.java)
regionArea == area
}?.get(1, Long::class.java)?.toInt() ?: 0
}
Copy link
Member Author

@Ji-soo708 Ji-soo708 Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지역별 공고 개수를 매칭하는 과정에서, 각 Area에 해당하는 공고 개수를 찾기 위해 regionData와 매칭 작업을 진행했습니다. 지역 구분이 많아 휴먼 에러가 발생할 수 있어, 이처럼 응답 필드를 정확히 매칭하고자 했습니다.

다만, 이 API는 자주 호출될 거라 기대하는데 매번 매칭 작업을 반복하는 것은 비효율적이라 생각합니다. 추후 레디스 캐싱 등을 활용해 최적화할 필요가 있을 것 같습니다… 🥲

Copy link
Contributor

@chock-cho chock-cho Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지역별 공고 개수를 매칭하는 과정에서 지역 구분이 많아 복잡할 수 있는 작업을 정확히 처리해주시고, 처리 방식을 나아가 고민하신 점이 인상깊었어요! 😊

말씀하신 우려사항에 대해서도 공감가는 게, 해당 API는 상당히 많이 호출될 거라 판단되어서 성능 최적화가 필요하다고 생각이 들어요. 🤔 특히 회원가입이나 공고 등록등에서 드롭다운으로 지역을 필터링하는 방법을 채택하는 반면, 공고 조회에서는 공고 개수를 보여준다는 구조라서요.
지수님 말씀처럼 레디스 캐싱을 도입해 자주 조회되는 데이터를 캐싱하는 방식도 좋고, 정기적인 배치 작업으로 캐싱 데이터를 갱신하는 방식도 고려해볼 수 있을 것 같아요.
예를 들어, 지역별 공고 개수를 캐싱에 저장해두고, 일정 주기로 배치 작업을 통해 갱신하면 실시간성을 어느 정도 유지하면서도 성능 최적화에 대한 이슈가 해결되지 않을까,, 개인적인 생각입니다!

멋진 설계와 고민 감사드리며, 추후에 디벨롭 과정에서 이 부분을 함께 논의해봐도 좋을 것 같아요! 🙌

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞아요! 저도 이 부분을 구현하면서 만약 나중에 레디스를 활용한다면, TTL을 설정하여 적당히 실시간성을 유지하면서도 성능을 개선하면 좋겠다고 생각했어요. 👍

요즘 개발하다 보니, 서비스 특성상 레디스의 필요성을 더 많이 느끼는 것 같아요. MVP 기능 개발 이후에는 레디스 같은 인프라나 기술을 적극적으로 활용해 성능이나 안정성을 개선해 나가고 싶습니다. ☺️

@Ji-soo708 Ji-soo708 requested a review from chock-cho January 13, 2025 07:43
chock-cho
chock-cho previously approved these changes Jan 13, 2025
Copy link
Contributor

@chock-cho chock-cho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WebExceptionHandler를 리팩터링하는 것이 상당히 큰 작업이었을 텐데, 꼼꼼하게 처리해주신 점이 인상 깊었어요!
JPQL과 querydsl 혼합 방식에 대해 코멘트 남겨드렸으니 가볍게 확인 부탁드릴게요.

수고 많으셨습니다~!

Comment on lines +13 to +17
@Query("SELECT e.area, COUNT(e) FROM experiment_post e WHERE e.region = :region GROUP BY e.area")
fun countExperimentPostByRegionGroupedByArea(@Param("region") region: Region): List<Tuple>

@Query("SELECT e.region, COUNT(e) FROM experiment_post e GROUP BY e.region")
fun countExperimentPostGroupedByRegion(): List<Tuple>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 Repository에서 JPQL을 활용해 간단한 정적 쿼리를 작성하신 점이 효율적이고 깔끔하다고 생각됩니다! 😊

다만 저번 PR에서 querydsl 세팅을 마친 상태라 어느 정도 합의가 필요하면 좋을 것 같아요.

특히 프로젝트에서 정적 쿼리와 동적 쿼리가 혼재되어 있다면,
저는 JPQL과 querydsl을 상황에 따라(예를 들자면 동적쿼리나 복잡한 조인연산 등등에는 querydsl, 아니라면 JPQL 방식을 채택한다든지...) 어느정도 혼합해서 사용하는 것도 좋은 접근법이라고 생각되는데, 혹시 이 부분에 대해 지수님은 어떻게 생각하시는지 궁금합니다! 🙌

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 JPQL과 QueryDSL을 상황에 맞게 적절히 활용하는 것이 효율적이라고 생각합니다!

이전에 모든 쿼리를 QueryDSL로만 처리했던 경험이 있는데, 한두 줄로 끝나는 간단한 쿼리도 QueryDSL로 구현하려다 보니 오히려 개발 생산성이 떨어진다고 느낀 적이 많았어요.

그래서 제 개인적인 의견으로는, 간단한 쿼리는 JPQL을 활용하고, 복잡하거나 동적 쿼리가 필요한 경우에는 QueryDSL을 사용하는 방향이 장기적으로 더 좋은 선택이라고 생각합니다.

수정님도 이 의견에 동의하신다면, 이 방향으로 진행해 보면 좋을 것 같아요! ☺️

@Ji-soo708 Ji-soo708 merged commit 829bfa9 into dev Jan 13, 2025
3 checks passed
@Ji-soo708 Ji-soo708 deleted the feat/YS-98 branch January 13, 2025 10:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ FEATURE 기능 추가 ♻️ REFACTORING 리팩토링
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants