LIAN KIM
ResumeProjectsBlog
이력서

On this page

문제검토와 판단배포 분리 검토스코프와 서브 스코프의존 규칙 강제마이그레이션결과더 읽기

프론트엔드 아키텍처 재구성

표준 FSD를 그대로 쓰지 않은 이유

패션 제품의 라이프사이클을 추적하고 디지털 제품 여권(DPP)을 발행하는 플랫폼에서, 프론트엔드 구조를 재설계한 기록이다.

문제#

하나의 코드베이스 안에 성격이 다른 세 영역이 함께 있었다. 운영자가 쓰는 관리 영역, 소비자가 제품 정보를 보는 영역, 외부 기관이 시험성적서를 조회하는 영역이다. 이 셋은 페이지도, 라우팅도, 비즈니스 로직도 거의 공유하지 않는 사실상 독립된 애플리케이션이었다.

게다가 관리 영역 안에서도 사용자가 한 종류가 아니었다. 플랫폼 운영자, 브랜드 담당자, 라벨 제작사처럼 권한이 다른 운영자들이 있었고, 각자 접근할 수 있는 화면과 기능이 달랐다.

이렇게 영역이 여러 층위로 갈리는데도, 코드는 한 구조에 섞여 있었고 코드 간의 경계가 강제되지 않았다. 한 영역의 변경이 다른 영역으로 번질 수 있었고, 권한이 다른 화면들의 코드가 서로 얽힐 여지가 있었다. 영역과 권한이 늘어날수록 더 풀기 어려워지는 구조였다.

여기에 빌드 환경의 문제가 겹쳤다. CRA는 공식적으로 지원이 중단된 상태였고, 그로 인해 일부 라이브러리에서 버전 호환 문제가 나타나고 있었다. 어차피 Vite로 옮겨야 했고, 옮기려면 코드 전체를 손대야 했다. 구조 재설계를 마이그레이션과 함께 진행하기로 한 배경이다.

검토와 판단#

배포 분리 검토#

앱을 아예 분리하는 선택지부터 검토했다. 모노레포나 마이크로 프론트엔드 같은 구조다. 이런 구조는 독립 배포, 독립 팀, 독립 릴리즈 주기가 필요할 때 가치가 크다. 우리는 한 팀이 하나의 파이프라인으로 함께 릴리즈하고 있었고, 인증과 공통 UI처럼 공유하는 자원도 많았다. 이 규모에서 배포를 쪼개면 오히려 런타임 통합, 공통 의존성 중복, 빌드 복잡도 같은 비용이 얻는 것보다 컸다.

지금 단계에 맞는 것은 배포의 분리가 아니라 관심사의 분리라고 판단했다.

스코프와 서브 스코프#

도메인을 기준으로 코드를 나누기 위해 FSD(Feature-Sliced Design)를 도입했다. 기능을 레이어와 슬라이스로 나누고, 상위 계층만 하위를 참조하게 하는 단방향 의존 구조다.

다만 표준 FSD를 그대로 적용하기에는 한 가지가 맞지 않았다. 표준 FSD는 하나의 애플리케이션을 전제로 계층을 나눈다. 그런데 이 프로젝트는 앞서의 세 영역이 사실상 별개의 앱이었고, 관리 영역은 그 안에서 다시 권한별로 갈렸다. 단일 애플리케이션을 전제한 계층 구조만으로는, 세 영역을 격리하고 권한이 다른 운영자 영역이 서로 침범하지 못하게 한다는 경계를 표현하기 어려웠다.

그래서 표준 FSD의 계층 위에 두 단계를 더 두었다.

  • Scope (앱 단위 분리) : 성격이 다른 세 영역을 최상위에서 독립된 스코프로 나눴다. 각 스코프는 자기만의 계층(pages·features·entities·shared)을 가진다.
  • Sub-Scope (권한 단위 분리) : 관리 영역처럼 권한이 다른 운영자가 공존하는 스코프는, 그 안에서 다시 권한별 하위 스코프로 나눴다.

이렇게 하면 가장 상위 단계가 영역과 권한이 되므로, 성격이 다르거나 권한이 다른 코드가 구조적으로 서로 침범하지 못한다. 영역과 권한이 여러 층위로 갈리는 이 프로젝트에는 표준 위에 상위 단계가 더 필요하다고 판단한 것이다. 두 단계의 스코프가 얹어진 이 구조를 Multi-scope FSD라고 부르기로 했다.

표준 FSD와 Multi-scope FSD 구조 비교
표준 FSD와 Multi-scope FSD 구조 비교

의존 규칙 강제#

구조를 나누는 것만으로는 부족했다. 경계를 정해도, 지키는 것이 사람의 주의에 달려 있으면 시간이 지나며 무너질 수 있다.

그래서 레이어 간 단방향 의존 원칙을 ESLint 규칙으로 강제했다. 상위 계층은 하위 계층을 참조할 수 있지만 그 반대는 막는 규칙을 도구가 검사하도록 했고, 규칙을 어긴 import가 있으면 husky와 lint-staged를 거쳐 커밋 단계에서 차단되게 했다. 아키텍처 위반이 커밋 시점의 도구에서 검출되도록, 문서가 아니라 실행되는 규칙으로 만들었다.

다만 규칙이 모든 경계를 커버한 것은 아니다. 레이어 간 의존은 ESLint로 강제했지만, 스코프 사이의 경계는 디렉토리 구조와 팀 규약으로 유지했다.

FSD 기초 적용(features와 entities 구분 등)과 Atomic Design 조합, ESLint 자동화의 구체적인 과정은 블로그에 정리했다 → FSD 도입기: features/entities 구분부터 ESLint 자동화까지

마이그레이션#

  • 마이그레이션 : 구조를 재구성하며 반복적으로 생기는 파일 이동과 import 경로 수정은 AI 도구로 자동화하고, 도메인 경계와 의존 방향 등 판단이 필요한 부분은 직접 검증하고 교정했다.
  • 공통 컴포넌트 : 공통 UI 컴포넌트는 Atomic Design을 기준으로 분류하고, Storybook으로 50개 이상을 문서화했다. FSD의 계층이 코드 배치 기준이라면, Atomic Design은 공통 UI의 분류 기준으로 함께 썼다.
  • 팀 기준 공유 : 팀원들이 같은 기준으로 구조를 판단할 수 있도록 FSD 개요, 구조 가이드, 체크리스트를 문서로 정리했다.

결과#

규칙을 어긴 코드는 커밋되지 않기 때문에, 잘못된 참조가 늘어나는 일을 막을 수 있었다. 팀원들의 온보딩도 이 구조와 문서를 기준으로 진행했다.

함께 진행한 CRA → Vite 전환으로 빌드 시간도 81초에서 34초로 58% 줄일 수 있었다. 전환 전후를 동일 조건에서 3회 빌드해 중앙값으로 재측정한 값이다.

더 읽기#

  • [블로그] FSD 도입기: features/entities 구분부터 ESLint 자동화까지. FSD 기초 적용, Atomic Design 조합, ESLint 자동화를 어떻게 했는지에 대한 기록