Skip to content

Commit a5a53e8

Browse files
authored
docs: Improve from-custom readability in kr documentation (#877)
1 parent 82c99c3 commit a5a53e8

File tree

1 file changed

+64
-70
lines changed
  • i18n/kr/docusaurus-plugin-content-docs/current/guides/migration

1 file changed

+64
-70
lines changed

i18n/kr/docusaurus-plugin-content-docs/current/guides/migration/from-custom.md

Lines changed: 64 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ sidebar_label: 기존 아키텍처에서 전환하기
55

66
# 기존 아키텍처에서 FSD로의 마이그레이션
77

8-
이 가이드는 기존 아키텍처를 **Feature-Sliced Design(FSD)** 으로 단계별 전환하는 방법을 설명합니다.
9-
8+
이 가이드는 기존 아키텍처를 **Feature-Sliced Design(FSD)** 으로 단계별 전환하는 방법을 설명합니다.
109
아래 폴더 구조를 예시로 살펴보세요. (파란 화살표를 클릭하면 펼쳐집니다).
1110

1211
<details className="file-tree">
@@ -54,18 +53,18 @@ Feature-Sliced Design(FSD)이 **정말 필요한지 먼저 확인하세요.**
5453
### 전환을 고려해야 할 징후
5554

5655
1. 신규 팀원이 프로젝트에 적응하기 어려워하는 경우
57-
2. 코드 일부를 수정할 때, 관련 없는 다른 코드에 오류가 발생하는 경우가 **잦은** 경우
56+
2. 코드 일부를 수정할 때, 관련 없는 다른 코드에 오류가 발생하는 경우가 **잦은** 경우
5857
3. 새 기능을 추가할 때 고려해야 할 사항이 너무 많아 어려움을 겪는 경우
5958

6059
**팀의 합의 없이 FSD 전환을 시작하지 마세요.**
61-
팀 리더라도 전환의 이점이 학습·전환 비용을 상회한다는 점을 먼저 설득해야 합니다.
60+
팀 리더라도 전환의 이점이 학습/전환 비용을 상회한다는 점을 먼저 설득해야 합니다.
6261
또한, 개선 효과가 바로 눈에 띄지 않을 수 있으므로 **팀원****프로젝트 매니저(PM)** 의 승인을 사전에 확보하고 이점을 공유하세요.
6362

6463
:::tip PM 설득 시 고려할 사항
6564

66-
- FSD 전환은 단계적으로 진행할 수 있어 기존 기능 개발을 중단하지 않아도 됩니다.
67-
- 명확한 아키텍처 구조는 신규 개발자 온보딩 시간을 단축합니다.
68-
- 공식 문서를 활용하면 별도 문서 유지·관리 비용을 절감할 수 있습니다.
65+
- FSD 전환은 단계적으로 진행할 수 있어 기존 기능 개발을 중단하지 않아도 됩니다.
66+
- 명확한 아키텍처 구조는 신규 개발자 온보딩 시간을 단축합니다.
67+
- 공식 문서를 활용하면 별도 문서 유지·관리 비용을 절감할 수 있습니다.
6968

7069
:::
7170

@@ -75,50 +74,48 @@ Feature-Sliced Design(FSD)이 **정말 필요한지 먼저 확인하세요.**
7574

7675
## 1단계: 페이지 단위로 코드 분리하기 {#divide-code-by-pages}
7776

78-
대부분의 커스텀 아키텍처는 규모와 관계없이 이미 어느 정도 페이지 단위로 코드를 나누고 있습니다. `📁 pages` 폴더가 있다면 이 단계를 건너뛰어도 됩니다.
79-
77+
대부분의 커스텀 아키텍처는 규모와 관계없이 이미 어느 정도 페이지 단위로 코드를 나누고 있습니다.
78+
`📁 pages` 폴더가 있다면 이 단계를 건너뛰어도 됩니다.
8079

8180
위에 예시 폴더처럼 `📁 routes`만 있다면 다음 순서를 따르세요.
8281

83-
1. `📁 pages` 폴더를 새로 만듭니다.
84-
2. `📁 routes`에 있던 **페이지용 컴포넌트**를 가능한 한 모두 `📁 pages` 폴더로 옮깁니다.
85-
3. 코드를 옮길 때마다 해당 페이지 전용 폴더를 만들고 그 안에 `index` 파일을 추가해 entry를 노출합니다.
82+
1. `📁 pages` 폴더를 새로 만듭니다.
83+
2. `📁 routes`에 있던 **페이지용 컴포넌트**를 가능한 한 모두 `📁 pages` 폴더로 옮깁니다.
84+
3. 코드를 옮길 때마다 해당 페이지 전용 폴더를 만들고 그 안에 `index.tsx` 파일을 추가해 **진입점(entry point)** 노출합니다.
8685

8786
:::note
8887

89-
이 단계에서는 **Page A에서 Page B의 코드를 import**해도 괜찮습니다. 나중 단계에서 이러한 의존성을 분리할 예정이니, 우선 **페이지 폴더를 만드는 것**에 집중하세요.
88+
이 단계에서는 **Page A에서 Page B의 코드를 import**해도 괜찮습니다.
89+
나중 단계에서 이러한 의존성을 분리할 예정이니, 우선 **페이지 폴더를 만드는 것**에 집중하세요.
9090

9191
:::
9292

93-
route file:
93+
**📁 Route File**
9494

95-
```js title="src/routes/products.[id].js"
96-
export { ProductPage as default } from "src/pages/product"
95+
```js title="route file:src/routes/products.[id].js"
96+
export { ProductPage as default } from "src/pages/product";
9797
```
9898

99-
page index file:
99+
**📁 Page Index File**
100100

101101
```js title="src/pages/product/index.js"
102-
export { ProductPage } from "./ProductPage.jsx"
102+
export { ProductPage } from "./ProductPage.jsx";
103103
```
104104

105-
page component file:
105+
**📁 Page Component File**
106106

107107
```jsx title="src/pages/product/ProductPage.jsx"
108108
export function ProductPage(props) {
109-
return <div />;
109+
return <div />;
110110
}
111111
```
112112

113113
## 2단계: 페이지 외부 코드를 분리하기 {#separate-everything-else-from-pages}
114114

115-
1. **`📁 src/shared` 폴더를 만든다.**
116-
- `📁 pages` 또는 `📁 routes`**import하지 않는** 모든 코드를 이곳으로 이동한다.
117-
2. **`📁 src/app` 폴더를 만든다.**
118-
- `📁 pages` 또는 `📁 routes`**import하는** 코드를 이곳으로 옮긴다. 라우트 파일도 여기에 포함한다.
115+
**📁 src/shared 폴더를 만들고,** 📁 pages 또는 📁 routes를 import하지 않는 모든(파일)은 이 폴더로 모읍니다.
116+
**📁 src/app 폴더를 만들고,** 📁 pages 또는 📁 routes를 import하는 모듈과 라우트 정의 파일은 이 폴더에 배치합니다.
119117

120-
> **Shared layer에는 slice가 없다.**
121-
> 따라서 segment 간 import는 자유롭다.
118+
> **Shared layer는 slice 개념이 존재하지 않기 때문에,** 서로 다른 segment 간에도 자유롭게 import할 수 있습니다
122119
123120
이제 폴더 구조는 다음과 같아야 합니다:
124121

@@ -189,39 +186,40 @@ export function ProductPage(props) {
189186
</ul>
190187
</details>
191188

192-
## 3단계: 페이지 간의 cross-imports 해결 {#tackle-cross-imports-between-pages}
189+
## 3단계: 페이지 cross-imports 해결 {#tackle-cross-imports-between-pages}
193190

194191
<!-- A good way to approach this is by setting up [Steiger][ext-steiger], the linter for FSD. -->
195192
<!-- TODO: add instructions once the new config format is standardized -->
196193

197-
한 페이지가 다른 페이지의 코드를 가져오고 있다면 두 가지 방법으로 의존성을 제거한다.
198-
199-
| 방법 | 사용 시점 |
200-
|------|-----------|
201-
| **A. 코드 복사** | 페이지마다 로직이 달라질 가능성이 있거나, 재사용성이 낮을 때 |
202-
| **B. Shared로 이동** | 여러 페이지에서 공통으로 쓰일 때 |
194+
한 페이지가 다른 페이지의 코드를 직접 import하고 있다면, 아래 두 가지 방식 중 하나로 의존성을 정리합니다.
203195

196+
| 방법 | 사용 시점 |
197+
| ----------------------------------- | -------------------------------------------------------------- |
198+
| **A. 코드 복사하여 독립시키기** | 페이지별로 로직이 달라질 가능성이 높거나, 재사용성이 낮은 경우 |
199+
| **B. Shared로 이동하여 공통화하기** | 여러 페이지에서 반복적으로 사용되는 경우 |
204200

205201
- Shared 이동 위치 예시
206-
- UI 구성 요소 → `📁 shared/ui`
207-
- 설정 상수   → `📁 shared/config`
208-
- 백엔드 호출  → `📁 shared/api`
202+
- UI 구성 요소 → `📁 shared/ui`
203+
- 설정 상수   → `📁 shared/config`
204+
- 백엔드 호출  → `📁 shared/api`
209205

210206
:::note
211207

212-
코드 복사는 잘못이 아니다. **중복보다 의존성 최소화**가 더 중요할 때가 많다.
213-
다만 비즈니스 로직은 중복을 피해야 하며, 복사 시에도 DRY 원칙을 염두에 둔다.
208+
코드를 복사하는 것은 잘못이 아닙니다.
209+
경우에 따라서는 **중복을 허용하더라도 페이지 간 의존성을 줄이는 것**이 더 중요합니다.
210+
다만, 비즈니스 로직처럼 변경 가능성이 큰 핵심 부분은 중복을 피하고, 복사할 때에도 가능한 한 DRY 원칙을 고려합니다.
214211

215212
:::
216213

217-
## 4단계: Shared 레이어 정리하기 {#unpack-shared-layer}
214+
## 4단계: Shared Layer 정리하기 {#unpack-shared-layer}
218215

219-
- **한 페이지에서만 쓰이는 코드**는 해당 페이지 **slice**이동한다.
220-
- `actions / reducers / selectors`예외가 아니다. **사용처와 가까이** 두는 편이 좋다.
216+
**한 페이지에서만 사용되는 코드**는 해당 페이지의 **slice**이동합니다.
217+
`actions, reducers, selectors` 역시 예외가 아니며, **사용되는 위치와 가까운 곳** 두는 것이 가장 좋습니다.
221218

222-
Shared는 모든 layer가 의존할 수 있는 **공통 의존점**이므로, 코드를 최소화해 변경 위험을 낮춘다.
219+
Shared는 모든 layer가 의존할 수 있는 **공통 의존 지점이**기 때문에,
220+
이곳에 코드를 과도하게 쌓아두지 않고 최소한으로 유지하는 것이 변경 위험을 줄이는 핵심 원칙입니다.
223221

224-
최종 폴더 구조는 다음과 같아야 합니다:
222+
이 단계를 마치면 폴더 구조는 아래와 같은 형태가 되는 것이 자연스럽습니다:
225223

226224
<details className="file-tree" open>
227225
<summary>📁 src</summary>
@@ -280,49 +278,45 @@ Shared는 모든 layer가 의존할 수 있는 **공통 의존점**이므로,
280278

281279
## 5단계: 기술적 목적별 segment 정리 {#organize-by-technical-purpose}
282280

283-
284-
| segment | 용도 예시 |
285-
|----------|-----------|
286-
| `ui` | Components, formatters, styles |
287-
| `api` | Backend requests, DTOs, mappers |
288-
| `model` | Store, schema, business logic |
289-
| `lib` | Shared utilities / helpers |
281+
| segment | 용도 예시 |
282+
| -------- | ---------------------------------- |
283+
| `ui` | Components, formatters, styles |
284+
| `api` | Backend requests, DTOs, mappers |
285+
| `model` | Store, schema, business logic |
286+
| `lib` | Shared utilities / helpers |
290287
| `config` | Configuration files, feature flags |
291288

289+
> **무엇인지**가 아니라 **무엇을 위해 존재하는지**를 기준으로 폴더를 구분합니다.
290+
> 따라서 `components`, `utils`, `types`처럼 목적이 모호한 폴더 이름은 지양합니다.
292291
293-
> **무엇인지**”가 아니라 “**무엇을 위해**” 존재하는지를 기준으로 나눈다.
294-
> 따라서 `components`, `utils`, `types` 같은 이름은 지양한다.
295-
296-
1. **각 페이지**`ui / model / api` 등 필요한 segment를 만든다.
297-
2. **Shared** 폴더를 정리한다.
298-
- `components·containers``shared/ui`
299-
- `helpers·utils` → `shared/lib` (기능별 그룹화 후)
300-
- `constants` → `shared/config`
301-
292+
1. **각 페이지 내부**에서, 필요한 `segment(ui, model, api 등)`를 구성합니다.
293+
2. **Shared 폴더는 공통 기능만 남기도록 정리합니다.**
294+
- `components/containers``shared/ui`
295+
- `helpers/utils` → `shared/lib` (기능별 그룹화 후)
296+
- `constants` → `shared/config`
302297

303298
## 선택 단계 {#optional-steps}
304299

305300
### 6단계: 여러 페이지에서 재사용되는 Redux slice를 Entities / Features layer로 분리하기 {#form-entities-features-from-redux}
306301

307-
- 여러 페이지에서 재사용되는 Redux **slice**주로 **product, user** 같은 **business entity**를 표현합니다.
308-
이 경우 **Entities layer**옮기고, **entity**마다 폴더를 하나씩 만듭니다.
309-
- 댓글 작성처럼 **사용자 행동(action)**다루는 **slice****Features layer**이동합니다.
302+
여러 페이지에서 반복적으로 사용되는 Redux **slice**대부분 **product, user**처럼 명확한 **business entity**를 표현합니다.
303+
이러한 slice는 **Entities layer**이동하며, **entity**마다 별도의 폴더를 구성합니다.
304+
반대로, 댓글 작성처럼 **사용자의 특정 행동(action)**중심으로 한 **slice****Features layer**옮겨 독립적으로 관리합니다.
310305

311-
**Entities****Features**는 서로 독립적으로 사용될 수 있도록 설계되어 있습니다.
312-
Entitles 간 연결이 필요하면 [Business-Entities Cross-Relations 가이드][business-entities-cross-relations]참고하세요.
313-
해당 **slice**와 연관된 API 함수는 `📁 shared/api`에 그대로 두어도 무방합니다.
306+
**Entities****Features**는 서로 의존하지 않고 사용할 수 있도록 설계해야 합니다.
307+
Entity 간의 관계가 필요하다면 [Business-Entities Cross-Relations 가이드][business-entities-cross-relations]참고해 구조화하면 됩니다.
308+
해당 **slice**와 연관된 API 함수는 `📁 shared/api`에 그대로 두어도 괜찮습니다.
314309

315310
### 7단계: modules 폴더 리팩터링 {#refactor-your-modules}
316311

317-
`📁 modules`는 과거에 비즈니스 로직을 모아 두던 곳으로, 성격상 **Features layer**와 비슷합니다.
318-
, 앱 Header처럼 **large UI block**(예: global Header, Sidebar)이라면 **Widgets layer**로 옮기는 편이 좋습니다.
312+
`📁 modules`는 과거에 비즈니스 로직을 모아두던 공간으로, 성격상 **Features layer**와 비슷합니다.
313+
다만, 앱 Header처럼 **large UI block**(예: global Header, Sidebar)이라면 **Widgets layer**로 옮기는 편이 좋습니다.
319314

320315
### 8단계: shared/ui에 presentational UI 기반 마련하기 {#form-clean-ui-foundation}
321316

322317
`📁 shared/ui`에는 비즈니스 로직이 전혀 없는, 재사용 가능한 presentational UI 컴포넌트만 남겨야 합니다.
323-
324-
- 기존 `📁 components` · `📁 containers`에 있던 컴포넌트에서 비즈니스 로직을 분리해 상위 layer로 이동합니다.
325-
- 여러 곳에서 쓰이지 않는 부분은 **복사(paste)** 해서 각 layer에서 독립적으로 관리해도 괜찮습니다.
318+
기존 `📁 components / 📁 containers`에 있던 컴포넌트에서 비즈니스 로직을 분리해 상위 layer로 이동시킵니다.
319+
여러 곳에서 쓰이지 않는 부분은 **복사(paste)** 해서 각 layer에서 독립적으로 관리해도 문제 없습니다.
326320

327321
## 참고 자료 {#see-also}
328322

0 commit comments

Comments
 (0)