Skip to content

Commit 31addca

Browse files
authored
docs: Public API page translated into Korean (#792)
* docs: Public API page translated into Korean * docs: publicAPI page update
1 parent 3a53c76 commit 31addca

File tree

1 file changed

+164
-0
lines changed
  • i18n/kr/docusaurus-plugin-content-docs/current/reference

1 file changed

+164
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
---
2+
sidebar_position: 3
3+
---
4+
5+
# Public API
6+
7+
Public API는 Slice와 같은 모듈 그룹과 이를 사용하는 코드 사이의 Contract 역할을 합니다. 또한 Gate 역할을 하여 특정 Object에 접근할 수 있는 유일한 경로를 제공합니다.
8+
9+
일반적으로 Public API는 Re-export가 포함된 Index File로 구현됩니다:
10+
11+
```js title="pages/auth/index.js"
12+
export { LoginPage } from "./ui/LoginPage";
13+
export { RegisterPage } from "./ui/RegisterPage";
14+
```
15+
16+
## 좋은 Public API의 조건
17+
18+
좋은 Public API는 Slice 사용과 통합을 용이하게 합니다. 세 가지 주요 목표:
19+
20+
1. Application은 Slice 내부 구조의 Refactoring에 영향받지 않아야 함
21+
2. Slice 동작의 중요한 변경은 Public API 변경으로 이어져야 함
22+
3. Slice의 필요한 부분만 외부에 노출되어야 함
23+
24+
마지막 목표는 실용적 고려사항을 포함합니다. 초기 개발 시 모든 Export를 자동으로 노출하고 싶은 유혹이 있어 Wildcard(*) Re-export를 사용하려 할 수 있습니다:
25+
26+
```js title="Bad practice, features/comments/index.js"
27+
// ❌ 잘못된 예시
28+
export * from "./ui/Comment"; // 👎 사용하지 마세요
29+
export * from "./model/comments"; // 💩 나쁜 관행
30+
```
31+
32+
이는 Slice Interface를 모호하게 만들어 발견성과 이해도를 낮춥니다. Interface가 불명확하면 Application 통합을 위해 코드를 깊이 분석해야 합니다.
33+
34+
또한 모듈 내부 구현이 의도치 않게 노출될 수 있어, 외부 코드가 이에 의존하게 되면 Refactoring이 어려워집니다.
35+
36+
## Cross-Import를 위한 Public API {#public-api-for-cross-imports}
37+
38+
Cross-import는 같은 Layer의 한 Slice가 다른 Slice를 Import하는 것입니다. [Layer Import Rule][import-rule-on-layers]으로 금지되지만, 때로는 필요한 경우가 있습니다.
39+
40+
예를 들어, Business Entity들은 실제로 서로 참조하는 경우가 많습니다. 이런 관계를 우회하기보다 코드에 자연스럽게 반영하는 것이 더 적절할 수 있습니다.
41+
42+
이를 위해 `@x-` 표기법의 특별한 Public API를 사용할 수 있습니다. Entity A와 B가 있고 B가 A의 일부를 Import해야 한다면, A는 B를 위한 전용 Public API를 선언할 수 있습니다:
43+
44+
- `📂 entities`
45+
- `📂 A`
46+
- `📂 @x`
47+
- `📄 B.ts``entities/B/` 전용 Public API
48+
- `📄 index.ts` — 일반 Public API
49+
50+
이제 `entities/B/` 코드는 `entities/A/@x/B`에서 필요한 부분을 Import할 수 있습니다:
51+
52+
```ts
53+
import type { EntityA } from "entities/A/@x/B";
54+
```
55+
56+
`A/@x/B`는 'A와 B의 교차'를 의미합니다.
57+
58+
:::note
59+
60+
Cross-import는 최소화해야 하며, **이 표기법은 Entity Layer에서만 사용**하세요. Cross-import 제거가 비효율적이거나 비현실적일 수 있기 때문입니다.
61+
62+
:::
63+
64+
## Index File의 문제점
65+
66+
Index File(Barrel File)은 Public API 정의의 일반적 방법이지만, 특정 Bundler나 Framework에서 문제를 일으킬 수 있습니다.
67+
68+
### Circular Import
69+
70+
Circular Import는 파일들이 서로를 순환적으로 Import하는 경우입니다.
71+
72+
<!-- TODO: add backgrounds to the images below, check on mobile -->
73+
74+
<figure>
75+
<img src="/img/circular-import-light.svg#light-mode-only" width="60%" alt="세 파일이 서로 원형으로 import하는 모습" />
76+
<img src="/img/circular-import-dark.svg#dark-mode-only" width="60%" alt="세 파일이 서로를 원형으로 import하고 있는 예시입니다." />
77+
<figcaption>
78+
위 그림: `fileA.js`, `fileB.js`, `fileC.js` 파일의 Circular Import 예시
79+
</figcaption>
80+
</figure>
81+
82+
이는 Bundler가 처리하기 어렵고 Runtime Error의 원인이 될 수 있습니다.
83+
84+
Index File 사용 시 Circular Import가 발생하기 쉽습니다. 특히 Slice의 Public API에서 여러 Object를 노출할 때 자주 발생합니다.
85+
86+
예시) `HomePage``loadUserStatistics`가 Public API로 노출되고 `HomePage``loadUserStatistics`에 접근해야 할 때:
87+
88+
```jsx title="pages/home/ui/HomePage.jsx"
89+
import { loadUserStatistics } from "../"; // pages/home/index.js에서 import
90+
91+
export function HomePage() { /**/ }
92+
```
93+
94+
```js title="pages/home/index.js"
95+
export { HomePage } from "./ui/HomePage";
96+
export { loadUserStatistics } from "./api/loadUserStatistics";
97+
```
98+
99+
이는 Circular Import를 생성합니다: `index.js``ui/HomePage.jsx`를 Import하고, `ui/HomePage.jsx`가 다시 `index.js`를 Import합니다.
100+
101+
해결을 위한 두 가지 원칙:
102+
- 같은 Slice 내: 항상 Relative Path Import 사용, 전체 경로 명시
103+
- 다른 Slice Import: 항상 Alias 등의 Absolute Import 사용
104+
105+
### Shared의 Large Bundle과 Tree-shaking 문제 {#large-bundles}
106+
107+
일부 Bundler는 모든 것을 Re-export하는 Index File이 있을 때 Tree-shaking(미사용 코드 제거)을 제대로 수행하지 못할 수 있습니다.
108+
109+
일반적으로 Public API에서는 큰 문제가 되지 않습니다. Module 내용이 밀접하게 연관되어 있어 하나를 Import하면 다른 것들도 필요한 경우가 많기 때문입니다. 하지만 FSD의 Public API Rule은 `shared/ui``shared/lib`에서 문제가 될 수 있습니다.
110+
111+
이 두 폴더는 보통 연관성이 적은 Component들의 집합입니다. 예를 들어, `shared/ui`는 UI Library의 모든 Component를 포함할 수 있습니다:
112+
113+
114+
- `📂 shared/ui/`
115+
- `📁 button`
116+
- `📁 text-field`
117+
- `📁 carousel`
118+
- `📁 accordion`
119+
120+
Syntax Highlighter나 Drag-and-Drop Library 같은 Heavy Dependency가 있을 때 문제가 더 심각해집니다. `shared/ui`에서 Button 같은 간단한 Component를 사용하는 모든 Page에 이런 Heavy Dependency가 포함되는 것은 피해야 합니다.
121+
122+
`shared/ui``shared/lib`의 단일 Public API로 인해 Bundle Size가 커진다면, 각 Component나 Library에 대해 별도의 Index File을 만드는 것이 좋습니다:
123+
124+
- `📂 shared/ui/`
125+
- `📂 button`
126+
- `📄 index.js`
127+
- `📂 text-field`
128+
- `📄 index.js`
129+
130+
이렇게 하면 다음과 같이 직접 Import가 가능합니다:
131+
132+
```js title="pages/sign-in/ui/SignInPage.jsx"
133+
import { Button } from '@/shared/ui/button';
134+
import { TextField } from '@/shared/ui/text-field';
135+
```
136+
137+
### Public API 우회 방지의 한계
138+
139+
Slice에 Index File을 추가해도 직접 Import를 막을 수는 없습니다. 특히 IDE의 Auto Import 기능에서 문제가 됩니다. Import 가능한 여러 경로 중 IDE가 직접 Import를 선택하여 Slice의 Public API Rule을 위반할 수 있습니다.
140+
141+
이 문제를 자동으로 감지하고 방지하려면 FSD용 Architecture Linter인 [Steiger][ext-steiger]를 사용하세요.
142+
143+
### Large Project에서의 Bundler 성능 문제
144+
145+
TkDodo의 ["Please Stop Using Barrel Files"][ext-please-stop-using-barrel-files] 글처럼, 많은 Index File은 Development Server 속도를 저하시킬 수 있습니다.
146+
147+
해결 방안:
148+
1. ["Shared의 Large Bundle 문제"](#large-bundles) 조언을 따르세요. `shared/ui``shared/lib`에 하나의 큰 Index File 대신 각 Component/Library별 Index File을 사용하세요.
149+
2. Slice Layer의 Segment에서 Index File 생성을 피하세요.
150+
예) "comments" Feature의 `📄 features/comments/index.js`가 있다면, `📄 features/comments/ui/index.js` 같은 추가 Index File은 불필요
151+
152+
3. 대규모 프로젝트는 여러 큰 Chunk로 분할을 고려하세요.
153+
예) Google Docs처럼 Document Editor와 File Browser를 분리. Monorepo로 각 Package가 독립적 Layer 구조를 가진 FSD Root가 되도록 구성:
154+
- 일부 Package는 Shared와 Entity Layer만 포함
155+
- 다른 Package는 Page와 App Layer만 포함
156+
- 또 다른 Package는 자체 작은 Shared와 다른 Package의 큰 Shared 활용 가능
157+
158+
<!-- TODO: add a link to a page that explains this in more detail (when one will exist) -->
159+
160+
<!-- TODO: discuss issues with mixing server/client code in Next/Remix -->
161+
162+
[import-rule-on-layers]: /docs/reference/layers#import-rule-on-layers
163+
[ext-steiger]: https://github.com/feature-sliced/steiger
164+
[ext-please-stop-using-barrel-files]: https://tkdodo.eu/blog/please-stop-using-barrel-files

0 commit comments

Comments
 (0)