menulogo

모두의 시간 서비스 개발 회고

@corinthioniaAugust 20, 2023

모두의 시간은 쉽고 빠르게 모임 시간을 정할 수 있도록 도와주는 서비스이다!

한 참여자가 일정을 등록할 수 있는 '방'을 생성하고 그 방의 링크를 공유하면, 다른 모임 참여자들이 각자의 일정을 등록할 수 있다. 그러면 '빠른 시간 순'과 '오래 만날 수 있는 순'의 결과를 제공하여 약속 시간을 보다 편리하게 정할 수 있도록 도와준다.


모두의 시간 사용해 보기 🚀🚀
https://www.modutime.site


0. Intro

모두의 시간 서비스의 MVP 개발이 어느 정도 끝났다! 생각보다 QA 기간이 길어지게 되어 서비스 출시일이 목표보다 약간 늦어지긴 했지만, 사용자가 불편함을 느끼지 않을 만큼 완성도를 높이는 게 더 중요하다고 생각했다.

내가 맡았던 부분의 이슈들을 모두 해결하여 어느 정도 여유가 생겼기 때문에 이제서야 개발 회고글을 작성해 본다!

1. 서비스 기획

모두의 시간 서비스는 IT 연합 동아리 DND에서 시작되었다. 2023년 1월 DND 8기 5조 팀으로 팀원들을 만나 현재까지 계속해서 서비스를 발전시켜 나가고 있다. 두 달 동안 서비스 기획부터 디자인, 개발까지 다 끝내기가 쉽지만은 않았지만 그래도 하면 되긴 하더라 😤

처음에 프로젝트 주제를 정할 때 팀원 모두 의견을 내었고 투표를 통해 '약속 시간 조율 서비스'로 결정되었다. 그 후에는 데스크 리서치와 사용자 조사 등을 통해 서비스의 방향성을 정했다.

인터뷰를 통해 많은 인사이트를 얻을 수 있었는데, 특히나 모임을 주도하는 사람들이 가진 불편함에 대해 공감이 갔다.

많은 사람들은 주로 카카오톡 단체 채팅방에서 투표 기능을 이용하여 친구들과 모임 일정을 정한다. 하지만 카톡을 아예 읽지 않는 사람도 있고, 제때 투표하지 않는 사람도 있고, 또 결과를 취합하여 일정을 확정하기까지 '모임을 주도하는 사람'에게 불편한 점이 한두 가지가 아니었다.


따라서 우리는 '모임을 주도하는 사람'의 불편함과 부담감을 덜어주고, 다른 참여자들은 '쉽고 빠르게' 일정을 등록할 수 있는 서비스를 만들고자 했다.

IT 연합 동아리 DND 8기 활동 후기

2. 기술 스택 정하기

기술 스택을 정할 때 예상치 못했던 한 가지 난관이 있었다. 바로 다른 프론트 개발자 친구와 스택이 맞지 않는 것이었다. 나는 React와 Nextjs 등의 웹 개발 스택을 가지고 있었다면, 그 친구는 React Native만 사용해 보고 React와 Next를 사용해 본 적이 없다고 했다.

하지만 우리 서비스는 주로 카카오톡 인앱 브라우저를 통해 이용할 것이라 생각했기에 웹으로 제작하기로 결정된 상태였으므로 React 또는 Next를 사용할 수밖에 없었다.

나는 React Native를 이용하여 개발을 진행해 본 적은 없지만, React와 어느 정도 비슷하다는 이야기를 들었기 때문에 우선은 React를 사용하기로 결정했다. 그후 빠른 개발을 위해 (내가 생각하기에) 금방 배워서 적용할 수 있는 Recoil, Emotion 등의 라이브러리를 사용하기로 했다.

처음에 DND에 지원했던 가장 큰 목적은 1. 나보다 개발 경험이 많은 현직자 분과 협업해 보는 것과 2. 나에게 익숙하지 않았던 기술들을 사용해 보고 싶었다. 개인적으로 위 두 목표를 달성하지 못하여 아쉬움이 남긴 하지만, 기존에 알던 지식들을 다시 한번 복습하는 계기로 생각하고 개발을 진행했으며, 현재 리팩토링을 진행하며 차차 새로운 기술을 적용시켜 나가고 있다.

3. 개발 과정

모두의 시간 서비스는 크게 [방 생성 / 초대 / 등록 현황 / 일정 등록 / 우선순위] 페이지로 나눌 수 있다. 내가 생각하기에 '일정 등록' 페이지가 구현하기 제일 까다로워 보여서 이 부분은 내가 맡겠다고 자원했다. 또한 일정 등록과 연관되는 등록 현황과 우선순위 부분까지 함께 맡게 되었다.

3-1. 등록 현황 페이지 개발하기

DND 과정 중에 '프로토타입 제작'이 있어서, 핵심 부분이라고 생각했던 '등록 현황' 페이지를 우선 개발했다. 이 부분에 들어가는 타이머 기능부터 표 형식의 layout을 구성하는 것까지 생각보다 쉽지 않아 보였다. 처음엔 외부 라이브러리를 사용할까도 생각했지만 개인적으로 직접 구현해 보고 싶은 마음이 컸기 때문에 여차저차 기능을 완성할 수 있었다.

프로토타입

그리고 짧은 시간 안에 개발하려다 보니 스트레스를 받았는지 프로토타입 제출하자마자 위경련이 찾아와서 응급실까지 갔다왔다는 이야기...

그후 디자인이 변경된 부분도 조금 있어서 최종적으로 완성된 화면은 아래와 같다.

등록 현황 표 부분은 각 칸마다 일정을 등록한 참여자 수를 데이터로 받아와서 opacity해당 칸에 일정 등록한 사람 수 / 전체 참여자 수 * 100으로 설정하여 어느 시간에 얼마큼의 사람들이 시간이 되는지 시각화하여 보여주었다.

그 다음으로 어려웠던 것은 전체 참여자 중 일정 등록을 완료한 사람의 비율에 따라 Progress bar 부분에 토끼 이미지를 함께 붙이는 것이었다. 이게 어려웠던 이유는 디자인상 특정 수치 이하/이상에서는 토끼의 위치가 Progress bar 끝 부분의 위치와 일치하지 않았기 때문이었다...


예를 들어, Progress bar가 오른쪽 끝 부분에 도달했음에도 불구하고 토끼 이미지는 특정 비율을 넘어가면 위치가 고정되어야 한다.


또한 참여율이 0%일 때에도 토끼 이미지는 Progress bar의 왼쪽 끝 부분에 위치하지 않는다... 🙄


이 문제는 Progress bar의 offsetWidth 값에 따라 토끼 이미지의 위치를 조정해 주는 방식으로 구현하긴 했는데, 이 과정에서 어느 정도 하드코딩 된 부분이 있어 차차 수정해 나가려 한다.

또한 이 부분을 구현하면서 아래와같이 모바일 환경에서 그림자의 잔상이 발생하는 문제가 있었다.


이 문제는 챗지피티의 도움을 받아 해결할 수 있었다... ㅎㅎ 👍🏻
모바일 환경에서 애니메이션 사용 시 잔상이 생길 때

3-2. 일정 등록 페이지 개발하기

일정 등록 페이지에서는 표의 각 칸들을 선택하여 참여자들이 자신의 일정을 등록할 수 있다.

처음에 일정 등록 페이지의 디자인을 받아보았을 때 몇 가지 어려움을 예상했다...

  1. 오른쪽의 스크롤바를 이용해야지만 표를 아래로 내릴 수 있다 (화면 전체는 스크롤 금지)
  2. 드래그 또는 클릭/터치를 통해 칸을 선택할 수 있다
  3. 날짜는 3일씩 화면에 보여지고, 전체 날짜가 3일씩 떨어지지 않는 경우 남는 날은 비활성화 처리 한다.
  4. 화살표 버튼을 클릭하여 날짜가 바뀌어도 이전에 선택한 값은 유지되어야 한다.

이게 주어진 기간 안에 구현이 가능할까 싶었지만 직접 구현해 보고 싶은 욕심이 매우 컸기 때문에 일단 해 보겠다고 했다!!

3-2-1. 스크롤바 기능 구현하기

처음에 디자인을 받아봤을 때, 기존의 Native 스크롤바를 커스텀하여 구현하기에는 한계가 있었다. Native 스크롤바를 이용하면 표 전체의 길이만큼 스크롤바 Track이 형성되는데, 우리 서비스에서는 표의 길이에 관계없이 Track의 길이는 고정되기 때문이다. 또한 스크롤바의 위치도 디자인처럼 고정시키기 어렵다는 문제가 있었다.

따라서 직접 스크롤바 기능을 만들어 보기로 했고, useRef를 잘 이용한다면 충분히 구현 가능할 것이라 생각했다. 하지만 생각보다 일이 잘 풀리지는 않았는데, 우연히 찾아본 Drag'n'Drop with mouse events 글이 정말 많은 도움이 되었다. 특히 글 아래에 슬라이더를 직접 구현해 보는 과제의 코드를 참고하여 기능을 구현할 수 있었다!! 이 부분도 추후에 다른 글로 작성해 봐야겠다 🙂

3-2-2. 드래그/터치/클릭 이벤트를 통해 칸 선택하기

초반에는 외부 라이브러리 없이 직접 이벤트 핸들러를 구현해 보려 했다. 하지만 터치 이벤트까지 고려해야 한다는 점이 난항이었다. PC 환경에서 클릭/드래그 이벤트는 잘 동작했는데, 모바일 환경에서 이용하려면 터치 이벤트를 따로 핸들링 해야 한다는 점이 어려웠다.

특히 여러 칸을 드래그 해서 선택할 때 onMouseMove 이벤트를 사용하여 구현했는데, 모바일 환경에서 이를 단순히 onTouchMove로 바꾸어 사용하기에는 문제가 있었다. onMouseMove를 이용할 시 마우스는 언제나 화면 속에 존재하기 때문에 마우스의 위치를 파악하기가 쉽지만, onTouchMove는 사용자가 어느 부분을 터치할지 미리 예상하는 것이 불가능하기 때문이었다.

그래서 고민 끝에 라이브러리를 사용하기로 했다. 여러 라이브러리를 찾다가 react-selecto 라는 라이브러리를 알게 되었고, 이를 통해 손쉽게 적용할 수 있었다. 다만 모바일 환경에서 한 칸씩 클릭하여 선택하는 게 잘 동작하지 않는 것 같아 추가적인 이벤트 핸들러를 작성하여 해결할 수 있었다.

3-2-3. 3일씩 화면에 보여주기

만약 [3월1일, 3월2일, 3월3일, 3월4일] 중 약속 시간을 정하고 싶은 경우를 가정해 보자. 일정 등록 페이지에서는 이를 3일씩 끊어서 보여줘야 했다. 즉, 배열의 길이를 3으로 나누고, 그에 따른 나머지는 회색으로 비활성화 처리를 해 주어야 했다. 이 부분은 다행히도 나머지 연산을 통해 손쉽게 구현할 수 있었다.

3-2-4. 날짜가 바뀌어도 이전에 선택한 값은 유지하기

화살표 버튼을 클릭하여 현재 보여지는 날짜의 이전/이후 날짜들을 선택할 수 있다. 문제는 다른 날짜들로 이동할 때 표 자체가 리렌더링 되어 이전에 선택한 값들이 초기화된다는 것이었다.

각 칸을 선택할 때 react-selecto 라이브러리를 이용하는데, 선택한 칸마다 selected라는 클래스명을 부여하여 선택 여부를 판단한다. 처음에는 칸이 선택될 때마다 e.target.id 값으로 그 칸에 해당하는 날짜 정보를 가져온 뒤 selected 라는 배열에 추가해 주었다. 그리고 선택된 상태에서 한 번 더 선택될 경우, selected 클래스를 제거하고 selected 배열에서 e.target.id 값을 filter() 메소드를 통해 제거해 주었다.

하지만 이 과정이 상당히 비효율적이라고 생각했다. 따라서 화살표 버튼을 클릭하거나, '등록하기' 버튼을 클릭하는 경우에만 selected 클래스명이 부여된 칸의 id 값을 가져오는 방식으로 구현했다.

예를 들어, [3월1일, 3월2일, 3월3일, 3월4일, 3월5일, 3월6일] 중 일정을 정하고 싶다고 가정해 보자. 이를 3개씩 묶기 때문에 표를 렌더링할 때 사용하는 날짜 객체는 다음과 같은 구조를 띄게 된다.

{
  "0": ["3월1일", "3월2일", "3월3일"],
  "1": ["3월4일", "3월5일", "3월6일"]
}

나는 이 객체의 key 값들을 page 라는 말로 대신하여 사용했다. 만약 page 값이 1인 경우, 화면에는 [3월4일, 3월5일, 3월6일]이 보여지는 것이다. 선택한 날짜들을 배열로 저장할 때에도 이와 같은 방식을 사용했다. 즉, page가 1인 상태에서 '2023-03-04 11:30', '2023-03-04 12:00'에 해당하는 칸을 선택했다면, selected 배열은 다음과 같이 저장된다.

{
    "1": ["2023-03-04 11:30", "2023-03-04 12:00"]
}

이렇게 하면 page 값이 변경되어도 이전에 선택했던 값을 보다 효율적으로 관리할 수 있었다.

3-3. 우선순위 페이지 개발하기

우선순위 페이지에서는 크게 어려운 부분은 없었다. 백엔드쪽에서 보내 주는 데이터를 그냥 보여주기만 하면 됐기 때문에 프론트보다는 백엔드쪽이 좀더 고생했을 것 같다.

그나마 좀 신경써서 개발했던 부분은 필터링 기능이었다. 특히 참여자 필터링을 구현할 때 여러 가지 경우의 수를 고려해야 했기 때문에 뭔가 더 재미있게 개발했던 기억이 있다 😁

UX를 고려한 필터링 기능 직접 구현해 보기

3-4. 코드 개선하기

동아리 활동 기간에 만든 프로젝트이다 보니 기한이 정해져 있어 깔끔한 코드를 작성하지 못했다고 생각한다. 기능구현이 우선이 되어 리팩토링을 뒤로 미뤄 뒀는데, 이제 어느 정도 여유가 생겨 차차 진행해 보려고 한다.

가장 최근에는 링크 공유 로직을 custom hook으로 작성하여 중복되는 코드를 줄이고자 했다.
링크 공유 기능을 위한 Custom hook 작성하기

앞으로도 리팩토링을 진행하며 '좋은 코드'에 대해서도 많은 고민을 해 봐야겠다.

3-5. 새로운 기술 사용해 보기

위에서 말했듯이, 나는 처음에 나에게 익숙하지 않았던 Next.js나 Tailwind 등을 사용해 보고 싶었다. 최근에 내가 맡은 모오오오오든 이슈들을 다 해결하여 여유가 생겼기 때문에!! 적용해 보고 싶은 것을 하나씩 진행해 보고 있다.

가장 먼저 Tanstack query 도입을 진행했다. 먼저 기본 개념과 사용법 등을 공부한 후 보통 어떤 식으로 코드를 작성하고, 또 어떻게 해야 깔끔하게 적용할 수 있을지 많이 찾아보고 고민했다.

아래 글은 Tanstack query를 도입한 과정에 대해 자세히 적은 글이다!
Tanstack query (React-query v4) 도입하기

그 다음으로 기존에 CRA로 세팅된 프로젝트를 Vite로 마이그레이션을 진행했다. 마이그레이션을 진행했던 이유는 빌드속도를 개선하기 위함이었는데, 실제로 5배나 빨라진 것을 확인할 수 있었다. 2배도 아니고 5배나 빨라졌다는 결과에 엄청 놀랐고, 앞으로도 React 프로젝트를 진행할 때 Vite와 함께 사용하여 개발할 것 같다!
CRA에서 Vite로 전환할 결심

3-6. 🫨...

최근에 확인해 보니 엄청 많은 기여를 했더라... 🙄


4. 앞으로

우리 팀은 계속해서 서비스를 디벨롭 해 나갈 예정이다. 현재로서는 카카오 로그인과 같은 추가적인 기능들을 구현할 예정이며 Google Analytics를 통해 수집한 데이터들을 토대로 사용성을 개선해 나갈 것이다.

나는 계속 해 왔던 것처럼 나에게 도움이 되는 여러 가지 시도를 해 볼 것 같다. 새로운 기술을 도입해 보는 것뿐만 아니라 기존에 존재하는 코드를 개선하고 최적화 작업을 진행하는 등 서비스 사용에도 도움이 될 작업들을 진행해 나갈 예정이다!! 😤🚀


5. 마지막으로

모임 약속 정할 때 모두의 시간 많이 사용해 주세요 🫶🏻


Links

Service
FE Repository
BE Repository
Behance
Disquiet

← 이전 글링크 공유 기능을 위한 Custom hook 작성하기
다음 글 →Gatsby - Google Search Console의 색인 생성 문제 (리디렉션이 포함된 페이지) 해결하기