팀프로젝트 | 🏄🏻‍♂️ 내 인생 성장곡선 사이트: Surf

noopy·2022년 1월 4일
2
post-thumbnail

개요

Surf 소개

기록을 통해 나만의 성장곡선을 만들어나가는 서비스.

기획 배경 및 동기

열심히 달려온 나 자신! 열심히는 하고 있는데 내가 얼마나 발전했는지 기록하는 공간은 없을까?
그냥 일기는 메모장에라도 적을 수 있고, 블로그는 이미 무수히 존재하고, 색다른 방법으로 동기부여 받고 기록하고 공유하는 그런 공간이 필요해! 🙆‍♀️

  • 성장곡선으로 한눈에 내 인생을 돌아보기
  • 남들의 성장곡선을 보며 동기부여도 받기
  • 곡선의 특정 구간마다 기록도 남기기
  • 곡선이 아닌 기록들만 모아서 보기
  • 필요하다면 포트폴리오로도 사용 가능하기

🪞 Surf 데모

로그인메인 화면 - Surf 첫 페이지메인 화면 - 특정 category 선택
게시글 작성무한 스크롤마이 페이지 - 내 정보 수정
대시보드카드 페이지카드 페이지 - 해당 월별 기록 리스트
마이 페이지에서 이동연도별 필터링, 해당 달의 작성 일수 확인 가능카드 선택시

작업 기간

2021-11-22 ~ 2021-12-23

기술 스택

FE

  • Next.js@12.0.4
  • swr@1.1.0
  • emotion/styled@.11.6.0
  • axios@0.24.0
  • storybook@6.4.0
  • yarn@1.22.17
  • vercel

기타 라이브러리

  • react-apexcharts@1.3.9
  • dayjs@1.10.7
  • emoji-picker-react@3.4.8
  • js-cookie@3.0.1
  • material-ui/core@4.12.3
  • react-lottie@1.2.3
  • react-icons@4.3.1
  • react-toastify@8.1.0
  • react-flicking@4.4.3

주요 구현 사항

😎 👈🏻 내가 구현하거나 참여한 사항들

  • 메인 페이지
    • 일년치 성장수치 데이터를 받아와 분기별로 필터링
    • 각 카테고리(성장곡선)별 그래프, 하단부 기록 필터링
    • 즐겨찾기 추가, 취소
  • 둘러보기 페이지 😎
    • 10개씩 데이터를 받아 무한 스크롤 구현
    • 팔로우, 좋아요 추가, 취소
  • 기록 추가 페이지 😎
    • 클릭, 혹은 드래그 앤 드롭으로 파일 추가
    • 카테고리 드롭다운
    • 카테고리 추가
    • 달력 구현
    • 드래그/버튼 클릭으로 성장수치 변경
    • 내용 추가
  • 마이 페이지
    • 팔로워, 팔로잉
    • 자기소개 표시/수정
    • 성장곡선 그래프 표시
    • 일년치 잔디 표시
  • 대시보드 페이지
    • 전체 카테고리 개수 표시
    • 평균 성장수치 표시
    • top 3 성장곡선과 평균값 표시
    • 일년치 잔디(surfing stat) 표시
    • 각 카테고리 평균 점수 및 기록 개수 표시
  • 전체카드 페이지
    • 년도별 카드 슬라이더
    • 오늘 날짜 클릭 시 이번달 카드로 돌아오기
    • 해당 달의 기록 수 표시
    • 카드 뒤집어 해당 일의 기록 작성했는지 표시
  • 월별 카드 페이지
    • 월별 데이터 받아와 뿌려주기
    • 즐겨찾기 추가, 취소
  • 기록 상세 페이지
    • 일별 데이터 받아와 뿌려주기
    • 이미지와 파일 분리해 보여주기
    • 이미지/파일이 없을 경우 표시
    • 기록 수정, 삭제, 즐겨찾기 추가
  • 카테고리 수정 페이지 😎
    • 카테고리 데이터 받아와 뿌려주기
    • 카테고리 추가, 수정, 삭제
  • 로그인, 회원가입 페이지 😎
    • 회원가입 후 쿠키에 token 저장
    • 회원가입 후 자동 로그인으로 메인페이지 이동
    • form validation 적용
    • 로그인, 회원가입 후 스플래시 스크린 구현

드디어 한달 여간의 Surf 팀 프로젝트가 끝났다. 이전까지는 멘토님께서 만들어주시는 완성된 API를 가져다 썼다가 처음으로 프론트와 백엔드가 한달 동안 A부터 Z까지 다 만들다보니 여러가지 시행착오를 겪었던 프로젝트였다. 그럼에도 불구하고 한달 간 열심히 달려와준 팀원분들 덕분에 결과물을 낼 수 있었던 것 같아 감사하다. 그럼 중간 회고록을 제외하고 최종 회고록에선 여러가지 여러가지 시행착오들에 대해 설명해보려 한다.

시행착오

메인 페이지

1. 라이브러리 잘 파악하기

우리의 핵심인 성장곡선을 표현하기 위해 Apexcharts 라이브러리를 사용했다.

TOAST UI의 chart와 고민했는데 아무래도 사용자수가 더 많고 다양한 프레임워크를 지원한다는 점에서 Apexcharts를 골랐다. UI도 좋고 공식문서 설명도 잘되어 있어 좋았지만, 우리가 간과했던 점은 두가지이다.

- 데이터가 많아질 때 차트가 어떻게 보일 것인가

Apexcharts 라이브러리의 예시들은 데이터가 큰 간극이 없고, 수치가 많지도 않아서 부드럽게 보였다. 그러나 실상은 Mock 데이터로 사용자가 거의 매일 기록을 올린다 가정했을 때 데이터가 많고 간극이 클수록 뾰족하게 보여 차트가 예쁘지 않았다 🥲.

-차트가 겹칠 때 어떻게 보일 것인가

여러 개의 성장곡선이 존재하고 데이터가 다른 성장곡선의 데이터보다 낮아서 감싸는 구조일 경우 겹칠 수록 보이지 않았다. 이부분은 투명도를 높이거나 테두리를 두껍게 해서 해결할 수 있을 것 같다. 밑에 gradient도 없애는 게 좋을 것 같다.

이런식으로 바꾸더라도 어느정도 겹칠 경우 차트가 잘 보이지 않는다는 문제가 있다. 셀렉트박스로 특정 차트만 선택할 수 있지만 애초에 차트가 명확히 보이지 않는 문제를 해결하지는 못한 것 같다.

2. 레이아웃 잘 선택하기

한달동안 기획부터 API 설계, 배포까지 진행해야 했고, 만들어야 할 페이지가 많다고 판단되어 모바일 사이즈만 만들기로 결정했다. 하지만 모바일 사이즈에선 차트가 너무 작아 잘 보이지 않았다. 애초에 기본적으로 제공해주는 차트 사이즈가 제한되어 있어 맘대로 키울 수가 없는 문제도 있었다.
가장 베스트는 달마다, 분기마다, 년마다 보이도록 UI를 짜는 것이었으나 시간부족으로 구현할 수 없을 것 같다는 생각에 빠르게 포기했다. 대신 처음 접속 시 일년치 데이터를 보게 한다음 사용자가 분기마다 차트를 볼 수 있도록 변경하여 차트를 좀 더 세부적으로 볼 수 있는 기능을 제공하였다.
또 필터링 기능은 프론트와 백 모두다 구현할 수 있기 때문에 백엔드쪽 부담을 줄이고자 처음 년도별 데이터만 받은 후 프론트에서 분기로 필터링하기로 하였다.


- 처음 일년치 데이터를 한번에 보여줬을 때

- 분기로 나눴을 때

- 특정 구간을 클릭하거나 hover 했을 때

모바일 화면에서 모든 성장 수치가 툴팁으로 보여지는 건 전체적인 성장곡선을 보기 힘들고 UX적으로 좋지 않을 것 같아 사용자가 클릭했을 때만 보이도록 만들었다.

메인 페이지에서 추가 구현하기

  • 필터링된 하단부 기록 무한 스크롤 구현
  • 분기를 클릭하지 않았을 때엔 Q1이 아닌 Year 등이 보이도록 수정
  • apexcharts 기능인 그래프 다운로드 설정 활용해 포트폴리오로 활용가능하게 하기
  • 첫 유저에겐 사용방법을 알려주기

둘러보기 페이지 😎

둘러보기 페이지는 타인과 소통할 수 있는 핵심적인 공간이다. 팔로우좋아요를 누를 수 있고 성장수치기록도 볼 수 있다.

10개씩 데이터를 불러와 기존과 합치기

백앤드에서 10개씩 데이터를 보내주면 스크롤할 때마다 기존 데이터와 합쳐서 누적시키는 작업을 진행했다.
swr로 get 요청을 처리하기 때문에 초기 cursorId=0을 제외하곤 받아온 데이터의 마지막 postId가 바뀔 때마다 자동적으로 데이터를 fetching 시켜준다.

문제는 interceptor Observer API와 useState가 비동기로 처리되기 때문에 타겟이 하단부에 닿았을 때엔 useState의 마지막 postId 값을 인식하지 못해 일시적으로 빈배열이 출력되었다.

이를 해결하기 위해 target이 intersecting인 시점엔 cursorId만 설정해주고 실제 postId값을 바꾸는 것은 useEffect로 분리하여 작업하였다.
즉, 컴포넌트가 리렌더링되더라도 새로고침되지 않도록 useRef로 postId를 설정하고 target이 intersecting한 시점엔 postId.current 값을 setState 해주었다.

useEffect의 감시대상을 swr가 받아온 데이터(recentPosts)로 설정해 recentPosts가 바뀔 때마다 postId.current값을 변경해주었다. 빈 배열이 아닐 때만 postId를 변경하도록 하여 마지막 postId를 할당할 수 있도록 확정할 수 있었다.

data fetching의 흐름
1. target이 intersecting됐을 때 postId.current값이 cursorId가 됨
2. swr의 키값(cursorId)이 변경될 때마다 data를 fetching 함
3. useEffect가 swr이 받아온 데이터가 변경될 때마다 기존데이터와 누적시키고 postId.current값을 변경함
4. target이 intersecting됐을 땐 누적된 데이터의 마지막 postId가 저장된 상태이므로 데이터를 잘 불러올 수 있음.

기록 추가 페이지 😎

기존 컴포넌트를 수정할 땐 독립적으로 설계하기

기록 추가 페이지는 Upload, Dropdown, DatePicker, ScoreSlider, Textarea 등 다양한 컴포넌트가 조립되어 만들어진 페이지이다.
처음 개발에 들어갈 때 가장 기초단위인 base 컴포넌트들을 만들고 시작했는데, 하나의 페이지를 만들 때 기존에 만들어놨던 컴포넌트들을 조금씩만 수정하여 쉽게 제작할 수 있어서 추후 편했다.
다만 전역적으로 사용될 컴포넌트이라 필요한 기능을 추가하기 위해 최대한 독립적으로 사용될 수 있도록 코드를 추가하는 것이 중요했다.
예를 들어 기록 추가 페이지에서 새 카테고리를 추가하는 기능이 Dropdown 컴포넌트에 필요했기 때문에 props로 isNew를 넣을 경우에만 드롭다운 마지막 요소에 isNew가 추가되도록 만들었다.


또 defaultProps를 통해 isNew props의 기본값을 false로 주어 해당 기능이 필요하지 않으면 기존 코드에 영향이 가지 않도록 하였다.

라이브러리를 쓰지 않고 캘린더를 만들어보기

캘린더를 MOU를 통해 더 인터랙티브한 컴포넌트로 만들 수 있었지만 스스로 도전해보고 싶어서 구글링과 day.js 라이브러리를 사용해 캘린더를 만들어보았다. 덕분에 day.js를 마스터한 것 같다 🤣🤣🤣

어려웠던 부분은 캘린더 첫 주에 저번 달 마지막 주가 섞여있는 경우를 구현해야 하는 것이었다.

이 부분은 day.js로 은근히 쉽게 구현할 수 있었다...!
이번 달의 첫째날 요일(firstDay)을 day.js로 구하면 숫자가 나온다. (일요일이 0, 토요일이 6).
range 함수는 인자가 한 개만 들어올 경우 0부터 해당 숫자 전까지를 요소로 하여 배열을 만들어준다. 예를 들어 firstDay가 토요일(6) 이고 range(6)이면 [0, 1, 2, 3, 4, 5] 라는 배열을 만들어준다.
Array(6).fill(아무거나).map((v, i) => i) 형태로도 만들 수 있지만 데브코스 아주 초기 때 배운 함수형 프로그래밍을 조금이라도 써보고 싶어서 lodash-es 라이브러리의 range 함수를 사용했다.
dayjs의 subtract(숫자, 날짜 type) 함수는 숫자만큼 이전의 dayjs 객체를 리턴해준다.

이걸 활용해서 firstDay에 대한 dayjs 객체로부터 subtract 함수를 이용해 firstDay - index를 해주면 (6, 5, 4, 3, 2, 1) 6일 전 dayjs 객체 ,5일 전 dayjs 객체 등 해당 dayjs 객체로부터 date를 빼내 구현할 수 있다.

추가적으로 오늘일 경우, 클릭했을 경우 강조 부분도 구현하기 살짝 힘들었는데 이 부분은 여기서 자세히 확인할 수 있다.

Total Review

백엔드와의 소통

처음으로 백엔드와 A to Z로 함께 만들어보는 거였고, 프론트나 백엔드나 협업 경험이 많으면 알아서 잘 딱 깔끔하고 센스있게 일처리를 했을 텐데 잘 몰라서 효율적으로 작업하지 못한 것이 아쉽다.
예를 들어 기존에 계획했던 일정을 소화하기 위해 일정을 가늠하고 역할 분담하는 것을 잘 파악했어야 했다는 점? 초기 기획 단계에서 백엔드 측이 충분히 일정을 소화하고 시간이 남을 것 같다고 판단하였지만 실제로는 should have의 API만 프로젝트 마감 5일 전에 받아서 적용하고 에러 처리하느라 프로젝트 완성도가 많이 떨어졌다. 또한 대부분의 http 상태 코드가 500번으로 넘어와서 프론트 코드 문제인지 서버 문제인지 파악하기 힘들어 에러 처리가 더 힘들었던 점도 있는 것 같다. 또한 후반부에 몰아치는 작업으로 에러가 발생할 때 말도없이 서버를 자꾸 내려서 작업을 멈추는 상황도 겪었다. 일정이 널널하다고 예상되더라도 최대한 빨리 작업하고 에러 처리 등의 완성도를 높였으면 더 좋은 결과물을 낼 수 있지 않았을까 생각이 든다.

위와는 별개로 수정이 필요한 API를 요청 드리면 최대한 빠르게 고쳐서 프론트에 넘겨주려고 노력한 백엔드에 감사하다. 또 기획단계에서 아이디어와 디자인이 프론트로부터 나왔기 때문에 백엔드쪽에서 서비스를 이해하기 어려울 거란 걱정도 있었지만 충분히 논의하고 헷갈리거나 추가, 수정이 필요한 부분에 적극적으로 의견을 내서 더 좋은 결과가 나온 것 같다.

who보단 how를

후반부에 작업이 몰아치다보니 팀원 중 한 분이 작은 단위로 커밋을 나누지 못하고 한꺼번에 올리는 일이 있었다. 충돌 처리를 하다 이리저리꼬여 다른 팀원의 코드들이 대거 사라지는 일이 발생했고 스트레스가 쌓인 상황에서 미안해하고 어쩔 줄 몰라했다.
어차피 그런 일은 누구나 겪을 수 있는 일이기 때문에 팀원들은 서로 다그치지 않고 어떻게 해결할 지 discord로 모여 충분한 논의를 나눴고 차근차근 해결하다보니 원래 작업 내용들을 복구할 수 있었다. 오히려 트러블 슈팅을 같이 공유하며 git을 더 이해할 수 있었던 경험이 되었다.
오류를 무서워하지 않고 차근차근 해결하기! 실수가 아닌 배움의 과정이라 생각하면 오히려 좋아 👍

profile
💪🏻 아는 걸 설명할 줄 아는 개발자 되기

0개의 댓글