폴더 디렉토리 구조 정리하기

2025년 02월 27일

안녕하세요, 웹 프론트엔드 개발자 Garden, 오소현입니다.

최근에 사내에서 프론트엔드 코드에 대해서 폴더 구조를 개편하고 이를 마이그레이션하는 작업을 진행하고 있는데요!

원래 폴더 구조는 어땠고, 이를 개편한 폴더 구조는 어떻게 되는지 소개해드리고자 합니다.

1. 원래 폴더 구조

저희 회사는 모노레포 구조로 한 서비스의 기능을 큰 단위로 나누어(이 기준은 연관된 서비스를 기준으로 나눴습니다.), 프론트엔드 서버를 큰 단위로 분리를 하였고 총 4개의 프론트엔드 서버를 운영하고 있습니다.

개발자들 각각 개인 프론트엔드 서버를 나누어 가지고 있어서 이 단위를 위주로 R&R을 나누어 개발 작업을 진행하고 있습니다.

기반이 되는 컴포넌트 디자인 패턴은 바로 아토믹 디자인 패턴이었는데요! 이 패턴은 컴포넌트를 최소 단위로 나누어 재사용성을 높이고 유지보수를 쉽게 하기 위해 사용되는 패턴입니다.

아토믹 디자인 패턴을 간단히 소개해보자면 각 단위별로 다음과 같이 나누어서 컴포넌트를 분리하고, 설계합니다.

  1. Atoms (원자):

    • 가장 기본이 되는 UI 요소들입니다.
    • 버튼, 인풋, 레이블과 같은 더 이상 쪼갤 수 없는 기본 컴포넌트들이 여기에 속합니다.
  2. Molecules (분자):

    • Atoms를 조합하여 만든 작은 단위의 UI 컴포넌트입니다.
    • 검색 폼(인풋 + 버튼), 네비게이션 링크 등이 이에 해당합니다.
  3. Organisms (유기체):

    • Molecules와 Atoms를 조합하여 만든 좀 더 복잡한 UI 섹션입니다.
    • 헤더, 푸터, 상품 리스트 등이 이에 해당합니다.
  4. Templates:

    • 페이지의 구조를 잡아주는 와이어프레임입니다.
    • 실제 컨텐츠가 아닌 레이아웃 구조를 정의합니다.
  5. Pages:

    • 실제 컨텐츠가 채워진 완성된 페이지입니다.
    • Templates에 실제 데이터를 넣어 구현한 최종 결과물입니다.

따라서 저희는 공용 컴포넌트에 대해서는 아토믹 디자인 패턴에 기반하여 컴포넌트들을 관리해오고 있었습니다.

그런데 아토믹 디자인 패턴을 도입해 사용하다보면 흔하게 고민하는 문제인 어디까지가 Atoms인지, Organisms인지, Templates인지, Pages인지 판단하기가 어려워졌습니다.

위와 같은 이슈도 있고, 너무 많은 컴포넌트가 공용 컴포넌트 영역인 shared-ui 폴더에 존재하여 관리하기도 어려워졌습니다.

또한 기존의 폴더 구조는 다양한 프로젝트와 라이브러리가 혼합되어 있어 의존성 관리와 모듈 간의 격리가 잘 이루어지지 않았습니다.

따라서 각 기능의 의존성을 높이기 위해서 FSD 구조를 도입해 각 기능별로 폴더를 나누어 관리하기로 하였습니다.

2. 개편한 폴더 구조

따라서 저희가 개편한 폴더 구조를 각 서버단위로 보면 다음과 같습니다.

1) 📦src

모든 소스 파일이 위치하는 핵심 디렉토리입니다. 이곳에서 주요 기능별로 컴포넌트와 관련 로직을 분류합니다.

2) 📂compounds

compounds 디렉토리는 각종 기능별로 세부 컴포넌트를 구분하여 관리합니다. 예를 들어, 채널 랭킹과 관련된 UI, 모델, API 등을 channel-rank 폴더 내에 정리하고 있습니다.

  • features: 각 기능 별로 UI와 로직을 분리하여 관리합니다. 예를 들어, ChannelRankFloatingMenu, ChannelRankHead 등 각 섹션별로 폴더를 구성합니다.
  • ui: UI 컴포넌트와 스타일 파일을 저장합니다. 예를 들어, 모바일 드롭다운 컴포넌트, 헤드 컴포넌트 등이 이에 해당합니다.
  • model: 데이터 관리 및 비즈니스 로직을 처리하는 파일을 포함합니다. 훅스 및 유틸리티 함수 등이 위치합니다.
  • api: 서버와의 통신을 담당하는 API 관련 파일들입니다. GraphQL이나 REST API 호출을 정의합니다.

3) 📂pages

Next.js 프레임워크의 페이지 라우팅 구조에 맞추어 각 페이지 컴포넌트를 관리합니다. index.jsx, 404.jsx 등의 페이지 라우팅과 관련된 컴포넌트가 포함됩니다.

4) 📂styles

전역 스타일, 모듈 스타일, 공통 사용 스타일 시트 등을 관리합니다. globals.css는 사이트 전체에 적용되는 기본 스타일을 정의합니다.

5) 📂wrapper

각 기능별로 페이지 내에서 사용할 수 있도록 래퍼 컴포넌트를 제공합니다. 예를 들어, ChannelRankWrapper, MoneyRankWrapper 등 페이지 별로 필요한 래퍼 컴포넌트들이 여기에 포함됩니다.

사진으로 시각화 하면 다음과 같습니다.

imageimage

예시로 보여드린 사진과 같은 구조를 조금 더 자세히 살펴보려 합니다.

해당 폴더는 features 폴더 내에 존재하는 폴더 구조입니다. 유튜브 채널 순위의 배너를 하나의 features로 분리해보았고, api/model/ui 폴더로 나눠서 구현해보았습니다.

3. 개편한 폴더 구조를 자세히 살펴보기(역할)

1) 📂 api 폴더

첫 번째 폴더는 api 폴더입니다. 해당 폴더는 서버와의 통신을 담당하고 있는 로직을 정의하는 폴더입니다. 대체적으로 graphql을 사용하여 서버와의 통신을 담당하고 있습니다.

위 코드를 보시면 api 폴더 내에는 두 가지 파일이 존재합니다:

  1. ChannelMoneyRankBanner.api.ts:

    • Apollo Client를 사용하여 실제 API 호출을 수행하는 커스텀 훅을 정의합니다.
    • 국가 코드와 같은 공통 유틸리티를 활용하여 데이터 요청을 구성합니다.
  2. ChannelMoneyRankBanner.gql.ts:

    • GraphQL 쿼리를 정의하는 파일입니다.
    • 채널의 수익 순위를 조회하는 쿼리
    • 환율 정보를 조회하는 쿼리

이렇게 api 폴더에서는 서버와의 통신에 필요한 모든 로직을 다 정의해두고, 필요한 곳에서 호출하여 사용합니다.

2) 📂 model 폴더

두 번째로 살펴볼 폴더는 model 폴더입니다. 이 폴더는 비즈니스 로직을 처리하고 상태를 관리하는 역할을 담당합니다.

model 폴더에는 크게 두 가지 파일이 존재합니다:

  1. ChannelMoneyRankBanner.types.ts:

    • 서버에서 받아오는 기본 채널 데이터의 타입을 정의합니다.
    • 실제 UI에서 사용할 채널 데이터의 타입으로, 기본 채널 데이터에 ranking 정보가 추가된 형태입니다.
  2. useChannelMoneyRankBanner.ts:

    • 비즈니스 로직을 처리하는 커스텀 훅을 구현하여 사용하고 있습니다.
      • 채널 데이터 fetch 및 가공
      • 환율 정보 관리
      • 다국어 처리
      • 이벤트 트래킹
      • 로딩 상태 관리

이처럼 model 폴더에서는 UI 로직과 분리된 순수한 비즈니스 로직을 관리합니다.

3) 📂 ui 폴더

마지막으로 살펴볼 폴더는 ui 폴더입니다. 이 폴더는 실제 사용자에게 보여지는 UI 컴포넌트들을 관리합니다.

  1. ChannelMoneyRankBanner.module.scss:

    • 컴포넌트의 스타일을 관리하고 있습니다!
  2. ChannelMoneyRankBanner.tsx:

    • 메인 UI 컴포넌트입니다.
    • model 폴더의 useChannelMoneyRankBanner 훅을 사용하여 비즈니스 로직을 관리합니다.
  3. Skeleton.tsx:

    • 데이터 로딩 중에 보여질 스켈레톤 UI를 정의합니다.

4. 운영 후기

저희는 위과 같이 개편을 하고 나서 api, model, ui 폴더로 구조화함으로써, 기능에 따라 코드를 분리하고 관리할 수 있게 되었습니다.

사실 명확한 FSD 구조가 아니고 저희는 각 프론트엔드 서버 별로 컴포넌트들이 기능에 의존하게 구조화를 하는것이 목표여서 완전한 FSD구조를 이루고 있지는 않지만 기능에 따라 코드를 분리하고 관리할 수 있게 되었습니다.

그리고 쉽게 찾아서 수정할 수 있는 코드를 만들어 준 것 같아 만족스러웠습니다.

공용 컴포넌트는 이제 디자인 시스템 레포만 남기는 것이 저희의 목표 입니다 :)