TLDR
주절주절이라 해결 방법을 구하려는 분께는 별 도움 안되는 아티클입니다.
리액트로 리빌딩하기
React로 뭘 만들어보자고 하고 이전에 바닐라 자바스크립트로 만들었던 웹 앱을 리액트로 다시 만들었다. 먼저 하고 있는 서비스를 정상적으로 동작 시키기까지 많은 우여 곡절이 있었다.
쿠키와 Same Site 옵션
일단 쿠키에서 문제가 발생했다. CSRF 공격을 예방하기 위해서 토큰을 사용했었다. 히로쿠에서 클라이언트와 서버를 따로 만들어서 동작을 시키자 동작을 하지 않았다. 쿠키를 정상적으로 주고받지 못했기 때문이었다. 경고 메시지를 보면 Same Site 옵션이 문제였다. 브라우저에서 Same Site가 true이거나 lax이면 도메인이 다른 서버에서 클라이언트에 쿠키를 발행해주지 않았다. 그래서 옵션을 none으로 변경했고 잘 동작하는 줄 알았다. 그런데 로컬에서만 동작하고 배포 환경에서는 동작하지 않았다.
이것 저것 찾아보다보니 유튜브에서 🎥라매개발자의 Heroku에 React + Express 서비스 자동 배포하기 (HM #1)이라는 컨텐츠를 찾을 수 있었다. 이전에 찾았던 글도 많았지만 이렇게 설명을 잘하는 컨텐츠는 없었다. 덕분에 클라이언트와 서버를 한 도메인에서 동작시킬 수 있었다. 쿠키 문제는 해결 되었다. 하지만 문제가 완전히 해결됐다고 볼 수 없다. 왜냐하면 어플리케이션이 꼭 Same Site에서 동작하라는 법은 없기 때문이다.
동영상을 보고나서 나에게 아쉬운 점이 생겼다. package.json에 script 명령어를 작성하는 방법은 알았지만 명령어 하나하나의 의미는 모르고 그냥 앵무새처럼 따라하기만 했다. 그리고 히로쿠가 start명령 후에 60초 안에 서버 빌드에 성공하지 못하면 실패가 된다는 것도 처음 알게 되었다. 내가 사용하고 있는 어플리케이션 환경에 대해서 잘 이해를 못한 상태로 사용해보고 동작하면 넘어가는 식의 학습이 이제 한계에 도달한 듯 했다. 그래서 개발 문서를 천천히 읽어보는 습관을 기르기로 했다. 이전의 뿌리 깊은 습관을 고치는게 너무 어렵다.
앤드 포인트 에러
테스트로 배포를 하고난 뒤에 동작이 CSRF 토큰은 해결이 되었다. 하지만 새로고침을 했을 때 클라이언트 페이지를 보여주지 않고 서버에서 앤드포인트가 없을 때 보여주는 에러가 브라우저에 출력되었다. 왠지 익스프레스의 :id를 인식할 때 순서때문에 발생하는 문제같아 보였다. 그래서 클라이언트의 페이지를 불러오는 앤드 포인트를 이리저리 옮기다가 서버의 앤드포인트 뒤로 이동시키자 더이상 의도하지 않은 동작이 발생하지 않았다.
수정한 코드
의도대로 동작하지 않는 딥 링크
웹 앱에서 성경 어플리케이션을 열고 싶었다. 이전에 웹으로 연결하던 페이지는 반응형으로 구현이 안되어있어서 모바일 환경에서 너무 불편했기 때문이다. 📄딥 링크를 구현하는 방법은 쉽게 찾을 수 있었다. 하지만 그 다음이 문제였다.
나의 로직은 어플이 있으면 실행하고 없으면 설치 하겠냐는 메시지를 보여주고 하고싶지 않으면 웹으로 연결된다. 딥 링크가 동작을 하면 다음 코드가 동작하지 않는다고 했는데 그냥 순차적으로 모든 함수를 다 실행시켰다. 해결을 하고 싶어서 하루 종일 핸드폰을 붙잡고 개발, 배포 환경을 왔다 갔다 하면서 테스트를 했지만 원하는 대로 동작하지 않았다. 밤을 세우고 나서 블로그 발행인 분께서 남겨주신 댓글을 보고 좀 절망을 했다. 어플이 열리고 난 후 이후 로직을 막을 방법이 없다고 했다. 사용자는 이런 사소한 것에도 불편을 겪을텐데... 어플리케이션의 완성도가 떨어지는 것 같았다. 어플로 연결하겠냐는 버튼을 하나 따로 만들어야 할 듯 했다.
요즘은 버튼을 하나 만드는 것도 부담이 된다. 예전이라면 그냥 하나 만들어서 붙였을 텐데 이젠 고민이 된다. 버튼 하나가 늘어나는 것은 상당한 부담이다. 클라이언트 환경에서 관리해야할 상태가 하나 더 늘어나는 것이라 매우 고민된다.
프로젝트는 하나만 잘 하자
팀 프로젝트는 꽤 순탄하게 진행되고 있지 않다. 내가 애초에 생각했던 팀플과 좀 거리가 멀었기 때문이다. 물론 백앤드 개발자와 많은 이야기를 나누면서 배우는게 많다. 하지만 프론트 앤드 개발자와 많은 의견을 공유할 수 없는 상황이 되었다. 함께 치열하게 고민하고 의견을 나누는 환경을 만들고 싶었지만 어쩔 수 없는 것 같다.
그래서 좀 질리다보면 앞에서 언급한 어플리케이션에 시간을 쏟게되고 그러다보니 에너지가 분산되서 결국 제대로 하는건 아무것도 없는 환경이 되고 말았다. 어제 밤을 세우다가 '이게 뭐하는 걸까.'라는 생각을 하게 되었다. 내가 몇십년 경력을 가진 시니어 개발자도 아닌데 너무 무리한 모험을 하는게 아닐까? 지엽적인 것에 너무 치중하는 것 같다. 뒤를 돌아보니 나 스스로가 너무 안일했던 것 같다. 시간 예산을 제대로 세우지 않아서 위기 관리가 잘 되지 않는 것 같다. 조금 질리더라도 내가 하기로 한 것은 그 시간에 꼭 해야겠다.
비동기 상황에서 상태 관리
우아한Tech에서 🎥React Query와 상태관리 :: 2월 우아한테크 세미나를 보았다. 일단 보면서 느낀건 상태나 상태 관리가 뭔지 개념은 잘 정리되어 있는 것 같았다. 하지만 기술적으로 구현을 하는 것은 혼란스러웠다. 이런 경우를 보고 '이해하지 못했다.'라고 말한다. 비동기 상황에서 상태 관리는 나를 혼란스럽게 한다.
일단 예로 하나만 들어보면 지금 앞에서 개발한 교회 어플리케이션의 조회수 로직이 망가져버렸다. 컨텐츠를 로딩하는 방법이 바닐라 환경과 완전하게 다르기 때문이다.
바닐라 환경에서는 리스트를 보여주는 앤드 포인트와 개별 아이템을 보여주는 앤드 포인트가 따로 있었다. 그래서 /item/:id로 접근을 하면 조회수를 일정 시간 내에서 1씩 올려주었다. 하지만 어플리케이션을 리액트로 바꾸면서 클라이언트와 서버간의 소통 방법이 마음에 안들었다. 두 앤드포인트는 데이터의 숫자만 다를 뿐 똑같은 데이터를 클라이언트에 보내준다. 덕분에 서버에 요청을 매번 보내기 때문에 너무 느렸다.(화면이 깜박인다) 그리고 더 마음에 안드는 건 사용자가 이미 받은 데이터가 있는 화면에 돌아와도 캐싱이 되지 않아서 다시 서버에 데이터를 요청하였다. 너무 비효율적이었다. 사용자가 얼마 되지 않아 부담이 안되어보이는 것일 뿐이었다.
그래서 React Query를 사용해서 서버에 데이터를 요청하면 사용자는 데이터를 전부 받아온다. 그 후에 캐싱된 데이터를 사용해서 개별 아이템을 보여주게 했다. React Query에서는 캐싱된 데이터를 얼마나 가지고 있을지 옵션을 줄 수 있다. 그래서 초기 로딩 속도가 1-2초 정도 걸린다. 이것도 정말 느린 듯한 느낌이다. 하지만 로딩 메시지를 보여주어서 간극을 매꿨다. 하지만 이후에는 캐싱된 데이터를 가지고 사용자에게 화면을 보여주기 때문에 더이상 깜박임이나 로딩은 표시되지 않는다.
말이 길어졌는데 문제는 /item/:id 앤드포인트가 없어졌기 때문에 조회수를 어떻게 올려야하는지 고민이 되었다. 조회수를 올려주는 앤드포인트를 하나 다시 만들어야 할까?
- 사용자가 프론트에 접근하면 조회수를 1 올려주고 그 값을 서버와 비교해서 증가했다면 증가했다고 서버에 알려주어야하는지 다른 방법이 있는지 모르겠다.
- 같은 시간에 조회수가 0인 게시물을 2명의 사용자가 눌렀을 때, 프론트에서는 분명 1로 변경될 것이다. 그럼 서버에서는 조회수를 어떻게 3으로 변경할 수 있을까?
- 누군가 조회수를 1 올렸다면 클라이언트에 어떻게 조회수를 반영해야할까? 시간 간격을 두고 서버에서 데이터를 다시 받아와야 할까? 그러면 앞에서 변경한 로직을 전부 변경해야할수도 있다.
- 사용자가 여러번 요청을 했을 때, 마지막 요청만 서버에 보내도록 하는 방법은 무엇이 있을까? 클라이언트에서 throttle로 제어를 했다고 해도 서버에서는 이걸 어떻게 알 수 있을까?
- 마지막으로 요청을 실패하게되면 어떻게 처리해야하나?
주절 주절 썼지만 구현 하면서 부딪쳐야 알 것 같다. 어쨌든 비동기 상황에서 상태 관리를 어떻게 해야하는지 고민이다. 지금은 React Query로 서버 데이터를 가져오고 Recoil에 저장해서 변경된 데이터를 따로 관리하고 있다. 하지만 selector라던가 mutation을 했을 때의 방법에 익숙하지 않다. 할꺼 많아서 좋겠다.
마무리
오늘은 시간을 내서 지금까지 했던 것을 주절주절 정리해봤다. 비동기 상황에서 상태 관리를 하는 방법은 나름대로 해법을 찾아야할 것 같다. 그럼 이만 아디오스.