
저는 개발자라면 코드만 잘 작성하면 될 줄 알았는데요?
개발 경험을 쌓아갈수록 구조 설계 능력이 중요해지는걸 뼈저리게 느꼈습니다...
특히 프로젝트 폴더구조 설계 능력이 생각 이상으로 더 중요한데요!
개발 전 구조 정책을 잘 설정해두지 않으면, 후반부로 갈수록 더 고생길이 열립니다..
( 알고 싶지 않던...고생길 루트... )
거기다 Cursor, Copilot 같은 AI 코딩 도구를 쓰면서 느낀 건,
구조가 잡혀있지 않으면 AI한테 좋은 명령도 못 내린다는 거였어요.
설계 능력의 중요성이 두 배로 와닿았습니다...
사실 전 FSD를 실제 프로젝트에 도입해봤지만, 제대로 이해하지 못한 채로 프로젝트가 끝난 아쉬운 경험이 있습니다..
뇌가 딱 감을 잡기 직전에 흐름이 끊어져서, 날을 잡고 FSD를 다시 제대로 공부하다보니 비교 대상으로 프랙탈 구조도 알게 되었습니다!!
( 1+1? 나이스~ )
공부한 내용을 정리하지 않으면 머리에 남지 않을 것 같아 기록을 남깁니다!
시작하기 앞서..
갑작스러운 문체 변경은... 이해해 주세요..두뇌 풀가동하면서 쓰느라 그렇답니다..
처음 HTML, CSS, JavaScript로 프로젝트를 처음 시작할 때는 파일 구조를 크게 신경쓰지 않았었다.
그리고 React를 처음 시작했을 때도, public/, src/ 정도만 알고,
그 안에 components/, pages/, utils/ 폴더 몇 개 만들어 파일 네이밍 규칙을 지키며 코드 구현에만 열중하는 상황을 1년 넘게 보내왔다.
그런데 창업 프로젝트에 들어가게되며 프로젝트 규모가 점점 커졌고,
이런 상황이 자주 발생했다.
components/ 폴더에 파일이 너무 많은데?"파일 구조는 단순한 취향 문제가 아니라,
나와 팀(과 ai)이 코드를 읽고, 찾고, 유지하는 속도에 직접적인 영향을 미친다는 것을 느끼게 되었다.
이 글은 먼저 프랙탈 구조를 살펴본 뒤,
한계를 극복하기 위해 등장한 FSD(Feature-Sliced Design)로 흘러가보겠다.
작은 구조가 전체 구조와 닮은 형태로 끝없이 되풀이되는 구조이다.
글로 풀어서 작성해본다면,
❶ 자신의 작은 부분에 자신과 닮은 모습이 나타나고
❷ 그 안의 작은 부분에도 자신과 닮은 모습이 무한히 반복되어 나타나는 구조이다.
이걸 프론트엔드 구조로 다시 작성해본다면,
❶ A폴더의 작은 부분인 하위 폴더 B폴더 안에 A폴더와 유사한 구조가 나타나고
❷ B폴더의 하위 폴더인 C폴더에도 동일한 구조가 반복되어 나타나는 형식을 말한다.
마지막으로 정의해보면,
폴더 구조에서 각 폴더가 동일한 내부 구조를 반복하는 구조이다.
예를 들어,
최상위 src/ 폴더에 components/, hooks/, utils/가 있다면,
feature 폴더 안에도 동일하게 components/, hooks/, utils/가 존재한다.

파일 타입(
components,hooks)이 아닌, 기능(auth,dashboard)이 최상위 분류 기준이다.
참고
이미지 속📁auth/,📁dashboard/폴더를 보면 Lv.1에서 반복된 요소가 Lv.3에서 다시 반복되는 걸 확인할 수 있다.
이런 성질을 자기 유사성(Self-similarity)이라고 한다.
한 기능을 삭제할 때 해당 폴더만 지우면 된다.
여러 기능에서 공유되는 코드는
src/바로 아래에 위치한다.
기능 이름으로 폴더를 찾으면 되기 때문에 진입장벽이 낮다.
ex. 📁auth/, 📁dashboard/
관련 파일이 한 폴더에 모여 있어 맥락을 파악하기 쉽다.
여기서, 응집성이란 뭘까?
응집성(응집도/Cohesion)란?
" 연관된 코드가 얼마나 한 곳(폴더)에 모여 있는가 "를 나타냅니다.
응집도가 높을 수록 관련 코드를 찾기 쉽고, 수정할 때 영향 범위도 예측하기 쉽습니다.
첨부한 이미지 기반으로 설명하자면,
로그인 관련components,hooks,utils이📁auth/폴더 하나에 모여있는 걸 응집도가 높다고 표현합니다.
▶ 참고 링크
기능 폴더를 통째로 복사하거나 삭제할 수 있다.
구조 자체가 설명적이다.
📁auth/가 📁dashboard/를 참조해도 구조상 막을 방법이 없다.
"이 코드, 공통으로 올려야할지, 기능 폴더에 둬야 할지" 결정하기 어려워진다.
기능이 20개를 넘어가면 📁features/폴더 자체가 복잡해진다.
명확한 표준이 없어 팀원마다 구조를 다르게 적용할 수 있다.
이를 보완하기 위해 팀 내 파일 구조 컨벤션이 필요하거나, 구조 자체가 규칙을 강제하는 방식을 도입하게 된다.
프랙탈 구조는 소규모 프로젝트에서 잘 작동한다.
그런데 팀이 커지고 기능이 늘어나면 두 가지 문제가 반복적으로 등장한다.
A 기능이 B를 참조하고, B가 다시 A를 참조하는 순환 참조가 일어나게 된다.
개발자마다 파일을 다른 위치에 넣는다..
( 파일 구조 컨벤션이 없다면, 일어나는 아찔한 상황.. )
이를 FSD의 레이어(Layer)개념으로 해결할 수 있다.
레이어를 정의하고, 상위 레이어만 하위 레이어를 참조할 수 있게 강제한다.

FSD는 코드를 주로 6개의 레이어(Layers)로 나눈다.
위로 갈 수록 "더 구체적인 기능", 아래로 갈수록 "더 범용적인 코드"이다.
참고
사실 레이어는 7개이다.
app 다음에processes가 있지만, 실제로 잘 사용되지는 않는다.
각 레이어는 자신보다 아래 레이어만 참조할 수 있다.
apppages, widgets, features, entities, sharedpageswidgets, features, entities, sharedappwidgetsfeatures, entities, sharedapp, pagesfeaturesentities, sharedapp, pages, widgetsentitiessharedapp, pages, widgets, featuressharedapp, pages, widgets, features, entities, shared레이어 간 참조는 항상 위에서 아래 방향으로만 흐른다.
바로 2-2. 참조 규칙 기반으로만 가능하다.
레이어 안에서는 2가지 단위가 있다.

사진과 같이 단위에 맞게 자르면 된다.
추가적으로 설명을 더 남겨보자면 아래와 같다.
📁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)
각 slice는 index.ts를 통해 외부에 노출할 코드를 명시적으로 선언한다.
외부에서는 slice 내부 파일을 직접 참조하지 않고, 반드시 index.ts를 통해 접근한다.

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

각각의 성격은 알겠다.
이제 어떤 상황에서 어떤 구조를 선택해야 할까?
프랙탈이 FSD로 발전했다에서 간혹 프랙탈 구조가 틀렸다고 생각할 수 있지만,
프랙탈 구조가 틀린건 아니다!!
프랙탈은 "파일을 어디에 둘 것인가"라는 목적에 집중했고,
FSD는 한 발 더 나아가 "코드가 서로 어떻게 참조해야 하는가"라는 목적에도 집중했다.
좋은 파일 구조란 "현재 팀과 프로젝트 규모에 맞는 구조"라 생각한다.
소규모로 시작할 때는 프랙탈로 빠르게 시작하고,
규모가 커지는 시점에 FSD 마이그레이션을 검토하는 것이 좋을 것 같다는 판단이다.
( 하지만 전 소규모 플젝도 공부를 위해 FSD를 선택했어요..! 프론트 혼자일때의 장점이랄까요 후후.. )
그리고 AI(Cursor, Claude Code, Codex 등)를 사용하여 코드를 작성해본 결과,
FSD가 AI에게도 좋은 선택이라 판단이 든다.
AI는 코드를 생성하는 속도는 빠르지만, 구조를 제대로 판단하지는 않는 것으로 보인다.
이전 FSD를 사용한 프로젝트에서 명확한 FSD 구조 설계 없이 진행하였더니, 점점 파일 구조가 붕괴되는 경험을 했었다.
요구사항에 대해 .md를 제대로 설정하지 않고, 너무 모호한 명령을 내려서 그럴수도 있지만, AI는 코드 생성 속도를 빠르게 높이는 것에 중점을 두고, 구조의 붕괴는 따로 요청 혹은 설정이 없다면 신경쓰지 않는다는 걸 알게되었다.
그래서 이번에는 FSD를 사람도, AI도 더 명확하게 이해할 수 있는 "좌표계"로 사용해보고자 한다.
AI는 기능 구현과 보일러플레이트를,
사람은 설계와 리스크 검토를 담당하는 방식으로 진행해보고자 한다.
( 제발 구조 붕괴 없이 잘 마무리되길...!!! )
결론은,
AI는 "무엇을 만들지" 를 도와주지만,
"어디에 어떻게 놓을지" 는 여전히 사람과 구조가 결정해야 한다고 생각한다.
AI는 "지금 잘 동작하는 코드" 를 만들고, FSD는 "나중에도 읽히는 구조" 를 만든다.
참고
▶ 🔗 FSD 공식 문서
▶ 🔗 토스 Frontend Fundamentals 공식 문서
▶ 프랙탈 구조란?