엘리스 두 번째 팀 프로젝트 회고

개발

엘리스 두 번째 팀 프로젝트 회고
최종 수정일:

프로젝트 소개

엘리스 SW 엔지니어 트랙이란 커리큘럼 속에서 꽤 오랜 시간 함께 교육을 들었으나, 비대면으로 진행된 탓에 교육생 간 소통이 원활하지 못했습니다.
더군다나 수료 후에도 지속해서 교육생을 묶어줄 커뮤니티의 부재를 해결하고자 커뮤니티를 제작하게 되었습니다.

안타깝게 AI 트랙을 4기 동안이나 진행하면서도 없던 커뮤니티가 저희 수료 날에 디스코드 서버로 생겨버린 탓에 흐지부지되긴 했습니다.

엘리스에서 제공해준 서버 외에도 제 서버 2대를 사비로 투자했고, 팀원 분 aws 프리티어 클라우드도 투자했고, coderland.dev이란 도메인까지 사비로 구매해 여러모로 진심으로 준비한 프로젝트였으나, 결과가 조금 아쉽게 돼버렸네요.
주제 자체가 엘리스 측에서 뭔가 진행하면 바로 엎어지기 쉬운 주제라 꾸준히 생각하고 경계하고 있었으나, 이리 빨리 엎어지는 것까진 안타깝게도 예상하지 못했습니다.

기술 스택

Frontend

TypeScript React CSS3 Jest Vite

Backend

TypeScript Express.js Jest PHP

Database

MongoDB

Server

Nginx

Version Control

Git GitLab

CI / CD

GitLab CI

OS

Ubuntu

서버 구조

코더랜드 서버 구조

시작하기 전 세운 목표

위 네 목표를 큰 틀로 잡고 시작했습니다.

잘 한 것

코드 리뷰

코드 리뷰

1차 프로젝트 땐 바닐라로만 작업해야 해서 구현할 것도 많은데 시간은 촉박해 문제를 전부 제가 해결해버릴 때가 많았습니다.
알량한 재주로 타인의 성장 가능성을 뺏은 것 같단 죄책감도 있고, 팀원분들께 도움이 되고자 하는 마음도 있어 이번엔 바쁜 와중에도 짬 내서 코드 리뷰를 꼼꼼히 진행했습니다.

Master - Sprint - Dev 구조로 브랜치를 만들어 진행했는데, Dev 브랜치에서 각자 기능을 구현한 뒤 Sprint 브랜치로 병합하고, 스프린트 단위가 끝날 때마다 Master로 병합하는 방식을 취했습니다. Dev 브랜치에서 Sprint 브랜치로 병합할 땐 제가 확인하고 병합을 진행하고 Master로 병합할 땐 코치님이 리뷰를 진행해주셨는데, 확실히 리뷰어가 있으니 많은 문제를 줄일 수 있었습니다.

등의 다양한 장점이 있었고, 앞으로도 반드시 해나가야겠다고 생각합니다.

코드 리뷰를 받으러 들어갔다가 어째 하고 온 게 더 많아진 것 같지만, 코드를 읽는 능력 등도 향상됐고 제가 파악하지 못하던 문제를 코치님께 피드백도 받았으니 여러모로 서로에게 큰 도움이 되었다 생각합니다.

테스트 환경 구성

두 개 모두 아주 큰 도움이 되었습니다.

useEffect를 잘못 활용해 글 상세 페이지에 접속하면 api 요청을 보내고, 상태가 업데이트되면 다시 api 요청을 보내는 아주 기막힌 상황인데, 가장 인상적인 오류였기에 들고 와 봤습니다.

이런 이슈 몇 개 때문에 제 서버가 수차례 의도치 않은 DDoS 공격을 받아내야 했고, 외에도 수차례 CI와 코드 리뷰로 미처 걸러내지 못한 오류를 배포 전에 잡아낼 수 있었습니다. 실험적인 기능을 도입할 때에도 실 서버와 거의 같은 상황에서 동작 여부를 테스트할 수 있으니 로컬 환경보다 훨씬 신뢰할 수 있는 테스트 결과를 제공해줬습니다.

더불어 브랜치에 변화가 있을 때마다 자동으로 배포가 이뤄지니, 온전히 개발과 코드 리뷰에만 집중할 수 있는 환경이 제공되어 최대한 애플리케이션 제작에만 집중할 수 있었습니다.
물론 Gitlab CI 설정하느라 한나절 정도를 까먹긴 했습니다만…개발 기간이 조금 더 길었더라면 투자한 시간보다 훨씬 많은 시간을 절약할 수 있었으리라 생각합니다.

컨벤션 제작

git 컨벤션

'한영 전환하기 귀찮아서'란 단소 단순한 이유로 커밋 메시지나 주석은 전부 영어로 작성해왔습니다.
하지만 영어로 커밋 메시지를 작성하면 읽을 때도 쓸 때도 한글보다 힘들단 의견에 커밋 메시지를 한글로 작성하는 방향으로 진행했습니다.
동사가 가장 앞으로 와 무슨 커밋인지 바로 파악할 수 있는 건 영어의 큰 장점이라 생각해, Fix, Update, Implement 등의 키워드를 추가해두고 메시지의 제일 앞에 대괄호로 추가하도록 진행했습니다.

외에도 제작 과정에서 가독성 향상과 통일성을 위해 코딩 컨벤션을 자잘하게 만들어가며 진행했고, CSS 네이밍 컨벤션도 BEM으로 통일하여 진행했습니다.

팀이 공유하는 규칙이 있어야 많은 일이 수월해진단 것을 다시금 뼈저리게 느꼈습니다.

직접 구현하는 습관

유독 웹 프론트엔드에서 자주 보이는 현상인데, 외부 라이브러리 등에 과하게 의존하는 것 같단 느낌을 받을 때가 가끔 있습니다.

등을 직접 구현했고, 애플리케이션에 적용하기에 부족하지도 않았습니다.

코더랜드 의존성

도무지 시간 내에 구현하지 못할 것 같은 의존성만 추가했습니다.

대부분 라이브러리는 최대한 다양한 기호에 맞출 수 있게 제작되거나 최대한 다양한 상황을 처리하도록 제작돼 불필요하게 거대할 때가 많습니다. 사용자화가 아무리 뛰어나다 한들 애플리케이션에 녹여내는 게 힘들 때도 있고요.

직접 만들며 많은 공부도 되었고, 성능도 충분했으며, 두 프로젝트 모두 코치님께 칭찬을 들으면 들었지 흠이 되지 않았고, 일정 내에 결국 모든 걸 소화했습니다. 사이드 프로젝트나 학습의 목적이 어느 정도 포함된 프로젝트에선 이런 습관을 들여두는 게 나중에 자산이 되리라 생각하기에, 앞으로도 이 습관을 유지하며 다양한 시도를 해볼 생각입니다.

export default function formatClassName(...names: Array<unknown>) {
  return names.filter((x) => !!x).join(" ");
}

목록에 없는 것 중 간단하지만 꽤 많이 활용한 유틸리티입니다.

<div className={`my-component ${state ? "my-component--state" : ""}`} />
<div className={`my-component${state ? " my-component--state" : ""}`} />

JSX를 사용하다 보면 꽤 자주 보이는 코드인데, 위의 방식을 사용하면 코드 에디터에선 깔끔하게 보이지만 HTML 렌더링이 지저분하고, 아래의 방식을 사용하면 개발하긴 힘들어도 렌더링 결과가 깔끔합니다.
둘 다 불필요하게 삼항 연산자를 사용해야 한단 문제도 있고요.

<div className={formatClassName(
  "my-component",
  state && "my-component--state"
)} />

개발 과정에서도, 렌더링 결과도 포기하지 않고 불필요한 삼항 연산자도 사용하지 않아도 되게 해줍니다.

더미 데이터 활용

아무래도 백엔드와 프론트엔드의 개발 속도가 같긴 힘듭니다. 프론트엔드에서 api 요청 결과가 필요한 시점이 와도 백엔드는 아직 DB 구조도 다 못 짰을 수도 있을 만큼 둘의 속도는 아주 다릅니다.
명세를 작성하고, 필요한 정보를 공유한 뒤, 인터페이스를 작성하고 더미 데이터를 추가하는 것까지는 당연히 진행했습니다.

export default async <T>(data: T) => data;

저번 프로젝트에서 아쉬웠던 것이, 더미 데이터를 바로바로 불러와서 사용하다 보니, 비동기를 처리하는 코드를 나중에 따로 작성해야 하고, import를 너무 중구난방으로 하는 결과가 발생해 상술한 것처럼 간단한 함수를 작성하고, dummy.ts란 파일에서 모든 더미 데이터를 관리하고, 위 함수를 거쳐 반환해 비동기 처리까지 미리 끝내둘 수 있었습니다.

문제가 된 것

부족한 기획

아이디어가 괜찮았고, 디자인보단 CSS 작성이 익숙한 사람들이라 기획이 여러모로 부족한 상태에서 개발을 시작했습니다.

그러다 보니 이 부분엔 과연 어떤 디자인이 합리적인지, 이 기능이 추가되는 게 맞는지 등의 문제와 마주할 때마다 고민하느라 꽤 많은 시간을 투자해야 했습니다.
또한 제작 과정에서 상술한 것처럼 '엘리스에서 무언가 진행하면 바로 엎어질 기획'이란 점이 내내 마음에 걸려 프로젝트의 방향성에 관한 논의도 가끔 스크럼에서 꺼냈습니다.

개발을 조금만 천천히 시작하고 깊은 고민을 했더라면 어느 정도 해결되었을 문제들이라 생각합니다.
다음 프로젝트부턴 반드시 일정 기간 이상은 기획에 투자해야겠습니다.

다소 아쉬웠던 소통

발생하고 있는 이슈나 특정 안건에 대한 생각이 자유롭게 오가지 못했단 느낌이 개발 과정에도 그렇고 끝나고 돌아보면서도 그렇고 많이 듭니다.
분위기가 이렇다 보니 저도 세부적인 일정을 계획해나간 걸 쉬이 공유하지 못했고, 팀원 분들도 이슈가 있을 때 쉽게 꺼내시지 못한단 느낌을 받았습니다.

자연스럽게 팀 단위의 효율을 끌어올리는 데 제동이 걸렸단 느낌이 들었고, 초기 기획 단계에서 '구현하면 좋지 않을까' 싶었던 채팅 기능은 끝내 제작하지 못했고, 1차 프로젝트 때보다 서로 열심히 하며 동기 부여되는 게 조금 약해진 것 같습니다. 시간에 쫓기다 프로젝트 막바지엔 일과를 분 단위로 짜두고 생활해야 하는 힘겨운 상황이 벌어지기도 했고요.

스크럼과 오피스 아워를 최대한 기록해두고, 코드 리뷰를 열심히 하며 문제가 될 것 같은 상황을 찾아내려 노력도 했으나 근본적인 문제 해결책은 아니었단 생각이 강하게 듭니다. 잡담도 쉽게 쉽게 할 수 있는 분위기를 만드는 방법에 관해 고민을 해봐야 할 것 같고, 혹여 그런 분위기가 생성되지 않더라도 적어도 이슈는 쉽게 공유할 수 있도록 다양한 협업 툴을 조사해봐야겠단 생각이 들었습니다.

전역 상태관리 능력

단적인 예시로 새 알림 존재 여부를 api 요청 시에 서버에서 반환해주는데, GNB에 해당 상태를 출력하기 위해 window에 Dispatch 함수를 등록해두고 api 요청을 보낼 때마다 새 알림 존재 여부를 확인해 해당 Dispatch 함수에 전달하도록 해뒀습니다.
api 요청 시 중복되는 작업을 처리하기 위한 함수를 제작했는데, 해당 함수는 함수형 컴포넌트가 아니기에 Context API를 활용한 훅을 제작하기도 어려웠고, 해당 함수를 Context API로 관리하는 것도 과투자란 생각이 강하게 들었습니다. 이미 Context API로 관리하는 상태가 4개나 있기도 해 더 추가하기도 꺼려지는 상황이었고요.

결국 주어진 시간 내에 확실한 처리를 위해 전역에 Dispatch 함수를 등록했는데, 그리 권장되는 방식은 아닐 것 같아 전역 상태관리에 관한 내용을 조금 더 공부해봐야 할 것 같습니다.
아직 외부 라이브러리를 도입할 만큼 프로젝트 규모가 크진 않다고 생각해 꾸역꾸역 Context API를 활용했는데, 너무 유연하지 못했나 싶기도 합니다. 가독성, 성능 등 다양한 지표에서 각종 라이브러리와 Context API도 비교해봐야겠습니다.

추가로 할 것

문서화

Typescript 코딩 표준

노션에서 확인

팀이 공유하는 다양한 규칙의 문서가 작성돼 있으면 좋겠다는 생각이 들어 코딩 표준부터 작성해가기 시작했습니다.
작성할 땐 네이버도 Airbnb 규칙 조금 수정해서 쓰던데 큰 의미가 있을까 싶을 때도 있었지만, 과정에 다양한 좋은 자료를 보며 생각을 정리한 부분이 많아 꽤 많은 도움이 됐습니다.

Git 컨벤션 등도 추가로 정리해볼 생각입니다.
이게 나름 문서 작성하며 정리하는 재미도 쏠쏠하네요.

여담으로, 노션 에디터에 잡렉도 많고, 해시로 페이지 내에서 이동할 때도 반 박자 느린데다, 구문 강조도 영 신통찮아 작성이 끝나면 다른 곳에 정리할 생각입니다.

Figma 익히기 및 디자인 공부

Figma를 기본적인 수준 밖에 다루질 못하니 이런저런 제약이 많았습니다.
디자인도 참 안타까운 수준이라 아직 갈 길이 멀다 싶네요.

Figma를 익히는 과정이 투자 대비 효용 가치가 현저히 낮다고 판단되면 디자인 라이브러리 같은 거라도 간단하게 만들어볼 생각입니다.

리팩터링

지금까지 경험을 바탕으로, 머리론 알고 있지만 귀찮아 굳이 하지 않았던 것들, 작업하며 깨달은 것들 등을 기반으로 차근차근 리팩터링을 시작했습니다.
언제나 단순히 만들고 끝내는 게 아니라 꾸준히 유지 보수하는 게 중요하다고 생각하기에, 지금 배포되어있는 서비스 대부분을 차근차근 고쳐갈 예정입니다.

클린 코드, 리팩터링 같은 책도 읽어볼까 싶어 주문해뒀습니다.

끝내며

앞선 1차 프로젝트에서 에너지를 엄청나게 소비한 뒤 시작한 프로젝트라 마른걸레 쥐어짜듯 에너지를 쥐어짜며 작업했습니다. 더욱 잘하고 싶은 마음만큼은 줄지 않았기에 솔직히 힘들지 않았다면 거짓말일 겁니다.
분명 눈은 뜨고 있는데 여기가 꿈인지 현실인지도 모르겠고, 멍해지는 시간도 길어지고, 정신적으로나 물리적으로 피폐해지는 와중에도 확실했던 건, 전 분명히 이걸 즐기고 있었단 겁니다. 결과물을 보며 벅차오르는 감정을 주체하지 못하겠을 때 다시금 제가 코딩을 얼마나 좋아하는지 깨달을 수 있었습니다.

작업하며 모차르트(W. A. Mozart)의 교향곡 41번을 다시금 듣기 시작했습니다. 아주 정교한 푸가 형식(곡의 대위법을 분석한 유튜브 비디오)을 듣자마자 악보를 찾아보고 충격에 휩싸여 몇 날 며칠을 저 곡만 들었는데, 서버들을 설정하고 CI / CD가 개발이 진행될 때마다 잘 작동하는 걸 보고 있으니 저 곡을 처음 들었을 때의 전율을 다시금 느낄 수 있었습니다. 물론 저만큼의 정교함엔 턱없이 못 미치지만, 제 자식이 더 예뻐 보이는 법 아니겠습니까.
저 곡을 들은 뒤로 존경하는 아키텍트에 모차르트도 추가되었는데, 존경하는 아키텍트께 한발 다가간 느낌도 들고 좋네요.

팀 프로젝트란 경험도 즐거웠기에, 사이드 프로젝트라도 더 해보고 싶은데, 사람을 어디서 어떻게 구할지가 애매하네요.

더욱 열심히 나아가겠단 다짐과 함께 이만 맺겠습니다.

Report an issue