위코드 1차 팀 프로젝트 'HealthEat' 회고

2022. 11. 27. 16:42·✪ 취미, 경험 회고 및 일상/[회고] IT 관련 경험 회고
반응형

프로젝트 소개

  • '피리마켓' '필리' 사이트를 모델링 한 프로젝트로, 약과 건강식품을 판매하는 커머스 사이트를 백지 상태에서 구현하였다.
  • 건강을 먹다는 의미로 사이트의 이름을 'HealthEat(헬스잇)'으로 지었다.
  • 기간 : 2022.11.14 ~ 2022.11.25
  • ➡️ 프로젝트 깃허브 레포지토리 바로가기
  • ➡️ 프로젝트 노션 페이지 바로가기

 

팀 소개

  • 프론트엔드 3명
    • 우석민 : Nav 바, 스토어 페이지 구현
    • 이상윤(나) : 메인 페이지, 상품 상세 페이지 구현
    • 이혜원 : 로그인 페이지, 회원가입 페이지 구현
  • 백엔드 2명
    • 이은영 : 찜하기 기능 구현
    • 조상원(PM) : 로그인, 제품조회 기능 구현

 

 

개발 도구 및 적용 기술 (+트렐로)

  • 프론트엔드
    • JavaScript(ES6)
    • React.js
    • Sass
    • React-router-dom
    • Fontawesome
  • 백엔드
    • JavaScript(ES6)
    • Node.js
    • Express
    • JSON Web TOKEN
    • Bcrypt
    • My SQL
    • Multer
  • 커뮤니케이션 및 버전 관리
    • Slack
    • Trello
    • Postman
    • Git / Github

 

작업 결과 (시연 영상)

 

 

백엔드 DB 모델링 및 END POINT

 

 

나의 작업 (내 구현 사항)

메인 페이지의 화면 슬라이더 구현

// PromotionSlide.js

// ... import 코드 생략

const PromotionSlide = () => {
  const [currentSlide, setCurrentSlide] = useState(0);
  const [sliderData, setSliderData] = useState([]);
  const slideLength = sliderData.length;

  // ... 데이터를 받아오는 코드 생략

  useEffect(() => {
    setCurrentSlide(0);
  }, []);

  // 5.5초 간격으로 다음 사진 슬라이드를 불러오는 auto 함수
  const auto = () => {
    slideInterval = setInterval(nextSlide, intervalTime);
  };

  let slideInterval = null;
  let intervalTime = 5500;

  useEffect(() => {
    auto();
    return () => clearInterval(slideInterval);
  }, [auto, currentSlide, slideInterval]);

  // 다음 사진 슬라이드로 넘어가는 함수
  const nextSlide = () => {
    setCurrentSlide((currentSlide + 1) % slideLength);
  };

  // 이전 사진 슬라이드로 넘어가는 함수
  const prevSlide = () => {
    setCurrentSlide((currentSlide - 1 + slideLength) % slideLength);
  };

  return (
    <article className="promotion-slide">
      {sliderData.map((slide, index) => {
        return (
          <div
            className={index === currentSlide ? 'slide current' : 'slide'}
            key={index}
          >
            {index === currentSlide && <img src={slide.image} alt="slide" />}
          </div>
        );
      })}
      
    // ...
    // 생략
    // ...
      
    </article>
  );
};

export default PromotionSlide;

 

 

 

메인 페이지의 카테고리 리스트 구현 및 각 항목에 알맞은 제품을 표시할 수 있도록 스토어 페이지로 연결

// MenuList.js

// ... import 코드 및 상수 데이터 코드 생략

const MenuList = () => {
  return (
    <article className="menu-list">
      <div className="menu-list-title">
        <span className="menu-list-title-name">고민별 상품 보기</span>
      </div>
      <div className="menu-list-items">
        {MENU_LIST_DATAS.map((data, idx) => (
          <ListItem key={idx} menuListDatas={data} />
        ))}
      </div>
    </article>
  );
};

export default MenuList;
// ListItem.js

import React from 'react';
import { useNavigate } from 'react-router-dom';

const ListItem = ({ menuListDatas }) => {
  const { category, name, image } = menuListDatas;
  const navigate = useNavigate();

  return (
    <div className="menu-list-each-item">
      <div
        className="menu-icon"
        onClick={() => {
          if (category >= 1 && category <= 4)
            navigate(`/store?category=${category}`);
        }}
      >
        <img src={image} />
      </div>
      <p className="menu-name">{name}</p>
    </div>
  );
};

export default ListItem;

 

 

 

백엔드에서 제품의 상세 데이터를 받아 상품 디테일 페이지에 표시 + 구매 수량에 맞춰 상품 가격 변경

// 구매 수량에 맞춰 상품 가격이 변하도록 구현한 코드

// BuyBar.js

// ... import 코드 생략

const BuyBar = ({ productID, productData }) => {
  const [quantity, setQuantity] = useState(1);
  const [totalPrice, setTotalPrice] = useState(0);
  const navigate = useNavigate();

  const { name, information, brand_name, price, discount_rate } = productData;

  useEffect(() => {
    setTotalPrice(parseInt(price) * quantity);
  }, [price, quantity]);

  // 조건부 랜더링
  // : 첫 랜더링 시 (랜더링 이후 실행되는) useEffect의 특성으로 인해 백엔드로부터 데이터가 수신되지 않으므로
  // 작성한 코드이다. 
  if (totalPrice === 0) return null;

  const plusQuantity = () => {
    setQuantity(prev => prev + 1);
  };

  const minusQuantity = () => {
    // quantity(구매 수량)가 0 이하로 내려가지 않도록 작성한 방어 코드 
    if (quantity >= 2) {
      setQuantity(prev => prev - 1);
    }
  };

  return (
    <>
      
      // .. 생략
      
        <div className="product-price">
          <span className="price discounted-price">
            {`${Math.round(totalPrice * (1 - discount_rate)).toLocaleString(
              'ko-KR'
            )}원`}
          </span>
          <span className="price fixed-price">
            {`${Math.round(totalPrice * 1).toLocaleString('ko-KR')}원`}
          </span>
          <span className="price discount-rate">{`${
            discount_rate * 100
          }%`}</span>
        </div>
        
      // .. 생략

    </>
  );
};

export default BuyBar;

 

 

프로젝트 후기 및 느낀 점

첫 팀 프로젝트를 통해 배웠던 것들

  • 브랜치를 생성해서 서로 작업하는 도중 초기 세팅을 수정해야 할 일이 생겼을 때 해결 방법
    • 다른 팀원에게 영향이 가는 수정 사항일 경우 새로운 브랜치를 생성하여 수정 사항을 반영한다.
    • 다른 팀원에게 영향이 가지 않는 수정사항일 경우 자신이 작업하고 있던 브랜치에 수정 사항을 반영한다.
  • 브랜치에서 다른 브랜치로 이동하고자 할 때, 현재 브랜치의 작업 내역을 모두 커밋한 후 이동해야 작업 내역이 꼬이지 않는다.

 

  • 브랜치 이름 작성 방식
    • 보통 branch명은 camelCase로 작성한다.
    • 예시 : feature/productDetail
  •  브랜치 기능 별 라벨 명
    • feature : 기능 구현할 때
    • develop : 여러 기능을 합쳐서 테스트할 때
    • release : 배포 전 최종 테스트할 때
    • hotfix : 배포 후 급하게 버그를 수정할 때

 

  • 팀 내 컨벤션은 미리 정해두는 것이 좋다. 
    • (예시) Git Branch 이름은 컴포넌트 이름과 동일하게 짓되, camelCase로 작성합니다.
    • (예시) CSS 클래스 이름은 kebab-case 방식으로 작성한다. 이름은 자유롭게 짓되, 이름을 보고 그것이 어떤 태그를 가리키는 지 파악할 수 있는 이름으로 작성합니다.
  • Daily Standup Meeting의 목적과 잘하는 법
    • 기한 내에 제품을 개발할 수 있도록 생산성을 높이기 위해서 Daily Standup Meeting을 진행한다.
    • 최대한 짧고 간결하게, 내가 한 것, 앞으로 해야할 것, 현재 막힌 부분 (문제 사항) 서로 공유하기
    • 미리 준비해오기

 

잘했던 점

  1. 팀원 모두가 서로에 대한 배려와 존중을 기반으로 상대방의 의견을 잘 들어주고 소통한 점
  2. 상황과 상관없이 함께 목표를 달성하겠다는 의지를 보여준 점
  3. 프로젝트를 진행하며 Notion, Figma 등 필요한 도구들을 바로바로 적용한 점
  4. 백엔드와 프론트엔드끼리 서로의 지식을 공유하고 배우려 한 점

 

아쉬웠던 점

  1. 스프린트 때 자세하게 티켓을 나누지 못한 점 (티켓의 내용을 세분화를 하지못하고 스토어, 상세페이지 등 크게 파트만 나누었다)
  2. 각자 자신의 업무에 몰입하느라, 모르고 어려운 것들(blocker)에 대해 팀원들과 공유하고 질문하는 것이 잘 되지 않았던 점
  3. 팀원 중 코로나 환자가 발생하여 온라인으로 미팅을 진행해야 했던 경우 서로 소통의 어려움이 있었던 점 (예: 온라인 참여자의 존재를 잠시 잊어버리고 오프라인 참여자들끼리만 대화를 이어나갔던 점)
  4. BE와 FE가 너무 분리되어 진행되다 보니 파트별 진행 상황을 서로 잘 알지 못했던 점
  5. 스프린트를 정보 공유의 목적으로만 진행해서 시간관리가 잘 되지 않았던 점
  6. 시간 관리를 위해 공통된 목적에 대한 데드라인을 정하지 않았던 점
  7. Fontawesome 같은 외부 라이브러리의 사용을 팀원들에게 깜박하고 미리 말하지 않은 채 내 클라이언트에만 설치하여 사용했던 점 (나중에 서로의 작업물을 main 브랜치에 merge하여 테스트를 진행할 때 충돌이 발생했다)
  8. 브랜치명, 클래스명, 변수명 컨번션을 미리 정하지 못하고 프로젝트 도중 정해 팀원들과 잘 공유되지 못했던 점

 

다음 프로젝트 때 개선할 포인트

  1. 스프린트 회의 때 시간이 좀 걸리더라도 최대한 자세하게 티켓을 세분화하여 전체적인 큰 그림을 모든 팀원들이 잘 이해한 상태로 프로젝트를 진행할 수 있게끔 하자.
  2. blocker들을 기록하고, 그 blocker에 대한 데드라인을 정해 프로젝트가 일정에 맞게 진행될 수 있도록 하자.
  3. 정확한 시간대를 정하여 프로젝트 진행하자.
  4. 개개인의 체력 및 컨디션 관리. 영양제도 좋지만, 기초 체력은 운동에서 나온다!
  5. 첫 번째 미팅 때 기획을 최대한 세분화해서 명확하게 잡아야 한다! (BE & PE 파트너를 정해서 하나의 기능 구현을 같이 진행하는 것도 좋은 방법)
  6. PM은 역할을 제대로 파악하여 계획한 일정들이 미뤄지지 않도록 힘써야한다.
  7. 팀원 각자 책임감을 갖고 서로 도울 수 있는 부분을 생각해보자.
  8. 데이터 형태를 어떻게 보내고 받을건지 → ERD를 함께 만들어보면 좋을 것 같다.
  9. 구글 드라이브 또는 노션에 필요한 데이터, 이미지등을 정리하는 공간을 만들어두면 좋을 것 같다.

 

느꼈던 점

팀 프로젝트가 처음이다 보니, 시작부터 모든 것이 낯설고 어색하게 다가왔다. 나만 그런 것이 아니라 모든 팀원 분들이 다 그렇게 느꼈으리라 생각한다. 하지만 그렇기에 프로젝트를 통해 배운 것 또한 많지 않았나 싶다. 고맙게도 처음 프로젝트를 기획할 때부터 모든 팀원 분들이 적극적으로 의견을 내주셨고, 또 서로 배려하는 자세를 갖고 적극적으로 프로젝트에 임해주셔서 나 또한 프로젝트에 더더욱 열심히 참여하려 열정을 낼 수 있지 않았나 싶다.

 

 

프로젝트 중 잘했던 점을 생각해보면, 같은 프론트엔드 팀원들을 적극적으로 도와주었다는 점을 꼽을 수 있을 것 같다. 당시 팀원 중 개발 관련 경험이 내가 제일 많아서 그랬는지, 팀원들이 개발 도중 어려운 일이 생기면 나에게 먼저 질문을 많이 해주셨다. 그래서 그럴 때마다 적극적으로 팀원을 도와가며 프로젝트가 중간에 막히지 않도록 신경썼다.

 

또 하나 잘했다고 생각이 드는 점을 기록하면, 프로젝트 중 모르는 것이 생겨 멘토님께 질문을 하기 전, 혼자 우선 고민을 해본 후 질문할 내용을 미리 정리했다는 점과, 개발 도중 만났던 오류를 그냥 넘기지 않고 따로 정리했다는 점이다. (내 깃허브의 ERROR NOTE 저장소는 이렇게 탄생하게 되었다.)

 

반면 아쉬웠던 점 역시 있었다. 특히 프로젝트 중 내 실수로 팀원들에게 미안해할만한 일이 생겼던 적이 있었다. 위에서도 언급을 했지만, FontAwesome 패키지를 내 로컬에만 설치하여 프로젝트에 활용했고 이를 팀원들에게 깜박하고 말하지 않았던 것이다. 결국 이로 인해 최종 테스트 때 패키지 충돌이 발생하였고, 팀원들에게 당혹감을 주고 나서야 비로소 '아차' 싶었다. 이번 일을 통해 팀원들과 꼭 공유해야 할 내용은 그때그때 바로 말해서 앞으로는 이런 일이 생기지 않도록 조심해야겠다는 생각이 들었다. 좋은 경험을 했다.

 

 

사실 프로젝트 시작 전, 2주도 채 되지 않는 짧은 기간 안에 프로젝트를 완성하는 것이 가능할까 싶은 생각이 강했다. 심지어 팀원 분들이 돌아가며 코로나에 걸리는 바람에 더욱 프로젝트 완성에 대한 확신이 부족했다. 그렇지만 이런 어려운 상황 속에서도 다들 맡은 바 최선을 다해준 덕분에 큰 문제없이 기간 내에 무사히 프로젝트를 마무리할 수 있었다.

비록 배포까지 하지 못한 점과 최종 결과물에 대한 아쉬움이 남는 것은 사실이지만, 기능 구현보다는 팀 프로젝트를 통해 최대한 다양한 경험을 해보자는 마인드여서 그랬는지, 충분히 만족스러운 프로젝트였다고 말할 수 있을 것 같다. 


마지막으로 이 자릴 빌어 함께 고생해준 팀원분들 모두에게 고맙고 고생했다는 말 남기고 싶다.

 

반응형

'✪ 취미, 경험 회고 및 일상 > [회고] IT 관련 경험 회고' 카테고리의 다른 글

🦁 멋쟁이 사자처럼 11기 합격 후기 (서류, 면접)  (0) 2023.03.22
위코드 2차 팀 프로젝트 'WeMong' 회고  (0) 2022.12.11
코드숨(CodeSoom) 리엑트 11기 마지막 회고 및 후기.. (부제 : 나는 실패했다)  (0) 2022.10.09
코드숨(CodeSoom) 리엑트 11기 5주차 회고  (0) 2022.09.05
코드숨(CodeSoom) 리엑트 11기 4주차 회고  (0) 2022.08.29
'✪ 취미, 경험 회고 및 일상/[회고] IT 관련 경험 회고' 카테고리의 다른 글
  • 🦁 멋쟁이 사자처럼 11기 합격 후기 (서류, 면접)
  • 위코드 2차 팀 프로젝트 'WeMong' 회고
  • 코드숨(CodeSoom) 리엑트 11기 마지막 회고 및 후기.. (부제 : 나는 실패했다)
  • 코드숨(CodeSoom) 리엑트 11기 5주차 회고
SangYoonLee (SYL)
SangYoonLee (SYL)
Slow, But Steady Wins The Race 😎
    반응형
  • SangYoonLee (SYL)
    ◆ Slow, But Steady ◆
    SangYoonLee (SYL)
  • 전체
    오늘
    어제
    • ◻ 전체 글 수 : (132)
      • ✪ 취미, 경험 회고 및 일상 (26)
        • [취미] Room Escape (2)
        • [회고] IT 관련 경험 회고 (18)
        • [일상] 일상 생각 (4)
        • [일상] 독후감 (1)
      • ◼ FrontEnd (30)
        • Web & HTML, CSS (9)
        • JavaScript (4)
        • TypeScript (1)
        • ReactJS (16)
      • ◼ CS (3)
        • 자료구조 & 알고리즘 (1)
        • 컴퓨터 구조 (1)
        • 운영체제 (1)
      • ◼ PS Note (40)
        • 백준 (38)
        • 프로그래머스 (2)
      • ◼ IT Etc. (33)
        • (Until 2021) (21)
        • Python (6)
        • C | C# | C++ (1)
        • Git (1)
        • Unity (4)
        • Game Dev. (0)
  • 블로그 메뉴

    • 홈
    • 💻 GitHub
    • 🟢 Velog
    • 🧩 온라인 방탈출 출시 작품 모음
  • 링크

    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    wecode
    리엑트
    C++
    개인 프로젝트
    관심사의 분리
    유니티
    후기
    소수 구하기
    Cpp
    JavaScript
    더라비린스
    CodeSoom
    1929
    회고
    React
    알고리즘
    프로젝트
    방탈출고사
    파이썬
    pygame
    Component
    코딩 일기
    주간 회고
    미궁 게임
    Python
    프로그래머스
    코드숨
    위코드
    unity
    백준
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
SangYoonLee (SYL)
위코드 1차 팀 프로젝트 'HealthEat' 회고
상단으로

티스토리툴바