Conversation
Walkthrough이 변경사항은 도메인 객체 및 API 응답/요청 DTO의 네이밍을 일관성 있게 정비하고, 책 관련 모집방(Recruiting Room) 조회 기능을 신규로 추가합니다. 또한, 도메인 계층에서 ISBN으로 책을 조회하는 방식이 Optional 반환 및 예외 처리 방식으로 개선되었으며, 관련 서비스와 테스트 코드도 이에 맞게 수정되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant BookQueryController
participant BookRecruitingRoomsUseCase
participant BookRecruitingRoomsService
participant RoomQueryPort
participant BookQueryMapper
Client->>BookQueryController: GET /books/{isbn}/recruiting-rooms?cursor=...
BookQueryController->>BookRecruitingRoomsUseCase: getRecruitingRoomsWithBook(isbn, cursor)
BookRecruitingRoomsUseCase->>BookRecruitingRoomsService: getRecruitingRoomsWithBook(isbn, cursor)
BookRecruitingRoomsService->>RoomQueryPort: findRoomsByIsbnOrderByDeadline(isbn, cursor)
RoomQueryPort-->>BookRecruitingRoomsService: CursorBasedList<RoomQueryDto>
BookRecruitingRoomsService->>BookQueryMapper: toRecruitingRoomDtoList(roomDtos)
BookQueryMapper-->>BookRecruitingRoomsService: List<RecruitingRoomDto>
BookRecruitingRoomsService-->>BookRecruitingRoomsUseCase: BookRecruitingRoomsResponse
BookRecruitingRoomsUseCase-->>BookQueryController: BookRecruitingRoomsResponse
BookQueryController-->>Client: BaseResponse<BookRecruitingRoomsResponse>
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changesNo out-of-scope changes detected. Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (5)
src/main/java/konkuk/thip/book/application/port/in/BookRecruitingRoomsUseCase.java (1)
7-7: 매개변수 검증 고려 필요
isbn과cursor매개변수에 대한 검증 로직이나 문서화를 고려해보세요. 특히 ISBN 형식 검증이나 null 처리에 대한 명세가 있으면 좋을 것 같습니다.다음과 같이 JavaDoc 추가를 고려해보세요:
+ /** + * 특정 책으로 모집중인 모임방을 조회합니다. + * + * @param isbn 책의 ISBN (필수) + * @param cursor 페이지네이션을 위한 커서 (null 가능) + * @return 모집중인 모임방 목록과 페이지네이션 정보 + */ BookRecruitingRoomsResponse getRecruitingRoomsWithBook(String isbn, String cursor);src/main/java/konkuk/thip/book/adapter/in/web/response/BookIsSavedResponse.java (1)
11-13: 정적 팩토리 메서드의 코드 포맷팅을 개선하세요.레코드 설계와 정적 팩토리 메서드 패턴은 적절하지만, 생성자 호출 시 매개변수 사이의 공백이 누락되었습니다.
다음과 같이 수정하세요:
- return new BookIsSavedResponse(bookIsSavedResult.isbn(),bookIsSavedResult.isSaved()); + return new BookIsSavedResponse(bookIsSavedResult.isbn(), bookIsSavedResult.isSaved());src/test/java/konkuk/thip/book/adapter/in/web/BookRecruitingRoomApiTest.java (2)
66-75: 테스트 데이터 생성 방식을 개선할 수 있습니다.테스트 데이터 생성 시
TestEntityFactory를 활용하는 것을 고려해보세요. 현재는 인라인으로 빌더를 사용하고 있지만, 팩토리 메서드를 사용하면 코드 중복을 줄이고 유지보수성을 향상시킬 수 있습니다.다음과 같이 리팩토링할 수 있습니다:
- BookJpaEntity book = bookJpaRepository.save(BookJpaEntity.builder() - .isbn("1234567890123") - .title("모집책") - .authorName("저자") - .publisher("출판사") - .pageCount(300) - .description("설명") - .imageUrl("http://image.com") - .bestSeller(false) - .build()); + BookJpaEntity book = bookJpaRepository.save(TestEntityFactory.createBookWithISBN("1234567890123"));
114-122: API 응답 검증이 충분하지 않을 수 있습니다.현재는 기본적인 필드들만 검증하고 있습니다. 응답 DTO의 다른 중요한 필드들(예: 카테고리, 모집 인원, 마감일 등)도 검증하는 것을 고려해보세요.
다음과 같은 검증을 추가할 수 있습니다:
.andExpect(jsonPath("$.data.recruitingRoomList[0].roomId").value(recruitingRoom.getRoomId())) .andExpect(jsonPath("$.data.recruitingRoomList[0].roomName").value("모집 중 방")) + .andExpect(jsonPath("$.data.recruitingRoomList[0].recruitCount").value(5)) + .andExpect(jsonPath("$.data.recruitingRoomList[0].isPublic").value(true)) .andExpect(jsonPath("$.data.recruitingRoomList.length()").value(1));src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java (1)
14-17: 편의 메소드 추가가 유용하지만 네이밍 개선을 고려해보세요.
getByIsbnOrThrow디폴트 메소드는 편의성을 제공하는 좋은 추가입니다. 다만 메소드명을getByIsbn으로 단순화하거나findByIsbnOrThrow로 일관성을 맞추는 것을 고려해보세요.- default Book getByIsbnOrThrow(String isbn){ + default Book findByIsbnOrThrow(String isbn){
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (31)
src/main/java/konkuk/thip/book/adapter/in/web/BookCommandController.java(2 hunks)src/main/java/konkuk/thip/book/adapter/in/web/BookQueryController.java(4 hunks)src/main/java/konkuk/thip/book/adapter/in/web/request/BookIsSavedRequest.java(1 hunks)src/main/java/konkuk/thip/book/adapter/in/web/response/BookDetailSearchResponse.java(1 hunks)src/main/java/konkuk/thip/book/adapter/in/web/response/BookIsSavedResponse.java(1 hunks)src/main/java/konkuk/thip/book/adapter/in/web/response/BookMostSearchResponse.java(1 hunks)src/main/java/konkuk/thip/book/adapter/in/web/response/BookRecruitingRoomsResponse.java(1 hunks)src/main/java/konkuk/thip/book/adapter/in/web/response/BookSearchListResponse.java(3 hunks)src/main/java/konkuk/thip/book/adapter/in/web/response/GetBookMostSearchResponse.java(0 hunks)src/main/java/konkuk/thip/book/adapter/in/web/response/PostBookIsSavedResponse.java(0 hunks)src/main/java/konkuk/thip/book/adapter/out/persistence/BookCommandPersistenceAdapter.java(2 hunks)src/main/java/konkuk/thip/book/application/mapper/BookQueryMapper.java(1 hunks)src/main/java/konkuk/thip/book/application/port/in/BookRecruitingRoomsUseCase.java(1 hunks)src/main/java/konkuk/thip/book/application/port/in/dto/BookDetailSearchResult.java(1 hunks)src/main/java/konkuk/thip/book/application/port/in/dto/BookMostSearchResult.java(0 hunks)src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java(1 hunks)src/main/java/konkuk/thip/book/application/service/BookMostSearchRankService.java(1 hunks)src/main/java/konkuk/thip/book/application/service/BookRecruitingRoomsService.java(1 hunks)src/main/java/konkuk/thip/book/application/service/BookSavedService.java(1 hunks)src/main/java/konkuk/thip/book/application/service/BookSearchService.java(3 hunks)src/main/java/konkuk/thip/feed/application/service/FeedCreateService.java(1 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java(3 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/function/RoomQueryFunction.java(1 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomJpaRepository.java(1 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepository.java(1 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepositoryImpl.java(1 hunks)src/main/java/konkuk/thip/room/application/port/out/RoomQueryPort.java(2 hunks)src/main/java/konkuk/thip/room/application/service/RoomCreateService.java(1 hunks)src/test/java/konkuk/thip/book/adapter/in/web/BookChangeSavedControllerTest.java(7 hunks)src/test/java/konkuk/thip/book/adapter/in/web/BookDetailSearchControllerTest.java(2 hunks)src/test/java/konkuk/thip/book/adapter/in/web/BookRecruitingRoomApiTest.java(1 hunks)
💤 Files with no reviewable changes (3)
- src/main/java/konkuk/thip/book/application/port/in/dto/BookMostSearchResult.java
- src/main/java/konkuk/thip/book/adapter/in/web/response/GetBookMostSearchResponse.java
- src/main/java/konkuk/thip/book/adapter/in/web/response/PostBookIsSavedResponse.java
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java (1)
src/main/java/konkuk/thip/common/exception/EntityNotFoundException.java (1)
EntityNotFoundException(5-10)
src/main/java/konkuk/thip/book/application/mapper/BookQueryMapper.java (1)
src/main/java/konkuk/thip/common/util/DateUtil.java (1)
DateUtil(12-62)
src/test/java/konkuk/thip/book/adapter/in/web/BookRecruitingRoomApiTest.java (1)
src/test/java/konkuk/thip/common/util/TestEntityFactory.java (1)
TestEntityFactory(33-304)
🔇 Additional comments (54)
src/main/java/konkuk/thip/book/application/port/in/BookRecruitingRoomsUseCase.java (1)
5-8: 인터페이스 설계가 깔끔합니다!헥사고날 아키텍처의 포트 패턴을 잘 따르고 있으며, 커서 기반 페이지네이션을 지원하는 메서드 시그니처가 적절합니다.
src/main/java/konkuk/thip/book/adapter/in/web/request/BookIsSavedRequest.java (1)
7-11: 네이밍 일관성 개선이 좋습니다!
PostBookIsSavedRequest에서BookIsSavedRequest로의 네이밍 변경이 더 직관적이고 일관성 있습니다. 검증 어노테이션과 스키마 문서화도 적절하게 유지되었습니다.src/main/java/konkuk/thip/book/application/service/BookSavedService.java (1)
37-37: 메서드 변경이 코드 가독성을 향상시킵니다!
findByIsbn(isbn)에서getByIsbnOrThrow(isbn)로의 변경이 코드의 의도를 더 명확하게 표현합니다. 기존의EntityNotFoundException처리 로직과 완벽하게 호환되며, Optional 처리 부분을 제거하여 코드가 더 간결해졌습니다.src/main/java/konkuk/thip/book/application/service/BookMostSearchRankService.java (1)
59-59: 일관된 리팩토링으로 코드베이스 통일성 확보다른 서비스와 동일한 패턴으로
getByIsbnOrThrow메서드를 사용하여 코드베이스 전반의 일관성을 유지했습니다. 기존의 예외 처리 로직과 네이버 API 폴백 동작도 그대로 유지되어 기능상 변화가 없습니다.src/main/java/konkuk/thip/book/application/port/in/dto/BookDetailSearchResult.java (1)
9-9: 필드명 개선이 명확성을 높입니다
recruitingReadCount에서readCount로의 네이밍 변경이 더 간결하고 의미가 명확합니다.src/main/java/konkuk/thip/feed/application/service/FeedCreateService.java (1)
72-72: 메서드 호출 변경이 적절합니다.
findByIsbn에서getByIsbnOrThrow로 변경하여 코드 의도가 더 명확해졌습니다. 기존의 예외 처리 로직도 그대로 유지되어 기능상 문제가 없습니다.src/test/java/konkuk/thip/book/adapter/in/web/BookDetailSearchControllerTest.java (2)
143-143: 테스트가 DTO 필드명 변경에 맞게 올바르게 업데이트되었습니다.
recruitingReadCount()에서readCount()로 변경하여 리네이밍된 DTO 필드와 일치합니다.
188-188: 테스트가 DTO 필드명 변경에 맞게 올바르게 업데이트되었습니다.다른 테스트 메서드와 일관성을 유지하며
readCount()필드를 올바르게 검증하고 있습니다.src/test/java/konkuk/thip/book/adapter/in/web/BookChangeSavedControllerTest.java (2)
4-4: DTO 클래스명 변경이 일관성 있게 적용되었습니다.
PostBookIsSavedRequest에서BookIsSavedRequest로 리네이밍된 클래스를 올바르게 import하고 있습니다.
110-110: 모든 테스트 메서드에서 DTO 클래스명이 일관성 있게 업데이트되었습니다.
PostBookIsSavedRequest에서BookIsSavedRequest로의 변경이 모든 테스트 케이스에 올바르게 적용되어 컨트롤러 변경사항과 일치합니다.Also applies to: 135-135, 167-167, 193-193, 216-216, 234-234
src/main/java/konkuk/thip/room/application/service/RoomCreateService.java (1)
54-54: 인터페이스 변경에 따른 메서드 호출 업데이트가 적절합니다.
getByIsbnOrThrow사용으로 코드 의도가 명확해지고, 기존 예외 처리 로직과 잘 맞아떨어집니다.src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepository.java (1)
34-34: 새로운 Repository 메서드가 적절하게 추가되었습니다.ISBN 기반 모집방 조회 기능을 위한 메서드로, 기존 패턴을 따르며 커서 기반 페이지네이션을 올바르게 지원합니다. 메서드명도 의도를 명확하게 표현합니다.
src/main/java/konkuk/thip/room/adapter/out/persistence/function/RoomQueryFunction.java (1)
10-10: 메서드 시그니처 변경이 적절합니다.
userId매개변수를 제거하고 람다 캡처를 통해 동적으로 전달하는 방식으로 변경한 것은 코드 중복을 줄이는 좋은 접근법입니다. PR 목표에서 언급한 공통 함수형 인터페이스 도입 취지와 일치합니다.src/main/java/konkuk/thip/book/adapter/out/persistence/BookCommandPersistenceAdapter.java (1)
27-30: Optional 반환 패턴으로 개선된 설계입니다.예외 처리 로직을 제거하고
Optional<Book>을 반환하도록 변경한 것은 관심사 분리 측면에서 좋은 개선입니다. 영속성 계층에서는 데이터 존재 여부만 표현하고, 예외 처리는 상위 계층(getByIsbnOrThrow)에서 담당하는 것이 더 적절합니다.src/main/java/konkuk/thip/room/application/port/out/RoomQueryPort.java (1)
35-35: 새로운 쿼리 메서드가 기존 패턴과 일관성 있게 추가되었습니다.
findRoomsByIsbnOrderByDeadline메서드는 기존 인터페이스의 명명 규칙과 반환 타입을 잘 따르고 있으며, 커서 기반 페이지네이션을 지원하여 일관된 API를 제공합니다.src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomJpaRepository.java (1)
12-16: ACTIVE 상태 필터링이 추가된 쿼리 메서드가 올바르게 구현되었습니다.비즈니스 로직에 맞게
ACTIVE상태의 방만 카운트하도록 필터링이 추가되었고, 명명된 매개변수를 사용하여 가독성과 보안성을 높였습니다. JPQL 쿼리 구조도 적절합니다.src/main/java/konkuk/thip/book/application/port/out/BookCommandPort.java (4)
5-8: 새로운 import 추가가 적절합니다Optional 반환 타입과 예외 처리를 위한 import들이 올바르게 추가되었습니다.
12-12: Optional 반환 타입으로 변경이 좋은 설계입니다메서드 시그니처를
Optional<Book>으로 변경한 것은 null 처리를 명시적으로 만들어 좋은 개선입니다.
14-17: ErrorCode.BOOK_NOT_FOUND 정의 확인 완료
getByIsbnOrThrow편의성 메서드에 사용된ErrorCode.BOOK_NOT_FOUND가
src/main/java/konkuk/thip/common/exception/code/ErrorCode.java
에서 다음과 같이 정의되어 있음을 확인했습니다:BOOK_NOT_FOUND(HttpStatus.NOT_FOUND, 80010, "존재하지 않는 BOOK 입니다."),따라서 해당 편의성 메서드 추가는 유효하며, 별도 조치 없이 머지하셔도 좋습니다.
12-12: Optional 반환 타입으로의 변경이 적절합니다.
findByIsbn메소드가Optional<Book>을 반환하도록 변경된 것은 null 안전성을 높이는 좋은 개선입니다. 존재하지 않을 수 있는 엔티티에 대한 명시적인 처리가 가능해졌습니다.src/main/java/konkuk/thip/book/adapter/in/web/response/BookSearchListResponse.java (4)
9-17: 네이밍 컨벤션 개선이 좋습니다
GetBookSearchListResponse에서BookSearchListResponse로 변경하여 "Get" 접두사를 제거한 것은 더 간결하고 일관된 네이밍입니다.
18-37: 팩토리 메서드가 올바르게 업데이트되었습니다새로운 레코드 타입을 반환하도록 팩토리 메서드가 정확히 수정되었고, 내부 로직은 그대로 유지되어 안전한 리팩토링입니다.
9-17: DTO 네이밍 규칙 표준화가 적절합니다.
GetBookSearchListResponse에서BookSearchListResponse로의 클래스명 변경은 더 간결하고 일관된 네이밍을 제공합니다. Get 접두사 제거가 코드베이스의 일관성을 향상시킵니다.
18-37: 정적 팩토리 메소드 업데이트가 올바릅니다.
of메소드의 반환 타입이 새로운 클래스명에 맞게 적절히 업데이트되었습니다. 내부 로직은 변경 없이 유지되어 안정성을 보장합니다.src/main/java/konkuk/thip/book/application/service/BookSearchService.java (6)
96-96: 새로운 인터페이스 메서드 사용이 적절합니다
findByIsbn에서getByIsbnOrThrow로 변경하여 새로운 BookCommandPort 인터페이스를 올바르게 사용하고 있습니다.
110-118: 변수명 변경이 더 명확합니다
recruitingReadCount에서readCount로 변경하여 의미가 더 명확해졌습니다. 실제로는 모집중인 독자 수가 아니라 전체 읽기 참여자 수를 나타내므로 적절한 네이밍입니다.
127-127: 메서드명 변경이 일관성 있습니다변수명 변경에 맞춰 메서드명도
getRecruitingReadCount에서getReadCount로 변경하여 일관성을 유지했습니다.
96-96: 예외 처리 방식 개선이 적절합니다.
findByIsbn에서getByIsbnOrThrow로 변경하여 예외 처리가 더 명시적이고 일관성 있게 되었습니다. 새로운 포트 인터페이스와 잘 연동됩니다.
110-110: 변수명 개선이 의미를 더 명확하게 합니다.
recruitingReadCount에서readCount로의 변경이 변수의 의미를 더 명확하고 간결하게 표현합니다. 네이밍 일관성 향상에 기여합니다.Also applies to: 117-117
127-127: 메소드명 변경이 일관성을 향상시킵니다.
getRecruitingReadCount에서getReadCount로의 메소드명 변경이 변수명 변경과 일치하여 코드의 일관성을 높입니다.src/main/java/konkuk/thip/book/adapter/in/web/response/BookDetailSearchResponse.java (4)
7-17: 레코드 클래스명과 필드명 개선이 좋습니다
GetBookDetailSearchResponse에서BookDetailSearchResponse로 변경하고,recruitingReadCount를readCount로 변경한 것이 더 간결하고 정확한 네이밍입니다.
18-30: 팩토리 메서드가 일관되게 업데이트되었습니다새로운 레코드 타입을 반환하도록 하고, 변경된 필드명
readCount를 올바르게 사용하여 서비스 레이어 변경사항과 일치합니다.
7-7: Response DTO 네이밍 표준화가 일관성을 향상시킵니다.
GetBookDetailSearchResponse에서BookDetailSearchResponse로의 클래스명 변경과 정적 팩토리 메소드 업데이트가 코드베이스의 네이밍 일관성을 크게 향상시킵니다.Also applies to: 18-20
15-15: 필드명 변경이 의미를 더 명확하게 합니다.
recruitingReadCount를readCount로 변경한 것이 필드의 의미를 더 간결하고 명확하게 표현합니다. 애플리케이션 레이어의 변경사항과 일치하여 일관성을 유지합니다.Also applies to: 28-28
src/main/java/konkuk/thip/book/adapter/in/web/response/BookMostSearchResponse.java (2)
1-13: 새로운 응답 DTO가 일관된 패턴을 따릅니다
BookMostSearchResponse클래스는 다른 응답 DTO들과 일관된 네이밍 컨벤션과 구조를 따르고 있습니다. 간단한 래퍼 역할을 하는 팩토리 메서드도 적절합니다.
1-13: 새로운 Response 클래스가 네이밍 일관성을 완성합니다.
BookMostSearchResponse클래스가 다른 Response 클래스들과 일관된 네이밍 패턴을 따르며, 정적 팩토리 메소드가 적절히 구현되었습니다. 코드베이스의 네이밍 표준화를 완성하는 좋은 추가입니다.src/main/java/konkuk/thip/book/adapter/in/web/BookCommandController.java (1)
8-9: DTO 네이밍 표준화가 잘 되었습니다.
PostBookIsSavedRequest와PostBookIsSavedResponse를 각각BookIsSavedRequest와BookIsSavedResponse로 변경하여 네이밍 일관성을 개선했습니다. 메서드 로직은 동일하게 유지되면서 새로운 static factory method를 올바르게 사용하고 있습니다.Also applies to: 37-37, 40-40, 43-43
src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomQueryRepositoryImpl.java (1)
379-406: 새로운 ISBN 기반 방 조회 메서드가 잘 구현되었습니다.커서 기반 페이지네이션을 올바르게 구현했으며, 복합 커서 조건(dateCursor와 roomIdCursor)을 통해 일관된 정렬을 보장합니다. 활성 상태이면서 모집 중인 방만 필터링하는 조건도 적절합니다.
src/main/java/konkuk/thip/book/application/service/BookRecruitingRoomsService.java (1)
15-31: 서비스 로직이 깔끔하게 구현되었습니다.의존성 주입, 커서 기반 페이지네이션 처리, DTO 매핑이 모두 올바르게 구현되어 있습니다. 상수로 정의된
DEFAULT_PAGE_SIZE도 적절하며, 메서드의 책임이 명확하게 분리되어 있습니다.src/main/java/konkuk/thip/book/application/mapper/BookQueryMapper.java (1)
12-26: MapStruct 매퍼가 올바르게 구성되었습니다.DateUtil을 활용한 날짜 포맷팅, 스프링 컴포넌트 모델 설정, 그리고 단일 객체와 리스트 변환 메서드가 모두 적절하게 구현되어 있습니다.
unmappedTargetPolicy = IGNORE설정도 명시적이어서 좋습니다.src/main/java/konkuk/thip/book/adapter/in/web/response/BookRecruitingRoomsResponse.java (1)
5-26: 응답 DTO 구조가 명확하고 잘 설계되었습니다.Java record를 활용하여 불변 객체로 구현했으며, 페이지네이션에 필요한 메타데이터(
nextCursor,isLast)와 실제 데이터를 적절히 분리했습니다. 중첩된RecruitingRoomDto와 각각의 static factory method도 일관성 있게 구현되어 있습니다.src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java (4)
51-52: 람다 캡처를 활용한 리팩토링이 잘 구현되었습니다.
RoomQueryFunction인터페이스를 활용하여userId매개변수를 람다 캡처로 처리하는 방식이 코드 중복을 효과적으로 줄였습니다. 함수형 인터페이스의 활용으로 가독성과 유지보수성이 향상되었습니다.Also applies to: 57-58, 63-64, 69-70
73-77: 새로운 메서드 구현이 기존 패턴과 일관성 있게 작성되었습니다.ISBN으로 방을 조회하는 새로운 메서드가 기존 패턴과 동일하게 구현되어 일관성을 유지하고 있습니다. 메서드명도 비즈니스 의도를 명확히 표현하고 있습니다.
79-79: 메서드 시그니처 단순화가 적절합니다.
findRooms메서드에서userId매개변수를 제거하고RoomQueryFunction만 받도록 변경한 것이 함수형 인터페이스의 활용 목적에 부합합니다. 람다 캡처를 통해 필요한 매개변수들을 동적으로 전달할 수 있게 되었습니다.Also applies to: 84-84
30-30: 메서드명 변경 의도 확인 완료
countActiveRoomsByBookIdAndStartDateAfter는 내부 JPA 쿼리의status = 'ACTIVE'필터를 명확하게 반영하기 위해 네이밍된 것이며,
포트(RoomQueryPort.countRecruitingRoomsByBookAndStartDateAfter)와 어댑터(RoomQueryPersistenceAdapter)에서 해당 메서드를 정상적으로 위임하고 있어 기능상 문제나 일관성 깨짐은 없습니다.• src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java –
countRecruitingRoomsByBookAndStartDateAfter→ 내부countActiveRoomsByBookIdAndStartDateAfter위임
• src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomJpaRepository.java –@Query에서status = 'ACTIVE'필터 사용src/test/java/konkuk/thip/book/adapter/in/web/BookRecruitingRoomApiTest.java (5)
34-39: 테스트 설정이 적절하게 구성되었습니다.Spring Boot 통합 테스트에 필요한 어노테이션들이 올바르게 설정되어 있습니다.
@AutoConfigureMockMvc(addFilters = false)와@Transactional을 통해 보안 필터를 비활성화하고 테스트 간 데이터 격리를 보장하고 있습니다.
89-111: 테스트 시나리오가 비즈니스 로직을 정확히 검증합니다.모집 중인 방과 마감된 방을 모두 생성하여 필터링 로직이 올바르게 동작하는지 확인하고 있습니다. 시작일과 종료일 설정을 통해 방의 상태를 명확히 구분한 것이 좋습니다.
126-134: 예외 상황 테스트가 적절합니다.존재하지 않는 ISBN에 대한 처리를 테스트하여 엣지 케이스를 잘 커버하고 있습니다. 빈 리스트 반환을 확인하는 것이 적절합니다.
138-176: 커서 기반 페이징 테스트가 포괄적입니다.첫 번째 페이지와 두 번째 페이지의 동작을 모두 검증하고,
nextCursor추출 및isLast플래그 확인까지 포함하여 완전한 페이징 시나리오를 테스트하고 있습니다.
145-152: 테스트 데이터 생성에서 팩토리 메서드 활용이 우수합니다.
TestEntityFactory.createCustomRoom을 사용하여 15개의 방을 생성하는 방식이 깔끔하고 유지보수하기 좋습니다. 시작일을 다르게 설정하여 정렬 테스트도 할 수 있게 구성한 것이 좋습니다.src/main/java/konkuk/thip/book/adapter/in/web/BookQueryController.java (4)
7-10: 응답 DTO 네이밍 개선이 일관성 있게 적용되었습니다.기존의
Get접두사를 제거한 DTO 네이밍 변경이 전체적으로 일관성 있게 적용되어 코드 가독성이 향상되었습니다.Also applies to: 12-12
42-42: 메서드 네이밍 컨벤션 변경이 적절합니다.REST API 컨트롤러에서
get접두사를show로 변경한 것이 RESTful한 네이밍 컨벤션에 더 부합합니다. 일관성 있게 적용되어 좋습니다.Also applies to: 56-56, 71-71
34-34: 새로운 의존성 주입이 적절합니다.
BookRecruitingRoomsUseCase의존성이 새로운 기능 구현을 위해 올바르게 추가되었습니다.
76-88: 새로운 엔드포인트 구현이 잘 설계되었습니다.ISBN 경로 변수와 커서 쿼리 파라미터를 사용한 RESTful API 설계가 적절합니다. Swagger 문서화도 충분히 되어 있고, ISBN 형식 검증을 위한 정규식 패턴도 올바르게 적용되었습니다.
src/main/java/konkuk/thip/book/adapter/in/web/BookQueryController.java
Outdated
Show resolved
Hide resolved
src/main/java/konkuk/thip/book/application/port/in/dto/BookDetailSearchResult.java
Show resolved
Hide resolved
hd0rable
left a comment
There was a problem hiding this comment.
수고하셨습니닷!! 현준님은 람다 진짜 잘 활용하시네여 람다 캡쳐 사용하는 방식으로 리펙토링하신거 좋은것같습니다~~ 붐업 붐업👍🏻
| String description, | ||
| int recruitingRoomCount, | ||
| int recruitingReadCount, | ||
| int readCount, |
| @@ -4,7 +4,7 @@ | |||
| import jakarta.validation.constraints.NotNull; | |||
|
|
|||
| @Schema(description = "책 저장 상태 변경 요청 DTO") | |||
| public record PostBookIsSavedRequest( | |||
There was a problem hiding this comment.
커컼.. 이게 아마 dto 컨벤션 바뀌기 전에 다 구현된것들이라.. 메서드명 다 붙어있던거 야무지게 빼주셧네요 감사합니다람쥐~~👍🏻
| BookJpaEntity bookJpaEntity = bookJpaRepository.findByIsbn(isbn).orElseThrow( | ||
| () -> new EntityNotFoundException(BOOK_NOT_FOUND)); | ||
| return bookMapper.toDomainEntity(bookJpaEntity); | ||
| public Optional<Book> findByIsbn(String isbn) { |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/main/java/konkuk/thip/book/adapter/in/web/response/BookRecruitingRoomsResponse.java (2)
11-13: 정적 팩토리 메서드가 불필요합니다.Java record는 이미 모든 필드를 받는 생성자를 자동으로 제공하므로, 단순히 생성자를 호출하는 정적 팩토리 메서드는 코드 중복입니다.
다음과 같이 정적 팩토리 메서드를 제거하는 것을 권장합니다:
- public static BookRecruitingRoomsResponse of(List<RecruitingRoomDto> recruitingRoomList, Integer totalRoomCount, String nextCursor, boolean isLast) { - return new BookRecruitingRoomsResponse(recruitingRoomList, totalRoomCount, nextCursor, isLast); - }
23-25: 중첩 record의 정적 팩토리 메서드도 불필요합니다.외부 record와 마찬가지로 Java record의 기본 생성자로 충분합니다.
다음과 같이 정적 팩토리 메서드를 제거하는 것을 권장합니다:
- public static RecruitingRoomDto of(Long roomId, String bookImageUrl, String roomName, int memberCount, int recruitCount, String deadlineEndDate) { - return new RecruitingRoomDto(roomId, bookImageUrl, roomName, memberCount, recruitCount, deadlineEndDate); - }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/main/java/konkuk/thip/book/adapter/in/web/response/BookRecruitingRoomsResponse.java(1 hunks)src/main/java/konkuk/thip/book/application/service/BookRecruitingRoomsService.java(1 hunks)src/main/java/konkuk/thip/book/application/service/BookSearchService.java(2 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java(3 hunks)src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomJpaRepository.java(1 hunks)src/main/java/konkuk/thip/room/application/port/out/RoomQueryPort.java(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- src/main/java/konkuk/thip/book/application/service/BookRecruitingRoomsService.java
- src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomJpaRepository.java
- src/main/java/konkuk/thip/book/application/service/BookSearchService.java
- src/main/java/konkuk/thip/room/application/port/out/RoomQueryPort.java
- src/main/java/konkuk/thip/room/adapter/out/persistence/RoomQueryPersistenceAdapter.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: thip 프로젝트에서는 query api(조회 api)에 한해서는 application 계층에서 adapter.in.web.response 패키지의 response dto를 직접 ...
Learnt from: buzz0331
PR: THIP-TextHip/THIP-Server#78
File: src/main/java/konkuk/thip/user/application/port/out/FollowingQueryPort.java:3-3
Timestamp: 2025-07-14T18:22:56.538Z
Learning: THIP 프로젝트에서는 Query API(조회 API)에 한해서는 application 계층에서 adapter.in.web.response 패키지의 response DTO를 직접 참조하는 것을 허용함. 이는 CQRS 아키텍처에서 읽기 전용 작업의 효율성을 위한 팀 컨벤션임.
Applied to files:
src/main/java/konkuk/thip/book/adapter/in/web/response/BookRecruitingRoomsResponse.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (3)
src/main/java/konkuk/thip/book/adapter/in/web/response/BookRecruitingRoomsResponse.java (3)
1-3: 패키지 구조와 import가 적절합니다.응답 DTO가 올바른 패키지에 위치하고 있으며, 필요한 import만 포함되어 있습니다.
5-10: 페이지네이션 필드 구조가 일관성 있게 설계되었습니다.커서 기반 페이지네이션을 위한
nextCursor,isLast필드와 함께 총 개수를 나타내는totalRoomCount필드가 포함되어 있어 클라이언트에서 페이지네이션을 효과적으로 구현할 수 있습니다.
15-22: 중첩 DTO의 필드 구조가 적절합니다.모집방 정보를 나타내는 필드들이 명확하고 일관성 있게 명명되어 있습니다.
memberCount와recruitCount필드를 통해 현재 참여 인원과 모집 정원을 구분하여 표현한 것이 좋습니다.
seongjunnoh
left a comment
There was a problem hiding this comment.
고생하셨습니다! 간단한 궁금증 리뷰로 남겼습니다!
| Integer totalRoomCount = (cursorStr == null || cursorStr.isBlank()) ? // 첫 요청 여부 판단 | ||
| roomQueryPort.countRecruitingRoomsByBookAndStartDateAfter(isbn, LocalDate.now()) : null; |
There was a problem hiding this comment.
LGTM 이게 디코에 질문 올리셨던 거군요! 좋습니다!!
| Optional<Book> findByIsbn(String isbn); | ||
|
|
||
| default Book getByIsbnOrThrow(String isbn){ | ||
| return findByIsbn(isbn) | ||
| .orElseThrow(() -> new EntityNotFoundException(ErrorCode.BOOK_NOT_FOUND)); | ||
| } |
There was a problem hiding this comment.
굳굳 서비스에서 try catch 를 하나 더 없앨 수 있겠네요
| roomJpaRepository.findRoomsByIsbnOrderByStartDateAsc(isbn, lastLocalDate, lastId, pageSize)); | ||
| } | ||
|
|
||
| private CursorBasedList<RoomQueryDto> findRooms(Cursor cursor, RoomQueryFunction queryFunction) { |
There was a problem hiding this comment.
p3 : 메서드 재 사용성을 위해 파라미터에서 userId를 제거하신 건가요?
There was a problem hiding this comment.
넵 기존 조회에서는 userId로 방을 조회하고 있었고, 이번 api의 요구사항은 책의 isbn으로 모임방을 조회하는 것이였습니다. 이때, 두 요구사항 모두 startDate와 roomId를 커서 필드로 잡고 복합 커서로 잡고 있어서 Cursor를 만드는 것과 인코딩하는 로직이 공통으로 쓰이는 것을 확인했습니다! 따라서 userId와 isbn 같은 식별자는 람다 캡처를 통해 동적으로 넘기도록 하고 공통된 로직만 함수형 인터페이스를 사용하도록 했습니다.
| @Override | ||
| public List<RoomQueryDto> findRoomsByIsbnOrderByStartDateAsc(String isbn, LocalDate dateCursor, Long roomIdCursor, int pageSize) { |
| @SpringBootTest | ||
| @ActiveProfiles("test") | ||
| @DisplayName("[통합] 특정 책으로 모집중인 모임방을 조회하는 api 통합 테스트") | ||
| @AutoConfigureMockMvc(addFilters = false) | ||
| @Transactional | ||
| class BookRecruitingRoomApiTest { |
#️⃣ 연관된 이슈
📝 작업 내용
조회 형식은 기존과 거의 동일합니다.
📸 스크린샷
💬 리뷰 요구사항
리팩토링 된 부분이 꽤 있어서 확인 부탁드립니다!
관련 내용은 노션에 문서화해두겠습니다.
같은 도메인에서 조회 api 구현시 대부분 같은 필드를 커서로 잡고 사용하는 것 같아서 커서 기반 페이징 처리시 위와 같은 방식으로 공통 함수형 인터페이스 하나를 두고 람다 캡처를 이용하면 중복 코드를 줄일 수 있을 것 같습니다!
📌 PR 진행 시 이러한 점들을 참고해 주세요
Summary by CodeRabbit
신규 기능
버그 수정
readCount로 변경되어 일관성을 높였습니다.리팩터링
테스트