[FEDC] 원데이히어로 팀 프로젝트 회고

thru·2023년 12월 13일
1

FEDC-MIL

목록 보기
7/7

토끼가 마스코트인 건 제 의견이 아닙니다 (진짜아님)


원데이히어로

프론트엔드 데브코스 두 번째이자 마지막 팀 프로젝트로 백엔드 팀과 함께 협업을 진행했다. 대부분의 팀원이 백엔드와 프론트엔드 간 협업하는 기회가 많지 않았기 때문에 이번 팀 프로젝트는 양측 모두 기술적으로 의미가 있는 서비스로 기획을 잡았다.

원데이히어로는 알바 대타나 귀찮은 일을 대신해줄 사람을 찾아주는 매칭 서비스이다. 대신해줄 사람은 히어로라고 명명했고, 히어로를 찾는 사람은 시민, 시민이 히어로를 찾으며 올리는 게시글은 미션이라고 부르기로 했다. 히어로와 시민은 미션을 통해 서로 매칭을 진행할 수 있으며, 매칭 후에는 채팅으로 상의할 수 있다. 히어로가 미션을 수행한 뒤에 시민이 미션을 완료 상태로 변경할 수 있고 각자 리뷰를 남길 수 있다.

백엔드와 프론트가 협업하는 핵심 기능은 채팅, 소셜로그인, 알림으로 정했다.
프론트 위주의 기능은 게시글 작성, 검색, 지도 등이 있다.


개발이슈

처음 프론트엔드 팀이 만나고 프로젝트가 시작하기 전, Next.js를 사용 여부에 관해 논의를 했다. 나는 React 기반의 이전 프로젝트에서 페이지 단위 메타태그를 설정해보려다 성능 문제로 포기한 적이 있어 쓰고 싶은 마음이 컸다. 예전에 Next.js 공식 문서를 본 적이 있었기 때문에 팀원들을 설득했고 모두 호의적이라서 쉽게 결정되었다.

다만 프레임워크 선택에 있어서 더 구체적인 논의가 있었어야 했다. 이번 프로젝트에선 사실 이거 좋다는데 써봅시다 에 가깝게 의사만 뭍는 논의였다. 이후 멘토님의 커피챗에서 알게된 바로는 현업에서는 이런 툴을 선택할 때 미리 사용해보거나 예상되는 이슈 및 장단점을 정리해서 발표를 하는 경우도 있다고 한다.

Next.js 13

프로젝트 설정 당시 Next.js의 최신 버전은 13.5였다. 공식문서에 app router가 메인으로 나오니 큰 고민없이 선택했는데 13.4부터 안정화된 기능이라서 레퍼런스를 찾을 때 약간의 어려움이 있었다. 그러나 더 큰 문제는 라이브러리들의 호환성이었다.

MSW 대체품 찾기

백엔드 API가 완성되기 전 병렬적 개발을 위해 Mock API를 설정하려고 MSW를 시도했다. 그러나 app router와 MSW의 동작 방식이 충돌되는 부분이 있어 route handler를 사용해 대체했다.

해당 이슈는 별도의 포스팅으로 정리했다.

fetch API 추상화하기

fetch APITanstack Query 중 우리 팀은 fetch를 선택했다. 당시 Tanstack Query의 핵심 기능이 캐시라고 생각했는데 Next.js의 fetch도 캐시가 포함되어있으니 같은 역할을 수행할 수 있을 거라고 예상했다. 또한 MSW로 한번 고역을 겪은 후 라이브러리를 적용하는 것에 보수적인 자세를 가지고 있었다.

겁먹지 말고 둘을 비교해봤어야 할 부분이었다고 생각한다. 이번 프로젝트에서 블로킹이 되었던 작업 대부분이 fetch와 관련되어 나타났다.

처음에는 fetch를 그대로 사용했는데 빌드 시점에 오류가 발생하면 배포가 실패했다. 이는 불안정하다고 생각해서 오류 처리 로직을 포함해서 safeFetch로 추상화했다.

이후 POST 요청 등에서의 사용을 위해 useMutationalFetchsafeFetch의 바인딩된 객체를 반환하고 로딩 상태를 확인할 수 있도록 추상화했다.

위 두 내용은 별도의 포스팅에 세부 사항을 정리했다.

마지막으로 일부 API에 적용된 무한스크롤을 위한 useInfiniteFetch를 구현했는데 예상했던 것보다 신경써야 할 부분이 많았다. 처음에는 단순히 observer나 더보기 버튼 클릭으로 state 배열에 추가하는 기능만 구현했다. 그런데 프로젝트 스펙 중에 무한스크롤 내부 아이템의 상태가 변해야하는 좋아요 버튼과 제안 거절/수락 버튼이 문제였다. 버튼을 클릭하면 아이템의 바뀐 상태를 업데이트 해야하는데 Next.js의 router.refresh가 통하지 않았다.

router.refresh는 서버에서 fetch해 가져온 데이터를 다시 fetch해와서 업데이트하고 클라이언트 측 state는 유지하는 기능이다. 서버에서 가져온 목록 API와 다르게 무한스크롤 API는 데이터가 state에 담겨있으므로 router.refresh가 통하지 않는게 당연했다.

때문에 state에 저장된 배열을 새로고침하는 메서드도 추가해야 했다. 그런데 이 기능이 UX적으로 정상 작동하려면 스크롤 위치를 저장하는 기능도 필요했다. 해당 기능을 구현했는데 routing간에도 적용하지 않을 이유가 없어 추가로 또 구현했다. 결과적으로 계획과 달리 비대한 훅으로 구현되었다.

observer 사용법을 리마인드하기위해 간단히 구글링할 때 무한스크롤을 완성하려면 스크롤 위치 관련 기능도 구현해야해서 생각보다 난이도가 있을 거라는 글을 본 적이 있다. 그 땐 위치까지 구현하겠나 싶었는데 사실상 연결된 기능이 맞았다.

서버 컴포넌트

app router에서는 서버 컴포넌트와 클라이언트 컴포넌트라는 렌더링 방식이 도입되었다. 컴포넌트 내부에서 사용할 수 있는 기능이 분리되어 있기 때문에 기능 단위로 지정하는 것은 어렵지 않았다. 다만 컴포넌트의 세부 범위를 결정하는 것은 개발자의 재량이라서 고민이 필요했다. 제일 쉬운 방법은 페이지 전체를 클라이언트 컴포넌트로 사용해서 일만 React처럼 사용하는 것이다. 하지만 서버 컴포넌트는 초기 HTML에 포함되어 사용자의 로딩 체감을 줄이고 번들 사이즈를 줄이는 이점이 있기 때문에 최대한 활용하고자 했다.

위 예시는 채팅방 페이지이다. 채팅은 웹소켓 통신과 사용자 입력 이벤트가 필요한 클라이언트 쪽 기능이다. 채팅 기록은 children으로 넘겨서 서버 컴포넌트로 설정해 로딩 화면에서도 볼 수 있도록 의도했다.

헤더와 미션 링크도 서버 컴포넌트로 설정했는데 해더의 경우 케밥 메뉴 버튼은 클릭 이벤트가 필요해서 컴포넌트를 분리해서 클라이언트 컴포넌트로 설정했다. 서버 컴포넌트에서 클라이언트 컴포넌트로 함수를 인수로 전달할 수 없기 때문에 메뉴에 대한 행동은 필요한 데이터를 객체로 전달해서 설정했다.

export type KebabMenuDataType = {
  name: string;
  apiPath?: string;
  method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
  requiredData?: { name: string; default?: any; options?: any[] }[];
  description?: string;
  redirectTo?: string;
  refresh?: boolean;
};

소셜로그인

Next.js가 풀스택 프레임워크라는 것에 익숙치않아 생겼던 이슈로 NextAuth가 있다. 처음에 NextAuth가 Next.js에 최적화된 인증 라이브러리이고 토큰 접근을 서버와 클라이언트 양쪽에서 쉽게 할 수 있는 기능을 제공하길래 사용하려했다. 그러나 NextAuth는 우리 팀처럼 별개의 백엔드 서버에서 사용자 계정을 관리하려는 경우에 적용할 수 없었고 Next.js 자체 백엔드에서 유저 계정을 관리하는 기능만 제공하는 것으로 보였다.

아직 리프레시 토큰이 구현 전이라 엑세스 토큰은 서버와 클라이언트 접근을 위해 쿠키에 저장했는데 추후 변경해야 한다.

채팅

StompJS를 이용해 구현했다. 난이도가 있을 거라는 초기 생각과는 다르게 백엔드의 역할이 85%정도 되는 느낌이었다. 채팅 기능을 커스텀 훅으로 분리하고 관련 컴포넌트를 배치하는 작업이 주된 이슈였다.

fetch 캐시

마지막 주에 QA를 하는데 계속 DB 변경사항이 프론트엔드쪽 데이터에 바로 반영되어 보여지지 않는 이슈가 있었다. 원인이라고 볼게 fetch의 기본 기능인 캐시밖에 없었는데 아무리 관련 옵션을 조절해도 해결되지 않았다. 찾아보니 Next.js 이슈에 캐시가 revalidation되지 않는다는 글이 있었고 Next.js 13 버전의 버그로 판단했다. 리펙토링 시에 최우선으로 버전 업을 시도해보기로 했다.

Tanstack이 그립다


Keep

Next.js 사용 전 체험

Next.js를 선택한 이유는 두 가지가 있다. 첫 번째는 서비스의 타겟이 대타를 찾는 급한 사람이라는 점이다. Next.js의 캐시나 이미지 등 최적화 전략과 SSR 및 hydration으로 얻는 로딩 시간의 이점이 서비스 이탈율을 줄일 수 있으리라 생각했다. 두 번째는 학습적 목적이다.

그런데 사실 프로젝트에 사용할 프레임워크에 배워보고 싶다는 이유로 처음 써보는 것을 선택하는 건 위험성이 크다고 생각한다. 우리 팀은 이를 극복하기 위해 프로젝트 시작 전 1주일 간 Next.js playground 레포를 하나 파서 각자 하고 싶은 방식대로 Next.js에 친숙해지는 시간을 가졌다. 대략적인 기능과 서버/클라이언트 컴포넌트의 컨셉을 알 수 있었고 Next.js에 적응하는 시간을 앞당길 수 있었다.

이 과정을 겪었어도 첫 한달에는 삽질이 제법 많았다.

문서화

지난 프로젝트에서 서로 뭘하는 지 PR과 issue로만 파악했더니 세부 과정에 대해선 모르는 상태로 프로젝트를 마쳤다. 이번엔 각자 구현한 기능 중에 쉽게 이해되지 않겠다 싶은 부분은 깃헙 wiki에 글을 작성해서 서로 의도와 사용법을 공유했다.

문제 공유

지난 프로젝트의 아쉬운 점에 혼자 개발하는 것을 집었다. 이번엔 화면 공유나 vscode Live share로 팀원이 막혔을 때 적극적으로 도왔다.

다만 팀원 분들이 도움 요청에 거리낌이 적어서 매끄럽게 도울 수 있었다고 생각한다.


Problem

라이브러리 선택

Next.js는 선택 후 체험하는 과정을 거쳐 도입했지만 라이브러리는 그렇지 않았다. 구글링한 내용에 적혀있는 장점에 매료되어 도입을 시도했다가 철회한 경우가 제법 있었다. Next.js 13이라는 특수한 환경에서 개발하는 만큼 호환성을 상세히 찾아보고 공식 문서를 통해 기능을 정확히 이해했어야 했다.

과한 기획

이전 프로젝트를 마무리했다는 자신감에 이번 프로젝트 땐 개발해보고 싶은 기능을 맘껏 넣었다. 페이지는 30페이지를 넘어가고 처음 시도해보는 툴도 많았다. 우리가 간과한 점은 프론트엔드 인원이 3명이고 기획과 디자인도 맡아야 한다는 점이다. 막바지엔 갈려나가다시피 개발했고 고도화는 손도 못댔다. 비교적 빠르게 기능 구현이 끝난 백엔드에게 QA를 맡겨 겉으로 보이는 버그는 대부분 잡았지만 양쪽 같이 했다면 더 완성도 있었을 것 같다.


Try

Next.js 이해 높이기

Next.js를 사용한 다른 팀의 발표를 보고 미들웨어가 비로그인 redirection 처리에 유용하게 쓰인다는 걸 알았다. 이 외에도 서버액션이나 캐시처럼 활용하지 못한 기능도 있고 쿠키도 이해가 아직 부족하다고 느낀다.


profile
프론트 공부 중

0개의 댓글