FSD(Feature-Sliced Design) Architecture

Seoyong Lee·2024년 4월 9일
3

개발 공부

목록 보기
20/21

FSD(Feature-Sliced Design)에 대한 리서치 문서입니다.
Feature-Sliced Design: The Best Frontend Architecture
Feature-Sliced Design

FSD의 3가지 컨셉

FSD는 Layers, Slices, Segments 세 가지 파트로 나누어집니다.

Layers

Layers는 top-level 디렉토리이며 서비스 분해의 첫 번째 단계에 속합니다.
Layers는 엄격하게 규격화된 구조로 되어있지만 이 중에서 몇 가지는 선택적으로 사용할 수 있습니다.

└── src/
    ├── app/
    ├── processes/ (deprecated)
    ├── pages/
    ├── widgets/
    ├── features/
    ├── entities/
    └── shared/
  • app:
    • 어플리케이션 로직이 초기화 되는 entry point 입니다.
    • 포함되는 것들의 예시
      • Providers
      • 라우트
      • 글로벌 스타일 및 타입 선언 등…
  • processes(optional layer):
    • 이 계층은 다단계 등록과 같은 여러 페이지에 걸쳐 있는 프로세스를 처리합니다.
  • pages:
    • 페이지들을 포함합니다.
    • 포함되는 것들의 예시
      • /404 페이지 컴포넌트
      • /home 페이지 컴포넌트 등 …
  • widgets:
    • 페이지에서 사용되는 standalone UI 컴포넌트 들입니다.
    • 포함되는 것들의 예시
      • header
      • navigation
      • layouts
  • features(optional layer):
    • 비즈니스적 가치를 가지는 기능단위입니다.
    • 포함되는 것들의 예시
      • Like
      • Review
      • ProductRatings
      • player
  • entities(optional layer):
    • 비즈니스 주체를 나타냅니다.
    • 포함되는 것들의 예시
      • users
      • reviews
      • friend
      • comments
      • feed
      • auth
  • shared:
    • 특정한 비즈니스 로직에 속하지 않는 컴포넌트나 유틸을 포함합니다.
    • 포함되는 것들의 예시
      • UI kit
      • axios 관련 설정
      • utils
      • helpers

여기서 중요한 점은 FSD는 위계적 구조(hierarchical structure)를 따른다는 점입니다.

Layer 원칙 1: 자신보다 아래 단계의 개체에만 접근할 수 있다
Layer 원칙 2: 위계가 낮은 컴포넌트일수록 영향을 받는 곳이 많기 때문에 변경은 위험하다

참고 - Layer 구분을 위한 비즈니스 로직

FSD에서 widgets, features, entities등의 레이어 구분은 비즈니스 로직의 포함 정도로 판단합니다. 그렇다면 비즈니스 로직이란 무엇일까요?

In computer software, business logic or domain logic is the part of the program that encodes the real-world business rules that determine how data can be created, stored, and changed.컴퓨터 소프트웨어에서 비즈니스 로직 또는 도메인 로직은 데이터 생성, 저장 및 변경 방법을 결정하는 실제 비즈니스 규칙을 인코딩하는 프로그램의 일부입니다.

Wikipedia - Business logic

소프트웨어 공학에서 말하는 비즈니스는 일반적인 맥락과는 다르게 ‘소프트웨어가 풀고자 하는 현실의 문제’를 뜻합니다. 비즈니스 로직은 도메인 로직이라고 부르기도 합니다. 만약 우리가 만드는 서비스가 비디오 스트리밍 도메인이라면 비디오 재생 및 공유, 결제 등이 바로 소프트웨어가 풀어야 하는 현실 문제가 됩니다. 따라서 FSD로 코드를 작성할 때 ‘이 코드가 실제로 비즈니스적 의사결정을 하고 있는지’ 정도에 따라 해당되는 Layer 폴더에 작성되어야 합니다.

만약 어떤 코드를 명확하게 비즈니스 로직인지 판단할 수 없다면 이는 해당 코드를 더 작개 쪼개야 한다는 신호입니다.

다음은 비디오 스트리밍 서비스에 대한 FSD 레이어 분리 예시입니다.

  • /app → entry point
  • /pages → 각 페이지입니다
    • /home
    • /video-player
    • /contents-detail
    • /user
  • /widgets → 혼자 독립적인 단위로 존재할 수 있는 컴포넌트 묶음입니다
    • /contents-list
    • /video-player
  • /features → 비즈니스 밸류를 가지는 사용자 시나리오나 기능을 다룹니다
    • /login
    • /player-controller
    • /player-captions
    • /banner-swiper
  • /entities → 비즈니스 주체입니다
    • /user
    • /video
    • /like
    • /contents
    • /banner
  • /shared → 특정 비즈니스 로직에 종속되지 않는 재사용 컴포넌트입니다
    • /api
    • /ui
    • /type

위 사례와 같이 FSD를 실제 적용해보면 widgets과 features, entities의 구분이 모호해지는 경우가 발생할 수 있습니다. 이를 보완하기 위해 다음의 가이드를 제안합니다.

  • widgets → pages 컴포넌트에서 조합하여 사용하기 위한 거의 완성된 독립 기능들
  • features → widgets를 구성하기 위한 비즈니스 로직의 구체적인 표현 기능들 (결제, 재생, 좋아요, 환불 등)
  • entities → features에서 구체적인 동작이 부여되기 전인 비즈니스 주체들 (유저, 비디오, 라이크버튼 등)
  • shared → 특정 비즈니스 로직에 속하지 않는 재사용 대상들 (AxiosInstance, types, ButtonBase, layout…)

Slices

각각의 Layer 마다 Slices라는 서브 디렉토리를 가집니다. 이는 두 번째 분해 레벨로 코드를 그것들의 가치로 묶는 것(group code by its value)을 목적으로 합니다.

└── src/
    ├── app/
    │   ├── providers/ 
    │   ├── styles/
    │   └── index.tsx/
    ├── pages/
    │   ├── home/
    │   ├── profile/
    │   └── about/
    ├── widgets/
    │   ├── newsfeed/
    │   ├── header/
    │   └── footer/
    ├── features/
    │   ├── user/
    │   ├── auth/
    │   └── favorites/
    ├── entities/
    │   ├── user/
    │   └── sessions/
    └── shared/

Segments

각각의 Slice는 다시 Segment로 구성됩니다. Segment는 목적 기반으로 Slice의 코드를 분할(divide the code within a slice based on its purpose)하도록 돕습니다.

  • api - 서버 요청
  • UI - Slice의 UI 컴포넌트
  • model - 비즈니스 로직, 상태 관련 인터랙션 (actions and selectors)
  • lib - Slice 안에서 사용되는 보조 함수
  • config - Slice에 대한 설정 (그러나 흔하게 발생하지는 않음)
  • consts - 필요한 상수

Public API

Public API는 index.ts와 같은 entry point 파일을 두어 필요한 기능만 Slice나 Segment에서 불러올 수 있도록 설정하는 것입니다. Public API는 다음의 원칙을 따릅니다.

Public API 원칙 1: 앱의 Slice와 Segment들은 Public API index 파일에 정의된 기능과 컴포넌트만 사용한다
Public API 원칙 2: Public API에 정의되지 않은 내부적인 부분은 격리된 것으로 간주하여 그 자신의 Slice나 Segment만 여기에 접근할 수 있다

아키텍처 심화

추상화와 비즈니스 로직

  • 위계가 높아질수록 특정 비즈니스 노드와 강하게 결합되며 더 많은 비즈니스 로직을 담게됩니다.
  • 위계가 낮아질수록 더욱 추상화 되며, 더욱 재사용 가능하게 되고 자율성은 줄어듭니다.

FSD가 해결할 수 있는 문제

  • Loose coupling: 느슨한 결합
  • High cohesion: 높은 응집력

Layer를 통해 추상화(Abstraction)와 다형성(Polymorphism)을 확보!

  • 낮은 단계의 레이어는 추상적이며 높은 레벨에서 재사용 가능
  • 특정 props에 따라 레이어는 다양한 동작 가능

Public API를 통해 캡슐화(Encapsulation) 확보!

  • 불필요하게 노출할 필요가 없는 부분은 격리

높은 Layer의 낮은 Layer 재사용을 이용한 상속(Inheritance) 구현!

기존 아키텍처와의 비교

  • 기존 아키텍처는 컴포넌트나 모듈 사이의 연결에 대한 명시적 연결이 부족하며 이는 규모가 커질수록 심각해진다.
  • FSD는 이러한 기존 구조의 문제점을 보완하여 더욱 명확한 정리를 돕는다.
  • FSD를 적용하려면 문제를 ‘나중’이 아닌 ‘지금’ 다룰 수 있어야 한다.

FSD 적용의 장점

  • 아키텍처 구성 요소를 쉽게 교체, 추가 또는 제거할 수 있다
  • 아키텍처의 표준화 가능
  • 확장성
  • 개발 스택과 무관한 방법론
  • 예상치 못한 부작용 없이 모듈 간 제어 및 명시적인 연결
  • 비즈니스 중심의 아키텍처 방법론

FSD 적용의 단점

  • 다른 많은 아키텍처 솔루션에 비해 진입 장벽이 높다
  • 팀 인식, 문화 및 개념 준수가 필요
  • 문제를 즉시 해결하지 못하고 나중에 해결하려 한다면 적합하지 않다

참고

https://feature-sliced.design/
https://velog.io/@eddy_song/domain-logic

2개의 댓글

comment-user-thumbnail
2024년 5월 3일

글 잘 봤습니다 내용중에 Public API 궁금한것이 있습니다. index.ts 로 설정하면 Slice나 Segment 가 아닌 외부에서 import 하면 오류가 발생하는부분인가요?

1개의 답글