Feature-Sliced Design은 프론트엔드 프로젝트를 위한 아키텍처 방법론입니다.
Feature-Sliced Design은 공식 문서에서 프론트엔드 프로젝트를 위한 아키텍처 방법론으로 언급되지만, 주요 목적이 패키지 의존성을 완화하는 구조를 만드는 것에 초점을 두고 있습니다.
공식문서 를 참고하여 더 상세한 내용을 확인할 수 있습니다.
FSD는 패키지 내부의 소스 코드 파일들 간에 불필요한 의존성을 줄이고 유연하게 관리하기 위해 사용됩니다. 폴더, 디렉토리, 패키지 등은 환경에 따라 다양한 이름으로 불리지만, 가장 중요한 것은 파일 간의 관계와 흐름을 쉽게 파악할 수 있도록 구조를 설계하는 것입니다.
FSD는 레이어, 슬라이스, 세그먼트라는 개념을 사용하여 파일간의 참조 방향성을 파악하기 쉽게 규칙들을 정의합니다.
레이어는 Feature-Sliced Design에서 최상위 조직 계층으로, 코드의 책임 범위와 다른 모듈에 대한 의존성을 기준으로 분리하는 역할을 합니다. 각 레이어는 코드의 책임 수준을 판단할 수 있도록 특별한 의미를 가집니다.
일반적인 JavaScript나 TypeScript 프로젝트는{프로젝트}/src
디렉토리 아래에 요구사항을 충족하는 패키지 또는 소스 코드 파일들로 구성됩니다.
경로에 작성된 파일들은 서로 상호작용하며 기능을 구현하기 때문에, 자연히 파일 간 참조 관계가 발생할 수밖에 없습니다. 이러한 참조를 체계적으로 관리하기 위해 FSD의 개념과 규칙을 활용하는 방법에 대해 알아보겠습니다.
먼저 src 패키지 하위에 생성되는 패키지들을 레이어라고 간주하고 다음과 같이 레이어들을 추가해줍니다.
알파벳 순서 정렬 때문에 순서가 섞이긴 했지만 번호를 매긴 순서대로 상위~하위 레이어로 분류합니다.
app
→ pages
→ widgets
→ features
→ entities
→ shared
위 레이어의 이름은 FSD 공식 문서에서 정의한 네이밍 규칙을 따르는게 좋습니다.
다만, 모든 레이어를 반드시 생성해야 하는 것은 아니며, 프로젝트의 성격에 따라 필요한 레이어만 선택적으로 만들어 사용할 수 있습니다.
레이어 하위에는 슬라이스(Slice)라는 패키지들이 구성되며, 슬라이스 내부에는 세그먼트(Segment)라는 패키지가 포함됩니다. FSD에서 슬라이스는 주로 레이어에 배치되는 위치에 따라 참조 가능 여부가 결정됩니다.
App
, Shared
레이어는 하위에 슬라이스 대신 세그먼트가 위치합니다. 따라서 참조 규칙을 따르지 않으며, 레이어 내부 세그먼트간의 참조가 가능합니다. 왜 예외인가?
예제 1
entities
레이어 하위의 user
슬라이스에 두개의 파일이 있는 상황입니다. ProfileCardUI
컴포넌트 파일과 해당 컴포넌트가 사용할 UserService
서비스 파일입니다.
ProfileCardUI
는 UserService
의 기능을 사용하기 위해 해당 파일을 참조하고 있습니다. 이는 동일한 슬라이스 내 파일 간의 참조로, 레이어 간 import 규칙을 위반하지 않으므로 자유롭게 참조할 수 있습니다.
다만, 이러한 사례는 FSD가 관여할 수 없는 클래스 간의 의존성 관리에 해당합니다. 따라서 참조가 자유롭다고 하더라도, 양방향 참조와 같은 잠재적인 문제는 개발자가 직접 해결해야 할 영역입니다.
예제 2
entities 레이어 하위의 user슬라이스에 ProfileCardUI파일에서 shared레이어 하위의 ui세그먼트에 BaseImageUI파일을 참조하고 있습니다. (위에 언급한대로 app, shared 레이어는 슬라이스 없이 세그먼트를 사용합니다.)
entities는 shared 레이어보다 상위 레이어에 해당하므로, 하위 레이어의 슬라이스를 참조할 수 있다는 규칙에 따라 이 경우 규칙을 위반하지 않게 됩니다.
예제 3
entities
레이어 하위의 user
슬라이스에서 entities
레이어 하위의 bookmark
슬라이스의 서비스 파일을 참조하여 사용하고 있습니다.
이 경우 동일한 레이어 내의 다른 슬라이스 참조 불가능 규칙을 위배함으로 허용되지 않습니다.
예제 4
entities
레이어 하위의 user
슬라이스에서 pages
레이어 하위의 home
슬라이스의 서비스 파일을 참조하여 사용하고 있습니다.
이 경우 상위 레이어 내의 슬라이스 참조 불가능 규칙을 위배함으로 허용되지 않습니다.
예제 5
shared
레이어 내의 ui
세그먼트에서 services
세그먼트 서비스를 참조하여 사용하고 있습니다.
이 경우 같은 레이어 내의 파일들이지만, app, shared의 경우 예외이기 때문에 허용되는 범위 입니다.
슬라이스는 Feature-Sliced Design의 두 번째 조직 계층으로, 코드의 의미를 제품, 비즈니스, 또는 애플리케이션 관점에서 그룹화하는 데 사용됩니다. 슬라이스 이름은 비즈니스 도메인에 따라 결정되며, 예를 들어 사진 갤러리는 photo
, effects
, gallery-page
슬라이스를, 소셜 네트워크는 post
, comments
, news-feed
슬라이스를 가질 수 있습니다.
Shared
와 App
레이어는 비즈니스 로직이 없거나 애플리케이션 전체에 관련된 코드만 포함하므로 슬라이스를 포함하지 않습니다.
FSD에서는 궁극적으로 슬라이스를 통해 다음과 같은 이점을 얻을 수 있다고 말합니다.
Zero Coupling and High Cohesion
슬라이스(Slice)는 독립적이며 높은 응집력을 가진 코드 파일 그룹으로 설계됩니다.
높은 응집력(High Cohesion)
관련된 기능이나 책임을 가진 코드 파일들이 한 슬라이스 안에 모여 있어야 합니다.
이렇게 하면 각 슬라이스 내부의 코드가 단일 책임에 집중할 수 있어 유지보수와 확장이 용이해집니다.
예: 사용자 프로필과 관련된 모든 코드를 하나의 슬라이스에 포함.
제로 결합(Zero Coupling)
슬라이스 간의 상호 의존성을 최소화하여 독립성을 유지해야 합니다.
이를 통해 한 슬라이스의 변경이 다른 슬라이스에 영향을 미치지 않도록 설계할 수 있습니다.
예: 사용자 슬라이스와 인증 슬라이스가 서로 독립적으로 작동.
슬라이스 내부 코드는 원하는 방식대로 조직할 수 있습니다.
내부 구조는 자유롭지만, 슬라이스가 다른 슬라이스와 상호작용할 때 명확한 공개 API를 제공하는 것이 중요합니다.
Public API 규칙
위와 같이 레이어/슬라이스(또는 세그먼트)/index
파일을 생성하여, 외부에서 참조 가능한 파일만 명시합니다. 예를 들어, 위의 경우 user
슬라이스에 api
파일이 존재하지만, 외부에서 사용될 필요가 없기 때문에 index
파일에 포함되지 않은 모습입니다.
슬라이스 내부 참조 예제
참조 규칙 예제에서 설명했던 예제들을 다시 확인해봅니다.
entities/user
슬라이스 내부의 파일들이 서로 참조하는 경우에는 Public API 규칙이 적용되지 않습니다. 따라서, 위와 같이 슬라이스 내부에서 파일 간 참조가 이루어지는 것은 문제가 없습니다.
올바른 공개 API 준수 예제
상위 page/home
에서 하위 entities/user
의 Public API에 명시된 파일들만 참조하는 모습입니다. Public API를 참조하면 슬라이스 경로 뒤에 개별 파일을 직접 참조하지 않게 되는 것을 확인할 수 있습니다.
공개 API를 사용하지 않는 예제
반대로, Public API 규칙을 지키지 않고 참조하는 경우는 위와 같은 모습입니다. 개별 파일을 직접 참조하기 때문에 슬라이스 간의 결합도가 높아지고, 코드 변경 시 의존성이 커져 유지보수가 어려워질 수 있습니다. 이러한 방식은 슬라이스 간의 독립성을 저해하므로, 반드시 Public API를 통해 참조하는 것이 권장됩니다.
슬라이스 그룹의 개념
서로 밀접하게 관련된 슬라이스들은 하나의 폴더 안에 구조적으로 그룹화할 수 있습니다. 예를 들어, 동일한 도메인이나 기능과 관련된 슬라이스들을 함께 묶어서 관리할 수 있습니다.
격리 규칙 유지
슬라이스 그룹 내에 포함된 슬라이스들은 다른 슬라이스들과 동일한 격리 규칙을 따라야 합니다.
이점
슬라이스 그룹은 프로젝트 구조를 더 명확하고 체계적으로 관리할 수 있게 해주지만, 슬라이스 간 결합도를 낮추는 원칙을 유지해야 합니다.
즉, 그룹화는 구조적 편의를 위한 것이지, 코드 공유나 의존성을 허용하기 위한 것이 아닙니다.
예를 들어, pages/login
과 pages/register
두 슬라이스가 있다고 가정해봅시다. 이 두 슬라이스가 비슷한 목적을 가지거나 관련된 도메인이라고 판단되면, 이를 하나의 그룹으로 묶어 관리하고 싶을 수 있습니다. 아래와 같이 말이죠.
우리가 평소에 해왔던 방식과 크게 다르지 않습니다. 중요한 점은 위 이미지의 pages/auth
는 슬라이스가 아니라, 단순히 login
과 register
슬라이스를 그룹화하는 폴더일 뿐입니다. 따라서, auth
내부에 있는 슬라이스들도 참조 규칙에 따라 서로 참조할 수 없습니다.
만약 로그인 페이지와 회원가입 페이지 간에 코드 공유나 참조를 허용하고 싶다면, 다음과 같이 구조를 변경할 수 있습니다.
auth
라는 하나의 슬라이스에 로그인 페이지와 회원가입 페이지를 모두 포함하는 형식입니다. 이 경우, 동일한 슬라이스 내에서는 파일 간 자유로운 참조가 가능하기 때문에 문제가 되지 않습니다. 다만, 슬라이스를 나누는 것은 도메인 영역을 분리하기 위한 목적이므로, 관련 없는 파일이 같은 슬라이스에 포함되지 않도록 주의해야 합니다.
세그먼트는 Feature-Sliced Design의 조직 계층에서 세 번째이자 최종 단계로, 코드를 기술적 성격에 따라 그룹화하는 데 사용됩니다.
세그먼트에는 표준화된 이름이 존재하지만, 프로젝트의 필요에 따라 사용자 정의 세그먼트를 생성할 수도 있습니다.
components
, hooks
, types
)은 지양해야 함.
components
대신 ui
, types
대신 model
과 같은 구체적이고 목적에 맞는 이름 권장.Feature-Sliced Design(FSD)는 거창한 개념이 아닙니다. 결국 핵심은 패키지 간 의존성을 체계적으로 관리하는 것입니다. 객체지향 프로그래밍에서는 SOLID 원칙을 준수하거나 다양한 디자인 패턴을 적용하면서 코드 구조와 설계를 고민합니다. 하지만, 정작 프로젝트를 확장하거나 유지보수할 때 큰 영향을 미치는 패키지 간 의존성은 간과되는 경우가 많습니다.
FSD는 이러한 패키지 의존성을 관리하는 데 초점을 둔 방법론입니다. 코드가 모듈화되고 독립적으로 설계될 수 있도록 레이어, 슬라이스, 세그먼트 등의 개념을 도입하여 파일 간의 관계와 참조 흐름을 명확히 정의합니다.
이 방식을 통해 의존성이 얽히고설킨 복잡한 구조를 방지하고, 변경의 영향을 최소화하여 안정적이고 유연한 프로젝트 구조를 만들 수 있습니다. 결국 FSD는 복잡한 이론이 아니라, 현실적인 문제를 해결하기 위한 실용적인 접근법입니다. 프로젝트 규모와 상관없이, 의존성을 관리하려는 노력이 바로 FSD의 본질입니다.