[Assignment 3] RED BRICK(레드브릭) TIL
- 진행 날짜 - 2021.11.08 pm 16:00 ~ 2021.11.10 am 10:00
- 과제 필수 포함 사항
위즈랩은 학생들이 코딩에 재미를 느낄 수 있도록 간단한 게임을 코딩을 통해 만들 수 있는 플랫폼입니다.
게임을 만들기 위해선 다음과 같은 과정이 필요합니다.
- 회원가입
- 게임 제작하기 - 제작 중 단계의 게임을 '프로젝트'라고 합니다
- 게임 출시(퍼블리싱)하기
각 단계의 요구사항은 다음과 같습니다
- 회원가입
- 게임 제작
- 프로젝트는 '실시간'으로 반영이 되어야 합니다
- 예를 들어, 프로젝트 수정 중 의도치 않은 사이트 종료 시에도 작업 내역은 보존되어야 합니다
- 프로젝트는 '실시간'으로 반영이 되어야 합니다
- 게임 출시하기
- 프로젝트 당 퍼블리싱 할 수 있는 개수는 하나입니다. 퍼블리싱한 게임은 수정할 수 있어야 하며, 수정 후 재출시시 기존에 퍼블리싱된 게임도 수정됩니다
- 출시하는 게임은 다른 사용자들도 볼 수 있으며, 사용자들의 조회수 / 좋아요 등을 기록할 수 있어야 합니다
- '게임 혹은 사용자 검색'을 통해서 찾을 수 있어야 합니다
- 13팀 과제 Github 리포지토리
🏫 사용한 프레임워크 & 라이브러리
- Nest JS
- config
- supertest
- class-validator & class-transformer
- passport-local & passport-jwt
- mongoose
- socket io
💯 구현 목록
- 회원가입
✅ 회원을 생성하는 API
✅ 로그인 API
- 프로젝트
✅ 프로젝트 생성 API
✅ 선택한 프로젝트를 가져오는 API
✅ 프로젝트 편집 API
✅ 프로젝트 조회 API
✅ 프로젝트 삭제 API
- 게임
✅ 해당 프로젝트를 퍼블리싱하는 API
✅ 퍼블리싱된 게임을 검색하는 API
- 좋아요 / 싫어요
✅ 좋아요 API
✅ 싫어요 API
✅ 선택한 게임 데이터를 가져오고, 조회수를 증가시키는 API
- 기업이 제시한 문제
✅ 회원가입 ~ 게임 출시까지 필요한 테이블 설계
✅ 게임 제작하기에 필요한 API
✅ 조회수 수정, 좋아요 API
✅ 게임 혹은 사용자로 검색 API
✅ 프로젝트 실시간 반영을 위한 Architecture 설계
✅ 설계한 Architecture를 토대로 기능 구현
✅ E2E Test
✅ Unit Test
📋 Database Modeling
😎 Architecture
💭 Project Review
프리온보딩 백엔드 코스 3차 과제로 레드 브릭 기업에서 내주신 과제를 진행하였습니다. 레드 브릭은 현재 국내에서 누구나 쉽게 코딩하여 게임을 만들 수 있는 소프트웨어 교육 플랫폼인 WizLab을 운영하고 있는 기업입니다. 그래서 그런지 이번 과제는 실시간으로 반영되는 것에 초점을 둔 백엔드 서버를 구현하는 것이었습니다.
그런데 지난 과제들과는 다르게 조금 다른 점은, 어떤 데이터베이스를 사용하는지도, 어떤 API를 구현해야 하는지 구체적으로 명시되어 있지 않다는 점이었습니다. 처음에 과제를 받았을 때 무엇을 어떤 식으로 구현해야 하는지 명시가 되어 있지 않아서 당황스러웠으나 팀원들과 머리를 맞대고 해결법을 찾기로 하였습니다.
💬 프로젝트 실시간 반영
과제에서 볼드체로 중요하다고 표시되어 있던 실시간 반영을 어떻게 구현해야 할지에 대한 해답을 얻기 위해 구글 크롬의 개발자 도구를 사용하여 WizLab 서비스의 네트워크 통신 데이터를 뜯어보기로 했습니다. 프로젝트를 불러올 때, 생성할 때는 REST API 방식으로 서버와 통신하고 있었고 씬, 스프라이트, 블록, 코드 등을 수정할 때는 웹 소켓 통신을 사용해서 서버와 통신한다는 것을 알았습니다. 아래의 사진을 보면 클라이언트가 서버와 소켓으로 연결하고 수정할 때마다 JSON 데이터를 전송한다는 것을 확인할 수 있습니다. 그래서 저희 팀은 소켓을 사용하여 프로젝트를 실시간으로 저장할 수 있게끔 구현하기로 했습니다.
클라이언트가 없으면 소켓 테스트를 어떻게 하지라는 의문이 있었는데 다행히도 Postman에서 web socket 테스트 기능을 지원해주고 있었습니다. New 버튼을 눌러서 web socket 테스트 버튼을 눌러주고 주소를 입력한 다음 connect 버튼을 눌러서 서버와 연결을 활성화해줍니다. 그다음 전송할 데이터와 이벤트 이름을 작성한 다음 send 버튼을 누르면 됩니다.
💬 MongoDB & mongoose
이 과제는 데이터베이스를 어떤 것을 사용하라고 명시되어 있지 않았기 때문에 어떤 데이터베이스를 사용할지 팀원들과 많은 회의를 하였습니다. 긴 회의 끝에 저희는 비 관계형 데이터베이스인 MongoDB를 사용하기로 하였습니다. 왜냐하면 실시간으로 프로젝트를 반영할 수 있어야 한다는 조건이 있었기 때문입니다.
비 관계형 데이터베이스는 관계형 데이터베이스와는 다르게 스키마에 대한 정의도 없고 관계를 정의하지도 않습니다. 이러한 특성 때문에 데이터의 무결성을 보장하거나 탐색 속도가 빠르지는 않지만 확장성이 뛰어나며 유연한 데이터 저장을 할 수 있고, 관계형 데이터베이스에 비해 쓰기와 읽기 성능이 빠릅니다. 그래서 실시간으로 소켓 통신하면서 해당 프로젝트의 씬, 블록, 코드 등의 데이터를 전 송하 기는 데에는 관계형 데이터베이스보다 비 관계형 데이터베이스를 사용하는 것이 좋다고 판단하였습니다.
MongoDB와 같이 사용할 ODM으로는 mongoose를 선택하였습니다. 지난 1차 과제에서 TypeOrm을 사용했다가 낭패를 봤기 때문에 요번에는 MongoDB와 가장 잘 맞는 ODM인 mongoose를 사용하여 과제를 진행하였습니다. 덕분에 TypeOrm에서 발생했던 문제들은 발생하지 않아서 편하게 코딩할 수 있었습니다. 그러나...
💬 Maximum Call Stack Size Exceeded
프로젝트 마무리 단계에서 예상치 못한 문제에 부딪히게 됐습니다. 저희 팀은 소켓을 사용하여 실시간으로 저장하는 것을 구현하기 위해 프로젝트와 관련된 씬, 코드, 블록 등의 데이터를 한 번에 가져오고 업데이트하는 방식으로 collection 구조를 잡아두고 작업을 하였습니다. 문제는 이렇게 구조를 잡고 하면, 내부의 데이터끼리 서로가 서로를 참조하며 무한 재귀 현상이 발생한다는 것이었습니다.
처음에 각자 구현할 때는 아무 문제없어 보였으나, 각자 구현한 것을 합치고 데이터들을 정립해 나가면서 mongoose와 MongoDB에서 문제가 발생하게 되었습니다. 해당 문제를 해결하기 위해 stackoverflow에 나와있는 해결법들을 사용해보았지만, 이미 현재의 형태로 데이터를 주고받게 작업이 된 상태였고 제출 시 간이 얼마 남지 않았었기에 끝내 수정하지 못했습니다.
👩💻 반성점 OR 다음 프로젝트부터 고치고 싶은 것
열심히 만들고 완성했다고 생각했을 때 발생하는 오류를 보는 기분이란... 아무래도 처음에 설계할 때 잘못 설계해서 데이터를 가지고 올 때 순환 참조 오류가 발생한 것 같습니다. 비록 프로젝트 제출 시간이 얼마 남지 않아 고치지 못하고 제출하기는 했지만, mongoose에서는 이런 오류가 발생할 수도 있다는 것을 배웠고 좀 더 철저하게 설계를 해야 한다는 것을 깨달을 수 있었습니다. 만약 mysql을 사용했다면 mongoose에서 이런 오류가 발생할 수도 있다는 것을 깨닫지 못했을 것 같습니다. 요번 프로젝트도 다 같이 밤을 새우며 열심히 작업했는데 많은 아쉬움이 남습니다. 😭