Skip to content

[우아한명지코스] 이성은 Spring Data JPA 4, 5, 6단계 미션 제출합니다.#226

Open
selee1012 wants to merge 23 commits into
next-step:selee1012from
selee1012:step2
Open

[우아한명지코스] 이성은 Spring Data JPA 4, 5, 6단계 미션 제출합니다.#226
selee1012 wants to merge 23 commits into
next-step:selee1012from
selee1012:step2

Conversation

@selee1012
Copy link
Copy Markdown

안녕하세요 우아한명지코스 이성은입니다.
먼저 늦게 리뷰 요청을 보내드리게 되어 죄송합니다
배우고 고민해 본 부분들 작성해 보았습니다.

배운 부분 & 앞으로 공부할 부분

  • 엔티티로 만들면 final을 사용할 수 없다는 걸 알게 되었습니다. "그렇다면 엔티티로 만드는 게 꼭 좋은 것인가?" 하는 의문이 들었습니다. 불변성을 보장하기 어려워지는 트레이드오프가 있는 것 같아, 이에 대해 더 공부해 볼 생각입니다.
  • 기본 생성자를 protected로 두는 게 일반적이라는 것도 알게 되었는데, 정확히 왜 public이나 private이 아니라 protected인지 그 이유를 더 찾아볼 생각입니다.
  • JPA를 쓰면서 내부 구조가 궁금해졌습니다. 메서드 이름만으로 쿼리가 자동 생성되는 게 편리했는데, 내부에서 어떤 과정을 거쳐 실제 SQL로 변환되어 실행되는지 알고 싶어졌습니다. 또 대기 순위 계산처럼 복잡한 쿼리는 결국 직접 짜야 했기 때문에, JPA를 쓴다고 해서 SQL이 아예 필요 없는 건 아니라는 걸 다시 한 번 느꼈습니다.
  • @JsonIgnore라는 어노테이션도 새로 알게 되었습니다. record에 추가한 getter가 직렬화 과정에서 의도치 않은 JSON 필드를 만들어 역직렬화가 실패하는 문제가 있었는데, 이걸 해결하는 과정에서 배우게 되었습니다.

고민한 부분

  • 회원 정보를 예약에 어떻게 담아야 할지 고민했습니다. 처음에는 member_id가 NOT NULL이어야 한다고 생각했는데, 테스트 케이스를 보니 관리자가 이름을 직접 입력하는 상황(회원 없이 이름만 있는 예약)이 존재했습니다. 요구사항에 맞춰야 한다고 판단해서 member_id를 nullable로 허용하게 했습니다.
  • 예약 대기는 힌트에 Waiting 클래스가 주어져서 별도 엔티티로 만들었지만, 사실 Reservation에 상태 컬럼을 두는 방식으로도 구현할 수 있을 것 같다는 생각이 들었습니다. 두 방식의 장단점은 더 고민하고 찾아볼 생각입니다.
  • 힌트에 주어진 JPQL은, 나보다 먼저 예약 대기를 건 사용자 수를 세고 거기에 +1을 해서 나의 대기 순번을 구하는 것으로 이해했습니다.
    응답 DTO를 record로 만들면서 메서드가 늘어나는 것에 대해 고민이 있었습니다. 하지만 일반 클래스에 비해 큰 단점이 없는 것 같고(getter 이름이 겹쳐 신경 쓸 부분이 생기는 정도?), 코드가 확실히 간단해져서 record를 유지하기로 했습니다.
  • 예약 대기 요청을 받을 때 WaitingRequest를 새로 만들기보다 기존 ReservationRequest를 재활용했습니다. 두 요청의 필드가 거의 겹쳐서, 새로 만드는 것이 오히려 구조를 더 복잡하게 만들 것 같다고 판단했습니다.

@selee1012 selee1012 changed the title [우아한명지코스] 이성은 Spring Data JPA 4, 5, 6단계 미션 제출합니다.Step2 [우아한명지코스] 이성은 Spring Data JPA 4, 5, 6단계 미션 제출합니다. May 29, 2026
@selee1012 selee1012 changed the base branch from main to selee1012 May 29, 2026 06:54
Copy link
Copy Markdown

@jhan0121 jhan0121 left a comment

Choose a reason for hiding this comment

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

안녕하세요 성은님! 이번 JPA 미션 리뷰어를 맡은 이주환입니다! 😄

JPA 미션 고생 많으셨어요! 잘 구현해주셨네요.👍 리뷰하다보니 코멘트 수가 조금 많아졌네요 😅 하나씩 차근차근히 확인해보시고 궁금한 점이 있으시면 사소한 것이어도 괜찮으니 언제든 질문해주세요!

추가로 JpaTest를 제외하고 나머지 테스트가 모두 실패하는데 확인해주세요!


@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

identity를 사용하셨군요! @GeneratedValue의 옵션으로 무엇이 있나요? 그 중 identity를 사용하신 이유가 궁금해요!

Comment on lines +7 to 11
private final MemberRepository memberRepository;

public MemberService(MemberDao memberDao) {
this.memberDao = memberDao;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

dao 명칭을 repository로 변경한 이유가 궁금해요! dao와 repository의 차이점은 무엇이 있나요?

Comment on lines +28 to +35
@JsonIgnore
public Long getId() {
return reservationId;
}

public String getStatus() {
return status;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

record는 전용 getter 포맷이 있어서 선언하실 필요가 없어요! record는 어떤 보일러플레이트를 자동화해주는지 알아볼까요?

  • 사용 예시
MyReservationResponse res = new MyReservationResponse(...);

res.reservationId(); // getId()와 같은 역할
res.status() // getStatus()와 같은 역할

Comment on lines 16 to 17
private final MemberService memberService;
private final JwtTokenProvider jwtTokenProvider;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

사용하지 않는 의존성은 제거해주세요~

Comment on lines +24 to +25
public ReservationService(ReservationRepository reservationRepository, MemberService memberService, JwtTokenProvider jwtTokenProvider,
TimeRepository timeRepository, ThemeRepository themeRepository, WaitingRepository waitingRepository) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
public ReservationService(ReservationRepository reservationRepository, MemberService memberService, JwtTokenProvider jwtTokenProvider,
TimeRepository timeRepository, ThemeRepository themeRepository, WaitingRepository waitingRepository) {
public ReservationService(
ReservationRepository reservationRepository,
MemberService memberService,
JwtTokenProvider jwtTokenProvider,
TimeRepository timeRepository,
ThemeRepository themeRepository,
WaitingRepository waitingRepository
) {

의존성이 많아지면 한 눈에 보기 쉽게 정리하는 것도 좋아요!

Comment on lines +16 to +17
@Column(name = "time_value")
private String time;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

여기에만 @Column을 적용하신 이유가 궁금해요! 해당 column만 이름을 다르게 저장하는 이유가 있으실까요?

@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private Long memberId;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reservation 엔티티에서는 member를 직접 참조했는데 Waiting에서는 id만 가지는 간접 참조를 구성하신 이유가 궁금해요! 각 방법의 장단점은 어떻게 될까요?

Comment on lines +9 to +11
public Long getId() {
return id;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

여기도 record라 별도의 getter가 필요없어요!

Comment on lines 28 to 40
CREATE TABLE reservation
(
id BIGINT NOT NULL AUTO_INCREMENT,
date VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
time_id BIGINT,
theme_id BIGINT,
id BIGINT NOT NULL AUTO_INCREMENT,
date VARCHAR(255) NOT NULL,
name VARCHAR(255),
member_id BIGINT,
time_id BIGINT,
theme_id BIGINT,
PRIMARY KEY (id),
FOREIGN KEY (member_id) REFERENCES member (id),
FOREIGN KEY (time_id) REFERENCES time (id),
FOREIGN KEY (theme_id) REFERENCES theme (id)
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

jpa를 사용하면 application.yml에서 자동으로 ddl을 생성해주는 기능이 있다는 사실을 알고 계신가요? ddl-auto 기능에 대해 알아보고 적용해볼까요?

}

@Test
void 오단계() {
Copy link
Copy Markdown

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants