프론트엔드 아키텍처 재구성
패션 제품의 라이프사이클을 추적하고 디지털 제품 여권(DPP)을 발행하는 플랫폼에서, 프론트엔드 구조를 재설계한 기록이다.
하나의 코드베이스 안에 성격이 다른 세 영역이 함께 있었다. 운영자가 쓰는 관리 영역, 소비자가 제품 정보를 보는 영역, 외부 기관이 시험성적서를 조회하는 영역이다. 이 셋은 페이지도, 라우팅도, 비즈니스 로직도 거의 공유하지 않는 사실상 독립된 애플리케이션이었다.
게다가 관리 영역 안에서도 사용자가 한 종류가 아니었다. 플랫폼 운영자, 브랜드 담당자, 라벨 제작사처럼 권한이 다른 운영자들이 있었고, 각자 접근할 수 있는 화면과 기능이 달랐다.
이렇게 영역이 여러 층위로 갈리는데도, 코드는 한 구조에 섞여 있었고 코드 간의 경계가 강제되지 않았다. 한 영역의 변경이 다른 영역으로 번질 수 있었고, 권한이 다른 화면들의 코드가 서로 얽힐 여지가 있었다. 영역과 권한이 늘어날수록 더 풀기 어려워지는 구조였다.
여기에 빌드 환경의 문제가 겹쳤다. CRA는 공식적으로 지원이 중단된 상태였고, 그로 인해 일부 라이브러리에서 버전 호환 문제가 나타나고 있었다. 어차피 Vite로 옮겨야 했고, 옮기려면 코드 전체를 손대야 했다. 구조 재설계를 마이그레이션과 함께 진행하기로 한 배경이다.
앱을 아예 분리하는 선택지부터 검토했다. 모노레포나 마이크로 프론트엔드 같은 구조다. 이런 구조는 독립 배포, 독립 팀, 독립 릴리즈 주기가 필요할 때 가치가 크다. 우리는 한 팀이 하나의 파이프라인으로 함께 릴리즈하고 있었고, 인증과 공통 UI처럼 공유하는 자원도 많았다. 이 규모에서 배포를 쪼개면 오히려 런타임 통합, 공통 의존성 중복, 빌드 복잡도 같은 비용이 얻는 것보다 컸다.
지금 단계에 맞는 것은 배포의 분리가 아니라 관심사의 분리라고 판단했다.
도메인을 기준으로 코드를 나누기 위해 FSD(Feature-Sliced Design)를 도입했다. 기능을 레이어와 슬라이스로 나누고, 상위 계층만 하위를 참조하게 하는 단방향 의존 구조다.
다만 표준 FSD를 그대로 적용하기에는 한 가지가 맞지 않았다. 표준 FSD는 하나의 애플리케이션을 전제로 계층을 나눈다. 그런데 이 프로젝트는 앞서의 세 영역이 사실상 별개의 앱이었고, 관리 영역은 그 안에서 다시 권한별로 갈렸다. 단일 애플리케이션을 전제한 계층 구조만으로는, 세 영역을 격리하고 권한이 다른 운영자 영역이 서로 침범하지 못하게 한다는 경계를 표현하기 어려웠다.
그래서 표준 FSD의 계층 위에 두 단계를 더 두었다.
pages·features·entities·shared)을 가진다.이렇게 하면 가장 상위 단계가 영역과 권한이 되므로, 성격이 다르거나 권한이 다른 코드가 구조적으로 서로 침범하지 못한다. 영역과 권한이 여러 층위로 갈리는 이 프로젝트에는 표준 위에 상위 단계가 더 필요하다고 판단한 것이다. 두 단계의 스코프가 얹어진 이 구조를 Multi-scope FSD라고 부르기로 했다.

구조를 나누는 것만으로는 부족했다. 경계를 정해도, 지키는 것이 사람의 주의에 달려 있으면 시간이 지나며 무너질 수 있다.
그래서 레이어 간 단방향 의존 원칙을 ESLint 규칙으로 강제했다. 상위 계층은 하위 계층을 참조할 수 있지만 그 반대는 막는 규칙을 도구가 검사하도록 했고, 규칙을 어긴 import가 있으면 husky와 lint-staged를 거쳐 커밋 단계에서 차단되게 했다. 아키텍처 위반이 커밋 시점의 도구에서 검출되도록, 문서가 아니라 실행되는 규칙으로 만들었다.
다만 규칙이 모든 경계를 커버한 것은 아니다. 레이어 간 의존은 ESLint로 강제했지만, 스코프 사이의 경계는 디렉토리 구조와 팀 규약으로 유지했다.
FSD 기초 적용(features와 entities 구분 등)과 Atomic Design 조합, ESLint 자동화의 구체적인 과정은 블로그에 정리했다 → FSD 도입기: features/entities 구분부터 ESLint 자동화까지
규칙을 어긴 코드는 커밋되지 않기 때문에, 잘못된 참조가 늘어나는 일을 막을 수 있었다. 팀원들의 온보딩도 이 구조와 문서를 기준으로 진행했다.
함께 진행한 CRA → Vite 전환으로 빌드 시간도 81초에서 34초로 58% 줄일 수 있었다. 전환 전후를 동일 조건에서 3회 빌드해 중앙값으로 재측정한 값이다.