Wisely 클론 프로젝트 회고

HUYKSKEE·2022년 8월 27일
0
post-custom-banner

✨Wisely 클론 프로젝트✨

아쉬운점이 대부분이었던 Wisely 클론 프로젝트 회고를 적어보려한다. 팀단위의 프로젝트가 익숙하지 않다보니 나오는 실수나 아쉬움은 당연할지도 모른다. 그러나 프로젝트 시작전 또는 개발을 공부하고부터 나 자신이 가졌던 동기부여가 사라져 있었다는 아쉬움이 정말 크다. 결과에 너무 의존했던 자신을 반성하며 아래 회고를 적어내려가겠다.

🌈 클론 사이트 선정🌈

  • 생활용품 정기구독 및 구매 사이트 Wisely

❔ 선정이유 ❓

FE 측면 : 반응형 사이트, carousel, 아코디언, 데이터 가공 (평점별 별개수 핸들링,평점 반올림, 가격 쉼표추가 ) , 쿼리파라미터(페이지네이션, 오더링) 구현 가능
BE 측면 : 일반구매 및 정기구독 조건 구분, 상품 내부 옵션별 데이터 구성, 상품별 평점 계산 시 서브쿼리 사용, 쿼리파라미터(페이지네이션, 오더링), 로그인, 회원가입, 장바구니 담기 및 수량 조절 기능 구현 가능

🎫구현사항

내가 맡은거 ✋
아닌거 👉

  • Login & Sing Up
    👉 백엔드와 통신하면서 실시간 유효성 검사
    👉 유효성 검사 후 회원가입 실시
    👉 JWT 토큰 받아서 localStorage 저장
  • Main
    👉 carousel
    👉 카테고리 라우터
    👉 인기제품 리스트 멀티 carousel
  • Product List
    👉 품절 제품 disable
    👉 카테고리 별 상품 데이터 filter
    👉 데이터 정렬(높은 가격순, 낮은 가격순, 판매량순, 평점순)
  • Product Detail
    ✋ 상품 옵션 선택시 옵션 폼 생성
    ✋ 상품 옵션별 수량, 조절, 삭제
    ✋ 상품 정보 아코디언
    ✋ 장바구니 담기 POST
    ✋ 장바구니 담기 후 모달 생성
    ✋ 장바구니 라우터 (장바구니 이동 버튼 클릭 후 장바구니 이동)
    ✋ 리뷰 데이터 페이지네이션
    ✋ 평점별 게이지 bar
    ✋ Under Bar 스크롤 이벤트 (특정 영역 스크롤시 Under Bar 생성 제거)
  • Cart
    👉 상품 수량, 조절, 삭제
    👉 백엔드랑 통신후 실시간 재고 반영
    👉 정기 구독 주기 선택
    👉 포인트 결제

😎주요 구현 과정😎

🌲 브랜치...

  • 작은 기능 단위로 브랜치를 각각 판다음 개발이 진행되면 코드리뷰도 쉬워지고 그건 곳 머지가 빠르게 된다. 이런 git-flow방식이 처음이다 보니 세부적으로 더 나누지 못했던 아쉬움이 있다.

🎫 데이터 가공

Wisely 상품은 특정 상품에 옵션이 달려있어 한 상품에 대한 옵션 데이터를 추가로 받아와야 한다.

  • 데이터 형식
{
  "productDetail": [
    {
      "countRating": "7",
      "avgRating": "2.8571",
      "productId": 1,
      "imageId": 1,
      "options": "빨강",
      "optionImg": "url_빨강",
      "sales": 100,
      "stock": 0,
      "categoryId": 2,
      "productName": "피부에 좋은 세럼",
      "price": "50000",
      "description": "트러블을 효과적으로 케어하는 고기능성 세럼",
      "descImg": "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDdqPX%2FbtrJ0UidvT8%2FXkD6VbIi7XfBVwO8CB4DhK%2Fimg.png",
      "thumbImg": "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwYQjQ%2FbtrJ4FDRA64%2FsJ77YKRN8JmLDVaPlV1u7k%2Fimg.jpg"
    },
    {
      "countRating": "7",
      "avgRating": "2.8571",
      "productId": 1,
      "imageId": 2,
      "options": "건성",
      "optionImg": "url_건성",
      "sales": 100,
      "stock": 0,
      "categoryId": 2,
      "productName": "피부에 좋은 세럼",
      "price": "50000",
      "description": "트러블을 효과적으로 케어하는 고기능성 세럼",
      "descImg": "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDdqPX%2FbtrJ0UidvT8%2FXkD6VbIi7XfBVwO8CB4DhK%2Fimg.png",
      "thumbImg": "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwYQjQ%2FbtrJ4FDRA64%2FsJ77YKRN8JmLDVaPlV1u7k%2Fimg.jpg"
    },
    {
      "countRating": "7",
      "avgRating": "2.8571",
      "productId": 1,
      "imageId": 3,
      "options": "abcd",
      "optionImg": "www.wesley.com",
      "sales": 100,
      "stock": 0,
      "categoryId": 2,
      "productName": "피부에 좋은 세럼",
      "price": "50000",
      "description": "트러블을 효과적으로 케어하는 고기능성 세럼",
      "descImg": "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDdqPX%2FbtrJ0UidvT8%2FXkD6VbIi7XfBVwO8CB4DhK%2Fimg.png",
      "thumbImg": "https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwYQjQ%2FbtrJ4FDRA64%2FsJ77YKRN8JmLDVaPlV1u7k%2Fimg.jpg"
    }
  ],
  • 우선 최종적으로 한 상품의 옵션에 대한 데이터는 이렇게 받아오기로 정했다. 이전까지는 중간중간 데이터가 오는 형식이 바뀌어서 데이터를 할당하는 구조를 여러번 바꿔야 했던게 시간을 많이 잡아먹었다.

  • 이런 사태를 미연에 방지하려면 내가 할 페이지에 대해 어떤 데이터가 어떻게 필요하다 라는걸 미리 문서화 해놓으면 어느정도 해결이 가능할 것 같다.

🛒 옵션별 수량 정보

  • 옵션별 수량정보를 변수에 담아야 하는데 받아오는 데이터에 수량에대한 데이터는 없기에 새롭게 key, value를 객체에 추가하는 함수를 이용했다.
const selectObj = product.productDetail

setItem([
        ...item,
        Object.assign(selectObj, {
          quantity: 1,
        }),
  • 옵션 클릭시 옵션 폼 생성

  • 옵션 클릭시 selectedItem state에 저장
const selectItem = ({ target }) => {
    const selectObj = product.productDetail[Number(target.id)];
    if (!selectedItem.includes(selectObj)) {
      setSelectedItem([
        ...selectedItem,
        Object.assign(selectObj, {
          quantity: 1,
        }),
      ]);
    }
  • 수량과 imageId 각각 state에 저장
  const [totalCount, setTotalCount] = useState({
    total1: null,
    total2: null,
    total3: null,
    total4: null,
  });
  const [imageId, setImageId] = useState({
    imageId1: null,
    imageId2: null,
    imageId3: null,
    imageId4: null,
  });
  • 한 상품당 옵션은 최대 4개라는 가정에 이런 코드가 나왔다.
    이때당시 코드 구조를 너무 많이 바꿔서 지쳐있는 상태였고 리팩토링을 전혀 진행하지 않았던....
  • 일단 옵션이 4개라는 가정 말고 하나의 state에서 동적으로 담기도록 구성하면 어땠을까 하는 아쉬움이 있다.

🚴‍♂️기승전결..🚴‍♀️

간단하게 움짤을 보면서 처음~끝을 설명하겠다.

  • 시작

    이때만큼은 자신감과 의욕이 가득했다.
  • 중간


    에러에게 폭행당하기 시작 점점 예민해지고 말수가 줄어들었다.
    그러나 기분이 태도가 되면 안된다.


  • 진짜 눈이 이렇게 된다.
    익숙하지 않은 협업 방식, 처음 만난 팀원 그리고 부족했던 소통 탓에 고생을 사서했다. 그 결과 밤을 새서 작업해야하는 일이 생기고, 모두가 머리를 합쳐 해결해야하는 문제들도 생겼다.

👏좋았던 점👏

  • 각자 맡은 페이지가 결국에는 연결되어야 하는데 개발 중간에는 각자 어느정도 진행되었는지 직관적으로 알기가 쉽지않다. 이런 부분들을 미리 미리 스탠드업 미팅에서 공유할 수 있어서 다음 단계 구상이 쉬워졌다.
  • 백엔드와 소통은 정말 어려운 부분중에 하나였다. 쿼리문이 어떻게 구성되는지 잘 모르고 설명 해준다고 다 이해하는 것도 아니었기에 우리팀 백엔드분들은 그림 또는 예시를 인용해 알기 쉽게 설명해주었고 이런 방식의 대화가 자주 이루어지다보니 소통도 간단해지고 한가지를 설명하는 시간도 많이 줄어들었다. 이런 부분들을 문서화 한다면 더욱 더 좋은 시너지가 날 것 같다.

💊아쉬운 점💊

  • 아쉬운점 대부분을 차지하는건 소통이다.
    서로 어느부분이 어떻게 개발되는지 모르는 상황에 중요한건 우리는 이렇게 데이터를 만든다. 내가 프론트단에 전해 줄 데이터 형식은 이렇게 될 것 같다. 또는 프론트에서 내가 맡은 페이지에 어떤 데이터들이 필요하며, 데이터 형식은 이렇게 오면 정말 가공하기 쉬울 것 같다. 라는 식의 대화가 미리 이루어 졌다면, 개발 시간을 좀 더 효율적이게 알차게 분배할 수 있었을 것 같다.
    피그마같은 툴을 사용해 내가 맡은 페이지를 명시하고 데이터 형식을 정해둔 공용 문서를 만들면 좋을 것 같다.
  • 동기부여
    프로젝트 시작전에 다졌던 동기부여가 어느순간 사라져있는 나 자신을 보게 되었다.
    정신없이 기능 개발을 진행하고 프로젝트가 막바지에 다다랐을 때 코드를 보니 효율적이고 동적인 코드가 아닌 문제상황을 회피하기 위한 회피성 코드구조가 많았고, 결국 내가 쓰고있는 언어, 라이브러리들을 써서 얻을 수 있는 이점들을 살리지 못했다.
    특히 Sass같은경우 extend와 mixin을 전혀 사용하지 않고 반복되는 코드를 일일이 적었던 점에 많은 아쉬움이 생긴다.
profile
개가수(개발자 + 가수) 🙏개발자들의 공유 문화를 지향합니다.🤝
post-custom-banner

1개의 댓글

comment-user-thumbnail
2022년 8월 28일

소통 잘 하면서 2차 화이팅하시죠!

답글 달기