본문 바로가기

트레이닝/42

[42seoul] Transcendence 웹 프로젝트

이제 프로젝트의 막바지에 다다르고 있다.(하지만 언제나처럼 끝날 듯 끝나지 않고 버그가 발견된다)

미리미리 각 작업할 때마다 진행사항이나 느낀점을 적었다면 좋았겠지만이제라도 적어본다

 

transcendence는 42라는 프로그래밍 과정 중 공통과정 마지막 과제이다 이전까지는 C언어의 시스템콜을 이용하여 OS의 주요한 부분들을 배우며 C++로 소켓 프로그래밍, C++컨테이너 만들기(제네릭 프로그래밍) 등을 하며 CS 전반적인 과정을 프로젝트와 옆의 동료들끼리 서로 물어가고 공부하며 진행해 왔었다.

 

transcendence는 웹과제로 로그인, 채팅, 게임 등의 기능을 구현하는 팀과제이다.

채팅 파트를 다른 팀원 두 분과 함께 총 3명이서 진행 중이며 직무 희망은 백앤드이지만
웹 전반에 대해 직접 만들어 보고 싶기도 하였고 궁금하였기에 프런트엔드로 참여하였다

과제에서 요구하는 기술 스택은 아래와 같다.

- Typescript framework (우리의 경우 svelte 선택)

- NestJS

- PostgreSQL

 

이렇게만 적으니 간단해 보이지만 Typescript(이하 TS) framework를 쓸려면 당연히 TS를 알아야 하고
TS를 잘 쓰려면 Javascript(이하 JS)를 이해하고 있어야 한다.

HTML, CSS에 대한 이해는 기본으로 들어가야 한다.


피곤하기도 하고 빨리 운동하고 자야 하니 위에 인트로 같은 이야기는 이만 줄인다
오늘과 요 근래에 적고 싶었던 것은
담당하는 채팅파트에서 효율적인 통신과 UX이다.

 

우리의 경우 socket.io를 사용하여 채팅을 구현하였다.

socket.io로 선정된 이유는 알고 있던 소캣(feat: 노마드코드 zoom clone coding) websocket, socket.io, webRTC 3개 중
websocket은 이전 버젼이고 socket.io가 더 발전해 있고 socket.io에서는 JSON parsing을 안 하고도 쓸 수 있으니 websocket은 선택지에서 빼었으며

 

주된 고민은 socket.io vs webRTC였다

socket.IO를 쓰면 서버를 거쳐서 클라이언트에게 전달해 주므로 서버에게 부하를 주게 된다.

그 외에 서버가 멀리 있는 경우 트래픽 비용이 커질 수 있다.

webRTC의 경우 클라이언트한테 부하를 전가시킬 수 있다.

서버는 처음에 클라이언트끼리 연결을 중개해 주는 역할을 하고 이후에는 클라이언트끼리 연결되어 있어서 서버 부하는 줄어든다. 하지만 클라이언트한테 부하를 전가시고, 클라이언트끼리 연결하므로 연결점이 서버를 거칠 때보다 많아지는 점이 있다.

 

우리의 경우 텍스트만 전송할 것이고 접속할 실제 클라이언트 수가 얼마 되지 않을 것이므로 

기능 제공이 더 많고 중앙에서 통제하는 방식의 socket.io를 선택하였다.

 

진짜 적고 싶었던 최근의 고민

DM 파트를 구현 중이었다. DM 채팅창을 켜지 않고서도 다른 유저로부터 오는 DM을 수신할 수 있어야 하므로 

store에 저장한(전역으로 저장) socket으로 메시지를 받고 local storage에 저장하는 방식을 선택했었다.

여기서 DM 채팅창을 켜었을 때에도 메시지를 받아서 화면에 뿌려주어야 하는데 

이미 client 다른 곳에서 수신한 DM 메시지를 


1. 어떻게 DM 채팅창 컴포넌트에서 메시지가 왔다는 것을 알아차리게 할 것인가였다.

 

 

 첫 번째 생각한 방식은 다른 파일에서 DM 메시지를 수신했을 때  커스텀 이벤트를 만들어서 DM 채팅창이 있는 컴포넌트에 이벤트를 보낸다는 생각이었다 하지만

socket.on이 있는 파일에서 커스텀 이벤트를 만들어서 보내는 것에 알 수 없는 에러들이 발생했다.

socket.on으로 DM 메시지를 받는 webSocketConnectionChat.ts에서 error가 발생하는 것이 아닌

DM 채팅창이 있는 컴포넌트의 try catch에 error가 발생했다.

webSocketConnectionChat.ts에서 커스텀 이벤트를 제거하면 에러가 발생하지 않았다.

어쩔 수 없이 우선 동작하는 것을 확인해야 다른 기능 테스트 및 추가 구현도 할 수 있으므로 비효율적이라는 것을 알지만두 번째 방법으로 서버에서 다른 이름의 소켓 이벤트를 만들어서 같은 데이터를 클라이언트의 DM 채팅방 컴포넌트로 보내게 했다.

 

즉, 서버에서는 같은 메시지에 대해서 같은 클라이언트한테 두 번 보내게 된다.

이 부분이 마음에 안 들었지만 일단은 실행되게 하고 리팩터링 하자는 마음으로 만들었다.

다행히? 당연하게도 DM 채팅창에서도 서버로부터 메시지를 수신하게 만들었으므로 두 명의 유저 모두 DM 채팅창을 켜놓고 메시지 보낼 때도 UI에 메시지들을 그릴 수 있게 되었다.

그러고 다음날 여전히 서버에서는 한 번 보낸 메시지, 이벤트에 대해서 굳이 네트워크를 타게 해서 트래픽을 늘리는 것과

만약 전송하는 데이터 크기가 크고, 거리가 지구와 달 혹은 더 멀리 우주처럼 먼 곳까지 통신해야 하는 것이었다면

그 비효율은 피부와 와닿다고 남고, 서비스를 쓰기 싫어질 만큼 문제를 주므로 마음에 들지는 않았다.
다시 한번 커스텀 이벤트를 구글링, 책을 다 동원해서 찾아보며 시도해 보았지만 어떤 이유로 동작하지 않는지 짐작하기 힘들 에러들만 만났다.

도저히 납득가지 않아서 소속되어 있는 42 커뮤니티에 글과 상황을 캡처해서 질문을 올렸다.

 

문제는 의외로 생각지 못한 부분에서 해결할 수 있었다.

socket.io는 event-driven-architecture로 되어있기에 

서버에서 1개의 소켓이벤트로 클라이언트에게 메시지를 보내도
클라이언트의 여러 컴포넌트에서 소켓 이벤트를 수신할 수 있었다!!!

당연히 1개의 이벤트에 대해서 클라이언트 측에서 수신할 수 있는 곳은 한 곳일 것이라 생각했는데 여러 곳에서 가능하다는 것이 나의 지레짐작으로 가지고 있던 편견을 깨주어서 흥미롭기도 하고 이런 짐작으로 문제를 제대로 정의해서 좀 더 나은 방법으로 빠르게 해결할 수 있던 기회를 놓친 게 아쉽기도 했다.

하지만 이렇게 가지고 있던 고정관념이나 짐작이 깨지는 게 프로그래밍의 재미이기도 하다.(자주 깨지면 현타 오지만)

 

 


2. 현재 채팅방 이름을 가지고 routing 주소를 만들고 있다. 채팅방 이름에 URL 파리미터나 유효한 토큰값들이 들어가면 
만들어진 채팅방으로 이동이 안 되는 이슈가 있다 ( / \? # 등등의 문자)

이 문제를 어떻게 해결할 것인가?

 

첫 번째 방법은 구글폼이나 다른 곳에서처럼 URL을 보면 %20 이런 식의 값이 여러 개 들어있는 것을 볼 수 있다.

그러한 URL 토큰값들을 함수를 이용해서 어떤 값으로 치환해서 처리하는 것이다.

채팅방을 생성하는 사용자 입장에서는 어떤 문자열 값이든 넣어서 생성할 수 있으므로 자유도가 있다.

하지만 테스트와 해시함 가 필요하고 채팅방 이름은 백앤드에서도 쓰므로 예기치 못한 에러들이 발생할 수 있어서 확인해야 하는 지점들이 많아진다는 단점이 있었다. 통합테스트를 하며 간간히 다른 디버깅 요소들도 나오고 있었기에 일을 키우지 않기로 하였다.

 

두 번째 방법 URL에 영향을 주는 토큰값들을 직접 걸러서 alert으로 알려준다.

여러 문자열 거르는 방식이 있는데 regex를 쓰기로 하였다. /[ ]/ 구문을 이용해서 처리하였고

URL에 영향주는 특정 파라미터 토큰값이 채팅방 이름에 있으면 alert을 띄우는 식으로 처리하였다.

이렇게 만들어서 PR을 보냈지만 팀원분이 다른 의견을 주었다.

 

세 번째 방법. 변수 네이밍처럼 특정 값들만 받게 하고, 특수문자의 경우 아예 입력창에 입력조차 못하게 만들자.

이렇게 하면 alert을 따로 띄울 필요가 없어서 직관적이라 생각했다.

키보드 입력이 될 때 이벤트가 발생하게 하여 입력값을 확인하게 하였다.

이로써 조금 더 불필요한 alert을 줄이고 구현될 수 있었다.

 

어떻게 보면 문자열 입력에 대한 유효성 검사로 간단한 부분이었지만 

이 작은 부분에서도 어떻게 하는 게 사용자에게 편리할지 혹은 구현자에게 편리할지

누군가에게 편하다고 하더라도 어떤 점에 편리한지,

그리고 같은 결과이더라도 어떻게 사용자에게 부드럽게 알릴지 생각하고 느낄 수 있었다.

문제해결에는 다양함이 존재하는 것을 다시 느낄 수 있었고 어떻게 하면 그런 다양한 접근을 할 수 있을지 고민해 볼 수 있었다.

일단 바로 떠오르는 방법으로는 문제를 잘 정의해서 다른 이에게 질문하는 것이 떠오른다(gpt포함)

그 외에는 내가 다른 사람이라 생각하고 이입해서 해볼 수 있을 거 같지만 애초에 생각이 다른 이에게 물어보는 것이 더욱 빠르고 효과적일 것이라 생각 든다.

'트레이닝 > 42' 카테고리의 다른 글

[42seoul] Webserv 후기  (0) 2023.04.17
[STL|Container] 이 과제는 무엇인가  (0) 2023.01.19
[Inception] intro  (0) 2022.12.25
[STL|Container] 공부해야할 것들  (0) 2022.12.11