회사 일이 널널해져서 잠깐의 여유가 생겼다. 마치 사무실 백수가 된 기분이라 '이제 뭐 하지?' 하다가 그동안 불편했던 사내 이슈 트래커를 만들었다. (오히려 좋아)
1. 기존 이슈 관리 방식의 문제점
원래 슬랙으로 이슈를 관리했다. 요청 사항이 생기면 기획자분이 채널에 직접 올려주셨고, 이와 별개로 파일 탭에도 기획서와 이런저런 이슈들이 구분 없이 뒤섞여 있었다.

개발자 입장에서는 스레드 알림이 오면 이게 어떤 이슈였는지 헷갈렸다. 또 기획서를 확인해야 하는 이슈는 파일 탭에 들어가서 목록을 스크롤하며 찾아야 했다. '개발 진행 중일까요?', '스테이징 배포 되었나요?', '운영 배포되면 말씀해주세요!'와 같은 소통도 매번 반복했다.

팀에서는 Jira, Linear 같은 서비스도 사용해봤다고 했지만 이런 이유들로 더 이상 안쓰고 있었다.
- Jira - 기능이 너무 많아 복잡하고, 100$ 이상 나오는 과금이 부담되었다.
- Linear - 이슈 업로드 개수 제한에 걸렸다.
사내 이슈 트래커를 만들어보면 재밌을 것 같았다. 비슷한 불편함을 겪고 있는 스타트업들도 꽤 있을거란 생각이 들었다. 그래서 나는 꼭 필요한 기능들만 담은, UX도 편리한 서비스를 만들어 SaaS로 제공하는 걸 목표로 세웠다. 약간 보급형 Linear 느낌,, 이름은 스프린트 만드는 사람들이라는 의미를 담아 Sprinters로 정했다.
2. 설득하기
기획자 분은 회사 소속은 아니지만 같은 공유 오피스에서 일하고 계신다. 이슈 트래커를 만들어보겠다고 했을 때, 이미 유명한 SaaS를 쓰면 되는데 굳이 또 만들 필요가 있냐고 하셨다고 들었지만, 나는 잠깐 시간을 내달라고 말씀드린 뒤 팀의 상황을 말씀드렸고, 하루 정도 걸려 만든 프로토타입을 보여드렸다.

기획자 분은 처음보단 나은 표정으로,,ㅋㅋ 만들어주면 한 번 써보겠다고 하셨다. 사실 당시에 보여드릴 땐 이슈들을 관리하는 칸반 보드만 있던 상태라 스프린트 개념이 없었는데, 스프린트로 관리할 수 있도록 해달라고 요청하셨다.
3. 개선하기
나는 슈퍼 P이기 때문에 처음부터 많은 걸 고려하진 못했지만 '어떻게 SaaS 형태로 제공할 수 있을까?'를 생각하면서 하나씩 기능을 늘려나갔다. 이런 고민을 하면서 뭔가를 만들어보는 것 자체가 정말 좋은 경험이란 걸 느꼈다. 특히 나는 이런 것들을 신경 썼다.
3-1. 자율성을 제공하자
3-1-1. 이미 존재하는 공간은 없다
일단 워크스페이스라는 개념이 필요했다. 누구나 각자의 워크스페이스를 만들 수 있어야 하며, 팀의 워크스페이스도 개인으로부터 시작된다. 그런데 사내에서만 쓴다면 이런 것 자체가 필요없다. 이미 워크스페이스가 존재한다는 가정 하에 칸반 보드부터 만들게 되기 때문이다.
필요한 기능을 기획자에게 직접 듣기도 하고, Jira를 써본 경험을 떠올려보기도 하고, 회사에서 이전에 썼던 Linear도 둘러보면서 생각을 넓혔다. Sprinters는 워크스페이스 > 프로젝트 > 스프린트 > 이슈 구조로 이슈를 관리하는데, 협업 툴이 왜 이런 구조를 사용하는지 알 수 있었다.
또한 사용자가 편하게 세팅할 수 있도록 온보딩 플로우를 제공해줬다.

3-1-2. 커스텀할 수 있어야 한다
또 다른 예시는 슬랙 연동이다. 프로젝트별로 백로그가 생성되면 슬랙 봇이 채널에 이슈 내용과 함께 요청자, 담당자를 태그해 알려준다.

그런데 실무에서는 보통 스레드에서 논의를 한다. 따라서 이슈 상태 변경은 채널보단 스레드 댓글로 달리도록 했다.

어떤 팀에서는 Design Completed 또는 In Progress 시점에 알람을 받고 싶지 않을 수 있다. 따라서 프로젝트별로 이슈의 상태별 알람 방식을 지정할 수 있게 해줬다.

또 기획자가 백로그를 미리 생성할 수 있는데, 생성할 때마다 매번 슬랙 알람이 가면 채널이 지저분해진다. 따라서 현재 진행 중인 스프린트에 이슈가 담길 때에만 알림이 가는 게 낫다고 생각했다. 이슈 상태 단계와 라벨도 원하는 대로 수정할 수 있어야 하고,, 이렇게 범용성을 고려하며 하나씩 개선하다보니 env에 넣는 값이나 하드코딩도 조금씩 없어졌다.
3-2. 좋은 UX/UI를 제공하자
요즘은 뭔가를 뚝딱 만들어내기 너무 쉽지만 AI 밤티가 너무 난다. 그래서 문장들을 일일히 보면서 다듬었고, 디자인을 잘 모르지만 이것저것 찾아보면서 공부했다.
3-2-1. 왜 내가 만들면 짜칠까?
제일 답답한 건 작은 버튼 하나도 내가 만들면 어딘가 짜치는데 Linear가 만든 건 고급스럽다는 것이다 ;;
처음에는 Linear의 개발자 도구를 까보다가 Linear 디자인 시스템을 복제한 피그마 링크를 찾았다. 요걸 던져주면서 클로드와 함께 디자인 토큰을 정리했다.

웹이 여러 Layer로 구성되어 있는 것처럼 디자인도 레이어를 고려해 입체감을 더해준다는 사실을 알았다. 내 생각보다 훨씬 디테일했다.
- HCL을 사용하면서 명도와 채도를 조절해가며 색상 토큰의 단계를 나눈다.
- 버튼에 1px의 border를 주는 것보단, 머리카락 같이 얇은 0.5px 정도의 border와 아래 방향으로 얕게 깔린 그림자를 주면 좀 더 세련돼 보인다.
- 바닥에서 멀리 떨어진 물체의 그림자가 더 넓고 흐린 것처럼, 화면에서 높이 떠 있는 느낌을 낼수록 offsetY와 blur를 함께 키워준다.
- font-weight을 400, 500만 쓰면서도 크기와 색상으로 중요도를 표현한다.
- 4배수 Spacing을 사용해 시각적으로 레이아웃을 구분한다.
한편 프로토타입의 화면은 깔끔해보이면서도 뭔가 아쉬웠다.

-
상단에 2주차 배포 라고 적힌 스프린트는 이슈를 담는 개념이지만, 카드 형태로 보여주니 아래 이슈들과 별개처럼 느껴진다.
-
여기에서 서비스 로고를 굳이 보여줄 필요가 없다. 사이드바가 없으니 상단의 공간을 최대한 아껴야 한다. 로고는 랜딩 페이지에서나 보여주고, 차라리
워크스페이스 > 프로젝트형태의 헤더를 띄워 유저가 나만의 공간에 들어온 느낌이 들게 해주는 게 낫다.
'브랜드 색상은 어떤 기준으로 사용해야 할까?', '어떨 때 Chip 모양 버튼을 써야 할까?' 등등 처음으로 고민해봤다. 나는 디자인 시스템은 중복 컴포넌트를 줄이고 효율적으로 개발하기 위해 필요하다고 생각했는데, 더 본질적으로는 사용자에게 일관되고 좋은 경험을 주기 위해 필요하다는 걸 느꼈다.
3-3. 성능을 개선하자
서버 개발은 처음이라 클로드와 계획을 세우면서 기능을 조금씩 넓혀갔다. 그런데 막상 배포해보니 너무 느렸다. 성능 탭을 보니 여러 문제가 있었지만 일단 서버 응답을 기다리는 시간이 너무 길었다. 그래서 측정-개선-재측정의 흐름을 세웠다.
대부분은 문제는 인증된 사용자인가? - 이 워크스페이스 멤버인가? - 이 프로젝트에 소속되어 있는가? 이런 것들을 검사하면서 요청을 할 때마다 서버-DB 왕복을 5번이나 하고 있었다. Cloudflare의 smart placement를 통해 서버 리전이 DB 쪽으로 옮겨가도록 했는데 index.html 도 엣지가 아닌 APAC까지 가서 받아와 느린 이슈도 있었다.
3-3-1. 서버-DB 왕복 횟수 측정하기
로컬에서는 네트워크 지연이 사실상 0ms라 전송 시간 자체는 측정할 수 없지만, 요청 하나를 처리하는 데 왕복이 몇 번 일어나는지는 셀 수 있다. 불필요한 왕복을 줄이기 위해 이미 받아온 JWT 토큰의 ID는 재사용하고, 불필요한 별도 조회는 서브 쿼리로 합치기도 하고, API를 제외한 요청은 엣지 서버에서 바로 반환하게 했다. 이때부터는 성능 병목이 많이 줄었고 본격적으로 라이트하우스 검사를 진행했다.
3-3-2. 번들 사이즈를 줄이기
네트워크를 최적화해도 초기 번들이 크면 성능 병목이 사라지지 않는다. 초기에 번들이 컸던 원인 중 하나가 앱 최상단의 Provider였는데, 무거운 라이브러리를 포함하는 TooltipProvider로 앱을 감싸니 툴팁이 없는 화면까지 그 로딩을 기다리게 됐다. 이런 건 지연 로딩으로 분리해줬다.
zod도 마찬가지였다. 나는 편의상 이 프로젝트를 모노레포로 구성했고, 백엔드와 프론트엔드가 공유하는 타입, 상수, zod 스키마를 packages/shared에 모아서 배럴 파일로 내보내고 있었다. 그러다보니 상수 하나만 가져와도 배럴에서 export하는 zod 스키마 모듈이 통째로 초기 번들에 딸려 들어왔다. 그래서 상수와 헬퍼를 zod 의존이 없는 별도 파일로 분리해 초기 번들을 줄였다.
3-3-3. 인라인 CSS + Cache-Control 적절히 활용하기
또한 CSS는 렌더 블로킹 리소스다. 앱 전체 CSS의 크기를 보니 압축 전 기준으로 11KB 남짓밖에 안됐다. 이 정도 크기면 별도 파일로 두는 이점이 없다고 판단해서 index.html에 인라인으로 넣어 CSS 파일을 받기 위한 요청 자체를 없앴다. 이렇게 HTML에 인라인으로 박아놔도 나쁘지 않은 건 Cache-Control: no-cache를 설정하면 브라우저는 매 요청마다 재검증만 하고 index.html이 수정되지 않는 한 엣지에서 바디가 없는 가벼운 304 응답을 받는다.
이렇게 HTTP 캐싱, 탠스택 쿼리 등 여러 캐싱 레이어들을 처음으로 만져볼 수 있어서 재밌었다. 또한 정확한 측정을 하려면 시크릿 탭에서 해야 한다는 걸 알았다. 아무리 개선해도 성능 점수가 70점대가 나오길래 뭐지? 싶었는데, React Developer Tools 크롬 익스텐션이 스크립트를 주입하는 것 때문에 정확한 측정이 안되던 것이었다. 지금은 성능 점수 재보면 99~100 정도 나오고 모두 Good 범위를 충분히 만족하게 됐다.
✨ 틈새 책 홍보
내가 베타 리더로 열심히 참여했던 '프론트엔드 성능 최적화 Deep Dive' 책이 드디어 출간되었다! 네이버 파이넨셜의 리드 개발자이신 김용찬 님의 저서로, 읽을 당시에도 진짜 길었지만, 종이책으로 보니 무려 1700페이지 정도 된다. 나는 이 책을 거의 두 달 간 읽으면서 밥먹듯이 밤을 샜지만,,ㅋㅋ 진짜 3년 이상의 경력은 얻었다는 느낌이 들 정도로 많은 도움을 많이 받았다. e-book으로만 출간되었지만 베타리더들에게는 직접 책을 인쇄해 하나뿐인 책을 보내주셨다! 감사합니다! (가보로 간직할 예정)


프런트엔드 성능 최적화 Deep Dive (ebook) 링크에서 구매할 수 있으니 프론트엔드 개발자라면 꼭 읽어보는 걸 추천한다!! 대상 독자는 3년 이상의 중고급 개발자이지만, 1-2년차가 읽어도 매우 많은 도움이 된다.
4. 성과
다시 본론으로 돌아와서.. 지금은 이런 모습이 됐다.(로컬 화면으로 대체) 모든 팀원분이 들어오셔서 주력 사업 뿐만 아니라 신사업 프로젝트에서도 활발하게 쓰고 계신다!


동료 FE 개발자 분이 Sprinters 사용법을 다 같이 배울 수 있도록 온보딩을 해주면 좋을 것 같다고 하셔서 회의실이 꽉 차게 모여 온보딩도 진행했다. 아직 협업 툴을 사용해보지 않은 인턴분들도 계셔서 하길 잘했다고 생각했다.

친한 동료분이 진짜 너무 잘 만들었다고 추진력이 좋은 것 같다고 칭찬해주시기도 했다 😀 내가 만든 서비스를 옆 팀원 분들이 쓰는 걸 보니 매우 뿌듯하다!
5. 마치며
나는 자잘한 코드 개선 하는 걸 좋아한다. 하지만 코드 양이 너무 빠르게 늘어나는 요즘 이런 게 큰 의미가 없는 것 같다. 특히나 완벽한 코드보단 빠른 속도가 중요한 스타트업에서는 더욱 그런 것 같다. 차라리 실제로 내가 불편한 것들을 문제로 인식하고, 개선하기 위해 고민해보고, 실제로 만들어서 함께 사용해보니 생각보다 재밌고 뿌듯했다. 또 그런 과정에서 배우는 게 많았다.
한편 개발자라는 직업에 대한 회의감도 드는데, 작은 스타트업들을 전전하면서도 맡은 일은 잘 하는 편이지만 딱히 내가 뭔가를 기여하고 있다는 생각은 안 들기 때문이다. 이슈 트래커도 만든 뒤 이슈 상태 관리나 소통이 좀 더 편해지긴 했지만 이걸로 기여를 했다는 생각은 안 든다. 네이버 최연소 임원이자 카카오 대표였던 디자이너 조수용의 '일의 감각' 영상에서 '너가 하는 일이 그리 대단하지 않다는 걸 인정하는 순간, 새로운 세계가 펼쳐진다.' 라는 말이 기억나는데 다시 봐야겠다. 개발자를 떠나서, 앞으로는 진짜 회사에 기여를 해보는 사람이 되고 싶다. 또 오래 일하면서 하나의 기술에 전문성을 가진 사람이 되고 싶다.