멋사 FE5 파이널 프로젝트 회고

목차

들어가면서

멋쟁이사자처럼 프론트엔드 스쿨 5기가 종료된 지 벌써 3개월이라는 시간이 흘렀습니다. 조금 늦었다는 생각도 들었지만, 기록을 남기지 않는 것 보다는 늦게나마 남기는 것이 낫기에 프로젝트의 여정을 담은 글을 작성해 보려고 합니다. 지금부터의 이야기는 이미 옅게 흩어진 제 기억과, 프로젝트를 진행하면서 노션에 남긴 메모를 최대한 참고해 정리한 결과물입니다.

프로젝트를 시작하기 전

팀 프로젝트를 제외한 정규 과정이 모두 종료된 후, 스스로 가장 먼저 던졌던 질문은 하나였습니다.

“지금의 내 실력으로 팀 프로젝트를 무사히 끝마칠 수 있을까?”

개발자가 되어야겠다는 생각으로 시작했던 부트캠프 초기와는 다르게, 시간이 지날수록 점점 네트워킹에 집중하고 본질을 잊어버리고 있었습니다. 당연히 학습은 미진할 수 밖에 없었고, 매일 찾아오는 새로운 배움에 물음표를 던지기 보다는 이른 마침표를 찍어내곤 했습니다. 결국 프로젝트를 함께 진행할 동료들에게 짐이 되는 것이 두려워지고 말았습니다.

그 두려움이 저를 프로젝트로 이끌었습니다. 오히려 두렵기 때문에 무엇이라도 더 해야겠다는 생각이 들었습니다. 그래서 프로젝트 팀이 정해졌을 때 먼저 자처해서 팀장이 되겠다고 했어요. 책임져야 할 것들이 많아질수록 더 프로젝트에 집중할 수 있다고 생각했고, 또 프로젝트의 전반적인 관리를 해 보고 싶다는 생각에서였습니다. 프로젝트의 일정을 관리하고, 팀원의 원활한 소통을 도우며 동시에 나에게 주어진 기능 구현을 해야 하기도 했습니다.

시작부터 끝까지

1주차: 프로젝트 계획 설립 & 디자인

1주차는 프로젝트 계획을 설립하는 시간이었습니다. 함께하게 된 팀원들은 기존의 부트캠프 기간동안 한 번도 이야기를 나눠보지 않은 인원이라 걱정이 앞섰지만, 다행히 빌런은 없었습니다. 모두가 서로의 의견을 존중하며, 때로는 비판적인 의견을 제시할 수 있는 역량을 가지고 있었어요. 덕분에 프로젝트 시작 전에 불필요한 감정 소모를 진행하는 일은 없었습니다. 먼저 각자의 역량에 대해서 솔직하게 공유하기로 했습니다. 팀원을 속이고 프로젝트를 진행하다가 예기치 못한 문제를 마주했을 때 잃는 것이 당장의 부끄러움보다 더 크기 때문이었습니다.

이후에는 팀 규칙을 정했습니다. 정말 세부적인 부분까지는 정해두지 않았지만, 최소한의 틀은 잡아두고자 했습니다. 예를 들면 회의에 참여하지 못할 경우에는 최소 12시간 전에는 알려달라나, 이것도 모르냐와 같은 말은 하지 않는다던가 등이었습니다. 어떻게 보면 당연할 수 있는 내용들이지만, 문서화의 유무에 따라 팀이 어떻게 받아들이는지가 다르기 때문입니다.

프로젝트의 주제도 결정해야 했습니다. 이미 멋사 측에서 백엔드와 기본적인 디자인을 제공했기에 큰 고민을 할 필요는 없었지만, 그래도 조금이나마 우리 팀만의 아이디어로 이루어진 프로젝트를 구현하고 싶었습니다. 소셜 서비스 형태의 오픈 마켓이라는 점을 고려해서, 여행 동행을 구하거나 여행 상품을 판매하는 사람들이 사용하는 서비스라면 어떨까라는 생각이 들었습니다. 그렇게 TravelUS라는 프로젝트가 탄생했어요.

또한 통일성 있고 유지보수가 쉬운 코드를 위한 코드 컨벤션과, 팀의 보다 나은 소통과 협업에 도움이 될 수 있는 커밋 컨벤션도 결정했습니다. 브랜치 전략도 결정했는데, 처음에는 Git FlowGitHub Flow 중에서 여러 이야기가 오갔습니다.

GitHub Flow 모식도

프로젝트의 규모와 개발부터 배포까지의 흐름이 비교적 단순하다는 점을 고려했을 때, 저희에게는 후자가 보다 나은 브랜치 전략이라고 판단했기에 최종적으로 GitHub Flow를 선택했습니다.

다음으로는 프로젝트에 어떤 기술 스택을 사용할지 결정해야 했습니다. 사용하기로 결정된 주요한 기술 스택은 React, Styled-components, Axios였다.

React는 SPA를 구현하고자 하는 팀의 의도에 부합했기 때문에 선택했습니다. 페이지의 전환 없이 필요한 데이터만을 서버로부터 받아와 렌더링할 수 있고, 컴포넌트 단위의 개발이 가능하기 때문에 비슷한 컨텐츠 요소를 여러 페이지에서 재활용해야 하는 저희 프로젝트에 잘 맞을 것이라고 판단했어요.

Styled-components는 다양한 CSS 라이브러리 선택지 중 하나였습니다. 저희 팀은 프로젝트의 규모가 작아 번들의 큰 크기가 크게 체감되지 않을 것이며, 스타일을 컴포넌트에 직접 연결해 가독성과 유지보수성을 높일 수 있다고 판단했기 때문에 해당 라이브러리를 사용하기로 결정했습니다.

Axios는 기존의 Fetch API에 비해서 요청을 보내는 코드가 간결하기 때문에 가독성 측면에서 좋고, 응답 데이터를 활용하기 편리하게 자동으로 JSON 형식으로 변경해 주며, 에러 처리 방식 및 메시지 형식이 자세하여 개발 중 오류를 처리하기 용이하기 때문에 선택했습니다.

이후 기능 및 API 명세를 확인하면서 공통으로 구현할 컴포넌트와 그렇지 않은 컴포넌트를 분리하고, 2주차부터는 본격적으로 공통 컴포넌트 개발을 시작했습니다.

2주차: 공통 컴포넌트 개발

이 기간 동안은 로그인 및 회원가입 페이지를 함께 작업했는데, 저는 회원가입 이후 초기 프로필을 설정하는 페이지를 맡게 됐습니다. 프로젝트 바로 직전 들었던 특강에서 마크업에 관련된 스포일러는 어느 정도 당했기 때문에 이를 구현하는 것은 어렵지 않았으나, 유효성 검사가 발목을 잡았습니다.

고민을 했던 부분은 이미지에 대한 유효성 검사였는데, 주어진 API에서는 jpg, gif, png, jpeg, bmp, tif, heic 확장자를 제외한 파일이 업로드 되거나 파일의 크기가 10MB를 초과할 경우 사용자에게 이를 알려주어야 했습니다.

const allowedExtensionsRegex = /\.(jpg|gif|png|jpeg|bmp|tif|heic)$/i;

따라서 파일 확장자에 대한 정규식을 만들고, 파일의 이름으로부터 확장자를 분리한 뒤 소문자로 변환하여 정규식의 패턴과 일치하는지 확인했습니다. 파일의 크기가 10MB를 초과하는지 역시 분기 처리를 통해 추가해 주었습니다.

3주차: 역할분담에 따른 기능 구현

3주차에는 역할분담에 따른 페이지 및 기능을 구현하는 기간이었습니다. 제가 맡은 기능은 크게 두 가지였습니다.

게시물 CRUD

게시물의 작성, 읽기, 수정, 삭제 기능과 이를 포함하는 페이지를 만들어야 했습니다. 읽기와 삭제는 서버에 GET요청을 보낸 응답을 렌더링하거나 DELETE 요청을 보내는 것이라 작성과 수정에 비하면 상대적으로 수월했는데, 역시 문제는 작성과 수정이었습니다.

게시물 작성을 구현하면서 무엇보다도 textarea 요소의 크기 변화에 대해서 많이 고민해야 했습니다. 텍스트를 작성할수록 textarea의 높이가 그 크기에 맞춰 자동으로 늘어나거나 줄어들도록 해야 했는데, 제가 선택한 방법은 textarea의 scrollHeight 속성을 조절하는 방법이었습니다.

const handleResizeHeight = () => {
	textarea.current.style.height = '0';
	textarea.current.style.height = `${textarea.current.scrollHeight}px`;
};

useRef 훅을 사용해 textarea를 참조하고, handleResizeHeight 를 사용해 사용자의 입력에 따라 그 크기를 조절했습니다. textarea에 작성되는 콘텐츠는 내용이 바뀔 때마다 상태로 저장해 서버에 요청을 보낼 때 용이하도록 했습니다.

게시물 수정의 경우 미리 작성된 게시글로부터 수정하기 위한 정보를 어떻게 불러오는지가 관건이었는데, 이 부분은 React Router의 useLocationuseNavigate 훅을 사용해 게시물 상세 페이지로부터 텍스트와 이미지를 전달받아 수정한 뒤 서버에 PUT 요청을 보내는 방식으로 구현했습니다.

댓글

댓글 기능은 크게 댓글 작성과 삭제로 나뉘어져 있었습니다. 사용자가 작성하지 않은 댓글은 삭제 대신 신고 처리가 가능하도록 구현해야 했습니다. 이 부분은 현재 로그인한 사용자의 ID가 클릭한 댓글의 작성자와 일치한다면 삭제 모달을, 아니라면 신고 모달을 띄우는 것으로 분기 처리를 해 주었습니다.

또한 댓글의 작성 시간은 게시물과는 다르게 x분 전, y시간 전 과 같이 표시되어야 했습니다. 어떤 방법을 사용하면 좋을 지 고민하다가 시간 관련 라이브러리인 moment.js를 선택했습니다.

moment.locale('ko');
const fromNow = moment(createdAt).fromNow();

이렇게 두 줄만 작성하면 현재 시간(fromNow)으로부터 댓글이 작성된 시간(createdAt)의 차이를 확인할 수 있었습니다. 심지어 지역 설정까지 가능했기 때문에 복잡한 로컬라이제이션 과정 없이 ‘5분 전’등으로 작성 시간을 표시할 수 있었습니다.

4주차: 버그 수정 및 배포

4주차는 그동안 발견하지 못했던 버그를 해결하고 최종적으로 완성된 프로젝트를 배포했습니다.

배포를 위한 툴로 Vercel, Netlify, GitHub Page가 고려되었는데, 배포할 프로젝트의 규모가 크지 않고, 최대한 간편하게 배포하기를 원했기 때문에 Netlify를 사용하여 배포했어요.

돌아보기

Liked

Lacked

Learned

Longed for

나오면서

첫 팀 프로젝트였던만큼 두렵기도 했고 설레이는 마음도 있었는데, 딱 정확히 반반이었던 것 같습니다. 처음 기능구현 사항을 확인했을 때는 이걸 언제 다 구현하나 싶었지만, 막상 닥치고 나니 어떻게든 구현하는 저를 볼 수 있었습니다. 물론 주어진 요구사항을 구현하는 것주어진 요구사항을 분석하면서 더 나은 서비스를 만들기 위해 노력하는 것 사이에는 큰 간극이 있지만, 전자도 해냈으니 점점 발전하면서 후자도 해낼 것이라고 믿습니다.

Travelus Feedback

그리고 동료평가 받기 전까지만 해도 팀원으로서 너무 별로였다는 평가가 있으면 어떡하지 걱정을 많이 했는데, 다행히 모든 피드백들이 내가 프로젝트에 열심히 기여했다고 이야기해 주고 있어서 조금은 뿌듯했습니다. 하지만 공통적으로 너무 무리하지 말고 건강을 꼭 챙기라는 이야기도 있어서 다음에는 꼭 건강도 관리하면서 프로젝트를 진행해야겠습니다.