[회고] 주니어 프론트엔드 개발자의 좌충우돌 웹 거래소 런칭기
이 글은 작년(2021년) 12월부터 올해(2022년) 4월에 카사코리아의 웹 거래소 MVP(Minimum Viable Product) 런칭 과정과 런칭 이후 현재(글 작성일 기준 2022년 9월)까지의 겪었던 회고입니다.
MVP 런칭 후 회고를 작성하고 싶었는데 현업과 다른 공부에 우선순위가 밀려 이제야 작성하게 되었다.
제목처럼 나는 2년 차 주니어 프론트엔드 개발자이다. 현재 카사코리아의 프론트엔드 엔지니어로 카사코리아의 전반적인 프론트엔드 개발을 담당하고 있다. 믿기지는 않지만 나는 웹 거래소 개발을 담당하여 초기 세팅부터 런칭까지 과정을 경험을 해봤다. 지금부터 그 경험한 과정과 의사결정 과정 및 어떻게 개발을 진행해왔는지에 대해서 기억을 되새기며 회고를 해보려 한다.
카사코리아란?
시작하기에 앞서 카사코리아는 뭐하는 회사이길래 거래소 개념의 서비스가 필요한 것일까?
카사는 그동안 개인이 투자하기 어려웠던 상업용부동산(빌딩)을 쉽게 접근할 수 있도록 만든 서비스이다. 사용자는 카사 플랫폼을 이용하여 5,000원 단위부터 상업용부동산을 투자하여 건물주처럼 임대수익을 받을 수 있다. 이는 부동산신탁의 수익증권 공유지분(DABS, 디지털 자산유동화증권)를 소유함으로 상업용부동산에 간접투자를 하게 되는 방식으로 이루어지게 된다. DABS를 소유함으로써 DABS 보유 비율에 따라 건물의 임대수익을 배당처럼 받을 수 있고, 주식처럼 자유롭게 거래하여 매매차익을 올리거나 건물 매각 시까지 보유하여 매각수익을 받을 수도 있다.
더 자세한 내용은 아래 영상을 참고하길 바란다.
웹 거래소를 왜 런칭하는데?
웹 거래소를 런칭하기 전까지는 웹에서는 브랜드 사이트만 존재했고 거래가 불가능했으며 앱으로만 거래가 가능했다. 그렇다면 앱으로만 거래해도 충분한 거 아니야? 라고 생각이 들지도 모른다. 하지만 고액/전문 투자자들은 연령대는 대부분 40대 이상이고, 카사 서비스를 이용하는 대부분의 고객들은 이미 주식과 같은 투자를 경험한 사용자들이다. 그러므로 고액/전문 투자자들은 웹에서 거래하는 형태의 HTS(Home Trading System), WTS에 더 익숙하다.
두 번째 문제는 무조건 앱을 설치해야지만 거래가 가능하다. 즉, PC에서는 거래가 불가능하다. 그렇기 때문에 다양한 환경에서의 투자할 수 있는 접근성이 낮은 문제가 있다.
우리는 위와 같은 문제로 웹 거래소를 런칭하기로 결정했다.
우리의 목표
우리의 예상과 목표는 접근성 강화로 인한 사용자의 stickiness를 증가시키는 것, 더 많은 고액 투자자 유입으로 인한 평균 예치금/투자 고객 비율을 증가시키는 것이었다.
우리의 단기 액션으로는 2022년 3월 중순에 MVP 기능을 오픈하는 것이었다. MVP의 주요 기능은 웹에서 기존 사용자가 로그인하여 투자를 할 수 있고, 건물들에 대한 정보를 볼 수 있도록 해주는 것이었다.
우리는 현재 어떤 상황일까?
웹 MVP를 시작할 당시에 프론트엔드 개발자는 나 포함 3명이었다. 세 명 모두 2 ~ 3년 차 주니어 개발자였다. 웹 거래소 개발뿐만 아니라 우리는 모바일 웹, 백오피스, 브랜드사이트 개발도 같이 진행되고 있었다. 어쨌든 건물은 계속 앱 서비스에서 공모가 진행되었고 그에 맞춰서 모바일에서 공모 및 투자는 지속적해서 이뤄졌기에 대응해주어야 했다. 그렇기에 우리는 각자가 담당해야 할 부분들을 정하는 의사결정이 필요했다.
우리는 각자 상황과 어떤 부분을 맡아야 더 좋은 시너지가 이뤄질지 생각해온 뒤 얘기를 해보았다. 솔직하게 모두가 신규 서비스 개발을 하고 싶었을 것이다. 어찌 된 건지 다들 각자 하고 싶은 것보단 모든 상황을 고려하여 생각했고 의사결정에 있어서 큰 어려움은 없었다. 결과적으로 각자 담당하는 부분은 존재하되 모두 신규 서비스 웹 거래소 개발을 하기로 정했다. 그중에서도 나는 웹 거래소를 메인으로 담당하게 되었다. 다른 한 분은 백오피스 개발, 또 다른 한 분은 나머지 모바일 웹이나 기존에 도메인에 대한 백그라운드 지식이 필요한 부분들을 담당하게 되었다.
이때의 나는 카사에 입사한 지 4개월밖에 되지 않은 상태라 생각보다 많은 책임감과 압박감이 동시에 들었지만, 그보다 새로운 서비스를 개발할 수 있다는 사실이 나를 더 설래게하였다.
그렇게 웹 스쿼드는 프론트 1명(나), 디자이너 1명, 백엔드 1명, 입사 예정인 PO 1명으로 이뤄졌고, 백엔드가 1명인 이유는 위에서도 말했다시피 이미 카사는 앱에서 서비스를 운영하고 있다고 했다. 그래서 대부분의 앱의 기능을 웹에 구현하는 것이기 때문에 백엔드의 대부분의 기능은 이미 구현이 되어있었다. 입사 예정인 PO가 담당하는 게 이상하다는 생각이 들 수 있겠지만 이 당시에 PO는 한 분도 없는 상태였기에 어쩔 수가 없었다.
PO의 합류 후 우리는 정의한 MVP 기능과 아주 간단한 와이어 프레임을 바탕으로 모두가 estimation을 진행했고, 3월 중순까지 MVP 런칭을 목표로 잡을 수 있었다.
프로젝트 환경 구축
이 시점에 나는 카사 웹의 zero-base인 프로젝트의 초기 세팅을 구축하였다. 내가 생각한 프로젝트의 초기 세팅은 우선 프로젝트의 동작하는 골격을 만드는 것이다.
동작하는 골격이란 전 구간을 대상으로 자동 빌드, 배포, 테스트를 할 수 있는 실제 기능을 가장 얇게 구현한 조각을 말한다. 즉, 우리는 이 동작하는 골격을 구축해놓으면 더 이상 개발 이외의 작업에 신경 쓸 필요가 없는 것이다. 그렇게 되면 온전히 개발에만 집중할 수 있게 된다.
또한, 동작하는 골격이라 하면 아주 간단한 첫 기능에 대한 인수 테스트를 작성한 상태일 것이다. 이렇게 되면 개발 시작과 동시에 빌드, 배포, 테스트까지 자동화되었고 빠른 피드백을 얻을 수 있게 되었다.
동작하는 골격의 자세한 내용은 여기를 참고하길 바란다. 그리고 테스트 주도 개발로 배우는 객체 지향 설계와 실천 책을 읽어보시기를 추천해 드린다. (책 요약)
너무 추상적이게 생각할 수도 있겠다. 그러면 프론트엔드에서 동작하는 골격이란 무엇일까?
- 패키지 메니저 설치 및 필요한 라이브러리 dependecy 설치
- TypeScript 세팅 및 정적 코드 분석 도구 Eslint 세팅
- 단위 테스트 환경 구축
- E2E(End To End) 테스트 환경 구축
- CI 파이프라인 구축
- CD 파이프라인 구축
- 첫번째 기능의 단위 테스트 통과 및 E2E 테스트 통과
- CI 파이프라인 검증 통과
- CD 파이프라인을 통해 개발 환경에 배포 완료
참고로 이 상태에서 테스트는 완벽하지 않다. 여기서 중요한 점은 테스트가 아니라 우리가 이런 시스템을 구축함으로써 앞으로 우리의 기능에 대한 요구사항은 얼마나 부합하는지 빠르게 평가를 할 수 있으며, 빠르게 피드백을 반영할 수 있다는 점이다.
이렇게 초반에는 불안정 해보이고 세팅해야 할 것들이 많아 보이지만 자동화를 구축되고 나면 앞으로 이 반복적인 과정이 안정화되어 오로지 개발에만 집중할 수 있게 된다.
기술 스택 선정
기술 스택 선정 과정은 혼자만 개발하는 것이 아니기에 같이 협업하는 프론트엔드 개발자 두 분과 함께 지속해서 미팅을 가졌다.
우리는 여러 의사결정의 과정을 거쳐 다음 기술들을 사용하기로 하였다.
Package Manager (Yarn berry, Yarn 3+)
패키지 매니저로 yarn, npm, pnpm, yarn berry등이 있는데 이 중에서 우리는 Yarn Berry를 사용하기로 했다.
Yarn Berry는 기존에 npm, yarn에서 사용하는 비효율적이고 종종 깨지는 의존성의 node_modules 방식을 개선한 방식이다.
Yarn Berry의 PnP(Plug and Play), ZipFS, Zero-Install, TypeScript Plugin 등을 사용하기 위해 선택했고, Yarn Berry 사용만으로 인해 CI dependency Install 시간도 매우 단축되기 때문에 도입하지 않을 이유가 없었다.
더 자세한 내용은 여기를 참고하길 바란다.
React.js & Next.js
React.js를 사용한 이유는 프론트엔드에서 가장 큰 생태계를 자랑하며, 우리가 가장 사용하기 익숙하였기에 결정하기에는 어렵지 않았다.
리액트 프레임워크인 Next.js를 사용한 이유는 쉽게 SSR, SSG를 사용할 수 있으며, SEO 최적화, 이미지 최적화 등 리액트만 사용했을 때 비해 더 쉽게 개발할 수 있어 Next.js를 사용하기로 하는 데에도 큰 어려움은 없었다.
Emotion
CSS를 작성하는 방법은 여러 가지가 있다. 그중에서 우리는 CSS-in-JS인 Emotion을 사용하기로 했다.
CSS-in-JS의 장점은 JavaScript로 CSS 스타일을 작성하도록 설계된 라이브러리라 JavaScript 코드 안에 CSS를 작업할 수 있다는 점이 개발자 경험에 매우 좋았다.
React에서 일반 css, sass 등을 사용하는 것보다 CSS-in-JS를 사용함으로 얻을 수 있는 가장 큰 이점은 리액트 컴포넌트를 Styled 컴포넌트로 개발할 수 있기 때문에 컴포넌트가 어떤 역할을 하는지 명확하게 컴포넌트 명을 지을 수 있다. className 충돌도 나지 않을뿐더러 리액트에서 추구하는 재사용 가능한 컴포넌트도 그대로 만들 수 있으며, 해당 컴포넌트가 하는 역할에 대해서 의미 있는 이름만 짓는다면 가독성 있는 컴포넌트를 만들 수 있는 장점이 있기 때문에 CSS-in-JS를 선택했다.
전역 상태 관리 (Recoil & react-query)
전역 상태 관리는 처음에는 redux-toolkit을 사용하기로 정했었다. 가장 대중적이고, 3명 다 사용해본 경험이 있었기 때문이다. redux-toolkit과 redux-thunk, redux-saga를 사용하려고 했지만, 거래소 특성상 API 호출도 많아 캐싱 기능이 필수로 필요하다고 느꼈다.
이 과정에서 react-query나 swr과 같은 데이터 패칭 라이브러리를 학습했었고 왜 데이터 패칭 라이브러리가 탄생하게 되었는가에 대해서 학습해보다 보니 꼭 필요함을 느꼈다. 캐싱 기능과 보일러 플레이트도 적고 더 간단하게 hook으로 사용할 수 있다는 점 이외에 필요함을 느꼈던 가장 큰 이유는 기존에 redux-toolkit만으로 모든 상태인 client state와 server state를 관리하면 서버 데이터는 항상 최신 상태임을 보장하지 않기 때문에 문제가 발생할 수 있다. 이 이유는 react-query와 같은 데이터 패칭 라이브러리가 탄생하게 된 이유이기도 하다.
react-query 공식 문서
While most traditional state management libraries are great for working with client state, they are not so great at working with async or server state. This is because server state is totally different. (대부분의 기존 상태 관리 라이브러리는 클라이언트 상태 작업에 적합하지만 비동기 또는 서버 상태 작업에는 적합하지 않습니다. 서버 상태가 완전히 다르기 때문입니다.)
그렇게 우리는 데이터 패칭 라이브러리인 react-query를 도입하기로 했다.
하지만, 이 이유로 redux-toolkit을 사용하지 않을 이유는 없었다. client state를 전역으로 관리할 때 redux-toolkit을 사용할 수 있기 때문이다. 여기서 의견이 살짝 갈렸다. 나는 client state 관리로 Recoil을 사용하자고 했었고, 나머지 두 분은 redux-toolkit으로 관리하자고 했었다.
내가 Recoil을 사용하자고 했던 이유는 다음과 같았다.
- 이전에 사용해봤을 때 Recoil은 러닝커브 그렇게 높지 않았다. Client State만 관리할 경우 더더욱 낮다.
- 아주 작은 단위인 atom으로 사용되어 해당 컴포넌트에서만 hook으로 간편하게 사용할 수 있다.
- 아무리 redux-toolkit을 사용한다고 해도 Client State만 관리하는데 Recoil에 비해 작성해야 할 보일러 플레이트가 많다.
- redux-toolkit은 사용하고 싶지 않은 immer, redux-thunk의 써드파티 라이브러리가 포함(참고)되어있지만 recoil은 pure dependency이다. (참고)
두분이 redux-toolkit을 사용하자고 했던 이유는 다음과 같았다.
- Recoil을 사용해본적이 없었다.
- 아직 Recoil은 experimental state이기 때문에 프로덕션 환경에서 사용하기에는 아직 시기상조다.
- 번들 사이즈는 recoil보다 redux-toolkit이 더 작다.
나는 Recoil을 사용하고자 하는 이유에 대한 부분에서 포기하기에는 너무 많은 장점이라 Recoil 도입을 포기하기보단 이유에 대해서 더 찾아보았다.
첫 번째 이유는 러닝커브가 높지 않았고 이전에 Recoil을 학습하고 경험을 해본 적이 있어서 기술 미팅 시간에 Recoil에 대해서 공유하는 시간을 가졌다. 기술 미팅 후 두 분께서 굉장히 간단해 보인다고 말씀을 하셨다.
두 번째 이유가 가장 큰 이유였는데 아직 experimental state이라도 이미 프로덕션 환경에서 사용 중인 회사가 있다면 충분히 설득할만할 거라고 생각이 들었다. 그래서 여러 큰 회사의 채용공고를 확인해보았고 그중에서 토스의 기술 스택은 이미 react-query와 recoil을 사용해서 프로덕션 환경에서 사용 중에 있었다. 그리고 카카오의 모 계열사에서도 사용 중이였다.
세 번째 이유는 도입을 결정지을만한 이유가 안 됐다.
그렇게 여러 미팅을 거쳐서 react-query로 server state를 관리하고 client state는 recoil을 관리하여 사용하기로 결정하였다! 😤
단위 테스트 (Jest & react-testing-library)
우리는 카사 웹 거래소 프로젝트를 시작할 때부터 TDD(Test Driven Development) 방법론으로 테스트를 작성하며 개발하기로 했다. 테스트가 필요한 이유는 명확했다. 카사의 도메인은 핀테크이기 때문에 결국엔 돈과 관련이 있다. 그 말은 최대한 기술 부채를 줄이고 발생할 수 있는 버그를 줄이도록 할 수 있는 가장 확실한 방법이 테스트라고 생각했다. 물론 TDD가 버그를 줄이기 위한 목적으로 사용되는 방법론은 아니다. TDD에 관한 얘기는 회고 글의 목적과 맞지 않기 때문에 얘기하지 않을 테지만 여태까지 경험하고 공부해왔던 것들을 바탕으로 글을 따로 하나 쓸 예정이다. 프론트엔드에서 TDD는 논란이 있고 얘기가 항상 많지만, 내가 여태까지 공부하고 여러 책을 읽어봤을 때 항상 테스트 얘기는 빠지지 않았었다.
이처럼 TDD 도입에 실패하는 주요 이유는 기술적 내용을 잘 몰라서보다 우리가 이 TDD에 대한 인식 즉, 사회적 자본과 사회적 기술이 없어서 실패하는 경우가 대부분이다. 만약에 팀원들이 TDD에 대해서 부정적이었고, 맘에 들지 않아 신뢰가 없는 상태였다면 도입하지 못했을 것이다. 만약 도입한다고 하더라도 분명 사회적 측면에서 해결하지 못했기 때문에 실패할 것이 분명하다. 그러므로 기술적인 측면보단 사회적 자본과 사회적 기술부터 해결돼야지만 TDD를 도입할 수 있을 것이다. 다행히도 팀원들 가치관도 비슷했기에 TDD 도입에 있어서는 어려움은 없었다.
함께자라기 내용 중
아무리 기술적인 실천법이라고 해도 그 기술은 사회적 맥락 속에서 실천되어야 하며 그 기술의 성공을 위해서는 사회적 자본과 사회적 기술이 함께 필요하다.
하지만 안타깝게도 현실에서는 팀원들이 맘에 안 들고, 그들도 나를 맘에 들어 하지 않는 상황, 즉 사화적 맥락이 나쁜 상황에서 타개책으로 TDD의 기술적 측면에만 매몰되는 경우가 있다. 사실 그런 상황에서는 무엇을 골라도 실패가 보장되어 있다. 어떤 기술적 실천법이라도 그걸 현실에서 적용하기 위해서는 사회적 자본과 기술이 필요하다.
TDD 도입에 실패하는 경우, 무엇이 병목이었나를 살펴보면 사람들이 TDD의 기술적 내용을 잘 몰라서보다도 TDD를 도입하는 데에 필요한 사회적 자본과 사회적 기술이 없어서가 훨씬 더 많았다. 그렇기 때문에 어떤 기술적 지식을 전달한다고 해도 그것을 사회적 맥락 속에서 가르치고 경험하게 해야 한다. 사회적 기술에는 도움받기, 피드백 주고받기, 영향력 미치기, 가르치고 배우기, 위임하기 등이 있다. (요약글 참고)
단위 테스트를 작성하기 위해서 가장 많이 사용되는 JavaScript 테스팅 프레임워크로 Jest, Mocha, Jasmine이 있다. 이 중에서 가장 많이 사용되고 이미 사용해본 경험이 있는 페이스북에서 관리하는 Jest를 사용하기로 결정했다.
React 컴포넌트를 테스트하기 위해서 DOM Testing 라이브러리인 react-testing-library를 같이 사용하였다.
E2E 테스트 (Cypress)
E2E 테스트 프레임워크를 정하는 과정에 있어서 의견이 갈렸다.
나는 CodeceptJs를 사용자하고 말했었고, 다른 한 분은 제일 대중적인 E2E 테스트 프레임워크인 Cypress를 사용하자고 했었다.
내가 CodeceptJs를 사용하자고 얘기했던 이유는 BDD 방식으로 누구나 보기 쉬운 E2E 테스트를 각자의 시나리오에 따라 좋은 가독성을 제공해주어 이전에 사용해본 경험이 좋아서 추천하게 되었다. 단점이라고 한다면 문서화가 아쉬웠었다.
다른 분께서 사용하자고 얘기했던 이유는 가장 대중적이고 커뮤니티가 커서 나중에 막히거나 이슈가 발생하면 해결하기가 더 수월할 것이다라는 이유였다.
그렇게 우리는 이 둘의 차이점과 어떤 프레임워크를 사용하는 게 우리 서비스에 좋을지에 대해서 찾아보았고 문서화를 했었다.
더 자세히 내용은 회사 내부 자산이기 때문에 공개가 불가능하지만 각 프레임워크의 기술 부채를 조금이나마 빠르게 줄이는 릴리즈 주기를 봤을 때 굉장히 많이 차이가 났었다. 그리고 커뮤니티 크기가 압도적으로 차이가 났기에 앞으로 우리가 해결하지 못할 문제가 발생했을 경우 더 수월하게 대응할 수 있을 것 같았던 Cypress를 선택하게 되었다.
CI / CD (Github Action / Dron CI, Argocd)
CI는 Github Action을 사용하여 단위 테스트, E2E 테스트, Lint 검증, UI 테스트(Storybook) 검증을 하도록 파이프라인을 구성했다. (현재는 번들 사이즈 체크도 하고 있다.)
CD는 프론트에서만 결정한다고 되는 문제가 아니고 Devops팀과 같이 커뮤니케이션하면서 세팅을 진행했었고, 기존에 카사에서 사용하고 있는 delivery는 drone ci, deploy는 Argocd으로 세팅하였다. (피드백 주신 전 카사 데브옵스 엔지니어 헐콩과 카사 백엔드 리더인 이완 감사드립니다. 🙇♂️)
기타 세팅
JavaScript 정적 코드 분석 도구인 ESLint를 사용했고, 가장 대중적인 airbnb 스타일 가이드를 사용했다.
그리고 추가적으로 react, jest, react-testing-library, storybook, cypress, typescript, simple-import-sort, emotion 룰 등을 같이 사용했다.
Husky & lint-staged
우리는 커밋 전에 husky pre commit와 lint-staged를 사용해 변경된 파일에 대해서 단위 테스트와 Lint를 검증했다.
TypeScript
JavaScript 슈퍼셋인 TypeScript가 빠지면 섭하지.
Sentry
Error Tracking 도구인 Sentry도 세팅했다.
환경변수에 따라 devlopment, staging 환경에서는 에러는 잡히지 않고 production 환경에서만 Error가 잡히도록 설정했다.
프로젝트 구조 및 팀 코드 컨벤션 정의
우리는 기술 스택을 정하는 동시에 프로젝트 구조와 코드 컨벤션도 정의를 했다.
프로젝트 구조
프로젝트 구조는 자세하게 말하기는 힘들지만, 기존에 redux를 사용했을 때 사용했던 Presentational Container 패턴을 사용하지 않기로 했다. recoil과 react-query는 hook으로 이뤄져 있기 때문에 해당 책임을 가지고 있는 컴포넌트에서 직접 호출하여 불필요한 props 전달을 피하는 게 더 좋을 것 같다는 판단을 했고, 지금까지도 만족하고 있다.
그러면 비즈니스 로직을 가지고 있는 Container를 대체할 곳은 어디일까? 우리는 Custom hook을 사용하여 react-query를 재사용하여 사용하도록 했고, 공통으로 사용되는 재사용 hook을 만들어서 사용하도록 했다.
단위 테스트 파일은 각자 파일에 가장 가까이에 위치하도록 했다. 이유는 TDD를 할 때 가장 밀접하게 연관된 코드이기 때문에 가장 수정이 많이 일어나는 곳이기 때문이다. 또한, storybook 파일도 각 해당 파일과 가장 밀접한 위치에 만들어 관리했다.
E2E 테스트 파일들은 Cypress 폴더 아래에 위치하도록 세팅했다. 이유가 있다면 기본적으로 E2E 테스트는 한 곳에 같이 위치하는 게 관리하기 좋았고 Jest랑 같이 사용할 때 Lint 설정 및 TypeScript 설정을 따로 해줘야 했고 Cypress 공식 문서상 제안하는 구조였다.
코드 컨벤션
코드 컨벤션은 처음에 어느 정도 정의해놓고 개발을 진행하면서 필요한 부분을 추가하였다.
기본적으로 eslint의 airbnb 컨벤션을 따랐고, 파일 네이밍과 폴더 네이밍, asset 파일 네이밍 등을 정했다.
우리가 코드 컨벤션을 정한 이유는 읽고 관리하기 쉬운 코드를 작성하기 위해서 정했으며, 이렇게 팀 코드 컨벤션을 정해 준수하면 가독성이 좋아지고, 규모가 점차 커질 프로젝트에서 유지보수 비용도 줄이는 데 도움을 줄 수 있을 거라 믿었기 때문이다.
참고로 전반적인 규칙은 리팩터링과 클린코드의 책을 많이 참고하여 코드를 작성하도록 노력했다. 6가지 정도 기준을 잡았다.
- 첫째도 둘째도 셋째도 가독성 좋은(다른 사람이 쉽게 읽고 이해할 수 있는) 코드를 작성하자.
- 테스트 코드도 리팩터링 대상이다. 테스트 코드는 실제 작성하는 코드보다 가독성이 더 중요하다.
- 주석은 죽을 때까지 최대한 피한다. 의미 없는 설명 주석을 다는 이유는 코드가 지저분하다는 것이다. 코드가 하는 얘기가 너무 많은지부터 파악하자. (예외 사항은 fix, todo)
- 함수나 컴포넌트의 하고자하는 일(책임)은 하나이도록 하자. (단일 책임 원칙)
- 함수명이나 메소드명, 변수명, 컴포넌트명은 의미 있는 이름으로 짓자. 만약 이름이 떠오르지 않거나 짓기 어렵다고 느껴진다면 해당 함수는 책임이 너무 많다는 뜻일 가능성이 높다. 따라서 책임을 줄이고 리팩터링부터하자.
- DRY(Don't Repeat Yourself)원칙을 지켜 중복된 코드를 없애자.
클린코드 내용 중 깨끗한 코드란?
깨끗한 코드는 작성자가 아닌 사람도 읽기 쉽고 고치기 쉽다. 단위 테스트 케이스와 인수 테스트 케이스가 존재한다. 깨끗한 코드에는 의미 있는 이름이 붙는다. 특정 목적을 달성하는 방법은 (여러 가지가 아니라) 하나만 제공한다. 의존성은 최소이며 각 의존성은 명확히 정의한다. API는 명확하며 최소로 줄였다. 언어에 따라 필요한 모든 정보를 코드만으로 명확히 표현할 수 없기에 코드는 문학적으로 표현해야 마땅한다.테스트 케이스가 없는 코드는 깨끗한 코드가 아니다. 아무리 코드가 우아해도, 아무리 가독성이 높아도, 테스트 케이스가 없으면 깨끗하지 않다. (클린코드 깨끗한 코드란? 정리)
드디어 시작된 설레임
언제나 무언가 만들어 나가는 거는 너무나 설렌다. 특히 개발이 더욱더 그런 것 같다. 언제나 쉬운 길은 없어서 어려운 문제를 해결했을 때 성취감은 국가가 허락한 마약 같은 느낌...? 그렇게 앞으로 할 일들이 많은 개발을 드디어 시작할 수 있다!
이렇게 동작하는 골격을 만들고 온전히 개발에만 집중할 수 있게 될 줄 알았다...
그럼요... 그렇게 개발에만 집중할 수 있을 줄 알았죠...
우리에게 찾아온 위기
역시나 이렇게 수월하게 가면 이상하지...
첫 번째 위기
경영진 및 여러 이해관계자와 커뮤니케이션을 통해 여러 번의 디자인이 수정되었다. 그로 인해서 개발 시작은 자연스럽게 늦어졌다. 지금 생각해보면 좋은 프로덕트를 만들기 위해서 당연한 거지만 그 과정에서 좀 아쉬움은 있었다. 그래도 개발 초기 단계여서 크게 어려운 문제는 아니였다.
두 번째 위기
프론트엔드 개발자가 3명이라고 말했었다. 카사는 싱가포르와 코리아가 있는데 우리는 코리아에 소속되어있었다. 그 중 한 분이 카사 싱가포르 쪽으로 가시게 되었다. 그렇게 둘이서 코리아의 프론트엔드의 리소스 분배를 다시하게 되었고, 결국에는 코리아에 계신 한 분께서도 더욱더 웹 거래소 쪽 개발에 신경 쓸 수 없게 되어서 개발 일정에도 차질이 생길 수밖에 없는 상황이었다.
세 번째 위기
디자이너분의 갑작스러운 퇴사를 결정하게 되었다. 개인적으로 친했던 디자이너분이었고 갑작스러운 소식에 놀랐다. 그래도 디자이너분께서 웹 거래소의 MVP 디자인을 전부 끝내시고 퇴사하시기로 하셨고, 퇴사하실 때까지 고생하시면서 MVP 기능에 해당하는 디자인은 다 끝내시고 가셨다. 물론 개발이 진행하면서 디자이너와 지속적인 커뮤니케이션을 많이 했는데 그 부분을 PO와 할 수밖에 없었고, 디자인 수정이 필요해도 수정을 할 수 없고 피그마상의 디자인을 감안하면서 개발을 할 수밖에 없었다.
그럼에도 불구하고 계속 앞으로 나아가야만 한다...!
우리는 우리가 처한 상황과 제한된 리소스만으로 최대한 노력을 하면서 프로덕트를 만들려고 노력했다.
일정? 코드 품질?
일정도 매우 중요했지만, 코드 품질도 포기할 수 없었다. 지금 시간이 부족해서 테스트 코드를 작성하지 않거나, 책임이 많고 결합도가 높은 함수 및 컴포넌트를 구현한다든지, 가독성 좋지 않은 코드를 작성하는 등 이런 사소하지만 매우 중요한 것들을 놓치게 된다면 나비효과처럼 나중에는 이런 기술 부채는 걷잡을 수 없이 늘어날 것이다.
그렇게 되면 어떻게 될까? 우리가 지금 당장은 빠르게 개발이 진행되어가는 게 눈에 보인다고 하자. 하지만, 우리는 이 프로젝트를 MVP 기능만 구현하고 끝일까? 아니다. 앞으로 지속적해서 유지보수가 이뤄져야만 하고 신규 피쳐도 계속해서 개발되어야만 한다. 그러므로 우리는 변경에 유연하고 리팩터링하기 쉬운 코드를 작성해야만 한다. 나는 그걸 가장 간단하면서 효과적으로 도와주는 방법이 TDD라고 생각했다.
나는 이전에 CPO 분이 입사하셨을 때 두세 번의 미팅을 가진 적이 있었다. 그 당시 CPO 분이 애자일 프로세스에 대해서 여럿 얘기를 해주셨다. 그리고 앞으로 일을 재밌게 할 수 있는 속도가 있는 애자일 프로세스에서 웹이 카사에서 많은 중요한 역할을 할 것이라고 말씀하셨다.
원래 말씀드릴 생각은 없었지만, 애자일에 관한 얘기가 많이 나와서 나는 CPO 님이 원하시는 애자일을 하기 위해서는 기술적으로도 그런 환경이 되어야 한다고 말씀드렸고, XP(Extreme programming) 에 대해서 얘기를 했다. 그중에서 론 제프리즈의 XP의 실천 방법 중 "기술 실천 방법" 대해서 말씀을 드렸다.
이 과정에서 CPO 님은 TDD, 짝 프로그래밍 등 잘 아시지는 못했지만, 해보라고 긍정적으로 얘기를 해주셨다.
만약에 부정적으로 얘기하시며 하지 말라고 하셨어도 죄송하지만 나는 안 하는 척하며 했을 것이다.
클린애자일 내용 중
절대, 절대, 절대, 짝 프로그래밍을 해도 되는지 허락받지말라. 아니면 테스트를 해도 되는지, 아니면 리팩터링을 해도 되는지 등등... 당신은 전문가다. 당신이 결정하라.
개발자가 테스트를 쓰는 데 허락을 받으려 해서는 안 된다. 단위 테스트나 리팩터링 작업 일정을 따로 잡아서도 안 된다. 이런 기술적인 작업은 기능 개발 과정에서 이미 이루어졌어야 한다. (선택이 아니라 필수)
생각보다 속도가 안나는걸...?
개발이 시작되고 프로젝트가 시작된 지 중간인 2월 말쯤이었을까? 할 테스크는 산더미인데 생각보다 속도가 나지 않아 보였다. 작은 단위로 일감을 쪼개 스토리 포인트를 산정하여 하나씩 하나씩 퀘스트 깨듯이 개발했고, 나는 할 수 있는 최선을 다해서 열심히 했다고 생각하지만, 어떤 이유 때문인지 생각보다 눈에 보이는 결과물이 잘 나타나지 않았다. 내가 이 정도밖에 안 되는 걸까...? 내 실력이 형편없기 때문에 속도가 나지 않는 걸까? 라는 스스로한테 의심하기 시작했다. 주니어 개발자가 이런 중요도 높은 프로젝트를 담당해서 개발하는 것부터가 말이 안 됐던 걸까? 이런저런 생각이 들었고 그에 따라서 자존감도 낮아져 가는 기분도 같이 느꼈다.
그리고 내가 지금 따르고 있는 가치관과 개발 원칙에 대해서도 의심이 들기도 했다. 테스트 코드 때문인가? 테스트를 작성함으로써 속도가 나지 않는 건가? 만약에 테스트코드를 작성하지 않았더라면 더 빨리 개발할 수 있었을까? 이런 생각이 드는 건 어쩌면 당연할지도 모른다. 책에서만 존재하는 이상적인 애자일, TDD 등을 실제로 경험해본 적이 없었기에 스스로에게도 확신이 없었다.
하지만, 지금 와서 포기하고 싶지 않았고 할 생각도 전혀 없었다. 분명히 단일책임원칙을 잘 지켜져 있었으며, 코드가 읽기 쉽게 잘 짜여있고 구조도 전체적으로 잘 갖춰졌다고 생각이 들었기 때문이다. 그리고 테스트 코드가 있어서 리팩터링 시에도 안심하고 할 수 있었다.
다시 진행하게된 Estimation(에스티메이션)
우리는 매일 아침 데일리 스크럼을 진행했고 매주 체크 미팅과 2주 단위의 스프린트를 돌며 회고를 진행해오면서 3월 중순인 MVP 런칭은 불가능하다고 판단했고, 다시 에스티메이션을 진행하기로 했다. 일정이 지연된 가장 큰 이유는 리소스 부족이 가장 크지 않았나 싶다. 어떻게 보면 당연했고, 상황이 좋지 않았기에 PO나 경영진 및 이해관계자들도 다 이해를 해주셨다. (물론 내가 알지 못하는 게 있을 수도...?)
그렇게 다시 에스티메이션을 진행했고, 그래도 우리는 빠르게 MVP 런칭을 하는 게 제일 우선이었다. 그래서 처음에 우리가 생각한 MVP의 주요 기능을 생각했을 때 웹에서 기존 사용자가 로그인하여 투자를 할 수 있고, 건물들에 대한 정보를 볼 수 있도록 해주는 것이었다. 투자를 할 수 있게 끔에 중점을 두었고, MVP에 굳이 필요 없는 부분은 스팩 아웃을 시키며 최대한 빨리 런칭을 하기 위해 집중하였다. 그렇게 에스티메이션을 통해 다시 산정한 스토리 포인트 기준으로 4주 뒤인 4월 초중순이었다.
사실 솔직히 여태까지 진행해온 개발 진행 상황을 보면 일정을 맞출 수 있을지 자신은 없었다. 그래도 열정만큼은 누구한테 지지않았기 때문에 오히려 어려운 과제 같아서 흥미진진했었고 이 퀘스트를 깨고야 말겠다는 생각이 더 강했던 것 같다.
역시 틀리지 않았어.
프로젝트가 진행되면 진행될수록, 개발이 진행되고 코드량이 많아질수록 TDD의 장점은 더 확연히 보이기 시작했다. TDD로 개발해오며 설계부터 생각하는 과정을 거쳐 테스트를 작성하고 코드를 작성하면서 저절로 테스트하기 쉬운 코드가 작성되었다.
그래서인지 우리는 잘 분리된 추상화 되어있는 공통 컴포넌트와 함수 등 DRY 원칙을 잘 지켜가며 작성하게 되었고, 테스트 코드를 작성하기 어렵다면 리팩터링을 통해 책임을 분리하여 테스트 짜기 쉬운 코드를 작성했다.
이러한 무한 TDD 사이클을 통해서 변경에 유연한 코드를 유지할 수 있었고, 신규 피쳐를 개발하거나 요구사항이 중간중간 변경이 될 때도 두려움 없이 코드를 수정하고 리팩터링할 수 있었다.
이 과정에서 개발에 속도가 붙는 게 눈에 보이기 시작했다. 이건 공통으로 사용하는 로직이 있는걸? 이건 이 컴포넌트를 가져가 쓰기만 하면 되잖아? 이 로직은 이렇게 단순하게 수정할 수 있잖아? 이렇듯 이미 잘 작성되어있는 테스트 코드와 변경에 유연한 코드를 통해 순식간에 J커브 현상처럼 개발에 속도가 붙는 게 보였다.
MVP 런칭
이런저런 우여곡절도 많았지만, 나의 첫 도전은 결국 끝이 보이기 시작했다. 일정에 맞춰 개발을 완료할 수 있었고, 4월 7일에 마지막 전체 프로덕트 테스트를 다 같이 진행 후 그 다음 주인 4월 14일에 MVP 런칭을 하게 되었다!
나는 런칭 후 무엇을 얻었을까?
얻은 것들이 진짜 너무 너무 너무 많았다. 간단하게 정리해보면 다음과 같다.
- 1 ~ 2년 차인 주니어 개발자가 회사에서 중요도 있는 하나의 프로덕트를 담당하여 초기 세팅부터 개발하여 런칭한 경험은 어디 가서도 두 번 다시 얻기 힘든 경험이였던 것 같다.
- 아주 큰 하나의 사이클을 끝내고 MVP 런칭까지 진행해오며 어떤 식으로 프로덕트가 만들어져가고 그 과정에서 어떻게 하면 더 좋은 커뮤니케이션을 할 수 있을지에 대해서도 많이 배웠다. 아직도 많이 부족하다고 늘 커뮤니케이션을 향상시키기 위해 고민을 많이 하고 있지만 회사에 뛰어난 동료들과 같이 일하면서 이전보다 커뮤니케이션도 많이 향상된 것 같다.
- 내가 여태까지 공부해오고 따르는 가치관이 틀리지 않았다는 것을 느꼈다. 이번 MVP 런칭하면서 여러 우여곡절이 있었지만, 이론적으로만 배웠던 그게 실제로 가능한 거야? 했던 그 좋았던 점들을 얼핏 경험해보며 스스로 가능하다는 것을 느껴봤다는 점이다. 물론, 완전 zero-base에서 개발한 것이 아닌 이미 모바일에서 개발된 서비스를 웹에 MVP를 런칭하는 것이었기 때문에 기획이 어느 정도 완성되어 가능했을지도 모른다. 그래서 다음에 또 이런 도전할 기회가 주어진다면 완전히 새로운 서비스를 만들면서 TDD를 적용해보고 싶어졌다. 다시 또 도전하고 싶어졌다랄까...?
- 테스트 커버리지 100%로 MVP 런칭을 했다. 물론 테스트 커버리지를 100%를 달성하기 위해 목숨 걸며 지키는 건 매우 좋지 않은 것을 알고 있다. 불필요한 부분에도 테스트 하게 되고 그만큼 어떻게든 커버리지를 채우기 위해서 시간이 소요될 수 있기 때문이다. 현재까지는 TDD로 개발해오다 보니 100%가 유지가 되었다.
우리는 런칭 당시 Test Suites는 269개, 테스트 개수는 총 941개로 커버리지 100%를 유지할 수 있었다. - 마지막으로 내가 제일 좋아하는 해냈다는 뿌듯함과 성취감. 개발이 더 재밌어졌다. 😤
MVP 런칭 이후
런칭만 하고 끝이면 이렇게 열심히 하지도 않았을 것이다. 런칭은 끝이 아니라 이제 시작이다. 이제 고작 MVP 런칭이였고 앞으로 할 테스크는 쌓이고 싸여있다.
런칭 전에는 보이지 않았던 버그들이 런칭 후 어마어마하게 보이기 시작했고, 한동안 그 버그를 해결해나갔다. 그러는 동시에 바로 개선 작업과 앞으로의 우선순위 및 리소스를 정리했다.
그리고 Production 환경에서 Sentry에 잡힌 에러 이슈들을 해결했다.
중간마다 안정화 기간도 가지며 신규 피쳐 개발에 집중해서 밀린 코드 퀄리티 개선 및 리팩터링 작업도 진행하였다.
런칭 후 내가 기술적으로 개선했던 작업이다.
기술적으로 무엇을 개선했을까?
React v18 마이그레이션 및 Next.js SWC 적용
런칭쯤에 React v18이 드디어 릴리즈 되었다는 소식을 접했다. 이전부터 react 18버전이 릴리즈될 것이라는 소식을 들었고 어떤 변경점이 있는지도 학습을 해왔던 상태였다. 그중에서 기존에 서버에서 렌더링할 때는 지원하지 않아 제한적으로 사용되었던 Suspense와 Concurrent mode(Concurrent rendering)를 사용할 수 있다는 변경점이 가장 흥미로웠고 릴리즈 되면 바로 적용하고 싶어졌다. 물론 React 18을 마이그레이션하는 과정에서 릴리즈된 지 얼마 안 된 터라 몇몇 라이브러리가 제대로 지원하지 않아 테스트 및 빌드가 깨지는 이슈가 있었다. 하지만 대부분 사용하고 있는 라이브러리 dependency를 업데이트 및 릴리즈되면서 deprecate 된 부분들을 수정함으로 대부분의 이슈를 해결할 수 있었다. 회사 내부 코드 및 트러블 슈팅한 내용은 공개하지 못하지만 사이드 프로젝트에서도 거의 동일한 이슈를 해결하였는데 궁금하다면 여기를 참고하길 바란다.
기존에 Next.js 12임에도 불구하고 babel를 사용하여 transpile을 하고 있었는데 SWC 컴파일러로 변경하는 작업을 했다. SWC는 Rust기반 컴파일러로 5배 빠른 빌드 속도, 3배 빠른 리플레쉬 등 속도 개선에서 너무 많은 이점이 있었기 때문에 무조건 변경해야만 했다. 그래서 기존에 babel을 사용하였던 Jest 환경 및 Next.js를 SWC로 변경하였다. 간단하게 변경함으로써 얻는 이점은 굉장했다. Jest 테스트 속도도 개선과 빌드 시 약 40초 정도 개선되었다.
참고
- Rust 컴파일러로 더 빠른 빌드 및 빠른 새로 고침
CI 개선
기존에 Yarn berry의 PnP 및 zero install 기능을 사용하고 있어서 CI에서 dependency Install 시간은 그렇게 길지는 않았다.
하지만, CI 단계에서 lint 검증, unit & e2e test 검증, UI test(storybook)를 검증하고 있었는데 코드량이 많아질수록 CI 단계에서 검증하는 시간이 늘어났다. 그래서 CI에서 Install 및 Build시 캐시를 적용하였고 병렬적으로 각각 검증을 진행하도록 변경하였다. 이렇게 진행한 결과 기존에 Install 시간은 약 40초에서 약 17초로 두 배정도 감소하였고, 각 검증을 병렬적으로 처리하면 그에 배로 감소시키는 효과를 얻을 수 있었다.
또한 검증단계를 하나 추가했는데 CI 단계에서 해당 작업에서 번들 사이즈에 얼마만큼의 영향을 주는지 검증하기 위해서 번들 사이즈 검증을 CI pipeline에 추가하였다.
그리고 CI 단계에서 수정된 코드뿐만 아니라 불필요하게 모든 코드에 대해서 전부 테스트 및 lint check를 하고 있었는데 코드량이 점점 많아질수록 오래 거리게 되었고 main 브랜치와 비교하여 수정된 부분만 테스트 및 Lint를 검증하도록 개선하였다. 이거는 정확하게 비교하기는 힘들지만 간단한 수정이 발생하는 hotfix PR인 경우에는 test는 11초, lint는 7초만에 검증이 완료되게 된다.
이렇게 CI를 지속해서 개선하려는 이유는 얻은 피드백을 바탕으로 빠르고 지속해서 반영하여 보여지는 결과를 내고 싶었기 때문이다.
commit 컨벤션 적용 및 PR 템플릿 적용
기존에 commit 컨벤션을 정의해놓고 개발하지 않았다. 코드 컨벤션뿐만 아니라 commit에도 컨벤션을 적용하는 게 앞으로 좋을 것 같았기 때문에 commit lint를 사용하여 컨벤션을 적용하였으며 husky를 통해 commit시 검증하도록 하였다.
PR 템플릿을 적용한 이유는 리뷰어와 리뷰이 모두를 위해서 적용했다. 리뷰이는 본인이 작성한 코드에 대해서 리뷰어의 이해를 돕기 위해서 필요하다는 생각이 들었다. 우아한형제들 기술블로그의 코드리뷰 관련한 좋은 글이 있어서 참고하였다.
Lighthouse로 웹페이지 품질을 측정 후 얻은 피드백 반영
Lighthouse를 사용하여 웹사이트 성능을 측정 후 할 수 있는 부분을 수정하였다.
Performance 부분은 대부분 이미지와 관련이 있었다. next image를 사용하여 webp로 최적화를 시켜놓았지만, performance가 떨어지게 나오는 이유는 이미지 크기가 보여지는 이미지 크기에 비해 너무 고화질이라 용량이 너무 커 다운로드 받는 속도가 느렸기 때문이다. 이 이슈에 대해서는 백엔드, 디자이너, 프론트, PO까지 같이 미팅을 통해서 이미지 사이즈에 맞춰서 사용할 수 있게끔 최적화를 하는 방법으로 ImageKit.io을 사용하기 했다.(적용해주신 백엔드분들 및 홍에게 감사드립니다. 🙇♂️)
아직 Next Image를 걷어내지도 않았고, 이미지 사이즈대로 맞추지도 않았는데도 불구하고 많이 향상된걸 볼 수 있었다.
Accessibility는 기본적으로 웹 접근성에 해당하는 피드백을 반영하였다.
Best Practices 부분도 Next Image와 관련이 있었기에 추후에 이미지 관련 작업을 진행하면 해결될 것이라 생각한다.
앞으로 개선하고 싶은 것들은 뭐야?
앞으로 개선하고 싶은 것들이 너무 많다. 다음은 개인적으로 개선하고 싶은 것들이다.
Concurrent mode 적용
현재도 적용할 수 있는 부분들을 적용하고 있는데 Suspense로 로딩 상태를 처리하고 Errorboundary를 사용하여 에러를 처리하니 확실히 코드가 선언적이여져서 테스트하기 좋은 코드가 되는 걸 느낄 수 있었다.
아직은 많이 적용하지는 못했지만, Concurrent mode를 사용하여 처리할 수 있는 작업을 나누어 우선순위를 부여함으로 우선순위가 높은 부분은 먼저 처리하여 조금 더 나은 사용자 경험을 줄 수 있는 서비스를 만들 수 있을 것 같다는 생각이 들었다.
현재 카사 웹사이트에서 예를 들어보자.
아래 사진은 카사 웹사이트의 사용자가 로그인했을 때 상단에 보이는 화면이다.
빨간색 블록을 확인해보자. 나의 투자 현황과 내가 보유한 배당받을 빌딩, 투자 가능한 빌딩 세 가지 컴포넌트가 렌더링 된다. 우리는 여기서 Concurrent mode를 적용해서 세 가지의 조각으로 나누어서 동시에 작업을 처리하게 할 수 있다.
추가적으로 useTransition를 사용하여 우선순위에 따른 상태 업데이트를 할 수도 있고 useDeferredValue도 사용하여 리랜더링도 지연할 수 있다.
React Query V4 마이그레이션
최근에 react query v4가 릴리즈되었고 그에 따라서 마이그레이션을 하고 싶어졌다. 어쨌든 메이저 버전이 릴리즈가 되었고 기술 부채를 최대한 줄이기 위해서는 꼭 해야 하는 작업이라고 생각이 들었다. react-query v4가 릴리즈된 주요 이유는 아마도 react의 의존성을 벗어나 다른 vue, 스벨트 등을 지원하기 위해서 그런 것 같았다. 그것 이외에도 메이저 버전업인 만큼 변경점이 많은데 공식 문서를 참고하면서 적용해봐야겠다.
공통으로 사용되는 컴포넌트 및 유틸 함수를 모듈화 라이브러리 만들기
앞으로 다른 프로젝트에서도 사용할 수 있게 공통으로 구현되어있는 컴포넌트와 유틸 함수를 각각 패키지를 모듈화하여 라이브러리로 만들어 개발 생산성을 최대한으로 향상시키고 싶어졌다.
그리고 스토리북 디자인시스템도 웹 기반으로만 적용되어있지만, 디자이너분들과 같이 디자인 시스템 라이브러리도 만들고 싶다.
E2E 테스트 작성
지금 Cypress를 사용하여 E2E 테스트를 작성하고 있는데 많은 부분이 작성되어있지 않다. 기존에 작성하지 못했던 이유는 입사한 지 얼마 되지 않아 도메인에 대한 지식도 부족했고, E2E 테스트는 Github Action으로 사용하지 못하는 VPN 이슈가 있어서 Drone으로 실행되는데 백엔드와 Devops의 Drone CI에서 E2E 테스트가 정상적으로 작동하지 않는 이슈가 있었다. 지금은 해결한 상태라 작성하지 못한 부분들을 차근차근 작성해나갈 예정이다.
테스트에 MSW 적용하기
단위 테스트에 API 부분이 전부 jest mocking하는 형태로 테스트하고 있다. 기존에 테스트에 중복적으로 API가 jest mocking되어 있는 부분을 MSW를 적용하여 네트워크 요청을 가로채 Service Worker API를 활용하여 동일한 API를 호출하는 것처럼 테스트하도록 변경하려고 한다.
기존에 테스트를 위해서 API jest mocking을 하는 방식은 테스트하기 위해 불필요한 사전 작업이 필요하여 개발 생산성을 저하시키는데 MSW를 사용하면 그러한 사전 작업 없이 같은 API를 호출하는 것처럼 테스트할 수 있으므로 가독성 향상 및 생산성 향상에 도움이 된다.
이외에도 CI에 NX를 적용하여 CI에서 수행하는 동작들의 결과를 저장하고 이를 캐싱하여 현재의 커밋과 그전의 커밋을 비교하여 변경되지 않으면 캐싱 된 결과물을 사용하도록 적용하는 것과 로딩 스켈레톤 사용자 경험 개선, 주요 라이브러리 dependency 업데이트, ImageKit을 사용한 사이즈 별로 이미지 최적화 적용 등 적용하고 개선하고 것들이 많다.
배우면 배우고 알면 알수록 배움은 끝이 없는 것 같다는 생각이 자주 드는 요즘이다.
기나긴 회고를 마무리하며...
카사에 입사해서 지난 1년여 동안 정말 많은 것들을 해 온 것 같다. 카사 웹 서비스는 초기 세팅부터 맡아서 직접 개발해오다 보니 진짜 애정이 안 생기려야 안 생길 수가 없는 내 자식 같은 느낌이 든다. 내가 만들긴 했지만 회사 소유니까 입양한 자식이 맞을려나...? (퇴사를 하게 되면 자식을 버리는 건가? 😅)
지금까지 다른 서비스도 같이 개발해오고는 있지만 주로 웹 거래소의 서비스를 만들어왔는데 앞으로도 할 신규 개발이 한참 쌓여있다. 입출금, 회원가입, 수익자총회, 공모 등 줄을 서 있다.
기술적인 부분에도 위에서 얘기했듯이 개선 작업들도 넘쳐나고 있다. 그래도 지금까지 잘 해왔다고 생각한다. 현재까지 test suite가 370개, 총 테스트가 1,350개 정도에 달한다. 테스트 커버리지도 현재(2022년 09월 29일 기준)까지도 100%를 유지하고 있다.
항상 생각하지만 이 서비스를 나 혼자 만들었다고 생각한 적은 한 번도 없다. 만약 그렇게 생각하면 미친 거지.
그래서 이 글에서 마지막은 같이 웹 거래소를 만든 동료들에게 고마움을 전하고싶다. 🙏
가장 먼저 언제나 배울 점이 많고 열정 넘치고 나를 카사에 데려오고 지금은 행복 코딩하려 🥕에 간 프론트 쿠쿠, 퇴사하기 전까지 책임감 넘치게 MVP 디자인을 끝내주고 언제나 내 편에서 좋은 말만 해주는 디자이너 케일리, 지금은 퇴사하셨지만 카사에서 가장 능력 있고 제일 많은 것들을 알고 계셨던 백엔드 제이슨, 입사하자마자 도메인 파악하기도 전에 신규 서비스 PO를 맡아 언제 입사했냐는 듯 다 부숴버린 일잘러 PO 지나까지 너무나 좋은 동료들이 있었기에 좋은 서비스를 만들었다고 생각한다.
그리고 지금까지 같이 서비스를 만들고 있는 홍, 리아, 칼까지 고마움을 전하고 싶다. 🙏
개인적인 회고
개인적으로 여태까지 작성했던 회고 글 중에 가장 정성들여 시간을 많이 투자해서 작성했는데 그만큼 얻는 것도 많은 회고였던 것 같다. 이번 회고를 통해 다시 한번 더 회사에서 해왔던 것들을 정리할 기회가 되었던 것 같고, 작년의 나와 비교했을 때 더 나은 내가 된 것 같아서 뿌듯하다.
스스로 생각해보았을 때 나는 새로운 것에 대한 습득과 배움에는 빠르지는 않다고 생각한다. 그렇지만 나는 언제나 그렇듯 느리지만 매일 매일 꾸준히 무엇인가를 끄적이고 있다. 나는 어제보다 더 나은 오늘의 내가 되도록 매일 노력하고 있다. 이제는 이렇게 꾸준히 열심히 하다보면 하루 이틀에는 보이지 않는 티끌이 태산이 되는 걸 많이 겪어보다 보니 이제는 꾸준함을 유지하는 게 그렇게 어렵지는 않다. 오히려 그 과정에서 느끼는 성취감이 더 나를 즐겁게 해주는 것 같다.
요즘은 꾸준함을 유지하는 것이 개발뿐만이 아닌 건강을 위해서 운동에도 꾸준함을 적용했다. 운동도 6개월 정도 꾸준히 해오다 보니 체력도 확실히 늘어났다는 게 느껴지고 요즘은 재미도 있어서 운동하는 시간도 계속 늘어나고 있다.
어쨌든 모든 일에는 열정과 꾸준함, 끝까지 하고자 하는 끈기만 있으면 안 될게 없는 것 같다. 마지막으로 디자이너 케일리의 추천을 받아 읽은 그릿이라는 책을 추천하며 기나긴 회고를 마무리하겠다.
그릿 내용 중
82p
노력하지 않을 때 당신의 재능은 발휘되지 않는 잠재력일 뿐이다. 재능이 기량으로 발전할 수도 있지만, 노력 없이는 불가능하다. 노력은 재능을 기량으로 발전시켜주는 동시에 기량이 결실로 이어지게 해준다.
183p
"열심히 하는 거죠. 재미가 없을 때도 해야 할 일은 해야죠. 왜냐하면 결과를 달성하면 엄청 즐거우니까요. 마지막에 '아하!' 하는 즐거움, 그것 때문에 먼 길을 참고 가는 것 입니다."
글 내용에 피드백 주신 데브옵스 엔지니어 헐콩, 백엔드 엔지니어 이완, 프로덕트 디자이너 제니 감사드립니다. 🙇♂️