Dig-Dig-Deep 프로젝트 회고
2023.09.23
Table of Contents
1월 5일부터 1월 20일까지 약 2주간 진행된 프로젝트를 기획하고 개발하였습니다.
기획
프로젝트 시작 전에도 여러 가지 아이디어를 제시하고 이에 대해 이야기했었지만 API를 확인한 뒤에는 이를 최대로 활용하고 가능성이 높은 프로젝트들을 브레인스토밍을 통해 도출하였다.
기획 회의 피그잼
특강에서 보았으나 잘 알지 못했던 신문물(?)에 익숙한 팀원 덕분에 피그잼을 활용하였고 두가지 후보가 있었으나 최종으로 내가 제시한 아이디어가 선택되어 이번 프로젝트에 더욱 책임감이 느껴졌다.
이후 유저스토리를 작성해보며 프로젝트 주요 타겟을 정하고 간단한 사용 시나리오를 작성해 보며 콘셉트를 잡아 나갔다.
프로젝트 소개
🦔 커뮤니케이션을 통한 학습을 제공하는 개발자 전용 SNS
이번 프로젝트 주제는 "React 혹은 Vue.js 이용하여 소셜 네트워크를 구현"이었다. 기획 단계에서도 학습, 스터디에 대한 내용이 주를 이뤘기 때문에 위와 같은 프로젝트 주제를 정하였고 재미 요소를 추가할 수 있는 새로운 두 가지 개념을 추가하였다.
개발자들이 "그라운드"에서 "디깅"을 통해 지식이 깊어질 수 있는 커뮤니티.
- 그라운드: 하나의 주제와 관련된 포스트를 의미한다.
- 디깅: 댓글을 남기는 행위를 의미한다.
처음 아이디어를 제시할 때 항상 깊이있는 학습이 중요하다는 말을 자주 들었지만 막상 공부하다 보면 넘어가게 되는 부분이 많다고 느꼈다. 누군가 내가 확인하지 못한 부분을 추천해 주거나 함께 알아간다면 어떨까 하는 아이디어에서 시작되어 팀원들의 아이디어가 더해져서 더 깊게 들어가는 디깅이라는 단어와 그라운드를 사용하게 되었다. (또한 이에 어울리는 로고로 두더지를 선택하였다.)
개발 문화
Git branch 전략
협업으로 진행되는 만큼 각 팀원들이 각자 역할을 가지고 진행되었다. 디자인, 문서화, Github 관리, PM, 프로젝트 설정등으로 나누었고 나는 여기에서 Github 관리를 맡게 되었다.
프로젝트 시작 단계에서 바로 issue 템플릿과 pull request 템플릿을 만들었다. 팀에서 진행할 git branch 전략을 위해서 필요한 내용이였기 때문이다. 우리는 이슈를 통해 브랜치를 만들고 이를 pull request하는 방식으로 진행되었다.
또한 pull request에 한명 이상 Approve 해야 머지할 수 있도록 하였고 코드리뷰를 통해 코드 품질을 관리할 수 있었다.
기술 스택
TypeScript와 React를 사용하였고 스타일링을 위해 Styled Components를 사용하였다. 타입스크립트를 사용해 본 경험은 없었으나 팀원들과 진행하는 프로젝트인 만큼 이번 기회에 사용법을 익히며 진행해보고자 했다.(부딪히며 배우게 되었고 이 부분에서 팀원의 도움을 많이 받게 되어 감사함을 느낍니다..🙇🏻♂️) 역시 팀원들이 있기에 두려움없이 사용해 볼 수 있었던 것 같다. 각 기술들의 장점과 단점을 느껴볼 수 있었다.
장점
- TypeScript - 타입을 미리 지정해줌으로써 휴먼에러를 많이 줄여주고 데이터 자동완성 기능 덕분에 편리한 작업을 이어갈 수 있었다.
- Recoil - 초기 설정을 진행해준 팀원 덕분에 짧은 코드로 전역상태값을 사용할 수 있어 아주 편리했다.
단점
- TypeScript - 익숙하지 않고 제대로 타입을 지정해줘야 하기에 번거로움이 있다. (모든 타입을 any로 사용할 수 없기 때문에)
- Recoil - 이번 프로젝트는 규모가 크지 않았기에 전역 상태값에 대한 토의를 팀원과 계속 진행하게 되었다.
기능 구현
프로젝트를 진행하며 내가 개발한 내용들은 아래와 같다.
검색 기능
키워드로 사용자와 그라운드를 분리하여 검색 가능하다. (깨알 같은 애니메이션도 사용감을 높이기 위해 적용하였다.)
여기서 사용한 방법은 useSearchParams를 활용하여 q와 type으로 쿼리를 나누어서 searchPage로 이동하며 함께 넘겨주고 이를 통해 검색되도록 하였다. 원래 API의 내용은 그라운드 + 사용자, 사용자로 구분되어 있고 그라운드와 사용자가 따로 분리되어 있지 않았지만 팀원들의 의견을 통해 분리를 시도하였고 두 검색 API result의 차이점을 활용하여 분리하고 각 내용을 추가하는 것이 아닌 Promise.all로 한 번에 상태값에 저장되도록 코드를 작성하였다.
한 가지 아쉬웠던 점은 각 포스트를 따로 가져와 한번에 표시해줘야 하기 때문에 검색 결과가 많지 않더라도 로딩시간이 길다는 점이었다. 이 문제에 관해서는 리팩토링을 통해 API를 개선하여 가져오면 좋을 것 같다고 생각하였다.
const getSearch = useCallback(async () => { const getType = searchParams.get('type'); const getSearchTerm = searchParams.get('q'); setLoading(true); if (getType === 'users') { const { data } = await axiosInstance.get<UserResponse[]>( `/search/users/${getSearchTerm}` ); setUserResult(data); } if (searchParams.get('type') === 'posts') { const { data } = await axiosInstance.get<PostResponse[]>( `/search/all/${getSearchTerm}` ); Promise.all( data.reduce<Promise<PostResponse>[]>((prev, post) => { if ('author' in post) { prev.push(getPost(post._id)); } return prev; }, []) ).then((data) => setPostResult(data)); } setLoading(false); }, [searchParams]);
메인 피드 구현
10개의 피드만 불러오고 무한스크롤을 통해 더보기 기능을 구현하였다.
무한스크롤은 강의를 통해 학습한 IntersectionObserver로 마지막 부분에 observer에 닿으면 그라운드를 더 불러오는 함수를 실행하도록 구현하였다.
이번 기능에서도 API에서 약간의 한계가 있었지만 방법을 찾아 구현할 수 있었다. 내가 해결한 방식은 채널 관련 data를 요청하면 모든 포스트의 내용이 담긴 배열이 아닌 id값만 포함한 배열을 가져온다. 이를 통해 빠른 속도로 총그라운드의 수를 알 수 있고 한번 더 data를 fetching하는데 주어진 limit & offset으로 이미 모든 그라운드를 표시했다면 더 로딩하지 않는 코드를 작성하였다.
좋아요
좋아요 버튼 기능을 토글로 구현하였다. Recoil에 저장된 user 정보를 활용하여 여부를 확인하여 사용자에 따라 다르게 보여준다. 로그인이 안된 상황에서는 토스트를 띄워준다.
const handleLike = async () => { const isLike = likesState.findIndex((like) => like.user === user._id); if (!token) { return showToast({ message: ERROR_MESSAGES.REQUIRE_LOGIN }); } if (isLike === -1) { try { const { data } = await createLike(_id); setLikesState([...likesState, data]); await getMyInfo(); sendNotification('LIKE', data._id, author._id, _id); showToast({ message: SUCCESS_MESSAGES.LIKE_SUCCESS }); } catch (error) { console.error(error); showToast({ message: ERROR_MESSAGES.SERVER_ERROR }); } } else { try { setLikesState( likesState.filter((item) => item._id !== likesState[isLike]._id) ); deleteLike(likesState[isLike]._id); if (user.likes) { getMyInfo(); } showToast({ message: SUCCESS_MESSAGES.UNLIKE_SUCCESS }); } catch (error) { console.log(error); showToast({ message: ERROR_MESSAGES.SERVER_ERROR }); } } };
공유 기능
공유 버튼을 클릭하면 클립보드에 해당 그라운드의 링크를 저장한다. useNavigator를 통해 어렵지 않게 구현할 수 있었다.
const handleShare = () => { navigator.clipboard.writeText(`${window.location.host}/posts/${_id}`); showToast({ message: SUCCESS_MESSAGES.SHARE_SUCCESS }); };
댓글
댓글 작성과 본인의 글인 경우 삭제가 가능하도록 구현하였다. 사용성을 위해 댓글을 작성하면 맨아래로 스크롤을 내리는 기능도 구현했다.
이와 관련된 내용을 블로그에 따로 작성하였습니다.
각 컴포넌트, 페이지
내가 구현한 부분들은 퍼블리싱까지 직접 진행하였는데 TopDown 방식으로 자주 사용되는 부분이 있다면 컴포넌트로 분리하는 방식으로 코드를 작성했다. 메인 페이지의 헤더, 각 그라운드의 사용자, 상세 페이지, 댓글 로그인 여부, 본인의 그라운드 혹은 댓글일 때 각 페이지에 따라 내용에 따라 달라지는 화면을 처리하는 내용이 생각보다 복잡해서 시간을 많이 소비하였지만 로직대로 괜찮은 결과물을 작성하였다고 생각한다.
여기서 깔끔한 코드를 작성하지 못한 것 같아 아쉬움이 많이 남는다. 이 또한 리팩토링을 통해 컴포넌트들의 코드를 조금 더 분리하고 재사용성이 좋게 개선해보려고 한다.
이외에도 그라운드 삭제, 수정 그리고 알림 전송과 같은 API 통신 관련된 부분을 구현하고 팀원들이 수월하게 작업할 수 있도록 구현하여 따로 util/api 파일에 정리하였다.
협업
처음으로 협업을 진행하는 만큼 가장 익숙하지 않았던 점은Git, GitHub 사용이였다. 물론 개인 프로젝트를 진행하며 나름 자신감을 가지고 있었지만 브랜치 전략을 사용하는 만큼 사용해보지 못한 다양한 기능들을 사용해야 했다.
이슈와 브랜치, 각 컨벤션에 맞춰 pull request를 작성하는 일이 번거로울 수 있었지만 사용하다 보니 금방 익숙해졌고 정해진 틀이 있으니 편하다는 생각이 커졌다. 더 많은 기능을 사용해보고 싶다는 생각에 마일스톤과 프로젝트도 잠깐 사용해 보았다.
소통에 있어서는 팀원들과 필요에 따른 회의와 하루에 두 번 정도의 스크럼을 진행하며 정말 많은 소통을 하였다. 이러한 방식을 토대로 서로가 원하는 UI나 기능들을 만족스럽게 구현할 수 있었다고 생각한다. 또한 코어 타임 동안은 바로바로 질문을 할 수 있었고 모든 팀원들에게 도움을 받고 또 줄 수 있었다.
그리고 KPT(keep, problem, try) 방식을 적용하여 기술 관련, 협업 관련 부분들에 대한 각자의 고민과 진행사항을 중간 회고를 진행하며 소통하였고 다른 팀원들의 고충도 들을 수 있어서 팀워크에 큰 도움이 됐다.
프로젝트를 마치며
돌이켜 생각해 보면 이번 프로젝트를 진행하며 가장 고민했던 부분은 API 통신 후 데이터 갱신에 대한 것이었다. 라이브러리를 사용하지 않았기에 하나씩 직접 작성하는 번거로움과 캐시를 적용해보지 못한 것에 아쉬움이 있어서 프로젝트 중간에 멘토님에게 질문을 했고 React query 라이브러리에 대해 설명해 주셨다. 리팩토링을 진행할 때 해당 라이브러리를 접목해보고 싶다.
그리고 과제에 제공된 기본 구현사항과 추가 사항에 집중하다 보니 디그디그딥만의 강점이 잘 드러나지 못한 부분이 아쉬웠다. 비즈니스적인 면에서 매력적인 기술을 사용해야 할 필요성을 느꼈고 이를 위해 코드를 효율적으로 보여주는 에디터 기능을 추가하는 것을 생각하고 있다.
위에서도 언급했지만 깔끔한 코드를 위한 리팩토링은 매 프로젝트마다 필요하다고 느끼기 때문에 이 또한 진행하려고 한다.
아쉬운 점도 많이 있지만 처음 진행해 본 팀 프로젝트였던 만큼 많은 내용을 배웠다. 2주 만에 이 정도의 프로젝트를 만들 수 있다는 협업의 효율적인 면을 느꼈고 앞으로도 다양한 협업을 진행해보고 싶다.
마지막으로 프로젝트를 진행하기 전에 내가 목표로 삼았던 내용이 있다.
각자 강점을 드러낼 수 있는 프로젝트로 나중에 취업에서도 플러스가 될 수 있는 경험을 해보고 싶다.
프로젝트를 마치고 팀원들과 이야기할 때 모두가 인정했던 부분은 각자 장점을 최대한 보여주었다는 점이다. 협업에서는 개발이 중요하지만 그 외에도 많은 점들이 필요하다는 것을 느끼게 되었고 2주라는 짧은 기간 동안 프로젝트를 완성할 수 있었던 건 팀원들이 모두 자신의 역할을 다 해주었기 때문이라고 생각한다.
흐지부지 리팩토링 없이 넘어가지 않는 것이 다음의 목표다. 벌써 다음 팀 회의 일정이 잡혔기 때문에 내가 아쉽다고 느꼈던 부분을 꾸준히 개선해 나가야겠다.