Skip to content

Commit 956ffa8

Browse files
committed
docs: cleanup and reorganize ko/current/reference for better readability
1 parent 298e812 commit 956ffa8

File tree

3 files changed

+305
-207
lines changed

3 files changed

+305
-207
lines changed

i18n/kr/docusaurus-plugin-content-docs/current/reference/layers.mdx

Lines changed: 134 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -3,181 +3,211 @@ sidebar_position: 1
33
pagination_next: reference/slices-segments
44
---
55

6-
import useBaseUrl from '@docusaurus/useBaseUrl';
6+
import useBaseUrl from "@docusaurus/useBaseUrl";
77

88
# Layer
99

10-
Layer는 Feature-Sliced Design에서 **코드를 구분하는 가장 큰 범위**입니다.
11-
코드를 나눌 때는 각 부분이 **어떤 기능을 담당하는지****다른 코드에 얼마나 의존하는지**를 기준으로 합니다.
12-
Layer마다 **어떤 역할을 맡는지**에 대한 공통된 의미가 있습니다.
13-
14-
**7개의 Layer**가 있으며, **담당 기능과 의존성이 많은 것**부터 **적은 것** 순으로 나열합니다.
15-
16-
<img src={useBaseUrl("/img/layers/folders-graphic-light.svg#light-mode-only")} width="180" style={{ float: "right", margin: "0 1em" }} alt="A file system tree, with a single root folder called src and then seven subfolders: app, processes, pages, widgets, features, entities, shared. The processes folder is slightly faded out." />
17-
<img src={useBaseUrl("/img/layers/folders-graphic-dark.svg#dark-mode-only")} width="180" style={{ float: "right", margin: "0 1em" }} alt="A file system tree, with a single root folder called src and then seven subfolders: app, processes, pages, widgets, features, entities, shared. The processes folder is slightly faded out." />
18-
19-
1. App
20-
2. Processes (deprecated)
21-
3. Pages
22-
4. Widgets
23-
5. Features
24-
6. Entities
10+
Layer는 Feature-Sliced Design에서 코드를 나눌 때 사용하는 **가장 큰 구분 단위**입니다.
11+
코드를 나눌 때는 각 부분이 **어떤 역할을 맡는지**, 그리고 **다른 코드에 얼마나 의존하는지**를 기준으로 합니다.
12+
각 Layer는 **이 Layer에는 어떤 코드가 와야 하는지**에 대해 **공통된 의미와 책임**이 정해져 있습니다.
13+
14+
**7개의 Layer**가 있으며, 아래로 내려갈수록 **담당하는 기능과 의존성이 줄어드는 순서**입니다.
15+
16+
<img
17+
src={useBaseUrl("/img/layers/folders-graphic-light.svg#light-mode-only")}
18+
width="180"
19+
style={{ float: "right", margin: "0 1em" }}
20+
alt="A file system tree, with a single root folder called src and then seven subfolders: app, processes, pages, widgets, features, entities, shared. The processes folder is slightly faded out."
21+
/>
22+
<img
23+
src={useBaseUrl("/img/layers/folders-graphic-dark.svg#dark-mode-only")}
24+
width="180"
25+
style={{ float: "right", margin: "0 1em" }}
26+
alt="A file system tree, with a single root folder called src and then seven subfolders: app, processes, pages, widgets, features, entities, shared. The processes folder is slightly faded out."
27+
/>
28+
29+
1. App
30+
2. Processes (deprecated)
31+
3. Pages
32+
4. Widgets
33+
5. Features
34+
6. Entities
2535
7. Shared
2636

27-
> 모든 Layer를 꼭 써야 하는 건 아닙니다. **필요할 때만** 추가하세요.
28-
> 대부분의 프론트엔드 프로젝트는 최소한 `shared`, `page`, `app`은 포함합니다.
37+
> 모든 Layer를 반드시 사용해야 하는 것은 아닙니다.
38+
> **필요한 경우에만** Layer를 추가하세요.
39+
> 대부분의 프론트엔드 프로젝트는 보통 최소한 `shared`, `page`, `app` 정도는 사용합니다.
2940
30-
실무에서는 폴더명을 소문자로 작성합니다(예: `📁 shared`, `📁 page`, `📁 app`).
31-
**새로운 Layer를 만드는 것은 권장하지 않습니다**(역할이 이미 표준화되어 있음).
41+
실무에서는 폴더명을 보통 소문자로 작성합니다. (예: `📁 shared`, `📁 page`, `📁 app`)
42+
또한, **새로운 Layer를 직접 정의해서 사용하는 것은 권장하지 않습니다.**
43+
(각 Layer의 역할이 이미 표준으로 충분히 정리되어 있기 때문입니다.)
3244

3345
## Import 규칙
3446

35-
Layer는 **Slice(서로 밀접하게 연관된 모듈 묶음)** 로 구성됩니다.
36-
Slice 간 연결은 **Layer Import 규칙**으로 제한합니다.
47+
각 Layer는 여러 개의 **Slice(서로 밀접하게 연관된 모듈 묶음)** 로 구성됩니다.
48+
Slice들 사이의 연결은 **Layer Import 규칙**을 통해 제한합니다.
49+
50+
> **규칙:**
51+
> 하나의 Slice 안에서 작성된 코드는
52+
> **자신이 속한 Layer보다 아래 Layer**에 있는 *다른 Slice*만 import할 수 있습니다.
3753
38-
> **규칙**: Slice 안의 코드는 **자신보다 아래 Layer***다른 Slice*만 Import할 수 있습니다.
54+
예를 들어, `📁 ~/features/aaa/api/request.ts` 파일은 다음과 같습니다.
3955

40-
예: `📁 ~/features/aaa/api/request.ts`
41-
- 같은 Layer의 `📁 ~/features/bbb`**불가능**
42-
- 더 아래 Layer(`📁 ~/entities`, `📁 ~/shared`) → **가능**
43-
- 같은 Slice(`📁 ~/features/aaa/lib/cache.ts`) → **가능**
56+
- 같은 Layer의 `📁 ~/features/bbb`**import 불가능**
57+
- 더 아래 Layer(`📁 ~/entities`, `📁 ~/shared`) → **import 가능**
58+
- 같은 Slice(`📁 ~/features/aaa/lib/cache.ts`) → **import 가능**
4459

45-
`app``shared`**예외**입니다.
46-
두 Layer는 **Layer이면서 동시에 하나의 큰 Slice처럼 동작**하고, 내부는 **Segment**로 나눕니다.
47-
이 경우 Segment끼리 자유롭게 Import할 수 있습니다.
48-
(`shared`는 비즈니스 도메인이 없고, `app`은 모든 도메인을 묶는 역할을 합니다.)
60+
`app``shared`는 조금 특이한 Layer입니다.
61+
두 Layer는 **Layer이면서 동시에 하나의 큰 Slice처럼 동작**하고 내부 구조는 **Segment**로 나뉩니다.
62+
63+
이 경우에는 Layer 내부에서 Segment끼리는 자유롭게 import할 수 있습니다.
64+
(`shared`는 비즈니스 도메인이 없고, `app`은 모든 도메인을 묶는 상위 조정자 역할을 합니다.)
4965

5066
## Layer별 역할
5167

52-
각 Layer가 어떤 의미를 가지며, 어떤 코드를 포함하는지 정리했습니다.
68+
이제 각 Layer가 어떤 의미를 가지는지,
69+
그리고 보통 어떤 종류의 코드가 해당 Layer에 들어오는지 정리해 보겠습니다.
5370

5471
### Shared
5572

56-
앱의 **기본 구성 요소**를 모아둡니다.
57-
백엔드, 서드파티 라이브러리, 실행 환경과의 연결, 그리고 **높은 응집도의 내부 라이브러리**를 포함합니다.
58-
59-
- `app`과 마찬가지로 **Slice 없이 Segment로만 구성**합니다.
60-
- 비즈니스 도메인이 없으므로 **Shared 안의 파일끼리는 자유롭게 Import**할 수 있습니다.
61-
62-
Segment 예시
63-
- `📁 api` — API 클라이언트와 백엔드 요청 함수
64-
- `📁 ui` — 공통 UI 컴포넌트
65-
- **비즈니스 로직 제외**, **브랜드 테마 적용 가능**
66-
- 로고, 레이아웃, 자동완성/검색창 등 UI 로직 포함 가능
67-
- 자동완성/검색창 등 **UI 로직 컴포넌트**도 가능
68-
- `📁 lib` — 내부 라이브러리
69-
- 단순 `utils/helpers` 모음이 아님 ([이 글 참고][ext-sova-utility-dump])
70-
- 하나의 주제(날짜, 색상, 텍스트 등)에 집중
71-
- README로 역할과 범위를 문서화
73+
Shared Layer는 앱의 **기본 구성 요소와 기반 도구들을 모아두는 곳**입니다.
74+
백엔드, 서드파티 라이브러리, 실행 환경과의 연결,
75+
그리고 여러 곳에서 사용하는 **응집도 높은 내부 라이브러리**가 여기에 위치합니다.
76+
77+
`app`과 마찬가지로 **Slice 없이 Segment로만 구성**합니다.
78+
비즈니스 도메인이 없기 때문에, **Shared 내부의 파일들은 서로 자유롭게 import**할 수 있습니다.
79+
80+
Segment 예시:
81+
82+
- `📁 api` — API 클라이언트와 공통 백엔드 요청 함수
83+
- `📁 ui` — 공통 UI 컴포넌트
84+
- **비즈니스 로직은 포함하지 않지만**, **브랜드 테마는 적용 가능**
85+
- 로고, 레이아웃, 자동완성/검색창 등 **UI 자체 로직**을 포함하는 컴포넌트는 허용
86+
- `📁 lib` — 내부 라이브러리
87+
- 단순히 `utils/helpers`를 모아두는 폴더가 아닙니다. ([이 글 참고][ext-sova-utility-dump])
88+
- 날짜, 색상, 텍스트 등 **하나의 주제에 집중**해야 합니다.
89+
- README를 통해 역할과 범위를 문서화하는 것을 권장합니다.
7290
- `📁 config` — 환경변수, 전역 Feature Flag
7391
- `📁 routes` — 라우트 상수/패턴
7492
- `📁 i18n` — 번역 설정, 전역 문자열
7593

76-
> Segment 이름은 **무엇을 하는 폴더인지** 드러나야 합니다.
77-
> `components`, `hooks`, `types`처럼 역할이 불명확한 이름은 피하세요.
94+
> Segment 이름은 **이 폴더가 무엇을 하는지**를 명확하게 드러내야 합니다.
95+
> `components`, `hooks`, `types`처럼 역할이 모호한 이름은 가급적 피하세요.
7896
7997
### Entities
8098

81-
프로젝트에서 다루는 **핵심 데이터 개념**나타냅니다.
82-
비즈니스 용어(예: `User`, `Post`, `Product`)와 일치하는 경우가 많습니다.
99+
Entities Layer는 프로젝트에서 다루는 **핵심 비즈니스 개념**표현합니다.
100+
대부분의 경우, 실제 도메인 용어(예: `User`, `Post`, `Product`)와 일치합니다.
83101

84-
Entity Slice에는 다음을 포함할 수 있습니다:
102+
Entity Slice에는 다음과 같은 것들을 포함할 수 있습니다.
85103

86-
구성
87-
- `📁 model` — 데이터 상태와 검증 스키마
88-
- `📁 api` — 해당 Entity의 API 요청
89-
- `📁 ui` — Entity의 시각적 표현
90-
- 완전한 UI 블록이 아니어도 됨
91-
- 여러 페이지에서 재사용 가능하게 설계
92-
- 비즈니스 로직은 props/slot으로 연결 권장
104+
구성:
93105

106+
- `📁 model` — 데이터 상태, 도메인 로직, 검증 스키마
107+
- `📁 api` — 해당 Entity와 관련된 API 요청
108+
- `📁 ui` — Entity의 시각적 표현
109+
- 완성된 큰 UI 블록이 아니어도 됩니다.
110+
- 여러 페이지에서 재사용 가능한 형태로 설계합니다.
111+
- 비즈니스 로직은 가능하면 props/slot으로 외부에서 주입하는 방식을 권장합니다.
94112

95113
#### Entity 간 관계
96114

97-
원칙적으로 Slice끼리는 서로 모르면 좋습니다.
98-
하지만 현실적으로 **다른 Entity를 포함**하거나 **상호작용**하는 경우가 있습니다.
99-
이때는 로직을 **상위 Layer(Feature/Page)** 로 올려 처리하세요.
115+
원칙적으로는 Entity Slice끼리는 서로 **서로를 모르는 상태**가 이상적입니다.
116+
하지만 실제 애플리케이션에서는 한 Entity가 다른 Entity를 **포함하거나**
117+
여러 Entity가 서로 **상호작용**하는 일이 자주 발생합니다.
118+
119+
이런 경우, 두 Entity 간의 구체적인 상호작용 로직은
120+
**상위 Layer(Feature 또는 Page)** 로 올려서 처리하는 것이 좋습니다.
100121

101-
만약 한 Entity 데이터에 다른 Entity가 포함된다면,
102-
`@x` 표기를 사용해 **교차 Public API**로 연결을 명시적으로 드러내세요.
122+
만약 한 Entity의 데이터 안에 다른 Entity가 포함되어야 한다면,
123+
`@x` 표기법을 사용해 **교차 Public API**를 통해 연결되었음을 명시해 주세요.
103124

104125
```ts title="entities/artist/model/artist.ts"
105126
import type { Song } from "entities/song/@x/artist";
106127

107128
export interface Artist {
108-
name: string;
109-
songs: Array<Song>;
129+
name: string;
130+
songs: Array<Song>;
110131
}
111132
```
112133

113-
자세한 내용은 [Cross-Import를 위한 Public API][public-api-for-cross-imports] 참고하세요.
134+
자세한 내용은 [Cross-Import를 위한 Public API][public-api-for-cross-imports] 문서를 참고하세요.
114135

115136
### Feature
116137

117-
사용자가 앱에서 수행하는 주요 기능을 담습니다.
118-
보통 특정 Entity와 연결됩니다.
138+
Features Layer에는 **사용자가 애플리케이션에서 수행하는 주요 기능**이 들어갑니다.
139+
보통 하나 이상의 Entity와 연관되어 동작합니다.
140+
141+
- 모든 동작을 무조건 Feature로 만들 필요는 없습니다.
142+
- **여러 페이지에서 재사용되는 기능**일 때 Feature로 추출하는 것을 고려하세요.
143+
- 예: 여러 종류의 에디터에서 동일한 댓글 기능을 사용한다면, `comments`를 Feature로 만들 수 있습니다.
144+
- Feature가 너무 많아지면, 중요한 기능이 어디 있는지 찾기 어려워질 수 있습니다.
119145

120-
- 모든 기능을 Feature로 만들 필요는 없습니다. 여러 페이지에서 재사용되는 경우에만 고려하세요.
121-
- 예: 여러 에디터에서 같은 댓글 기능을 쓴다면, comments를 Feature로 만듭니다.
122-
- Feature가 너무 많으면 중요한 기능을 찾기 어려워집니다.
146+
구성:
123147

124-
구성
125-
- 📁 ui — 상호작용 UI(예: 폼)
126-
- 📁 api — 기능 관련 API 요청
127-
- 📁 model — 검증, 내부 상태
128-
- 📁 config — Feature Flag
148+
- `📁 ui` — 상호작용 UI (예: 폼, 검색 바 등)
149+
- `📁 api` — 해당 기능과 직접 관련된 API 요청
150+
- `📁 model` — 검증 로직, 내부 상태 관리
151+
- `📁 config` — Feature Flag 등 기능별 설정
129152

130-
> 새로운 팀원이 들어왔을 때 Page와 Feature만 봐도 앱 기능 구조를 파악할 수 있도록 구성하세요.
153+
> 새로운 팀원이 프로젝트에 합류했을 때,
154+
> Page와 Feature만 훑어봐도 **이 앱이 어떤 기능을 제공하는지**를 대략 이해할 수 있도록 구성하는 것이 목표입니다.
131155
132156
### Widget
133157

134-
독립적으로 동작하는 큰 UI 블록입니다.
135-
여러 페이지에서 재사용되거나, 한 페이지에 큰 블록이 여럿 있을 때 유용합니다.
158+
Widgets Layer는 **독립적으로 동작하는 비교적 큰 UI 블록**을 두는 곳입니다.
159+
여러 페이지에서 재사용되거나, 한 페이지에서 **큰 섹션 단위로 나누어지는 UI 블록**있을 때 유용합니다.
136160

137161
:::tip
138162

139-
- 재사용되지 않고 특정 페이지의 핵심 콘텐츠라면 Widget으로 분리하지 말고 Page 안에 두세요.
140-
- Nested Routing(예: [Remix][ext-remix]) 환경에서는 Widget이 **Page와 유사한 방식**으로 동작합니다.
141-
예를 들어, 데이터 로딩, 로딩 상태 표시, 에러 처리 등을 포함해 **하나의 라우터 단위 블록**을 구성할 수 있습니다.
163+
재사용되지 않고 특정 페이지의 핵심 콘텐츠에만 쓰인다면, 굳이 Widget으로 분리하지 말고 Page 내부에 두는 것이 좋습니다.
164+
Nested Routing(예: [Remix][ext-remix]) 환경에서는 Widget이 **Page와 비슷한 역할**을 할 수 있습니다.
165+
예를 들어 데이터 로딩, 로딩 상태 표시, 에러 처리 등을 모두 포함하는 **하나의 라우터 단위 UI 블록**으로 동작할 수 있습니다.
142166

143167
:::
144168

145169
### Page
146170

147-
웹/앱의 **화면(screen) 또는 액티비티(activity)** 에 해당합니다.
148-
대부분 페이지 1개 = Slice 1개이지만, 유사한 페이지는 하나의 Slice로 묶을 수 있습니다.
171+
Pages Layer는 웹/앱에서 보이는 **화면(screen) 또는 액티비티(activity)** 에 해당합니다.
172+
일반적으로 “페이지 1개 = Slice 1개” 구조를 많이 사용하지만,
173+
구조가 유사한 페이지들은 하나의 Slice로 묶는 것도 가능합니다.
149174

150-
- 코드 찾기만 쉽다면 Page Slice 크기 제한은 없습니다.
151-
- 재사용되지 않는 UI는 Page 안에 둡니다.
152-
- 보통 전용 모델은 없고, 간단한 상태만 컴포넌트 내부에서 관리합니다.
175+
코드를 찾기만 쉽다면, Page Slice의 크기에 특별한 제한은 없습니다.
176+
재사용되지 않는 UI는 그대로 Page 내부에 두면 됩니다.
177+
Page Layer에는 보통 전용 model이 없으며, 필요한 경우 간단한 상태만 컴포넌트 내부에서 관리합니다.
153178

154-
구성 예
155-
- 📁 ui — UI, 로딩 상태, 에러 처리
156-
- 📁 api — 데이터 패칭/변경 요청
179+
구성 예:
180+
181+
- `📁 ui` — 페이지 UI, 로딩 상태, 에러 상태 처리
182+
- `📁 api` — 페이지에서 사용하는 데이터 패칭/변경 요청
157183

158184
### Process
159185

160186
:::caution
161187

162-
Deprecated — 기존 코드는 feature나 app으로 옮기세요.
188+
**Deprecated**기존에 사용하던 코드는 가능하면 Feature나 App Layer로 이동하세요.
163189

164190
:::
165191

166-
과거에는 여러 페이지를 넘나드는 기능을 위한 탈출구 역할이었지만,
167-
정의가 모호해 대부분의 앱에서는 사용하지 않습니다.
168-
라우터, 서버 레벨 로직은 App Layer에 두고, App이 너무 커질 때만 제한적으로 고려하세요.
192+
과거에는 여러 페이지를 넘나드는 복잡한 기능을 처리하기 위한 **탈출구 같은 Layer**로 사용되었습니다.
193+
하지만 역할이 모호하고, 대부분의 애플리케이션에서는 굳이 사용하지 않아도 충분히 설계가 가능합니다.
194+
195+
라우터, 서버 연동 같은 전역적인 로직은 보통 App Layer에 둡니다.
196+
App Layer가 너무 복잡해질 때 정말 필요한 경우에만 제한적으로 고려할 수 있습니다.
169197

170198
### App
171199

172-
앱 전역에서 동작하는 **환경 설정****공용 로직**을 관리하는 Layer입니다.
173-
예를 들어, 라우터 설정, 전역 상태 관리, 글로벌 스타일, 진입점 설정 등 **앱 전체에 영향을 주는 코드**를 둡니다.
200+
App Layer는 앱 전역에서 동작하는 **환경 설정****공용 로직**을 관리하는 곳입니다.
201+
예를 들어 라우터 설정, 전역 상태 관리(Store 설정), 글로벌 스타일 앱 진입점(Entry Point) 설정 등과 같이
202+
**앱 전체에 영향을 주는 코드**가 위치합니다.
203+
`shared`와 마찬가지로 Slice 없이 **Segment만으로 구성**합니다.
204+
205+
대표적인 Segment 예:
174206

175-
- shared처럼 Slice 없이 Segment로 구성합니다.
176-
- 대표 Segment:
177-
- `📁 routes` — Router 설정
178-
- `📁 store` — Global State Store 설정
179-
- `📁 styles` — Global Style
180-
- `📁 entrypoint` — Application Entry Point와 Framework 설정
207+
- `📁 routes` — Router 설정
208+
- `📁 store` — Global State Store 설정
209+
- `📁 styles` — Global Style
210+
- `📁 entrypoint` — Application Entry Point와 Framework 설정
181211

182212
[public-api-for-cross-imports]: /docs/reference/public-api#public-api-for-cross-imports
183213
[ext-remix]: https://remix.run

0 commit comments

Comments
 (0)