이 포스팅은 김영한님의 실전! 스프링 부트와 JPA활용 1
을 참고하여 작성되었습니다.
이번 포스팅에서는 우리가 만들 Commerce App의 요구사항 분석을 진행하고 이어 설계를 해보도록 하겠습니다.
요구사항 분석
우리가 만들어볼 App은 간단한 쇼핑몰
입니다. 각 기능별 요구사항을 알아보도록 하겠습니다.
1. 회원
- 회원 등록
- 회원 조회
- 로그인
2. 상품
- 상품 등록
- 상품 수정
- 상품 조회
* 상품은 재고관리가 필요합니다.
* 상품 종류에는 도서, 음반, 영화가 있습니다.
* 상품을 카테고리로 구분할 수 있습니다.
* 상품 주문시 배송 정보를 입력합니다.
3. 주문
- 상품 주문
- 상품 주문 취소
- 주문 내역 조회
도메인 모델
다음으로 해야할 일은, 요구사항을 토대로 도메인 모델을 도출하는 것입니다.
큰 그림을 먼저 본 뒤, 각각의 부분의 테이블 관계설정의 이유에 대해 설명드리는 것이 이해가 쉬울것 같아 설계 결과를 먼저 보여드립니다.
1. 회원과 주문
회원은 여러번의 주문이 가능하기 때문에, 1:N
관계를 가집니다.
2. 주문과 배송
각각의 주문에는 배송에 필요한 정보들이 필요하기 때문에, 주문과 배송은 1:1
관계를 가집니다.
3. 주문과 상품
주문과 상품은 약간은 생각이 필요합니다. 먼저, 각 주문은 여러개의 상품을 포함할 수 있고, 또 각 상품역시 여러 주문에 포함될수 있습니다. 때문에 주문과 상품의 관계는 N:N
입니다.
하지만 DB에서는 N:N 관계를 표현할 수 없기 때문에, 이들을 1:N , N:1
관계로 풀어서 표현해야 합니다. 추가적으로 이들 관계를 표현하기 위해 생성된 주문상품
테이블에는 상품수량
정보가 추가적으로 담깁니다. 상품수량의 경우, 주문테이블과 상품테이블
어느쪽에도 속할수 없기 때문입니다.
4. 상품과 도서, 음반, 영화
여러 종류의 상품이 존재하는데 이들은, 상품을 상속받도록 했습니다.
엔티티 설계
이어서, 도출해낸 도메인 모델을 토대로하여, 엔티티를 설계해보겠습니다. 마찬가지로 먼저 완성된 설계를 보고, 각각의 엔티티를 살펴보도록 하겠습니다.
- 화살표선은
단방향 연관관계
를 나타냅니다. - 실선은
양방향 연관관계
를 나타냅니다. - 안이 비어있는 화살표선은
상속 관계
를나타냅니다.
- 빨간색 테두리는
연관관계를 나타내는 필드
입니다.
1. 엔티티의 필드
우선은 각각의 엔티티에 포함된 필드들에 대해 알아보고, 이어 각엔티티들의 연관관계와 그 이유를 알아보도록 하겠습니다.
1.1 Member
id : db의 식별자로 사용됩니다.
name: 회원명을 나타냅니다.
address: 주소지를 나타냅니다. (Adress라는 별도의 밸류타입이 사용됩니다.)
1.2 Order
id: db의 식별자입니다.
*orderer: 주문자를 나타냅니다.
*orderItemList: 주문한 상품의 리스트를 나타냅니다.
*delivery: 배송정보를 나타냅니다.
orderDate: 주문한 시간을 나타냅니다.
orderStatus: 주문 상태를 나타냅니다. (OrderStatus라는 별도의 밸류타입이 사용됩니다.)
totalAmount: 각 item에 대한 주문 수량 * 가격
의 모든 합을 나타냅니다.(Money라는 밸류타입이 사용됩니다.)
1.3 Delivery
id: ..
address: 배송지 (Address 밸류 타입이 사용됩니다.)
deliveryStatus: 배송상태 (DeliveryStatus 밸류 타입이 사용됩니다.)
1.4 OrderItem
id: ..
item: 주문한 상품
order: orderItem이 속한 주문
orderQuantity: 각 Item 주문 수량
orderItemAmount: item의 주문수량에 따른 총액
1.5 Item
id: ..
name: 상품명
price: 상품의 가격
stockQuantity: 상품의 재고량
categoryList: item이 속한 카테고리 리스트
2. 엔티티 연관관계
2.1 Member와 Order
Member와 Order간의 관계는 주문에서 회원을 참조하는 단방향 연관관계
입니다. Member가 주문을 하기 때문에, Member에서 Order를 참조해야할 것 같지만, 그렇지 않습니다. 이유는 다음과 같습니다.
- Order는 Member에 포함된 필드가 아닌, 별도의 엔티티입니다. 따라서, 각각의 Order에서 주문자를 찾기위해 Member를 참조하면 됩니다.
- Member가 주문한 Order 목록을 가져올 때에도, Order 입장에서 Member의 식별자를 조건으로하여 검색을 하면 됩니다.
x*연관관계를 최소화 하자 !!
되도록이면 필요없는 연관관계는 줄이는 것이 좋습니다. Member와 Order역시 양방향 연관관계를 맺는다면, 프로그래밍시 양쪽으로 트래버스가 가능하기 때문에, 개발의 편의성은 있지만, 유지보수가 어려워집니다.
예를들어, Member에서 Order로 참조가 가능하다면, Member관련 메소드에서, Order관련 오퍼레이션을 동작하기 때문에 Member가 Order에 의존성이 생깁니다. 이 때문에 Order관련 오퍼레이션을 변경할때 이를 사용한 Member의 메소드에도 영향이 미칩니다.
2.2 Order와 Delivery
Order에서 Delivery로의 단방향 연관관계
를 맺습니다.
- 주문정보를 조회할때, 배송정보가 필요하기 때문입니다.
- 배송정보를 조회하고 조회한 배송정보에서 주문정보를 알아낼 필요가 없습니다.
2.3 Order와 OrderItem과 Item
Order에서 OrderItem을 참조하는 단방향 연관관계
이며, OrderItem에서 Item을 참조하는 단방향 연관관계
입니다.
- 주문정보를 조회했을 때, 각각의 주문한 상품에대한 정보를 조회합니다.
- 반대로 주문정보에 포함된 각 주문상품을 먼저 조회한뒤, 주문상품이 포함된 주문을 조회할 일이 없습니다.