Coinone Clone Project 후기

손병진·2020년 10월 20일
1

wecode

목록 보기
27/27

프로젝트 개요

  • 팀명 : wallstreet
  • 기간 : 2020.10.02 ~ 2020.10.16
  • 인원 : 총 5명 (백엔드 2명, 프론트엔드 3명)
  • 설명 : 가상 화폐 거래 사이트 '코인원' 사이트를 참고하여 클론 프로젝트를 진행하였으며, 레이아웃과 기능을 크게 3개로 나눠 역할을 분담하였다.
  • 역할 분담
    • 백엔드: 회원가입, 로그인 / 가상 거래 데이터 생성 / 암호화폐 매수, 매도 기능
    • 프론트엔드: 메인페이지 / 거래소페이지 / 기타(로그인, 회원가입, 수익현황 등)

결과물📽

소셜로그인

카카오톡 서버 측으로 유저 정보를 post 통신으로 보냈을 때 응답으로 받은 토큰을 백엔드 측으로 보내주고, 우리 서버에서 다시 카카오톡 서버와 통신하여 전용 토큰을 만드는 알고리즘으로 소셜로그인 기능을 구현하였습니다.


메인

  • High-charts 라이브러리를 이용한 선그래프 구현이 주요 과제 였습니다. 주가 데이터 수치를 UI에 보여주는 것 이외에도 등락율을 계산하여 선 색깔을 부여하고, 클릭시 해당 종목의 데이터를 가져와 보여주게끔 하였습니다.

거래소

상단

  • 주가 그래프
    이 또한 Hichart-charts 라이브러리 중에서도 stock charts 템플릿을 참고하여 주가그래프를 구현하였습니다. 메인 페이지와 같이 해당 종목을 눌렀을 때, 데이터가 바뀌어 보여지게끔 하였고, 서버와 통신하는 시점에 로딩이미지가 나오도록 했습니다.

하단

  • 데이터 업데이트
    setInterval 요청으로 데이터가 계속 업데이트 될 수 있게끔 설정하였으며, 바뀔 때마다 해당 종목에 깜빡이는 애니메이션을 설정했습니다.
  • 매수/매도 기능
    가격과 수량을 입력하여 매수 버튼을 누르면 완료되었다는 모달창이 나오고 유저별 주문건으로 갱신될 수 있도록 설정했습니다.

수익현황

  • 위 매수/매도 정보를 바탕으로 갱신된 유저 정보(보유한 종목)가 나올 수 있게끔 저장된 토큰을 활용하여 서버와의 post 통신을 하였고, 받은 JSON 파일을 토대로 UI를 구성하였습니다.

기억하고 싶은 코드💯

데이터 업데이트 애니메이션

  • 상황 설명
    거래소 페이지 하단에 실시간 채결내역과 시세별 주문현황이 있는데 해당 데이터를 업데이터 시켜주어야 해서 setTimeout 함수를 활용하여 약 7초 주기로 데이터를 새로 받아오고 있었다. 여기서 변하는 데이터에 따라 특정 효과를 주어 업데이트가 되는 부분을 시각적으로 보여주고자 하였다.
    • 데이터 형태는 배열안의 배열
      -> [ [시세, 수량, 주문금액] , [ ] , [ ] ... [ ] ]
// 받아온 데이터와 이전 데이터를 비교해 Boolean 값을 삽입
// buyArr 새로 들어오는 데이터, buyWaiting 기존 데이터(시세별 주문현황)
    for (let i = 0; i < buyArr.length; i++) {
      for (let e = 0; e < buyWaiting.length; e++) {
        if (
          buyArr[i][0] === buyWaiting[e][0] &&
          buyArr[i][1] === buyWaiting[e][1]
        ) {
          buyArr[i][3] = false;
          // 새로운 데이터와 기존 데이터에 내용이 동일하다면 false 삽입
          continue;
        }
      }
      if (buyArr[i][3] !== false) {
        // 위 조건에 해당하지 않으면 true 삽입
        buyArr[i][3] = true;
      }
    }
/*styled-component*/
const MapUnit = styled.div`
  ${({ theme }) => theme.flex(null, 'center', 'row')}
  position:relative;
  text-align: right;
  height: 36px;

  /* boolean 값에 따라 애니메이션 활성화 */
  @keyframes updatingData {
    0% {
      opacity: 0;
    }
    50% {
      opacity: 1;
    }
    100% {
      opacity: 0;
    }
  }
  animation-name: ${({ update }) => (update ? 'updatingData' : null)};
  animation-duration: ${({ update }) => (update ? '1s' : null)};
  animation-timing-function: ${({ update }) => (update ? 'ease-out' : null)};
  
  div {
    ${({ theme }) => theme.flex('space-between', 'center', 'row')}
  }
`;
  • 선정 이유
    이 코드를 고민했던 두 가지 포인트가 있었다.

    1. 어떻게 전후데이터를 비교할 것인가
    2. 무엇을 기준으로 css 애니메이션을 반응하도록 설정해야 하는가

    • 첫 번째 고민에서 중요한 포인트는 raw 데이터에 너무 집착해서는 안된다는 점이었다.
      데이터가 업데이트 되었다는 점에서 필자는 http 통신 직후에 기존 state와 비교하려 했었다. 그렇게 하니, 너무나도 방대한 복잡한 로직으로 빠지게 되었다. 하지만 나중에 보았을 때, 애니메이션을 위해서는 raw 데이터의 비교가 아닌 UI 데이터의 비교로 한발짝 물러서야 한다는 것을 알았다. 그래서 좀더 간단한 로직으로 데이터 비교가 가능했다.

    • 두 번째에서는 프론트엔드에서도 충분히 데이터를 가공해서 활용할 수 있다는 점이다.
      이것도 처음에는 받아온 데이터를 그냥 활용하려해서 굉장히 고민했는데 나중에 아이디어가 떠올랐을 때는 의외로 쉽게 풀렸다. 그냥 기존 데이터에서 새로운 프로퍼티를 추가해준 것 뿐이었다. 비교하는 로직을 거친 뒤 그 결과값에 따라 Boolean 값을 부여했다. 이를 활용하니 애니메이션 적용도 바로 가능했다.

    사실, 이것은 막바지에 구현하려는 추가 기능이었다. 백엔드가 가상 데이터를 실시간으로 업데이트하고 받아오는 과정이었는데, 사이트에서 너무 눈에 띄지 않았기 때문이다. 데이터를 최대한 전달력있게 보여주는 것이 프론트에 역할이라고 생각했고, 그동안의 팀원들의 노고를 꼭 보여주고 싶었기에 매달렸던 것 같다. 구현했을 때는 굉장히 기뻤고 보람찼기에 선정하게 되었다.


Optional Chaining

  • 상황 설명
    HighCharts 그래프에 활용하는 데이터 형식이 있고, 그 안에 수치 데이터를 삽입하는 부분이 있다. 해당 부분을 fetch 함수 실행할 때마다 바꿔주어야 했고, 이를 위해 함수를 별도로 선언하였다.
    그런데, fetch 이전의 초기 rendering 에서 그래프 데이터 형식이 완전하지 않아서 해당 함수에서 활용하는 key 값에 대해 undefined 오류가 발생하였다.

  • optional chaining
    ?. : 앞의 평가 대상이 undefinednull 이면 평가를 멈추고 undefined 를 반환한다.

  //데이터를 호출하는 함수 선언
  const fetchChart = () => {
    
    // state 값에 대입
    setChart({
      ...chart,
      plotOptions: {
        line: {
          color: chartList[coinId]?.upDown > 0 ? "#e12343" : "#1763b6",
        },
      },
      
      // optional chaining 사용
      title: {
        text: chartList[coinId]?.coinName,
      },
      subtitle: {
        text: chartList[coinId]?.present,

        style: {
          color: chartList[coinId]?.upDown > 0 ? "#e12343" : "#1763b6",
        }
      },
      series: [
        {
          data: chartList[coinId]?.data.map((data) => [
            data.reported_time,
            data.closing_price,
          ]),
        },
      ],
    });
  };
  • 선정 이유
    • 해당 코드는 막연하게 알고있던 optional chaining의 활용과 컴포넌트 렌더링 과정에 대해 좀더 깊게 이해할 수 있는 계기가 되었어서 작성하였다.
    • 일단, 해당 프로젝트는 데이터가 굉장히 많이 활용되었기 때문에 데이터가 전환되고 그 값을 할당하고 활용하는 변수들이 중요한 부분이었다. 그래서 구현하는 데에 있어서도 그 변수 내부에 key 값이 어느 시점에 어떻게 활용되는지도 알아야 했다. 왜냐하면 lifecycle 과정에서 처음 렌더링 될 때에는 state값이 선언만 있어 그래프에 들어가는 데이터가 없었기 때문이다. 그렇다고 해서 그 거대한 데이터를 미리 넣어둘 수도 없었기 때문에 optional chaining 활용해서 해결할 수 있었다. 이 고민 또한 많은 깨달음을 얻을 수 있었기에 선정하게 되었다.

짧은 후기✏

뭔가 고생했던 것에 비하면 너무나도 짧은 블로깅인 듯한 느낌이지만, 그래도 위에서 언급한 코드는 정말 몇시간 동안 고민해서 깨달았던 것들이라 정말 보람찼던 기억이다. 그리고 처음으로 PM 역할을 맡아 프로젝트를 진행해서 초반에는 부담이 되기도 했지만, 팀원들이 정말 열정적으로 함께 참여해줘서 진심으로 감사했다.
위에는 개인적으로 기억나는 코드지만 정말 드라마틱한 순간이 많았던 것 같다. 처음으로 우리의 데이터를 그래프에 넣었을 때, High-charts 라이브러리 템플릿의 프로퍼티를 하나하나 이해하가며 커스터마이징 했을때, 백엔드 분들이 만든 주가데이터 수치가 의도한대로 맞춰져서 생성됐을 때 등등 함께 해주셔서 정말 감사하다는 말씀을 드리고 싶다.
저번 프로젝트는 본인이 맡은 역할에 충실하고 기여하겠다는 마음이 강했다면 이번에는 프로젝트를 이끌어가야한다는 마음이었다. 그래서 더욱 많은 도움을 느꼈고 함께 프로젝트를 만들어간다는 느낌을 정말 많이 받았다.
몇날 몇일 새벽동안 프로젝트 준비하시느라 정말 고생한 예원, 예찬, 지선, 수정님에게 큰 은혜를 받았다는 말씀을 전하며, 우리팀 WallStreet 평생 기억할 것이고 사랑합니다~💗

profile
https://castie.tistory.com

0개의 댓글