도메인 리팩토링 #954
Replies: 7 comments 7 replies
-
DTO가 너무 계층적으로 되어 있어 문제일까?
|
Beta Was this translation helpful? Give feedback.
-
오늘도 좋은 고민거리를 제공해주어서 고마워요 아루 1/ Question, OptionGroup, OptionItem 을 template 패키지 하위로 이동 하는 것에 대해서
@RequiredArgsConstructor
@Component
public class TemplateCacheRepository {
private final SectionRepository sectionRepository;
private final QuestionRepository questionRepository;
private final OptionGroupRepository optionGroupRepository;
private final OptionItemRepository optionItemRepository;
Map<Long, List<Section>> templateIdSections;
Map<Long, List<Question>> sectionIdQuestions;
Map<Long, OptionGroup> optionGroupIdQuestion;
Map<Long, List<OptionItem>> optionItemsByOptionGroup;
@Cacheable(value = "templateCache", key = "#templateId")
public List<Question> getQuestionsByTemplateId(long templateId) {
}
@Cacheable(value = "templateCache", key = "#sectionId")
public List<Question> getQuestionsBySectionId(long sectionId) {
}
@PostConstruct
public void init() {
}
}
// QuestionRepository.java
@Query("""
SELECT q.id FROM Question q
JOIN SectionQuestion sq
ON q.id = sq.questionId
JOIN TemplateSection ts
ON sq.sectionId = ts.sectionId
WHERE ts.templateId = :templateId
""")
Set<Long> findAllQuestionIdByTemplateId(long templateId); 정리하자면, 패키지를 옮기는 것에 동의합니다. |
Beta Was this translation helpful? Give feedback.
-
2/ 서비스 코드가 다른 패키지의 Repository 를 직접 참조하지 않게 하는 것에 대해서
아루가 말한 문제점에 대해서 저도 공감하고, 이를 해결한다면 훨씬 좋은 코드가 될 것이라 생각합니다.
따라서 제가 생각해본 대안은.. 일급컬렉션의 특성을 가진 repository를 만들어서 이런 역할을 위임하는 것입니다. 이렇게 한다면 아래와 같은 함수들도 repository 안으로 옮길 수도 있지 않을까요..? Map<Long, List<OptionItem>> optionItemsByOptionGroup = optionItemRepository.findAllByQuestionIds(questionIds)
.stream()
.collect(Collectors.groupingBy(OptionItem::getOptionGroupId)); |
Beta Was this translation helpful? Give feedback.
-
3/ Dto 조합하는 걸 비즈니스 로직이라고 할 수 있나?이제는 우리가 불편함을 느끼고 있으니.. |
Beta Was this translation helpful? Give feedback.
-
1.템플릿 패키지에 질문, 옵션 등이 지금 생각하면 왜 같이 안 묶여져있는지 모르겠네요. 우리의 기준은 명확했어요. 생명주기, 변경..근데 질문와 옵션 그룹은 모두 템플릿과 섹션에 종속되어서 템플릿이 삭제되면 모두 삭제 되어야 한다고 생각해요. 만약 하나의 질문이나 옵션이 다른 템플릿에서도 사용되면 생명주기가 다른 것이 아니냐 할 수 있는데, 옵션이나 질문을 재사용하는 것 보단 템플릿에 맞춰서 새로 만드는 게 맞다고 생각합니다. 만약 여러 템플릿에서 사용되고 있는 질문이 있는데 한 템플릿에서 그 질문의 의도가 잘못 사용되고 있어서 수정된다면 그 질문을 사용하는 다른 템플릿에서도 영향을 끼칠 수 있다고 생각해요. 2.패키지 의존 관련.이 부분은 일단 그냥 사용하려면 어쩔 수 없는 부분이라고 생각해요.(물론 각각의 레포를 다 넣는다면 되겠지만 비효율적) 그래서 전에 하던 게 템플릿류들을 모두 캐싱해서 가지고 있는 클래스를 하나 만들고 그걸 사용하게 하는거였죠(산초가 올린 클래스랑 비슷) 근데 그때는 캐시에 대해 잘 몰라서 적용이 한참 걸렸는데 스프링 캐시 사용하면 깔끔하게 할 수 있을 것 같아요. 이렇게 하면 서비스마다 템플릿 재료들이 필요하면 그냥 저기서만 가져다 쓰면 되니 저 클래슨느 의존받기만 해서 방향이 일관됩니다. 그리고 이 캐시를 사용하는 곳도 저는 서비스 보단 persistence 쪽이 맞다고 생각해요. 서비스에서는 단순히 persistence에서 필요한 재료를 찾은 것 뿐이고 그 재료를 DB에서 가져올지, 캐시데이터를 가져올지는 몰라도 되는거죠. 그래서 저는 레포지토리 추상화를 사용해서 xxxRepository를 service 패키지에 3.DTO는 생각할게 많은데 일단 근본적으로 서비스 특성을 고려해도 뎁스가 너무 깊지 않나 생각합니다. 이것부터 논의해보면 좋을 것 같아요. |
Beta Was this translation helpful? Give feedback.
-
읽기/쓰기 DB 시점의 불일치가 존재해도 된다. 그 근거로는:
|
Beta Was this translation helpful? Give feedback.
-
네오의 조언우테코 이상의 것을 해보자지금까지 우테코에서 했던 것은 "학습에 대한 것" 네오가 제안한 해결 방법문제 시 했던 조회에 대한 코드가 복잡한 것은 아래와 같은 해결 방식이 있을 수 있다.
우리가 선택한 것에 대해서 감수를 해야 한다우리의 의도였던 '각 패키지가 다른 DB 를 사용한다고 가정하는 것' 역시 우리의 선택이다. 그리고 우리가 dto 재사용을 막게 한 것도 우리의 선택. 깊은 dto 에 대해서 네오가 진단한 원인 🩺우리가 진짜로 msa 환경을 고려했다면, ❗️클라이언트 입장에서 필요한 것들을 조회를 해오는게 맞았다❗️ PS) API 에서 내려줘야 하는 응답에 대한 조언이전에는 하나의 페이지에 하나의 API 호출이었다. 그래서 클라이언트의 변화마다 서버가 변해야 해서 힘들었다. |
Beta Was this translation helpful? Give feedback.
-
현재 도메인 구조를 아래와 같이 바꿔볼까 하는데 어떻게 생각하시나요?
변경된 점은 질문, 옵션이 템플릿 아래로 들어간 건데, 내부적으로는 여전히 간접 참조하고 있지만 응집도 측면에서 보았을 때는 같이 있는 게 자연스러워서요 (템플릿을 조회할 때 질문을 함께 조회함)
조회는 따로 생각해야 하지 않나? 라고 할 수도 있겠습니다만, 나중에 커스텀 질문 + 템플릿이 들어온다면 (만약) -> 생성도 같은 패키지에서만 죽 이루어지면 괜찮지 않을까 해서용
(서비스 계층화도 고려해보고 있습니다, 이번 쿠폰 미션에서 영감을 조금 받아서요)
패키지가 서로 다른 (분야가 서로 다른) 곳의
Repository
를 참조하지 않는 편이 좋을까? 예를 들어,TemplateService
에서ReviewGroupRepository
를 참조하지 않도록 한다.ReviewGroupService
를 참조하고,TemplateService
에서ReviewGroup
을 못 찾는 것에 대한 예외의 책임을 지운다.) 리뷰 그룹을 못 찾는 것에 대한 예외를 묻는 사람(템플릿)이 발생시켜야 할까, 찾는 사람(리뷰그룹)이 발생시켜야 할까? 예외도 클래스다. 예외도 다른 패키지에 있다면 의존해야 한다.만약 지양해야 한다면, 테스트 코드는 어떤 식으로 작성하는가? 다른 패키지의 서비스를 Mocking해야 하나? (극단적인 경우)
문제라고 생각하는 상황:
Review
쪽에서QuestionRepository
를 들춰봄. Template을 받아다가 가공할 수는 없었을까? 더 상위(추상적인) 계층 을 바라볼수록 변경에 유연하다.QuestionRepository
에 작성된 모든 쿼리 메서드는 리뷰에서 조회를 위해 사용되고 있다.지금 하고 있는 일:
Template
리턴하는 상황 (매핑) 확인 중, 다음과 같은 두 가지 경우를 고려,Template
에서Section
을 묶어 리턴해야 함.Dto 조합하는 걸 비즈니스 로직이라고 할 수 있나? 내 생각에는 아니다.
@Transactional
처럼 한 번에 처리해주면 좋을 텐데... 조회를 위한 로직은 비즈니스 로직이라고 볼 수는 없다고 생각한다.이야기해야 할 것: 도메인 의존이 생각보다 꼬여 있다. 잘 풀어나가 보자!
Beta Was this translation helpful? Give feedback.
All reactions