테마
Dooray 프로젝트 소개 - 모놀리식에서 마이크로 프론트엔드로
NHN Dooray(두레이) 리뉴얼 프로젝트의 배경과 점진적 마이그레이션을 선택한 이유를 살펴본다.
학습 목표
- NHN Dooray 서비스의 전체 아키텍처와 프로젝트 규모를 이해한다.
- 프론트엔드 모놀리식 + 백엔드 마이크로서비스 조합에서 발생하는 문제점을 파악한다.
- 빅뱅 전환 대신 점진적 마이그레이션을 선택한 근거를 설명할 수 있다.
- 전체 마이그레이션 로드맵의 각 단계를 개괄적으로 이해한다.
본문
1. Dooray 서비스란 무엇인가
Dooray(두레이)는 NHN에서 운영하는 협업 플랫폼이다. 단일 서비스가 아니라 업무 관리, 메일, 캘린더, 드라이브, 위키, 주소록, 게시판 등 다수의 도메인 서비스가 하나의 통합 워크스페이스로 묶여 있다.
2021년 10월 리뉴얼 프로젝트가 재개되었으며, 이 시점에서 모놀리식 SPA를 점진적으로 마이크로 프론트엔드 아키텍처로 전환하는 여정이 시작되었다.
서비스들은 전체 레이아웃이 매우 유사하고, URL 체계도 서비스 단위로 명확하게 분리되어 있었다. 이런 특성은 마이크로 프론트엔드 적용에 유리한 조건이었다.
2. 리뉴얼 시점의 기술 스택과 아키텍처
리뉴얼이 재개된 시점의 기술 환경은 다음과 같았다.
| 항목 | 선택 |
|---|---|
| 모노레포 도구 | Yarn Classic Workspaces |
| UI 프레임워크 | React + TypeScript |
| 번들러 | Vite (초기) |
| 전역 상태 관리 | Redux Toolkit + Redux Saga |
| 스타일링 | Emotion (CSS-in-JS) |
| 패키지 구성 | UIKit(디자인 시스템) + Main Service(SPA) |
핵심 문제: UIKit은 빌드 결과물이 아닌 소스코드를 직접 참조하는 형태였다. tsconfig.json의 paths alias를 통해 Main Service가 UIKit의 소스코드를 직접 import하고 있었기 때문에, 두 패키지는 사실상 코드 위치만 분리된 강결합 상태였다.
또한 Yarn Classic의 Phantom Dependency 문제로 인해 UIKit 내부에서 import하는 의존성(예: Emotion)이 실제로는 Main Service의 node_modules에서 해석되는 불안정한 구조였다.
3. 시스템 전체 아키텍처
프론트엔드만 모놀리식이었고, 백엔드는 이미 마이크로서비스로 운영 중이었다.
프론트엔드 애플리케이션은 SPA로 빌드한 뒤 Nginx를 통해 정적 파일로 서빙되었고, Aggregation Layer가 게이트웨이 및 세션 관리 역할을 수행했다. 각 도메인별 백엔드 서비스는 마이크로서비스 형태로 이미 독립 운영 중이었다.
4. 서비스별 상세 구성
Dooray의 각 서비스는 독립적인 도메인 로직을 가지고 있었지만, 하나의 SPA 안에서 공존하고 있었다.
| 서비스 | 주요 기능 | URL 패턴 |
|---|---|---|
| 홈/게시판 | 대시보드, 공지사항, 게시판 관리 | /home/* |
| 업무(Task) | 업무 생성/관리, 담당자 배정, 상태 추적 | /task/* |
| 메일(Mail) | 메일 송수신, 첨부파일, 필터 | /mail/* |
| 캘린더 | 일정 관리, 공유 캘린더, 알림 | /calendar/* |
| 드라이브 | 파일 업로드/다운로드, 폴더 관리, 공유 | /drive/* |
| 위키 | 문서 작성/편집, 버전 관리 | /wiki/* |
| 주소록 | 사내 연락처 검색, 조직도 | /contacts/* |
| 결재 | 결재 요청/승인 (별도 서버, 리뉴얼 범위 밖) | 별도 도메인 |
서비스 간 UI가 매우 유사하고 일관된 디자인 체계를 따르고 있어, 워크스페이스 형태의 통합 서비스라는 특성이 마이크로 프론트엔드 적용에 적합한 조건을 만들었다. URL 체계가 서비스 단위로 깔끔하게 나뉘어 있었기 때문에 라우팅 기반의 서비스 분리가 자연스러웠다.
5. 프로젝트 규모와 도전 과제
- 12명 이상의 프론트엔드 엔지니어가 참여 (지원 인력 포함 약 20명)
- Main Service 내에서
src/modules/{서비스명}디렉토리로 코드를 나누어 작업 - 전역 스토어는 Ducks 패턴으로 모듈화하여 관리
- 각 엔지니어는 담당 서비스 디렉토리에서 작업하여 conflict를 최소화하려 했으나, 공통 모듈과 Redux 스토어 변경 시에는 충돌이 빈번하게 발생했다.
마이크로 프론트엔드 도입을 검토하게 된 신호들
| 문제 | 설명 |
|---|---|
| 도메인 지식의 파편화 | 20명의 엔지니어가 모든 도메인을 파악하기 어려움 |
| 오너십 부재 | 서비스별 담당자에게 명확한 소유권을 부여하고 싶었음 |
| 레거시 재생산 우려 | 새로 만드는 서비스가 다시 거대한 레거시가 되지 않길 바랐음 |
| 빌드 시간 증가 | 소스코드가 방대해지면서 개발 빌드가 점점 느려짐 |
| 통합/QA/배포의 고통 | 하나의 SPA를 통합 테스트하고 배포하는 과정이 병목 |
| 기술 선택권 제한 | 엔지니어에게 서비스별 기술 자율성을 부여하고 싶었음 |
6. 점진적 마이그레이션을 선택한 이유
빅뱅 전환(한 번에 모든 것을 바꾸는 방식) 대신 점진적 전환을 선택한 이유는 분명했다.
- 운영 중인 서비스: 사용자에게 서비스를 제공하면서 동시에 아키텍처를 변경해야 했다.
- 리스크 관리: 단계마다 검증하고 문제가 있으면 롤백할 수 있어야 했다.
- 팀 학습 곡선: 팀 전체가 마이크로 프론트엔드에 대한 경험이 부족했다.
- 비즈니스 연속성: 리뉴얼 작업과 신규 기능 개발이 동시에 진행되어야 했다.
점진적 전환 로드맵 개요
| 단계 | 내용 | 핵심 변경 |
|---|---|---|
| Phase 1 | 모노레포 내 패키지 분리 | 코드 물리적 이동, TS path alias 활용 |
| Phase 2a | 의존성 정리 및 패키지 계층화 | 공유 코드 추상화, 인프라 패키지 분리 |
| Phase 2b | 빌드타임 공유에서 패키지 빌드 후 공유로 전환 | 패키지 매니저 변경, NX 도입, 빌드 설정 |
| Phase 3 | 런타임 모듈 페더레이션 전환 | Webpack Module Federation, 독립 배포 |
7. 당부의 말: 사례의 한계
이 프로젝트 사례는 하나의 참고 사례일 뿐이다. 발표자(프로젝트 리드) 자신도 "지금이라면 다르게 했을 것"이라는 부분이 있다고 밝혔다.
- 모든 조직과 프로젝트에 동일하게 적용할 수 없다.
- 아키텍처 결정은 각 팀의 상황, 규모, 기술 수준에 맞게 조정해야 한다.
- 이 사례에서의 실수와 교훈을 참고하되, 맹목적으로 따르지 않아야 한다.
핵심 정리
| 항목 | 내용 |
|---|---|
| 프로젝트 | NHN Dooray 리뉴얼 (2021.10 재개) |
| 초기 상태 | FE 모놀리식 SPA + BE 마이크로서비스 |
| 팀 규모 | FE 12명+ (지원 포함 ~20명) |
| 기술 스택 | React, TypeScript, Redux, Emotion, Yarn Classic |
| 핵심 문제 | 도메인 파편화, 빌드 시간 증가, 배포 병목, 오너십 부재 |
| 전략 | 점진적 마이그레이션 (4단계 로드맵) |
| UIKit 이슈 | 빌드 없이 소스코드 직접 참조, Phantom Dependency |
기억할 포인트:
- 백엔드는 이미 마이크로서비스였지만 프론트엔드는 모놀리식이었다.
- UIKit과 Main Service는 "패키지 분리"라고 하지만 실제로는 소스코드 위치만 나눈 강결합이었다.
- 점진적 전환은 매 단계마다 검증과 롤백이 가능해야 한다.
다음 단계
다음 문서에서는 Phase 1: 모노레포 내 패키지 분리 과정을 상세히 다룬다. TypeScript의 path alias를 활용한 과도기 단계 전략과 서비스별 코드를 물리적으로 분리하는 구체적인 방법을 살펴본다.