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

[Feat] 예약 현황 조회 / 예약 하기 기능 구현 #12

Merged
merged 27 commits into from
Dec 10, 2024

Conversation

uijin31
Copy link
Collaborator

@uijin31 uijin31 commented Dec 4, 2024

🔗 관련 이슈

#10 #11

👩🏻‍💻 구현 내용

  • H2, Spring Data Jpa 의존성 추가
  • Booking, BookingSlot, Place, User 엔티티 생성
  • 예약 현황 조회 기능 구현 및 단위 테스트 작성
  • 예약 하기 기능 구현 및 단위 테스트 작성

💬 PR 포인트 & 궁금한 점

  • 기능을 구현한 뒤 통합 테스트를 연결하려고 했는데, 사용자 생성 / 가게 등록 등이 되어야 예약 현황 조회, 예약 하기가 가능할 것 같더라구요! 보통 통합 테스트에서 given 절에 데이터를 다 준비해 두나요?(ex. 유저 생성, 가게 생성) 아니면 모킹을 해야 할까요? 통합 테스트라 모킹을 하면 안될 것 같긴한데.. 그럼 회원 가입 / 가게 등록 로직을 구현하고 통합 테스트와 연결해야 할까요?
  • 현재는 예약이 결제 대기 중 or 확정 대기 중이더라도, 일단 해당 예약 슬롯에 예약이 있으면 다른 사람이 예약을 하지 못하도록 되어 있는데요! 만약 결제가 너무 오랫동안되지 않았거나, 확정 대기가 길어지면 따로 배치를 통해 삭제하도록 할지 고민 중인데, 이 방법으로 해도 괜찮을까요?
  • 각 레이어 (controller, service, domain) 별로 입력값을 검증하는 것을 좋을지.. 앞에 레이어를 신뢰하고 컨트롤러에서만 검증하도록 할지 고민이 됩니다.! 레이어별로 검증하는 것이 베스트지만, 중복이 되는 것 같은 느낌도 들어서요 😢
  • 나머지는 댓글로 달아 놓겠습니다!

uijin31 and others added 27 commits December 3, 2024 17:47
- H2, Spring Data Jpa 설정 추가
- 깔끔한 테스트 작성을 위해 @nested 추가
- 실제 데이터 셋팅 로직(given) 추가
[Feat] 예약 현황 조회 기능 구현 및 단위 테스트 작성
- partySize 컬럼 추가
- bookingSlotId에 unique 속성 추가
- 정적 팩터리 메서드 추가
- isBooked 상태 변경
- 예약 상태를 반환
- Step 1. 사용자 검증
- Step 2. 식당 검증
- Step 3. 예약이 가능한지 확인
- Step 4. 예약 생성
- Step 5. 이벤트 발행
@uijin31 uijin31 added the ✨ feature New feature or request label Dec 4, 2024
@uijin31 uijin31 requested a review from f-lab-lyan December 4, 2024 09:54
@uijin31 uijin31 self-assigned this Dec 4, 2024
Copy link
Collaborator Author

@uijin31 uijin31 left a comment

Choose a reason for hiding this comment

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

질문은 리뷰로 남겨놨습니다:)

Comment on lines +28 to +29
private final UserRepository userRepository;
private final PlaceRepository placeRepository;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

🙋🏻‍♀️ 추후에 User / Place / Booking 모듈이 따로 배포될 정도로 확장이 되는 경우를 생각하면 이렇게 바로 Repository를 의존하면 안될 것 같은데.. 너무 먼 미래를 걱정하는 걸까요? 😂

Comment on lines +29 to +30
@Column(name = "booking_slot_id", nullable = false, unique = true)
private Long bookingSlotId;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

🙋🏻‍♀️ 여러명이 동시에 예약을 하는 경우에 낙관적 락이나 레디스를 통해 해결해야겠다! 라고 생각했었는데, 개발을 하다보니 그냥 bookingSlotId에 unique를 걸어두면, 데이터베이스에 절대 같은 날짜/시간/테이블을 예약할 일이 없더라구요! 실무(?)에서는 어떤 방식으로 동시 예약을 막는지 여쭤봐도 될까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

🙋🏻‍♀️ 엔티티 간에 관계에서 객체를 사용하지 않고, id 값을 가지도록 했는데요! 그 이유는 1️⃣ 객체를 가지고 있으면 엔티티 간에 결합도가 높아져서 추후 모듈을 분리하기 어려울 것 같다고 판단을 하였고, 2️⃣ JPA를 사용하더라도 지연로딩을 걸고, 필요할 때 fetch join을 사용하니, 이렇게 id만 가지도 있더라도 필요할 때 join으로 가져오면 될 것 같다고 판단했습니다!

그런데.. 객체지향적으로 코드를 작성하기 위해 JPA를 사용하는데.. id로 관계를 맺는 것이 과연 맞는 선택인지가 고민이 됩니다.!

Comment on lines +41 to +42
@Column(name = "is_booked")
private boolean isBooked;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

🙋🏻‍♀️ 사실 이 BookingSlot의 id를 가지고 있는 Booking이 있는지 확인하면 예약이 되었는지 알 수 있지만, 이렇게 컬럼을 따로 두면 성능면에서 더 좋을 것 같아서 반정규화를 했습니다! 그런데 처음부터 반정규화를 하는 것보다 데이터 중복을 최소로 하고, 성능 문제가 발생할 때 반정규화를 하는 것이 더 나을까요?

Copy link
Collaborator

Choose a reason for hiding this comment

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

저는 개인적으로 연관관계를 최소화하는 것이 더 바람직하다고 생각하는 입장이긴합니다. :-) 데이터가 필요할 때, 디비에서 데이터를 가져오는 것이 장기적으로는 더 바람직한 방식이 아닐까 하는 생각이 듭니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

확실히 'BookingSlot의 id를 가지고 있는 Booking이 있더라도, 결제 기한이 지났으면 예약할 수 있다.' 와 같이 요구사항이 변경되면.. 변경 포인트가 2개라 더 유지보수 하기 어려울 것 같네요..!🤔

Comment on lines +53 to +62
public BookingStatus book() {
if (isBooked) {
throw new IllegalArgumentException("이미 예약된 테이블입니다.");
}

isBooked = true;

return isDepositRequired() ? BookingStatus.PENDING_PAYMENT
: isConfirmRequired() ? BookingStatus.PENDING_CONFIRM : BookingStatus.CONFIRMED;
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

🙋🏻‍♀️ 이 메서드가 내부적으로 상태도 바꾸면서, 반환값을 가지는 것이 클라이언트 입장에서 혼란스러울까요..? 메서드가 행위를 하는 것인지, 조회를 하는 것인지 명확하게 분리를 하는 것이 디버깅에도 좋다고 들어서요..!

Copy link
Collaborator

Choose a reason for hiding this comment

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

말씀하신대로 메소드가 어떤 동작을 할 것인지 명확하게 하는 것이 좋은데, 이런 구조에서는 쉽지 않을 것 같아요. 이 얘기는 저 위에 비지니스 로직을 누가 가질 것인지와 연관지에서 멘토링 시간에 얘기해보면 좋을 것 같습니다.

@@ -0,0 +1,13 @@
package com.nowait.place.domain.model;

public enum PlaceType {
Copy link
Collaborator

Choose a reason for hiding this comment

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

이렇게 하면, PlaceType은 동적으로 추가가 불가능해질 것 같네요. :-)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

엔티티로 만들어서, 관리자가 수정할 수 있도록 하는 것이 좋을까요?
관리자 기능을 만들 생각을 못해서 해당 문제도 생각하지 못했네요😥 백로그에 담아 보겠습니다!

private final ApplicationEventPublisher eventPublisher;

@Async
public void publishBookedEvent(Booking booking, Long placeId) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

음 ... 이 코드는 페어가 필요한 것 같은데, 일단 리스너는 아직 구현하지 않으신건가요? 아니면, 제가 놓친 코드가 있을까요? 그리고 그것과 별개로, ApplicationEventPublisher를 써서 하고 싶은 것이 뭐였을지 궁금하네요!!!! 😬

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

예약 시나리오에서 예약이 완료되면, 사용자와 가게에 알림을 보내는 로직이 필요해서 넣었습니다! 그런데 아직 알림 기능을 개발하지 못해서 리스너는 구현이 되어 있지 않은 상태입니다😂 미리 코멘트를 남기거나, 필요할 때 작성하는게 더 나았을 것 같네요ㅜㅜ

Copy link
Collaborator

@f-lab-lyan f-lab-lyan left a comment

Choose a reason for hiding this comment

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

몇몇 궁금한 지점들이 있습니다만, 코드 전체적으로는 크게 문제는 없어보입니다. 머지하시고, 다음 작업을 하셔도 괜찮을 것 같습니다.

@uijin31 uijin31 merged commit 591fe0b into main Dec 10, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants