[What's Dat?] React & Firebase 2주 프로젝트 후기 (feat. 코드스테이츠)

Hailey Song·2020년 11월 20일
2

PROJECT

목록 보기
3/4
post-thumbnail

0. Intro.


(언제나 그렇듯 아무말 주의, 격식없음 주의)

드디어 코드스테이츠에서의 첫 프로젝트(2주 프로젝트)가 끝났다!
망낳머머아허ㅏㅇ너ㅏㅇ나ㅇ 만감이 교차하는데 일단은 엄청 후련하고 엄청 뿌듯하다는 말이 절로 나온다. 코딩을 시작한지 3개월밖에 안됐다는 사실을 떠올리면 그 동안 내가 얼마나 성장해왔는지 확인할 수 있어서 무척 기분이 좋고, (남들 눈에는 이제 막 걸음마를 뗀 초보 예비개발자겠지만) 지금까지 열심히 달려와준 나 자신이 너무너무 자랑스럽다. 계속 달려야한다고 채찍질을 해왔는데 오늘은 나에게 아낌없는 칭찬칭찬의 시간을 퍼부어줄 것이다...ㅎ

아무튼 이제 3일 후에 다시 두 번째 프로젝트(4주 프로젝트)가 시작하는데, 그때에는 더 정신이 없을 것 같아 여운이 가시지 않은 채로 급하게 프로젝트 후기글을 남긴다. 발표가 끝난지 얼마 지나지 않았기 때문에 아직도 흥분 상태이므로 아무말을 써도(문장이 정리되지 않아도) 넓은 마음으로 양해해주시길...

1. Team / Project Introduction

👑 팀 소개

감사하게도 정말정말 잘 맞는 팀원분들과 프로젝트를 할 수 있게 되었다. 평소에 서로 친분이 있고 교류도 잦았던 분들이라 서로의 성향을 잘 알아서 역할 분배도 딱딱 이루어졌고, 무엇보다 열정이 넘쳐흐르는 분들이었기 때문에 2주 동안 말도 안되는 분량을 뽝뽝 소화해낼 수 있었던 것 같다.

암튼 각설하고, 우리팀 Rock Paper Queens(코드스테이츠 수료생이라면 각 단어들이 어디서 유래되었는지 눈치챌 수 있을 것이다..)는 팀원 전원이 모두 풀스택으로 참가했다. 사실 코드스테이츠에서는 프론트엔드와 백엔드를 나누어서 작업하기를 권장했지만, 일단은 팀원 모두가 프론트엔드 희망자들이었고, (욕심이 그득그득한) 우리가 만들고 싶었던 서비스를 2주(라고 쓰고 10일이라 읽는다) 안에 구현하기 위해서는 분야의 구분 없이 팀원 모두의 협력이 필요했기 때문이었다. 고심고심 끝에 프론트엔드로는 리액트, 백엔드로는 파이어베이스를 쓰기로 합의하게 되었고, 그 결과 프론트와 백의 구분이 모호해지게 되었다.

🤪 아이디어 회의


2주 프로젝트는 우리가 배운 것을 실제로 적용하는 것 이상으로, 정말 우리가 즐겁게 해보고 싶은 것을 선택하고 싶었기에 게임이라는 주제를 선택했다.
또 팀원 모두가 데이터를 시각적으로 보여주는 데에 관심이 있어, 추후 D3를 배우고 싶다는 열망 하에 그 징검다리로 캔버스 분야를 선택했다. 두 가지를 조합하다보니 보드게임 텔레스트레이션이라는 게임에서 아이디어를 얻어,실시간 온라인으로 사람들과 함께 즐길 수 있는 What's Dat?(이게 뭐지?)이라는 게임을 구상하게 되었다.

텔레스트레이션은 위의 그림과 같이 꼬리에 꼬리를 물어 서로에게 퀴즈를 내는 보드게임이다. 마치 가족오락관같이(옛날 사람 인증) 맨 처음 사람이 단어를 제시하면 그 다음 사람이 그 단어에 대한 그림을 그린다. 그 다음 사람은 (첫 제시어는 모르는 상태로) 이전 그림만 보고 무엇인지 추측하여 단어를 제출하고, 그 다음 사람이 그 단어를 보고 무엇인지 그리게 된다. 이렇게 반복하면 가장 첫 단어가 경이롭게 바뀌는 놀라운 경험을 하게 된다. (파전이 감자가 된다거나, 해리포터가 자석이 된다거나..)

(TMI : What's Dat이라는 이름은.. 사전조사를 가장해 팀원들과 텔레스트레이션 보드게임을 하는 과정에서 가장 많이 나온 말에서 유래했다.. 도대체... 이게 뭐야....)

(도대체 이게 뭐냔 말이야.. 근데 또 놀랍게도 다른 팀원분은 정답을 맞추셨다.)

🗒 프로젝트 소개

0. Main Page


(gif 파일이 색감을 잘 살려주지 못해서 슬프다.) 암튼 구름 둥둥 너무 예뻐서 인트로로 찰칵. 애니메이션을 담당한 팀원분이 어엄청 고생하셨던 기억이 난다. 하지만 결과물이 너무 귀엽고 예쁨.

1. Authentication


What's Dat은 이메일을 통한 회원가입 및 로그인, 구글과 페이스북, 트위터를 통한 소셜 로그인, 로그아웃, 프로필 수정 기능을 모두 지원한다.(로그인 시연 영상의 닉네임이 머글로 시작해서 볼드모드로 끝나는 건 안 비밀)
나중에 기술스택에서도 설명하겠지만 프론트엔드에서는 주로 React의 Form 라이브러리인 formik를 사용했고(그렇게 form 지옥이 시작되었다), 데이터베이스는 Firebase authentication와 Firebase firestore을 사용했다. 처음에는 그냥 firebase의 authentication 기능으로만 유저를 관리하려고 했는데, firebase의 auth에는 우리가 원하는 커스텀 필드를 넣어줄 수 없다는 문제에 봉착했다. 결국 firebase auth를 통해 받은 유저 데이터를 우리가 원하는 형태로 재가공하여 firestore에 업로드하는 방법을 사용했다.

2. Game Room CRUD


다음은 게임방에 관한 부분이다.
새 방을 생성하거나, 이미 생성된 방에 들어가거나, 혹은 각 방에 부여된 고유한 코드를 통해 방에 들어가는 기능을 구현했다. 방을 생성할 때에는 방의 제목, 제한 시간(제한 시간 20초를 해놓고 게임을 하면 심장이 쫄깃하다.), 최대 인원(3~6명까지 설정 가능)을 선택할 수 있게 했고, 그렇게 방을 생성한 유저가 👑호스트가 되어 해당 유저만 방의 설정을 수정할 수 있는 권한을 부여했다. 다른 사람들이 방을 수정하려고 하면 에러 모달이 뜨게 만들었다.
또한 호스트에는 앞에 👑 이모지를 붙여주어 차별성을 주었고, 나 자신은 다른 유저들과 색을 달리 해 한 눈에 띌 수 있게 구현하였다. (이렇게 각 유저마다 UI상의 차별성을 주기 위해 props 지옥에 빠졌다..)
또한 유저가 방에 들어올 때마다, 즉 데이터베이스의 정보가 바뀔 때마다 트리거를 걸어주는 firebase의 onSnapshot 기능을 이용하여 실시간으로 유저들이 들어오는 것을 보여줄 수 있도록 렌더링했고(useEffect 지옥에 빠졌다...), 같은 실시간 기능을 이용하여 유저들이 자신의 아이디를 클릭해 레디 상태를 표시할 때마다 바로바로 렌더링해주었다. 덕분에.. 그 어렵다는... firebase 과금에 성공했다!ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
호스트가 나가면 그 다음 사람에게 호스트 지위를 넘겨주고, 모든 사람이 떠나면 방을 자동으로 삭제하는 기능도 추가했다.

3. Game Playing


드디어 드디어 대망의 게임 페이지! 내가 맡았던 부분이 이 곳이었는데 3일 동안 정말 눈물났던 기억이 있다.. 흑흑..
게임 페이지는 첫 단어를 선택하는 select word 페이지, 이전 단어에 대한 그림을 그리는 drawing 페이지, 이전 그림에 대한 단어를 맞추는 guess word 페이지, 모든 사람들의 결과를 연결리스트 슬라이드로 한 눈에 보여주는 result page로 구성되어있고, 이것을 game index.js라는 하나의 컴포넌트에서 state 조건에 따라 렌더링해주도록 구성하였다.
유저가 submit 버튼을 누르거나 제한 시간이 초과하면 유저가 작성한 value(그림 혹은 단어)를 firestore로 보내고, 모든 유저가 단어를 보낼 때까지 waiting 모달을 띄워주면서 아직 제출하지 못한 팀원의 목록을 실시간으로 보여준다.
모든 팀원이 value를 제출하면 firestore functions로 트리거를 걸어 다음 라운드를 생성해주게 만들고, 다음 라운드가 생성되는 것을 실시간 snapshot으로 받아 리액트에서 짝수 라운드일 경우에는 guess word 페이지를, 홀수 라운드일 경우에는 drawing 페이지를 렌더링하게 만들었다. 그리고 모든 라운드가 끝나면 모든 유저가 제출한 데이터들을 받아서 링크드리스트 느낌으로 재가공해 리액트 슬라이드로 표현해주었다.

말로는 이렇게 쉽게 끝났지만.. 진짜 알고리즘의 끝판왕이었다.. 플레이어 수에 따라 총 라운드 수도 달라지고, 모든 유저가 이전 유저와 연결되어야 하고, 결과 페이지에서는 모든 것을 다 연결시켜줘야 하니까.. 그리고 또 그걸 한정된 데이터 스키마 안에서 처리하려다보니까 정말 눈물이 나왔다. 같이 지옥의 알고리즘을 푼 팀장님이 없었다면 어떻게 되었을지.. 또르륵..

그리고 여기서 정말 고생했던 것은 async의 개념이었다. 어싱크는 await만 붙여주면 되지!라고 간단히 생각했는데 정말정말... 정말... 알면 알수록 알 수 없는 친구였다. 데이터베이스에서 받아오는 시간과 state로 관리해주는 시간이 절묘하게 맞아떨어져야만 게임이 돌아가는데 내가 예상했던 것과는 전혀 다른 순서로 진행되니까 엄청 당황했던 기억이 났다. 그날 새벽은 정말 파김치가 되어서 잠이 들었다.
하지만 덕분에 테스트 일환으로 게임은 원없이 했다. 나중에 게임 룸을 담당했던 팀원분들에게 들켜 원망을 샀다ㅋㅋㅋㅋㅋㅋ

3. Wireframe & UI Design

와이어프레임과 UI 디자인은 각각 미로와 피그마를 통해서 진행했다. 모두 실시간 협업이 가능한 툴이어서 모든 팀원이 무슨 마인크래프트 같이 하듯이 콧노래를 흥얼흥얼하면서 디자인을 했던 기억이 있다.ㅋㅋㅋㅋ

먼저 미로로는 대애강 어떤 페이지가 있어야하는지, 각 페이지에는 무엇이 들어가야하는지 자유롭게 브레인스토밍하는 시간을 가졌다. 나중에 보니 놀랍게도 여기서 얼추 뼈대가 갖춰져 있었다. 여기서 나온 거의 모든 기능을 구현했다고 생각하니 엄청 뿌듯하다.

그 다음에는 피그마로 옮겨서 구체적인 디자인 작업에 들어갔다. 디자이너가 없어 메인 색상이나 폰트 크기, 여백 등을 중구난방으로 결정했는데 나중에 CSS 작업을 할 때 굉장히 일이 번거로워지는 원인 중 하나가 되었다. 다음엔 이 점을 교훈삼아 디자인 가이드라인을 세우고 작업하자고 팀원들끼리 합의를 보았다.

피그마에서 작업한 페이지 중 하나. 그 당시의 우리는 미래의 나에게 어떠한 고통을 줄 지 전혀 생각지도 못한 채 해맑게 해당 페이지에 모달을 세 개나 만들었다.

4. Development Stack


다음은 우리가 사용했던 기술 스택들이다. 프론트는 리액트, 백은 파이어베이스로 프로젝트를 진행했다.

1) Atomic Design과 Story Book, Styled-Components

리액트를 공부하면서 리액트는 재사용이 가능한 컴포넌트로 구성되어있다는 설명을 진짜 많이 들었는데, 지금까지는 컴포넌트를 재사용해본 적이 없었다. 물론 리스트를 만들때 map을 돌려 똑같은 것을 여러번 찍어내긴 했지만 그건 다른 이야기고..ㅠㅠ
그래서 이번 프로젝트를 통해 리액트의 본질(?)에 접근해보고자 Atomic 디자인을 채택하게 되었다.

아토믹 디자인이란 위 그림과 같이 아톰 단계에서 컴포넌트들을 가장 작은 단위(예를 들면 버튼, 헤더, 아이콘, 인풋 등)를 쪼개고, 그 아톰들을 조합하여 분자를 만들고, 또 그것들을 조합하여 유기체로, 템플릿으로, 최종적으로 페이지로 만드는 것을 말한다. 사실 원래 아토믹 디자인은 이렇게 아톰, 분자(Molecules), 유기체, 템플릿, 페이지의 다섯 단계를 일컫는데, 우리는 2주라는 짧은 시간 동안 모든 단계를 구현하기가 어렵고 각 단계의 구분이 모호하다는 생각에 아톰과 모듈(분자+유기체), 템플릿, 페이지의 4단계를 채택해서 작업하였다.

아토믹 디자인과 엄청난 시너지 효과를 내는 것이 바로 StoryBook이었다. 예를 들어 atom 단계의 버튼을 여러 페이지에 재사용하려다보면 각 페이지에 맞는 스타일로 조정되어야 한다. 그런 속성들을 부모 컴포넌트로부터 props를 받아야하는데, 문제는 버튼 스타일을 구성하는 props가 너무 많다는 것이다! 패딩, 폰트사이즈, 배경색, 폰트색, 보더, 보더컬러, 섀도우, 마우스오버 등등! 이 모든 props를 내려주어야 모든 페이지에서 재사용 가능한 커스텀 버튼이 완성될 수 있다. 그러나 우리는 이 버튼만을 아톰으로 쓰지 않지... 우리에게는 버튼, 헤더, 컨테이너, 아이콘 등등의 총 19개의 아톰이 있었고 그것들을 조합한 18개의 모듈들이, 그것을 조합한 16개의 템플릿과 17개의 페이지가 있었다... 각각은 props를 정말 적으면 두 개, 정말 많으면 10개까지 받았으므로 우리는 그 수백여가지의 props들을 관리해야했다. 그럴 때 필요한 것이 시각적인 문서화 작업이었고, 그것을 가장 강력하게 지원하는 것이 리액트 스토리북이었다.

위와 같이 스토리북은 각 컴포넌트가 어떤 props를 받는지, 어떤 옵션을 받아서 어떻게 변화하는지 시각적으로 보여줄 수 있는 도구였다. 따라서 다른 팀원이 만든 아톰들을 내 아톰들과 조합할 때 엄청난 힘을 발휘했고, 코드를 일일이 읽지 않아도 어떻게 사용해야하는지 직관적으로 알 수 있어서 작업 속도가 빨라졌다. 물론 classname 이름 규칙이나 props 규칙을 사전에 정하지 않아 팀원들끼리 코드 스타일을 맞추지 못해서 아쉬움이 남는다.

그리고 Stypled-Component 역시 처음 사용해봤는데, CSS를 재사용 + 커스텀 가능한 컴포넌트로 만들 수 있다는 것이 정말 강력했다. 그냥 index.css에 모든 classname으로 CSS를 때려박았던 나에게는 정말 신세계!

2) React state 관리 Redux vs Context

사실 Redux에 대한 두려움이 있었다.. 일단.. 이해하는 데 어엄청난 시간이 걸렸다(사실 지금도 이해하지 못한 것 같다.) 그리고 리덕스를 배우고자 개인적으로 시작했던 리덕스 프로젝트도 큰 산을 넘기지 못하고 무너졌다. 그래서 팀장님이 시간상 리덕스가 아니라 global context로 state를 관리하자고 말씀하셨을 때 내심 환호성을 질렀다(firebase나 storybook, styled-component 등 2주 안에 새로 배워야할 것들이 너무너무 많아서 state는 익숙한 걸로 하길 원했던 거기도 했다.)

결론적으로 말하자면, 팀원들은 다음 프로젝트로 Redux를 쓰는데에 전원 찬성했다. 리덕스를 왜 써야하는지도 정말 온 몸으로 느꼈다.. context로는 감당이 안 됐다... o<-<

3) Firebase

이번 프로젝트의 꽃 F.I.R.E.B.A.S.E.....o<-<

우리가 이번 프로젝트에 사용한 firebase 서비스를 대애강 이런 관계도로 그려보긴 했는데..정확한지는 모르겠다. 프로젝트를 firebase로 진행했지만 firebase를 이해했다고 말하기가 정말 민망하다. 일단 공식문서와 유튜브를 보면서 어찌저찌 부딪혀보기는 했는데 아직도 어둠 속을 걷는 것만 같은 기분이다.

firebase는 서버리스여서 클라이언트와 서버의 경계가 모호하다는 말을 많이 들었는데 사용해보니 정말 그랬다. 여태까지 내가 배웠던 서버(express 밖에 없다..)는 데이터베이스에서 데이터를 받아와서 API 문서에 맞게 데이터를 가공해서 클라이언트로 전달해주는 역할이었다면, firebase는 클라이언트에서도 데이터베이스의 데이터를 바로 받아올 수 있고, 서버의 역할을 하는(것 같은...) firebase functions에서도 데이터를 받아올 수 있어서 어디서 데이터를 가공해야하는지, 어떨 땐 어느 기능을 사용하는 것인지 많이 혼란스러웠던 것 같다. 실제로 클라이언트에서 처리해주어야 할 로직과 functions에서 처리해주어야 할 로직을 구분하지 못해 비효율적인(1번 돌아야하는데 최대 6번을 돌게 되는) 코드를 작성한 적이 있다. 물론 그걸 알아차렸을 때는 그 코드 자체가 젠가탑의 아래쪽에 있어서 쉽게 건들지 못했던 기억이... 하나를 고치면 모든게 와르르 무너질 것 같아서...ㅠㅠ

암튼 그렇게 functions 무한루핑으로 firebase에서 과금을 물고(이야 신난다!) 비효율적인 코드를 몇 십 번 쓰고 나니 대강 어느 곳에서 어느 것을 사용해야하는지 감은 올 듯 말 듯한데, 그걸 확신할 수가 없어서 좀 조심스럽긴 하다. firebase가 핫하다고 다들 말하는 것에 비해 자료가 정말정말정말정말 없어서.. 심지어 stackoverflow에서도 찾기 어려워서 이해되지도 않는 공식문서를 붙잡고 끙끙대며 어찌저찌 만들었다.

그럼에도 불구하고! firebase에 대한 팀원들의 공통 의견은 긍정적이었다. 우선 NOSQL의 신세계(라 쓰고 혼돈이라 읽는다)를 경험해봤고, firebase 자체가 여러 기능들을 지원해주다보니 프론트엔드에 좀 더 집중할 수 있게 만들어주었다. 가격도 착했다..(우리의 엄청난 비효율을 단 돈 3센트에 무마해주었다..) 만약 나중에 소규모 사이드 프로젝트를 진행하게 된다면 firebase를 선택하게 될 것 같다는 팀원분의 말에 모두가 공감을 했다. 그렇지만 한편으로는 SQL이 너무 그립기도 했다.. NOSQL은 너무 자유로워.. 자유롭기만 해..

4) Deployment

배포는 간단했다. 터미널에 이 명령어만 쓰면 된다. firebase deploy!
(물론 firebase 셋업이 잘 되어있을 때 이야기다.. o<-<..)

5. Review

😱 풀 모각코! 모두 고생했어요!

과장 안 보태고.. 지난 2주간 먹고 자는 시간 외엔 코딩만 했고, 깨어있는 동안은 반드시 모각코(구글 미팅 화상통화)를 했다. 모든 팀원이 그랬다. 정말 우리를 위잉위잉 갈아넣은 스케줄이지만 거의 24시간을 같이 있어서인지 팀원들간의 소통에 어려움이 전혀 없었다. 문제가 생기면 바로바로 전달됐고, 팀원들 자체가 모듈화가 되어섴ㅋㅋ 정말 해결하기 어려운 문제는 자유롭게 페어 프로그래밍으로 진행했다. 함께 고민하고 토론하고 의견을 조율하는 과정도 충분히 이루어졌고, 팀에 필요한 레퍼런스는 반드시 공유하고 문서화했다. 무엇보다 팀원들의 시너지 효과가 너무너무 좋았다. 그 2주일 동안 서로가 서로를 통해 성장하고 있다는 것이 느껴졌다. 엄청난 스케줄에도 불구하고 서로 얼굴 찌푸리는 일 없이, 심지어는 진심으로 행복하게 웃으면서 프로젝트를 진행할 수 있었던 것은 정말 행운이라고 생각한다. 팀원분들이 없었다면 여기까지 오지 못했을 것 같다. (팀원분들이 이 글을 읽을지는 모르겠지만) 이 자리를 빌어 진심으로 감사의 마음을 전한다.

😚 느낀 점

이번 프로젝트는 정말 여러가지를 새로 도입해보았던 것 같다. 아토믹, 스토리북, 스타일드 컴포넌트, 파이어베이스까지. 10일이라는 짧은 시간 안에 지금까지 배운 내용만으로도 원대한 목표를 달성하기 벅찬데, 새로운 것을 배우고 익숙하게 적용하기까지의 시간이 부담스럽지 않았다면 거짓말일 것이다. 그럼에도 불구하고 정말 하길 잘 했다는 생각을 했다. 비록 처음 배우는 거라 우당탕탕 엉망진창 중구난방의 코드가 난발했지만 하면 할수록 '아 이래서 사람들이 그렇게 강조했던 거구나', '아 이래서 이럴 땐 이렇게 하라는 거였구나', '아 이래서...'와 같은 감상이 절로 나오는 경험을 하게 되었다. 선배 개발자들이 고뇌했던 부분들, 그들이 생각했던 철학들, 그들이 만들었던 체계들을 몸소 겪어보고 이해해나가는 과정의 출발선에 비로소 서 있는 느낌.

아무튼 다음에는 더 잘 할 수 있을 것 같다! 이 마음가짐만으로도 충분히 의의가 있지 않을까.

😹 다음 프로젝트에는..

  • 여러 곳에서 쓰이는 기능은 아예 함수를 따로 만들어서 사용하자(유저 정보를 업데이트하는 함수라던가..) 함수 분리에 대한 중요성을 절절히 느꼈다.
  • state로 관리하는 데이터와 DB에서 받아오는 데이터의 변수 이름을 잘 구분할 수 있게 짓자.
  • 라우팅은 DB에서 받아온 데이터가 아니라 state를 기준으로!(동기화의 문제) 그러므로 async도 순서를 잘 생각하자.
  • 유저가 브라우저를 새로고침하면 state가 날아간다. state 유지 문제에 대한 고민을 더 해보자.

6. Outro.

마지막으로 개인적으로 웃겼던 (이번에도 테스트를 가장한) 게임 캡쳐를 투척하고 간다ㅋㅋㅋㅋㅋㅋ 장발장이라는 단어는 내가 냈곸ㅋㅋㅋㅋ 그 뒤로는 팀원분들의 대환장 콜라보다.

장발장 첫 그림 진짜 잘 그려주셨는데 그 다음에 비엔나 소시지도둑 뭐냐궄ㅋㅋㅋㅋㅋㅋ 그 다음 그림은 또 왜 소세지를 휘두르고 있엌ㅋㅋㅋㅋ 당분간 내 웃음지뢰가 될 것 같다.

암튼 정말 두서없이 막 쏟아부은 글. 오늘은 여기까지.
다음 글은 아마 4주 프로젝트 후기글로 돌아오지 않을까. 그때까지 살아있길 빈다.

0개의 댓글