🗂️ FSD 아키텍처 적용을 통한 기능 중심 설계 리팩토링
아키텍처의 중요성을 깨닫다
많은 학생 개발자들은 다양하고 깊은 개발 경험을 쌓기에 급급하다. 싱크스팟 프로젝트를 처음 개발할 때, 사용해 봤으니까 라는 이유로 고전적인 계층형 아키텍처를 활용해 설계했다. 기능이 고도화되고, 관리해야할 파일이 많아진 현재 시점에서 리팩토링이 필요하다는 것을 느꼈다.
문제상황, 변화의 필요성
기존 싱크스팟의 폴더구조는 고전적인 계층형 아키텍처를 기준으로 삼았다.
계층형 아키텍처는 명확한 표준은 없지만, 단순함과 역할기반 덕분에 많이 사용되고 있다. 싱크스팟에서는 프로젝트가 커지고, 코드를 리팩토링 할수록 각 기능에 해당하는 단위가 여러곳에 흩어져있다는 불편함이 생겼다.
- 레이어 + 기능 분산: 하나의 기능이 components, pages, queries, mutations, types, constants 등 여러 위치에 흩어져 있다.
- 하나의 도메인/기능에 대한 로직은 여러 폴더를 오가며 의존성과 연관요소를 확인해야하는 부분에서, 기능 단위 관점에서 책임이 분산되어 있다.
- 디렉토리 간 이동이 잦아지고, 관련 파일 소속을 한눈에 보기 어렵다.
- 유사 기능 도입 및 변경 시 관계된 코드묶음이 물리적으로 떨어져 있다. 이는 `응집도 저하`를 발생한다
책임 기능이 반복됨에 따른 중복 구조로 발생하는 문제점이 있다.
기능 중심이 아닌, 역할 중심 구조화로 인해 유지보수성과 코드 응집도가 저하된다.
- 경로 탐색 비용 증가 : 기능 관련 로직을 파악하기 위해 여러 디렉토리를 이동해야 한다.
현재 역할 중심 폴더 구조
src/components/location/AddressDisplay.tsx
src/hooks/location/useAutoScroll.ts
src/apis/location/deletePlaceDelete.ts
FSD 아키텍처의 기능 중심 폴더 구조
📂entities/location/
┣ 📂api
┣ 📂model
┣ 📂types
┣ 📂lib
┗ 📂constants
- 코드 모듈화 단위 : 하나의 폴더에 몇백줄로 작성되어있는 코드 -> 기능 단위 캡슐화를 통해 재사용성, 코드응집력 향상
🚨 기존 아키텍처 분석 - 무엇이 문제였나?
src
┣ apis
┃ ┣ 도메인
┃ ┗ instance.ts
┣ assets
┣ components
┃ ┣ auth
┃ ┃ ┣ constants
┃ ┃ ┃ ┗ index.ts
┃ ┃ ┣ oauth
┃ ┣ common
┃ ┣ error ┣ boundary
┃ ┣ layout
┃ ┗ 도메인
┣ constants
┃ ┣ api.ts
┃ ┗ path.ts
┣ hooks
┃ ┣ 도메인
┃ ┗ 공통
┣ pages
┃ ┗ 도메인
┣ routes
┣ state
┃ ┣ mutations
┃ ┃ ┗ 도메인
┃ ┣ queries
┃ ┃ ┗ 도메인
┃ ┗ store
┣ styles
┣ types
┃ ┣ 도메인
┃ ┗ 전역
┣ utils
┣ App.tsx
┣ main.tsx
┗ vite-env.d.ts
위 폴더구조에서 확인할 수 있듯이, 도메인 즉 기능이 반복된다. 따라서 하나의 기능이 전체적으로 수정된다면 모든 파일을 방문해야 한다.
`src/page/도메인` `src/type/도메인` `src/api/도메인` `src/state/mutations/도메인`
하나의 비즈니스 로직이 여러 레이어에 분선되어있어 의존성이 혼재되어 있었다. 작은 단위의 테스트를 진행하거나 유사기능을 여러 폴더에 중복되게 생성하였다.
❓FSD 아키텍처 또한 반복되는 세그먼트(ui, api, model) 을 가지지 않는가? 는 의문이 들 수 있다.
FSD 도입은 단순히 폴더 중복을 줄이자는 논점이 아니라, 기능 중심으로 구조를 재조직해 유지보수성과 코드 응집력을 높이기 위한 설계 접근이다. 폴더 구조 중복 해소는 기능적 관점에서 그에 따라오는 부수적인 이점에 가깝다. 중요한 것은 폴더명이 반복되는지 여부가 아니라, 그 반복이 `기능 중심`인지 `역할 중심`인지에 따라 구조적 응집도가 달라진다는 점이다. FSD의 기능(도메인) 단위의 캡슐화와 책임 집중은 기능 단위의 작업으로 개선할 수 있다.
또한, 파일과 폴더의 목적이 부합하지 않다고 판단했다.
1. constants, hooks, utils 의 위치
src/constants, src/utils 내부의 파일은 공통 전역에서 사용되는 함수를 모아두었다.
기능(도메인)마다 필요한 함수는 `src/components/time/utils/timeFormat.ts` `src/components/auth/constants/index.s` 등 컴포넌트 하위에 위치해있다.
🚫 해당 파일은 컴포넌트에 해당하는 것이 아니다. 유틸에 해당하는 동작을 수행하기 때문에, 현재 컴포넌트 폴더에 위치한 것은 적절하지 않다고 판단했다. time 뿐만 아니라 기능(도메인)에 사용되는 다른 함수도 컴포넌트 폴더에 위치하고 있어 문제라고 생각한다.
2. 페이지, 컴포넌트 모듈화를 통한 레거시 분해
기존에는 몇몇 페이지 코드에 모든 로직이 들어있었다. [GITHUB]
이를 컴포넌트로 분리해서 리팩토링 했다. [GITHUB]
기능 단위 컴포넌트로 구분했을때, 여러 컴포넌트가 구성되게 된다. 이때 각 컴포넌트 분리 기준은 관심사, 재사용성, 영역 등이 있다.
하나의 기능을 수정하려면 여러 계층에 걸쳐서 수정해야하는 변경전파 범위가 크고, 코드 시나리오 기반으로 추적하거나 재사용하는데 비효율적이다. 아토믹, FSD 등 다른 아키텍처에서 지향하는 책임 단위의 모듈화를 구성하기에는 어려움이 있다. 컴포넌트 경계의 기준이 모호하기도 하기 때문이다.
또한 한 파일에 모든 로직을 모아놓은 개발방식은 유지보수성을 저해하고, 협업에서도 불리하게 적용될 수 있다.
3. 의존성 결합도 증가
모든 폴더가 서로 의존할 수 있어 의도치않은 순환 참조가 발생하거나, 코드 수정으로 인한 사이드 이펙트를 예상하기 어렵다. 의존성 방향이라는 개념이 없기 때문에 불필요한 결합도가 점차 증가할 수 밖에 없다.
이를 정리할 수 있는 적절한 규칙이 필요했다.
여러 아키텍처 개선 방법을 고민하다
싱크스팟 프로젝트는 2차 스프린트가 끝나고, 개인 코드 리팩토링과 Sentry 로 모니터링하여 에러 발생 시 해결하는 운영 과정을 진행 중이다. 즉 현재 급한 기능 HotFix 는 없다. 지금이 제대로 된 아키텍처를 도입할 적절한 시기라고 생각했다. 초기 도입 후 적응 + 코드 리팩토링 병행하며 구조를 더 탄탄히 다질 수 있는 기회였다.
- Atomic Design 아토믹 디자인패턴 : UI 구성 단의에 대한 명확한 계층화. 비즈니스 로직/기능 단위 구분이 어렵다.
- Domain-Driven Design 도메인 중심 디자인 패턴 : 도메인/유스케이스 중심. 대규모 도메인 복잡성에 유리하고, 오버엔지니어링 위험이 있다.
- 헥사고날 아키텍처 Hexagonal : 도메인 로직을 중심으로 내부와 외부 어댑터를 분리한다. 위 문제를 해결하지만, 프론트엔드에 적용 시 UI 와 분리된 로직으로 인해 불필요한 응집도 저하, 과도한 추상화를 할 위험이 있다.
- Micro Forntends : 여러 앱을 팀 단위로 분산 개발 배포한다. 병렬 개발에 최적화 되어있으며, 대규모 조직에 적합하다.
- Feature-Sliced Design FSD : 도메인 중심 수직 분리, 경계가 명확하다. 기능단위 확장이 잦은 팀이 주로 사용하며, 초기 설계 진입장벽 있다.
💡 FSD 를 싱크스팟에 도입하자!
처음에는 스토리북이 적용되어 있기 때문에 아토믹 디자인과의 조합이 기대되었다. 그러나 아토믹 디자인은 UI 가 중심이 되었는데, 싱크스팟에는 전문적인 디자이너가 부재했다.. 원하는 단위로 화면을 다시 만들거나 구성해달라고 요청할 수 없었다. 또한 원자 라는 단위로 관리하기에는 현재 프로젝트 코드가 크게 작성되어 있었다.
그 다음으로 고려한 아키텍처가 FSD 이다. 싱크스팟은 MVP 가 명확하다. 중간지점 찾기, 장소투표, 시간투표, 이를 진행하기 위한 온보딩 도메인, 모임 관리와 더불어서 유저 관리하는 기능이다. 이러한 코드 및 기능 작성은 도메인 단위로 명확히 분리되어있다. 기능 추가 및 변경 시 응집도를 더 많이 챙길 수 있는 구조 변경이 필요했다. 초기 도입 비용이 많지만, 이후 점진적으로 도입할 수 있어 현재 운영관리중인 프로젝트 상황에 적절하다고 판단했다.
팀원과 의견을 주고받은 discussions 에서 일부를 첨부한다. 아래와 같은 위험이 있지만, 위에 작성한 확장성과 문제해결에 필요하다고 느끼게 되었다.
폴더구조에 대해서 관심을 가지고 개선하려고 노력하신 점 감사합니다. 사실 개발초기부터 리팩토링을 하는 지금까지 초기 폴더구조가 이어져오던터라 변경하는 것에 걱정이 있었어요. 바뀐 폴더구조에 대해 적응하는것도 하나의 비용이라고 생각했고, 지금 상황에 꼭 필요한가?라는 의문도 있었거든요. 또 리팩토링 과정도 파일에 대한 코드 리팩토링이 대부분이었고, 별다른 기능추가가 없었기 때문에 폴더 구조를 바꾸는 것에 대한 의구심이 있었어요.
하지만 말씀해주신 확장성을 고려한다면 폴더구조를 개선하는 것도 좋아보입니다.
FSD 아키텍처가 무엇인가?
기능 중심 구조는 `느슨한 결합` `높은 응집력`을 과제로 한다.
FSD 의 레이어 : 추상화, 다형성을 달성한다.
- 낮은 레이어는 추상화 되어있어 높은 레이어에서 재사용한다.
- 단방향 계층 의존성 원칙을 통해 상속을 만족한다.
FSD 의 슬라이스, 세그먼트 : 캡슐화를 달성한다.
- 외부에서 필요하거나, 필요하지 않은 것을 구분하여 공개 API 를 export 한다.
- 슬라이스의 내부 세그먼트에 직접적으로 접근하지 않고, 공개 AI 를 통해 접근하여 코드를 명확히 격리한다.
3가지로 단계가 구분된다.
레이어 Layers : app, pages, widgets, features, entities, shared
최상위 디렉토리이다. 레이어의 수는 최대 7개 이고, 이 레이어 중 일부만 선택해서 구성할 수도 있다.
- app : 애플리케이션 로직이 초기화 되는곳
- provider, router, 전역 styles, 전역 layout 등을 이곳에서 정의한다.
📦app
┣ 📂layout ┣ Layout.tsx, index.ts
┣ 📂providers
┃ ┣ APIErrorBoundary.tsx
┃ ┣ APIErrorFallback.tsx
┃ ┗ index.ts
┣ 📂routes
┃ ┣ 📂guards
┃ ┃ ┣ PrivateRoute.tsx
┃ ┃ ┣ PublicRoute.tsx
┃ ┃ ┗ index.ts
┃ ┗ AppRouter.tsx
┣ 📂styles
┃ ┗ global.css
┗ App.tsx
- processes : 단계별 등록 프로세스를 처리한다. 더이상 사용되지 않는다.
- pages : 애플리케이션의 페이지가 포함된다. 동일 또는 하위 레이어 (widgets 등)의 모임으로 구성될 수 있다.
📦pages
┣ 📂about
┃ ┣ 📂ui
┃ ┃ ┗ AboutPage.tsx
┃ ┗ index.ts
- widgets : 페이지에 사용되는 독립적인 UI 컴포넌트
📦widgets
┣ 📂about
┃ ┣ 📂model
┃ ┃ ┣ index.ts
┃ ┃ ┣ mobileTabOption.ts
┃ ┃ ┗ teamData.ts
┃ ┗ 📂ui
┃ ┃ ┣ 📂featureSection
┃ ┃ ┃ ┣ MidpointSection.tsx
┃ ┃ ┃ ┣ PlaceVoteSection.tsx
┃ ┃ ┃ ┗ TimeVoteSection.tsx
┃ ┃ ┣ AboutService.tsx
┃ ┃ ┣ Footer.tsx
┃ ┃ ┣ TabNavigation.tsx
┃ ┃ ┗ index.ts
- features : 비즈니스 가치를 전달하는 사용자 시나리오와 기능을 다룬다.
- entities : 비즈시트 엔티티를 나타낸다. 사용자 리뷰 댓글 등이 포함된다
features, entities 레이어는 선택적 레이어 이다.
- shared : 특정 비즈니스 로직에 종속되지 않은 재사용 가능한 컴포넌트와 유틸리티가 포함된다.
- UI 키트, axios 설정, 애플리케이션 설정, 비즈니스 로직에 묶이지 않은 헬퍼 등이다.
🚨 features VS entities 나누는 기준의 주관성 문제를 위한 규칙 설정
두 레이어의 명확한 기준과 비교가 어려웠다. 어떤 비즈니스 로직이 features 에 들어가야 하는지, entites 에 들어가는지 모호했다.
팀원은 아래처럼 의견을 내기도 했다.
features | entities |
UI, 사용자 상호작용에 집중 | 도미엔 중심의 데이터 처리 로직 |
그러나 두 레이어는 각자 다른 역할(슬라이스)를 가지기 때문에 features 레이어에서 api 를 사용하지 않는 방향은 어려웠다. 데이터 entites 정보를 features가 기능 로직으로 조합하거나 사용자의 동적 작업을 담당하기 때문이다.
둘을 명확히 구분할 수 있도록 아래 조건을 제시했다.
`entities api` : 기본적인 데이터 조회 `R`
`features api` : 동사로 표현되는 요청 `CUD` (ex. 게시물을 북마크한다, 메시지를 전송한다 등)
데이터를 다루는 방식 CRUD 의 동작에 한해서, 사용자와 상호작용이 필요한 CUD 의 작업을 features 레이어에 작성하자고 규칙을 지정했다. 도표화 하면 아래와 같다.
✅ Entities Layer 구분 기준
→ 아래 조건 중 하나라도 해당되면 entities에 배치
구분 기준 | 설명 |
핵심 비즈니스 도메인 API | 프로젝트의 핵심 기능을 구성하는 도메인 단위 API (예: 투표 결과, 사용자 정보 등) |
공통 재사용 가능성 | 여러 feature에서 공통으로 재사용되는 경우 (중복 방지를 위한 분리) |
단순 조회(R) 중심의 API | 기본적인 데이터 조회만을 담당하며, 복잡한 사용자 동작이나 흐름 제어 없음 |
복잡한 사용자 인터랙션이 아님 | 사용자 행위가 API 흐름을 제어하지 않고, 단순 렌더링이나 필터링 등 수동적 처리일 경우 |
✅ Features Layer 구분 기준
→ 아래 조건 중 하나라도 해당되면 features에 배치
구분 기준 | 설명 |
Entities 조합 및 흐름 제어 | 여러 entities를 조합해 비즈니스 로직을 수행하거나 흐름을 제어하는 경우 |
사용자 동작 중심 | 사용자 액션(클릭, 입력 등)에 따라 API 요청 흐름이 발생하는 경우 |
CUD 중심 동사 기반 API | 데이터를 생성(Create), 수정(Update), 삭제(Delete)하는 행위 중심의 API 처리 (ex. 장소 등록, 투표 등) |
인터랙션 제어 및 상태 변화 포함 | 비즈니스 로직에 따라 상태 변화 및 복잡한 UI 상호작용을 포함하는 경우 |
슬라이스 Slice : 비즈니스 엔티티
코드를 도메인 및 기능을 중심으로 그룹화 하는 것이다. 관련된 코드는 구조적으로 디렉토리 내에 그룹지을 수 있지만, 격리 계층 갭슐화 공개 규칙을 지켜야 한다.
page, widgets, features, entities 는 도메인 기능이 같아도, 다른 이름을 가질 수 있다.
📦page
┗ 📂profile
📦features
┣ 📂user
┣ 📂auth
┗ 📂favorites
📦entities
┗ 📂user
세그먼트 Segment : 목적(역할) 에 따라 슬라이스 내의 코드를 나눈다.
팀의 합의가 필요한 부분이다. 구성과 이름이 변경될 수 있다.
- api : 필요한 서버 요청
- UI : 슬라이스의 UI 컴포넌트
- model : 비즈니스 로직. 상태와의 상호작용. actions, selectors 등이 해당한다.
- lib : 슬라이스 내에서 사용되는 보조 기능
- config : 슬라이스에 필요한 구성값. 구성 세그먼트는 거의 필요하지 않다.
- consts : 필요한 상수
기존 고전적인 계층형 아키텍쳐에서 구분되어있는 역할을 위 세그먼트로 구분하였다.
기존 고전적인 계층형 아키텍처 | FSD 아키텍처 |
api/도메인 state/queries/도메인 state/mutations/도메인 |
api |
components/~.tsx | ui |
state/store/~ type/도메인 hooks/ 도메인 |
model |
components/도메인/utils | lib |
페이지네이션 limit, 쿼리 키, 차트 옵션 등 | config |
compoenents/도메인/constants 버튼 타입 enum, 탭 key, 에러 메시지 등 |
constants |
❓ FSD 규칙을 eslint 로 강제할 수 있을까
eslint 린트는 코드 품질을 위한 검사도구 이다. 이를 폴더를 만들 때에도 제한을 둘 수 있을까? 틀린 말이다.
정확히는 FSD 아키텍츠의 계층 규칙을 코드 내부에서 지켰나 확인하는 방법이다.
- 코드에서 사용하는 폴더에 대하여 import 문 규칙
- index 경유
- import 순서
- 계층 레이어 간 import 방향 제어
- slice 간 import 금지 (features/<A> 에서 features/<B> 접근 방지)
FSD 의 모든 규칙을 지정하고, 신뢰성과 안정성 있는 대표적인 FSD 플러그인은 찾지 못했다. -> eslint-plugin-import : 계층 단방향 import 규칙을 지정하는 라이브러리
또는 직접 코드로 작성하여, 레이어 간의 경우의 수를 차단하는 방법이 있다.
// 1. 레이어 간 import 순서 강제
'import/order': ['error', {
groups: [['builtin', 'external'], 'internal', ['parent', 'sibling', 'index']],
pathGroups: [
{ pattern: 'app/**', group: 'internal', position: 'before' },
{ pattern: 'pages/**', group: 'internal', position: 'before' },
{ pattern: 'widgets/**', group: 'internal' },
{ pattern: 'features/**', group: 'internal' },
{ pattern: 'entities/**', group: 'internal' },
{ pattern: 'shared/**', group: 'internal', position: 'after' },
],
alphabetize: { order: 'asc', caseInsensitive: true },
'newlines-between': 'always',
}],
// 2. import 시 절대경로 index.ts 통해서만 import 강제
'no-restricted-imports': ['error', {
patterns: [
// 내부 구조 직접 import 금지
{
group: ['features/*/*/*', 'entities/*/*/*', 'shared/*/*/*'],
message: '모듈 public API(index.ts) 를 통해 import 하세요',
},
{
group: ['state/**', 'store/**'],
message: '전역 상태는 직접 import 하지 마세요. features 또는 entities 단에서 사용하세요.',
},
],
}],
},
// 3. slice 간 import 금지
{
files: ['src/features/**'],
rules: {
'no-restricted-imports': ['error', {
patterns: ['features/*'],
}],
},
},
싱크스팟 프로젝트의 경우, 현재 마이그레이션 및 적용 초기 단계이기 때문에 구조에 대한 논의 이후 FSD 에 lint를 적용하기로 결정했다.
위 규칙의 경우에도, 기본적인 부분만 제한하고 유연하게 가져가는게 좋을 것 같다고 생각했다.
💬 FSD 아키텍처 - 싱크스팟 마이그레이션 ing...
FSD 는 초기 적용 비용이 높은 편이다. 특히 거의 모든 코드에서 참조하고 있는 shared 파일이 이동하면, 많은 양의 import 문이 수정되었다. 따라서 PR 단위가 커지며, 팀에서는 부정적인 경험이 쌓일 수밖에 없다. 이는 런닝커브를 유발 할 수 있다.
초기 app 레이어와 shared 레이어도 분류해서 작업하는 것을 추천한다.
초기 단계에서의 app, share 레이어의 변경사항을 아래 도표로 표현했다.
app 레이어 구성요소
프로바이더, 라우터, 전역 스타일, 전역 타입 선언 등
기존 | 개선 |
components/layout/… | app/layout/… → RoomLayout 의 경우 유저 feature 로 이동할 예정 |
components/error/boundary/… | app/providers/… |
→ app 레이어는 index 가 필요없지만, app/routes 에서 사용하기 때문에 export 를 모아서 작성하였음 | |
components/common/routes/privateRoute… | app/routes/AppRouter.tsx |
app/routes/guards/… | |
styles/global.css | app/styles/global.css |
src/App.tsx | app/App.tsx |
*개선점 : 컴포넌트에 해당하지 않는 layout, porvider, guards 등이 app 레이어로 위치 -> 기능에 따른 명확한 위치로 변경
shared 레이어구성요소
UI 키트, axios 설정, 애플리케이션 설정, 비즈니스 로직에 묶이지 않은 헬퍼
전역에서 재사용 가능한 컴포넌트와 유틸리티 포함
기존 | 개선 |
src/assets/… | shared/assets/… → 이미지, 폰트 공유 |
src/constants/.. | shared/constants/… → api, path |
src/utiles/… | shared/utils/.. → 전역 유틸리티 |
src/hooks/… , src/types/… | shared/hooks/… , shared/types/… |
src/components/common/… | shared/ui/… → 전역 컴포넌트 Button Input toast |
utils 의 renderShareButton.tsx 의 경우, entites/shareModal 으로 이동이 예상된다.
hooks, types 의 경우 초기 shared 에 포함시킨 후
page widgets feature 에 따라 구분되는 기능에 포함되는 타입을 이동시키는 점진적 개선방식으로 진행한다.
page, widgets 예시 작업 - About
about 구성은 해당 페이지이다.
Syncspot | 모두가 편하게 만나는 지름길
중간지점 찾기부터 시간/장소 투표까지 한 번에 해결하세요!
syncspot.kr
UI 위주의 작업이고, 작은 단위이기 때문에 초기작업과 함께 간단한 about 예시를 작성하였다.
page 레이어 구성요소
페이지들의 평면 목록(widgets)을 담고 있는 레이어 - widgets 의 조립만을 담당함
페이지 코드는 widgets 로 구성되어야 하고, api 등의 segements 요소는 widgets 로 변경 및 이동해야 한다.
기존 | 개선 |
src/pages/about/AboutPage.tsx | src/pages/about/ui/AboutPage.tsx → 한곳에서 모두 작성된 내용을 widgets 로 분리 |
src/pages/about/index.ts → 페이지 export |
widgets 레이어 구성요소
header 의 경우 추가 정리가 필요하다.
기존 | 개선 |
모바일 타입 상수 Footer 팀원 정보 데이터 |
widgets/about/model/mobileTabOption teamData → FSD 원칙에 따르면 widgets 는 model 슬라이스를 가질 수 없음. 그러나 widgets 내부에서만 사용되고, api 요청 (핵심도메인) 활용하지 않기 때문에 내부에 배치함 |
src/pages/about/AboutPage.tsx 페이지 파일에 모두 작성 |
widgets/about/ui/featureSection/MidpointSection PlaceVoteSection TimeVoteSection |
src/pages/about/AboutPage.tsx 페이지 파일에 모두 작성 |
widgets/about/AboutService Footer TabNavigation index |
components/layout/header components/users/… (menu 관련 파일) |
widgets/header/ui/… → 추후 feature, entites 재배치, components/users/… menu 관련된 부분 통합 |
👍 도입 후 얻은 성과, 인사이트
아직 논의중인 부분
- 다른 브랜치에서 적응 후에 develop 브랜치에 머지하자
- 런닝커브 때문에 적응될 때 까지 도입을 미뤘으면 한다.
- 기능별로 점진적으로 수정하자는 목적이다.
- 실제 개발환경에서 부딪힌다면 학습 속도가 향상될 것이다.
- Feature-Sliced Design: The Best Frontend Architecture 글에서는 문제를 나중이 아닌 지금 해결해야 한다고 한다.
- 런닝커브 때문에 적응될 때 까지 도입을 미뤘으면 한다.
However, when working with Feature-Sliced Design, problems need to be addressed "now" rather than "later." Issues in the code and deviations from the concepts become immediately apparent
- stories 테스트 코드의 위치
- 스토리의 경우, 도메인 운영과 별도의 문서 영역이기 때문에 FSD 외부에서 관리해야 한다.
- ✅`채택` ui 와 나란히 배치하면 작성이 필요한 컴포넌트를 즉각적으로 확인할 수 있다.(테스트코드와 유사한 장점)
- react-query 서버상태관리 코드의 위치
- state 레이어 생성 후, 모아서 관리
- 도메인(slices) 별 api segments 세그먼트에서 관리
- 현재 구조에는 state 폴더 안에 store 폴더로 클라이언트 상태가 포함되어있고, mutations, queries 폴더로 서버상태가 포함되어있다.
- 폴더 목적이 명확하지 않다고 생각되어, 2. 도메인의 api 세그먼트에 query 문 위치하는 방식을 제안했다.
부수효과
- 개발 경험
- 명확한 책임 분리로 인한 개발 속도 향상
- 스토리 테스트 작성의 용이성 증대
- 코드 품질 향성
- 일관된 프로젝트 구조
- 모드 모듈화 및 구조화로 인한 높아진 코드 재사용성
- 향상된 유지보수성
- 이외
- 팀 커뮤니케이션 개선 - 카카오톡 X 깃허브, Discussion, 슬랙 등의 업무 도구 활용
- MVP 비즈니스 도메인에 대한 이해도 증가