Skip to content
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

[BE] feat: 변경된 도메인 구조가 적용된 리뷰 작성 API 구현 #296

Merged
merged 42 commits into from
Aug 12, 2024

Conversation

nayonsoso
Copy link
Contributor


🚀 어떤 기능을 구현했나요 ?

  • 리뷰 작성 기능을 구현했습니다.

🔥 어떻게 해결했나요 ?

  • 충돌이 나는 것을 피하기 위해 & 서비스 분리가 필요하다 생각해서 CreateReviewService 를 만들어서 거기서 작업했습니다.
  • dto 도 패키지 별 분리를 하면 좋겠다 생각해서 create 라는 패키지를 파서 거기에 dto 추가 생성했습니다.
  • 서술형 질문, 객관식 질문에 대해서 저장을 할 때 검증이 많아서 객체를 분리했습니다.
  • 특히 객관식 질문 검증 짱마늠

📝 어떤 부분에 집중해서 리뷰해야 할까요?

  • 이번에 서비스도 분리하고 dto 패키지도 분리하는 등 제가 주관대로 한 부분들이 조금 있는데, 혹시 마음에 안들면 코멘트 남겨주세용~

📚 참고 자료, 할 말

  • 다음에 도메인 엎고 역할 분배할 순간이 다시 온다면, "생성자와 레포지토리 & default 함수 정도"는 만들고 분배해야 할 듯🤯

공통 코드에서 리팩터링 필요하다 느낀 부분

  1. 선택지를 뜻하는 checkbox 와 option 이라는 단어를 통일해서 하나만 사용해야 한다.
  2. Review 가 templateId 를 갖는게 아니라 ReviewGroup 이 갖게 해야 한다.
  3. 테스트 코드를 작성할 때, Template 이 SessionId 를 List sessionIds 으로 참조하고 있는 상태에서, template.getSesstionIds() 를 호출하니 lazily initialize exception 이 발생했다. ElementCollection으로 참조하는 것도 순전히 자바 객체처럼 참조하는 것은 아니고, 내부적으로 트랜잭션을 신경써야 하는 것 같다. 일단 테스트코드에서 그런 상황이 발생하지 않게끔 갯수만 검증하는 식으로 구현하긴 했다.

- 명시적이게 Question2 로 변경
@nayonsoso nayonsoso linked an issue Aug 10, 2024 that may be closed by this pull request
10 tasks
Copy link

github-actions bot commented Aug 10, 2024

Test Results

49 tests   49 ✅  1s ⏱️
20 suites   0 💤
20 files     0 ❌

Results for commit 04f5b66.

♻️ This comment has been updated with latest results.

@donghoony donghoony changed the title [BE] 변경된 도메인 구조가 적용된 리뷰 작성 API 를 구현한다. [BE] feat: 변경된 도메인 구조가 적용된 리뷰 작성 API 구현 Aug 11, 2024
Copy link
Contributor

@donghoony donghoony left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

밤까지 고생했습니다 👍🏻

Copy link
Contributor

@Kimprodp Kimprodp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전체적으로 좋네요 급하게 수정되어야 할 부분은 없을 것 같고, 논의가 필요한 부분만 다 같이 논의해보면 좋을듯!

참고로 로깅 너무 잘해놔서 내 기능 구현할때 편했어요 (●'◡'●)👍

@@ -25,7 +26,7 @@ public class Review2 {
private Long id;

@Column(name = "template_id", nullable = false)
private long templateId;
private long templateId; // todo: templateId 를 여기가 아니라 reviewGroup 안에 둬야 함
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분 다시 논의 해보면 좋겠지만, 중간에 템플릿이 변경되면 리뷰 그룹을 다시 생성해야 하나요?
리뷰 그룹이 templateId를 가지고 있으면 리뷰 그룹 하나는 하나의 템플릿만 사용하지 못할 것 같은데..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리뷰 그룹이 templateId를 가지고 있으면 리뷰 그룹 하나는 하나의 템플릿만 사용하지 못할 것 같은데..

하나의 리뷰 그룹은 하나의 템플릿을 사용하는게 자연스럽다고 생각해요!
'리뷰 그룹'이라고 함은, 리뷰를 작성하는 대상들을 정의하는 것인데,
작성자들마다 다른 템플릿을 보여주진 않을 것 같아요.
혹시 테드가 다르게 생각하고 있는 부분이 있다면 알려주세용~

중간에 템플릿이 변경되면 리뷰 그룹을 다시 생성해야 하나요?

이건 다 같이 논의되지 않았긴 했는데, 제 생각에는 중간에 템플릿이 바뀌지 않을 것 같습니다

Copy link
Contributor

@skylar1220 skylar1220 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

검증 수고했어여🥲👏


public OptionItemNotFoundException(long id) {
super("옵션 아이템이 존재하지 않아요.");
log.info("OptionItemNotFoundException is occurred - id: {}", id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예외의 info / warn / error를 책정하는 기준이 있어야겠네요!
이 예외도 일어날 가능성이 적다는 측면이라면 warn 정도도 괜찮을 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예외의 info / warn / error를 책정하는 기준이 있어야겠네요!

동의합니다~
서버가 내려준 대로 응답하면 발생하지 않을 예외들은 warn 으로 두는게 좋을 것 같아요.
누군가 사이트를 통하지 않고 이상한 형식으로 리뷰를 제출하려 한다는 거니까요.
이건 지금 고칠건 아닌 것 같고, 나중에 상의할 필요가 있다는 생각이 들어 이슈에 추가해뒀습니다!

.orElseThrow(() -> new ReviewGroupNotFoundByRequestReviewCodeException(reviewRequestCode));
}

private void validateSubmittedQuestionAndProvidedQuestionMatch(CreateReviewRequest request, Template template) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validateFormAndTemplateQuestionMatch
응답한 폼은 Form, 양식은 Template 으로 명칭을 통일해서 이름을 간략화하는 건 어떨까요?
다른 pr에도 코멘트로 남겼는데, 이 명칭이 혼용되고 있는 것에 대해 문제를 느꼈었어서요!
이건 전체 논의가 필요할 것 같네요!

@Kimprodp @donghoony

Copy link
Contributor Author

@nayonsoso nayonsoso Aug 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

응답한 폼은 Form, 양식은 Template 으로 명칭을 통일해서 이름을 간략화하는 건 어떨까요?

이 문장에서

응답한 폼은 Form, 양식은 Template 으로 명칭을 통일

하는 것은 좋은 의견같습니다!

이름을 간략화하는 건 어떨까요?

그런데 요 부분은 다른 생각인게,
이 검증 함수는 '질문의 id'를 검증하는 함수이기 때문에 길더라도 지금의 이름이 의미를 잘 드러낸다고 생각해요. 심지어 이 클래스 안에 validate 가 많기 때문에 의미를 명확히 하는게 더 중요하다고 생각고요! 그래서 일단 이렇게 두겠습니다 ㅎㅎ 🫰🏻

Comment on lines 53 to 56
private void validateQuestionRequired(CreateReviewAnswerRequest request, Question2 question) {
if (question.isRequired() && request.selectedOptionIds() == null) {
throw new RequiredQuestionMustBeAnsweredException(question.getId());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(수정사항 아님! 논의할점!)
그리고 request.selectedOptionIds() == null 이 부분 리스트인데 null 검증을 하고있는 상황을 보면서 생각이 들었는데요!
현재 api 문서에는 주관식인경우 selectedOptionIds가 null로 오고있는데 null 위험성을 경계하자면 프론트에게 빈 list로 보내달라고 요청하는 건 어떨까? 하는 생각이 들어서 논의해보고 싶네요!

Comment on lines +47 to +48
return reviewGroupRepository.findByReviewRequestCode(reviewRequestCode)
.orElseThrow(() -> new ReviewGroupNotFoundByRequestReviewCodeException(reviewRequestCode));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createService를 분리하여 관심사도 분리하고, 응집도 up! 서비스 가벼워지는 것 좋아요~
다만 이런 부분이 reviewService(분리 후에는 조회에 집중되어있음)에도 중복 로직이 있어서 이런 부분을 아예 조회 서비스에서 불러와서 쓰게해야할지, 중복을 감수할지 고민이네요!

Copy link
Contributor Author

@nayonsoso nayonsoso Aug 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

응집도 up! 서비스 가벼워지는 것 좋아요~

🥰

다만 이런 부분이 reviewService(분리 후에는 조회에 집중되어있음)에도 중복 로직이 있어서 이런 부분을 아예 조회 서비스에서 불러와서 쓰게해야할지, 중복을 감수할지 고민이네요!

서비스를 각각 분리한다면 충분히 생길만한 고민이네요! 그런데 그런 순간이 왔을 때 해결책을 찾아보는 것도 좋을 것 같아요~ 어떤게 중복되는지에 따라 달라질 것 같아서요!

Comment on lines +29 to +32
private Question2 validateQuestionExists(CreateReviewAnswerRequest request) {
long questionId = request.questionId();
return question2Repository.getQuestionById(questionId);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 선택형 validator, 서술형 validator에 중복으로 들어있는 로직이네요.
만약 수정사항이 생기면 두 부분의 검증 메서드의 정합성을 신경써야한다는 점이 걸려요!

  1. 완전 공통 validate 부분은 서비스에서 검증하기
  2. 공통 검증 validator를 하나 만들기
    두개정도 떠오르는데 2번은 과하니 1번 방법은 어떤가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예리하게 보셨네요...
그런데 더욱 놀라운 사실은 이미 1번을 서비스에서 하고 있습니다.!

image

그래서 왜 서비스에서 검증하는 것을 XXXAnswerRequestValidator에도 검증하느냐 한다면,
저는 XXXAnswerRequestValidator 그 자체로 "검증해주는 객체"로 생각했어요. 그래서 앞에서 어떤 함수를 선언했는지에 상관 없이 그 안에서 QuestionId에 대한 검증을 하게 해줬어요. 제출된 응답에 대해 검증을 하는 객체이니까, 그 응답이 존재하는 questionId에 대한것인지 검증하는 책임을 갖는게 당연하다 생각했지요!

수정사항이 생기면 두 부분의 검증 메서드의 정합성을 신경써야한다는 점이 걸려요!

그와 별개로 이 부분에는 동의를 하는데요, 상속을 사용하면 참 좋겠다는 생각을 했습니다. 이건 나중에 더 이야기해봐요!

- private 함수를 호출하지 사용하지 않고, repository 함수를 바로 호출하도록 변경
- question 과 template 패키지에 각각 존재하던 것을 question 패키지로 통합
…ature/292-review-create-api

# Conflicts:
#	backend/src/main/java/reviewme/question/domain/Question2.java
#	backend/src/main/java/reviewme/question/repository/OptionGroupRepository.java
#	backend/src/main/java/reviewme/question/repository/OptionItemRepository.java
#	backend/src/main/java/reviewme/review/controller/ReviewController.java
#	backend/src/main/java/reviewme/review/domain/Review2.java
#	backend/src/main/java/reviewme/template/repository/SectionRepository.java
- merge 후 발생하는 컨플릭을 해결한 뒤 발생한 컴파일 에러를 해결한다.
Copy link
Contributor

@skylar1220 skylar1220 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

궈궈

@nayonsoso nayonsoso merged commit 48e2876 into develop Aug 12, 2024
4 checks passed
@donghoony donghoony deleted the be/feature/292-review-create-api branch August 20, 2024 01:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

[BE] 리뷰 쓰기 기능을 구현한다.
4 participants