74 lines
10 KiB
Markdown
74 lines
10 KiB
Markdown
# [[Folder Structure]]
|
|
|
|
## 📌 Brief Summary
|
|
폴더 구조(Folder Structure)는 소프트웨어 프로젝트 내에서 파일과 디렉터리를 논리적으로 조직하는 아키텍처적 기반을 의미합니다 [1, 2]. 최신 프론트엔드 개발에서는 단순한 파일 유형 기반(File-Type Based) 구조의 한계를 극복하기 위해, 비즈니스 도메인이나 기능(Feature)을 중심으로 모듈화하는 방향으로 진화해 왔습니다 [3, 4]. 잘 설계된 폴더 구조는 애플리케이션의 유지보수성, 확장성, 팀 협업 효율을 극대화하고 기술 부채를 줄이는 데 핵심적인 역할을 합니다 [2, 5-9].
|
|
|
|
## 📖 Core Content
|
|
|
|
- **기존 구조의 한계와 진화**: 과거에는 컴포넌트, 훅, 스타일 등을 각각의 기술적 파일 유형별 폴더에 모아두는 방식(File-Type Based Structure)을 주로 사용했습니다 [3, 10]. 이 방식은 소규모 앱에서는 설정이 직관적이지만, 애플리케이션이 커질수록 하나의 기능을 수정하기 위해 여러 폴더를 탐색해야 하므로 개발자의 인지 부하를 높이고 스파게티 코드를 유발합니다 [3, 10].
|
|
- **기능 기반 조직(Feature-Based Organization)**: 2025년 현재 업계 표준은 비즈니스 기능(도메인)을 중심으로 코드를 구성하는 방식입니다 [4, 11]. `src/features/` 디렉터리 하위에 특정 기능(예: 인증, 대시보드)과 관련된 컴포넌트, 훅, API 로직, 타입을 모아두어 높은 응집도와 모듈 독립성을 확보합니다 [11, 12].
|
|
- **권장되는 하이브리드 폴더 구조**: 대규모 확장이 가능한 React 프로젝트는 파일 유형과 기능을 결합한 하이브리드 디렉터리 구조를 권장합니다 [13]. 대표적인 `src/` 하위 구성은 다음과 같습니다:
|
|
- `assets/`: 이미지, 폰트 등 여러 기능에서 공유되는 정적 미디어 리소스 [13, 14].
|
|
- `components/`: 버튼, 모달 등 도메인에 종속되지 않고 재사용되는 공통 UI 컴포넌트 [11, 14, 15].
|
|
- `features/`: 도메인별 특정 비즈니스 로직 및 UI가 캡슐화된 모듈 [11, 12, 15].
|
|
- `pages/` (또는 `routes/`): 라우팅에 매핑되는 페이지 레벨 컴포넌트 [16, 17].
|
|
- `hooks/`, `services/`, `utils/`: 공통 커스텀 훅, 외부 API 통신 및 비즈니스 로직, 헬퍼 함수 [12, 17-20].
|
|
- `store/` (또는 `context/`): 전역 상태 관리 로직 [16-18].
|
|
- **Feature-Sliced Design (FSD)**: 기능 기반 구조를 더 엄격한 아키텍처 방법론으로 발전시킨 형태입니다 [21, 22]. 코드를 `app`, `pages`, `widgets`, `features`, `entities`, `shared`라는 명확한 계층(Layer)으로 나눕니다 [23, 24]. 상위 계층이 하위 계층에만 의존할 수 있다는 단방향 의존성 규칙을 강제하여 순환 참조와 아키텍처의 붕괴를 막습니다 [22, 23].
|
|
- **네이밍 컨벤션과 거버넌스**: 폴더 구조는 엄격한 명명 규칙과 결합될 때 효과적입니다. 운영체제 간(Windows/Mac vs Linux) 대소문자 구분 문제로 인한 CI/CD 빌드 실패를 막기 위해 파일과 폴더명은 주로 `kebab-case`를 사용하며, React 컴포넌트 명칭은 `PascalCase`를 사용하는 것이 표준입니다 [25-30]. Next.js에서는 `(folderName)` 형태를 사용하여 URL 경로에 영향을 주지 않고 논리적으로 라우트를 그룹화하는 패턴도 활용됩니다 [31, 32].
|
|
|
|
## ⚖️ Trade-offs & Caveats
|
|
기능 기반(Feature-based) 구조나 Feature-Sliced Design(FSD)과 같은 고도화된 폴더 구조는 소규모 프로젝트나 초보자에게는 과도한 오버헤드(Overkill)가 될 수 있습니다 [33]. 단순한 앱에 적용할 경우 불필요한 하위 폴더와 중복된 구조를 무수히 생성하게 되어 오히려 개발 속도를 저하시킬 수 있습니다 [33].
|
|
|
|
특히 FSD 구조를 도입할 경우, 특정 모듈이 어느 계층에 속해야 하는지("이 모듈이 feature인가 widget인가?")를 결정하는 데 있어 의미론적 논쟁과 인지적 오버헤드가 발생합니다 [34]. 또한, 팀 전체가 이 방법론과 계층 규칙을 명확히 이해하고 문서화하지 않으면, 개발자들이 규칙을 무시하고 모든 코드를 최하단인 `shared` 폴더에 쏟아부어 오히려 버그를 양산하고 코드 변경 시의 영향 범위(Blast radius)를 통제 불능으로 만들 위험이 큽니다 [34, 35].
|
|
|
|
추가로, 모듈 내부를 캡슐화하기 위해 진입점을 하나로 통일하는 배럴 파일(Barrel files, 예: `index.ts`를 통한 Public API 노출) 패턴은 내부 리팩토링을 안전하게 만들어주지만, 번들링(Bundling)이나 트리 쉐이킹(Tree-shaking) 과정에서 원치 않는 모듈까지 불러와 성능상 불이익을 초래할 수 있다는 단점이 존재합니다 [34, 36, 37].
|
|
|
|
## 🔗 Knowledge Connections
|
|
|
|
### Related Concepts
|
|
|
|
#### [아키텍처/기반 기술]
|
|
- [[Feature-Sliced Design]]
|
|
- 연결 이유: Folder Structure를 단순한 디렉터리 분리가 아닌, 계층(Layer)과 슬라이스(Slice) 기반의 엄격한 아키텍처 방법론으로 승격시킨 개념이기 때문입니다 [21-24].
|
|
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 단방향 의존성 원칙과 모듈 캡슐화를 통해 대규모 React 앱이 어떻게 스파게티 코드를 방지하는지 이해할 수 있습니다 [23, 37].
|
|
- [[Separation of Concerns]]
|
|
- 연결 이유: Folder Structure를 UI 렌더링, 비즈니스 로직, 상태 관리 등으로 나누는 핵심 소프트웨어 공학 원리입니다 [8, 30].
|
|
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 왜 `components/`와 `services/`, `store/` 폴더를 분리해야 하는지 그 근본적인 이유를 알 수 있습니다 [30].
|
|
- [[Domain-Driven Design]]
|
|
- 연결 이유: 프론트엔드 코드의 폴더를 기술적 유형이 아닌 비즈니스 도메인(기능) 중심으로 나누는 데 논리적 기반을 제공합니다 [12, 38].
|
|
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: `features/` 폴더 내에 코드를 응집시키는 것이 비즈니스 요구사항 변화에 어떻게 유연하게 대처하게 하는지 파악할 수 있습니다 [38].
|
|
|
|
#### [구현/활용 도구]
|
|
- [[Naming Conventions]]
|
|
- 연결 이유: 일관된 명명 규칙은 폴더 구조의 가독성과 예측 가능성을 완성하는 필수 요소입니다 [25, 26, 30, 39].
|
|
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 왜 폴더명은 `kebab-case`를 쓰고 컴포넌트는 `PascalCase`를 써야 CI/CD 파이프라인에서 오류가 나지 않는지 이해할 수 있습니다 [25, 40].
|
|
- [[State Management]]
|
|
- 연결 이유: 폴더 구조에서 전역 상태(`store/`, `context/`)와 지역/기능 상태(`features/`)를 어디에 위치시킬지 결정하는 핵심 요소입니다 [16, 18, 19, 41, 42].
|
|
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: Zustand, Context API 등 관리 도구에 따라 전역 인프라 상태와 도메인 상태를 분리 배치하는 전략을 학습할 수 있습니다 [43].
|
|
|
|
### Deeper Research Questions
|
|
|
|
- Feature-Sliced Design(FSD)에서 하위 계층이 상위 계층을 참조하지 못하도록 ESLint 규칙을 통해 어떻게 단방향 의존성을 강제할 수 있는가?
|
|
- 배럴 파일(`index.ts`)을 이용한 Public API 패턴이 Webpack이나 Vite의 트리 쉐이킹(Tree-shaking) 최적화에 미치는 정확한 부작용과 그 해결책은 무엇인가?
|
|
- '인증(Auth)'과 같이 애플리케이션 전반에 걸쳐 사용되는 교차 절단 관심사(Cross-cutting concerns)는 기능 기반(Feature-based) 폴더 구조에서 어떻게 분리하고 배치해야 코드 응집도를 잃지 않는가?
|
|
- 소규모 프로젝트(Flat structure)에서 대규모 프로젝트(Feature-Sliced Design)로 폴더 구조를 마이그레이션해야 하는 구체적인 임계점(컴포넌트 수, 팀 규모 등)이나 코드 스멜 지표는 무엇인가?
|
|
- Next.js의 App Router에서 제공하는 Route Grouping `(folder)` 문법과 기존의 기능 기반 폴더 분리(`features/`) 패턴을 어떻게 충돌 없이 조화롭게 설계할 수 있는가?
|
|
|
|
### Practical Application Contexts
|
|
|
|
- **Implementation:** 운영체제(Windows vs Linux)에 따른 대소문자 구분 이슈를 방지하기 위해 폴더와 파일명 생성 시 일관된 `kebab-case`를 적용하는 규칙을 프로젝트 린팅 룰에 설정합니다 [25-27].
|
|
- **System Design:** 프로젝트 설계 초기 단계에서 `features/` 폴더를 정의하여 UI 요소와 비즈니스 로직의 경계를 명확히 하고, 공통 컴포넌트는 오직 Presentation 역할만 수행하도록 시스템을 구조화합니다 [11, 44].
|
|
- **Operation / Maintenance:** 새로운 개발자가 팀에 합류했을 때, 기능별로 고립된 폴더 구조를 통해 전체 코드를 파악하지 않고도 자신이 맡은 도메인(`features/auth` 등)만 분석하여 즉시 유지보수 업무에 투입될 수 있도록 돕습니다 [6].
|
|
- **Learning Path:** 처음 React를 학습할 때는 Flat 구조로 시작하여 기본기를 익히고, 프로젝트가 커짐에 따라 File-Type Based 구조를 거쳐 최종적으로 Feature-Based 또는 FSD 아키텍처로 진화하는 순차적 학습이 권장됩니다 [4, 9, 10, 33].
|
|
- **My Project Relevance:** 현재 진행 중인 또는 계획된 React 프로젝트의 규모와 팀원의 숙련도를 평가하여, 지나치게 복잡한 FSD를 바로 도입하기보다는 `features/`와 `components/`를 결합한 하이브리드 방식을 적용해 점진적인 모듈화를 시도하는 지표로 삼을 수 있습니다.
|
|
|
|
### Adjacent Topics
|
|
|
|
- [[Code Splitting]]
|
|
- 확장 방향: 폴더 구조를 라우트나 기능 단위로 명확히 나누면, Vite나 Webpack을 이용해 해당 모듈들을 독립적인 청크(Chunk)로 나누어 지연 로딩(Lazy Loading)하는 최적화 전략으로 자연스럽게 확장할 수 있습니다 [45, 46].
|
|
- [[Micro-Frontends]]
|
|
- 확장 방향: 모놀리식 단일 폴더 구조가 감당할 수 없을 만큼 거대해진 엔터프라이즈 환경에서, 아예 독립적으로 배포 및 운영 가능한 프론트엔드 애플리케이션으로 분할하는 극단적 아키텍처 방법론으로 확장됩니다 [21].
|
|
|
|
---
|
|
*Last updated: 2026-04-30* |