MEI

FSD 아키텍처를 프로젝트에 적용시켜보기 본문

TECH

FSD 아키텍처를 프로젝트에 적용시켜보기

mei.zy 2025. 1. 31. 12:32

FSD 아키텍처를 프로젝트에 접목 시켜보기입니다.

 

FSD가 뭐야.. 너무 생소해 😱 라고 할 수 있는데 저도 마찬가지였습니당..

 

프로젝트를 진행하면서 현재 폴더 구조가 그렇게 나쁘다고도 생각 못하고 있었구요..! (components / hooks / utils 등으로 쪼개는 프로젝트 구조였음) 근데 개발하면서 그런 고민은 하게 됩니당.. 혹시 폴더 구조가 depth 가 너무 깊어지진 않는지, 명확하게 폴더를 분리하고 있는지..

 

그런 것들을 해결하기 위해서 FSD 라는 아키텍처를 토이 프로젝트에 적용해보고자 했습니당..😚

역시 이것저것 테스트해보는건 토이프로젝트만한게 없는 것 같음! (이미 진행중인 프로젝트였어서 마이그레이션 지옥...)

 

FSD 란 ?

Feature-sliced Design 의 요약이라는데, 그냥 코드에 대한 규칙을 모아놓은 아키텍처 방법론이라고만 이해했다.

FSD 에서는 Layer, Slice, Segment 같은 3계층 구조를 가지고 있다. 이게 어떤 의미냐면, 폴더 depth 가 최대 3개로 제한한다는 의미이다.

 

1. Layer 계층

기존에 components, utils, hooks 로 쪼개져있는 것들을 대신하는 계층이라고 생각하면 된다. 

폴더 구조 명칭이 굉장히 어색하게 느껴질 수 있는데 익숙해진다.. 🙂 그리고 사용하다보면 보다 더 명확하게 쪼개고 있다는 느낌을 받을 수 있다.

 

- app : Provider, Router, 전역 스타일 등...

- processes : 더이상 사용되지 않는다고 해서 스킵

- pages : 페이지 별 화면

- widgets : 독립적으로 동작하는 컴포넌트 혹은 UI, 하나의 완전한 기능

- features : 컴포넌트의 동작들이 담김

- entities : 프로젝트가 다루는 비즈니스적인 엔티티들,

- shared : 공통적으로 사용하는 것들 (기존 utils , constants 가 shared의 slice가 될 수 있을 것 같다.)

 

그리고 가장 중요한 것은 레이어는 아래에 있는 레이어는 모두 import 할 수 있지만, 자신보다 상위에 있는 레이어는 import 할 수 없다는 것이다. (어차피 뒤에서 lint 설정을 할 것이라 너무 걱정하지 않아도 된다 !)

 

 

이렇게만 설명하면 진짜 어렵게만 느껴진다..😓

그래서 컴포넌트들은 어떻게 쪼개라는거지? 라는 생각이 든다.

그래서 FSD 공식문서에서 튜토리얼을 제공해준다. (근데 상세하게 widgets/features/entities 는 설명해주지 않음)

그래서 layer 분리 예제는 아래에서 첨부해보았당.. 

 

튜토리얼 | Feature-Sliced Design

Part 1. 설계

feature-sliced.design

 

2. Slice

도메인 별로 코드가 분할되는 부분이다.

 

* slice 는 내부에서 다른 slice 를 참고 할 수 없다. (이미지를 바라보면, user slice 는 post slice 를 참고할 수 없다.)

 

3. Segment

이름이 제한된 것은 아닌데 관례적으로 제공하는 이름이 있다. 공식 문서에서 훔쳐옴

 

  • ui - UI와 관련된 모든 것: UI 컴포넌트, 날짜 포맷터, 스타일 등.
  • api - 백엔드 상호작용: request 함수, 데이터 타입, mapper 등.
  • model - 데이터 모델: 스키마, 인터페이스, 스토어, 비즈니스 로직.
  • lib - 슬라이스 안에 있는 다른 모듈이 필요로 하는 라이브러리 코드.
  • config - 설정 파일과 기능 플래그.

** Layer : widgets / feature / entitites 구분 예시

💡 pages는 정말 페이지 렌더링용이어서 컴포넌트들 조합 외 아무런 로직을 넣지 않을 예정이다.

💡  일단 비즈니스 로직이 아예 없는 UI 는  📁 shared > ui 로 분리할 예정이다 ! (Button, Input 등 pure 한 component 들)

 

다음과 같은 form 이 존재하고, 

" Form 입력 후 > 유효성 검사 (required 필드들이 잘 입력되었는지) > publish Aritcle 버튼 클릭해서 Post API 요청"

하는 기능이 있다고 설계한다.

 

 

 

✅ entitites : 도메인과 관련된 애들만 들어감

- api 요청 관련 types / 요청하는 로직 / 유효성 schema

📁 entities // layer
   ㄴ 📁 create //slice
      ㄴ 📁 api // segment - api 요청 관련 + type 정의
      ㄴ 📁 model // segment - 스키마 담김

 

✅ features : 진짜 '동작'

- 폼을 입력하는 동작을 담는다. feature는 따로 segment 로 나누진 않았다.. 여러 개의 동작이 나눠진다면 ui 라는 segment 로 나눠도 괜찮을 것 같당 

📁 features // layer
   ㄴ 📁 create //slice

 

✅ widgets : 컴포넌트 묶음

📁 widgets // layer
   ㄴ 📁 create //slice

 

그래서 page 는 정말 widgets 를 끌어오는 수준에서만 사용할 수도 있다. 혹은 widgets 의 조합이던가.. 

 

 

FSD 로 마이그레이션

이론은 간단하게 생각하고.. 가장 빠른 방법은 역시 적용해보는 것이다. FSD 아키텍처의 장점은 공식문서가 아주 잘되어 있고..lint도 제공해준다.. 👍 도입하기 전에, Next.js 를 사용하고 있다면 다음 챕터의 글은 읽어보는 것이 좋을 것 같다.. Next.js 에서는 여전히 page router 방식과 app router 방식 모두 제공하고 있기 때문이다. 

 

< 린트 설정 > 

lint 는 아래 레포에서 설정하는 법이 정해져있다.

 

steiger 이라는 것을 설치하게끔 하는데 eslint 랑은 또 별개로? 동작하는 것 같다. 

eslint 에서 영감을 받아서 fsd 측에서 만들었다고 적혀있다..

예전 버전에서는 eslint 에 rule 을 추가해주는 쪽으로 안내했던 것 같은데 😓 lint 관련 파일을 하나 더 만들어야 하기 때문에 반갑진 않다. (그리고 example 로 추가해준 예시들 중에서 steiger를 쓰는 곳이 없었음....)

 

+ 추가 ) steiger를 Lint 개념이라고만 생각했었는데 generator 도 해준다고 한다.
 

GitHub - feature-sliced/steiger: Universal file structure and project architecture linter

Universal file structure and project architecture linter - feature-sliced/steiger

github.com

 

 

위와 같은 사유 + beta 버전이라고 적혀 있었기 때문에 다른 방법으로 lint 를 추가해주려고 했는데 ..

 

FSD-Pure-Next.js-Template/.eslintrc.json at master · yunglocokid/FSD-Pure-Next.js-Template

🛠️ Pure template for development on Next.js in the Feature-Sliсed Design architecture - yunglocokid/FSD-Pure-Next.js-Template

github.com

레포 코드 뜯어보니까 boudaries eslint plugin 을 이용해서 하나하나 import 구문을 막아줬다..😱

그래서 그냥 steiger 를 쓰기로 했다.. 

 

pnpm add --save-dev steiger @feature-sliced/steiger-plugin

 

steiger 세팅은 그냥 recommended 만 두었다.

더 필요한 것들이 있으면 차근차근 설정하려고 한다. 일단 우선적으로 필요했던건 계층 별로 import 막는거였는데 이정도는 가능한 것 같아서 추천만 사용하기 !

// .steiger.config.js

import fsd from "@feature-sliced/steiger-plugin";
import { defineConfig } from "steiger";

export default defineConfig([...fsd.configs.recommended]);

 

 

 

FSD 공식 홈페이지에서 제공해주는 예제 레포를 많이 참고 했다.. 아래에 있는 레포 구조를 많이 참고했는데, 이유는 그냥 Next.js 버전이 14버전으로 가장 최신 버전이어서 참고하기 괜찮아서였다..😀

 

GitHub - falkomerr/falkchat

Contribute to falkomerr/falkchat development by creating an account on GitHub.

github.com

 

 

사용 후기는 프로젝트를 진행해보면서 확인해야할 것 같다.

실제 장점들은 머리론 알지만 (폴더 구분 구조가 명확해짐..등) 아직 와닿진 않는다. 그 이유는 토이프로젝트를 같이 하는 친구도 FSD 아키텍처를 인지하는데까지 시간이 걸리기 때문이당..😓 아직 마이그레이션만 한거여서 명확한건 사실 이전이다 ('components' 라는 폴더 이름이 얼마나 직관적인가......!!!!!) 사용해보고 또 후기 남길 수 있었음 좋겠네요..

 

reference

 

(번역) 기능 분할 설계 - 최고의 프런트엔드 아키텍처

기능 분할 설계(Feature-Sliced Design, FSD) 아키텍처의 개념과 이 아키텍처 방법론이 해결하는 문제를 이야기하고, FSD를 기존 아키텍처 및 모듈식 아키텍처와 비교한 뒤 장단점에 대해 소개합니다.

emewjin.github.io