[MarketBully] - 팀 프로젝트

김찬영·2020년 12월 27일
3

Project Complete

목록 보기
2/4
post-thumbnail

Marketkurly Clone


평소 외모에 관심이 많았던 나

대학생때부터 옷에 관심이 많았다. 20대 초반에 사진을 지금보면 해괴망측한 옷을 입은 나를 발견할 수있다. 그때 당시에는 그 옷들이 왜이렇게 이뻐보였을까?싶다. 그런걸 보면 어떤 것이든간에 모든지 유행이라는건 필연적으로 존재하는 거같다. 사이트도 마찬가지라 생각한다. 일반화시킬 수 없겠지만 요즘트랜드는 좀더 심플하고 사용자가 한눈에 파악할 수있는 컴포트한 사이트들이 대세인거 같다. 이마트나 스타벅스 그리고 마켓컬리도 흠잡을 때 없이 컴포트하며 심플하다. 하지만 심플하면서도 필요한 것들은 다 갖추어져있다. 만약 Front-End로서 교과서가 있다면 마켓컬리라고 생각했다. 물론 내가 이 사이트를 모두 이해하고 구현 할 수는 없겠지만, 기본개념을 다지기엔 정말 좋다고 느꼈다. 장바구니 기능은 단연컨데, 장바구니에만 쓰이는 것이아니라 생각한다. 그 기능으로 여러곳에 사용할 수 있다는 것이다. 외모에 대해 처음 관심이 생긴 나를 생각해 봤을때, 기본이라는 것은 필수 불가결이다.

마켓컬리에서 마켓불리로 가는 순간을 간직하다 🙏

본디 마켓컬리에서 kurly의 뜻을 찾아보면 '식문화의'라는 뜻의 영단어 'culinary'에서 시작되었다고 한다. 이 시대의 새로운 식문화를 선도하는 기업으로 나아가겠다는 의미이다. 우리는 거기서 간단한 아이디어를 냈다. bully라는 의미를 찾아보면 약한자를 괴롭히는 사람이라고 되어있다.
우리는 소비자가 그냥 지나칠 수없는 엄청난 매력을 지녀서 살수밖에 없게 만드는 선한? 강요성을 띄는 bully로 이름을 작명하게 되었다.

MarketBully

  • Clone website : Marketkurly
  • Project Period : 12.14 ~ 12.24 (11th)
  • Front-End : 한민아, 김찬영, 이장현, 박채훈
  • Back-End : 이현주, 이주형, 김원희
  • Demo Video
  • Github

Skill Stack

Front-End

  • HTML / CSS / Javascript
  • React(CRA)
  • Sass

Back-End

  • Python
  • Django
  • CORS Header
  • Bcrypt
  • PyJWT
  • MySQL
  • AqueryTool : 데이터베이스 모델링

협업 Tool

  • Git, Github
  • Slack : 비대면 소통
  • Trello : 일정관리 및 작업 현황 공유
  • Notion : 팀 내 개발 자료, 규칙, 안건 등 기록

구현한 기능

  • 회원가입 & 로그인

  • token 유지상태관리

  • Navbar 상품별 필터링 및 라우팅

  • 메인페이지 MD추천 구현

  • 제품목록페이지 상품목록나열 및 가격순 필터링

  • 제품 상세페이지 스크롤 이동 및 게시판 페이지네이션

  • 장바구니, 결제페이지 수량변경,삭제,선택삭제,전체선택 및 결제금액 계산

내가 담당한 기능

Header 및 전반적인 Main 페이지기능을 담당했다.

1. 로그인 토큰유지 및 삭제

  • 로그인을 하기전에 Header에 모습이다.

  • 로그인을 하고나서 (토큰을 받은 후) 해더부분이 변경됨을 알수 있다. 영상에는 나오지않지만, 마우스를 올렸을때 드롭다운이 생성되어 로그아웃버튼을 클릭하면 토큰을 삭제하고 다시 로그인 페이지로 이동하게된다.

Main 페이지

  • 화면을 내렸을때, Nav가 고정되도록 scrollTop함수를 이용하여 fixed
  • 메인배너와 추천 배너등 Slider기능이 많이들어가서 따로 Slider 폴터를 만들어 관리함
  • Slider는 Slick이란 라이브러리 적용

MD 추천

  • MD추천에서 메뉴탭 원리를 적용시켰으며, 백엔드에서 받은 Data를 이중으로 필터링
  • 소고기품목을 눌렀을때 소고기의 관련된 슬라이더만 필터링하게 구현
  • 그리고 이미지를 클릭하면 해당품목의 상세페이지로 라우팅

  • 이중드롭다운을 구현
  • 백엔드 데이터활용
  • 품목 누를시 해당품목으로 이동

셀프 칭찬 👍

1. 첫 협업 마인드 갖추기

첫 협업이라서 부족한점도 많았지만, 되도록 팀에게 피해가지않도록 맡은 기능들에 대해서는 될때까지 포기하지않고 구현했다. 특히 MD추천에서 필터링을 할때는 너무 힘들어서 멘탈관리를 열심히 했던거 같다. 그리고 우리팀은 너무 좋았던 점이 항상 서로를 챙겨주었던거 같다. 미팅시간도 철저하게 서로지키면서, 진지할땐 진지하면서도 점심시간이나 저녁시간에는 같이 먹으면서 수시로 서로에대해 관심을 가졌다. 걱정과달리 팀분위기가 화목하여 힘들어도 금방 이겨낼 수있었다.

2. 백엔드와 첫 만남

일전의, 위스타그램을 클론할때 로그인하여 토큰을 받는거 까지는 구현했었다. 하지만, 방대한 데이터들을 받아서 사용하는 것은 아직 낯설었다. 특히, json 형식이 내가 원하는 형태가아니라서 처음으로 난감했었다. 어떻게 내가 원하는 데이터들만 쏙 빼서 사용할 수 있을까 많이 고민했었다. 현업에서도 내가원하는 데이터형식만 올 수 없다고 생각한다. 그런점에서 많은 도움이 되었고, 추가적으로 json의 복잡한 형식다루기를 좀더 공부하도록 해야겠다고 느꼈다.

3. 선행학습과 적용하는 능력

사실, 내가 구현하는 대부분이 위코드 세션에서 나오는 내용들이다. 세션에서 배운 메뉴탭, 라우팅, 로그인토큰유지등 계속 선행학습과 복습을 통하여 내것으로 만들려고 노력했다. 앞서 만든 몬스터 프로젝트를 반복숙달하면서 이해하려고 노력했던점이 많은 도움이 되었다. 그래서 적용하는데 오랜시간이 걸리지않았고 적용하고 구현되었을때 너무기분이 좋았다. 리팩토링하여 완전히 내것으로 만들자!

아쉬운 점들 😓

1. 컨디션관리!

아무래도 왕복3시간이라는 점은 나에게 큰 부담으로 다가왔다. 다른분들도 멀리서 오셨지만 나는 이에대해 잘 적응하지 못했던거 같다. 개인적인 욕심이 많아서 새벽에 첫차타고 거의 막바지에 전철을 탔다. 빨리일어나고 늦게 일어나는 것을 반복하다보니 아무래도 피로가 금방 몰려왔고, 항상 피곤한상태였던거 같다. 그래서 진도도 많이 못나갔던거 같다. 정말정말 컨디션관리가 너무 중요하다는 것을 크게 깨달았다. 나는 슈퍼맨이 아님을 다시한번 느꼈고, 차라리 집중할때 200% 집중할 수 있도록 관리를 철저히 해야겠다!

2. 다른 역할을 맡은 기능들을 구현해보지 못한점!

사실 쇼핑몰을 하면 뺴놓을 수 없는 기능중 하나가 바로 장바구니 페이지, 결제페이지, 아이템리스트 및 디테일 페이지이다. 이러한 기능들은 다른 팀원들이 구현했지만 아직 나는 다 이해하지 못했다. 틈틈히 팀원들 코딩을 보면서 공부해 나갈 생각이지만 직접 구현해보지 못해서 아쉽다. 2차 프로젝트에서는 내가 직접 구현할 생각이다.

3. 좀더 잘할 수 있지 않았을까? 하는 아쉬움!

배우러 왔기때문에 개인역량이 부족한건 어쩔수 없는 부분이다. 하지만 스스로 해결하는 능력은 내가 추구하는 것중에 하나이다. 같은 팀원중 한분은 모르는 부분이 있어도 스스로 해결하는 능력이 좋으셨다. 모르는 부분이 있다면 논리적으로 현재 상황이 어떤 상황이고 왜 안되는지 그리고 내가 무엇을 더 공부해야 하는지에대해 계속 물으셨던거 같다. 마치 선생님같으셨다. 나 또한 그러한 점들을 본받아 항상 논리적인 사고방식을 갖고 문제를 어떻게 효율적으로 해결해 나갈지 항상 질문을 던지고 답을 찾을 생각이다.

4. Git Pull requests

코드를 작성하는데 급급하여, push 후, PR에 신경쓰지못했다. 어떻게보면 제일중요한게 회사에서는 내가한 일에대한 보고이다. 즉, 마무리까지 깔끔해야 일을 잘한다고 생각한다. 내가 어떤상황이므로 어떤걸 필요로하는지 나타내지않으면 상대방은 알 수가없다.

위에사진은 내가 아끼는 동료의 commit이다. PR은 아니지만 이렇게 체계적으로 작성하는 것에대해 다음프로젝트에선 좀더 신경쓰고 고민해봐야겠다.


기억에 꼭 저장하고싶은 코드!

1. Life Cycle로 접근하는 Login 로직

우선, Login 로직을 짤때, 제일중요한 부분은 Login 했을때 token이 localStorage에 있는지 확인해야한다.

componentDidMount(){
 localStorage.getItem("token") ? this.setState({isLogined : true}) 
 : this.setState({isLogined : false})

componentDidMount에서 랜더링 후에, 체크를 해준다. 하지만 이에 문제가 발생했다. 바로 새로고침을 해야 로그인 컴포넌트가 트루가 된다. 즉 Login 컴포넌트에서 업데이트가 되지않았다.

componentDidUpdate() {
  if(this.state.isLogined === false) {
       localStorage.getItem("token") ? 
       this.setState({isLogined : true}) : null
       }
       }

맨처음 isLogined 초기값이 false로 설정했다. 그랬을 경우, Login에서 Header로 넘어올때 localStorage의 토큰을 확인후, lsLogined를 true로 변경한다. 그러면 컴포넌트디드마운트의 무한루프로 걸리지않고도 랜더링전에 isLogined는 true가 된상태로 랜더링이 된다.

2. MD추천 이중 필터에서 이미지 클릭할때 동적라우팅 적용하기

첫번째 사진에서 이중필터링된 데이터의 각각의 id를 img태그의 부모인 div에 id를 설정한다. 그리고 onClick 함수를 사용하여 event를 사용하여 id를 ItemDetail/id 이렇게 사용하게된다.
현재 내가누르고 있는 이미지의 id와 ItemDetail에 있는 id가 동일하기떄문에 이미지를 눌렀을때 해당되는 ItemDetail 페이지로 이동하게 된다. 여기서 event.currentTarget을 사용한 이유는 이미지를 누르면 이미지에 해당되는 id가 전달되는데, 이는 undefined가 나온다. 그러므로 img가 아닌 현재 내가 클릭이벤트를 실행하는 곳의 id를 받아오고 싶을때 사용하게된다.

3. 이중 filtering

clickHandler = (currentId, name) => {
    const filteringSubCategoryName = this.state.data.filter(data => {
      return data.subcategory_name.includes(name);
    });

    this.setState({ filteringSubCategoryName, mode: true, currentId });
  };
  
  
  --render--
  const CATEGORY_Slide = [
      "돼지고기",
      "소고기",
      "양고기",
      "계란류",
      "닭, 오리고기",
      "양념육, 돈까스",
    ];

 const MAPPING_Slide = {
      1 : <MDRecommandSlide filteringSubCategoryName
      ={this.state.filteringSubCategoryName} />,
      }
      
      ---return---
      <div className="mdRcommandMenu">
          {CATEGORY_Slide?.map((name, index) => (
            <button
              key={index}
              class="mdRcommandBtn"
              onClick={() => this.clickHandler(index + 1, name)}
            >
              {name}
            </button>
          ))}
        </div>

 {this.state.SlideContainermode ? (
          <div className="RcommandSlideContainer">
          {MAPPING_Slide[currentId]} </div>
        ) : (
          <div className="RcommandSlideContainer">
            {" "}
            <InitialMDRecommand data={this.state.data} />{" "}
          </div>
        )}

카테고리슬라이드 배열을 맵함수를 사용하여 각버튼이 클릭될때 index +1, data를 넘겨준다. 여기서 index+1은
SlideContainermodermode가 트루일때 MAPPING_Slide 객체를 맵핑하기위한 currentId값이다. index는 0부터 시작하므로 객체의 key가 1이므로 시작점을 맞춰주었다. 그리고 두번째 인자인 data는 백엔드에서 받아온 data의 subcategory의 이름이 CATEGORY_Slide의 이름을 포함한 된 값들을 반환하는 filteringSubCategoryName배열을 만들었다. 그리고 filtering된 data를 MDRecommandSlide 컴포넌트에 props로 넘겨준다

    const { filteringSubCategoryName } = this.props;
    return (
      <div>
        <Slider {...settings}>
          {filteringSubCategoryName?.map(data => {
            return (
              <div key={data.id} id={data.id} className="MDRcommanCard" onClick={this.goToDetail}>
                <Link className="MDLink">
                  <img src={data.image_url} alt={data.subcategory_name}></img>
                </Link>
                <div className="recommand__desc">
                  <Link className="recommand__link">
                    <p>{data.name}</p>
                  </Link>
                  <span>{Math.floor(data.price).toLocaleString("en")}</span>
                  <span className="save">
                    {Math.floor(data.price - data.price * data.discount_percentage).toLocaleString(
                      "en"
                    )}
                  </span>
                </div>
              </div>
            );
          })}
        </Slider>
      </div>

props로 넘겨온 data를 사용하기위해 다시한번 map를 사용한다. 여기서 힘들었던점은 json 형식이 나에게 다소 어렵게 느껴졌다. 배열안에 객체안에 배열 .. 이렇게 이중, 삼중으로 짜여져있어서 접근하는게 쉽지않았지만 RUN.JS로 계속 연습한 결과가 빛을 바랬던거 같다.

4. git log --graph --online --all

이 기능은 git history를 체계적으로 볼 수있다. 이번 프로젝트에서 제일 힘든것중에 하나가 git 상태 관리였다. 이는 정리하고싶어서 간단하게 정리해보았다.

git clone후, 각자의 컴포넌트에서 작업수행 -> 작업완료후, 해당 브랜치에서 푸쉬 -> 푸쉬 후, PR작성 (라벨,현재상황정리) -> 리뷰받은 것, 수정해야할 것들 해당 브랜치에서 작업 -> 작업완료후, 머지하기 -> 로컬 마스터로 이동하여 리모트 마스터를 pull -> 해당 브랜치 이동후, master와 merge 실행 -> 컨플리트 유무 확인후, 있으면 해결하고 없으면 그대로 push -> PR 작성

이런 과정의 반복이었다. 여기서 git restore, git stash 등 많은 걸 배웠는데 이건 추후에 정리해야겠다.

마켓컬리 프로젝트 후기

시작부터 만만하지 않았다.

하필 프로젝트 기간때 코로나가 기승을 부려 2.5단계 이상으로 격상했다. 때문에 우린 위코드 건물을 사용할 수 없었고, 개인 팀마다 각자 공부할 터전을 구해야 했다. 그리하여 공유오피스에 세 팀이 입성하게 되었다. 하지만 공유오피스의 와이파이, 시설관리, 난방 추가비용, 창문없는 답답한 환경속..등 신경써야할 부분이 생각보다 많았다. 특히 밥을 먹는게 제일 힘들었던 거 같다. 매일 밥먹을때마다 어디서 먹어야할지 고민했다. 실내에서는 음식섭취가 금지되어있기 때문이다.

마켓컬리 너 나랑친해질래??

사실 마켓컬리 사이트는 이번에 처음 접하게 되었다. 아무래도 가족이랑 같이살다보니까 무엇을 시켜먹을일이 없는편이다. 그나마 아는사이트가 이마트정도였던거 같다. 마켓컬리를 분석하는 도중 마켓컬리의 취지를 알게되었다. 신속배달은 물론이고 친환경적인 부분에서도 꾀나 신경을 많이 쓰는것같다. 특히, 소비자 의견을 적극반영하는데 있어서 노력한다는 점이 마음에 들었다. 신기하게도 그 덕분인지 마켓컬리가 친숙하게 느껴졌고, 프로젝트 하는 기간동안 수십번 이상은 클릭했던거 같다.

그래도 우리는 달린다!

갖가지 안좋은 환경속에서도 우리는 쉼없이 달렸다. 특히, 우리팀원들에게 감사함을 전하고싶다. 시작이 반이라고 했던가. 우리팀원들은 첫날부터도 진지하게 임했고 레이아웃을 짜는데 몰입했다. 백엔드 또한 모델링 하는데 집중했다. 다른팀들은 첫날이라고 쉬엄쉬엄 하는 팀이 있었다고 한다.(다른팀을 비교하는 내용이아닙니다) 솔직히 나 또한 누군가가 이끌어주지 않았다면 첫날이니 가볍게 했을거같은 생각이든다. 만약에 그랬다면, 기능구현도 제대로 완성할 수 있었을까 싶다. 우리는 시작부터 좋은흐름을 계속 이어나가서 백엔드와 프론트 서로 맞춰나가면서 마지막까지도 수정을 반복했다. 그래서 더 좋은 결과를 이뤄낸거같다!

이제는 내가 주도하고싶은 마음이..! 🚀

프로젝트에 임할때 우리팀에는 잘하는 분이 계셨다. 그래서 나는 어딘가 모르게 안도했는지도 모른다. 모르는 것에대해서 물어볼 사람이 생겼다는 점. 그리고 든든하다는 점. 그게 나쁜건 아니지만, 그때는 의지하는 마음이 컸던거 같다. 끝나고나면 내가 더 주도적으로 할 수 있었던 부분이 있었는데 더 용기내볼껄 이라는 생각이 든다.
2차프로젝트에서는 비록 PM이 아니지만, 좀더 의견을 내고 적극적인 자세로 임할 생각이다. 그리고 그분한테 많은 것들을 배웠다. 그러한 점들을 적극 이용할 것이다.
마켓컬리 감사합니다. 2주동안 너무 행복했고 즐거웠어요!!

profile
Front-end Developer

2개의 댓글

comment-user-thumbnail
2020년 12월 28일

1차 플젝 너무 고생하셨습니다 찬영님! 매일 같이 누군가 붙잡고 열심히 질문하시던 찬영님 모습이 눈에 선하네요. 찬영님의 그런 탐구심, 그리고 거절에도 굴하지 않고 계속해서 물어보는 자세 진심으로 멋지다고 생각합니다. 앞으로도 계속 그런 멋진 모습으로 어떤 과제가 오던 차근차근 뿌셔 주세요~ ^-^ 👊 제가 찬영님 많이 응원합니다.

그리고 죽는 소리, 약한 소리는 좀 그만하셔두 될 것 같아요. 찬영님은 저랑 태현님이 인정한 남자니까요 ㅎ____ㅎ

1개의 답글