Skip to content
This repository has been archived by the owner on Aug 13, 2022. It is now read-only.

[#25] 결제관련 entity 생성 및 설계 #38

Open
wants to merge 7 commits into
base: feature/13
Choose a base branch
from
Open

Conversation

jjeda
Copy link
Collaborator

@jjeda jjeda commented Dec 11, 2019

  • 조인 전략으로 상속구조 매핑
  • Payment 관련 Entity, Repository 생성

결제하는 방법에 3가지(카드, 계좌이체, 모바일)

3개의 클래스는 Payment 라는 부모 (추상)클래스를 상속받고있음 -> JPA 조인전략으로 상속관계 매핑

  • 각각의 결제 방법에 따라 저장돼있는 정보가 다르기때문
  • 예) 카드결제 -> 카드정보, 계좌이제 -> 입금된 계좌 정보 등

Client 측에서 결제정보를 @RequestBody Payment payment 로 가져옴
상위 타입에 PaymentRepository를 사용해서 DB에 저장

- 조인 전략으로 상속구조 매핑
- Payment 관련 Entity, Repository 생성:
Comment on lines 49 to 68
@Test
public void testPayment() throws Exception {

AccountDto buyerAccountDto = AccountDto.builder()
.accountRole(Set.of(AccountRole.USER))
.address(new Address("a", "b", "c"))
.email("[email protected]")
.nickname("buyer")
.phone("01012341234")
.password("pass")
.build();
AccountDto buyerDto = accountService.saveAccount(buyerAccountDto);

mockMvc.perform(post("/api/orders/buyer/payment")
.header(HttpHeaders.AUTHORIZATION, getAccessToken(buyerAccountDto))
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaTypes.HAL_JSON))
.andDo(print());
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

상속관계 매핑 테스트한다고 임의로 넣은코드가 커밋됐네요~ 다음 커밋에 수정하겠습니다

@jjeda jjeda requested a review from f-lab-dev December 11, 2019 14:51
@jjeda jjeda self-assigned this Dec 11, 2019
@jjeda
Copy link
Collaborator Author

jjeda commented Dec 11, 2019

코드는 몇줄안되지만..
다른 결제방법을 분기하는 방법이 아닌 하나의 상위타입으로 처리하는 방식으로 설계하느라 오래걸렸네요~
적절한지 봐주시면 비즈니스 로직도 완성하겠습니다.

@f-lab-dev
Copy link
Member

전체적으로 보았을때 추상화에 대한 아이디어는 좋았지만 이는 "동작"에 대한 추상화입니다. 저장하는 데이터는 결제테이블이 하나만 있는게 좋을 것 같아요. (결제수단 n개만큼 테이블을 만들면 jpa외의 툴을 사용할때 상당히 복잡할겁니다)
신용카드 정보와 같은 결제수단별 특징이 있는 데이터는 별도의 테이블로 만들고요~

@f-lab-dev
Copy link
Member

그리고 approve된 PR들은 머지하셔도 됩니다

- Payment 관련 Entity 생성
- Payment 관련 Dto, Cotroller, Service, Repository 생성
- Service 레이어 추상화
- TODO : 전략패턴 적용
Copy link
Collaborator Author

@jjeda jjeda left a comment

Choose a reason for hiding this comment

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

이번 설계 방법은
Service 레이어를 추상화하여 각각의 결제 방법을 서비스단에서 나눴습니다.

클라이언트에서 Type 을 보내주면, Factory에서 해당하는 Type의 서비스를 결정하여 리턴해주고
컨트롤러에서는 주입받은 서비스를 통해서 상위타입인 인터페이스로 호출합니다.
각각의 Service layer에서는 Payment table과 각각 결제정보 table에 접근하는 방식입니다.

- Order <-> Payment 일대일 매핑
- PaymentService factory 생성
- PaymentService 공통 로직 추가
Comment on lines 15 to 16
public PaymentDto payForOrder(PaymentDto paymentDto, Long orderId) {
public Payment payForOrder(PaymentDto paymentDto, Long orderId) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

기존 주문관련 로직들이 DTO가아니라 Entity를 리턴하도록 코드 작성했는데,
이후에 한번에 은닉화 적용하기위해 임시적으로 Entity를 리턴하도록 했습니다~

@jjeda
Copy link
Collaborator Author

jjeda commented Dec 19, 2019

이번에 고민하는 부분은 각 결제 방법마다 다른종류의 정보들을 Client에서 어떻게 받아올지가 고민이었습니다.

시도해본 방법

  1. PaymentDto 를 추상화하여 다른 결제방법 dto들이 구현하도록하고 Service와 똑같이 factory를 통해 dto 를 결정하는방법
  2. @RequestBody로 받아오는 부분의 타입들을 각각의 결제방법으로 받아와서 메서드 오버라이딩으로 분기
  • 결제방법이 추가되면 Controller 안에 메서드가 추가됨 -> OCP 에 어긋나다고 생각
  • 이렇게 하지 않으려고 Service 부분 추상화 적용한거였는데..
  1. PaymentDto 에 결제방법에 쓰이는 모든 필드를 넣고 Type에 따라 다른 Entity로 변환해줌
  • 쓰이지 않는 필드값들이 NULL

위 3가지 정도 생각해봤는데 어떤게 적절한지, 다른 방법이 더 합리적인지 궁금합니다~

@f-lab-dev
Copy link
Member

일단 이쪽부분은 클래스 다이어그램으로 그려보시면 좋을 것 같습니다. 그것을 바탕으로 얘기해본 다음 최종 클래스다이어그램을 위키에 올려봐도 좋을 것 같고요,

요청마다 다른 응답을 내려주는 부분은 거기서도 상속을 이용해보시면 좋을 것 같습니다. 추상화를 해두면 클라이언트에 분기할 필요없이 그냥 내려줘도 됩니다. 어차피 JSON으로 변환되니까요~

- 각 결제수단 DTO 들이 PaymentDto 를 상속받게 변경
- CashPaymentService 결제 메서드 수정
- TODO : 공통 부분 추출
- 결제완료 메서드 -> OrderService 로 이동
- 각 결제별 핵심로직은 PaymentService 로 추상화
- Factory 로직을 분기 -> Map 으로 변경
- DTO 와 Adapter 로 책임 분리
- 결제완료에 대한 테스트 코드
- PaymentDto 관련 수정
- 결제완료에서 결제정보를 세터를통해 수정하도록 변경
.payment(paymentDto.toPaymentEntity())
.build();
}
public static PaymentDto toDto(CashPayment cashPayment) {
Copy link
Member

Choose a reason for hiding this comment

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

이거는 from이나 fromEntity가 낫지 않을까요? 사용할 때 모양이 PaymentDto.toDto()의 모양이 되는데 PaymentDto를 다시 Dto로 변환해주는 역할로 보일 수 있을 것 같습니다

break;
default:
throw new IllegalArgumentException();
public PaymentService getType(PaymentType paymentType) {
Copy link
Member

Choose a reason for hiding this comment

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

Type을 가져오는게 아니라 Service를 가져오는것이므로 이름을 적절하게 바꿔주면 좋을 것 같습니다~

/* 주문이 완료되면 아이템의 전체 재고에서 주문수량만큼 빼주어야한다. */
//TODO : N+1문제 -> 벌크호출
orderItems.forEach((orderItem) ->
itemService.decrementStock(orderItem.getItem().getId(), orderItem.getQuantity())
Copy link
Member

Choose a reason for hiding this comment

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

이것도 TODO로 두기보다는 이 이슈에서 바로 해결해주면 좋을 것 같습니다~ 블로그 포스팅거리도 될 것 같네요

[#39] 결제완료에 대한 테스트 코드추가
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants