둘러보기
Feature-Sliced Design (FSD)는 프론트엔드 애플리케이션의 구조를 잡는 아키텍처 방법론입니다. 간단히 말해, 코드 구성에 관한 규칙과 관례를 모아놓은 것입니다. 이 방법론의 주요 목적은 계속 변화하는 비즈니스 요구사항에 직면했을 때 프로젝트를 더 이해하기 쉽고 안정적으로 만드는 것입니다.
FSD는 규칙을 제시할 뿐만 아니라, 실제 개발 과정을 돕는 다양한 도구들을 함께 제공합니다. 프로젝트 아키텍처를 확인하는 린터, CLI나 IDE를 통한 폴더 생성기, 그리고 다양한 예제 라이브러리를 제공합니다.
내 프로젝트에 적합할까?
FSD는 규모에 관계 없이 모든 팀과 프로젝트에서 사용할 수 있습니다. 다음과 같은 경우 여러분의 프로젝트에 적합합니다:
- 여러분이 프론트엔드를 개발하고 있다면 (웹, 모바일, 데스크톱 등의 UI)
- 여러분이 라이브러리가 아닌 애플리케이션을 만들고 있다면
그게 다예요! 사용하는 프로그래밍 언어, UI 프레임워크, 상태 관리의 제한은 없습니다. FSD를 점진적으로 도입할 수 있고, 모노레포에서 사용할 수 있으며, 앱을 패키지로 분할하고 각각에 FSD를 개별적으로 적용하여 큰 규모로 확장할 수 있습니다.
이미 아키텍처가 있고 FSD로의 전환을 고려 중이라면, 현재 아키텍처가 문제를 일으키고 있는지 확인하세요. 예를 들어, 프로젝트가 너무 커지고 상호 연결되어 새로운 기능을 효율적으로 구현하기 어려워졌거나, 많은 사람이 새롭게 팀에 합류할 것으로 예상되는 경우입니다. 현재 아키텍처가 잘 작동한다면 변경할 필요가 없을 수도 있습니다. 하지만 마이그레이션을 결정했다면, 마이그레이션 가이드를 확인하세요.
간단한 예제
다음은 FSD를 구현한 간단한 프로젝트입니다:
📁 app
📁 pages
📁 shared
이 최상위 폴더들을 레이어(layers)라고 합니다. 더 자세히 살펴보겠습니다:
📂 app
📁 routes
📁 analytics
📂 pages
📁 home
📂 article-reader
📁 ui
📁 api
📁 settings
📂 shared
📁 ui
📁 api
📂 pages 내부의 폴더들을 슬라이스(slices)라고 합니다. 슬라이스는 도메인에 따라 레이어를 나눕니다.(이 경우에는 페이지별로)
📂 app
, 📂 shared
, 그리고 📂 pages/article-reader
내부의 폴더들을 세그먼트(segments)라고 합니다. 세그먼트는 코드의 기능적 목적, 다시말해 코드가 수행하는 역할 따라 슬라이스(또는 레이어)를 나눕니다.
개념
레이어, 슬라이스, 세그먼트는 다음과 같은 계층 구조를 형성합니다:
레이어
레이어는 모든 FSD 프로젝트에서 표준화되어 있습니다. 모든 레이어를 사용할 필요는 없지만, 이름은 중요합니다. 현재(위에서 아래로) 7개가 있습니다:
- App* - 앱을 실행하는 모든 것 - 라우팅, 진입점, 전역 스타일, 프로바이더.
- Processes(더 이상 사용되지 않음) - 페이지 간 복잡한 시나리오.
- Pages - 전체 페이지 또는 중첩 라우팅에서 페이지의 주요 부분.
- Widgets - 독립적으로 작동하는 대규모 기능 또는 UI 컴포넌트, 보통 하나의 완전한 기능.
- Features - 제품 전반에 걸쳐 재사용되는 기능 구현체로, 사용자에게 실질적인 비즈니스 가치를 제공하는 동작.
- Entities - 프로젝트가 다루는 비즈니스 엔티티, 예를 들어 user 또는 product.
- Shared* - 재사용 가능한 기능, 특히 프로젝트/비즈니스의 특성과 분리되어 있을 때 (반드시 그럴 필요는 없음).
* - App과 Shared는 다른 레이어들과 달리 슬라이스를 가지지 않으며, 직접 세그먼트로 구성됩니다.
레이어를 다룰 때의 중요한 점은 한 레이어의 구성 요소는 반드시 아래에 있는 레이어의 구성 요소만 알수있고 임포트할 수 있다는 것입니다.
슬라이스
다음은 슬라이스입니다. 슬라이스는 비즈니스 도메인별로 코드를 분할합니다. 여러분은 자유롭게 이름을 선택할 수 있고, 원하는 만큼 많이 만들 수 있습니다. 슬라이스는 논리적으로 관련된 모듈들을 가까이 유지함으로써 코드베이스를 더 쉽게 탐색할 수 있게 해줍니다.
슬라이스는 같은 레이어 안에서 다른 슬라이스를 참조할 수 없으며, 이 규칙은 높은 응집도와 낮은 결합도를 유지하는 데 도움이 됩니다.
세그먼트
슬라이스와 App, Shared 레이어는 세그먼트로 구성되며, 세그먼트는 목적에 따라 코드를 그룹화합니다. 세그먼트 이름은 표준에 의해 제한되지 않지만, 가장 일반적인 목적을 위한 몇 가지 관례적인 이름이 있습니다.:
ui
- UI와 관련된 모든 것: UI 컴포넌트, 날짜 포맷터, 스타일 등.api
- 백엔드 상호작용: request 함수, 데이터 타입, mapper 등.model
- 데이터 모델: 스키마, 인터페이스, 스토어, 비즈니스 로직.lib
- 슬라이스 안에 있는 다른 모듈이 필요로 하는 라이브러리 코드.config
- 설정 파일과 기능 플래그.
대부분의 레이어에서는 이 세그먼트들로 충분하며, Shared나 App에서만 자신만의 세그먼트를 만들 것입니다. 하지만 이건 꼭 지켜야하는 규칙은 아닙니다.
장점
-
균일성
구조가 표준화되어 있어, 프로젝트가 더 균일해지며, 이는 새로운 멤버가 팀에 적응하는 것을 더 쉽게 만듭니다. -
변경과 리팩토링에 대한 안정성
한 레이어의 구성 요소는 같은 레이어나 상위 레이어의 다른 구성 요소를 사용할 수 없습니다. 이로 인해 앱의 사이드 이펙트 없이 격리된 수정을 할 수 있습니다. -
로직 재사용을 통제
레이어에 따라 코드를 매우 재사용 가능하게 또는 매우 지역적으로 만들 수 있습니다. 이는 DRY 원칙과 실용성 사이의 균형을 유지합니다. -
비즈니스와 사용자 요구에 대한 지향성
앱은 비즈니스 도메인으로 분할되며, 이름을 지을 때 비즈니스 언어 사용이 권장됩니다. 이로 인해 프로젝트와 무관한 부분을 완전히 이해하지 않고도 유용한 개발을 할 수 있습니다.
점진적 도입
FSD로 마이그레이션하고자 하는 기존 코드베이스가 있다면, 다음과 같은 전략을 제안합니다. 이는 우리의 마이그레이션 경험에서 유용했던 방법입니다.
-
App과 Shared 레이어를 모듈별로 천천히 구성하여 기반을 만드는 것으로 시작하세요.
-
기존의 모든 UI를 Widgets와 Pages에 큰 틀에서 분배하세요. FSD 규칙을 위반하는 의존성이 있더라도 괜찮습니다.
-
점진적으로 임포트 위반을 해결하고, Entities와 가능하다면 Features도 추출하기 시작하세요.
리팩토링 중이거나 프로젝트의 특정 부분만 리팩토링할 때는 새로운 대규모 엔티티를 추가하지 않는 것이 좋습니다.