사이드 프로젝트에서 아토믹 디자인 패턴의 단계를 축소(atoms, composites, layouts)하여 적용했습니다.
composities 부분에서는 atoms의 조합을 비즈니스 도메인으로 분리하여 관리했습니다.
그러나 시간이 지날수록 코드가 복잡해지고 비대해져서 폴더 구조를 다시 고려하게 되었습니다.
이 과정에서 FSD 아키텍처에 대한 글을 읽게 되어 흥미를 느꼈고, 해당 사이드 프로젝트에 FSD를 적용하기로 결정했습니다.

FSD(Feature-Sliced Design)

FSD는 프론트엔드 애플리케이션에 대한 아키텍처 방법론으로, Layers, Slices, Segments로 구분하여 관리합니다. (자세한 내용은 링크 참조)

1. Layers

A) app

  • 앱의 전체 설정, styles, providers 등을 관리합니다.
  • ex: Global Styles, Routing, Analytics initialization 등

B) processes

  • 여러 페이지에 걸친 프로세스를 관리합니다.
  • 현재는 사용되지 않습니다.
  • ex: 회원가입 절차가 여러 페이지로 구성될 때 사용

C) pages

  • 웹 사이트의 경우 전체 페이지, 모바일 앱의 경우 화면 또는 액티비티입니다.
  • widgets과 비슷하지만 규모가 더 큽니다.
  • ex: 로그인 페이지, 뉴스 피드, 사용자의 공개 프로필 등

D) widgets

  • 하위 레이어들을 조합하여 만든 구성요소입니다.
  • ex: 헤더, 포스트 카드 등

E) features

  • 사용자 상호작용과 비즈니스 로직을 포함한 레이어입니다.
  • ex: 댓글 좋아요 기능, 도서 검색 기능 등

F) entities

  • 특정 비즈니스 엔티티를 관리하는 레이어입니다.
  • ex: 도서, 사용자 등

G) shared

  • 재사용 가능한 기능들로 구성된 레이어입니다.
  • ex: UIKit(버튼, 모달), 유틸리티 함수 등

💡 모든 레이어를 사용할 필요는 없습니다.

👑 상위 레이어와 하위 레이어 간의 의존성 규칙

상위 레이어는 하위 레이어의 내용을 참조할 수 있지만, 반대의 경우는 불가능합니다.
(ex: features 레이어는 entities 레이어의 내용을 참조할 수 있지만, entities 레이어가 features 레이어를 참조하는 것은 허용되지 않습니다.)

2. Slices

Layers 내에서 비즈니스 도메인에 따라 코드를 그룹화합니다.
밀접하게 관련된 Slices는 디렉토리에 그룹화할 수 있지만 다른 Slices와 동일한 격리 규칙을 적용해야하며, 디렉터리에 코드를 공유해서는 안 됩니다.

💡 shared, app 레이어에는 Slices가 포함되어 있지 않습니다.

👑 Public API 규칙

index.ts 파일에는 외부에서 참조할 수 있는 public 모듈만을 작성하고, 내부적으로만 사용되는 private 모듈은 포함하지 않습니다.

따라서, 애플리케이션의 다른 부분에서는 index.ts 파일을 통해서만 public 모듈에 접근하여 사용할 수 있고, index.ts 파일에 정의되지 않은 private 모듈은 내부에서만 접근할 수 있습니다.

3. Segments

Slices 내에서 더 구체적인 기능이나 역할을 담당합니다.

팀에서 자체적으로 합의한 용어를 사용해도 무방하나, 저는 추후 커뮤니티에서의 소통을 원할하게 하기 위해
위의 이미지의 용어들을 최대한 그대로 사용했습니다! 🖐️

FSD 적용 후 폴더 구조

위의 내용과 FSD 적용 예시 사이트(링크) 참고하여 다음과 같이 폴더 구조를 변경했습니다.

📦 src
  - 📂 app
    - 📂 providers
    - 📂 routers
    - 📂 styles
    - 📜 App.tsx
  - 📂 pages
    - 📂 main
      - 📂 ui
        - 📜 Page.tsx
  - 📂 widgets
    - 📂 header
      - 📂 ui
        - 📜 Header.tsx
    - 📂 layout
      - 📂 ui
        - 📜 Layout.tsx
  - 📂 features
    - 📂 reset-password
      - 📂 lib
      - 📂 ui 
    - 📂 like-record
      - 📂 ui
    - 📂 change-reading-status
      - 📂 lib
      - 📂 ui
  - 📂 entities
    - 📂 book
      - 📂 api
      - 📂 model
      - 📂 ui
  - 📂 shared
    - 📂 api
    - 📂 assets
      - 📂 icon
      - 📂 image
    - 📂 constants
    - 📂 context
    - 📂 lib
      - 📂 config // queryClient, supabase 설정
      - 📂 hooks
      - 📜 number.ts // 유틸 함수
      - 📜 validation.ts
    - 📂 model
      - 📜 types.ts
    - 📂 ui
      - 📂 button
      - 📂 input

느낀점

기능 분할 설계에서 Slices의 사용을 통해 프로젝트 비즈니스 로직에 대한 코드가 구조적으로 작성됨에 따라 추후 기능 추가/수정 시 확장성과 유지보수성이 향상될 것 같습니다!

다만, Layers, Slices, Segments로 구성됨에 따라, 아키텍처가 표준화되어 있어
문서를 보면 이해는 가지만 실제로 프로젝트에 적용해보니 소규모 프로젝트임에도 불구하고
features, entities, widgets 레이어를 어떻게 구성해야될지, 그리고 도서 엔티티와 독서 기록 엔티티를 구분했지만 실제로는 특정 도서안에 독서 기록이 포함된 것으로 볼 수 있어 중첩된 엔티티 구조를 어떻게 관리해야 될지 결정하는 데 어려움을 겪었습니다 😇...

이러한 문제로 인해, 한 번에 적용하기에는 어려워 점진적으로 구조를 개선해 나가야 될 것 같습니다!😃

참고

profile
HIHIHI

1개의 댓글

comment-user-thumbnail
2025년 2월 12일

오 저도 지금 fsd를 적용하려고 고민하고 있는데, 참 이걸 어떻게 나눠서 어떻게 적용할지가 고민인데 비슷한 고민을 하고 계셨군요. 좋은 글 잘 읽었습니다. 감사합니다.

답글 달기
Powered by GraphCDN, the GraphQL CDN