안녕하세요! delay100입니다. 오랜만이에요!
지난 한 달 동안 글을 올리지 못했는데, 그동안 새로운 프로젝트를 시작해서 깊이 몰두하고 있었습니다. 기존에 제가 했던 프로젝트들은 주로 CRUD 위주였지만, 이번에는 CRUD를 넘어서 다양한 요소들을 도입해보았습니다. 물론, 각 요소가 왜 필요한지 깊이 고민하고 신중하게 반영하려 노력했습니다. 항상 풀스택 개발을 하다 보니 백엔드의 다양한 스택을 많이 사용해보지 못했는데, 이번 기회에 이를 경험해보고자 했습니다.
특히, Redisson을 도입했다가 성능 개선 과정에서 Redisson을 사용하지 않는 것이 더 좋은 성능을 낼 수 있다는 것을 알게 되어 아쉽지만 제거하는 상황도 있었습니다. 이와 관련된 자세한 내용은 재고 관리 부분에서 이야기해보겠습니다.
앞으로 개발하면서 개인 Notion에 간단하게 정리해둔 내용들을 다듬어서 1일 1포스팅으로 공유할 예정입니다!
프로젝트 간단 소개
- 주제: e-commerce 쇼핑몰 프로젝트
- 목표: e-commerce에 필요한 기본 기능인 회원, 상품, 주문, 장바구니 등을 만들되, 하나의 기능을 만들 때 고민을 많이 해볼 것
- 기간: 2024.06.19 ~ 2024.07.16 (1개월)
- 인원: 1인(백엔드, Springboot)
- 기술스택: Springboot, Mysql, SpringSecurity, JWT, AWS S3, Redis, Docker, Git Action(CI), SMPT, JMeter
ReadMe.md에 추가로 상세하게 정리해두겠습니다.
개발 인스타그램: https://www.instagram.com/p/C9gdq_NBvBT/?igsh=bG1rMWpyM2VicDl6
블로그에 적으려면 시간이 오래 걸리기 때문에, 특정 개발 시점에 가장 중요시 여겼던 부분을 잊지 않기 위해 기록해두었습니다.
ERD 작성
여러 버전이 있는 이유는, 단기간에 1인 개발을 하면서 계속 수정/추가 내용이 생겨서, ERD를 계속 업데이트 할 수 밖에 없었습니다.
1. 왜 MySQL을 선택했냐면요..
- 데이터 일관성과 무결성: MySQL은 ACID 트랜잭션을 지원해서 주문이나 결제 같은 중요한 트랜잭션의 일관성과 무결성을 보장해줍니다. e커머스에선 필수적이라고 생각했습니다.
- 복잡한 쿼리 처리: MySQL은 조인과 서브쿼리를 잘 처리해줘서 회원, 주문, 상품 간의 복잡한 관계를 쉽게 관리할 수 있습니다. 반면, MongoDB는 이런 복잡한 트랜잭션과 조인에 약할 수 있습니다.
- 명확한 데이터 구조: e커머스 데이터는 대부분 정형화된 스키마를 따르기 때문에 MySQL의 관계형 데이터베이스 구조가 딱 맞았습니다. 데이터 무결성과 명확한 구조를 보장할 수 있다는 장점을 가지고 있습니다.
- 역사깊은 MySQL: MySQL은 오랫동안 많이 사용되어 왔고, 문서와 커뮤니티 지원이 많아서 문제 해결이 쉽습니다. 개발하고 유지보수하기도 편리합니다.
- 성능 최적화 유리: MySQL은 인덱스와 최적화 기법이 잘 되어 있어서 검색 같은 읽기 작업이 많은 e커머스 환경에 딱 좋다고 판단했습니다.
그럼 MongoDB는?
MongoDB는 대규모 데이터 처리와 유연한 스키마 설계에서 장점을 가지고 있지만, 데이터 일관성 보장과 복잡한 쿼리 처리에서는 MySQL만큼 강력하지 않습니다. 특히 e커머스 환경에서는 데이터의 일관성과 정확성이 중요해서 MySQL이 더 적합하다고 생각했습니다.
2. Version1
프로젝트를 시작하고 가장 처음으로 작성한 ERD입니다. 이때 생각한게 가장 기본적인 이커머스를 만들려고 했습니다.
회원 - 주문 - 상품이 가장 기본이 되는 테이블이라고 생각을 했습니다. 그리고 e-commerce 도메인에 대해 구체적으로 알지 못했기 때문에, 위와같이 가장 간단한 기준으로 작성을 하려고 했습니다.
[이 시점의 생각]
1차 erd 작성을 끝냈다.
아마도 수정할 부분이 엄청 많을 듯 싶다.
- 특히나 주문상품 테이블을 저렇게 설계하는게 맞는지 고민중이다.
사용자가 주문 1개당 n개의 상품을 넣을 수 있는데 이 n개의 상품에 대해서 나타내려면 주문 상품 테이블이 필요하다고 생각했다. 우선은 이렇게 진행해보고 추후에 변경할 듯 싶다!
- 그리고 유저 admin 기능은 당장에 구현하지 않을 것 같은데 확장성을 위해 우선 넣어두려 한다.
- 우선 e-commerce 기본에 충실해서 하려고 한다!!!
이후에 간단하게 작성한 ERD에 수정사항을 발견하고 반영했습니다. 아래의 내용은 반영한 내용입니다.
- Timestamp는 백엔드에서 코드로 자동으로 넣어줄텐데, NULL이 아니라 NOT NULL로 명시하는게 더 낫다. DB는 최소한의 Nullable할 것.
- Springboot에서 인가처리를 할 때 SpringSecurity를 이용할건데, User는 기본 변수와 겹쳐서 헷갈릴 수 있다. Member로 변경!
- 상품 주문 시, 회원과 상품 수신자의 정보가 다를 수 있다. 해당 컬럼 등(결제방식, 배송액, ..등) 추가할 것
3. Version2-1(상품 관련)
굉장히 복잡한 상품 관련 ERD가 탄생했었습니다. 지금보니 네이밍도 그렇고 잘 파악하기 힘들어 보이네요..
사실 이 테이블을 만들 때 대표적인 e-commerce인 쿠팡의 url을 막 뒤져보면서 .. 삽질을 했었는데, 그래서 이런 여러개의 테이블이 나왔던 것 같습니다..
이 시점에서 생각했던 상품 테이블 관계는 아래와 같습니다.
상품 테이블 관계
- product: 테이블은 모든 상품 정보를 저장합니다.
- product_option: 테이블은 상품 옵션 유형을 저장합니다.
- product_option_value: 테이블은 각 옵션 유형의 값을 저장합니다.
- product_variant: 테이블은 각 상품의 변형을 저장하며, 각각의 변형은 가격과 재고 정보를 포함합니다.
- product_option_variant: 테이블은 각 변형이 어떤 옵션 값을 가지는지를 정의합니다.
즉, 여기서는 상품 옵션에 대해 2차 depth를 가지고 싶어했었습니다. 그걸 상품 옵션, 상품 변형으로 구현하려고 했었지요,,
1차 depth(상품 옵션) - 사용자가 정의하는 대분류
2차 depth(상품 변형) - 사용자가 정의하는 소분류
지금와서 생각해보니 하나의 테이블을 두고 자기 자신을 참조하는 foreign key를 두어 구현하면 됐을 것 같아요! (현재는 다른 테이블 구조를 갖게 되었지만요)
[이 시점의 생각] -> 너무 복잡하게 생각했던 과거의 나.. 주저리주저리입니다
~이전까지도 생각~
뭔가 다른 상품들이 나온다. 흠.. item을 분류하는 값이 products뒤의 id기도 하고 itemId기도 한 것 같다.. 왜 이렇게 됐을까???? 잘 이해가 가지 않으므로… 나는 이렇게까지 분류는 필요 없을 듯 하니..
productsId - 상품 분류
itemId - 상품 상세
이렇게만 가져가야겠다. 테이블이 쿠팡만큼 복잡해지면 관리도 쉽지 않을거같다.
이렇게까지 1시간 넘게를 투자했는데…ㅋㅋㅋ다시 처음 생각한 원점으로 돌아왔다.
결국 상품의 큰 분류 테이블을 만들고, 해당 id로 묶인 상세 테이블 가져가는 방식.
이제 결국 상세 테이블에서 어떻게 분류할 것인가?에 대한 고민으로 다시 돌아왔다.
products를 product로 하기엔 너무 헷갈리는뎅 products 테이블이랑 item테이블로 db컬럼을 가져가야겠다
item에 대한 상세가 있는 경우에만 옵션에 또 적는걸로,
예를들어, 코튼수건을 팔려고 할 때,
코튼 수건 자체가 products임
item은 컬럼에 옵션id, 옵션명, 옵션상세id, 옵션상세명 , 묶음개수, 묶음가격, 남은수량이 들어가있다.
*남은 수량은 사용자에게 노출되고 있지 않은 남은 총 수량이다.
예를들어 저 코튼 수건을 예로 들면
item에
1, 색상, 1, 그레이 null, 5개, 22900, 1100
1, 사이즈, 1, 150x180 null, 5개, 22900, 1100
사용자가 추가할 수 있는 옵션 테이블을 하나 더 만들어야하나??싶음 …
기본값은 해당 리스트를 가져왔을 때 가장 상단에 있는 것으로 하면 될거같다. limit 1걸어서??
이미지는 공통적으로 보여줄 이미지는 상품에 저장하고, 개별적으로 눌러서 보여줄거는 상품 상세에 저장.
여기까지 생각하고 카카오톡 선물하기의 위시리스트를 확인해보았는데,,,,,
위시리스트는 또 개별 상품 상세에 대한 정보는 딱히 없다.
즉, 위시리스트는 상품이긴하나 상세 상품이 아니라 상세 상품을 선택할 수 있는 전체 폼을 보여준다.
4. Version2-2(위시리스트, 상품 상세 추가)
다음으로, 이 ERD를 만들었을때 하고있던 생각은 상품의 가장 작은 단위로 상품상세를 가져가야겠다는 것이었습니다.
그런데 만들고 나니 가독성이 떨어지고 쓸데없는 순환참조가 발생할 수 있을 것 같다고 생각했습니다.
또한 상품을 상품 상세로 나눈 의미가 없는 느낌도 들었습니다.
[이 시점의 생각]
일단 현재까지 erd는 이러한데 …구조가 구리다,,, 왜자꾸 circle형이 되는거지 !?!?
상품 상세랑 상품이랑 나눌 이유가 없어진다….이러면….
5. Version3
결국 상품 옵션을 상품에만 종속되게 변경하고, 리뷰테이블, 이미지 테이블을 추가했습니다.
이미지 테이블에 관계가 없는 이유는 회원 프로필 이미지로 해당 테이블을 사용할수도 있고, 상품의 이미지로도 사용할 수도 있을 것 같아서 연관관계를 맺고 싶지 않았습니다.
그리고 버전1에서 수정사항으로 언급되었던 주문 테이블에 컬럼들이 잔뜩 추가된 것을 볼 수 있습니다!
6. Version4(현재 최종)
1. 이미지 테이블
이미지 테이블에 "이미지 테이블, 이미지 테이블 ID"이 있는 이유는 새로 앞에서 잠깐 언급했듯 여러 테이블에서 사용하기 위함입니다.
ex)
이미지테이블 - Member, Product
이미지테이블 ID - 1, 2, 3, 4 등.. 이미지테이블(Member, Product 등)에서 사용되는 pk(id)
2. 상품 옵션 테이블
상품 재고 - 상품 옵션 테이블
기존에는 상품 테이블(모든 옵션의 재고 합), 상품 옵션 테이블(단일 재고)에서 이중으로 재고를 관리했는데 데이터를 이중으로 관리하는게 이슈가 발생할 수 있다고 생각했습니다.
상품 가격 - 상품 테이블, 상품 옵션 테이블에서 관리
상품 재고는 상품 옵션 테이블에서 관리됩니다. 기존에는 상품 테이블에서 모든 옵션의 재고 합을, 상품 옵션 테이블에서 단일 재고를 관리했는데, 이렇게 데이터를 이중으로 관리하는 방식은 이슈가 발생할 수 있다고 생각했습니다.
상품 가격은 상품 테이블과 상품 옵션 테이블에서 관리됩니다. 상품 가격을 두 테이블에 나눠둔 이유는 기본 가격이 있는 상품에 옵션에 따른 추가 금액을 반영하기 위함입니다.
어쩌다보니 버전이 5까지 변화되었네요,, 처음에는 이렇게까지 추가될지 몰랐는데 참 뿌듯합니다.. 그치만 앞으로 개발하면서도 ERD가 변경되지 않을까 싶습니다.
1달동안 애정을 가지고 만든 만큼 할 이야기가 정말 많습니다.. 고민한 부분들을 열심히 정리해보겠습니다..! 그리고 e-commerce를 개발하시는 분들중에 저와 같은 고민을 하고 계시는 분들께도 도움이 되었으면 좋겠습니다!
'Study > SpringBoot' 카테고리의 다른 글
[e-commerce 프로젝트] 4. 마이페이지 정보 업데이트 (4) | 2024.07.25 |
---|---|
[e-commerce 프로젝트] 3. 로그인(SpringSecurity + JWT 로그인 및 인가) (7) | 2024.07.24 |
[e-commerce 프로젝트] 2. 회원가입(네이버 이메일 인증, 개인정보·비밀번호 암호화) (6) | 2024.07.24 |
[SpringBoot] 따라하면 만들어지는 메모장 + AWS 배포까지 (1) (0) | 2024.05.22 |
[SpringBoot] Spring프로젝트 Postman에서 확인하기 (0) | 2024.05.13 |