개발자 99% 커뮤니티에서 수다 떨어요!
https://nomadcatch.netlify.app/
노마드 캐치 : Nomad Catch
ReactJS, ExpressJS, Socket.IO, WebRTC, HTML Canvas, StyledComponents
개발 기간 : 2주
프로젝트의 최대 문제점 : 개발자가 그림을 심각하게 못그림 ...
자기소개
안녕하세요 Geony 입니다.
노마드 코더에서 공부를 시작한지 이제 6개월차 코린이 입니다. 🙋
일과 시간에 틈틈히 시간을 쪼개 공부를 할 수 밖에 없어 아직 실력을 많이 쌓진 못했지만 지금까지 제가 지금까지 공부했던 내용들을 간단히 복습 해보고 WebSocket 과 WebRTC 와 같은 실시간 채팅 솔루션을 더 깊이 이해하고 싶은 마음에 이번 챌린지를 도전하게 되었습니다.
서비스 소개
https://nomadcatch.netlify.app/
이번에 제가 소개하는 서비스의 이름은 노마드 캐치 Nomad Cache 입니다.
줌의 화상 채팅과 캐치마인드의 드로잉 채팅 기술을 조합하여 만든 웹 기반 서비스입니다.
이 서비스에서는 화상 채팅과 더불어 간단한 그림으로 단어를 맞추는 간단한 게임을 진행할 수 있습니다.
두 유저가 방에 입장하면 화상 채팅이 시작하고 둘 중에 먼저 Start 버튼을 누른 사람이 출제자가 되어 게임을 시작합니다.
출제자에게 문제가 주어지고 출제자는 문제를 캔버스 판에 그리는 그림으로 묘사하여 상대방이 맞추도록 해야 합니다.
상대방이 정답을 메시지 창에 입력하면 정답을 맞췄다는 메시지가 나오고 게임은 종료합니다.
누구든 다시 Start 버튼을 누르면 게임을 다시 재개할 수 있습니다.
개발 과정 (어려웠던 점과 해결방법)
Canvas + WebRTC DataChannel 로 구현하는 캐치마인드 화면
줌클론 강의 중에 니꼬쌤이 PeerConnection의 DataChannel 을 이용하면 모든 데이터를 실시간으로 주고 받을 수 있다고 말씀하셨는데요.
또 자바스크립트로 캔버스 만들기 강의에서 HTML의 canvas 기능에 대해 공부를 했던 기억이 떠올랐습니다.
이 두 기술을 조합하면 재밌는 결과물을 만들 수 있을 것 같았죠! 🙌
(줌클론 2기 졸업 과제로 노마드 캐치 버전1을 만들어보지만 제대로 동작하지 않아 실패 ... ㅠ )
첫그림
이번 챌린지를 통해 저의 미완성 프로젝트를 업그레이드할 수 있는 좋은 기회라 생각하여 기존 바닐라 자바스크립트를 싹 지우고 ReactJS 를 프론트로 ExpressJS 를 소켓 서버로 만들기 시작합니다.
클라이언트와 서버의 Socket 연결까지는 무사히 만들었지만 그 이후가 문제였습니다.
WebRTC Connection 은 핑퐁처럼 offer - answer - candidate 를 브라우저끼리 주고 받으며 신뢰를 확보하고 직통으로 브라우저를 연결하게 되는데요.
리액트는 state 가 변경될 때마다 해당 부분을 다시 랜더링 해버리는데 이 부분에서 연결이 계속 끊기거나 중첩되어 에러가 발생했습니다.
특히 개발 환경에서 React Strict Mode 를 사용하면 랜더링을 두번씩 처리하여 커넥션이 계속 망가져버리는데 처음에는 원인을 몰라 굉장히 당황스러웠습니다.
또한 useEffect 와 같은 Hook 으로 마운트 이후 랜더링을 통제하여 커넥션을 유지할 수 있다는 아주 기본적인 사실을 깨닫는데도 시간이 조금 필요 했습니다.
삽질하느라 고생했지만, 바닐라 자바스크립트로에서는 경험해보지 못한 커넥션 오류 덕분에 리액트의 동작 원리에 대해 공부해볼 수 있는 좋은 시간이었습니다.
Stun 서버를 이용하여 4명이 채팅하는 서비스를 만들고 싶었지만 제한 시간을 맞출 수 없을 것 같아 다음 프로젝트를 위해 아껴두기로 했습니다… 😅
프론트에서 Socket 서버랑 통신하는 건 정말 쉽지만 Peer Connection 을 만드는 건 굉장히 까다로웠는데 이유는 브라우저의 새로고침이라는 무시무시한 기능 때문이었습니다.
Connection을 간신히 이어 놓아도 새로고침 한방이면 모든걸 초토화 시켜버리니 굉장히 당황스러웠습니다.
사실 줌 클론 강의에서는 언급하지 않는 부분이지만 새로고침 이후에도 커넥션이 유지되면 정말 멋질 것 같아 해결 방법을 몇날 몇일 찾아보았지만 제 수준에서는 구현하기 어려웠습니다.
로컬에서는 새로고침해도 재연결이 가능하지만 Netlify 에서는 새로고침을 하는 순간 페이지가 뻗어버리는데 원인을 잘 모르겠습니다.. ㅠㅠ
Session Store를 만들어 현재 소켓 ID나 토큰을 저장하여 연결이 끊겨도 기억해둔 토큰으로 기존 연결을 복구하는 방법 등이 있다는 것을 찾아보았는데 나중에 더 공부하여 이 부분을 더욱 정교하게 구현해보고 싶습니다.
어디 숨어 있었는지 배포좀 해보려면 튀어나오는 CORS 에러 : cors 라이브러리와 io server 설정으로 해결 ㅜ
PeerConnection의 DataChannel 을 이용하여 캔버스 이미지를 전송하기 위해서도 어려움을 많이 겪었습니다.
처음에 시도한 방법은 캔버스 자체를 Image Blob file 로 변환하여 DataChannel 을 통해 전송하는 방법이었는데 처음에는 멋진 방법이라 생각했는데 문제는 마우스 움직임에 따라 파일을 계속 전송하는 방법이기 때문에 과부하가 올 수 있고, 화면상에서 이미지가 계속 갱신되기 때문에 깜빡 거리는 현상이 발생하고 이런저런 버그가 많이 발생하더라구요.
고민하던 중에 캔버스 상에서 이미지가 그려지는데 필요한 자료는 X, Y 좌표 이기 때문에 좌표 값과 캔버스 상태 정보만 DataChannel 로 계속 전달하면 해당 브라우저에서 값을 받아 캔버스에 그림을 그려주는 함수를 계속 호출하는 방식으로 변경했습니다. 결국 두 개의 브라우저가 캔버스 상의 좌표만 동기화시켜주면 각자 붓으로 좌표를 따라 그리는 것이죠.
사실 만들고 보니 Socket 메시지로도 구현 가능할 것 같긴 한데… DataChannel 이 끊김 없이 더 빠르지 않을까? 하는 생각입니다.
어찌 되었든 덕분에 브라우저간 DataChannel을 통해 실시간 데이터 전송에 대해서 공부해볼 수 있었습니다. WebSocket과 WebRTC가 정말 멋진 기술이라는 것을 새삼 느꼈습니다.
모바일에서 그림을 그리도록 하려면 터치 이벤트를 잡으면 된다.
리액트 덕분에 styled-component 와 같은 유용한 라이브러리를 사용할 수 있었습니다. 손쉽게 CSS 작업을 할 수 있었죠..
이전에 카카오 클론에서 했던 input 디자인이 생각나서 비슷하게 만들어 보았습니다.
신규 메시지에 따라 스크롤리 자동으로 내려가는 것과 모바일에서 키보드가 하단에서 떠오를 때 스크롤이 자동으로 밑으로 내려가도록 하는 부분들은 useRef 를 이용하여 손쉽게 구현했습니다.
제 처음 목표는 모바일에서 동작 가능한 프로젝트였기 때문에, 디자인은 모바일 레이아웃에 맞춰 작업을 했습니다.
모바일 화면이니 캔버스에 마우스 뿐만 아니라 손가락 터치도 인식해야되는 조건이 생겼는데요.
은근히 까다로운 문제였습니다. Touch 이벤트에서 생성되는 좌표가 마우스 좌표랑은 달랐기 때문입니다.
Touch 가 이루어지는 X, Y 좌표를 정확하게 캐치하여 캔버스에 Path 값으로 보내기 위해 테스트를 계속 해봐도 Screen 에 맞춰 좌표 기준을 정하려고 해도 몇 픽셀씩 어긋나더라구요. 그래서 수동으로 값을 집어 넣어 억지로 맞췄는데 이 부분도 더 근본적인 해결 방법을 찾아보고 싶습니다.
화면을 클릭하면 화면 전송을 차단하고 스피커 모양을 클릭하면 음소거로 전환하도록 만들었습니다.
모바일 전용이라 따로 카메라 선택은 만들지 않았습니다. (오직 셀카용 카메라만 가능)
모바일로도 화상 채팅 / 그림 그리기 / 채팅 가능 !
문제 출제 같은 경우 서버에 저장된 단어들을 랜덤으로 불러와 출제자에게 보여주는 방식입니다. (심플!)
Start 버튼을 누르는 유저에게만 보여주도록 출제자와 동일한 이름의 유저에게만 노출되도록 간단한 조건문을 구현하여 만들어보았습니다.
그리고 유저가 보내는 메시지를 검수하여 문장 내에 정답이 포함되어 있는지 확인하여 포함되어 있다면 축하 메시지를 보내도록 만들었습니다.
이런 작은 게임 요소들이 앱을 더욱 흥미롭게 만들어주는 것 같더라구요.
front-end 배포는 Netlify
back-end 배포는 Heroku 에서 진행하였습니다!
앞으로 계획
노마드에서 공부 계획은 우버 이츠 완강 - 인스타 챌린지 졸업 - 우버 이츠 챌린지 졸업 - 캐럿 마켓 챌린지 졸업 - 타입스크립트 챌린지 졸업
요렇게 끝낼 예정입니다.
사이드 프로젝트 계획은
7월 중에는 인스타클론 강의를 바탕으로 뽀모도로 클론 앱을 만들 예정이고
8월 ~ 9월 중으로는 NextJS 로 기존 회사 홈페이지를 리뉴얼하고 제가 쓸 모바일 청첩장도 만들어볼 예정입니다. ㅎㅎ
올해는 기본적인 웹개발 지식을 탄탄히 쌓고 블록체인 기술도 공부해보고 싶습니다.
내년에는 아이템을 선정해 사업화할 수 있는 기회가 왔으면 좋겠구요 !
이번 프로젝트에서 초보자 주제에 너무 많은 욕심을 부려 힘들었지만 핵심 기능은 모두 구현하고 배포까지 할 수 있어서 정말 다행입니다. (이제 넝마같은 코드들을 리팩터링할 시간)
개발 공부는 하면 할수록 더 어렵고 끝이 없는 것 같습니다.
열심히 공부하시는 노마드 코더 여러분 더욱 화이팅 하시구요.
멋진 강의와 챌린지 만들어주신 니꼬쌤과 린쌤에게 다시 한 번 감사드립니다. 🙏🏻
PS.
이 앱의 캔버스를 이용하여 정답으로 멋진 그림 그려주신 분께 스타벅스 커피 한 잔 쏘겠습니다 ☕️
슬랙에 Geony 태그해서 올려주세요 ~ 👍🏻