만약 FSD 아키텍처가 궁금하다면 이 글을 참조하세요

FSD 아키텍처 OOP의 장점을 프론트엔드로!

 

FSD 아키텍처, OOP의 장점을 프론트엔드로!

기존의 기능 분할 설계(Feature-Sliced Design, FSD) 아키텍처 FSD는 다형성(polymorphism), 캡슐화(encapsulation), 상속(inheritance) 및 추상화(abstraction) 와 같은 개념을 프런트엔드에 적용하는 데 도움을 줍니다.

curt-poem.tistory.com

 

저는 싸피에서 프로젝트를 진행하면서 불편한 점을 하나 느꼈습니다. 바로 프로젝트의 폴더 구조였습니다. 기존에 진행하였던 프로젝트에서는 강의에서 들었던 방식과 유사한 구조를 만들었습니다. assets, components, page, store, util로 나누어진 였습니다. 이런 구조를 사용한 이유는 단순한 구조로 쉽게 사용할 수 있기도 했었고 굳이 폴더 구조에 대해서 오래 생각하고 싶은 마음도 없엇기 때문었습니다. 다만 사용하면서 파일을 새로 만들 때나 일을 찾을 때 불편함을 느꼈습니다. 개인적인 생각으로 그 이유는 다음의 두 가지 때문이었습니다.

  1. 디렉토리가 필요 이상으로 깊어져 파일에 접근하기가 번거로웠습니다.
  2. 어떤 폴더에 어떤 파일이 있는지 쉽게 알 수가 없었습니다.
  3. 컴포넌트에서 사용하는 API를 수정해야될 때 util폴더까지 찾아가야 했습니다.

어떻게 해야 두 가지의 불편함을 해소할 수 있을까요? 바로 폴더의 구조를 명확하기 하기입니다. 이렇게 한다면 프로젝트를 더 쉽게 관리할 수 있을 것입니다. 폴더의 구조를 명확하게 해 파일이 있어야 할 위치를 명확히 지정해둔다면 파일을 저장할 위치를 생각하거나 파일을 찾는데 낭비하는 시간이 줄어들 것입니다.


프로젝트 폴더의 구조를 명확하게 정하기에 앞서 어떤 조건이 필요한지 생각해봅시다. 모듈 간의 느슨한 결합과 높은 응집력을 가지며 확장이 쉬운 아키텍처가 좋을 것입니다. 그리고 해당 아키텍처를 아는 사람이라면 바로 사용할 수 있을 정도로 명확하면 더 좋겠죠. 구글을 통해 몇몇 아키텍처를 찾아보고 (번역) 기능 분할 설계 - 최고의 프런트엔드 아키텍처라는 글을 읽고 FSD라는 아키텍처를 적용해보기로 했습니다. 디렉토리의 깊이도 제한되며, 각 레이어마다 사용처가 정해져있는 것이 편해보였기 때문입니다. 하지만 이는 대규모 프로젝트에 적합해 보였으며 제가 진행하려는 (상대적으로 작은)프로젝트에 사용하기 위해서는 고칠 필요가 있어보였습니다. 그럼 제가 어떻게 FSD를 축소하여 수정하였는지 보실까요?

 

레이어 수정하기

현재 프로젝트의 초기 설정만 마친 상태이므로 구조가 변경되지 않을 것이라는 보장은 없지만 현재 상태를 기준으로 설명드리겠습니다.

FSD에는 최대 7개나 되는 레이어를 사용할 수 있습니다. 제가 진행하려는 프로젝트의 경우 이 모든 레이어를 사용할 필요가 없었습니다.

필수적인 레이어인 app과 shared, 그리고 pages를 사용하기로 하고 추가적으로 componets 레이어를 사용하기로 했습니다. 여기서 page를 RN 프로젝이트에 맞게 screen으로 수정하고 components는 features와 entities를 합친 레이어로 간주하였습니다. widget을 어떻게 사용할지에 대해 고민하였는데 프로젝트 크기가 작아 스크린의 수가 많지 않았고 widget의 역할을 screen에서 처리해도 복잡하지 않을 것 같아 widget을 따로 빼지 않았습니다. 결과적으로 레이어 단계의 분기는 기존의 방법과 같아보이지만 안의 내용물이 크게 달라진 모습이 되었습니다.

app

app에는 navigation만이 위치해있습니다. reactNavigation 라이브러를 사용하기 위한 슬라이스입니다. 전체 스크린을 이동할 수 있는 bottom-navigation 하나와 4가지 주요 스크린에서 이동이 가능한 native-stack-navigation을 위한 파일을 4가지 두었습니다. 각 스크린 네비게이션의 크기가 이미 작음에도 불구하고 따로 둔 이유는 네비게이션이나 라우터를 추가할 때 같은 줄을 수정하여 발생하는 git conflict를 없애기 위함입니다. 추가적으로 각 진입점이 되는 페이지만 관리하면 되기 때문에 네비게이션 관리가 편해질 것 같았습니다.

 

전역 스타일과 관련된 색상 상수들을 App 레이어의 constant 폴더에 위치하도록 두었습니다.

 

전역상태 관리를 위해서는 zustand를 사용하고 zustand는 provider 없이 동작하기 때문에 관련 설정은 app에 존재하지 않습니다.

 

tanstackQueray의 프로바이더는 app레이어의 app.tsx에 바로 추가해주었습니다. 이때 queryClientsms tanstackQueary의 전역 설정과 관계된 부분이고 하위 레이어인 components 내부에서 사용이 가능해야되므로 shared에 위치합니다.

 

app의 (Storybook 명령어 설정을 위한 최상위 App.tsx를 제외한)최초 진입점은 app.tsx로 이름을 설정하여 기존의 app.tsx와 같다는 것을 분명히 하였습니다. 최상위에 존재하는 app.tsx가 app 슬라이스의 app.tsx를 import하여 사용합니다.

screens

screens는 비지니스 로직에 따라 구분하였습니다. bottom-navigation에서 설정한 진입점이 되는 주요 스크린을 기준으로 4개의 슬라이스를 만들고 각각의 스크린을 슬라이스 내부에 위치시킬 것입니다. 기능별로 나누어지는 폴더 안에 여러 개의 스크린 파일이 들어갈 것입니다.

components

components는 실제의 기능이 수행되는 로직과 UI를 세그먼트로 구분하여 위치시키도록 하였습니다. 먼저 componetnts 안에 example이라는 슬라이스가 있을 것입니다. 이 슬라이스는 하나의 기능을 담당하게 되며, components 안의 다른 슬라이스를 사용할 수도 있습니다. 만약 해당 슬라이스가 스크린에서 사용되어야 한다면 index.tsx를 통해 중계되어 내보내질 것입니다.

 

슬라이스는 크게 기능이 수행되는 기능 세그먼트, UI를 담당하는 UI 세그먼트, 그리고 백엔드 서버에 요청을 보내는 API 세그먼트와 타입을 선언하는 type 세그먼트로 구성됩니다. 필요에 따라 필요한 상수인 consts, 여기에서만 사용되는 라이브러리나 설정 등을 담당하는 lib 세그먼트가 추가될 수도 있습니다.

 

기능 세그먼트는 기능 담당에 더해 해당 슬라이스 밖으로 내보내지는 세그먼트가 됩니다. 이름이 widget이나 feature 등 기존의 fsd 아키텍처와 다른 이유는 동료들이 해당 폴더 구조 사용에 익숙하고 역할도 비슷하기 때문입니다. 다만 슬라이스와 세그먼트로 나누어지는 것은 기존의 방식과 크게 다른 점입니다.

shared

벌써 마지막 레이어입니다. 전역에서 사용할 공통 컴포넌트 그리고 라이브러리들의 전역 설정이 여기에 정의됩니다. 애플리케이션 전반에서 사용되는 axios의 인스턴스, tanstackQueary의 QueryClient, 그리고 전역 상태 관리를 위한 zustand의 스토어들이 여기서 설정됩니다.

 

라이브러리는 각각의 슬라이스로 나누어져 들어갑니다. axios, tanstackquery, zustand가 위치하고 그 내부에 세그먼트가 위치합니다. zustand가 여러 개의 store로 나누어질 수 있고 각 store는 다른 파일로 저장될 것입니다.

여기도 마찬가지로 index.ts가 있습니다.

그 외 추가사항

 

각 세그먼트에는 index.ts를 만들어 모든 스크린을 여기서 중계하여 내보내기 때문에 세그먼트 외부에서 세그먼트를 사용하는 레이어는 캡슐화된 세그먼트를 볼 수 있습니다. 각각의 레이어 내부에 있는 index.js 혹은 index.ts 파일을 사용하는 것은 상위 레이어여야 합니다. 동일 레이어에서 index.ts가 내보낸 코드 불러온다면 번들링 시점에서 상호 참조 오류가 발생합니다.

 

test 코드는 테스트하고자하는 각각의 컴포넌트 혹은 페이지와 같은 디렉토리에 위치시키기로 하였습니다. 어떤 기능을 테스트할지 명확히 알 수 있고 프로젝트의 크기가 크지 않으며, 잘 구조화되어 있어 test를 한 곳에 몰아넣는 것보다 더 편할 것이라고 판단하였기 때문입니다. jest를 사용하기 때문에 테스트 코드의 위치는 문제가 되지 않았습니다.

 

components 레이어의 각 슬라이스는 UI 세그먼트를 따로 가지기 때문에 스토리북 사용하기 편할 것으로 생각됩니다. 스토리북 코드들은 루트 디렉토리에 있는 .storybook/stoires 폴더에 위치하도록 결정하였습니다. 또한 스토리북은 RN에서 사용할 때 기존의 ReactNative와 달리 기본적으로 명령어가 분리되어 있지 않아 불편을 해소하기 위해 개발 과정에서 명령어에 따라 스토리북을 실행할지 애플리케이션을 실행할지 나누는 것을 How to swap between React Native Storybook and your app를 참조하여 설정하엿습니다. npm start는 기존 애플리케이션을 실행, npm storybook은 스토리북을 실행합니다.

 

이외에도 expo기반 RN 프로젝트에 jest를 적용하는데 있어서 오류로 시간을 많이 소모했었는데 트러블 슈팅으로 글을 올릴 예정입니다.

 

PS. 제가 FSD를 수정한 뒤의 폴더 구조는 싸피 수업 중에 학습한 내용에서 크게 바꾸지 않았고 일반적인 프로그래밍 강의에서 사용하는 모습과 비슷하기에 어렵지 않게 사용할 수 있을 것입니다. 아래의 링크를 누르면 레포지토리로 이동할 수 있습니다. 예시도 작성해 놓았으니 참고하세요

 

GitHub - Dohun-choi/Customized-FSD-For-small-RN-Project: EXPO기반 RN 프로젝트에 FSD를 최대한 쉽게 바꾸어 적용

EXPO기반 RN 프로젝트에 FSD를 최대한 쉽게 바꾸어 적용해 보았습니다. Contribute to Dohun-choi/Customized-FSD-For-small-RN-Project development by creating an account on GitHub.

github.com

 

썸네일: Microsoft copilot

+ Recent posts