Next.js v14 + MUI v5 셋팅에 이어서 폴더 구조(아키텍처)에 대해서 설명하려합니다.
저는 항상 프로젝트를 시작, 진행하면서 고민되는 포인트는 프로젝트 아키텍처를 어떻게 설계해 나가야 되는 것인가 대한 고민을 했었는데요.
프로젝트 규모에 따른 아키텍처 설계 기준을 정리해보려합니다. 일단 현재 셋팅하고있는 Next.js +. MUI프로젝트는 FSD(기능 분할 설계)를 활용할 계획입니다. 어떤기준으로 정한것인지 아래에 살펴보겠습니다.
전통적 아키텍처 (작은 프로젝트나 개인 프로젝트)
전통적인 아키텍처(폴더구조)는 제가 프로젝트에자주 사용하구조입니다.
이 구조는 재사용 가능한 컴포넌트, 전역 상태 관리, API 호출, 커스텀 훅, 상수, 타입, 스타일, 유틸리티 함수 등을 별도의 폴더로 구분하여 관심사를 분리하고 있습니다.
전통적인 아키텍처에는 눈에 띄는 단점이 있습니다. 가장 큰 단점은 컴포넌트 간의 암묵적인 연결과 모듈의 복잡성 때문에 프로젝트가 유지보수하기 어려워진다는 것입니다. 이 아키텍처의 단점은 시간이 흐를수록 더욱 분명해집니다. 프로젝트가 진화할수록 애플리케이션 아키텍처는 엉망진창이 되어 버립니다.
전통적인 아키텍처는 지속적인 유지보수가 없는 작은 프로젝트나 개인 프로젝트에는 적합합니다.
(저는 지금까지 회사에서 어떤 프로젝트간에 전통적인 아키텍처로 진행을 했었는데 프로젝트가 진화할수록 제 머리속의 복잡도도 진화하는것 같았습니다.ㅠ)
my-app/
│
├── src/
│ ├── components/ # 재사용 가능한 컴포넌트
│ │ ├── common/ # 전역적으로 사용되는 컴포넌트 (버튼, 헤더, 푸터 등)
│ │ └── Blog # 블로그 페이지에서 사용되는 컴포넌트
│ │ ├── index.tsx
│ │ ├── BlogContainer.tsx
│ │ └── BlogContainer.stories.tsx
│ │
│ ├── store/ # 전역 상태 관리 (예: Context API, Redux, recoil, zustand 등)
│ │
│ ├── app/ # Next.js app 라우팅
│ │ └── page.tsx
│ │ └── layout.tsx
│ │
│ ├── api/ # api와 관련된 로직
│ │
│ ├── hooks/ # 커스텀 React 훅
│ │
│ ├── constants/ # 상수 값
│ │
│ ├── types/ # 타입 (typescript 사용시)
│ │
│ ├── styles/ # 스타일 관련 파일(CSS, Tailwind 설정 등)
│ │
│ └── utils/ # 유틸리티 함수
│ │
│ └── providers/ # provider컴포넌트 (Mui, tanstack-query, recoil 등등..)
│
...생략
FSD - Feature-Sliced Design (대규모 프로젝트)
전통적인 아키텍처가 아닌 FSD에 대해서 알아보겠습니다.
기능 분할 설계(FSD)의 과제 중 하나는 결합을 느슨하게 하고 응집력을 높이는 것입니다. FSD가 이러한 결과를 어떻게 달성하는지 이해하는 것은 중요합니다. 아래 인용을 참고해주세요.
OOP에서는 다형성(polymorphism), 캡슐화(encapsulation), 상속(inheritance) 및 추상화(abstraction) 와 같은 개념을 통해 이러한 문제들을 오랜 시간 동안 해결해 왔습니다. 이러한 개념들은 코드의 격리, 재사용성, 그리고 다양한 결과를 보장합니다. 이는 컴포넌트나 기능이 어떻게 사용되느냐에 따라 다른 결과를 얻을 수 있도록 합니다.
기능 분할 설계는 이러한 원칙들을 프런트엔드에 적용하는 데 도움을 줍니다.
추상화와 다형성은 레이어를 통해 달성됩니다. 낮은 레이어는 더 추상화 되어있기 때문에 더 높은 레이어에서 재사용될 수 있으며, 특정한 매개변수나 속성에 따라 컴포넌트나 기능이 다르게 작동할 수 있습니다.
캡슐화는 슬라이스와 세그먼트 외부에서 필요하지 않은 것을 격리시키는 공개 API를 통해 달성됩니다. 슬라이스의 내부 세그먼트에 대한 접근은 제한되며, 공개 API는 슬라이스 또는 세그먼트의 기능 및 컴포넌트에 접근할 수 있는 유일한 방법입니다.
상속 또한 레이어를 통해 달성됩니다. 더 높은 레이어는 낮은 레이어를 재사용할 수 있습니다
요약하자면 프로젝트 폴더구조를 레이어와, 슬라이스, 세그먼트로 구분하여 결합을 느슨하게 하고 응집력을 높인다는 것입니다. 어떻게? OOP 개념을 활용해서! 조금 더 자세한 사항은 FSD 참고사이트를 확인해주세요.
기능 | oop 개념 적용 |
레이어 | 추상화, 다형성, 상속, |
슬라이스 | 캡슐화 |
저는 FSD의 모든 특징을 사용하진 않고 features, shared만을 사용해서 프로젝트를 진행하려합니다.
더 필요한 부분이 있다면 참고에 있는 글을 읽고 본인에게 맞는 프로젝트 구조를 적용하시면 됩니다!
그럼 다음 포스트는 Next.js 렌더링에 관해서 포스트해보겠습니다.
my-app/
│
├── src/
│ ├── features/ # 기능별 모듈 디렉토리
│ │ ├── auth/ # 인증 기능 (로그인, 회원가입 등)
│ │ │ ├── components/ # 인증 관련 컴포넌트
│ │ │ ├── hooks/ # 인증 관련 커스텀 훅
│ │ │ ├── api/ # 인증 관련 api
│ │ │ ├── pages/ # 인증 관련 페이지
│ │ │ ├── types/ # 인증 관련 타입 (typescript 사용시)
│ │ │ ├── constants/ # 인증 관련 상수 값
│ │ │ └── utils/ # 인증 관련 유틸리티 함수
│ │ │
│ │ ├── blog/ # 블로그 기능
│ │ │ ├── components/ # 블로그 관련 컴포넌트
│ │ │ ├── hooks/ # 블로그 관련 커스텀 훅
│ │ │ ├── api/ # 블로그 관련 api
│ │ │ ├── pages/ # 블로그 관련 페이지
│ │ │ ├── types/ # 블로그 관련 타입 (typescript 사용시)
│ │ │ ├── constants/ # 블로그 관련 상수 값
│ │ │ └── utils/ # 블로그 관련 유틸리티 함수
│ │ │
│ │ └── [other features] # 다른 기능들
│ │
│ ├── app/ # Next.js app 라우팅
│ │ └── page.tsx # features 내부의 pages와 연결
│ │ └── layout.tsx
│ │
│ ├── shared/
│ ├── components/ # 전역에서 사용되는 재사용 가능한 컴포넌트
│ ├── hooks/ # 전역에서 사용되는 커스텀 훅
│ ├── api/ # 전역에서 사용되는 api
│ ├── utils/ # 전역 유틸리티 함수
│ ├── types/ # 전역에서 사용되는 타입 (typescript 사용시)
│ ├── constants/ # 전역에서 사용되는 상수 값
│ ├── store/ # 전역 상태 관리 (예: Context API, Redux, recoil, zustand 등)
│ └── styles/ # 전역 스타일
│ └── providers/ # 프로바이더 (예: MUI Provider, tanstack-query Provider 등등..)
│
...생략