저는 개발자라면 코드만 잘 작성하면 될 줄 알았는데요?
개발 경험을 쌓아갈수록 구조 설계 능력이 중요해지는걸 뼈저리게 느꼈습니다...

특히 프로젝트 폴더구조 설계 능력이 생각 이상으로 더 중요한데요!
개발 전 구조 정책을 잘 설정해두지 않으면, 후반부로 갈수록 더 고생길이 열립니다..
( 알고 싶지 않던...고생길 루트... )

거기다 Cursor, Copilot 같은 AI 코딩 도구를 쓰면서 느낀 건,
구조가 잡혀있지 않으면 AI한테 좋은 명령도 못 내린다는 거였어요.
설계 능력의 중요성이 두 배로 와닿았습니다...

사실 전 FSD를 실제 프로젝트에 도입해봤지만, 제대로 이해하지 못한 채로 프로젝트가 끝난 아쉬운 경험이 있습니다..
뇌가 딱 감을 잡기 직전에 흐름이 끊어져서, 날을 잡고 FSD를 다시 제대로 공부하다보니 비교 대상으로 프랙탈 구조도 알게 되었습니다!!
( 1+1? 나이스~ )

공부한 내용을 정리하지 않으면 머리에 남지 않을 것 같아 기록을 남깁니다!

시작하기 앞서..

갑작스러운 문체 변경은... 이해해 주세요..두뇌 풀가동하면서 쓰느라 그렇답니다..

Intro

처음 HTML, CSS, JavaScript로 프로젝트를 처음 시작할 때는 파일 구조를 크게 신경쓰지 않았었다.
그리고 React를 처음 시작했을 때도, public/, src/ 정도만 알고,
그 안에 components/, pages/, utils/ 폴더 몇 개 만들어 파일 네이밍 규칙을 지키며 코드 구현에만 열중하는 상황을 1년 넘게 보내왔다.

그런데 창업 프로젝트에 들어가게되며 프로젝트 규모가 점점 커졌고,
이런 상황이 자주 발생했다.

  • "이 컴포넌트, 어느 폴더에 넣어야 하지?"
  • "components/ 폴더에 파일이 너무 많은데?"
  • "이 유틸함수는 어디서 쓰지? 지금도 쓰는건가?"

파일 구조는 단순한 취향 문제가 아니라,
나와 팀(과 ai)이 코드를 읽고, 찾고, 유지하는 속도에 직접적인 영향을 미친다는 것을 느끼게 되었다.

이 글은 먼저 프랙탈 구조를 살펴본 뒤,
한계를 극복하기 위해 등장한 FSD(Feature-Sliced Design)로 흘러가보겠다.

1. 프랙탈 구조(Fractal Structure)

1-1. 프랙탈(Fractal)이란?

작은 구조가 전체 구조와 닮은 형태로 끝없이 되풀이되는 구조이다.

글로 풀어서 작성해본다면,
❶ 자신의 작은 부분자신과 닮은 모습이 나타나고
❷ 그 안의 작은 부분에도 자신과 닮은 모습무한히 반복되어 나타나는 구조이다.

이걸 프론트엔드 구조로 다시 작성해본다면,
❶ A폴더의 작은 부분인 하위 폴더 B폴더 안에 A폴더와 유사한 구조가 나타나고
❷ B폴더의 하위 폴더인 C폴더에도 동일한 구조가 반복되어 나타나는 형식을 말한다.

마지막으로 정의해보면,
폴더 구조에서 각 폴더가 동일한 내부 구조를 반복하는 구조이다.

예를 들어,
최상위 src/ 폴더에 components/, hooks/, utils/가 있다면,
feature 폴더 안에도 동일하게 components/, hooks/, utils/가 존재한다.

1-2. 프랙탈 구조의 핵심 규칙

1. 기능 단위로 폴더를 나눈다.

파일 타입(components, hooks)이 아닌, 기능(auth, dashboard)이 최상위 분류 기준이다.

참고
이미지 속 📁auth/, 📁dashboard/ 폴더를 보면 Lv.1에서 반복된 요소가 Lv.3에서 다시 반복되는 걸 확인할 수 있다.

이런 성질을 자기 유사성(Self-similarity)이라고 한다.

2. 각 기능 폴더는 독립적이다.

한 기능을 삭제할 때 해당 폴더만 지우면 된다.

3. 공통 코드는 최상위에 둔다

여러 기능에서 공유되는 코드는src/ 바로 아래에 위치한다.

1-3. 프랙탈 구조의 장점

1. 직관적이다.

기능 이름으로 폴더를 찾으면 되기 때문에 진입장벽이 낮다.
ex. 📁auth/, 📁dashboard/

2. 로컬 응집성이 높다.

관련 파일이 한 폴더에 모여 있어 맥락을 파악하기 쉽다.

여기서, 응집성이란 뭘까?

응집성(응집도/Cohesion)란?

" 연관된 코드가 얼마나 한 곳(폴더)에 모여 있는가 "를 나타냅니다.
응집도가 높을 수록 관련 코드를 찾기 쉽고, 수정할 때 영향 범위도 예측하기 쉽습니다.

첨부한 이미지 기반으로 설명하자면,
로그인 관련 components, hooks, utils📁auth/폴더 하나에 모여있는 걸 응집도가 높다고 표현합니다.
▶ 참고 링크

3. 독립성이 좋다.

기능 폴더를 통째로 복사하거나 삭제할 수 있다.

4. 별도의 학습이 필요 없다.

구조 자체가 설명적이다.

1-4. 프랙탈 구조의 단점

1. 기능 간 참조를 구조적으로 제한할 수 없다

📁auth/📁dashboard/를 참조해도 구조상 막을 방법이 없다.

2. 공통 코드의 경계가 모호하다.

"이 코드, 공통으로 올려야할지, 기능 폴더에 둬야 할지" 결정하기 어려워진다.

3. 규모가 커지면 혼란스러워 진다.

기능이 20개를 넘어가면 📁features/폴더 자체가 복잡해진다.

4. 팀마다 해석이 다르다.

명확한 표준이 없어 팀원마다 구조를 다르게 적용할 수 있다.
이를 보완하기 위해 팀 내 파일 구조 컨벤션이 필요하거나, 구조 자체가 규칙을 강제하는 방식을 도입하게 된다.

1-5. 프랙탈 구조의 문제 상황

프랙탈 구조는 소규모 프로젝트에서 잘 작동한다.
그런데 팀이 커지고 기능이 늘어나면 두 가지 문제가 반복적으로 등장한다.

1. 의존성 방향이 뒤섞인다.

A 기능이 B를 참조하고, B가 다시 A를 참조하는 순환 참조가 일어나게 된다.

2. 코드의 위치 결정이 주관적이다.

개발자마다 파일을 다른 위치에 넣는다..
( 파일 구조 컨벤션이 없다면, 일어나는 아찔한 상황.. )

이를 FSD의 레이어(Layer)개념으로 해결할 수 있다.

2. FSD 구조(Feature-Sliced Design)

레이어를 정의하고, 상위 레이어만 하위 레이어를 참조할 수 있게 강제한다.

2-1. 레이어 설명

FSD는 코드를 주로 6개의 레이어(Layers)로 나눈다.
위로 갈 수록 "더 구체적인 기능", 아래로 갈수록 "더 범용적인 코드"이다.

  • app : 앱 초기화, 라우팅 설정, 전역 Provider
  • pages : 라우트에 대응하는 페이지 컴포넌트
  • widgets : 여러 features를 조합한 독립적인 UI 블록
  • features : 사용자 시나리오(행동) 단위의 기능 (로그인, 장바구니 담기 등)
  • entities : 비즈니스 도메인 단위(User, Product, Order 등). 데이터 모델
  • shared : 재사용 가능한 UI 컴포넌트, 유틸, API 클라이언트

참고
사실 레이어는 7개이다.
app 다음에 processes가 있지만, 실제로 잘 사용되지는 않는다.

2-2. 레이어의 참조 규칙

각 레이어는 자신보다 아래 레이어만 참조할 수 있다.

app

  • 참조 가능 : pages, widgets, features, entities, shared
  • 참조 불가능 : X

pages

  • 참조 가능 : widgets, features, entities, shared
  • 참조 불가능 : app

widgets

  • 참조 가능 : features, entities, shared
  • 참조 불가능 : app, pages

features

  • 참조 가능 : entities, shared
  • 참조 불가능 : app, pages, widgets

entities

  • 참조 가능 : shared
  • 참조 불가능 : app, pages, widgets, features

shared

  • 참조 가능 : X
  • 참조 불가능 : app, pages, widgets, features, entities, shared

2-3. 레이어의 핵심 규칙

1. 단방향 의존성(Unidirectional Dependencies)

레이어 간 참조는 항상 위에서 아래 방향으로만 흐른다.
바로 2-2. 참조 규칙 기반으로만 가능하다.

2. Slice와 Segment

레이어 안에서는 2가지 단위가 있다.

  • Slice : 각 레이어 안에서 코드를 나누는 단위
  • Segment : slice 안에서 역할별로 나누는 단위


사진과 같이 단위에 맞게 자르면 된다.
추가적으로 설명을 더 남겨보자면 아래와 같다.

📁features : 레이어
├📁auth : 기능 단위 슬라이스 (Slice)
│   ├ 📁ui : UI 컴포넌트 시그먼트 (Segment)
│   ├ 📁model : 상태, 비즈니스 로직 시그먼트 (Segment)
│   └ 📁api : API 호출 시그먼트 (Segment)

슬라이스(Slice)은 프로젝트별 네이밍 컨벤션이 필요하다.
Slice 네이밍은 도메인(명사)기준이 표준이므로, 프로젝트 컨벤션에 따라 자유롭게 정하되,
시그먼트 이름은 FSD 표준 명칭(ui, model, api, lib, config)을 따르는 것을 권장한다.

FSD 사용하는 실제 프로젝트 구조
기능 : post 생성 / post 삭제

📁 features/
├── 📁 post-create/ : Post 생성
│ ├── 📁 ui/ : 생성에 필요한 UI 컴포넌트
│ ├── 📁 model/ : Post 생성 관련 상태 관리, 비즈니스 로직
│ └── 📁 api/ : Post 생성 요청 (POST)
└── 📁 post-delete/ : Post 삭제
│ ├── 📁 ui/ : 삭제에 필요한 UI 컴포넌트
│ ├── 📁 model/ : Post 삭제 관련 상태 관리, 비즈니스 로직
│ └── 📁 api/ : Post 삭제 요청 (DELETE)
📁 entities/
└── 📁 post/
│ ├── 📁 ui/ : PostCard, PostPreview 등 순수 UI
│ ├── 📁 model/ : Post 타입 정의
│ └── 📁 api/ : Post 데이터 조회 (GET)

3. Public API(index.ts)

각 slice는 index.ts를 통해 외부에 노출할 코드를 명시적으로 선언한다.
외부에서는 slice 내부 파일을 직접 참조하지 않고, 반드시 index.ts를 통해 접근한다.

2-4. FSD 구조의 장점

  • 의존성이 명확하다. 레이어 규칙 덕분에 순환 참조가 구조적으로 불가능하다.
  • 코드 위치 결정이 객관적이다. " 이 코드는 어느 레이어인가? " 위치가 결정된다.
  • 대규모 팀에서 강하다. 여러 팀이 서로 다른 레이어를 맡아 병렬로 작업할 수 있다.
  • eslint 플러그인으로 자동 강제할 수 있다. eslint-plugin-fsd

2-5. FSD 구조의 단점

  • 학습 곡선이 있다. 6개 레이어와 각 규칙을 이해하는 데 시간이 필요하다.
    ( 지금의 나에요.. )
  • 소규모 프로젝트엔 과하다. 기능이 5개 미만이면 구조가 오히려 복잡하게 느껴진다.
  • 초기 설정 비용이 있다. alias 설정, eslint 규칙 등 사전 설정이 필요하다.
  • widgets 레이어가 모호하게 느껴질 수 있다. pages와 features의 중간 개념이라 처음엔 구분이 어렵다.

3. 프랙탈 → FSD, 왜 발전했는가??

두 구조의 철학을 (ai가) 비교한 표를 먼저 봐보자.

각각의 성격은 알겠다.
이제 어떤 상황에서 어떤 구조를 선택해야 할까?

1. 프랙탈 구조가 적합한 경우

  • 혼자 개발하거나, 팀이 2~3명인 경우
  • MVP나 사이드 프로젝트처럼 빠른 초기 개발이 중요한 경우
  • 기능이 10개 이하로 유지될 것으로 예상되는 경우

2. FSD가 적합한 경우

  • 팀이 5명 이상이거나 앞으로 커질 예정인 경우
  • 장기적으로 유지보수할 서비스인 경우
  • 도메인이 복잡하고 기능 간 의존성 관리가 중요한 경우

프랙탈이 FSD로 발전했다에서 간혹 프랙탈 구조가 틀렸다고 생각할 수 있지만,
프랙탈 구조가 틀린건 아니다!!

프랙탈은 "파일을 어디에 둘 것인가"라는 목적에 집중했고,
FSD는 한 발 더 나아가 "코드가 서로 어떻게 참조해야 하는가"라는 목적에도 집중했다.


4. 마치며..

좋은 파일 구조란 "현재 팀과 프로젝트 규모에 맞는 구조"라 생각한다.

소규모로 시작할 때는 프랙탈로 빠르게 시작하고,
규모가 커지는 시점에 FSD 마이그레이션을 검토하는 것이 좋을 것 같다는 판단이다.
( 하지만 전 소규모 플젝도 공부를 위해 FSD를 선택했어요..! 프론트 혼자일때의 장점이랄까요 후후.. )

그리고 AI(Cursor, Claude Code, Codex 등)를 사용하여 코드를 작성해본 결과,
FSD가 AI에게도 좋은 선택이라 판단이 든다.

AI는 코드를 생성하는 속도는 빠르지만, 구조를 제대로 판단하지는 않는 것으로 보인다.
이전 FSD를 사용한 프로젝트에서 명확한 FSD 구조 설계 없이 진행하였더니, 점점 파일 구조가 붕괴되는 경험을 했었다.

요구사항에 대해 .md를 제대로 설정하지 않고, 너무 모호한 명령을 내려서 그럴수도 있지만, AI는 코드 생성 속도를 빠르게 높이는 것에 중점을 두고, 구조의 붕괴는 따로 요청 혹은 설정이 없다면 신경쓰지 않는다는 걸 알게되었다.

그래서 이번에는 FSD를 사람도, AI도 더 명확하게 이해할 수 있는 "좌표계"로 사용해보고자 한다.
AI기능 구현과 보일러플레이트를,
사람설계와 리스크 검토를 담당하는 방식으로 진행해보고자 한다.
( 제발 구조 붕괴 없이 잘 마무리되길...!!! )

결론은,
AI는 "무엇을 만들지" 를 도와주지만,
"어디에 어떻게 놓을지" 는 여전히 사람과 구조가 결정해야 한다고 생각한다.

AI는 "지금 잘 동작하는 코드" 를 만들고, FSD는 "나중에도 읽히는 구조" 를 만든다.

참고
▶ 🔗 FSD 공식 문서
▶ 🔗 토스 Frontend Fundamentals 공식 문서
▶ 프랙탈 구조란?

profile
바라는 색이 있다면 눈이 멀도록 바라볼 것. 가능한 온몸으로 부서질 것.

0개의 댓글