들어가며
최근 프로젝트를 진행하면서 폴더 구조의 재설계가 필요하게 되었습니다.
프로젝트의 성장과 변화에 따라, 더 효율적인 디렉토리 구조를 모색하게 되었어요.
이번 글에서는 그 변화의 과정과 배경, 그리고 새로운 구조에 대해 이야기해보려 합니다.
예전 구조는 어땠나요?
Next.js의 Pages Router를 사용할 때에는 아래와 같은 구조를 가지고 시작했습니다.
next-app/
├── public/ # 정적 파일 저장소
│ ├── favicon.ico # 파비콘
│ └── images/ # 이미지 파일
├── src/ # 주요 소스 코드
│ ├── components/ # 재사용 가능한 컴포넌트
│ │ ├── atoms/ # Atomic Design 패턴
│ │ │ ├── Button.tsx # 버튼 컴포넌트
│ │ │ └── Button.module.scss # 버튼 컴포넌트의 스타일
│ │ ├── molecules/
│ │ ├── organisms/
│ │ ├── templates/
│ │ └── pages/
│ ├── hooks/ # 커스텀 React 훅
│ │ └── useAuth.tsx # 인증 관련 커스텀 훅
│ ├── pages/ # 페이지 컴포넌트 및 API 라우트
│ │ ├── api/ # API 라우트
│ │ │ └── users.tsx # 사용자 관련 API 엔드포인트
│ │ ├── _app.tsx # 메인 애플리케이션 구조
│ │ ├── index.tsx # 홈페이지
│ │ └── about.tsx # '소개' 페이지
│ ├── styles/ # 스타일 정의
│ │ └── globals.scss # 전역 스타일
│ └── utils/ # 유틸리티 함수
│ └── fetcher.tsx # 데이터 패칭 유틸리티 함수
├── .env.local # 로컬 환경 설정 파일
├── next.config.js # Next.js 설정 파일
└── package.json # 프로젝트 메타데이터 및 스크립트
특히 `/src/components` 내에서 아토믹 디자인 패턴을 적용하여 컴포넌트의 재사용성과 확장성을 높이려는 시도를 했습니다.
변화의 필요성
프로젝트가 성장하면서 컴포넌트의 정확한 분류가 어렵고, 각 개발자마다 컴포넌트를 인식하는 시각의 차이도 있다보니 일관성이 떨어지는 부분도 있었어요. Next.js의 App Router 방식으로 달라졌고요.
새로운 시도: 파일 콜로케이션
이러한 배경에서, 각 페이지 및 기능별로 관련 컴포넌트와 로직을 함께 배치하는 파일 콜로케이션 방식에 대해 관심을 갖게 되었습니다. 그리고 다음과 같은 구조를 시도해보기로 했어요.
app/
├── menu/ # 메뉴
│ ├── components/ # 메뉴에서 사용되는 컴포넌트
│ │ └── Card.tsx
│ │ └── Box.tsx
│ └── page.tsx # 페이지
... 생략
처음에는 페이지별로 컴포넌트가 분산되어 관리되는 것에 대한 우려가 있었지만, 실제 적용해보니 관련 컴포넌트를 빠르게 찾고, 수정하는 등의 작업이 훨씬 수월해졌습니다.
파일 콜로케이션의 장점
1. 가독성 향상: 관련 파일이 가까이 있어, 필요한 코드를 빠르게 찾을 수 있습니다.
2. 유지보수 용이성: 관련된 모든 파일이 한 곳에 있어 수정 및 업데이트가 용이합니다.
3. 팀 협업 효율성 증가: 프로젝트의 구조가 명확해져 새 팀원이 쉽게 적응할 수 있습니다.
최종 프로젝트 구조
이러한 변화를 거쳐, 다음 예시와 같은 프로젝트 구조를 사용하기로 했어요.
app/
├── base
│ ├── components # 전역 공유 컴포넌트 디렉토리
│ │ ├── ui # UI 컴포넌트
│ │ │ ├── Button.tsx # 버튼 컴포넌트
│ │ │ └── Input.tsx # 입력 필드 컴포넌트
│ │ └── hooks # 공통 훅
│ │ └── useAuth.ts # 인증 관련 커스텀 훅
│ ├── api
│ │ └── key.ts
│ ├── types
│ └── utils
├── layout.tsx # 전역 레이아웃(헤더, 푸터 포함)
├── error.tsx # 전역 오류 페이지
└── [auth] # 인증 관련 라우트 그룹
│ ├── api # 인증 관련 API 엔드포인트
│ │ └── login.ts # 로그인 API 엔드포인트
│ ├── login
│ │ ├── page.tsx # 로그인 페이지
│ │ ├── layout.tsx # 로그인 페이지 특정 레이아웃
│ │ └── components # 로그인 페이지 전용 컴포넌트
│ │ └── LoginForm.tsx # 로그인 폼 컴포넌트
│ └── register
│ ├── page.tsx # 등록 페이지
│ └── components # 등록 페이지 전용 컴포넌트
│ └── RegisterForm.tsx # 등록 폼 컴포넌트
└── dashboard # 대시보드 라우트 그룹
├── api # 대시보드 관련 API 엔드포인트
│ └── fetchDashboardData.ts # 대시보드 데이터를 가져오는 API
├── layout.tsx # 대시보드 공통 레이아웃
├── page.tsx # 대시보드 메인 페이지
├── components # 대시보드 전용 컴포넌트
│ └── DashboardChart.tsx # 대시보드 차트 컴포넌트
├── settings # 설정 관련 서브라우트
│ ├── page.tsx # 설정 페이지
│ └── [profile] # 프로필 설정 동적 라우트
│ └── page.tsx # 프로필 설정 페이지
└── reports # 보고서 관련 서브라우트
├── page.tsx # 보고서 메인 페이지
└── [id] # 개별 보고서 동적 라우트
└── page.tsx # 개별 보고서 페이지
└── products # 제품 관련 라우트
├── api # 제품 관련 API 엔드포인트
│ ├── fetchProducts.ts # 제품 목록을 가져오는 API
│ └── fetchProductDetail.ts # 제품 상세 정보를 가져오는 API
├── index.tsx # 제품 목록 페이지
├── [id] # 제품 상세 페이지 동적 라우트
│ └── page.tsx
└── new
└── page.tsx # 새 제품 추가 페이지
각 기능별로 폴더를 분리하고, 필요한 컴포넌트와 로직을 함께 배치함으로써 프로젝트의 관리와 확장성을 기대할 수 있게 되었습니다.
마치며
프로젝트 구조 변화는 쉽지 않은 과정인 것 같아요.
하지만 파일 콜로케이션을 통한 새로운 구조 시도는 프로젝트의 가독성, 유지보수성, 그리고 팀의 협업 효율성이 좋아진 것 같습니다.
새로운 구조적 접근 방식을 소개해주신 천승준 주임님께 감사의 인사를 드립니다. 🙇♂️