(8주차 ~ 11주차)
끝나지 않을 것 같던 항해의 마지막 실전프로젝트도 끝을 향해 달려가고 있다. 확실히 디자이너 분들과 협업을 진행하다보니 디자인을 위한 디자인에 의한 기능들을 빼놓을 수가 없었다. 가끔 이렇게 까지 해야할까라는 생각이 들때가 있지만, 프론트 개발자라면 이 모든 과정도 사용자를 위한 배려이자 서비스 정신이겠다는 결론이다. 기본적인 MVP 기능을 완성한 뒤 디자이너분들과 피드백을 주고받으며 기능을 추가하거나 디버깅을 진행하고 있다.
피드백을 진행하면서 정말 다양한 에러와 마주했다. 예외처리를 하는 일도 정말 손이 많이가는 일이라는 걸 느꼈다. 그러면서 에러 바운더리에 관한 내용을 접하게 되었는데, 최근 에러 처리에서 중요한 개념이라는 것을 알게되었다. 이번 프로젝트에서 적용을 하기엔 이미 짜여진 에러처리 과정이 있어서, 이후 프로젝트를 진행하게 된다면 적용해 볼 예정이다. 디버깅 내용으로는 타입에러 혹은 리턴 값을 제대로 주지않아서 생긴 간단한 것부터 훅과 관련한 에러까지 다양했다. 그 중 가장 고생했던 두 상황은 다음과 같다.
일반 window 알럿으로는 감당이 되지 않았던 알럿 디자인을 해결하기 위해 스윗알럿을 적용하게 되었다. 자체적으로 모달을 만들어서 사용하기에는 코드량이나 재사용성을 고려하였을 때 무리가 있다고 판단을 하였고 다운로드 수, 브라우저간 호환성, 지속적인 모니터링, 자유로운 커스텀 등의 기준으로 봤을 때 스윗알럿2가 가장 우리 프로젝트에 적합하다고 판단 되어 적용하게 되었다.
문제의 발단
우리 서비스 내에는 채팅 추가 기능에서와 같이 confirm 확인 이후 서버와 통신을 해야하는 파트가 있었다. 라이브러리 문서 내에서 ajax 콜을 할 수 있다는 내용은 포함되어 있었지만 그것을 바로 우리 프로젝트에 적용하기 힘들다는 판단이 들었고, 기존 post 모듈 내에 작성되었던 미들웨어에 디스패치로 접근하는 것이 그 동안의 패턴이었기에 알럿에서도 디스패치를 당연히 써야한다고 생각했다.
문제의 원인
하지만 스윗 알럿을 작성해둔 모듈은 함수형 컴포넌트가 아니었고 react hook을 사용할 수 있는 구조가 아니었다. 이때 정말 다양한 에러와 마주하며 hook rules break와 관련한 에러 메세지를 접했다. hook은 함수형 컴포넌트일때, 최상위에서만 호출 된다는 규칙에서 자꾸 에러가 발생했다.
해결 과정
문제의 발단
앞선 난관은 스윗 알럿 내에서 axios 요청을 하며 일정부분 문제가 해결 된 것 처럼 보였다. 하지만 얼마 가지 않아서 모듈에서 모듈별 미들웨어로 관리되어야할 axios요청들이 무분별하게 스윗알럿 컴포넌트에서 불려지고 있었고, 요청 이후 리덕스로 관리할 데이터가 생기자 처리가 되지 않는 문제가 발생했다. 결국 코드의 재사용성과 데이터 관리 부분만 보아도 이전에 시도한 방법이 best practice가 아니었다는 것을 알 수 있는 대목이었다.
문제의 원인
재사용성이 불가능하게 된 원인은 confirm 이후의 과정을 제대로 핸들링하지 못했다는 것이었다. 결국 사용자가 확인, 취소, miss를 행동을 했을 때, 그 이후 행동을 다룰 방법을 찾지 못했다. 임시방편으로 하다보니 특정 상황에 맞는 특정 알럿을 모두 만들어야하는 상황까지 간 것이었다. 따라서 스윗 알럿을 호출한 뒤 이후 행동을 이어나갈 수 있는 방법을 찾아야했다.
해결 과정
그러다 문득 임포트해서 사용하고 있던 스윗 알럿이 true, false를 반환 한다면 이 값을 이용해 이후 동작을 결정 지을 수 있겠다는 생각이 들었다.
채팅에 기능을 추가하게 된 배경은 효과적으로 트롤러를 관리하기 위해서이다. 단순 채팅 기능 이외에 추가하게 된 기능은 다음과 같다.
채팅 기능을 추가하는 과정에서도 역시 다양한 버그에 부딪혔지만 그 중 가장 기억에 남는 이슈 두 가지는 실시간 강퇴 기능 구현과 웹소켓 간헐적 끊김 현상이었다.
강퇴 기능 구현배경
승인 거절, 수락과 채팅방 내 방장에게 강퇴 권한을 부여하여 강퇴를 시킬 수 있게 한 이유는 악성 유저를 사용자들 스스로 필터링할 수 있게 하여 사용자들이 조금이라도 더 안전한 환경에서 서비스를 이용할 수 있게하기 위해서이다. 이때 실시간으로 강퇴를 시켜야 했던 이유는 악성 유저가 채팅에 참여 중이지 않을 수 있지만, 실시간으로 채팅에 참여 중인 상황이라면 방장이 강퇴를 한 그 순간에 강퇴 당한 사용자가 채팅방 밖으로 퇴장당해야만 해당 기능이 의미가 있기 때문이다.
문제의 원인
처음 이 기능이 까다롭다고 느낀 것은 한 가지 기능에 총 3가지의 유형이 있어 구조가 복잡했기 때문이다. 먼저 방장은 참여자를 내보낼 수 있어야했고, 강퇴를 당한 유저는 채팅방 밖으로, 남아있는 유저와 팀장의 채팅방 참여 인원에서는 해당 유저를 삭제해줘야 했다. 그러기 위해서는 각각의 아이디 정보를 구분해야 했고 관련 데이터를 관계를 웹소켓 상에서 정리하는 것이 어려웠다.
해결 과정
처음에는 문제에 접근하는 방식을 가늠하는 것 부터 어려웠다. 그 이유는 웹소켓이 실시간 채팅이라는 기능에 초점이 맞추어져있어서 메세지를 주고받는 것 이외의 행동을 하게 할 수 있다는 생각을 하지 못했기 때문이다. 이후 실시간이라는 개념에 초점을 두고 생각을 발전시켜보니 스톰프 센드를 할 때, 유저의 정보를 보내주고 받는 메세지의 모듈에서 메세지로 넘어온 아이디와 접속 중인 유저 본인의 아이디를 비교하게 되면 실시간으로 어떤 행동을 이끌어 낼 수 있지 않을까하는 접근을 하게되었다.
이 과정에서 임머 불면성에 관련한 에러도 접하게 되었는데, 대략적으로 설명하자면 값을 리턴하던지 draft 변경을 하던지 둘 중 하나만 하라는 내용이었다. 실시간으로 행동을 이끌어 내려다보니 하나의 리듀서에 너무 많은 조건을 주게 되면서 코드가 엉켰고 그 때문에 발생한 에러라고 생각된다. 그러면서 리듀서의 순수 함수와 예측가능한 상태라는 개념에 관해 생각하게 되었는데 아직은 완벽히 이해 되지는 않지만 앞으로도 계속해서 고민해 볼 부분같다.
참고 자료
리덕스의 리듀서가 순수 함수여야만 하는 이유
이러한 고민과 접근 이후에 완벽하지는 못해도 원하는 기능을 구현 할 수 있었고, 스톰프 메세지를 주고 받는 개념을 이용하여 채팅 메세지를 보내는 함수 이외에 강퇴, 방폭을 할 수 있는 함수를 작성하여 기능을 추가 하게 되었다.
> 에러 메세지 내용
useState Hook을 통해 state값이 변하거나 Action을 실행시키는 dispatch가 동작할 때 렌더링이 일어나는 사실에 대한 정확한 이해가 부족하여, 과도한 리렌더링으로 인한 주요 채팅 기능의 오작동을 야기했다.
현재는 onChange 마다 실행되던 dispatch 와 액션 부분을 삭제하였고, 그 대신 useRef의 defalutValue값을 소켓 메세지 함수의 파라미터로 사용하고 있다.
웹 소켓 끊어짐 현상이 해결되었고, 채팅 입력시 input의 text 밀림 현상 및 채팅 속도가 개선 되었다.
문제 발견 과정
사이즈가 큰 이미지의 경우 프로필 수정 이후 이미지 렌더링 되지 않는 현상 발생
프로필 수정 api 요청의 응답이 페이지 렌더링 속도에 미치지 못하였다.
api 요청 전 페이지 이동이 되면서 수정 액션이 실행되지 않았음을 확인 하였다. (api 요청 응답 없음)
해결 과정
비동기 처리 순서에 문제가 있다고 생각해서, api 요청이 완료되기 전까지 로딩 처리를 하였고, 로딩이 완료 된 후 확인 알럿 처리를 하였다.
그럼에도 불구하고 로딩이 너무 오래 걸리는 현상이 발생하여 서버에 올려주는 이미지의 용량이 매우 큰 것이 문제라고 판단하였다.
이미지 리사이징 라이브러리를 통해 서버로 api 요청 전 리사이징 된 이미지를 넘겨주었다.
결과 및 소감
큰 용량의 이미지를 업로드 해도 최대 사이즈가 300px을 넘지 않게 되었고, 처리 속도가 향상 되었다.
이전까지 서버에서 이미지 리사이징을 해왔지만 이것을 계기로 프론트 단의 처리가 필요함을 느꼈다.