[REFACTOR] #491 CampaignReviewUsecase 조회 흐름 분리#491
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
Walkthrough읽기 및 쿼리 책임을 Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (4)
src/main/java/com/lokoko/domain/campaignReview/application/service/CampaignReviewReadService.java (3)
213-261: 완료된 리뷰 조회 로직을 간소화할 수 있습니다.현재
findContentTypesByRound로 타입 목록을 조회한 후, 각 타입별로findByContentType을 다시 호출합니다.getAllByCreatorCampaignAndRound(Line 265에서 이미 사용 중)를 활용하면 단일 조회로 처리할 수 있습니다.♻️ 간소화 예시 (createCompletedFirstReviewContents)
private List<CompletedReviewResponse.CompletedReviewContent> createCompletedFirstReviewContents( CreatorCampaign creatorCampaign ) { - List<ContentType> existingFirstTypes = - campaignReviewGetService.findContentTypesByRound(creatorCampaign.getId(), ReviewRound.FIRST); - - return existingFirstTypes.stream() - .map(contentType -> { - Optional<CampaignReview> firstReview = campaignReviewGetService - .findByContentType(creatorCampaign.getId(), ReviewRound.FIRST, contentType); - - if (firstReview.isPresent()) { - CampaignReview review = firstReview.get(); - return CompletedReviewResponse.CompletedReviewContent.builder() - .contentType(contentType) - .captionWithHashtags(review.getCaptionWithHashtags()) - .mediaUrls(campaignReviewGetService.getOrderedMediaUrls(review)) - .build(); - } - return null; - }) - .filter(Objects::nonNull) - .toList(); + List<CampaignReview> firstReviews = + campaignReviewGetService.getAllByCreatorCampaignAndRound(creatorCampaign, ReviewRound.FIRST); + + return firstReviews.stream() + .map(review -> CompletedReviewResponse.CompletedReviewContent.builder() + .contentType(review.getContentType()) + .captionWithHashtags(review.getCaptionWithHashtags()) + .mediaUrls(campaignReviewGetService.getOrderedMediaUrls(review)) + .build()) + .toList(); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/lokoko/domain/campaignReview/application/service/CampaignReviewReadService.java` around lines 213 - 261, Both createCompletedReviewContents and createCompletedFirstReviewContents make N+1 lookups by calling campaignReviewGetService.findContentTypesByRound then findByContentType per type; replace that by a single call to campaignReviewGetService.getAllByCreatorCampaignAndRound(creatorCampaign, ReviewRound.FIRST/SECOND) to fetch all CampaignReview objects, then map each CampaignReview to a CompletedReviewResponse.CompletedReviewContent using review.getContentType(), review.getCaptionWithHashtags(), and campaignReviewGetService.getOrderedMediaUrls(review); remove the intermediate findContentTypesByRound/findByContentType calls and eliminate null handling since mapping from the returned reviews will produce only valid contents.
119-141:createReviewContentStatuses에서도 동일한 중복 조회 패턴이 있습니다.
currentRound == ReviewRound.SECOND일 때hasFirstReview는 항상true입니다(Line 117 로직). 따라서 Lines 122-129와 134-141에서 동일한 1차 리뷰를 두 번 조회합니다.♻️ 통합 리팩토링 제안
String brandNote = null; Instant revisionRequestedAt = null; - if (currentRound == ReviewRound.SECOND) { - Optional<CampaignReview> firstReviewForContentType = campaignReviewGetService - .findByContentType(creatorCampaign.getId(), ReviewRound.FIRST, contentType); - if (firstReviewForContentType.isPresent()) { - CampaignReview review = firstReviewForContentType.get(); - brandNote = review.getBrandNote(); - revisionRequestedAt = review.getRevisionRequestedAt(); - } - } - String captionWithHashtags = null; List<String> mediaUrls = null; if (hasFirstReview) { Optional<CampaignReview> existingReview = campaignReviewGetService .findByContentType(creatorCampaign.getId(), ReviewRound.FIRST, contentType); if (existingReview.isPresent()) { CampaignReview review = existingReview.get(); + if (currentRound == ReviewRound.SECOND) { + brandNote = review.getBrandNote(); + revisionRequestedAt = review.getRevisionRequestedAt(); + } captionWithHashtags = review.getCaptionWithHashtags(); mediaUrls = campaignReviewGetService.getOrderedMediaUrls(review); } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/lokoko/domain/campaignReview/application/service/CampaignReviewReadService.java` around lines 119 - 141, There are duplicate lookups of the first review when currentRound == ReviewRound.SECOND (and hasFirstReview is always true), causing two calls to campaignReviewGetService.findByContentType; refactor to perform a single lookup once (e.g., call campaignReviewGetService.findByContentType(creatorCampaign.getId(), ReviewRound.FIRST, contentType) into an Optional<CampaignReview> firstReview) and then extract brandNote, revisionRequestedAt, captionWithHashtags and mediaUrls from that single review using review.getBrandNote(), review.getRevisionRequestedAt(), review.getCaptionWithHashtags() and campaignReviewGetService.getOrderedMediaUrls(review); apply the same consolidation in createReviewContentStatuses (or extract a small helper like getFirstReviewForContentType / populateFirstReviewFields) to reuse the result instead of duplicating the service call.
179-199: 동일한 리뷰를 중복 조회하고 있습니다.
targetRound == ReviewRound.SECOND일 때firstReviewForContentType을 두 번 조회합니다(Lines 180-187, 192-199). 하나의 조회로 통합하면 불필요한 DB 호출을 줄일 수 있습니다.♻️ 중복 조회 통합 제안
String brandNote = null; Instant revisionRequestedAt = null; - if (targetRound == ReviewRound.SECOND) { - Optional<CampaignReview> firstReviewForContentType = campaignReviewGetService - .findByContentType(creatorCampaign.getId(), ReviewRound.FIRST, contentType); - if (firstReviewForContentType.isPresent()) { - CampaignReview review = firstReviewForContentType.get(); - brandNote = review.getBrandNote(); - revisionRequestedAt = review.getRevisionRequestedAt(); - } - } - String captionWithHashtags = null; List<String> mediaUrls = null; if (targetRound == ReviewRound.SECOND) { Optional<CampaignReview> firstReviewForContentType = campaignReviewGetService .findByContentType(creatorCampaign.getId(), ReviewRound.FIRST, contentType); if (firstReviewForContentType.isPresent()) { CampaignReview review = firstReviewForContentType.get(); + brandNote = review.getBrandNote(); + revisionRequestedAt = review.getRevisionRequestedAt(); captionWithHashtags = review.getCaptionWithHashtags(); mediaUrls = campaignReviewGetService.getOrderedMediaUrls(review); } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/com/lokoko/domain/campaignReview/application/service/CampaignReviewReadService.java` around lines 179 - 199, When targetRound == ReviewRound.SECOND you call campaignReviewGetService.findByContentType(...) twice; replace the two separate lookups with a single Optional<CampaignReview> firstReviewForContentType = campaignReviewGetService.findByContentType(creatorCampaign.getId(), ReviewRound.FIRST, contentType) and, if present, populate brandNote, revisionRequestedAt, captionWithHashtags and mediaUrls (use campaignReviewGetService.getOrderedMediaUrls(review) for mediaUrls) from that one review instance to eliminate the duplicate DB call.src/test/java/com/lokoko/domain/campaignReview/application/service/CampaignReviewReadServiceTest.java (1)
130-145: 추가 테스트 커버리지를 고려해 주세요.현재 테스트는 주요 시나리오를 잘 다루고 있습니다. 다음 케이스들을 추후 추가하면 테스트 커버리지가 더 강화됩니다:
getMyReviewables()메서드 테스트getCompletedReviews()non-beta 플로우 (2차 리뷰 반환)ReviewRound.FIRST/ReviewRound.SECOND파라미터에 따른 필터링 로직추가 테스트 케이스 생성을 도와드릴까요?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/com/lokoko/domain/campaignReview/application/service/CampaignReviewReadServiceTest.java` around lines 130 - 145, Add unit tests to increase coverage: create tests in CampaignReviewReadServiceTest for getMyReviewables(), for getCompletedReviews() non-beta flow verifying it returns second-round reviews (use campaignReviewReadService.getCompletedReviews and mock necessary services like campaignGetService and creatorCampaignGetService), and tests asserting filtering by ReviewRound.FIRST and ReviewRound.SECOND parameters (exercise methods that accept ReviewRound and verify returned lists are correctly filtered). Mock/stub dependencies (campaignGetService, creatorCampaignGetService, review repositories) and use the existing assert patterns to validate returned elements and exception-free behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@src/main/java/com/lokoko/domain/campaignReview/application/service/CampaignReviewReadService.java`:
- Around line 213-261: Both createCompletedReviewContents and
createCompletedFirstReviewContents make N+1 lookups by calling
campaignReviewGetService.findContentTypesByRound then findByContentType per
type; replace that by a single call to
campaignReviewGetService.getAllByCreatorCampaignAndRound(creatorCampaign,
ReviewRound.FIRST/SECOND) to fetch all CampaignReview objects, then map each
CampaignReview to a CompletedReviewResponse.CompletedReviewContent using
review.getContentType(), review.getCaptionWithHashtags(), and
campaignReviewGetService.getOrderedMediaUrls(review); remove the intermediate
findContentTypesByRound/findByContentType calls and eliminate null handling
since mapping from the returned reviews will produce only valid contents.
- Around line 119-141: There are duplicate lookups of the first review when
currentRound == ReviewRound.SECOND (and hasFirstReview is always true), causing
two calls to campaignReviewGetService.findByContentType; refactor to perform a
single lookup once (e.g., call
campaignReviewGetService.findByContentType(creatorCampaign.getId(),
ReviewRound.FIRST, contentType) into an Optional<CampaignReview> firstReview)
and then extract brandNote, revisionRequestedAt, captionWithHashtags and
mediaUrls from that single review using review.getBrandNote(),
review.getRevisionRequestedAt(), review.getCaptionWithHashtags() and
campaignReviewGetService.getOrderedMediaUrls(review); apply the same
consolidation in createReviewContentStatuses (or extract a small helper like
getFirstReviewForContentType / populateFirstReviewFields) to reuse the result
instead of duplicating the service call.
- Around line 179-199: When targetRound == ReviewRound.SECOND you call
campaignReviewGetService.findByContentType(...) twice; replace the two separate
lookups with a single Optional<CampaignReview> firstReviewForContentType =
campaignReviewGetService.findByContentType(creatorCampaign.getId(),
ReviewRound.FIRST, contentType) and, if present, populate brandNote,
revisionRequestedAt, captionWithHashtags and mediaUrls (use
campaignReviewGetService.getOrderedMediaUrls(review) for mediaUrls) from that
one review instance to eliminate the duplicate DB call.
In
`@src/test/java/com/lokoko/domain/campaignReview/application/service/CampaignReviewReadServiceTest.java`:
- Around line 130-145: Add unit tests to increase coverage: create tests in
CampaignReviewReadServiceTest for getMyReviewables(), for getCompletedReviews()
non-beta flow verifying it returns second-round reviews (use
campaignReviewReadService.getCompletedReviews and mock necessary services like
campaignGetService and creatorCampaignGetService), and tests asserting filtering
by ReviewRound.FIRST and ReviewRound.SECOND parameters (exercise methods that
accept ReviewRound and verify returned lists are correctly filtered). Mock/stub
dependencies (campaignGetService, creatorCampaignGetService, review
repositories) and use the existing assert patterns to validate returned elements
and exception-free behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 904a6b48-ff14-4dea-89fd-e0176215ad06
📒 Files selected for processing (3)
src/main/java/com/lokoko/domain/campaignReview/application/service/CampaignReviewReadService.javasrc/main/java/com/lokoko/domain/campaignReview/application/usecase/CampaignReviewUsecase.javasrc/test/java/com/lokoko/domain/campaignReview/application/service/CampaignReviewReadServiceTest.java
Related issue 🛠
작업 내용 💻
BrandUsecase.getCreatorPerformances(...)의 조회 조립/수동 페이징 책임을BrandCreatorPerformanceQueryService로 분리CampaignReviewUsecase의 조회 메서드(getMyReviewableCampaign,getMyReviewables,getCompletedReviews)를CampaignReviewReadService로 분리BrandUsecase,CampaignReviewUsecase는 조회 진입점과 최소한의 orchestration만 담당하도록 정리secondContentPlatform == null일 때 발생할 수 있던 NPE 방지 처리같이 얘기해보고 싶은 내용이 있다면 작성 📢
usecase를 없애기보다는, fat usecase에 몰려 있던 조회 조립 책임을QueryService / ReadService로 걷어내는 정리 작업에 가까워요Assembler/Resolver로 분리하는 방법도 있긴한데, 너무 과한거같아서 조회 전용 서비스 안에 응집시키는 선까지 작업을 진행했어요)Summary by CodeRabbit
릴리스 노트
Refactor
Tests