[회고] 북스테어즈: 꿈꾸던 이상적인 협업

웹프론트엔드 리드 개발자로서 참여한 프로젝트, 북스테어즈가 드디어 1차 릴리즈에 성공했습니다. 본 게시물에서는 북스테어즈에 대한 소개와 함께 전반적인 협업 방식과 사용한 기술에 대해 소개하려 합니다.

1. 진짜 독서가들을 위한 독서법, 북스테어즈(BookStairs)

📚 이미지를 클릭하면 사이트로 이동합니다. 📚

팀원들의 회고록 보러가기

메인 PM의 서비스 기획 일지
디자이너의 회고
웹 프론트엔드 개발자의 성장 회고

그 외 링크

전체 팀원 소개 구경하기(클릭)
북스테어즈 깃헙 구경하기(클릭)
디스콰이엇 - 북스에터즈 게시물 구경하기(클릭)

2. 팀 협업 방식

잠깐 사전 지식!
북스테어즈국내 최대 규모의 IT 벤처 창업 동아리, 솝트(SOPT) 29th 프로젝트 팀의 결과물 입니다. 매 기수 SOPT에서는 기획, 디자인, 웹, 안드로이드, iOS, 서버파트가 8주 간의 세미나로 필요한 지식을 습득합니다. 그리고 구현하고 싶은 아이디어가 있는 사람들이 기획경선에서 메인 PM으로서의 자격을 얻어 팀원을 모집할 수 있게 됩니다. 기획/디자인/클라이언트/서버가 모여 10명 내외의 팀원이 만나 총 5주 동안 프로젝트를 진행하게 되는데, 이를 SOPT에서는 앱잼(APP JAM)이라고 칭합니다.

팀 북스테어즈는 모두가 한 그림을 그릴 수 있도록 매일 밤 전체 회의를 진행하고, 3개의 협업툴(노션, 슬랙, 피그마)을 주로 사용했습니다.

2-1. 노션

각 파트의 진행상황을 모아보고, 각종 이슈를 관리하고, 회의록을 작성하는 등 대부분의 문서 작업은 노션으로 진행했습니다. 덕분에 문서가 분산되는 것을 최소화할 수 있었고, 칸반보드를 적극 활용함으로써 다른 파트와의 타임라인을 맞출 수도 있었습니다.

2-2. 슬랙

개인적인 연락이나 급한 연락은 카카오톡을 사용했지만, 프로젝트와 관련한 대부분의 이야기는 슬랙을 통해 전달했습니다. 개인과 개인 간의 DM은 지양하고, 가능한 모든 내용을 투명하게 모든 팀원들과 공유하는 것을 원칙으로 했습니다. 내용이 흩어지지 않도록 이슈마다의 관련 답변은 스레드로 작성했습니다.

2-3. 피그마

모든 디자인은 피그마로 전달되었습니다. 북스테어즈의 디자이너들은 최소한의 에셋과 설정으로 개발에서의 자원적 낭비를 최소화해주었습니다. 개발팀 역시, 개발에서의 편의보다는 유저의 입장에서 필요한 기능인지를 먼저 생각하며 디자인팀의 요구사항을 반영하는 것을 우선으로 하였습니다.

특히, 디자인 팀에서 제공한 글꼴과 색상에 대한 세팅이 아주 인상적이었습니다. 웹 프론트엔드 팀은 global로 적용될 style theme을 먼저 세팅한 후 작업을 시작합니다. 이는 추후 스타일이 변경될 때 변수의 내용만 변경하면 모두 반영될 수 있도록 유지보수의 측면에서 매우 좋습니다. 이를 위해 디자인팀에서도 피그마에 글꼴과 색상을 모두 등록해 너무 다양한 스타일이 사용되지 않도록 경계해주었습니다.

style theme에 사용될 변수 네이밍 방식
가령, 프로젝트에서 사용될 색상을 위 사진처럼 미리 변수로 등록해 사용한다고 가정해봅시다. 같은 orange여도 조금씩 다른 명도/채도 등의 이유로 코드는 달라지기 마련입니다. 이를 위해 변수 네이밍을 잘 정해야하는데, 같은 계열의 색상에 대해 100, 200 등의 숫자를 부여하는 것을 추천합니다.

1,2,3이 아닌 100,200인 이유는 추후 중간에 색상이 추가될 경우 orange150 등의 이름으로 사용할 수 있기 때문입니다. 예를 들어, 연분홍 pink100과 진한분홍 pink200을 사용해 프로젝트를 진행하다가, 모종의 이유로 이 가운데에 위치할 애매한 분홍2개가 추가된다면 pink150 pink175 등의 이름을 사용할 수 있습니다. 만약 pink1, pink2로 지어두었다면, pink1.2 pink1.5 등이 될 수도 있고, 온점이 변수명에 사용될 수 없는 언어라면 pink1, pink12, pink15, pink2 등의 요상한 네이밍이 될 가능성이 있습니다.

출처: 디자이너스 인스타그램 게시물

3. 웹 프론트엔드 협업 방식

여기서부터는 웹 프론트엔드의 협업과 기술에 대한 이야기를 합니다.

3-1. 전체 룰

  1. 정기적으로 상황을 공유할 수 있도록 타임테이블을 정합니다.
    아래는 실제로 2주 동안 합숙하며, 매일 공유하는 것을 원칙으로 했던 시기의 타임테이블 입니다.
  • 18시까지 작업 내용 PR 날리기
  • 21시 30분까지 코드 리뷰하기
  • 21시 30분 웹파트 회의 - PR 확인 후 머지 & 회고
  • 23시 전체 회의 참여
  • 이후 코드리뷰 반영이나 수정 등 각자 작업 후 취침
  1. 주의해야할 워딩을 정합니다.
    의도가 보이는 장난은 가능합니다. 대신 팀원이 싫어하는 워딩은 지양합니다.
  • 금지어 목록: ㅋㅋ(ㅋ 두개가 붙어있는 것만 아니면 됨), 어?(많은 사람들이 아는 금지어, 욕은 가능)
  1. 칭찬도 좋지만, 팩폭합니다.
    자신의 할 일을 제대로 하지 않아 발생하는 일들에 대한 지적도 필요합니다. 사과는 지양하고 "알려줘서 고맙다"는 감사와 인정을 지향합니다. 또한, 말하는 사람도 듣는 사람도 피드백에 대해서는 쿨하게 인정합니다.

  2. 주기적으로 코드리뷰하고 컨벤션에 신경쓰기

  • 마치 한 사람이 짠 코드처럼 보이게 하는 것을 목표로 합니다.
  • 모두가 코드를 이해할 수 있도록 모르는 것은 자유롭게 질문하고 공유할 수 있는 편안한 분위기를 조성합니다.
  1. 질문은 바로바로!합니다.
  • 만약 바로 물어보기 애매한 상황이라면 커밋메시지와 라벨을 통해 확인할 수 있도록 합니다.

3-2. 함께 자라기

SOPT에서 만나, 각자가 경험한 것을 양껏 사용해 함께 공부하며 만들어가는 프로젝트인 만큼 우리에게 가장 중요한 것은 "함께 자라는 것"이었습니다. 이를 위해, 어떤 상황에서도 가장 높은 우선순위를 갖는 기준들을 다음과 같습니다.

  • 주기적으로 자신을 되돌아보는 회고 문화를 지향합니다.
    프로젝트를 빠르게 진행하는 집중 개발 기간에는 바쁘더라도 오히려 매일 회고를 진행했습니다. 서로의 상황과 감정을 공유하며 덜 지치고 즐겁게 개발할 수 있는 분위기를 만들고 싶었기 때문입니다. 또한, 회고가 부담이 되지 않도록 가벼운 말과 농담을 섞어 편한 분위기에서 진행합니다.

  • 적극적으로 피드백을 주고 받습니다.
    앞서 말한 회고는 물론, 코드리뷰를 통해 서로에 대한 피드백을 주고 받습니다. 피드백의 내용 중에는 코드를 칭찬할 수도 있고, 감정에 공감할 수도 있고, 문제를 지적할 수도 있고, 토론을 시작할 수도 있습니다. 말하는 사람과 듣는 사람 모두 서로를 배려하는 부드러운 말을 사용하되, 정확한 워딩을 사용해 오해없이 전달될 수 있도록 합니다.

  • 질문을 두려워하지 않고, 귀찮아하지 않습니다.
    각자가 경험하고 배워온 것은 모두 상이합니다. 때문에 남들이 아는 것을 나만 모를 수도 있고 그 반대일 수도 있습니다. 서로의 코드를 이해하고 함께 성장하기 위해서 모르는 것은 두려워하지말고 질문할 수 있는 분위기를 만듭니다. 이를 위해 우선되어야하는 것은 질문을 받았을 때 일말의 귀찮음의 감정도 없어야한다는 것입니다. 나도 언젠가 질문자가 될 수 있다는 것을 염두에 두고 서로를 배려합니다.

3-3. on-call 문화 지향하기

담당뷰를 배정해서 진행하는 것이 아니라, 모두가 서로의 코드를 이해하는 것이 가장 중요합니다.

언제든 웹파트로 요청이 들어왔을 때, 누구든 대응할 수 있는 on-call 구조를 지향합니다.

초반 작업을 진행했거나, 모종의 이유로 하나의 기능만을 담당하여 더 자세하게 아는 팀원이 있을 수도 있지만, 전체적인 흐름과 구조는 모두가 이해할 수 있어야합니다.

이를 위해서는 모두가 컨벤션에 유의하며 코드를 작성하고, 새로 알게된 사실이나 에러 해결 방법들에 대해서는 적극적으로 공유합니다. 그리고 이슈와 PR을 통해 서로의 작업 상황을 확인하며 자신의 타임라인을 관리합니다.

가장 중요한 것은 주기적으로 코드리뷰를 하는 것입니다. 코드리뷰에 너무 많은 시간을 쓰지 않도록 커밋은 기능 단위로 쪼갭니다. 이는 file changes를 기능별로 확인할 수 있어 코드리뷰에서의 부담을 줄여줍니다.

또한, 다른 사람의 코드를 보며 궁금한 것은 주저없이, 부끄러워하지말고 질문하며, 질문을 받은 사람도 무시나 귀찮음이 아닌 성실하고 따뜻하게 답합니다. 분명 그 과정에서도 배우는 것이 있을겁니다!

4. 웹 프론트엔드에서 사용한 기술

기본적으로 "불필요한 기술은 뺀다"는 기준으로 번들사이즈 최소화를 신경썼습니다. 동시에 "공부해보고 싶은 기술"이라면 긍정적으로 재고하는 방식을 택했습니다. 예를 들어, 디바운스 기능 구현에서 loadash를 사용하지 않고 setTiemout으로 직접 구현하고, 모바일 반응형(랜딩페이지 한정) 구현에서 실험적으로 react-responsive를 사용해보기도 했습니다.

"axios": "^0.24.0",
"framer-motion": "^6.2.3",
"react-hook-form": "^7.28.1",
"react-responsive": "^9.0.0-beta.6",
"react-textarea-autosize": "^8.3.3",
"recoil": "^0.6.1",
"recoil-persist": "^4.0.0",
"styled-components": "^5.3.3",
"styled-reset": "^4.3.4",
"swr": "^1.2.1",
"typescript": "^4.5.4"

4-1. axios, swr

서버와의 통신은 axios로 하고, mutation기능을 사용하기 위해 swr을 추가로 사용했습니다. 더 다양한 기술을 제공하는 react-query를 고려했었으나, 번들사이즈와 대비해 북스테어즈에서 실제로 사용되는 기술은 적다는 이유로 swr을 채택했습니다.

4-2. styled-components, styled-reset

기본 스타일링은 styled-components를 사용했고, global style을 적용하는 과정에서 styled-reset도 사용되었습니다.

4-3. react-textarea-autosize, framer-motion, react-responsive

반응형과 애니메이션은 가능한 css에서 기본으로 제공하는 것을 사용했으나, textarea의 auto sizing 문제를 해결하기 위해 react-textarea-autosize를 사용했고, 도전적으로 공부해보고 싶다는 이유로 framer-motion과 react-responsive를 추가했습니다.

4-4. react-hook-form

변화를 감지해야하는 변수들은 useState로 관리했으나, 하나의 state 내에서도 일부는 굳이 매 변화마다 rendering이 바뀔 필요가 없을 수 있다는 것을 발견했습니다. 이에, 일부 내용은 react-hook-form으로 관리하여 렌더링을 줄여 reflow 문제를 개선했습니다. 더 구체적인 내용은 다음 목차에서 설명하겠습니다.

4-4. recoil, recoil-persist

가능한 전역 변수 관리는 사용하지 않는 것을 원칙으로 했습니다. props로 넘겨주면서 props drilling이 심각하지는 않은지를 경계하고, 심한 경우에는 useContext로 일부 컴포넌트들에 대한 전역 변수 관리를 택하기로 하였습니다. 로그인 여부, 사용자의 북노트 id 등에 대한 정보는 useLocation의 state로 넘겨주었는데, 나중에 북노트 id의 타입이 변경되었을 때, 일일이 state를 찾으며 변경하다보니 유지 보수 측면에서 매우 불편하다는 것을 발견했습니다. 이처럼 많은 페이지에서 사용되는 변수의 경우에는 전역 변수 관리가 필요하다고 판단했고, 공부의 목적으로 recoil, recoil-persist를 추가해 사용했습니다.

5. 배운점

  1. 함께 자라기의 가능성
    상황을 투명하게 공유하고, 자신을 주기적으로 돌아보고, 팀원과 피드백을 주고받으면서 팀 북스테어즈 모두는 큰 성장을 이뤄냈습니다. 프로젝트 종료 후 다른 팀의 이야기를 들으면서 팀의 분위기를 어떻게 가져가느냐, 어떻게 운영하는가에 따라서 크게 달라질 수 있다는 것을 알 수 있었습니다.

  2. 제어가 필요한 변수와 아닌 변수를 구분하기
    아래 페이지는 책을 읽으며 자신의 생각을 질문과 답변의 형식으로 정리할 수 있게 하는 페이지 입니다. 본 페이지는 재귀컴포넌트로 구현되어, 모든 내용이 하나의 state로 관리되고 있습니다.

큰 질문이 채워지면 하단의 질문 리스트 추가 버튼이 활성화되어야하고, 큰 답변도 채워지면 작성완료 버튼을 누를 수 있게 됩니다. 그 상태를 매번 감지해야하므로 state를 택했습니다.
하지만, 꼬리질문/답변의 경우 굳이 모든 변화를 감지해야할 이유가 없음에도 상태 변화에 따라 렌더링이 계속되어 reflow 에러를 마주하기도 했습니다. 재귀 컴포넌트로 구현되어 모든 변화마다 path로 tree에서 자신의 위치를 찾아 값을 바꾸는 것은 물론 엔터와 쉬프트 엔터를 모두 확인하기 때문입니다.

이를 해결하기 위해 꼬리질문/답변의 내용을 포함해 하나의 state로 관리하는 것은 변하지 않되, 꼬리질문/답변의 경우 onChange마다 모든 상태를 감시하지는 않습니다. useForm에서 제공하는 register 기능으로 변수의 내용을 따로 기억하고 있다가, 저장이 필요한 시점에 해당 내용을 전체 state에 끼워넣는 방식으로 변경하였습니다. reflow가 감소해 해당 워닝은 더이상 발견되지 않았습니다 :)

6. 앞으로의 일정

  1. 당장 마주한 이슈 해결
    유저가 불편하다고 느끼거나, 문제가 될 수 있는 기능들은 빠르게 수정해 반영합니다.
  2. Next.js로의 마이그레이션
    react, 그 중에서도 CRA로 작업하면서 번들사이즈를 줄이는 고민과 리액트를 더 리액트스럽게 사용하는 것에 대해서 익힐 수 있었습니다. 이제는 페이지마다의 pre-rendering 방식을 고민하고, 추후 기획의도에 따라 SEO를 장악할 수 있는 서비스가 될 수 있도록 고민하면서 Next.js로 마이그레이션을 진행합니다.

책을 제대로 읽고 계신가요?

책의 내용을 머리에 담기 보다 활자만 읽고 있지는 않으신가요?

책을 읽으면서 떠오르는 내용을 그냥 넘기기 보다는 스스로 질문하고 답하면서 체계적인 독서를 해보는 것은 어떠신가요?
북스테어즈와 함께 계단식 성장을 이뤄보아요!

진짜 독서가들을 위한 독서법, 북스테어즈!

많은 관심과 피드백 바랍니다!

좋은 웹페이지 즐겨찾기