복잡한 코드 구조의 해답을 찾다: 유지보수가 쉬운 프론트엔드를 위한 ‘기능 중심 아키텍처(FSD)’ 실전 전략

컴포넌트 폴더 안에 수백 개의 파일이 쌓여가는데, 정작 필요한 코드를 찾는 데만 10분이 넘게 걸리고 있지는 않으신가요? 프로젝트의 규모가 커질수록 우리가 가장 먼저 마주하는 벽은 기술적인 한계가 아니라, 바로 ‘코드를 어디에 두어야 할지 모르는 막막함’입니다. 초기에는 명확해 보였던 components, hooks, utils라는 폴더 구조가 어느새 서로 얽히고설킨 스파게티 코드로 변질되는 것은 프론트엔드 개발자라면 누구나 겪는 고질적인 통증이죠.

오늘날의 프론트엔드 생태계는 단순히 화면을 그리는 것을 넘어, 복잡한 비즈니스 로직을 브라우저에서 처리해야 하는 상황에 직면해 있습니다. 이러한 혼란을 잠재우고 2026년 현재 가장 주목받는 대안으로 자리 잡은 기능 중심 아키텍처(Feature-Sliced Design, 이하 FSD)에 대해 깊이 있게 살펴보겠습니다.

1. 왜 우리는 기존의 폴더 구조에 한계를 느낄까요?

우리가 관습적으로 사용해온 ‘기술 기반 폴더링’은 규모가 작은 프로젝트에서는 매우 직관적입니다. 하지만 비즈니스 로직이 고도화될수록 다음과 같은 문제들이 발생합니다.

  • 비대해진 컴포넌트 폴더: Button, Input 같은 공통 UI와 UserProfile, OrderList 같은 도메인 UI가 한데 섞여 관리의 주체를 잃어버립니다.
  • 예측 불가능한 부수 효과: 특정 기능을 수정했을 뿐인데 전혀 상관없는 페이지에서 에러가 발생하는 ‘순환 참조’와 ‘강한 결합’의 늪에 빠지게 됩니다.
  • 낮은 응집도: 하나의 기능을 수정하기 위해 components, hooks, types, store 폴더를 끊임없이 오가야 하는 번거로움이 발생합니다.

이러한 문제를 해결하기 위해 등장한 FSD는 코드를 ‘기술적 역할’이 아닌 ‘비즈니스 가치와 사용 영역’에 따라 분리하는 것을 핵심으로 합니다.

2. FSD 아키텍처의 핵심: 7개의 계층 구조

FSD는 프로젝트를 7개의 계층(Layers)으로 나눕니다. 각 계층은 아래에서 위로 향하는 단방향 의존성을 가집니다. 즉, 상위 계층은 하위 계층을 사용할 수 있지만, 하위 계층은 상위 계층을 절대 참조할 수 없습니다.

1) Shared (공유 계층)

특정 비즈니스 로직에 종속되지 않는 가장 낮은 수준의 계층입니다. UIKit, API 클라이언트, 날짜 포맷터 같은 범용적인 도구들이 여기에 속합니다. 이 계층의 코드는 프로젝트 어디에서든 재사용될 수 있습니다.

2) Entities (엔티티 계층)

비즈니스 실체(Entity)를 나타냅니다. 예를 들어 서비스가 쇼핑몰이라면 User, Product, Order가 엔티티가 됩니다. 여기에는 해당 엔티티의 슬라이스 상태(State)나 데이터 스키마가 포함됩니다.

3) Features (기능 계층)

사용자가 수행하는 ‘동작’ 중심의 계층입니다. ‘장바구니에 담기’, ‘비밀번호 변경’과 같이 구체적인 비즈니스 가치를 지닌 기능들이 모여 있습니다. 엔티티를 조합하여 실제 동작을 만들어내는 곳이라고 이해하면 쉽습니다.

4) Widgets (위젯 계층)

독립적인 UI 유닛입니다. 여러 개의 기능(Features)과 엔티티(Entities)를 조합하여 화면의 완성된 조각을 만듭니다. 예를 들어 상단의 HeaderProductCard 등이 위젯이 될 수 있습니다.

5) Pages (페이지 계층)

실제 라우팅이 일어나는 단위입니다. 위젯과 기능들을 배치하여 사용자에게 보여줄 최종 화면을 구성합니다.

6) Processes (프로세스 계층 – 선택 사항)

여러 페이지에 걸친 복잡한 비즈니스 흐름을 관리합니다. 최근에는 기능(Features) 계층에서 대부분 처리가 가능해지면서 점차 생략되기도 하는 계층입니다.

7) App (앱 계층)

애플리케이션의 설정이 이루어지는 최상위 계층입니다. Provider, Global Styles, Routing Table 등이 여기에 위치합니다.

3. ‘Public API’ 패턴으로 보호하는 코드의 경계

FSD의 진정한 강력함은 ‘Public API’라는 규칙에서 나옵니다. 각 슬라이스(폴더)는 반드시 index.ts 파일을 가져야 하며, 외부에서는 이 파일을 통해서만 내부의 코드를 참조할 수 있습니다.

💡 왜 Public API가 중요한가요?
내부에서만 사용하는 헬퍼 함수나 스타일 파일을 외부에서 직접 참조하지 못하게 막음으로써, 내부 구현을 마음껏 리팩토링하더라도 외부 코드에 영향을 주지 않는 ‘캡슐화’를 완벽히 실현할 수 있기 때문입니다.

예를 들어 features/auth/ui/LoginForm.tsx를 외부에서 불러올 때, 직접 경로를 참조하는 것이 아니라 features/auth에서 노출된 것만 사용하는 방식입니다. 이는 대규모 팀 단위 개발에서 코드의 오용을 막는 가장 강력한 방어선이 됩니다.

4. 실전 사례: 상품 상세 페이지 구축하기

이론만으로는 와닿지 않으시죠? 상품 상세 페이지를 FSD로 설계한다면 어떤 모습일지 상상해봅시다.

  1. Shared: 디자인 시스템의 Button, Skeleton UI를 가져옵니다.
  2. Entities: Product 엔티티에서 상품의 데이터 타입과 상태를 정의합니다.
  3. Features: AddToCartButton(장바구니 담기), ToggleWishlist(찜하기) 기능을 구현합니다.
  4. Widgets: 상품 이미지와 상세 설명, 구매 버튼이 조합된 ProductDetailsCard 위젯을 만듭니다.
  5. Pages: 위젯들을 배치하여 /products/:id 경로에 매핑되는 ProductPage를 완성합니다.

이렇게 구조화하면 “장바구니 담기 로직에 문제가 생겼어!”라는 이슈가 발생했을 때, 우리는 고민 없이 features/add-to-cart 폴더만 열어보면 됩니다. 다른 곳을 헤맬 필요가 없는 것이죠.

5. FSD 도입 시 주의해야 할 점

물론 FSD가 모든 프로젝트의 만병통치약은 아닙니다. 도입 전 반드시 고려해야 할 포인트가 있습니다.

  • 초기 설계 비용: 폴더 구조를 나누고 계층을 고민하는 시간이 기존 방식보다 더 많이 소요됩니다. 소규모 토이 프로젝트에는 오히려 과할 수 있습니다.
  • 학습 곡선: 팀원 모두가 각 계층의 정의와 단방향 의존성 규칙을 명확히 숙지해야 합니다. 잘못된 계층 분리는 오히려 혼란을 가중시킵니다.
  • 추상화의 딜레마: 너무 세밀하게 쪼개다 보면 오히려 파일 탐색기만 복잡해질 수 있습니다. 프로젝트의 성격에 맞춰 계층을 유연하게 조정하는 ‘적정 기술’의 마인드가 필요합니다.

요약 및 마무리

개발자의 실력은 단순히 코드를 짜는 능력이 아니라, ‘복잡성을 다루는 능력’에서 차이가 납니다. FSD(Feature-Sliced Design)는 바로 그 복잡성을 통제하기 위한 강력한 도구입니다.

  1. 계층화: 기술이 아닌 비즈니스 가치로 코드를 나눕니다.
  2. 단방향성: 상위에서 하위로만 흐르는 의존성으로 스파게티 코드를 방지합니다.
  3. 캡슐화: Public API를 통해 내부 구현을 보호합니다.

지금 진행하고 있는 프로젝트의 components 폴더가 비명을 지르고 있다면, 조금씩 FSD의 개념을 도입해보는 것은 어떨까요? 처음부터 모든 구조를 바꿀 필요는 없습니다. 가장 혼란스러운 부분부터 ‘기능’ 단위로 묶어보는 것만으로도 여러분의 코드는 훨씬 더 건강해질 거예요.

더 이상 코드의 위치를 고민하느라 시간을 허비하지 마세요. 구조가 명확해지면 개발의 즐거움은 자연스럽게 따라옵니다. 오늘도 더 나은 코드를 위해 고민하는 여러분을 응원합니다!

댓글 남기기