얼마 전 벨로그 글을 구경하다가 프론트엔드 개발자 관점으로 바라보는 관심사의 분리와 좋은 폴더 구조 (feat. FSD)라는 글을 보게 되었다. 폴더 구조에 대한 고민이 많던 찰나에 재미있게 보았고 여기에서 나온 FSD 아키텍처에 대해 알아보고자 한다.
Feature-Sliced Design(FSD)는 이름 그대로 기능에 따라 코드를 분리하는 아키텍처이다.
기존에 내가 사용하던 폴더 구조는 아래와 같다. (Vite 기준)
src
|_api
|_assets
|_components
|_constants
|_hooks
|_lib
|_models
|_pages
|_store
|_types
|_utils
서버와 통신하는 부분은 api 폴더에, 공통적으로 사용되거나 페이지별로 필요한 컴포넌트들은 components 폴더에 넣어두었다. 즉, 역할에 따라 폴더 구조를 나누었다.
FSD는 위에서 언급했듯이 기능에 따라 분리를 하게 되며 아래와 같은 계층적 구조를 가지게 된다.
출처: https://feature-sliced.design/kr/docs/get-started/overview
app
- 애플리케이션의 진입점과 전역적으로 적용되는 설정 및 구조를 관리pages
- 전체 페이지 또는 중첩 라우팅에서 페이지의 주요 부분Home.tsx
혹은 글 상세 페이지인 Post.tsx
widgets
- 페이지 전반에 걸쳐 공통적이고 반복적으로 사용되는 UI 구성 요소. 특정 페이지에 종속되지 않으며 여러 페이지에서 재사용 가능Header/index.tsx
features
- 특정 기능 단위로 모아둔 폴더. 각 feature는 독립적인 비즈니스 로직이나 특정 기능을 담당하는 컴포넌트를 포함entities
- 애플리케이션의 핵심 도메인 모델을 관리하는 폴더. API 요청, 데이터 모델, 전역 상태 관리 등user/model.ts
: 사용자 모델 정의product/api.ts
: 상품과 관련된 API 호출 로직shared
- 애플리케이션 전반에서 재사용 가능한 작은 유틸리티와 컴포넌트를 모아둔 폴더ui/Button.tsx
: 재사용 가능한 버튼 컴포넌트lib/api.ts
: 공통 API 호출 로직utils/formatDate.ts
: 날짜 포맷팅 유틸리티app
과 shared
의 경우 slice는 없고 segment만 있다.
widget과 shared를 처음 봤을 때 애플리케이션 전반에 걸쳐 공통적으로 재사용이라는 의미로 어떤 것이 다른지 궁금했다.
widgets는 크고 레이아웃적인 요소들(Header, Footer), shared는 재사용 가능한 작은 컴포넌트(Button)나 기능들(formatDate)로 나누어지며, 그 역할과 사용 범위가 다르다.
Slice는 비즈니스 도메인별로 코드를 분할된 것을 의미한다.
features
|_user
|_post
|_comment
Slice는 같은 레이어 안에서 다른 슬라이스를 참조할 수 없다. 이는 높은 응집도와 낮은 결합도를 유지하는 데 도움이 된다.
Segement는 목적에 따라 코드를 그룹화한다. 아래는 몇 가지 관례적인 이름이다.
ui
- UI 컴포넌트, 스타일 등 UI와 관련된 모든 것api
- 백엔드와 상호작용할 때 필요한 모든 것model
- 데이터의 구조, 인터페이스 관련 로직lib
- 슬라이스 안에 있는 다른 모듈이 필요로 하는 유틸리티 함수를 포함하는 라이브러리 코드config
- 설정 파일과 기능 플래그.cli를 통해 Next 프로젝트를 생성 후 아래와 같이 적용해볼 수 있을 것 같다. (App router, src directory 사용)
src
|_app
|_entities
|_features
|_shared
|_widgets
위 폴더구조에서 pages
가 빠진 이유는 App router의 경우 폴더 내부에서 작성한 page.tsx 파일이 page 자체가 되기 때문에 제외해도 무방할 것 같다고 생각했다.
프로젝트가 점점 커지면 FSD 아키텍처를 써보면 괜찮다는 이야기는 이전에 들었던 적이 있다. 그래서 벨로그의 글을 보다가 공부해봐야겠다는 생각을 했고, 좋은 시간이었다.
하지만 아직 FSD 아키텍처를 완벽하게 이해하지는 못한 것 같다. 이번 기회에 프로젝트에 한 번 도입해보며 알아가는 시간을 가져보아야겠다.