CSON 프로젝트 마이그레이션 하기
JavaScript 기반의 리액트 프로젝트를 마이그레이션 하다. 😎
최근 어느 제약회사에서 CSON이라는 이름의 프로젝트를 진행하고 있습니다. 처음부터 제가 프로젝트를 맡아 진행한 것은 아니었는데요, 기존 웹을 개발하시던 분이 좋은 일로 프로젝트를 그만두게 되면서 제가 그 자리를 맡게 되었습니다.
CSON은 CSO(의약품 판촉영업자, Contract Sales Organization)의 영업을 도와주는 의료 도메인 서비스입니다.
발단
기존 프로젝트는 JavaScript
, React
, Recoil
기반으로 작성되어 있었고, 저에게 익숙한 스택이었기 때문에 들어오는 요청을 처리하는 데 큰 어려움은 없었습니다. 하지만, ① API 타입을 명시할 수 없는 불편함. ② 오류 추적의 어려움. ③ PriavteRoute
가 클라이언트 단에서 분기되어 발생하는 깜빡임 현상 등의 문제를 경험했습니다.
여기에서 ①, ② 문제는 TypeScript
도입, ③ 문제는 Next.js
의 Middleware
를 통해 해결할 수 있다고 생각했고, 앱 라우터 환경에서의 컴포넌트 Colocation
, 서버 컴포넌트를 활용한 데이터 패칭 등의 이점이 크다고 생각했습니다.
회사 측에서는 출시일만 맞춰달라고 요청하셔서, 마이그레이션과 기존 코드 개선, 새로운 페이지 추가 작업을 동시에 진행하게 되었습니다.
전개
처음에는 기존 구조를 크게 건드리지 않고, 새로운 기능이나 페이지를 작성할 때만 .tsx
확장자의 TypeScript
컴포넌트를 사용하는 방식으로 점진적인 마이그레이션을 시도했습니다. 기존 JavaScript
코드와 혼용이 가능하다는 점을 활용해, 일단 되는 데까지 해보자는 접근이었죠.
위기
개발을 계속하다 보니, 코드 구조 자체에 대한 고민이 생기기 시작했습니다. 당시 프로젝트의 구조는 아래와 같은데요,
cson
└── src
├── api
├── assets
├── auth
├── common
│ ├── components
│ └── constants
├── components
├── hooks
├── manage
│ ├── components
│ ├── constants
│ └── pages
├── recoil
├── service
│ ├── components
│ ├── constants
│ └── pages
├── styles
└── utils
service
는 사용자용 웹, manage
는 관리자용 웹 도메인을 담당하는 구조였지만, 페이지 내에서 사용되는 모든 컴포넌트를 components
폴더에 몰아넣다 보니, 어떤 컴포넌트가 어떤 페이지에서 사용되는지 파악하기 어려운 문제가 있었습니다.
더 큰 문제는 이 프로젝트가 SPA(Single Page Application)
로 동작하다 보니, 일반 사용자조차도 관리자 페이지의 스크립트를 함께 로드해야 한다는 점이었습니다. 페이지가 늘어날수록 번들 용량은 계속해서 커졌습니다. 게다가 제약사와 딜러용 웹도 추가될 예정이었기 때문에, 확장성을 유지할 수 없다고 판단했습니다.
결국, 도메인별로 앱을 나누고, 각 앱이 독립적으로 동작하는 구조로 전환하기로 했고, 새로운 리포지터리를 구성하면서 프로젝트 구조를 전면적으로 다시 설계하게 되었습니다.
절정
GDGoC HUFS
Monthly: 패키지 매니저와 모노레포
전략 글을 작성할 정도로 저는 pnpm
과 Turborepo
를 이용한 모노레포 구조를 좋아합니다. 빌드 파이프라인 작성도 쉽고, 속도도 빠르며, 도메인 단위로 앱을 분리하기에 아주 적합하죠.
CSON 프로젝트도 이 구조를 적용했고, 최종적으로 아래와 같이 재구성했습니다.
cson
├── apps
│ ├── service
│ ├── manager
│ ├── pharmacist
│ └── dealer
├── packages
│ ├── api
│ ├── style
│ ├── ui
│ └── icon
└── tools
├── config-eslint
└── config-typescript
공통으로 사용하는 패키지는 packages
에 작성하고, 이 의존성을 가져와 사용합니다. 각 앱에서 Next.js
의 앱 라우터를 사용하는 만큼, 함께 수정되는 파일을 같은 디렉토리에 두기 원칙을 지키기 쉬워졌습니다.
컴포넌트에 대해 다시 생각해 보면서 전역 상태 관리 라이브러리를 사용하지 않아도 되겠다는 생각이 들었고, 페이지 상태 관리에 searchParams
를 사용하여, URL
을 통한 맥락 전달도 가능해졌습니다.
성능 이점도 있었는데요, 기존의 경우 Lazy Loading
이 사용되지 않았기 때문에, 822 kB
의 초기 번들 크기를 가지고 있었습니다. 현재는 가장 크기가 큰 매니저 앱이 174 kB
로 매우 줄어들었고, middleware
를 통한 인증 처리로 깜빡임 현상도 없어졌습니다.
결말
잠깐 과거를 반성하자면, 다른 개발자들이 이력에 마이그레이션 경험을 적어놓는 것에 특별함을 느끼지 못했습니다. 하지만, 이번 프로젝트를 통해 생각했던 것보다 더 많은 작업량과 고민이 필요함을 경험했습니다.
컴포넌트를 작성할 때, 단순히 기존 코드를 복사해서 붙여 넣는 것이 아니라 역할에 맞게 구조를 다시 설계하고, 진짜 필요한 것만 남기는 과정이 반복됐는데요, 이 과정에서 꼭 복잡한 의존성이 있어야 좋은 구조가 되는 건 아니라는 것도 배웠습니다.
CSON은 선유도로 출근하며 즐겁게 개발한 만큼 더 애정이 가는 프로젝트입니다. 저는 이 프로젝트가 예상대로 흘러갔으면 좋겠고, 업계에서 인정받는 서비스로 성장하기를 진심으로 바라고 있습니다.