-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor: Like 도메인 리팩토링 #50
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package project.flipnote.like.service; | ||
|
|
||
| import org.springframework.stereotype.Service; | ||
|
|
||
| import lombok.RequiredArgsConstructor; | ||
| import project.flipnote.common.exception.BizException; | ||
| import project.flipnote.like.entity.Like; | ||
| import project.flipnote.like.entity.LikeTargetType; | ||
| import project.flipnote.like.exception.LikeErrorCode; | ||
| import project.flipnote.like.repository.LikeRepository; | ||
|
|
||
| @RequiredArgsConstructor | ||
| @Service | ||
| public class LikeReader { | ||
|
|
||
| private final LikeRepository likeRepository; | ||
|
|
||
| public Like findByTargetAndUserId(LikeTargetType targetType, Long targetId, Long userId) { | ||
| return likeRepository.findByTargetTypeAndTargetIdAndUserId(targetType, targetId, userId) | ||
| .orElseThrow(() -> new BizException(LikeErrorCode.LIKE_NOT_FOUND)); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| package project.flipnote.like.service; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Set; | ||
| import java.util.function.Function; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| import org.springframework.stereotype.Service; | ||
|
|
||
| import jakarta.annotation.PostConstruct; | ||
| import lombok.RequiredArgsConstructor; | ||
| import project.flipnote.common.exception.BizException; | ||
| import project.flipnote.like.entity.LikeTargetType; | ||
| import project.flipnote.like.exception.LikeErrorCode; | ||
| import project.flipnote.like.model.response.LikeTargetResponse; | ||
| import project.flipnote.like.service.fetcher.LikeTargetFetcher; | ||
|
|
||
| @RequiredArgsConstructor | ||
| @Service | ||
| public class LikeTargetFetchService<T extends LikeTargetResponse> { | ||
|
|
||
| private final List<LikeTargetFetcher<T>> fetchers; | ||
|
|
||
|
Comment on lines
+21
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 제네릭 불변성으로 인한 Spring 주입 실패 가능성 (치명적). List<LikeTargetFetcher>는 제네릭 불변(invariant)이라 LikeTargetFetcher가 LikeTargetFetcher에 주입되지 않습니다. 현재 LikeService/LikePolicyService에서 LikeTargetFetchService를 주입하고 있어, 실제로는 컨텍스트 로딩 시점에 주입 실패가 발생할 확률이 높습니다. 아래처럼 서비스의 제네릭을 제거하고, 내부에서 안전한(경고 억제) 캐스팅을 사용하면 주입 문제가 해소됩니다. -@RequiredArgsConstructor
-@Service
-public class LikeTargetFetchService<T extends LikeTargetResponse> {
+@RequiredArgsConstructor
+@Service
+public class LikeTargetFetchService {
- private final List<LikeTargetFetcher<T>> fetchers;
+ private final List<LikeTargetFetcher<?>> fetchers;
- private Map<LikeTargetType, LikeTargetFetcher<T>> fetcherMap;
+ private Map<LikeTargetType, LikeTargetFetcher<?>> fetcherMap;
@PostConstruct
public void init() {
- this.fetcherMap = this.fetchers.stream()
- .collect(Collectors.toMap(LikeTargetFetcher::getTargetType, Function.identity()));
+ this.fetcherMap = this.fetchers.stream()
+ .collect(Collectors.toMap(LikeTargetFetcher::getTargetType, Function.identity()));
}
public boolean isTargetViewable(LikeTargetType targetType, Long targetId, Long userId) {
- LikeTargetFetcher<T> targetFetcher = getFetcher(targetType);
+ LikeTargetFetcher<?> targetFetcher = getFetcher(targetType);
return targetFetcher.isTargetViewable(targetId, userId);
}
- public Map<Long, T> fetchByTypeAndIds(
+ public <T extends LikeTargetResponse> Map<Long, T> fetchByTypeAndIds(
LikeTargetType targetType,
Set<Long> targetIds,
Long userId
) {
- LikeTargetFetcher<T> targetFetcher = getFetcher(targetType);
- return targetFetcher.fetchByIds(targetIds, userId);
+ @SuppressWarnings("unchecked")
+ LikeTargetFetcher<T> targetFetcher = (LikeTargetFetcher<T>) getFetcher(targetType);
+ return targetFetcher.fetchByIds(targetIds, userId);
}
- private LikeTargetFetcher<T> getFetcher(LikeTargetType targetType) {
- LikeTargetFetcher<T> fetcher = fetcherMap.get(targetType);
+ private LikeTargetFetcher<?> getFetcher(LikeTargetType targetType) {
+ LikeTargetFetcher<?> fetcher = fetcherMap.get(targetType);
if (fetcher == null) {
throw new BizException(LikeErrorCode.INVALID_LIKE_TYPE);
}
return fetcher;
}
}이 변경에 맞춰 LikeService/LikePolicyService의 필드 타입도 LikeTargetFetchService (비제네릭)로 조정해야 합니다. Also applies to: 39-47, 49-56 🤖 Prompt for AI Agents |
||
| private Map<LikeTargetType, LikeTargetFetcher<T>> fetcherMap; | ||
|
|
||
| @PostConstruct | ||
| public void init() { | ||
| this.fetcherMap = this.fetchers.stream() | ||
| .collect(Collectors.toMap(LikeTargetFetcher::getTargetType, Function.identity())); | ||
| } | ||
|
|
||
| public boolean isTargetViewable(LikeTargetType targetType, Long targetId, Long userId) { | ||
| LikeTargetFetcher<T> targetFetcher = getFetcher(targetType); | ||
|
|
||
| return targetFetcher.isTargetViewable(targetId, userId); | ||
| } | ||
|
|
||
| public Map<Long, T> fetchByTypeAndIds( | ||
| LikeTargetType targetType, | ||
| Set<Long> targetIds, | ||
| Long userId | ||
| ) { | ||
| LikeTargetFetcher<T> targetFetcher = getFetcher(targetType); | ||
|
|
||
| return targetFetcher.fetchByIds(targetIds, userId); | ||
| } | ||
|
|
||
| private LikeTargetFetcher<T> getFetcher(LikeTargetType targetType) { | ||
| LikeTargetFetcher<T> fetcher = fetcherMap.get(targetType); | ||
| if (fetcher == null) { | ||
| throw new BizException(LikeErrorCode.INVALID_LIKE_TYPE); | ||
| } | ||
|
|
||
| return fetcher; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Like 도메인의 오류 코드를 사용하세요 (북마크 도메인으로 던짐).
가시성 검증 실패 시 BOOKMARK_TARGET_NOT_FOUND를 던지는 것은 도메인 불일치입니다. Like 흐름에서는 LikeErrorCode 쪽의 대상-부재 코드를 사용해야 API/문서 일관성이 유지됩니다. 또한 현재 메서드명은 “존재”를 암시하나, 실제로는 “가시성(뷰어블)”을 검증하므로 네이밍/주석 정비가 필요합니다.
다음과 같이 수정을 제안합니다(상수명은 기존 코드베이스에 맞춰 확인 필요합니다. 기존에 LIKE_TARGET_NOT_FOUND가 있었다면 그걸 사용하세요).
추가로, 실질 검증이 “존재”가 아니라 “가시성”이므로 아래 중 하나를 권장합니다.
🏁 Script executed:
Length of output: 5522
Like 도메인 오류 코드 사용 및 메서드명 정비
src/main/java/project/flipnote/like/service/LikePolicyService.java(라인 20-23): 가시성 검증 실패에 BookmarkErrorCode.BOOKMARK_TARGET_NOT_FOUND를 던지고 있음 — LikeErrorCode.LIKE_TARGET_NOT_FOUND로 교체하세요.
메서드명은 '존재'가 아니라 '가시성(viewable)'을 검증하므로 validateTargetViewable(...)로 변경하거나 Javadoc으로 가시성 검증임을 명시하세요.
📝 Committable suggestion
🤖 Prompt for AI Agents