아가릿!은 숭실대학교 중앙동아리 유어슈에서 만든 웹서비스로, 말로만 결심하는 사람들을 위한 결심 공유 프로젝트이다. 사용자는 자신을 포함한 모두가 볼 수 있도록 결심을 외치고 주변 친구들에게 결심에 대한 응원 편지를 받게 된다. 그리고 3주 후에 받은 응원 편지를 확인하며 결심에 대한 결의를 다질 수 있게 도와준다.
▶ 아가릿 바로가기
개발 동아리에 들어왔음에도 이렇다 할 참여를 해보지 못했던 터라 프로젝트에 제대로 참여를 해보고 싶은 마음이 있었다. 하지만 나의 부족한 실력으로 행여나 팀에 피해를 주지 않을까 하는 조심스러움이 컸다. 그래도 계속 피할 수는 없는 법! 용기를 내서 프로젝트에 프론트 개발자로 참여하기로 했고 이참에 나의 개발 실력도 더 늘려보고 싶었다.
그동안 클론 코딩이나 이미 오래전 완성된 디자인과 API로 페이지 구현하는 정도의 프로젝트만 경험했다 보니 다른 파트와 협업해 본 경험이 거의 없었다. 이번 프로젝트를 통해서 같은 개발 팀원분들과는 물론이고 다른 파트의 팀원분들과도 소통하고 협업하는 방식을 배워보고 싶었다.
프로젝트 경험이 많은 편이 아니었다 보니 서비스 출시는 경험해 본 적이 없었다. 개발에 발을 담그다 보면 서비스 하나쯤은 출시해 보고 싶은 마음은 당연할 것이다. 그 마음은 나 또한 마찬가지였다...ㅎ
내가 동아리에 들어갔을 당시에는 거의 비대면으로 진행하기도 했고, 집과 학교와의 거리가 멀다 보니 동방도 잘 가기가 힘들었다. 그러다 보니, 같은 파트 분들하고도 아주 친해지지 못했고 다른 파트 분들과는 대부분 얼굴도 몰랐다. 그래서 다른 분들과도 서로 알고 지내고 싶은 마음이 컸다.
프론트 회의 결과 대부분의 기술 스택이 이전 프로젝트에서 프론트 리드님께서 만들어 주신 것을 이용하면 좋을 것 같아 대부분의 기반은 이전 프로젝트에서 가져왔고 조금 수정이나 추가해서 사용하는 방식으로 진행했다. 이후에 세부적인 설정은 테크 리드님이 도와주셨다. 여기서는 개발에 사용되었던 큰 스택들만 작성해 보겠다.
추가로 로그인은 카카오 로그인을 이용했다.
프론트엔드를 담당한 둘이 모여서 간단한 그라운드 룰을 정했다. 정한 내용들은 아래와 같다.
feat/닉네임/기능
아가릿!의 기능 중에는 필수로 구현해야 할 기능과 있어도 그만 없어도 그만인 기능이 있었기 때문에 스프린트 1과 2로 나누어 진행하기로 했다. 스프린트 1에서는 반드시 구현해야 하는 기능들로 구성되었고 약 일주일 정도 스프린트 1을 진행하기로 했다. 어느 정도 기능들과 디자인이 정리되고 나서 프론트엔드 내부에서 task를 나누기로 했다. task를 나누는 기준은 대부분 페이지 단위나 컴포넌트 단위였다. 처음부터 모든 task를 나누는 것은 무리가 있었기 때문에 급하게 구현해야 하는 것, 시나리오상 초반에 해당하는 페이지부터 task를 나누었고 각자 개발을 진행했다.
개발은 각자 맡은 파트대로 브랜치를 나누어 진행하고 그라운드 룰대로 세세하게 쪼개서 커밋을 하고 한 번에 pr을 날리는 방식으로 진행했다. pr을 날리면 서로의 코드를 확인해 주고 고쳐야 할 점과 궁금한 점은 comment로 소통했다. 특별한 이유가 없는 이상 상대가 허락해야 develop 브랜치로 merge 할 수 있게 진행했다. 그 외의 다른 파트 팀에 질문할 사항이나 개발 도중 막히는 부분, 코드 외적인 부분은 슬랙으로 소통했다. 개발이 어느 정도 진행되면 다시 한번 디스코드에서 모여 남은 task를 작업량이 균등하도록 나누어 다시 개발을 진행했다.
1차 개발 완료된 것으로 베타 테스트와 QA를 진행했다. 그러면서 발견한 문제점들은 리스트로 정리하며 금방 바꿀 수 있는 부분이나 중요한 기능들은 바로 수정을 진행했고 남은 문제점들은 스프린트 2에서 수정하기로 했다.
수정해야 할 점과 추가로 변경 및 구현해야 하는 기능들로 스프린트 2를 진행되었다. 스프린트 2는 스프린트 1보다 구현해야 할 기능이 적기 때문에 기간을 더 짧게 잡고 진행했다. 이전 방식처럼 프론트엔드 내부에서 task를 나누었고 task는 우선순위 1순위부터 나누고 1순위 개발이 끝나면 2순위 task를 나누는 방식으로 진행했다.
스프린트 1과 마찬가지로 그라운드 룰대로 개발을 진행했으며 1순위가 끝나면 2순위, 2순위가 끝나면 3순위를 개발하는 방식으로 진행되었다. 대부분은 기존의 기능들을 조금씩 수정하는 것들이었기 때문에 빠르게 끝낼 수 있었다.
Radix-ui는 UI 라이브러리 중 하나이며 흔히 Headless UI 라이브러리라고 한다. 디자인 없이 기능만 제공해 주는 라이브러리라는 뜻이다. 아가릿! 디자인에는 토스트 메시지나 다이얼로그 기능이 엄청나게 사용된다. 그래서 테크 리드님의 추천을 받아 Radix-ui를 사용하게 되었다. UI 라이브러리를 사용해 본 적이 없던 터라 처음에는 사용법이 많이 어색하고 적응이 필요했지만 사용하다 보니 라이브러리를 사용하는 것이 얼마나 편안하고 구현 시간 단축에 큰 도움이 되는지를 알 수 있었다. 게다가 공식 문서에서도 예제와 함께 설명이 잘 되어있어서 몇 번 연습하다 보면 금방 배울 수 있었다.
싱글톤 패턴이라는 것을 이번 프로젝트를 하면서 처음 들었다. 우리는 react-cookie로 관리되는 토큰을 싱글톤 패턴을 적용해 관리했다. 그래서 매번 cookie 인스턴스를 만들지 않아도 되었으며 이 방식으로 토큰을 어떤 식으로 등록하고 가져오고 수정하는지 숨길 수 있었다.
아가릿!에는 상당히 디자인이 중요한 서비스이다 보니 CSS에 많은 공과 시간을 들여야 했다. 때문에 CSS에서 막히는 부분이 꽤 있었다. 특히 버튼에 postion:fixed를 활용하는 데 있어서 원하는 위치에 배치가 안 된다든지 부모 요소를 원하는 요소가 아닌 다른 요소로 인식한다든지의 문제가 있었다. 결국 수많은 시도와 노력 끝에 원하는 디자인대로 만들 수 있었다.
위에 언급했다시피 아가릿!에는 많은 디자인 요소들이 들어갔는데 그러다 보니 공통 컴포넌트가 절실히 필요했다. 하지만 생각보다 겹치는 요소들이 적어서 공통 컴포넌트를 많이 만들어 활용할 수 없었고 그마저도 미세하게 다른 부분이 있어서 이를 해결하는 데 어려움이 있었다. 그래도 할 수 있는 최선으로 공통 컴포넌트를 만들어 구현했다.
응원 편지를 등록하는 것은 아가릿! 서비스에서 가장 중요한 기능이다. 하지만 사용자가 응원 편지를 등록할 때 바로 보이지 않는 에러가 있었다. 해당 부분 구현에 있어서 어떻게 해결해야 할지 많이 고민했고 이는 useQuery의 refetch 기능으로 해결이 가능했다. 하지만 refetch를 호출하는 경우를 구현하는 과정에서 코드상으로 괜찮은지는 확신이 들진 않았다.
개발 도중 통신이 제대로 되지 않아 500 에러가 뜨는 상황이 계속 발생했다. 처음에는 500 에러를 보고 백엔드 쪽 문제인 줄 알았으나 테크 리드님의 도움을 받아 통신 요청 시 토큰이 Authorization에 제대로 들어가지 않아 생기는 문제점임을 확인했다. 당시 토큰은 react-cookie를 이용해 관리하고 있었는데 리드님의 도움으로 토큰을 싱글톤 패턴으로 적용해 관리하는 방법부터 문제가 되는 부분까지 해결할 수 있었다. 그리고 개발자 도구의 network 탭을 확인하는 것이 많은 도움이 된다는 것을 배웠다.
삭제된 결심을 조회할 경우에 다른 페이지로 이동시키고자 react-query의 onError 메소드에서 처리하는 로직을 짰으나 생각한 대로 처리가 되지 않았다. 혼자서 어떻게든 해결해 보고자 했으나 해결 방식을 모르겠어서 팀원에게 도움을 요청했고 덕분에 해결의 실마리를 잡을 수 있었다. 당시 백엔드에서는 삭제된 결심을 조회할 경우에 예외 처리를 하고 있었다. 보통 이런 경우에는 예외 처리가 아닌 삭제 여부를 알려주는 새로운 필드를 추가해 알려주는 방식을 이용한다고 팀원분이 알려주셨고 이 방식으로 잘 해결할 수 있었다.
당시 리걸팀의 질문 스레드, 개발팀의 버그 스레드, 다른 팀에서 개발팀에 문의하는 스레드, 디자인 스레드 등 동시에 많은 스레드가 진행 중이었다. 또 스레드에서 다른 주제의 이야기가 나오는 등 스레드가 혼합되기 시작하면서 소통이 원활하게 되지 않은 문제점이 있었다. 칸반보드나 리스트를 만들어 보자는 이야기가 나왔지만, 의견대로 칸반보드나 리스트가 잘 활용되었는지는 잘 모르겠다.
아가릿!은 웹으로 제작되었지만 주로 모바일에서 사용될 것을 고려해 만들어졌다. 이 서비스가 바이럴이 되기 위해서는 인스타 같은 SNS나 에브리타임 앱을 많이 활용해야 했고 해당 앱들은 PC보다는 모바일에서 가장 빈번한 접속이 이뤄지기 때문에 모바일 버전을 반드시 고려해야 했다. 그러나 애초에 모바일을 고려하며 만든 웹은 처음이었기에 초반엔 많이 허둥댔던 것 같다. 그래서 다른 프로젝트의 깃허브 코드도 참고해 보며 진행했다. (개인적으로 진저호텔의 코드를 참고했다.) 그리고 나름대로 작은 사이즈의 모바일도 고려하며 코드를 짰음에도 고려하지 못했던 사이즈도 있었기 때문에 이미지 사이즈 조절이나 여백같이 자잘한 수정이 필요했다.
전체적으로 개발 일정이 여유로운 편은 아니었다. 하지만 방학이 아닌 학기 중에 프로젝트가 진행되었던 점. 각자의 개인 일정이 있다는 점 때문에 더더욱 촉박하게 느껴졌던 것 같다. 개발할 시간이 부족하다 보니 기능을 축소해야 했고 그래서 변경된 부분이 꽤 많았다. 디자인팀 역시 빠른 시간 내에 디자인을 완성시해야 했었기 때문인지 디자인 중 놓치거나 통일되지 못한 부분이 있어 그 부분에 대해서 계속 질문을 해야 했던 점이 있었다. 그래도 빠른 디자인 변경과 질문에 대한 답변 덕분에 촉박했던 시간 동안 완성할 수 있었다고 생각한다. 모두가 엄청 열정적이었다!!!
지극히 개인적인 문제이지만 이 부분이 가장 어려웠던 것 중 하나였다. 개발 시간에는 개발에만 딱 집중하고 개인 일정을 해야 하는 시간에는 일정에 딱 집중을 하면 너무나도 좋았겠지만... 그러지 못했다. 개발 시간에 개인적인 일이나 문제가 생겨 몇 분, 심하면 몇 시간 동안 집중을 못 하는 일들이 벌어졌고 개인 일정을 하면서도 계속 노트북을 붙잡고 슬랙을 확인하느라 어느 하나 제대로 집중하지 못한 문제가 있었다. 물론 해커톤 형식으로 굉장히 빠르게 개발이 진행되어야 했지만, 이 둘 사이의 경계선을 확실히 구분 짓지 못하다 보니 난감한 상황이 꽤 있었다. 아쉽게도 이번 프로젝트 동안에는 이 문제에 대해서 완벽히 극복하지 못했기 때문에 이 부분은 앞으로 내가 반드시! 꼭! 해결해야 할 문제 중 하나가 될 것 같다.
이건 함께 프론트엔드를 담당했던 Hanna에게 많이 배웠다. 비교적 프로젝트 경험이 적은 나보다 협업 경험이 있던 편이어서 그런지 소통 방식과 task 나누는 방식부터 커밋 방식이라든지 코드 리뷰라든지 PR을 날리는 방식까지 상당히 많은 것을 배웠다.
동시에 둘이 각자 개발을 진행하다 보니 생각보다 브랜치 관리도 중요했다. 그러다보니 브랜치 관리가 제대로 되지 않아 커밋이 겹치는 경우도 더러 있었다. 그 부분까지는 생각하지 못했기 때문에 브랜치와 커밋 관리를 중요하게 해야 한다는 것을 깨달을 수 있었던 것 같다.
eslint와 prettier를 사용한 적이 있긴 하지만 솔직히 그렇게 중요한지 잘 모르고 넘어갔었다. 하지만 사소한 코드 스타일이라던지 import 순서마저도 정리가 필요하고 정리를 해야 더 코드가 눈에 들어오고 이해하기 쉽다는 걸 깨달았다. 처음에는 다소 부족한 점이 있게 eslint를 설정했는데 이후에 테크 리드님의 도움으로 더 꼼꼼하게 설정하여 더 이해하기 좋은 코드로 정리할 수 있었다.
디자인팀과 예상했던 것보다 더 많이 세세하게 소통해야 했다. 개발 도중에도 색상과 폰트 같은 자잘한 부분들을 확인받아야 했고, 디자인의 의도를 알아야 개발을 수월하게 할 수 있기 때문에 정확한 디자인 의도와 기능까지 질문해야 했다. 처음에는 혼자 일하던 방식에 익숙해서 나도 모르게 명확히 이해되지 않거나 통일되지 않는 것 같은 디자인을 봐도 내가 알아서 해석하고 이해하는 방식으로 진행하려다가 아차 싶었다. 그래서 의문점이 들면 바로 슬랙 채널로 질문하며 세세하게 이해하며 디자인적 요소들을 놓치지 않으려고 했다. 가끔은 서로 자잘하게 소통하다보니 디자인팀이 놓친 부분을 개발팀에서 발견하는 경우도 있고 디자인을 고민하는 과정에서 개발팀의 의견도 적극 반영되는 경우도 있었다. 이런 과정들을 통해서 개발팀이 디자인팀과 협업하는 방식과 과정을 배울 수 있었다.
개발팀은 리걸팀과의 협업은 거의 없으리라 생각했지만, 전혀 아니었다. 마케팅팀이나 디자인팀이 알려줄 수 없는 기술적인 부분들을 설명하기 위해서 개발팀이 생각보다 많이 리걸팀과 소통해야 했다. 대면으로 진행하기에는 시간도 촉박했기에 비대면으로 진행되었고 그러다 보니 모든 것을 텍스트로 설명해야 했다. 나는 알고 있는 모든 것들을 텍스트로 최대한 쉽게 설명하려 노력했다. 보통 리걸팀과의 협업을 이런 식으로 진행하는지는 모르겠지만 그래도 꽤 만족스러운 소통이었다고 생각한다. 그 어느 팀과의 협업 중에서도 리걸팀과의 협업이 기억에 많이 남았다.
아래의 이미지는 텍스트로 리걸팀이 쉽게 이해할 수 있도록 노력했던 메시지다.. 내용은 비밀! 저 메시지 이외에도 꽤 많은 소통을 했다.
처음으로 A-Z까지 참여한 프로젝트였다. 기획 회의부터 디자인이 나오는 과정, 디자인을 토대로 개발 진행, 릴리즈, 마케팅까지 이 모든 과정에 참여하고 지켜볼 수 있었던 건 개발자로서 되게 좋은 기회였던 것 같다. 다른 파트의 팀들은 정확히 어떤 일을 하고 어떻게 협업하는지도 지켜보며 각 팀의 프로세스를 이해할 수 있었다. 그리고 이 프로젝트를 하기 전까지는 솔직히 개발 시작 전 어떤 단계들이 진행되고 서비스가 완성되면 어떤 단계들이 진행되는지 거의 몰랐다. 생각보다 개발 전후 단계도 복잡하고 꽤 많은 시간과 노력이 들어간다는 것을 알게 되었다. 덕분에 전체적인 프로젝트 진행 과정을 더 잘 이해할 수 있었다. 역시 이론으로 공부하는 것보다는 직접 보고 경험해 보는 것이 최고인 것 같다.
아무래도 프로젝트 경험이 부족한 탓인지 개발 방식부터 시작해서 전체적인 프로젝트 진행 방식에 적응하다 보니 빠르게 프로세스를 이해하지 못했던 것 같다. 다른 분들이 눈치채셨는지 모르겠지만 혼자서는 엄청나게 허둥거리고 따라가려고 부단히 노력했다..ㅎㅎ 그래도 꽤 잘 해낸 걸지도..??라고 생각하는데 다른 분들은 어떻게 생각하실지 모르겠다.
물론 아쉬운 부분도 있었다. 일단 생각보다 백엔드와 협업이 제대로 이루어지지 못한 것 같았다. 본격적으로 개발을 시작하기 전에 백엔드와 DTO? 작업을 진행해야 했었지만 개발 시간이 부족했던 탓인지 시간이 안 맞았던 탓인지 그런 과정 없이 각자 알아서 개발을 시작했다. 그러다 보니 필요한 데이터 필드가 없기도 했고, 왜 존재하는지 모르겠는 필드가 있기도 했다. 백엔드와의 협업이 체계적으로 이루어졌다면 더 효율적으로 개발할 수 있지 않았을까 하는 생각이 든다.
그리고 나 스스로에게도 아쉬운 점이 있었다. 나는 혼자서 해결해 보려고 하는 경향이 있어서 개발 도중 막히는 부분을 몇 시간 동안 붙잡으면서 시간 낭비를 하는 경우가 있었다. 팀원을 믿고 막히는 부분에 대해서는 질문도 적극적으로 해야 했는데 그러지 못했다. 또, 생각보다 좋은 아이디어가 많이 나오지 않아서 기획이나 디자인 회의에서 많은 의견을 제시해 보지 못한 점도 아쉬웠다. 나에겐 팀원들이 제시한 아이디어 대부분에 '우와.. 참신하다!', '오!!! 좋은데?' 이런 생각만 하고 있었지만 다른 팀원들은 해당 아이디어로 진행했을 때 발생할 수 있는 문제점이나 더 나은 개선책을 생각해 내셨다. 나를 제외한 모두가 적극적이었던 것 같았다😭 그래서 나도 더 좋은 아이디어와 함께 적극적으로 참여했으면 더 좋았지 않았을까 하고 많이 반성하게 된 계기가 되었다.
힘들지만 많이 배운 프로젝트였다. 짧은 시간 동안 결과물을 만들어 내는 건 생각보다 많이 힘들었지만 그래도 프로젝트에 참여했던 건 절대 후회하지 않는다. 어엿한 프론트엔드 개발자로서 스스로 도전한 첫 프로젝트였기에 내 스스로가 대견했다. 프로젝트 덕분에 좋은 사람들도 만나며 적극적인 자세, 열정적인 자세, 자신이 맡은 일에 진심으로 최선을 다하는 자세를 보고 스스로 나의 태도는 어떤지 돌아보고 반성하는 계기가 되기도 했다. 덕분에 주니어 개발자로서 한 층 더 성장할 수 있었던 계기였다.
뿌듯하고 성취감 넘치는 프로젝트였다. 아가릿! 서비스는 봄 축제에 동아리 부스와 학교 건물 내 게시판에 포스터를 붙이며 홍보를 진행했었는데 지나가면서 포스터를 볼 때마다 얼마나 뿌듯하던지 같이 있던 사람들에게 내가 만든 거라며 조금 자랑을 하기도 했다😄😄
이렇게 모두가 열정적이고 최선을 다하는 멋진 팀을 또 만날 수 있을까 싶어요! 짧은 시간 동안 함께 고생하고 노력한 팀원분들 모두 멋지고, 감사하고 덕분에 많이 배워갑니다👍👍👍👍