Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,137 +6,131 @@ sidebar_position: 4

## v2 도입 배경

**feature-slices** 개념은 2018년 [첫 발표][ext-tg-spb]된 이후, 다양한 프로젝트 경험과 커뮤니티 피드백을 거치며 발전해 왔습니다.
동시에 **[기본 원칙][ext-v1]**(표준화된 프로젝트 구조, 비즈니스 로직 우선 분리, isolated features, Public API)은 그대로 유지되었습니다.
**feature-slices** 개념은 2018년 [첫 발표][ext-tg-spb]된 이후 다양한 프로젝트 경험과 커뮤니티 피드백을 통해 지속적으로 발전해 왔습니다.
그 과정에서도 **[기본 원칙][ext-v1]**-표준화된 프로젝트 구조, 비즈니스 로직 기반 분리, isolated features, Public API—는 그대로 유지되었습니다.

하지만 v1에는 다음과 같은 한계가 있었습니다:
그러나 v1에는 다음과 같은 한계가 존재했습니다:

- 과도한 **boilerplate** 발생
- 추상화 규칙이 모호해 **코드베이스 복잡도** 상승
- 암묵적 설계로 **확장·온보딩 어려움**
- 과도한 **boilerplate** 발생
- 추상화 규칙이 모호해 **코드베이스 복잡도** 상승
- 암묵적 설계로 **확장/온보딩 어려움**

이러한 한계를 해결하기 위해 ([`v2`][ext-v2])는 기존 장점을 유지하면서도 위 과제들을 보완하도록 설계되었습니다.
또한 [Oleg Isonen][ext-kof]이 발표한 [**feature-driven**][ext-fdd] 등 유사 방법론과 아이디어를 융합해 애플리케이션 구조를 한층 더 **유연**, **명확**, **효율적**으로 다듬었습니다.

> 이 과정에서 방법론의 공식 명칭은 *feature-slice*에서 **feature-sliced**로 정식화되었습니다.
이를 해결하기 위해 등장한 것이 **[v2][ext-v2]** 입니다.
v2는 기존 장점을 유지하는 동시에 이러한 문제들을 보완하도록 설계되었습니다.
또한 [Oleg Isonen][ext-kof]이 발표한 [feature-driven][ext-fdd] 등 유사 방법론의 장점을 반영해 더 **유연하고**, **명확하며**, **효율적인** 구조로 발전했습니다.

> 이 과정에서 방법론의 공식 명칭은 feature-slice에서 **feature-sliced**로 정식화되었습니다.

## v2 마이그레이션 이유

> `WIP:` 작업이 진행 중이며, 일부 세부 사항이 변경될 수 있습니다.
> `WIP:` 문서는 계속 업데이트 중이며, 일부 내용은 변경될 수 있습니다.

### 직관적 구조 제공

v2는 **layer → slice → segment** 3단계만 알면 대부분 구조 결정을 내릴 수 있습니다.<br/>
덕분에 새로운 팀원이 **어디에 무엇을 둬야 하나** 부터 고민하지 않아 온보딩 속도가 빨라집니다.
v2는 **layer → slice → segment** 라는 세 가지 개념만 이해하면 구조적 결정을 쉽게 내릴 수 있습니다.
덕분에 신규 팀원이 **어디에 어디에 둘지** 고민할 필요가 줄어들어 온보딩 속도가 크게 향상됩니다.

### 유연한 모듈화

- **독립 영역**은 slice 단위로, **전역 흐름**은 Processes layer로 분리해 확장성을 확보합니다.
- 새 module을 추가할 때 *(layer → slice → segment)* 규칙만 따르면 폴더 재배치와 리팩터링 작업 부담이 크게 줄어듭니다.

#### 커뮤니티·도구 지원 확대
- 새로운 module을 추가할 때 _(layer → slice → segment)_ 규칙만 따르면 폴더 재배치나 리팩터링 부담이 크게 줄어듭니다.

v2 개발은 **코어 팀**과 커뮤니티 기여자들이 함께 이끌고 있습니다.
#### 커뮤니티/도구 지원 확대

v2는 **코어 팀** 과 커뮤니티가 함께 발전시키고 있으며, 다음과 같은 리소스도 제공됩니다.
다음 리소스를 활용해 보세요:

- **실제 사례 공유**: 다양한 프로젝트 환경에서의 적용 사례
- **실제 사례 공유**: 다양한 프로젝트 환경에서의 적용 사례
- **단계별 가이드**: 설정·구성·운영 전 과정을 담은 튜토리얼
- **코드 템플릿 & 예제**: 시작부터 배포까지 참고할 수 있는 실전 코드
- **온보딩 문서**: 신규 개발자를 위한 개념 요약 및 학습 자료
- **검증 툴킷**: steiger CLI 등 정책 준수·lint를 지원하는 유틸리티
- **코드 템플릿 & 예제**: 시작부터 배포까지 참고할 수 있는 실전 코드
- **온보딩 문서**: 신규 개발자를 위한 개념 요약 및 학습 자료
- **검증 툴킷**: steiger CLI 등 정책 준수/lint를 지원하는 유틸리티

> v1 지원은 계속 유지되지만, 새로운 기능·개선 사항은 **v2**에 우선 반영됩니다.
> 주요 업데이트 시에도 **안정적 마이그레이션 경로**를 보장합니다.
> v1도 계속 지원되지만, 새로운 기능과 개선은 **v2**에 우선 적용됩니다.
> 주요 업데이트 **안정적인 마이그레이션 경로**도 함께 제공합니다.

## 주요 변경 사항

### Layer 구조 명확화

v2에서는 layer를 최상위부터 최하위까지 명시적으로 구분합니다:
v2는 layer를 다음과 같이 명확히 구분합니다:

- `/app` > `/processes` > **`/pages`** > **`/features`** > `/entities` > `/shared`

- 모든 모듈이 `pages`/`features` layer에만 속하지 않습니다.
- 이 구조를 통해 [layer별 의존 규칙][ext-tg-v2-draft]을 명시적으로 설정할 수 있습니다.
- **상위 layer**는 더 넓은 **Context**를 제공합니다.
- 상위 layer 모듈은 **하위 layer** 모듈만 import할 수 있습니다.
- **하위 layer**는 **변경 리스크(Risk)와 책임(Responsibility)** 이 더 큽니다.
- 재사용 빈도가 높아, 수정 시 영향 범위가 넓습니다.
`/app` > `/processes` > **`/pages`** > **`/features`** > `/entities` > `/shared`

모든 모듈이 `pages, features`에만 속하지 않습니다.
이 구조는 [layer 의존 규칙][ext-tg-v2-draft]을 명확히 설정할 수 있도록 돕습니다.
**상위 layer**는 더 넓은 **context**를 제공하며, **하위 layer**는 더 낮은 **변경 리스크와 높은 재사용성**을 갖습니다.

### Shared 통합

프로젝트 `src` 루트에 흩어져 있던 UI, lib, API 인프라 추상화를 `/src/shared` 폴더로 통합했습니다.
`src` 루트에 흩어져 있던 UI, lib, API 인프라 추상화를 `/src/shared` 통합했습니다.

- `shared/ui` - 공통 UI components(선택 사항)
- *기존 `Atomic Design` 사용도 가능합니다.*
- `shared/lib` - 재사용 가능한 helper libraries
- *무분별한 helper dump 지양*
- `shared/api` - API entry points
- *각 feature/page 내 local 정의 가능하지만, 전역 entry point 집중을 권장*
- `shared` 폴더에는 **business logic** 의존을 두지 않습니다
- *불가피할 경우 `entities` layer 이상으로 로직을 옮기세요.*
- _기존 `Atomic Design` 사용도 가능합니다._
- `shared/lib` - 재사용 가능한 helper libraries
- _무분별한 helper dump 지양_
- `shared/api` - API entry points
- _각 feature/page 내 local 정의 가능하지만, 전역 entry point 집중을 권장_
- `shared` 폴더에는 **business logic** 의존을 두지 않습니다
- _불가피할 경우 `entities` layer 이상으로 로직을 옮기세요._

### Entities / Processes Layer 추가

v2에서는 로직 복잡성과 높은 결합을 줄이기 위한 **새로운 추상화**가 추가되었습니다.

- **`/entities`**
프론트엔드에서 사용되는 **business entities**(예: `user`, `order`, `i18n`, `blog`)를 담당하는 layer입니다.
프론트엔드에서 사용되는 **business entities**(예: `user`, `order`, `i18n`, `blog`)를 담당하는 layer입니다.
- **`/processes`**
애플리케이션 전반에 걸친 **비즈니스 process**(예: `payment`, `auth`, `quick-tour`)를 캡슐화하는 선택적 layer입니다.
process *로직이 여러 페이지에 분산될 때* 도입을 권장합니다.

process _로직이 여러 페이지에 분산될 때_ 도입을 권장합니다.

### 추상화·네이밍 가이드
### 추상화/네이밍 가이드

아래에서는 v2 권장 layer·segment 명칭을 이전 명칭과 대응하여 정리했습니다.<br/>
추상화·네이밍 관련 상세 가이드는 [명확한 네이밍 권장사항][refs-adaptability]을 참고하세요.
아래는 v2 권장 네이밍과 이전 명칭 간의 대응 관계입니다.
아래에서는 v2 권장 layer·segment 명칭을 이전 명칭과 대응하여 정리했습니다.
추상화/네이밍 관련 상세 가이드는 [명확한 네이밍 권장사항][refs-adaptability]을 참고하세요.

[disc-process]: https://github.com/feature-sliced/documentation/discussions/20
[disc-features]: https://github.com/feature-sliced/documentation/discussions/23
[disc-entities]: https://github.com/feature-sliced/documentation/discussions/18#discussioncomment-422649
[disc-shared]: https://github.com/feature-sliced/documentation/discussions/31#discussioncomment-453020

[disc-ui]: https://github.com/feature-sliced/documentation/discussions/31#discussioncomment-453132
[disc-model]: https://github.com/feature-sliced/documentation/discussions/31#discussioncomment-472645
[disc-api]: https://github.com/feature-sliced/documentation/discussions/66

#### Layer

- `/app` — **Application init**
- *이전 명칭: `app`, `core`,`init`, `src/index` (가끔 사용됨)*
- _이전 명칭: `app`, `core`,`init`, `src/index` (가끔 사용됨)_
- `/processes` — [**Business process**][disc-process]
- *이전 명칭: `processes`, `flows`, `workflows`*
- _이전 명칭: `processes`, `flows`, `workflows`_
- `/pages` — **Application page**
- *이전 명칭: `pages`, `screens`, `views`, `layouts`, `components`, `containers`*
- _이전 명칭: `pages`, `screens`, `views`, `layouts`, `components`, `containers`_
- `/features` — [**Feature module**][disc-features]
- *이전 명칭: `features`, `components`, `containers`*
- _이전 명칭: `features`, `components`, `containers`_
- `/entities` — [**Business entity**][disc-entities]
- *이전 명칭: `entities`, `models`, `shared`*
- _이전 명칭: `entities`, `models`, `shared`_
- `/shared` — [**Infrastructure**][disc-shared] 🔥
- *이전 명칭: `shared`, `common`, `lib`*
- _이전 명칭: `shared`, `common`, `lib`_

#### Segment

- `/ui` — [**UI segment**][disc-ui] 🔥
- *이전 명칭: `ui`, `components`, `view`*
- _이전 명칭: `ui`, `components`, `view`_
- `/model` — [**비즈니스 로직 segment**][disc-model] 🔥
- *이전 명칭: `model`, `store`, `state`, `services`, `controller`*
- _이전 명칭: `model`, `store`, `state`, `services`, `controller`_
- `/lib` — **보조 코드 segment**
- *이전 명칭: `lib`, `libs`, `utils`, `helpers`*
- _이전 명칭: `lib`, `libs`, `utils`, `helpers`_
- `/api` — [**API segment**][disc-api]
- *이전 명칭: `api`, `service`, `requests`, `queries`*
- _이전 명칭: `api`, `service`, `requests`, `queries`_
- `/config` — **애플리케이션 설정 segment**
- *이전 명칭: `config`, `env`, `get-env`*
- _이전 명칭: `config`, `env`, `get-env`_

## 낮은 결합 원칙 강화

새 layer 규칙 덕분에 [Zero-Coupling, High-Cohesion 원칙][refs-low-coupling]을 지키기 쉬워졌습니다.

*단, 모듈을 완전히 분리할 수 없는 경우에는 Public API 등 명확한 인터페이스 경계를 정의하고, 해당 의존 코드는 가능한 한 하위 layer에 위치시키는 것을 권장합니다.*
Layer 구조가 명확해지면서 [Zero-Coupling, High-Cohesion 원칙][refs-low-coupling]을 보다 쉽게 지킬 수 있게 되었습니다.
완전한 분리가 어렵다면 Public API 등 명확하게 드러나는 인터페이스를 두어 경계를 명확히 하고,
가능한 한 하위 layer에서 의존성이 내려가도록 구조화할 것을 권장합니다.

## 참고 자료

Expand All @@ -148,7 +142,6 @@ v2에서는 로직 복잡성과 높은 결합을 줄이기 위한 **새로운

[refs-low-coupling]: /docs/reference/slices-segments#zero-coupling-high-cohesion
[refs-adaptability]: /docs/about/understanding/naming

[ext-v1]: https://feature-sliced.github.io/featureslices.dev/v1.0.html
[ext-tg-spb]: https://t.me/feature_slices
[ext-fdd]: https://github.com/feature-sliced/documentation/tree/rc/feature-driven
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,81 +4,86 @@ sidebar_position: 5

# v2.0 -> v2.1 마이그레이션 가이드

v2.1의 핵심 변화는 Page 중심(Page-First) 접근 방식을 통한 인터페이스 구조화입니다.
v2.1의 핵심 변화는 Page 중심(Page-First) 접근 방식을 기반으로 인터페이스 구조를 재정비한 것입니다.

## v2.0 접근 방식

v2.0에서는 **Entity** 와 **Feature** 단위를 중심으로 애플리케이션을 분리했습니다.
화면을 이루는 최소 단위인 entity 표현이나 상호작용 요소까지 모두 세분화한 뒤,<br/>
이를 **Widget** 으로 조합하고, 최종적으로 **Page** 를 구성하는 모델이었죠.
v2.0에서는 애플리케이션을 **Entity**와 **Feature** 단위로 세분화하여 구성했습니다.
화면을 이루는 가장 작은 단위(entity 표현, 상호작용 요소 등)를 잘게 나눈 뒤,
이를 **Widget**으로 조합하고, 최종적으로 **Page**를 구성하는 방식이었습니다.

이렇게 하면 재사용성과 모듈화 면에서 이점이 있었지만,<br/>
실제로는 대부분의 비즈니스 로직이 entity·feature layer에 집중되고,<br/>
Page는 단순 조합 계층에 머물러 자신만의 책임이 희미해지는 문제가 발생했습니다.
이 방식은 재사용성과 모듈화 측면에서 장점이 있었지만, 다음과 같은 문제가 발생했습니다:
비즈니스 로직이 대부분 **entity/feature** layer에 과도하게 집중되었고,
Page는 단순한 조합 계층으로 남아 고유한 책임이 약해지는 문제가 나타났습니다.

## v2.1 접근 방식

v2.1에서는 **Pages-First** 사고방식을 도입합니다.
대부분의 개발자가 이미 애플리케이션을 Page 단위로 나누는 데 익숙하고,<br/>
코드베이스에서 컴포넌트를 찾을 때도 Page가 자연스러운 출발점이기 때문입니다.
v2.1은 **Pages-First** 사고방식을 도입합니다.
개발자가 실제로 코드베이스를 탐색할 때 Page 단위로 구조를 파악하는 것이 더 자연스럽고,
구성 요소를 찾는 출발점도 대부분 Page이기 때문입니다.

- **Page 내부에 주요 UI와 비즈니스 로직**을 두고 **Shared** layer는 순수 재사용 요소만 관리
- 공통 로직이 실제로 여러 Page에서 쓰일 때만 하위 layer(Feature·Entity)로 분리
v2.1의 핵심 원칙은 다음과 같습니다:

이 접근의 장점은 다음과 같습니다:
- Page 내부에 주요 UI와 비즈니스 로직을 배치합니다.
- Shared layer에는 순수 재사용 요소만 유지합니다.
- 여러 Page에서 실제로 공유되는 로직만 Feature/Entity로 분리합니다.

1. **Page가 책임 단위**가 되어, 코드 위치와 역할이 명확해집니다.
2. Shared layer는 **유틸·컴포넌트**처럼 순수 재사용 코드만 담아, 의존 경로가 간결해집니다.
3. 공통 로직을 실제로 재사용할 때만 하위 layer로 이동해, 불필요한 추상화와 의존성 얽힘을 방지합니다.
이 접근 방식의 장점

또한 v2.1에서는 **Entity 간 cross-import**를 `@x` 표기법으로 **표준화**했습니다.
이제 다음과 같은 형식으로 명확한 경로를 사용할 수 있습니다:
1. **Page가 명확한 책임 단위**가 되어, 코드의 역할이 분명해집니다.
2. **Shared** layer가 불필요하게 비대해지는 것을 방지해 의존성이 간결해집니다.
3. 공통 로직을 실제로 재사용할 때만 분리하므로 과도한 추상화가 줄어듭니다.

또한 v2.1에서는 **Entity 간 cross-import**를 위한 `@x` 표기법이 **표준화**되었습니다.
이를 통해 import 경로를 더 명확하고 일관되게 관리할 수 있습니다.


## 마이그레이션 프로세스 {#how-to-migrate}

v2.1은 하위 호환성을 보장하므로, 기존 FSD v2.0 프로젝트는 **수정 없이** 동작합니다.
새 모델을 활용하려면 아래 단계를 단계적으로 적용해 보세요.
v2.1은 하위 호환성을 제공합니다.
즉, 기존 v2.0 프로젝트는 **수정 없이** 그대로 동작합니다.
다만 v2.1의 구조적 장점을 활용하려면 아래 단계를 차례로 적용하면 됩니다.

### 1. Slice 병합

FSD v2.1의 Page-First 모델에서는 **실제로 여러 Page에서 재사용되지 않는** slice를 굳이 독립 단위로 유지할 필요가 없습니다.
단일 page에서만 사용되는 slice는 해당 page 안으로 병합하면, 코드 탐색과 유지보수가 더 쉬워집니다.
v2.1 Page-First 모델에서는 **여러 Page에서 재사용되지 않는** slice는 Page 내부로 병합하는 것을 권장합니다.
이렇게 하면 코드 탐색이 빨라지고 유지보수 비용도 줄어듭니다.

#### Steiger로 자동 탐지하기

프로젝트 루트에서 [Steiger][steiger] linter를 실행하세요.<br/>
v2.1 mental model에 맞춘 주요 lint 규칙은 다음과 같습니다:

- [`insignificant-slice`][insignificant-slice]
단일 Page에서만 참조되는 slice를 찾아냅니다.
→ **해당 slice를 Page 내부로 병합**하도록 제안합니다.
- [`excessive-slicing`][excessive-slicing]
너무 잘게 나뉜 slice를 감지합니다.
→ **유사한 slice를 통합**하거나 **그룹화**해 탐색성을 높이도록 권장합니다.
프로젝트 루트에서 [Steiger][steiger]를 실행하면 v2.1 mental model에 맞추어 slice 사용 여부를 자동으로 분석해줍니다:

```bash
npx steiger src
```

이 명령으로 `한 번만 쓰이는 slice` 목록이 출력됩니다.<br/>
- [`insignificant-slice`][insignificant-slice]
단일 Page에서만 사용되는 slice를 탐지합니다.
→ **Page 내부로 병합하는 것을 권장**합니다.
- [`excessive-slicing`][excessive-slicing]
지나치게 잘게 나뉜 slice를 찾아줍니다.
→ **유사한 slice를 통합하거나 그룹화하여 탐색성**을 높입니다.


이 명령으로 `한 번만 쓰이는 slice` 목록이 출력됩니다.
이제 각 slice의 재사용 여부를 검토하고, 과하다면 해당 page로 병합하거나 비슷한 역할끼리 묶어 보세요.

:::tip Slice 관리

각 계층은 해당 계층에 속한 모든 Slices의 namespace를 관리합니다. 이는 전역 변수를 관리하는 것과 비슷한 개념입니다:
Slice는 해당 layer의 namespace를 구성하는 요소입니다.
전역 변수를 최소화하듯, slice도 실제로 재사용되는 경우에만 독립 단위로 유지하세요.

- 전역 변수는 꼭 필요한 경우에만 사용하듯이 Slice도 실제로 재사용되는 경우에만 독립적으로 분리하세요
- 한 곳에서만 사용되는 코드는 해당 Page나 Feature 내부로 이동하는 것이 좋습니다
한 곳에서만 쓰이는 slice → Page 또는 Feature 내부로 이동
여러 Page에서 재사용되는 slice → 그대로 유지

:::

### 2. Cross Import 표준화

새로운 `@x-` 표기법으로 Entity 간 cross-import를 통일합니다:
v2.1에서는 Entity 간 cross-import를 위해 `@x-` 표기법을 사용합니다.

```ts title="entities/B/some/file.ts"
// v2.1 권장 cross-import 방식
// v2.1 권장 방식
import type { EntityA } from "entities/A/@x/B";
```

Expand Down