코딩하는 고릴라

[FE] FSD 아키텍처를 활용한 디렉토리 구조 구성 본문

Project/Pennypal

[FE] FSD 아키텍처를 활용한 디렉토리 구조 구성

코릴라입니다 2024. 4. 5. 14:16
반응형

🐶 WHY

기존 프로젝트에서는 디렉토리 구조를 크게 [assets / pages / components]로 구성하였습니다. pages 폴더 내부에는 URL 라우팅에 따라 출력될 페이지들을, components 폴더 내부에는 해당 pages 내부에 들어갈 컴포넌트들을 작성했습니다. 이 과정에서 UI와 로직을 담당하는 함수들을 분리해놓지 않아 한 파일 내에 너무나도 많은 코드들이 얽혀있어 필요한 부분을 찾는데 다소 어려움을 겪었습니다. 이와 같은 어려움을 해소하기 위해 어떤 방법이 있나 찾아보던 와중 FSD 아키텍처를 알게 되었고 이를 간소화하여 프로젝트에 적용해보았습니다.


🦍 WHAT

FSD(Feature-Sliced Design, 기능 분할 설계) 아키텍처는 크게 Layers, Slices, Segments 층으로 구성되어 있습니다. 각각의 계층별로 폴더를 구성하여 작업하는 방식인데, 이번 프로젝트에서 FSD를 적용하며 본래의 FSD의 모습과는 다소 차이가 생겼습니다. FSD 아키텍처에 대한 자세한 설명은 아래에서 확인할 수 있으니 이에 대한 설명은 각설하고 프로젝트에 적용시킨 모습을 기술하겠습니다.

 

(번역) 기능 분할 설계 - 최고의 프런트엔드 아키텍처

기능 분할 설계(Feature-Sliced Design, FSD) 아키텍처의 개념과 이 아키텍처 방법론이 해결하는 문제를 이야기하고, FSD를 기존 아키텍처 및 모듈식 아키텍처와 비교한 뒤 장단점에 대해 소개합니다.

emewjin.github.io


🐹 HOW

FSD : Layers 계층 - Slices 계층 - Segments 계층

 

Layers 계층은 위와 같이 구성했습니다.

 

- app: 최상위 계층으로서 어플리케이션의 전반적인 리듀서, 라우터 설정을 담고 있는 파일을 'app' 폴더 내부에 두었습니다.

 

- pages: URL 라우팅에 의해 출력될 페이지 컴포넌트와 이 페이지를 이루는 컴포넌트들을 담고 있습니다.

 

- entities: 컴포넌트에서 가져다 쓸 데이터를 담았습니다. 이번 프로젝트에서는 타입스크립트의 Type 데이터들 일부만 담고 있어 그 효용성을 크게 느끼지 못했으나 다음 프로젝트에서는 보다 적극적으로 활용해 UI를 구성하는 컴포넌트 코드를 보다 간결히 유지해보고자 합니다.

 

- shared: 어플리케이션 전반적인 부분에서 가져다 쓸 수 있는 UI, 함수, API 설정등을 담고 있습니다. 

 

- styles: SCSS를 활용한 스타일링에 필요한 파일들을 담았습니다. 7-1 패턴을 활용하였으며 이에 대해서는 다른 게시글에서 설명하도록 하겠습니다.

 

- assets: 프로젝트에 사용되는 폰트 파일들을 담았습니다. 해당 폴더는 FSD와는 별개로 필요에 의해 작성한 폴더이며, CSS 파일에서 public 폴더 내에 있는 폰트 파일을 import 하는데 문제가 있어 의도치 않게 생겨난 폴더입니다. 이에 대해서는 추가 학습 후 보완 필요성을 느꼈습니다.

 

FSD 아키텍처에서 설명하는 7개의 레이어(app - processes - pages - widgets - features - entities - shared) 중 4개의 레이어를 사용하여 기본적인 틀을 잡았습니다.


FSD : Layers 계층 - Slices 계층 - Segments 계층

Slices 계층은 위와 같이 구성했습니다.

 

서비스에서 제공하는 각각의 기능 단위로 구분하여 지출에 관련된 내용, 금융에 관련된 내용 각각을 나누어 구조화했습니다.

위에서 pages 폴더 내 slices를 보여드렸지만, entities 폴더 내에도 위와 같이 동일한 slices들을 두었습니다.

또한 이 slices 계층에서 핵심적인 부분은 index.ts에 있습니다.

// index.ts

export * from '@/pages/main';
export * from '@/pages/expenditure';
export * from '@/pages/finance';
export * from '@/pages/market';

 

index.ts 파일 내에는 위처럼 각 slice에 포함된 내용들을 외부로 export 하는 역할을 담당하고 있습니다.

항상 index.ts 파일을 통해 상위 Layer에서 이를 가져다 쓸 수 있도록 캡슐화하는 역할을 담당하며, 똑같은 ui를 여기저기서 import 할 때 그 경로가 제각각 다르게 명시되는 일을 줄여 코드를 보다 깔끔히 유지할 수 있습니다.

 

@/pages/main/main.tsx 파일 내 Main 컴포넌트를 상위 레이어에서 임포트 할 시 다음과 같이 명시해주면 가능합니다.

import { Main } from '@/pages';

// 위 index.ts를 적용하지 않았을 경우
import { Main } from '@/pages/main/main.tsx'

FSD : Layers 계층 - Slices 계층 - Segments 계층

Segments 계층은 위와 같이 구성했습니다.

 

- api: 백엔드와의 통신을 위한 axios 함수들을 담아 놓았습니다.

- model: Market 페이지 내부에서 관리할 상태들을 다루는 redux, ui와의 상호작용을 위해 필요로 하는 함수들을 작성해두었습니다.

- ui: URL라우팅에 대응될 최상위 컴포넌트인 Market.tsx와 이 컴포넌트 내부에 들어갈 각각의 하위 컴포넌트들을 추가적인 폴더로 생성해 관리했습니다. FSD에서는 기본적으로 해당 컴포넌트들도 Layers 계층에서 다른 Layer로 분리하여 작성하는 것으로 이해했으나, ui segments 내에 컴포넌트들을 구성했을 때 개인적으로 더 편리하다고 느껴져 조금 수정된 구조를 채택했습니다.

 

기능적 요소, 시각적 요소들을 분리하여 새로운 파일로 관리하다보니 필요한 파일, 코드를 찾는데 훨씬 편리함을 느꼈습니다.


🐈 Result

- 구분할 부분들을 명확히 분리해 코드를 작성하니 파일 수는 많아졌으나 파일 내 코드는 보다 간결해졌습니다. 필요한 부분들을 파일명으로 쉽게 찾아낼 수 있어 긴 코드를 위에서부터 훑어 내려가며 찾는 일이 적어졌습니다.

- FSD는 규모가 큰 프로젝트에 유리하다고는 하나, 프로젝트를 진행하며 현업에서 적용해봄직한 아키텍처를 활용했던 부분이 생산성 향상까지 이어져 왜 정립된 아키텍처를 활용하는지 이해했습니다.

- 또한 이런 아키텍처를 무조건적으로 받아들여 똑같이 구성하는 것보다, 팀원들과의 합의를 통해 보다 편리한 디렉토리 구조를 유지하는 것 또한 중요함을 느꼈습니다.

반응형