FSD 아키텍쳐 : 새로운 프론트엔드 아키텍쳐

BiBi·2024년 3월 15일

Feature-Sliced Design: The Best Frontend Architecture

FSD 아키텍쳐

Feature-Sliced Design 으로 프런트엔드 애플리케이션을 스캐폴딩하기 위한 아키텍처 방법론입니다. 간단히 말해, 코드 구성에 관한 규칙의 모음이다. 이 방법론의 주된 목적은 끊임없이 변화하는 비즈니스 요구사항에 맞서 프로젝트를 더 이해하기 쉽고 체계적으로 만드는 것이다.

Features

  • Explicit business logic : 명시적인 비즈니스 로직. 도메인 범위 덕분에 쉽게 검색 가능한 아키텍처이다.
  • Adaptability : 적응성. 새로운 요구 사항에 따라 아키텍처 구성 요소를 유연하게 교체 및 추가할 수 있다.
  • Tech debt & Refactoring : 기술 부채 및 리팩토링. 각 모듈은 사이드 이펙트없이 독립적으로 수정/재작성할 수 있다.
  • Explicit code reuse : 명시적 코드 재사용. DRY와 로컬 사용자화 사이의 균형이 유지된다.

Scheme

FSD에서 프로젝트는 레이어로 구성되며, 각 레이어는 슬라이스로, 각 슬라이스는 세그먼트로 구성된다.
features

Layers

레이어는 디렉토리의 최상위이고, 애플리케이션 분해의 첫번쩨 단계이다. 레이어의 수는 최대 7개로 제한되어 있으며, 일부는 옵셔널하지만 표준화되어 있다. 현재는 아래와 같이 레이어가 구분되어 있다. 각 레이어는 고유의 책임영역이 있고, business-oriented하다.
processes (deprecated)

  • App
    애플리케이션 로직이 초기화되는 공간이다. Providers, routers, global styles, global type declarations, 등등 이 여기서 정의된다. 즉 애플리케이션의 진입점 역할을 한다.

  • Processes(deprecated, optional)
    이 레이어는 여러 페이지에 걸쳐있는 프로세스를 처리한다.(ex, multi-step registration) 이 레이어는 더이상 사용되지 않는다.

  • Pages
    entities, features, widgets 레이어 로 전체 페이지를 구성하기 위한 구성 레이어이다. 이 레이어는 애플리케이션의 페이지가 포함된다.

  • Widgets
    entities와 features 레이어를 의미있는 블록으로 결합하는 composition layer이다. 페이지에서 사용되는 독립적인 UI 컴포넌트들이 있다. (ex, IssuesList, UserProfile)

  • Features(optional)
    이 레이어는 business value를 전달하는 유저 시나리오와 같은 기능을 다룬다. (ex, SendComment, AddToCart, UsersSearch)

  • Entities(optional)
    이 레이어는 business entities를 나타낸다.(ex, User, Product, Order)

  • Shared
    이 레이어에는 특정 비즈니스 로직에 종속되지 않은 재사용가능한 컴포넌트와 유틸리티가 포함되어 있다. (ex, UIKit, libs, API)

이러한 레이어들은 코드베이스를 구성하고, 모듈식, 유지보수 가능, 확장 가능한 아키텍쳐를 만드는데 도움이 된다.
imjod1r4jmgwrnkxysm8

FSD의 주요 특징중 하나는 계층적 구조이다. 이 구조에서 entities 레이어는 features 레이어가 더 상위이기 때문에 features 레이어의 기능을 사용할 수 없다. 비슷하게, features 레이어는 widget 이나 processes 레이어의 기능을 사용할 수 없다. 즉, 위 레이어는 아래 레이어만 활용할 수 있는데 이는 한방향으로만 향하는 선형적인 흐름을 유지하기 위한것이다.

0icvw9lyxhc8vy87svif
따라서 계층구조에서 레이어의 위치가 낮을 수록 코드의 많은 곳에서 사용될 가능성이 높기 때문에 변경하는 것이 위험하다. 예를들어, shared 레이어의 UI-kit는 features, widgets, pages 레이어에서 사용될 수 있다.

Slices

각 레이어 에는 애플리케이션 분해의 두번째 레벨인 slice라는 하위 디렉토리가 있다. slice에서 연결은 추상적인 것이 아니라, 특정 business entities에 대한 것이다. 즉, 비즈니스 도메인 별로 코드를 분할해서 논리적으로 관련된 모듈을 서로 가깝게 유지하여 코드 베이스를 쉽게 탐색할 수 있다. 슬라이스는 같은 레이어에서 다른 슬라이스를 사용할수 없으므로 응집력이 높고 결합력이 낮다.

slice는 프로젝트의 business 영역에 의해 직접 결정되기때문에 이름이 표준화되어있지 않다. 예를들어, photo gallery를 생각해보면, photo, album, gallery와 같은 섹션이 있을 수 있다. 그리고 SNS는 post, user, newsfeed와 같은 슬라이스가 필요할 것이다.

밀접하게 관련된 부분들은 구조적으로 디렉토리내에서 그룹화되어있지만, 다른 슬라이스와 같은 격리 규칙을 준수해야하며, 이 디렉토리에 있는 코드는 직접적으로 공유되면 안된다.

Segments

각 슬라이스는 세그먼트로 구성된다. 세그먼트는 기술적 목적에 따라 슬라이스 내의 코드를 나누는데 도움이 되는 작은 모듈이다. 팀의 합의에 따라 세그먼트는 구성과 이름이 결정된다. 가장 일반적인 세그먼트는 ui, model(store, actions), api, lib(utils/hooks) 이다.
providers

  • Api : 서버 요청
  • UI : 슬라이스의 UI 컴포넌트
  • Model : 비즈니스 로직, 즉 state와의 상호작용. 예를들어 action, selector가 해당된다.
  • Lib : 슬라이스 내에서 사용되는 보조 기능

FSD 예시(SNS 애플리케이션-글카드)

  • App : routing, store, global styles 설정이 있다.
  • Pages : 앱의 각 페이지에 대한 라우팅 구성요소가 포함되어 있으며, 대부분 구성이며, 로직은 거의 없다.
  • Widgets : 백엔드의 관련 호출에 연결되어 있는 content와 interactive 버튼이 조립되어 있는 post card가 있다.
  • Features : 카드의 상호작용(좋아요 버튼)와 이러한 상호작용을 처리하는 로직을 포함한다.
  • Entities : 콘텐츠와 인터렉티브 요소를 위한 slot이 있는 card의 shell을 포함한다. 글 작성자를 나타내는 tile도 여기에 있지만 다른 슬라이스의 entities에 있다.

Public API

Pasted Graphic 5
각 슬라이스와 세그먼트는 public API를 가진다. public API는 index파일이며, 이 파일을 통해 필요한 기능만 외부로 내부내고 불필요한 기능들은 격리할 수 있다. Index 파일이 진입점 역할을 한다.

Public API는 import와 export로 단순하게 작동하므로 애플리케이션을 변경할때 코드의 모든곳에서 import를 변경할 필요가 없다.
export { Title } from

규칙

  1. Access Control
    Public API는 모듈의 콘텐츠에 대한 접근을 제어해야 한다. 애플리케이션의 다른 부분은 public API에 표시된 모듈 엔티티만 접근할 수 있다. 표시되지 않은 모듈 내부부분은 모듈 자체만 접근할 수 있다.
    Pasted Graphic 6
  2. Sustainability for changes
    public API는 모듈 내부의 변경사항에 대해 지속가능해야 한다. 즉 내부 구조의 변경이 public API의 변경으로 이어지면 안된다.
    Pasted Graphic 7
  3. Integrability
    publicAPI는 쉽고 유연한 통합이 가능해야 한다. 나머지 애플리케이션에서 사용하기 편리해야 한다.

단점

  • 대부분의 인기있는 번들러에서, re-exports때문에 code-splitting이 잘 작동하지 못하는데, 이것은 이 접근방식으로 tree-shaking을 하면 모듈의 일부가 아닌 전체 모듈만 버리는 것이 안전하기때문이다. 예를들어, authModel을 page model로 import 하면, AuthForm 컴포넌트 페이지에서 아용되지 않더라도, 페이지 청크안에 들어간다.
  • 결과적으로, 브라우저는 “for the company” 번들에 포함된 모든 모듈을 포함하여 그안에 있는 모든 모듈을 처리해야하므로 청크의 초기화 비용이 많이 든다.

해결방법
webpack을 사용하면 re-exports 파일이 부작용이 없는것으로 표시할 수 있으므로 이러한 파일로 작업할때 webpack이 공격적인 최적화를 사용할 수 있다.

Deeper into architecture

Abstraction and business logic

계층이 높은 레이어일수록 특정 business node에 더 종속이 되고, 더많은 business logic이 포함된다. 계층이 낮은 레이어일수록 추상화 수준이 높고, 재사용성이 높고, 레이어 자체의 자율성이 적다.
ENTITIES

How does FSD solve the problem?

FSD의 과제중 하나는 느슨한 결합과 높은 응집력을 달성하는 것이다.
OOP에서는 다형성(polymorphism), 캡슐화(encapsulation), 상속(inheritance) 및 추상화(abstraction) 와 같은 개념을 통해 이런 문제를 해결해왔다. 이러한 개념들은 코드의 격리성, 재사용성 및 다양성을 보장하고 이를 통해 컴포넌트나 기능을 사용하는 방법에 따라 다른 결과를 얻을 수 있다.

FSD는 이러한 원칙들을 프론트엔드에 적용하는데 도움을 준다.
추상화와 다형성은 레이어를 통해 이루어진다. 하위레이어는 추상적이기 대문에 상위 레이어에서 재사용할수 있으며, 조건에 따라 parameter나 props에 의해 지정된 컴포넌트나 기능들이 다르게 작동할 수 있다.
캡슐화는 public API를 통해 이루어지며, 이는 필요하지 않은 부분을 외부로부터 슬라이스와 세그먼트 안으로 분리한다. 슬라이스의 내부 세그먼트에 대한 접근은 제한되며, public API는 슬라이스 또는 세그먼트에서 기능 및 컴포넌트에 접근할 수 있는 유일한 방법이다.
상속 또한 레이어를 통해 달성된다. 계층이 높은 레이어가 하위 레이어를 재사용 할 수 있다.

Comparison with the classic architecture

클래식한 아키텍쳐에 명확한 표준은 없지만 일반적으로 다음과 같은 형식을 볼 수 있다.
assets
클래식한 아키텍쳐의 가장 큰 단점은 컴포넌트간의 암묵적인 연결과 모듈의 복잡성때문에 프로젝트를 유지 관리하기가 어렵다는 것이다. 따라서 프로젝트가 계속 진행함에 따라 아키텍쳐가 엉망이 될 수 있다.
따라서 클래식한 아키텍쳐는 지속적인 유지관리나 하위 프로젝트가 없는 소규모 프로젝트에 적합하다.

FSD는 concept과 standard 때문에 기존 아키텍쳐의 문제를 방지한다. 하지만 FSD로 작업하는 개발자는 클래식한 아키텍쳐를 다룰때보다 더 높은 이해도와 기술 수준을 필요로 한다. 왜냐면 FSD를 사용할때 발생하는 코드의 문제점과 개념에서 벗어난 부분들이 즉시 드러나기 때문에 나중이 아니라 지금 당장 해결해야 되기 때문이다.

Comparison with simple modular architecture

간단한 모듈식 아키텍쳐에는 몇가지 단점들이 있다.

  • 기능을 어떤 모듈이나 컴포넌트에 넣을지 명확하지 않을때가 있다.
  • 다른 모듈내에서 모듈을 사용하는 것에 어려움이있다.
  • Business entities를 저장하는데 문제가 있다.
  • 글로벌 함수의 암시적 종속성으로 인해 구조가 복잡해진다.

복잡하거나 중간정도의 복잡한 프로젝트에서는 단순한 모듈식 아키텍쳐보다 FSD를 선호해야 한다. FSD는 많은 근본적인 아키텍쳐들의 문제를 해결하면서 단점도 거의 없다.
단순성과 개발 속도측면으로 본다면 간단한 모듈식 아키텍쳐가 더 유리할 수 있다. MVP가 필요하거나 수명이 잛은 프로젝트를 개발하는 경우에는 FSD보다 유리하지만 그 외의 경우에는 FSD가 더 바람직하다.

Advantages and disadvantages of architecture

장점

  • Uniformity(통일성) : 코드는 영향력 범위(레이어), 도메인(슬라이스), 기술적 목적(세그먼트)에 따라 구성된다. 따라서 초보자도 쉽게 이해할 수 있는 표준화된 아키텍쳐가 만들어진다.
  • Controlled reuse of logic(로직의 제어된 재사용) : 각 아키텍쳐 컴포넌트는 목적과 예측가능한 종속성이 있다. 이를 통해 DRY 원칙을 따르는 것과 적응 가능성 사이의 균형을 유지할 수 있다.
  • Stability in face of changes and refactoring(변경 및 리팩터링에 대한 안정성) : 특정 레이어의 모듈은 같은 레이어 또는 그 위의 레이어에 있는 다른 모듈을 사용할 수 없다. 이를 통해 예기치 않은 결과 없이 격리된 수정이 가능하다.
  • Orientation to business and suers needs(비즈니스 및 사용자 요구사항에 대한 오리엔테이션) : 앱이 비즈니스 도메인으로 나뉘면 코드를 탐색하여 모든 프로젝트 기능을 발견하고 더 깊이 이해할 수 있다.

단점

  • 다른 많은 아키텍처 솔루션들에 비해 높은 진입 장벽이 있다.
  • 인식, 팀 문화 및 개념 준수가 필요하다.
  • 도전 과제와 문제를 나중이 아닌 즉시 해결해야 한다. 코드 문제와 개념에서 벗어난 부분을 즉시 확인할 수 있다. (장점으로 볼 수 있음)

Conclusion

FSD는 프런트엔드 개발자가 알고 사용할 수 있는 흥미롭고 가치 있는 발견이다. FSD는 팀에 유연하고 표준화되며 확장 가능한 아키텍처와 개발 문화를 제공할 수 있다. 하지만 이 방법론의 긍정적인 측면을 활용하려면 팀 내에서 지식, 인식 및 규칙이 필요하다.

FSD Example. Github Client
FSD 공식문서

profile
프론트엔드 개발자