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

[4기 유명한 & 나영경] Springboot-board-JPA 1차 PR 입니다. #230

Open
wants to merge 51 commits into
base: 명한,영경-mission
Choose a base branch
from

Conversation

yumyeonghan
Copy link

📌 과제 설명

  • 유명한, 나영경 페어를 이루어 프로그래밍을 진행했습니다.

👩‍💻 요구 사항과 구현 내용

SpringDataJPA 를 설정한다.

  • datasource : h2 or mysql

엔티티를 구성한다

  • 회원(User)
    • id (PK) (auto increment)
    • name
    • age
    • hobby
    • created_at
    • created_by
  • 게시글(Post)
    • id (PK) (auto increment)
    • title
    • content
    • created_at
    • created_by
  • 회원과 게시글에 대한 연관관계를 설정한다.
    • 회원과 게시글은 1:N 관계이다.
  • 게시글 Repository를 구현한다. (PostRepository)

API를 구현한다.

  • 게시글 조회
    • 페이징 조회 (GET "/posts")
    • 단건 조회 (GET "/posts/{id}")
  • 게시글 작성 (POST "/posts")
  • 게시글 수정 (POST "/posts/{id}")

REST-DOCS를 이용해서 문서화한다.

Copy link
Member

@dojinyou dojinyou left a comment

Choose a reason for hiding this comment

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

수고하셨습니다!

src/main/java/com/programmers/domain/post/entity/Post.java Outdated Show resolved Hide resolved

import static org.assertj.core.api.Assertions.assertThat;

@DataJpaTest

Choose a reason for hiding this comment

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

@DataJpaTest는 보통 영속성 레이어 테스트에서 많이 사용하는데, 다른 방법은 없을까요?

Copy link
Author

Choose a reason for hiding this comment

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

서비스 레이어의 단위테스트는

  1. 빠르게 실행되어야 하고
  2. 다른 테스트로부터 영향을 받으면 안되고
  3. DB에 의존하면 안된다고 생각합니다

따라서 DB에 직접적인 연관을 하고있는 Repository 레이어에 대한 의존성을 제거하고, 서비스 레이어만 독립적으로 테스트할 수 있도록
@DataJpaTest 대신, Mock을 사용했습니다.
3bb298f

- 영속성 레이어 테스트가 아닌, 서비스 레이어의 단위테스트 이기 때문에 @DataJpaTest 대신 Mock 사용
Comment on lines +26 to +27
private final PostRepository postRepository;
private final UserRepository userRepository;
Copy link
Member

Choose a reason for hiding this comment

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

다른 도메인의 Repository 직접 참조하시는 이유가 있나요?

Copy link
Author

Choose a reason for hiding this comment

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

다른 도메인의 레포나 서비스를 참조해도 되는지, 이부분도 고민이 많이 됐고, 실제 팀원들과 얘기할때도 명확하게 답을 내리지 못했습니다.

우선은 Post를 생성하기 위해선 반드시 User 엔티티가 필요하기 때문에 Repository를 참조해서 User 엔티티를 조회하는데 사용했습니다.

이 부분에 대해서 멘토님들의 의견은 어떠신지 궁금합니다.!

Choose a reason for hiding this comment

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

Service, Repository 중 어느 것에 의존할 것이냐는 항상 의견이 나뉘는 것 같아요. 장단점이 어떤게 있을 지 생각해보면 좋을 것 같네요.

예를들어 userId에 해당하는 User가 없을 때 어떤 정책을 세웠을 텐데 Repository에 의존하면 해당 로직에 대한 코드가 중복될 수 있겠네요. 특정 비즈니스에 종속적이지 않고 단순히 영속성 계층에서 데이터를 조회하거나 영속화 하고 싶다면 Repository에 의존할 수도 있을 것 같네요.

Copy link
Member

Choose a reason for hiding this comment

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

저는 개인적으로 Service가 다른 Service를 참조하는 걸 선호하는 편입니다!

import com.programmers.domain.user.entity.User;
import org.springframework.stereotype.Component;

@Component
Copy link
Member

Choose a reason for hiding this comment

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

@Component로 관리하는 이유가 있나요?

Copy link
Author

Choose a reason for hiding this comment

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

처음엔 유틸 관련 기능이라 static 활용을 고려했습니다.
그런데 해당 클래스는 PostService에서만 사용을 하기 때문에, 먼가 static 보단
빈으로 등록해서 관리를 하는게 더 나을거 같다고 생각을 했습니다.

혹시 유틸 기능이니깐 static으로 사용해야할까요?
아니면 컨버터 대신 Dto에 변환 메서드를 구현해서 사용하는 방법도 좋은 방법일까요?

Copy link
Member

Choose a reason for hiding this comment

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

딱히 답이 있는 문제는 아닌 것 같아요.
여러 장 단점이 있는데 중요한 건 명확한 근거가 필요하다는 점인 것 같아요.
한번 고민해보시죠. dto에 변환 메서드를 구현하는 방법도 고민해볼 수 있을 것 같아요

src/main/java/com/programmers/domain/post/entity/Post.java Outdated Show resolved Hide resolved
Comment on lines 39 to 40
@Mock
private PostConverter postConverter;

Choose a reason for hiding this comment

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

이정도는 모킹할 필요가 없지 않을까요?

Copy link
Author

Choose a reason for hiding this comment

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

승훈님의 질문을 PostConverter는 실제 구현체를 쓰는게 낫다라고 이해를 했습니다.

현재 테스트하고있는 PostServiceImpl는 단위 테스트를 하기위해 Mock으로 되어있습니다.
따라서 해당 클래스가 의존하고 있는 빈들을 모킹을 했는데, 그중 PostConverter 빈만 실제 구현체를 사용해서 PostServiceImpl에 주입할 수는 없는것 같습니다.

혹시 제가 질문을 잘못 이해했을까요?
(아니면 컨버터 역할을 하는 객체를 static으로 만들라는 뜻일까요?)

Choose a reason for hiding this comment

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

PostServiceImpl은 목이 아니지 않나요?
image

Comment on lines +21 to +31
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
private ErrorResult handleIllegalArgumentException(IllegalArgumentException e) {
return new ErrorResult(HttpStatus.BAD_REQUEST.value(), e.getMessage());
}

@ExceptionHandler(NoSuchElementException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
private ErrorResult handleNoSuchElementException(NoSuchElementException e) {
return new ErrorResult(HttpStatus.BAD_REQUEST.value(), e.getMessage());
}

Choose a reason for hiding this comment

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

예외 메시지를 그대로 클라이언트에게 전달해주면 안될 것 같네요~

Copy link
Author

Choose a reason for hiding this comment

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

IllegalArgumentException 또는 NoSuchElementException 같이 자바 기본 예외를 사용하면, 제가 직접 던진 부분 이외에 예상치 못하게 서버에서 발생해버리면, 결국에는 기본 예외 메세지가 나갈것같습니다.
이렇게 발생한 예외 메세지(제가 직접 던진 예외 메세지 + 해당 예외의 기본 메세지)들을 하나하나 구분해서 핸들링 하는것보다

차라리 사용자 정의 예외를 만들어서 처리하고,
그 이외에 자바 기본 예외가 발생하는 것들은

@ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    private ErrorResult handleException() {
        return new ErrorResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), INTERNAL_SERVER_ERROR_MESSAGE);
    }

해당 로직으로 한번에 "예상치 못한 예외" 같은걸로 처리하도록 설계하고자 하는데, 혹시 이러한 방법으로 설계해도 될까요?

Choose a reason for hiding this comment

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

네 좋을 것 같아요

Comment on lines +26 to +27
private final PostRepository postRepository;
private final UserRepository userRepository;

Choose a reason for hiding this comment

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

Service, Repository 중 어느 것에 의존할 것이냐는 항상 의견이 나뉘는 것 같아요. 장단점이 어떤게 있을 지 생각해보면 좋을 것 같네요.

예를들어 userId에 해당하는 User가 없을 때 어떤 정책을 세웠을 텐데 Repository에 의존하면 해당 로직에 대한 코드가 중복될 수 있겠네요. 특정 비즈니스에 종속적이지 않고 단순히 영속성 계층에서 데이터를 조회하거나 영속화 하고 싶다면 Repository에 의존할 수도 있을 것 같네요.

@Override
public UserDto findUser(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new NoSuchElementException(USER_NOT_FOUND));

Choose a reason for hiding this comment

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

어떤 id가 들어왔는지 함께 나타내주면 좋을 것 같네요

Copy link
Member

@dojinyou dojinyou left a comment

Choose a reason for hiding this comment

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

수고하셨습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants