FSD 아키텍처는 대규모 프론트엔드 프로젝트의 구조 문제를 계층 분리로 다룬다

항해99 코드 리뷰 중에 FSD(Feature-Sliced Design)라는 키워드가 나왔다. 처음 들어봤던 개념이라 찾아봤는데, 대규모 프론트엔드 프로젝트가 왜 구조적으로 망가지는지를 설명해주는 아키텍처 패턴이었다.

기존 프론트엔드 구조의 문제

보통 프론트엔드 프로젝트는 이렇게 시작한다:

src/
  components/
  pages/
  hooks/
  utils/
  services/

작을 때는 문제없다. 그런데 팀이 늘고 기능이 쌓이면 components/에 수십 개가 넘는 컴포넌트가 생기고, 어디서 무엇이 어디를 import하는지 파악이 안 된다. UserCardProductList에서 쓰이고, ProductList가 다시 UserProfile을 import하는 순환 의존성이 생기기 시작한다. 이걸 규모가 커지면서 생기는 “구조 문제”라고 한다.

FSD의 핵심: 계층을 정의하고, 위에서 아래로만

FSD는 프로젝트를 6개의 계층으로 나눈다:

계층역할
app앱 초기화, 라우팅, 전역 스타일
pages라우트별 페이지 컴포넌트
widgets여러 feature를 조합한 독립 블록
features사용자 시나리오 단위 (좋아요, 댓글 작성 등)
entities비즈니스 도메인 (User, Product, Order)
shared공용 유틸리티, UI 컴포넌트, API 클라이언트

핵심 규칙은 단순하다. 상위 계층은 하위 계층을 import할 수 있지만, 그 반대는 안 된다. entitiesfeatures를 import하면 안 된다. shared는 그 어떤 계층도 import하면 안 된다.

이 규칙 하나로 순환 의존성이 원천 차단된다.

각 feature는 슬라이스로 분리된다

계층 안에서 기능별로 또 분리한다. 예를 들어 features/ 안에는:

features/
  add-to-cart/
  write-comment/
  like-post/

각 슬라이스는 자신의 UI, 모델, API 호출을 다 갖는다. 다른 슬라이스를 import하면 안 된다. 슬라이스 간 공유가 필요한 것은 sharedentities로 내려야 한다.

이 덕분에 “add-to-cart 기능을 삭제해도 되나?” 같은 질문에 자신 있게 답할 수 있다. 해당 슬라이스가 다른 슬라이스에 의존하지 않으니까.

실제로 쓸 때 고민되는 지점

소규모 프로젝트에서 FSD를 처음부터 도입하면 오버엔지니어링이 될 수 있다. 화면이 3개짜리 프로젝트에서 6개 계층을 만드는 건 배보다 배꼽이 크다.

기존 레거시 코드베이스에 점진적으로 도입하는 것도 쉽지 않다. 처음에는 sharedentities만 분리하고, 점차 features를 추가하는 방식으로 접근하는 게 현실적이다.

연결

출처