[하루 한 시간] FSD 개요 정리

이종호·2025년 9월 27일

하루 한 시간

목록 보기
2/13

프론트엔드 어플리케이션의 구조를 위한 아키텍처 방법론
코드를 어떻게 분리하고 구성할지 명확히 정의
변화하는 비즈니스 요구 속에서도 프로젝트 이해하기 쉽고 안정적으로 유지

실무를 위한 도구 지원

보통 보니까

  • app
  • pages
  • widgets
  • features
  • entities
  • shared

이 위계가 실제 중요하다.
아래에 나오겠지만, 위에서 아래를 참조할 수 있지만,
아래에서 위나 동급의 위치는 참조할 수 없다.

즉 pages에서 widgets나 features는 맘대로 import할 수 있지만
features에서 widgets나 다른 features를 import해선 안된다.

widgets, features, entities 차이가 헷갈려 클로드에게 물어봤다.

Entities

  • ex) User, Product, Order, Comment
  • UI나 비즈니스 로직 없이 순수한 데이터 모델과 기본 연산만 포함
// entities/user
- model/types.ts (User 타입 정의)
- api/userApi.ts (유저 데이터 fetch)
- ui/UserAvatar.tsx(유저 아바타 컴포넌트)

Features

  • ex) addToCart, likePost, loginUser, filterProducts
  • 사용자가 할 수 있는 행동/기능
  • 비스지스 로직이 포함된 실제 기능 구현
  • entities를 사용해서 특정 동작을 수행
// features/auth-user/
- model/authStore.ts (로그인 상태 관리)
- api/authApi.ts (로그인/로그아웃 API)
- ui/LoginForm.tsx(로그인 폼)

핵심 차이

  • Entities: "무엇"
  • Features: "어떻게"
    Entities는 여러 Features 에서 사용되지만, Features는 특정 기능에만 집중함

Widgets

  • ex) Header, Sidebar, PostList, UserProfile, CommentSection
  • 여러 features와 entities를 조합한 독립적인 UI 블록
  • 페이지에 바로 삽입할 수 있는 완성된 컴포넌트

여기서 내가 fsd examples에서 다른 프로젝트 몇개를 살펴봤는데, 프로젝트 규모가 크지 않아서 그런지 대부분 widgets는 보이지 않았다.

여기까지 본 소감은 뭔가 컴포넌트 단위는 어쩔 수 없는건지 아토믹 패턴과 비슷했고
다만, 너무 세세하게 나눠쓸모없었던 아토믹처럼

꽤나 단순하기에 features로 할지, widgets로 할지 고민이 될것 같다는 생각이 들고
entities는 무조건 먼저 하고, features와 widgets가 entities를 이용하게 끔 짜야 할것 같다는 생각이 든다.
아무리 간단한 컴포넌트 이더라도, 아마 pages안에 entities만 덩그라니 있는 경우는 없어야 할것 같은데.. 실제 프로젝트를 보면서 정리할 수 있을것 같다.


여기서 어떤 위치의 코드를 가져올 수 있는지 없는지 아는게 중요한데 클로드를 통해 알아봤다.

FSD 의존성 규칙 (위에서 아래로만 가능)

Entities

✅ 가져올 수 있음:

shared/*

❌ 가져올 수 없음:

다른 entities/
features/

widgets/
pages/

Features

✅ 가져올 수 있음:

shared/
entities/

❌ 가져올 수 없음:

다른 features/ (중요!)
widgets/

pages/*

Widgets

✅ 가져올 수 있음:

shared/
entities/

features/*

❌ 가져올 수 없음:

다른 widgets/
pages/

Pages

✅ 가져올 수 있음:

shared/
entities/

features/
widgets/

❌ 가져올 수 없음:

다른 pages/*

핵심 원칙

상위 레이어는 하위 레이어만 import 가능
같은 레이어끼리는 import 금지 (feature ↔ feature ❌)
하위에서 상위로 import 금지 (entities → features ❌)

이렇게 하면 순환 의존성이 없고 코드가 단방향으로 흐릅니다.

이렇다고 하는데 공시 예제 프로젝트만 봐도 해당 규칙이 어긋나는 부분들이 발견된다.

더 지켜봐야겠지만 다른 사람들도 종종 어떨때 규칙을 지키기 어렵다고 토로하는 글을 본적 있는만큼 회사 프로젝트에 적용하기전에 고민이 많이 되는 부분은 어쩔 수 없다.

그 뒤로 저런 Layer 계층이 다음에 도메인을 나타내는 Slices 다음에 특정 역할에 맞는 segments로 나뉘게 된다.
app과 shared는 도메인을 가지지 않기에 Slice가 없고
pages, widgets, features, entities는 slices, segments를 가진다.

Layer

app, shared(Layer)는 도메인(Slices)가 없이 Segements들로만 이루어짐

  • navigation과 providers가 어떻게 보면 도메인 역할을 하는거 같은데 다들 그러려니하는거 같다..?

entitiues, features, widgets, pages(Layers)는 도메인(Slice) 뒤에 Segements들이 나옴

점진적 도입 방법

  1. app, shared 먼저 정리
  2. 기존 UI를 widgets, pages로 대략 분배, 이 과정에서 FSD 규칙을 위반해도 OK!
  3. Import 위반을 하나씩 해결하면서, entities, feawtuers를 추출함

    리팩토링 중에는 새로운 대규모 Entities 추가를 피하는게 좋다고함

profile
코딩은 해봐야 아는 것

0개의 댓글