Conversation
|
""" Walkthrough이 PR은 오픈런(FCFS) 게시글 기능의 리팩토링과 테스트 코드 강화를 중심으로, 캐싱 로직을 Spring Cache에서 Redis 기반 수동 캐싱으로 전환하고, Redis 키 및 락 관리 상수를 통일했으며, 서비스 및 테스트 전반에 걸쳐 Board 엔티티 대신 DTO를 활용하도록 변경했습니다. 또한, Micrometer 기반의 모니터링 코드와 성능 테스트, 다양한 페이징 쿼리 메서드가 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant BoardController
participant BoardService
participant BoardCacheService
participant RedisService
participant BoardRepository
Client->>BoardController: GET /board/{id}
BoardController->>BoardService: findBoardInCache(boardId, userId)
BoardService->>BoardCacheService: getOrSetCache(boardId)
BoardCacheService->>RedisService: getKeyValue(cacheKey)
alt Cache Hit
RedisService-->>BoardCacheService: BoardResponseDto
BoardCacheService-->>BoardService: BoardResponseDto
else Cache Miss
BoardCacheService->>BoardRepository: findById(boardId)
BoardRepository-->>BoardCacheService: Board
BoardCacheService->>RedisService: setKeyValue(cacheKey, dto, ttl)
BoardCacheService-->>BoardService: BoardResponseDto
end
BoardService-->>BoardController: BoardResponseDto
BoardController-->>Client: BoardResponseDto
Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (8)
💤 Files with no reviewable changes (8)
⏰ 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
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/main/java/com/example/taste/domain/board/service/BoardService.java (1)
11-11: 중복된 import 제거가 필요합니다.
LocalDateTime이 중복으로 import되어 있습니다. 불필요한 import를 제거해주세요.-import java.time.LocalDateTime;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/main/java/com/example/taste/common/constant/SocketConst.java(1 hunks)src/main/java/com/example/taste/domain/board/mq/BoardStatusConsumer.java(2 hunks)src/main/java/com/example/taste/domain/board/service/BoardService.java(2 hunks)src/main/java/com/example/taste/domain/board/service/FcfsQueueService.java(4 hunks)src/test/java/com/example/taste/domain/board/service/FcfsQueueServiceTest.java(8 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: mo00ai
PR: mo00ai/your-my-taste#112
File: src/main/java/com/example/taste/domain/image/service/ImageService.java:0-0
Timestamp: 2025-06-22T18:33:56.980Z
Learning: 사용자 mo00ai는 성능 테스트 진행 중에는 코드 변경을 피하고, 테스트 완료 후에 수정 작업을 진행하는 것을 선호함.
Learnt from: kmchaejin
PR: mo00ai/your-my-taste#33
File: src/main/java/com/example/taste/domain/store/service/StoreBucketService.java:127-139
Timestamp: 2025-06-04T02:13:29.504Z
Learning: kmchaejin은 코드에서 검증 로직을 별도 메서드로 분리하여 재사용 가능하게 구조화하는 것을 선호합니다.
src/main/java/com/example/taste/domain/board/service/FcfsQueueService.java (2)
Learnt from: rlgkghkd
PR: mo00ai/your-my-taste#92
File: src/main/java/com/example/taste/common/service/RedisService.java:120-126
Timestamp: 2025-06-18T01:56:09.908Z
Learning: In src/main/java/com/example/taste/common/service/RedisService.java, the `notification:count:user:{userId}:{category}` count is used to track whether all notifications (both Redis and MySQL) have been viewed/read by the user, not to count the actual number of notifications stored in Redis. This count operates independently from Redis notification storage management.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
src/test/java/com/example/taste/domain/board/service/FcfsQueueServiceTest.java (3)
Learnt from: rlgkghkd
PR: mo00ai/your-my-taste#92
File: src/main/java/com/example/taste/common/service/RedisService.java:120-126
Timestamp: 2025-06-18T01:56:09.908Z
Learning: In src/main/java/com/example/taste/common/service/RedisService.java, the `notification:count:user:{userId}:{category}` count is used to track whether all notifications (both Redis and MySQL) have been viewed/read by the user, not to count the actual number of notifications stored in Redis. This count operates independently from Redis notification storage management.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/entity/Board.java:123-124
Timestamp: 2025-06-15T15:10:23.413Z
Learning: 오픈런 게시글 생성 시 status가 null일 때 예외를 던지기보다는 CLOSED를 기본값으로 설정하여 안전한 기본 동작을 보장하는 것을 선호함. 방어적 프로그래밍 접근 방식을 사용함.
🧬 Code Graph Analysis (3)
src/main/java/com/example/taste/domain/board/mq/BoardStatusConsumer.java (1)
src/main/java/com/example/taste/common/constant/SocketConst.java (1)
SocketConst(3-5)
src/main/java/com/example/taste/domain/board/service/FcfsQueueService.java (1)
src/main/java/com/example/taste/common/constant/SocketConst.java (1)
SocketConst(3-5)
src/test/java/com/example/taste/domain/board/service/FcfsQueueServiceTest.java (2)
src/main/java/com/example/taste/common/constant/SocketConst.java (1)
SocketConst(3-5)src/test/java/com/example/taste/domain/pk/service/PkServicePerformanceTest.java (1)
Tag(6-12)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: generate-jooq
🔇 Additional comments (11)
src/main/java/com/example/taste/common/constant/SocketConst.java (1)
3-5: 상수 클래스 추가가 잘 구현되었습니다!하드코딩된 WebSocket 경로 문자열을 상수로 분리하여 코드의 재사용성과 유지보수성을 향상시키는 좋은 리팩토링입니다.
src/main/java/com/example/taste/domain/board/mq/BoardStatusConsumer.java (2)
4-4: 상수 임포트가 적절히 추가되었습니다.SocketConst 클래스에서 상수를 static import로 가져와 코드의 가독성을 높였습니다.
23-23: 하드코딩된 문자열을 상수로 대체한 변경이 우수합니다.기존의 하드코딩된 WebSocket 경로 문자열을
BOARD_SOCKET_DESTINATION상수로 대체하여 코드의 일관성과 유지보수성을 향상시켰습니다.src/main/java/com/example/taste/domain/board/service/FcfsQueueService.java (2)
4-4: 상수 임포트가 적절히 추가되었습니다.SocketConst 클래스의 상수를 static import로 가져와 코드의 가독성을 높였습니다.
55-55: 여러 메서드에서 일관되게 상수를 사용한 변경이 우수합니다.
tryEnterFcfsQueue,tryEnterFcfsQueueByLettuce,tryEnterFcfsQueueByRedisson메서드에서 하드코딩된 WebSocket 경로 문자열을BOARD_SOCKET_DESTINATION상수로 일관되게 대체하여 코드의 유지보수성을 크게 향상시켰습니다.Also applies to: 97-97, 149-149
src/main/java/com/example/taste/domain/board/service/BoardService.java (1)
239-243: 변수명 변경으로 코드 가독성이 향상되었습니다.
isClosed에서isBeforeOpen으로 변수명을 변경하여 비즈니스 로직의 의미를 더 명확하게 표현했습니다. 부정 논리보다는 긍정 논리를 사용하여 코드의 가독성이 크게 개선되었습니다.src/test/java/com/example/taste/domain/board/service/FcfsQueueServiceTest.java (5)
4-4: 테스트에서도 상수 임포트가 적절히 추가되었습니다.SocketConst 클래스의 상수를 static import하여 테스트 코드와 프로덕션 코드 간 일관성을 유지했습니다.
85-85: 성능 테스트 태그로 변경이 적절합니다.PR의 성능 관련 목적에 맞게 테스트 태그를
"local-only"에서"Performance"로 변경하여 테스트 분류를 명확히 했습니다.Also applies to: 174-174
99-99: 테스트에서 상수 사용으로 일관성이 향상되었습니다.테스트 코드에서도 하드코딩된 경로 문자열을
BOARD_SOCKET_DESTINATION상수로 대체하여 프로덕션 코드와의 일관성을 유지하고 유지보수성을 향상시켰습니다.Also applies to: 264-264
134-138: 테스트 안정성과 검증 로직이 개선되었습니다.타임아웃을 15초에서 5초로 단축하여 테스트 실행 시간을 개선하고, 수신된 메시지에 잔여 슬롯 수가 포함되어 있는지 검증하는 assertion을 추가하여 테스트의 정확성을 높였습니다.
190-199: 스레드 생명주기 관리가 개선되었습니다.
lockerThread.join()을 추가하고 try-catch 블록으로 감싸서 스레드가 완전히 종료된 후 테스트가 계속 진행되도록 하여 테스트의 안정성을 크게 향상시켰습니다.Also applies to: 232-237
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (11)
src/main/java/com/example/taste/domain/board/repository/FcfsInformationRepository.java (1)
14-14: 반환 타입을 더 간단하게 개선할 수 있습니다.현재
Iterable<? extends FcfsInformation>타입보다는List<FcfsInformation>또는 단순히Iterable<FcfsInformation>을 사용하는 것이 더 명확하고 사용하기 쉬울 것입니다.다음과 같이 개선할 수 있습니다:
- Iterable<? extends FcfsInformation> findAllByBoardId(Long boardId); + List<FcfsInformation> findAllByBoardId(Long boardId);src/main/java/com/example/taste/domain/board/entity/BoardType.java (1)
35-37: 메서드명을 더 명확하게 개선하는 것을 권장합니다.
matches메서드명이 무엇을 매칭하는지 명확하지 않습니다.N타입(일반 게시글)만 체크하는 특정 목적이므로isNormalBoard(String type)같은 더 명확한 네이밍을 고려해보세요.- public boolean matches(String type) { - return N == from(type); - } + public boolean isNormalBoard(String type) { + return N == from(type); + }src/main/java/com/example/taste/domain/user/entity/User.java (1)
172-174: 메서드 구현이 간단하고 명확합니다.엔티티 레벨에서 posting count를 관리하는 방식으로 변경된 것이 좋습니다. 다만
increasePoint메서드와 달리 오버플로우 검증이 없는 점을 참고하세요.src/main/java/com/example/taste/domain/board/controller/BoardController.java (2)
56-57: 메트릭 변수명 개선을 제안합니다.변수명을 더 명확하게 개선하는 것을 제안합니다:
boardRate→boardLatencyTimercounter→boardRequestCounter- private Timer boardRate; - private Counter counter; + private Timer boardLatencyTimer; + private Counter boardRequestCounter;
90-90: 주석 처리된 코드를 정리하세요.주석 처리된 코드는 성능 테스트 완료 후 제거하는 것이 좋습니다. 코드의 가독성을 위해 불필요한 주석을 정리해주세요.
- //BoardResponseDto responseDto = boardService.findBoard(boardId, userId); BoardResponseDto responseDto = boardService.findBoardInCache(boardId, userId);src/main/java/com/example/taste/domain/board/batch/ClosingBoardBatchConfig.java (1)
85-128: 주석 처리된 코드를 제거하세요.이전 구현 방식들이 주석으로 남아있습니다. 버전 관리 시스템에서 히스토리를 확인할 수 있으므로 주석 처리된 코드는 제거하는 것이 좋습니다.
src/main/java/com/example/taste/domain/board/service/FcfsQueueService.java (3)
47-58: Counter 이름을 더 명확하게 개선하세요.현재 counter 이름이 너무 일반적입니다. Micrometer 네이밍 컨벤션에 따라 더 구체적인 이름을 사용하는 것이 좋습니다.
- baseCounter = Counter.builder("fcfs.success.base") + baseCounter = Counter.builder("fcfs.queue.entries.success") + .tag("method", "base") .description("조건문 방식 FCFS 성공 카운터") .register(registry); - lettuceCounter = Counter.builder("fcfs.success.lettuce") + lettuceCounter = Counter.builder("fcfs.queue.entries.success") + .tag("method", "lettuce") .description("Lettuce 락 방식 FCFS 성공 카운터") .register(registry); - redissonCounter = Counter.builder("fcfs.success.redisson") + redissonCounter = Counter.builder("fcfs.queue.entries.success") + .tag("method", "redisson") .description("Redisson 락 방식 FCFS 성공 카운터") .register(registry);
86-88: 주석 처리된 메시징 코드를 제거하세요.BoardStatusPublisher로 마이그레이션이 완료되었으므로 이전 메시징 템플릿 코드는 제거해야 합니다.
Also applies to: 143-145, 197-199
71-73: 추가된 DB 조회가 성능에 영향을 줄 수 있습니다.
existsByBoardId체크가 추가되어 매 요청마다 추가 DB 쿼리가 발생합니다. 이미 FCFS 정보가 DB에 저장되었는지 확인하는 로직으로 보이는데, Redis에서 이 정보를 캐싱하거나 다른 방식으로 최적화하는 것을 고려해보세요.Also applies to: 127-129, 181-183
src/test/java/com/example/taste/domain/board/service/FcfsLockPerformanceTest.java (1)
129-138: @transactional 테스트에서 수동 cleanup은 불필요합니다.@transactional 어노테이션이 있으면 테스트 종료 시 자동으로 롤백됩니다. 수동 cleanup 코드를 제거하거나, @transactional을 제거하고 수동 cleanup만 사용하세요.
Also applies to: 198-207, 267-276
src/main/java/com/example/taste/domain/board/service/BoardService.java (1)
161-164: 주석 처리된 테스트 코드를 제거해주세요.성능 테스트를 위한 것으로 보이지만, 프로덕션 코드에 주석으로 남아있는 것은 적절하지 않습니다.
// 선착순 공개 게시글이면 순위 검증 if (dto.getAccessPolicy().isFcfs()) { - //fcfsQueueService.tryEnterFcfsQueue(dto, user); - //fcfsQueueService.tryEnterFcfsQueueByLettuce(dto, user); fcfsQueueService.tryEnterFcfsQueueByRedisson(dto, user); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (28)
docker-compose.test.yml(1 hunks)src/main/java/com/example/taste/common/constant/CacheConst.java(0 hunks)src/main/java/com/example/taste/common/constant/RedisConst.java(1 hunks)src/main/java/com/example/taste/config/CacheConfig.java(0 hunks)src/main/java/com/example/taste/config/RedisConfig.java(0 hunks)src/main/java/com/example/taste/domain/board/batch/ClosingBoardBatchConfig.java(4 hunks)src/main/java/com/example/taste/domain/board/controller/BoardController.java(3 hunks)src/main/java/com/example/taste/domain/board/dto/response/BoardResponseDto.java(3 hunks)src/main/java/com/example/taste/domain/board/entity/Board.java(0 hunks)src/main/java/com/example/taste/domain/board/entity/BoardType.java(1 hunks)src/main/java/com/example/taste/domain/board/repository/BoardRepositoryJooqCustom.java(1 hunks)src/main/java/com/example/taste/domain/board/repository/BoardRepositoryJooqCustomImpl.java(2 hunks)src/main/java/com/example/taste/domain/board/repository/FcfsInformationRepository.java(1 hunks)src/main/java/com/example/taste/domain/board/scheduler/BoardScheduler.java(1 hunks)src/main/java/com/example/taste/domain/board/service/BoardCacheService.java(1 hunks)src/main/java/com/example/taste/domain/board/service/BoardService.java(7 hunks)src/main/java/com/example/taste/domain/board/service/FcfsInformationService.java(1 hunks)src/main/java/com/example/taste/domain/board/service/FcfsQueueService.java(3 hunks)src/main/java/com/example/taste/domain/user/entity/User.java(1 hunks)src/main/java/com/example/taste/domain/user/repository/UserRepository.java(0 hunks)src/main/java/com/example/taste/domain/user/repository/UserRepositoryCustom.java(1 hunks)src/main/java/com/example/taste/domain/user/repository/UserRepositoryImpl.java(1 hunks)src/test/java/com/example/taste/domain/board/service/BoardCacheServiceTest.java(6 hunks)src/test/java/com/example/taste/domain/board/service/BoardServiceTest.java(1 hunks)src/test/java/com/example/taste/domain/board/service/BoardServiceUnitTest.java(4 hunks)src/test/java/com/example/taste/domain/board/service/FcfsInformationServiceTest.java(1 hunks)src/test/java/com/example/taste/domain/board/service/FcfsLockPerformanceTest.java(1 hunks)src/test/java/com/example/taste/domain/board/service/FcfsQueueServiceTest.java(11 hunks)
💤 Files with no reviewable changes (5)
- src/main/java/com/example/taste/config/RedisConfig.java
- src/main/java/com/example/taste/domain/user/repository/UserRepository.java
- src/main/java/com/example/taste/common/constant/CacheConst.java
- src/main/java/com/example/taste/domain/board/entity/Board.java
- src/main/java/com/example/taste/config/CacheConfig.java
🚧 Files skipped from review as they are similar to previous changes (1)
- src/test/java/com/example/taste/domain/board/service/FcfsQueueServiceTest.java
🧰 Additional context used
🧠 Learnings (18)
📓 Common learnings
Learnt from: mo00ai
PR: mo00ai/your-my-taste#112
File: src/main/java/com/example/taste/domain/image/service/ImageService.java:0-0
Timestamp: 2025-06-22T18:33:56.980Z
Learning: 사용자 mo00ai는 성능 테스트 진행 중에는 코드 변경을 피하고, 테스트 완료 후에 수정 작업을 진행하는 것을 선호함.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#141
File: src/main/java/com/example/taste/config/SecurityConfig.java:57-57
Timestamp: 2025-07-03T00:42:54.175Z
Learning: 사용자 Chaemin07는 보안 설정이나 리팩토링과 같은 개선 제안을 현재 PR에서 즉시 적용하기보다는 추후 수정하는 것을 선호함.
Learnt from: kmchaejin
PR: mo00ai/your-my-taste#33
File: src/main/java/com/example/taste/domain/store/service/StoreBucketService.java:127-139
Timestamp: 2025-06-04T02:13:29.504Z
Learning: kmchaejin은 코드에서 검증 로직을 별도 메서드로 분리하여 재사용 가능하게 구조화하는 것을 선호합니다.
src/main/java/com/example/taste/domain/board/repository/FcfsInformationRepository.java (1)
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
src/main/java/com/example/taste/domain/user/repository/UserRepositoryImpl.java (4)
Learnt from: mo00ai
PR: mo00ai/your-my-taste#34
File: src/main/java/com/example/taste/domain/user/entity/User.java:148-150
Timestamp: 2025-06-04T03:45:00.977Z
Learning: In the User entity's increasePoint method in src/main/java/com/example/taste/domain/user/entity/User.java, negative value validation is not needed because the PkType enum guarantees positive values (POST(30), LIKE(20), REVIEW(20), EVENT(500)), and the method is primarily used through PkService.savePkLog which uses PkType.getPoint().
Learnt from: rlgkghkd
PR: mo00ai/your-my-taste#92
File: src/main/java/com/example/taste/common/service/RedisService.java:120-126
Timestamp: 2025-06-18T01:56:09.908Z
Learning: In src/main/java/com/example/taste/common/service/RedisService.java, the `notification:count:user:{userId}:{category}` count is used to track whether all notifications (both Redis and MySQL) have been viewed/read by the user, not to count the actual number of notifications stored in Redis. This count operates independently from Redis notification storage management.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#105
File: src/main/java/com/example/taste/domain/user/repository/UserRepository.java:48-50
Timestamp: 2025-06-21T03:24:22.552Z
Learning: UserRepository의 resetAllPoints() (JPA)와 resetAllUserPoints() (JOOQ) 메서드 중복은 성능 테스트를 위한 것임. 사용자가 JPA와 JOOQ 구현체 간의 성능 차이를 측정한 후 제거할 예정임.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#60
File: src/main/java/com/example/taste/domain/user/repository/UserRepository.java:3-3
Timestamp: 2025-06-09T03:41:29.753Z
Learning: PK 랭킹 조회를 위해 상위 N명만 필요한 경우, PageRequest.of(0, N)을 사용하여 List<Entity>를 반환하는 방식이 페이징 메타데이터가 필요하지 않은 상황에서 적합한 패턴입니다.
src/test/java/com/example/taste/domain/board/service/BoardServiceUnitTest.java (1)
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
src/main/java/com/example/taste/domain/board/service/FcfsInformationService.java (1)
Learnt from: rlgkghkd
PR: mo00ai/your-my-taste#92
File: src/main/java/com/example/taste/common/service/RedisService.java:120-126
Timestamp: 2025-06-18T01:56:09.908Z
Learning: In src/main/java/com/example/taste/common/service/RedisService.java, the `notification:count:user:{userId}:{category}` count is used to track whether all notifications (both Redis and MySQL) have been viewed/read by the user, not to count the actual number of notifications stored in Redis. This count operates independently from Redis notification storage management.
src/main/java/com/example/taste/domain/user/repository/UserRepositoryCustom.java (6)
Learnt from: mo00ai
PR: mo00ai/your-my-taste#34
File: src/main/java/com/example/taste/domain/user/entity/User.java:148-150
Timestamp: 2025-06-04T03:45:00.977Z
Learning: In the User entity's increasePoint method in src/main/java/com/example/taste/domain/user/entity/User.java, negative value validation is not needed because the PkType enum guarantees positive values (POST(30), LIKE(20), REVIEW(20), EVENT(500)), and the method is primarily used through PkService.savePkLog which uses PkType.getPoint().
Learnt from: rlgkghkd
PR: mo00ai/your-my-taste#92
File: src/main/java/com/example/taste/common/service/RedisService.java:120-126
Timestamp: 2025-06-18T01:56:09.908Z
Learning: In src/main/java/com/example/taste/common/service/RedisService.java, the `notification:count:user:{userId}:{category}` count is used to track whether all notifications (both Redis and MySQL) have been viewed/read by the user, not to count the actual number of notifications stored in Redis. This count operates independently from Redis notification storage management.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#105
File: src/main/java/com/example/taste/domain/user/repository/UserRepository.java:48-50
Timestamp: 2025-06-21T03:24:22.552Z
Learning: UserRepository의 resetAllPoints() (JPA)와 resetAllUserPoints() (JOOQ) 메서드 중복은 성능 테스트를 위한 것임. 사용자가 JPA와 JOOQ 구현체 간의 성능 차이를 측정한 후 제거할 예정임.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#105
File: src/main/java/com/example/taste/domain/user/service/UserService.java:243-262
Timestamp: 2025-06-20T16:18:51.339Z
Learning: UserService의 resetUsersPoint() 메서드에서 JDBC, JPA, JOOQ 구현체를 모두 주석으로 남겨둔 이유는 성능 테스트를 위한 것임. 사용자가 각 구현체 간의 성능 차이를 측정하기 위해 의도적으로 여러 구현 방식을 유지하고 있음.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#60
File: src/main/java/com/example/taste/domain/user/repository/UserRepository.java:3-3
Timestamp: 2025-06-09T03:41:29.753Z
Learning: PK 랭킹 조회를 위해 상위 N명만 필요한 경우, PageRequest.of(0, N)을 사용하여 List<Entity>를 반환하는 방식이 페이징 메타데이터가 필요하지 않은 상황에서 적합한 패턴입니다.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
src/main/java/com/example/taste/domain/user/entity/User.java (3)
Learnt from: mo00ai
PR: mo00ai/your-my-taste#34
File: src/main/java/com/example/taste/domain/user/entity/User.java:148-150
Timestamp: 2025-06-04T03:45:00.977Z
Learning: In the User entity's increasePoint method in src/main/java/com/example/taste/domain/user/entity/User.java, negative value validation is not needed because the PkType enum guarantees positive values (POST(30), LIKE(20), REVIEW(20), EVENT(500)), and the method is primarily used through PkService.savePkLog which uses PkType.getPoint().
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#105
File: src/main/java/com/example/taste/domain/user/repository/UserRepository.java:48-50
Timestamp: 2025-06-21T03:24:22.552Z
Learning: UserRepository의 resetAllPoints() (JPA)와 resetAllUserPoints() (JOOQ) 메서드 중복은 성능 테스트를 위한 것임. 사용자가 JPA와 JOOQ 구현체 간의 성능 차이를 측정한 후 제거할 예정임.
src/main/java/com/example/taste/domain/board/repository/BoardRepositoryJooqCustom.java (1)
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
src/main/java/com/example/taste/domain/board/repository/BoardRepositoryJooqCustomImpl.java (1)
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
src/main/java/com/example/taste/domain/board/dto/response/BoardResponseDto.java (2)
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/strategy/NormalBoardCreationStrategy.java:12-19
Timestamp: 2025-06-15T14:36:37.828Z
Learning: BoardRequestDto는 Jackson의 @JsonTypeInfo와 @JsonSubTypes를 사용하여 타입 정보 기반 역직렬화를 하므로, 전략 패턴에서의 타입 캐스팅이 안전하다. 컨트롤러의 @Valid 검증과 함께 추가적인 null 체크나 타입 검증이 필요하지 않다.
src/main/java/com/example/taste/domain/board/controller/BoardController.java (1)
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
src/main/java/com/example/taste/common/constant/RedisConst.java (3)
Learnt from: mo00ai
PR: mo00ai/your-my-taste#45
File: src/main/java/com/example/taste/config/RedisConfig.java:65-65
Timestamp: 2025-06-04T12:18:56.059Z
Learning: PkCriteria 데이터는 관리자가 10개 이하의 PK 포인트 기준만 관리하므로 메모리 차지가 적어서 Redis 캐시에서 TTL을 설정하지 않고 사용한다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#60
File: src/main/java/com/example/taste/domain/pk/scheduler/PkLogScheduler.java:38-60
Timestamp: 2025-06-09T04:21:59.289Z
Learning: PkLogScheduler에서 Redis 키들은 TTL(Time To Live)을 통해 자동으로 삭제되므로 수동 키 삭제 로직이 필요하지 않습니다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#105
File: src/main/java/com/example/taste/domain/pk/batch/PkLogBatchConfig.java:81-93
Timestamp: 2025-06-20T16:19:21.527Z
Learning: PK 로그 배치 처리에서 Redis 키(`pkLog:*` 패턴)는 TTL(Time to Live)로 자동 삭제되도록 설정되어 있어 수동으로 삭제할 필요가 없음.
src/test/java/com/example/taste/domain/board/service/BoardCacheServiceTest.java (1)
Learnt from: rlgkghkd
PR: mo00ai/your-my-taste#92
File: src/main/java/com/example/taste/common/service/RedisService.java:120-126
Timestamp: 2025-06-18T01:56:09.908Z
Learning: In src/main/java/com/example/taste/common/service/RedisService.java, the `notification:count:user:{userId}:{category}` count is used to track whether all notifications (both Redis and MySQL) have been viewed/read by the user, not to count the actual number of notifications stored in Redis. This count operates independently from Redis notification storage management.
src/main/java/com/example/taste/domain/board/batch/ClosingBoardBatchConfig.java (2)
Learnt from: mo00ai
PR: mo00ai/your-my-taste#105
File: src/main/java/com/example/taste/domain/user/repository/UserRepositoryJooqCustomImpl.java:0-0
Timestamp: 2025-06-21T05:46:17.046Z
Learning: Spring Batch 환경에서는 step 레벨에서 PlatformTransactionManager를 통해 트랜잭션이 관리되므로, 개별 repository 메서드에 @Transactional 어노테이션을 중복으로 추가할 필요가 없음. 배치 writer에서 트랜잭션 매니저를 통해 하나로 묶어서 처리함.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
src/main/java/com/example/taste/domain/board/service/FcfsQueueService.java (1)
Learnt from: rlgkghkd
PR: mo00ai/your-my-taste#92
File: src/main/java/com/example/taste/common/service/RedisService.java:120-126
Timestamp: 2025-06-18T01:56:09.908Z
Learning: In src/main/java/com/example/taste/common/service/RedisService.java, the `notification:count:user:{userId}:{category}` count is used to track whether all notifications (both Redis and MySQL) have been viewed/read by the user, not to count the actual number of notifications stored in Redis. This count operates independently from Redis notification storage management.
src/test/java/com/example/taste/domain/board/service/FcfsLockPerformanceTest.java (2)
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#85
File: src/main/java/com/example/taste/domain/event/init/EventSchedulerInitializer.java:0-0
Timestamp: 2025-06-17T23:28:23.702Z
Learning: EventSchedulerInitializer.java의 하드코딩된 사용자 ID (findById(4L), findById(5L), findById(6L))는 시험용으로 작성되었으며, 향후 리팩토링 예정입니다.
src/main/java/com/example/taste/domain/board/service/BoardCacheService.java (5)
Learnt from: rlgkghkd
PR: mo00ai/your-my-taste#92
File: src/main/java/com/example/taste/common/service/RedisService.java:120-126
Timestamp: 2025-06-18T01:56:09.908Z
Learning: In src/main/java/com/example/taste/common/service/RedisService.java, the `notification:count:user:{userId}:{category}` count is used to track whether all notifications (both Redis and MySQL) have been viewed/read by the user, not to count the actual number of notifications stored in Redis. This count operates independently from Redis notification storage management.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#45
File: src/main/java/com/example/taste/domain/pk/service/PkService.java:149-191
Timestamp: 2025-06-04T12:29:53.184Z
Learning: Spring에서 self-invocation 문제를 해결하기 위해 특정 메서드만 별도 서비스로 분리하는 것이 효과적인 방법이다. 전체 서비스를 분리할 필요 없이 캐시가 필요한 메서드만 분리해도 문제를 해결할 수 있다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#34
File: src/main/java/com/example/taste/domain/pk/service/PkService.java:0-0
Timestamp: 2025-06-04T04:05:51.696Z
Learning: 이 프로젝트의 PkService에서는 PK 기준 조회 시 DB 접근 빈도가 높아서 성능 개선이 필요하며, 향후 Redis 캐시를 도입할 계획이 있다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#45
File: src/main/java/com/example/taste/domain/pk/service/PkService.java:149-191
Timestamp: 2025-06-04T12:28:01.798Z
Learning: Spring에서 같은 클래스 내의 메서드 호출 시 @Cacheable 등의 AOP 어노테이션이 동작하지 않는 self-invocation 문제가 있다. 이를 해결하기 위해서는 별도 서비스 분리, self-injection, ApplicationContext 활용 등의 방법을 사용해야 한다.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
src/main/java/com/example/taste/domain/board/service/BoardService.java (6)
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#34
File: src/main/java/com/example/taste/domain/user/entity/User.java:148-150
Timestamp: 2025-06-04T03:45:00.977Z
Learning: In the User entity's increasePoint method in src/main/java/com/example/taste/domain/user/entity/User.java, negative value validation is not needed because the PkType enum guarantees positive values (POST(30), LIKE(20), REVIEW(20), EVENT(500)), and the method is primarily used through PkService.savePkLog which uses PkType.getPoint().
Learnt from: rlgkghkd
PR: mo00ai/your-my-taste#92
File: src/main/java/com/example/taste/common/service/RedisService.java:120-126
Timestamp: 2025-06-18T01:56:09.908Z
Learning: In src/main/java/com/example/taste/common/service/RedisService.java, the `notification:count:user:{userId}:{category}` count is used to track whether all notifications (both Redis and MySQL) have been viewed/read by the user, not to count the actual number of notifications stored in Redis. This count operates independently from Redis notification storage management.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#105
File: src/main/java/com/example/taste/domain/user/repository/UserRepository.java:48-50
Timestamp: 2025-06-21T03:24:22.552Z
Learning: UserRepository의 resetAllPoints() (JPA)와 resetAllUserPoints() (JOOQ) 메서드 중복은 성능 테스트를 위한 것임. 사용자가 JPA와 JOOQ 구현체 간의 성능 차이를 측정한 후 제거할 예정임.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#60
File: src/main/java/com/example/taste/domain/event/scheduler/EventScheduler.java:0-0
Timestamp: 2025-06-09T04:12:45.332Z
Learning: PkService의 savePkLog 메서드는 내부에서 userService.increaseUserPoint(user, point)를 호출하여 포인트 부여 로직을 포함하고 있다. 따라서 savePkLog 호출 시 별도의 포인트 부여 로직은 불필요하다.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/entity/Board.java:123-124
Timestamp: 2025-06-15T15:10:23.413Z
Learning: 오픈런 게시글 생성 시 status가 null일 때 예외를 던지기보다는 CLOSED를 기본값으로 설정하여 안전한 기본 동작을 보장하는 것을 선호함. 방어적 프로그래밍 접근 방식을 사용함.
🧬 Code Graph Analysis (3)
src/main/java/com/example/taste/domain/board/dto/response/BoardResponseDto.java (2)
src/main/java/com/example/taste/domain/board/dto/response/OpenRunBoardResponseDto.java (1)
Getter(13-54)src/main/java/com/example/taste/domain/board/dto/response/OpenRunBoardQueryDto.java (1)
Getter(12-35)
src/test/java/com/example/taste/domain/board/service/BoardCacheServiceTest.java (6)
src/main/java/com/example/taste/common/constant/RedisConst.java (1)
RedisConst(8-14)src/test/java/com/example/taste/fixtures/ImageFixture.java (1)
ImageFixture(6-17)src/test/java/com/example/taste/fixtures/UserFixture.java (1)
UserFixture(15-110)src/test/java/com/example/taste/fixtures/CategoryFixture.java (1)
CategoryFixture(7-14)src/test/java/com/example/taste/fixtures/StoreFixture.java (1)
StoreFixture(9-21)src/test/java/com/example/taste/fixtures/BoardFixture.java (1)
BoardFixture(10-37)
src/test/java/com/example/taste/domain/board/service/FcfsLockPerformanceTest.java (6)
src/main/java/com/example/taste/common/constant/RedisConst.java (1)
RedisConst(8-14)src/test/java/com/example/taste/fixtures/BoardFixture.java (1)
BoardFixture(10-37)src/test/java/com/example/taste/fixtures/CategoryFixture.java (1)
CategoryFixture(7-14)src/test/java/com/example/taste/fixtures/ImageFixture.java (1)
ImageFixture(6-17)src/test/java/com/example/taste/fixtures/StoreFixture.java (1)
StoreFixture(9-21)src/test/java/com/example/taste/fixtures/UserFixture.java (1)
UserFixture(15-110)
🔇 Additional comments (28)
docker-compose.test.yml (1)
13-14: 테스트 환경 데이터베이스 초기화 설정이 적절합니다.성능 테스트를 위한 일관된 데이터베이스 상태 구성을 위해 init.sql 파일을 마운트하는 것이 좋은 접근 방식입니다.
src/main/java/com/example/taste/common/constant/RedisConst.java (3)
3-3: Duration 임포트가 적절하게 추가되었습니다.새로운 DEFAULT_TTL 상수를 위한 필요한 임포트입니다.
10-11: Redis 키 접두사 리네이밍이 기능을 더 명확하게 표현합니다.OPENRUN에서 FCFS로 변경하여 First Come First Serve의 의미를 더 명확하게 전달합니다.
12-13: 캐시 관련 상수 추가가 적절합니다.캐시 키 관리와 기본 TTL 설정을 위한 새로운 상수들이 코드베이스의 일관성을 높일 것입니다.
src/main/java/com/example/taste/domain/user/repository/UserRepositoryCustom.java (1)
3-3: 임포트 순서가 정리되었습니다.Java 표준 라이브러리 임포트를 Spring 임포트보다 먼저 배치하는 것이 일반적인 관례입니다.
src/test/java/com/example/taste/domain/board/service/FcfsInformationServiceTest.java (2)
60-60: Redis 키 접두사 상수 변경이 일관되게 적용되었습니다.RedisConst에서 변경된 FCFS_KEY_PREFIX 상수를 올바르게 사용하고 있습니다.
64-64: 메서드 시그니처 변경에 맞춰 테스트가 올바르게 수정되었습니다.Board 객체 대신 board.getId()를 전달하여 변경된 서비스 메서드 시그니처와 일치시켰습니다.
src/test/java/com/example/taste/domain/board/service/BoardServiceTest.java (1)
121-121: 상수 리팩토링이 올바르게 반영되었습니다.
OPENRUN_KEY_PREFIX에서FCFS_KEY_PREFIX로의 변경이 RedisConst 리팩토링과 일관되게 적용되었습니다.src/main/java/com/example/taste/domain/user/repository/UserRepositoryImpl.java (1)
8-8: 단순한 import 정리입니다.Import 순서 변경은 기능적 영향이 없는 코드 정리입니다.
src/test/java/com/example/taste/domain/board/service/BoardServiceUnitTest.java (1)
44-44: DTO 사용으로의 전환이 올바르게 적용되었습니다.모든 테스트 메서드에서
Board엔티티에서BoardResponseDto로,validateBoard에서validateOBoard로 일관되게 변경되었습니다. 서비스 레이어 리팩토링과 잘 일치합니다.Also applies to: 48-48, 64-64, 68-68, 84-84, 88-88
src/main/java/com/example/taste/domain/board/service/FcfsInformationService.java (1)
22-26: 메서드 시그니처 개선이 적절합니다.Board 엔티티 대신 Long boardId를 직접 받도록 변경한 것은 의존성을 줄이고 메서드의 책임을 명확히 하는 좋은 리팩토링입니다. 이는 테스트 가능성도 향상시킵니다.
src/main/java/com/example/taste/domain/board/repository/BoardRepositoryJooqCustom.java (1)
12-14: 페이지네이션 지원 추가가 적절합니다.대용량 데이터 처리를 위한 Pageable 기반 페이지네이션과 커서 기반 페이지네이션을 모두 지원하는 것은 성능 개선에 도움이 됩니다. 특히 커서 기반 페이지네이션은 대용량 데이터에서 더 안정적인 성능을 제공합니다.
src/main/java/com/example/taste/domain/board/repository/BoardRepositoryJooqCustomImpl.java (2)
37-50: Pageable 기반 페이지네이션 구현이 올바릅니다.orderBy, limit, offset을 적절히 사용하여 페이지네이션을 구현했습니다. 기존 메서드와 동일한 조건을 유지하면서 페이지네이션 기능을 추가한 것이 좋습니다.
53-66: 커서 기반 페이지네이션 구현이 효율적입니다.
BOARD.ID.gt(lastId)조건을 사용한 커서 기반 페이지네이션은 대용량 데이터에서 안정적인 성능을 제공합니다. 댓글의 "커서 조건"도 코드의 의도를 명확히 해줍니다.src/main/java/com/example/taste/domain/board/dto/response/BoardResponseDto.java (3)
15-15: JSON 직렬화 최적화가 적절합니다.
@JsonInclude(JsonInclude.Include.NON_NULL)어노테이션을 추가하여 null 필드를 JSON 응답에서 제외하는 것은 응답 크기를 줄이고 성능을 향상시키는 좋은 방법입니다.
27-29: 새로운 필드 추가가 적절합니다.
accessPolicy,openTime,openLimit필드를 추가하여 게시글의 접근 정책과 오픈런 관련 정보를 DTO에 포함하는 것은 엔티티에서 DTO로의 전환을 지원하는 좋은 변경사항입니다.
44-46: 조건부 필드 설정 로직이 적절합니다.
isNBoard()조건에 따라openTime과openLimit을 null로 설정하는 것은 일반 게시글과 오픈런 게시글을 적절히 구분하는 좋은 로직입니다.src/main/java/com/example/taste/domain/board/controller/BoardController.java (2)
59-70: 성능 모니터링 추가가 적절합니다.성능 테스트를 위한 Micrometer 메트릭 추가는 좋은 개선사항입니다. 응답 시간과 요청 수를 모니터링할 수 있어 성능 분석에 도움이 됩니다.
87-94: 메트릭 측정 로직이 적절합니다.Timer.Sample을 사용한 응답 시간 측정과 Counter 증가 로직이 올바르게 구현되었습니다. 캐시 사용으로 변경한 것도 성능 개선에 도움이 됩니다.
src/main/java/com/example/taste/domain/board/scheduler/BoardScheduler.java (1)
1-54: 전체 파일이 주석 처리되어 있습니다.이 스케줄러가 더 이상 필요하지 않다면 파일을 삭제하는 것이 좋습니다. 일시적으로 비활성화된 것이라면 그 이유를 명확히 설명하는 주석을 추가해 주세요.
src/main/java/com/example/taste/domain/board/batch/ClosingBoardBatchConfig.java (1)
129-162: 커서 기반 페이지네이션 구현이 좋습니다!대량의 데이터를 효율적으로 처리할 수 있는 방식으로 개선되었습니다.
src/test/java/com/example/taste/domain/board/service/BoardCacheServiceTest.java (1)
1-147: Redis 기반 캐싱으로의 리팩토링이 잘 되었습니다!Spring Cache에서 RedisService로의 전환이 일관성 있게 잘 적용되었고, 테스트도 새로운 동작을 적절히 검증하고 있습니다.
src/main/java/com/example/taste/domain/board/service/BoardCacheService.java (3)
3-4: 상수 클래스 분리가 적절합니다.캐싱 관련 상수를
RedisConst로 분리한 것이 좋은 구조적 개선입니다.
34-39: 캐시 히트 메트릭 추가가 훌륭합니다.성능 테스트를 위한 캐시 히트율 모니터링이 적절히 구현되었습니다.
57-59: FCFS 게시글의 TTL 로직을 확인해주세요.FCFS(선착순) 게시글은
openTime과openLimit을 무시하고 항상DEFAULT_TTL을 사용합니다. 이것이 의도된 비즈니스 로직인지 확인이 필요합니다.src/main/java/com/example/taste/domain/board/service/BoardService.java (3)
267-276: 만료된 타임어택 게시글 조회를 위한 페이징 메서드 추가가 적절합니다.페이지 기반과 커서 기반 두 가지 방식을 제공하여 성능 테스트에 유용할 것으로 보입니다.
239-243: 변수명 개선이 좋습니다.
isNotOpen에서isBeforeOpen으로 변경하여 의미가 더 명확해졌습니다.
182-183: Redis 키 접두사 FCFS_KEY_PREFIX로의 일관된 변경 확인
전체 코드베이스에서OPENRUN_KEY_PREFIX참조가 제거되었으며, 모든 사용처가FCFS_KEY_PREFIX로 일관되게 업데이트되었습니다.
- 상수 정의:
src/main/java/com/example/taste/common/constant/RedisConst.java- 서비스 구현:
BoardService.java,FcfsQueueService.java- 테스트 코드:
BoardServiceTest.java,FcfsQueueServiceTest.java,FcfsLockPerformanceTest.java,FcfsInformationServiceTest.java등변경 사항이 일관적이므로 추가 조치가 필요 없습니다.
src/main/java/com/example/taste/domain/board/batch/ClosingBoardBatchConfig.java
Show resolved
Hide resolved
src/test/java/com/example/taste/domain/board/service/FcfsLockPerformanceTest.java
Show resolved
Hide resolved
src/test/java/com/example/taste/domain/board/service/FcfsLockPerformanceTest.java
Outdated
Show resolved
Hide resolved
src/main/java/com/example/taste/domain/board/service/BoardCacheService.java
Outdated
Show resolved
Hide resolved
src/main/java/com/example/taste/domain/board/service/BoardCacheService.java
Show resolved
Hide resolved
…at#123/performance
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/main/java/com/example/taste/domain/board/batch/ClosingBoardBatchConfig.java (1)
37-37: Counter 이름과 설명을 더 구체적으로 수정하세요.과거 리뷰에서 지적된 것과 동일한 문제가 여전히 남아있습니다. Counter 이름이 너무 일반적이고, 설명도 더 구체적이어야 합니다.
다음과 같이 수정하세요:
- counter = Counter.builder("counter") - .description("배치작업 총 처리 건 수") - .register(meterRegistry); + counter = Counter.builder("closing.board.batch.processed") + .description("배치 작업의 총 처리 건 수") + .register(meterRegistry);Also applies to: 40-48
🧹 Nitpick comments (1)
src/main/java/com/example/taste/domain/board/batch/ClosingBoardBatchConfig.java (1)
85-127: 주석 처리된 코드를 제거하는 것을 권장합니다.주석으로 처리된 이전 구현들이 상당한 분량을 차지하고 있어 코드 가독성을 저해하고 있습니다. 버전 관리 시스템에서 이력을 확인할 수 있으므로 제거하는 것이 좋습니다.
다음과 같이 주석 처리된 코드를 제거하세요:
- // @Bean - // @StepScope - // public ItemReader<Long> closingBoardReader(BoardService boardService) { - // // 1차 캐시가 bulk 연산을 덮어쓰지 않도록 board가 아닌 id 값만 반환 - // log.info("스케줄러 실행 시간 : {}", System.currentTimeMillis()); - // List<Long> expiredBoardIds = boardService.findExpiredTimeAttackBoardIds(TIMEATTACK); - // //log.debug("[BoardScheduler] 만료된 오픈런 게시글 id: {}", expiredBoardIds); - // return new IteratorItemReader<>(expiredBoardIds); - // } - - // @Bean - // @StepScope - // public ItemReader<Long> closingBoardReader(BoardService boardService) { - // return new ItemReader<>() { - // private static final int PAGE_SIZE = 100; - // private int currentPage = 0; - // private Iterator<Long> currentIterator = null; - // private boolean noMoreData = false; - // - // @Override - // public Long read() { - // if (noMoreData) - // return null; - // - // // 현재 iterator가 없거나 모두 읽은 경우 다음 페이지 로딩 - // if (currentIterator == null || !currentIterator.hasNext()) { - // if (currentIterator == null) { - // log.info("스케줄러 시작 시간 : {}", System.currentTimeMillis()); - // - // } - // List<Long> nextPage = boardService.findExpiredTimeAttackBoardIdsPaged(TIMEATTACK, currentPage++, - // PAGE_SIZE); - // if (nextPage == null || nextPage.isEmpty()) { - // noMoreData = true; - // return null; - // } - // currentIterator = nextPage.iterator(); - // } - // - // return currentIterator.next(); - // } - // }; - // }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/main/java/com/example/taste/domain/board/batch/ClosingBoardBatchConfig.java(4 hunks)src/main/java/com/example/taste/domain/board/entity/BoardType.java(1 hunks)src/main/java/com/example/taste/domain/board/service/BoardCacheService.java(1 hunks)src/main/java/com/example/taste/domain/board/service/BoardService.java(7 hunks)src/main/java/com/example/taste/domain/user/entity/User.java(2 hunks)src/test/java/com/example/taste/domain/board/service/BoardServiceTest.java(1 hunks)src/test/java/com/example/taste/domain/board/service/BoardServiceUnitTest.java(6 hunks)src/test/java/com/example/taste/domain/board/service/FcfsLockPerformanceTest.java(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- src/main/java/com/example/taste/domain/user/entity/User.java
- src/test/java/com/example/taste/domain/board/service/FcfsLockPerformanceTest.java
- src/test/java/com/example/taste/domain/board/service/BoardServiceUnitTest.java
- src/main/java/com/example/taste/domain/board/service/BoardCacheService.java
- src/main/java/com/example/taste/domain/board/service/BoardService.java
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: mo00ai
PR: mo00ai/your-my-taste#112
File: src/main/java/com/example/taste/domain/image/service/ImageService.java:0-0
Timestamp: 2025-06-22T18:33:56.980Z
Learning: 사용자 mo00ai는 성능 테스트 진행 중에는 코드 변경을 피하고, 테스트 완료 후에 수정 작업을 진행하는 것을 선호함.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#141
File: src/main/java/com/example/taste/config/SecurityConfig.java:57-57
Timestamp: 2025-07-03T00:42:54.175Z
Learning: 사용자 Chaemin07는 보안 설정이나 리팩토링과 같은 개선 제안을 현재 PR에서 즉시 적용하기보다는 추후 수정하는 것을 선호함.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#34
File: src/main/java/com/example/taste/domain/pk/service/PkService.java:0-0
Timestamp: 2025-06-04T04:05:51.696Z
Learning: 이 프로젝트의 PkService에서는 PK 기준 조회 시 DB 접근 빈도가 높아서 성능 개선이 필요하며, 향후 Redis 캐시를 도입할 계획이 있다.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#60
File: src/main/java/com/example/taste/domain/user/repository/UserJdbcRepository.java:14-17
Timestamp: 2025-06-09T05:58:14.063Z
Learning: mo00ai는 성능 최적화보다는 단계별 기술 진화를 선호한다. 현재 단계에서 기본 기능을 구현하고, 이후 Spring Batch 도입 시점에 성능 최적화를 진행하여 before/after 성능 비교를 통한 정량적 개선 효과를 측정하는 접근법을 선호한다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#45
File: src/main/java/com/example/taste/domain/pk/entity/PkLog.java:28-28
Timestamp: 2025-06-04T12:56:55.316Z
Learning: mo00ai의 프로젝트에서 PkLog는 BaseCreatedAtEntity 상속을 제거하고 자체 createdAt 필드를 가지도록 변경되었다. 이는 캐시 우선 접근 방식(사용자 액션 → Redis 캐시 등록 → RDB bulk insert)에서 정확한 생성 시점을 보존하기 위한 설계이다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#45
File: src/main/java/com/example/taste/domain/pk/service/PkService.java:149-191
Timestamp: 2025-06-04T12:29:53.184Z
Learning: Spring에서 self-invocation 문제를 해결하기 위해 특정 메서드만 별도 서비스로 분리하는 것이 효과적인 방법이다. 전체 서비스를 분리할 필요 없이 캐시가 필요한 메서드만 분리해도 문제를 해결할 수 있다.
Learnt from: kmchaejin
PR: mo00ai/your-my-taste#33
File: src/main/java/com/example/taste/domain/store/service/StoreBucketService.java:127-139
Timestamp: 2025-06-04T02:13:29.504Z
Learning: kmchaejin은 코드에서 검증 로직을 별도 메서드로 분리하여 재사용 가능하게 구조화하는 것을 선호합니다.
src/test/java/com/example/taste/domain/board/service/BoardServiceTest.java (1)
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
src/main/java/com/example/taste/domain/board/batch/ClosingBoardBatchConfig.java (2)
Learnt from: mo00ai
PR: mo00ai/your-my-taste#105
File: src/main/java/com/example/taste/domain/user/repository/UserRepositoryJooqCustomImpl.java:0-0
Timestamp: 2025-06-21T05:46:17.046Z
Learning: Spring Batch 환경에서는 step 레벨에서 PlatformTransactionManager를 통해 트랜잭션이 관리되므로, 개별 repository 메서드에 @Transactional 어노테이션을 중복으로 추가할 필요가 없음. 배치 writer에서 트랜잭션 매니저를 통해 하나로 묶어서 처리함.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
⏰ 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: generate-jooq
🔇 Additional comments (6)
src/test/java/com/example/taste/domain/board/service/BoardServiceTest.java (1)
94-94: Redis 키 상수명 변경이 적절합니다.
OPENRUN_KEY_PREFIX에서FCFS_KEY_PREFIX로 변경하여 실제 기능을 더 명확히 표현하고 있습니다. FCFS(First Come First Served) 게시판에 대한 테스트이므로 의미적으로 더 정확한 상수명입니다.src/main/java/com/example/taste/domain/board/entity/BoardType.java (1)
35-37: 새로운matches메서드 구현이 깔끔합니다.기존
from메서드를 재사용하여 일관성 있는 구현을 제공하고 있습니다. 코드가 간결하고 의도가 명확합니다.다만 향후 고려사항으로,
matches메서드는 일반적으로 예외를 던지지 않는 것이 관례입니다. 현재from메서드에서 유효하지 않은 입력에 대해 예외를 던지므로, null 체크나 안전한 버전 제공도 검토해볼 수 있습니다.src/main/java/com/example/taste/domain/board/batch/ClosingBoardBatchConfig.java (4)
5-5: 필요한 import 추가가 적절히 처리되었습니다.Micrometer 메트릭 기능을 위한 import들이 올바르게 추가되었습니다.
Also applies to: 29-32
81-81: 적절한 예외 처리 추가입니다.EmptyResultDataAccessException에 대한 skip 처리가 추가되어 배치 작업의 안정성이 향상되었습니다.
131-162: Seek-based pagination 구현이 우수합니다.새로운 reader 구현이 기존의 offset-based pagination 방식보다 성능상 이점이 있는 seek-based pagination 방식으로 변경되었습니다. 대용량 데이터 처리 시 성능 향상이 기대됩니다.
174-174: 메트릭 추가가 적절합니다.Writer에서 처리된 건수만큼 counter를 증가시키는 로직이 올바르게 구현되었습니다. 배치 작업 모니터링에 유용한 메트릭이 될 것입니다.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/test/java/com/example/taste/domain/board/service/BoardServiceTest.java (1)
55-84: 테스트 데이터 설정 최적화 제안각 테스트에서 동일한 엔티티 생성 패턴이 반복되고 있습니다. 공통 설정을
@BeforeEach메서드나 헬퍼 메서드로 추출하여 중복을 줄이는 것을 고려해보세요.@BeforeEach void setUp() { image = ImageFixture.create(); user = userRepository.saveAndFlush(UserFixture.createNoMorePosting(image)); category = categoryRepository.save(CategoryFixture.create()); store = storeRepository.save(StoreFixture.create(category)); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/test/java/com/example/taste/domain/board/service/BoardCacheServiceTest.java(5 hunks)src/test/java/com/example/taste/domain/board/service/BoardServiceTest.java(1 hunks)src/test/java/com/example/taste/domain/board/service/BoardServiceUnitTest.java(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/test/java/com/example/taste/domain/board/service/BoardServiceUnitTest.java
- src/test/java/com/example/taste/domain/board/service/BoardCacheServiceTest.java
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mo00ai
PR: mo00ai/your-my-taste#112
File: src/main/java/com/example/taste/domain/image/service/ImageService.java:0-0
Timestamp: 2025-06-22T18:33:56.980Z
Learning: 사용자 mo00ai는 성능 테스트 진행 중에는 코드 변경을 피하고, 테스트 완료 후에 수정 작업을 진행하는 것을 선호함.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#141
File: src/main/java/com/example/taste/config/SecurityConfig.java:57-57
Timestamp: 2025-07-03T00:42:54.175Z
Learning: 사용자 Chaemin07는 보안 설정이나 리팩토링과 같은 개선 제안을 현재 PR에서 즉시 적용하기보다는 추후 수정하는 것을 선호함.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#34
File: src/main/java/com/example/taste/domain/pk/service/PkService.java:0-0
Timestamp: 2025-06-04T04:05:51.696Z
Learning: 이 프로젝트의 PkService에서는 PK 기준 조회 시 DB 접근 빈도가 높아서 성능 개선이 필요하며, 향후 Redis 캐시를 도입할 계획이 있다.
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#60
File: src/main/java/com/example/taste/domain/user/repository/UserJdbcRepository.java:14-17
Timestamp: 2025-06-09T05:58:14.063Z
Learning: mo00ai는 성능 최적화보다는 단계별 기술 진화를 선호한다. 현재 단계에서 기본 기능을 구현하고, 이후 Spring Batch 도입 시점에 성능 최적화를 진행하여 before/after 성능 비교를 통한 정량적 개선 효과를 측정하는 접근법을 선호한다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#45
File: src/main/java/com/example/taste/domain/pk/entity/PkLog.java:28-28
Timestamp: 2025-06-04T12:56:55.316Z
Learning: mo00ai의 프로젝트에서 PkLog는 BaseCreatedAtEntity 상속을 제거하고 자체 createdAt 필드를 가지도록 변경되었다. 이는 캐시 우선 접근 방식(사용자 액션 → Redis 캐시 등록 → RDB bulk insert)에서 정확한 생성 시점을 보존하기 위한 설계이다.
Learnt from: mo00ai
PR: mo00ai/your-my-taste#45
File: src/main/java/com/example/taste/domain/pk/service/PkService.java:149-191
Timestamp: 2025-06-04T12:29:53.184Z
Learning: Spring에서 self-invocation 문제를 해결하기 위해 특정 메서드만 별도 서비스로 분리하는 것이 효과적인 방법이다. 전체 서비스를 분리할 필요 없이 캐시가 필요한 메서드만 분리해도 문제를 해결할 수 있다.
Learnt from: kmchaejin
PR: mo00ai/your-my-taste#33
File: src/main/java/com/example/taste/domain/store/service/StoreBucketService.java:127-139
Timestamp: 2025-06-04T02:13:29.504Z
Learning: kmchaejin은 코드에서 검증 로직을 별도 메서드로 분리하여 재사용 가능하게 구조화하는 것을 선호합니다.
src/test/java/com/example/taste/domain/board/service/BoardServiceTest.java (2)
Learnt from: Chaemin07
PR: mo00ai/your-my-taste#82
File: src/main/java/com/example/taste/domain/board/service/BoardService.java:0-0
Timestamp: 2025-06-15T15:10:27.636Z
Learning: BoardRepositoryImpl.findBoardListDtoByUserIdList 메서드의 성능 최적화가 완료되었습니다. 서브쿼리 방식에서 LEFT JOIN + GROUP BY 방식으로 변경하여 N+1 쿼리 문제를 해결했습니다.
Learnt from: rlgkghkd
PR: mo00ai/your-my-taste#92
File: src/main/java/com/example/taste/common/service/RedisService.java:120-126
Timestamp: 2025-06-18T01:56:09.908Z
Learning: In src/main/java/com/example/taste/common/service/RedisService.java, the `notification:count:user:{userId}:{category}` count is used to track whether all notifications (both Redis and MySQL) have been viewed/read by the user, not to count the actual number of notifications stored in Redis. This count operates independently from Redis notification storage management.
⏰ 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: generate-jooq
🔇 Additional comments (2)
src/test/java/com/example/taste/domain/board/service/BoardServiceTest.java (2)
63-63: 상수명 변경 승인
OPENRUN_KEY_PREFIX에서FCFS_KEY_PREFIX로 변경한 것은 코드 가독성 향상에 도움이 됩니다. FCFS(First Come First Served)가 더 명확한 의미를 전달합니다.
52-177: 테스트 커버리지 우수오픈런 게시글 기능의 다양한 시나리오를 포괄적으로 테스트하고 있습니다:
- FCFS/TIMEATTACK 타입별 테스트
- 열린/닫힌 상태별 응답 필드 검증
- Redis 데이터 정리 확인
각 테스트가 명확한 given-when-then 구조를 따르고 있어 가독성이 좋습니다.
📌 관련 이슈
✨ 기능 요약
📝 상세 내역
🙋♀️ 리뷰어 참고사항
Summary by CodeRabbit
신규 기능
버그 수정
리팩터링
테스트
문서화/기타