1차 프로젝트 회고 _ 이마트 PEACOCK 클론

Minji Jeong·2021년 10월 17일
1

Project

목록 보기
2/3
post-thumbnail

드디어 1차 프로젝트가 끝이났다!
물론 리팩토링 해야할 것들이 산더미이지만, 1차 프로젝트 기간으로 잡은 2주가
정말 쏜살같이 지나갔다. 내 삶에서 손에 꼽을 정도로 가장 바쁘고 알차게 보낸 2주였는데, 몸은 힘들었지만 정말 행복하고 보람찼던 것 같다.

MECOOK!

우리조가 클론할 사이트는 이마트 PEACOCK 사이트였다.
이마트에가면 PEACOCK 브랜드 제품을 별도로 파는데, 그 제품들에 대한 정보를 확인하고, 주문/배송을 할 수 있는 사이트였다.
레이아웃 짜는 것 보다 기능 구현과 통신에 좀 더 포커스를 맞추고 싶었는데,
이마트 PEACOCK 사이트는 레이아웃이 비교적 간단해서 좋았다.
PEACOCK를 조금 바꿔서 MECOOK이라는 이름으로 프로젝트를 시작했다!

기획에서 바뀐 점

프론트엔드 4명, 백엔드 2명이었다.
2주라는 짧은 시간 내에 프로젝트를 완성해야 했기 때문에
필수 기능을 구현하는데에 지장이 있을정도로 시간이 걸리는 서브 기능이나, 사이트에서 중요한 역할을 하지 않는 부분들은 과감히 빼기로 하였다.

로그인 및 회원가입

PEACOCK 사이트는 유저의 계정이 이마트 SSG 페이지와 연동되어있었다.
그래서 회원가입과 로그인은 사이트 자제적으로 하는 방식으로 변경하였다.

마이페이지

SSG과 연동되었기 때문에, 자체적인 마이페이지도 당연히 없었다.
초반에 사이트를 분석하는데,
Nav 바에 카테고리별로 상품을 보여주는 부분이 있는데 화면 사이드에서 튀어나오는 MARKET 태그를 열어보면 또 다른 카테고리별로 상품을 보여주는 부분이 있었다.

이 부분은 생략해도 될 것 같아서, 저 컴포넌트를 카테고리 리스트 대신
사용자 정보와 장바구니를 담는 마이페이지로 대체하기로 하였다!
별거 아니긴 한데, 아무리 생각해도 이 부분은 잘 기획한 것 같다 😎

일정 관리

이번 프로젝트에서 처음으로 팀장을 맡게 되었는데,
일정 관리와 파트 분배할 때에 가장 중요한 역할을 한 사람인 만큼 아쉬움이 많은 부분이었다.

Trello를 사용하여 각 팀원의 진행상황과 전체적인 진행상황을 체크했다.

아쉬운점

레이아웃을 최대한 빨리 구현해둔 다음에 기능을 완성하고, 통신을 완성해야 한다고 생각해서 계획을 맞춰서 짰고, 그러다보니 첫째주는 정말 빨리빨리 진도를 나가게 되었다. 이틀째만에 레이아웃을 다 완성하고, 5일 째에는 기능까지 거의 다 완성을 하게 되었다.

그런데 백엔드와 함께 하는 작업 이라는 것을 까마득히 잊는 전략이라는 것을 깨달았다. 통신이라는 작업은 백엔드와 프론트엔드가 함께 맞춰보고, 양 쪽 다 이상이 없을 때 완벽해지는 작업이다.

레이아웃과 기능을 아무리 빨리 끝냈어도, 2주차가 되서야 통신을 시작했더니 백엔드도 그때 그때 수정해야 할 사항들이 많아졌고, 통신이 안되다 보니 점점 프로젝트 속도가 늦어지기 시작한 것 같다.
결국은 밤을 새게 되었고, 겨우겨우 마감일에 맞춰서 급하게 프로젝트를 마무리하게 되었다.

매일 아침 회의록 작성!

고등학교 때 프로젝트를 해본 경험 때문에, 회의록의 중요성이나 문서의 중요성을 어느정도 알고 있는 편이었다.

회의록을 작성하는 이유는 매일 어떤 내용에 대해서 이야기 했고, 그 사항을 팀원 모두가 수시로 찾아보고 기억할 수 있도록 하기 위함이다. 회의 내용에 대해서 서로 기억하는 것이 다르면 곤란한 상황이 올 수도 있다 😂
그래서 매일 아침 회의 내용을 작성하여, Trello에 올려 모두가 수시로 확인 가능하도록 하였다!

API 주소 공유

프로젝트를 진행할 때 생성되는 문서는 정말 많다. 기획서부터 기능 명세서, API 명세서, 테스트 명세서 등...
문서를 적는 이유도 마찬가지로 프로젝트에 대한 내용들을 정확하게 명세해놓고, 그에 따라서 팀원들의 생각이 불일치 하여 발생하는 문제점을 최소화하기 위해서이다.

이번 프로젝트에서는 애자일 프로세스 방식을 사용하여 매일 아침 회의가 이루어졌다. 애자일 프로세스는 스크럼 단위를 짧게하여 자주 피드백 - 자주 수정을 거치는 방식이다. 따라서 문서화에 초점을 둘 필요는 없었다.

하지만 없으니까 불편한 것이 하나 있었다. 바로 API 명세서였다.
백엔드에서 API 주소를 변경하거나, 새로운 메서드가 하나씩 생길 때 마다
Slack 대화로만 전달하기에는 너무 불편하다는 생각이 들었다.
그래서 Trello 한 구석에 API 주소와 테스트할 토큰값 등을 공유해두었다.

기억에 남는 코드

Nav에는 DINING, CAFE, CUPBOARD 이렇게 3가지의 대분류 카테고리가 있다.
그리고 그 안에는 또 하위 카테고리가 있다.
모두 같은 형태의 component이지만, Nav에서 어떤 값을 선택했는지에 따라서 다른 카테고리들을 띄워주어야했다. 따라서 Product Category 컴포넌트에서 Nav에서 어떤 값을 눌렀는지 그 값을 알고 있어야 했다.

다양한 방법들이 있었다 (동적 라우팅 등)
그런데 동적 라우팅을 쓰기에는 대분류가 3가지 밖에 없어서 <Link></Link> 컴포넌트로 해결해도 될 것 같았다!
Link 객체의 속성인 to 값으로 경로만 넣을 수 있는게 아니라, 객체도 넣을 수 있었다. pathname에는 눌렀을 때 이동할 페이지의 경로를, state에는 해당 페이지로 넘길 데이터들을 적어줄 수 있었다. 따라서 Nav의 값인 categoryName을 state값으로 ProductCategory 컴포넌트로 넘겨주었고,
위처럼 this.props.location.state.넘겨준 props명으로 DINING인지, CAFE인지, CUPBOARD인지 받을 수 있었다.

카테고리별 상품 리스트 _ API 통신

카테고리별 상품 리스트를 불러오는 API 통신을 구현할 때,
로그인한 사용자와 로그인하지 않은 사용자에게 보여줄 내용을 구별해야했다.

헤더에 TOKEN 값을 포함해서 보내면 로그인한 유저가 볼 내용을,
TOKEN값을 포함하지 않고 그냥 보내면 비회원이 볼 내용을 보내주는 형식이었다.

if (localStorage.getItem('token') === null) {
        fetch(
          `https://f960-211-106-114-186.ngrok.io/product/menu/${this.props.listId}/navbar`,
          {
            method: 'GET',
          }
        )
          .then(res => res.json())
          .then(data => {
            this.setState({ productList: data.result });
          });
      } else {
        fetch(
          `https://f960-211-106-114-186.ngrok.io/product/menu/${this.props.listId}/navbar`,
          {
            method: 'GET',
            headers: {
              Authorization: localStorage.getItem('token'),
            },
          }
        )
          .then(res => res.json())
          .then(data => {
            this.setState({ productList: data.result });
          });
      }

이것이 처음 작성했던 코드였다. localStorage.getItem('token') 시 그 값이 null을 반환하면 로그인하지 않은 유저이므로 헤더 없이 통신하고, 그 반대일 경우에는 헤더를 포함해서 보내주는 것이었다.

아무리 생각해도 코드를 줄일 수 있을 것 같았다.
너무나도 명확하게 줄일 수 있는 코드라는 것이 보이고, spread 연산자에 조건을 붙이면 될 것 같았는데, 표현하는 형식이 헷갈려서 꽤 고민했었다.
그리고 줄인 결과! 다음처럼 줄일 수 있었다.

 const TOKEN = localStorage.getItem('token');
      
      fetch(
          `https://f960-211-106-114-186.ngrok.io/product/menu/${this.props.listId}/navbar`,
          {
            method: 'GET',
            ...(TOKEN && { headers: {
              'Content-type': 'application/json',
              Authorization: TOKEN,
            }}),
          }
        )
          .then(res => res.json())
          .then(data => {
            this.setState({ productList: data.result });
          });

카테고리별 상품 리스트 _ css

서로 다른 카테고리에 hover 할 때마다 background-image를 변경해주는 코드인데, 클래스를 바꿔서 다른 css를 적용해주는 방식을 쓰다보니

.background1 { background-image: url('../../assets/image/1.jpg')}
.background2 { background-image: url('../../assets/image/2.jpg')}
.background3 { background-image: url('../../assets/image/3.jpg')}

위의 코드와 같은 사태가 발생하였다... 카테고리만 10개인데 이걸 10개 다 나열할 수도 없고 방법은 모르겠고 정말 난감하였다 😥
그냥 저렇게 코드를 쓴다는 것 자체가 좀 자존심 상했다ㅎㅎ...

그러다가 Sass에 @each라는 명령어가 있다는 것을 알게 되었다.
@each는 클래스명 부분과 안에 들어가는 속성 부분을 변수를 대입하여 각각 적용할 수 있도록 하는 것이었다. js에서 for...in문 쓰는것과도 형태가 비슷해보였다.

$images: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;

@each $number in $images {
  .image#{$number} {
    background-image: url('../../assets/images/' + $number + '.jpg');
  }
}

코드가 이렇게나 간단해졌다...!

장바구니 체크 기능 구현

장바구니에 담은 상품들 중, 체크한 상품들의 가격을 계산하고 주문하는 기능을 개발하였다. 이 부분을 만들면서 가장 중요한 문제는 이것이었다.

각 상품을 check하면 원래 가지고 있는 값에서
반대(check일때 클릭하면 uncheck, uncheck일때 클릭하면 check)가 될텐데, 이 상품이 지금 check되어있는지 여부를 어떻게 확인하지?

모두 체크 기능을 생각하던, check된 item을 uncheck하던, check된 상품들만 주문을 하게 하던, 모든 방면에서 check된 item만 담고 있는 배열이 필요하다고 생각하였다. 그래야 모든 문제가 해결될 것 같았다.

그래서 state값으로 checkedItemList:[]라는 배열을 만들었고, 각 cartItem의 isChecked 여부는 이 checkedItemList에 포함되어 있는지에 따라 결정을 해주는 방식을 사용하였다.

이달의 베스트 메뉴 및 상품 검색 기능

그래서 앞으로 어떻게 할까?

이번 프로젝트를 통해 정말 많은 것을 배웠다.

  1. 백-프론트가 협업하는 과정과 서로에게 제공해야 하는 정보
  2. React로 기능을 구현하고 서버와 통신하는 방법
  3. 팀원들 간 소통의 중요성
  4. Trello 일정 관리의 중요성

소통의 중요성

특히 소통. 이번 프로젝트로 몸소 겪어보니, 개발하는 시간 60%, 대화하는 시간 40%인 것 같다.
생각보다 정말 대화를 많이 하였는데 대화 하는 시간이 늘어난다고 해서 개발이 그만큼 늦어지는 것이 아니라, 그만큼 개발의 방향을 잡을 수 있어서 꼭 필요한 과정이라는 생각이 들었다.

일정은?

2차 프로젝트 때는 프로젝트 초기에 레이아웃, 기능 구현에만 신경쓰지 말고 통신도 신경써서 나중에는 통신에 문제가 없도록 일정을 짜고 싶다.

Code Refactoring!

우선 작동하는 프로그램을 만들기 위해서 코드를 짜는 것도 정말 중요하다.
하지만, 그 코드를 내 것으로 만들고 더 효율적인 프로그램으로 만들기 위해서는
코드 리팩토링 과정이 꼭 필요하다고 생각한다.

마감일에 맞춰서 개발하다보니 엉망진창인 코드도 있다.
이런 코드들은 수정해서 외적으로 뿐만이 아니라, 내적으로도(코드도ㅎㅎ) 아름다운 프로그램을 만들고 싶다.

길고 긴 회고의 마무리!!!

정말 밤새가면서 열정적으로 한 프로젝트였는데 ...! 🔥
함께한 팀원들도 정말 좋았고, 열정적인 나의 텐션을 따라와주어서 정말 고마웠다.

처음 팀장을 맡아서 혹시나 프로젝트를 진행하는 과정에서 상처를 주진 않을지,
내가 프로젝트를 진행하는 과정에 불편함을 느끼진 않을지 매번 신경쓰게 됐던 것 같다. 부족한 점이 많이 보였을텐데, 믿고 따라와줘서 감사할 따름이다 🙇‍♀️

프로젝트 시연 영상
MECOOK GitHub

profile
쿼카를 사랑하는 프론트엔드 개발자입니다 :)

0개의 댓글