1. ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ๊ฐ ์ค์ํ ๊น?
- ์ ์ง๋ณด์์ฑ: ๊ธฐ๋ฅ์ด ๋์ด๋๊ณ ํ์์ด ๋ง์์ง์๋ก, ๊ตฌ์กฐ๊ฐ ์ํค๋ฉด ์ ์ง๋ณด์๊ฐ ์ด๋ ต๋ค.
- ์ฝ๋ ํ์ ์๋: ํ์ผ์ ๋น ๋ฅด๊ฒ ์ฐพ์ ์ ์์ด ์์ฐ์ฑ ํฅ์.
- ํ์ ๋ช ํ์ฑ: ์ญํ ๋ณ/๊ธฐ๋ฅ๋ณ ์ฑ ์์ด ๋ช ํํด์ ธ ์ฝ๋ ์ถฉ๋ ์ค์ด๋ฆ.
- ํ์ฅ์ฑ: ๊ตฌ์กฐ๊ฐ ์ ์ง์ฌ ์์ผ๋ฉด ๊ธฐ๋ฅ์ ํ์ฅํ๊ธฐ ์ฌ์.
์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ณต์กํ ์๋ก ๋ ์ค์.
2. "๋๋๋ค"๋ ๊ฑด ๋ฌด์์ ๊ธฐ์ค์ผ๋ก?
- ๋๋ ํ ๋ฆฌ๋ฅผ ๋๋๋ ๊ฐ๋ ์ ๊ฒฐ๊ตญ ๋ชจ๋ํ๋ฅผ ์ด๋ป๊ฒ ์ ์ฉํ ๊ฒ์ธ๊ฐ์ ๋ํ ๊ณ ๋ฏผ.
- ESM๊ณผ ๊ฐ์ ๋ชจ๋ ์์คํ
์ด ๋ถ์กฑํ๋ ์์ ์๋?
- ์ ์ญ ๊ฐ์ฒด(namespace)๋ฅผ ์ด์ฉํด ๊ณ์ธต์ ํ๋ด๋ด๊ธฐ๋ ํจ.
๊ณผ๊ฑฐ ๋ฐฉ์: Namespace ํจํด (ESM ์ด์ )
(์ ์ ์ญ๋ณ์ ํ๋๋ผ๋...)
const naver = {}
naver.auth = {}
naver.auth.login = function() {}
naver.store = {}
naver.store.product = {}
naver.store.product.list = function() {}
ํ์ฌ ๋ฐฉ์: ESM (ES Modules) ๊ธฐ๋ฐ ๊ตฌ์กฐํ
- ESM ๋๋ถ์ React๋ฅผ ๋น๋กฏํ SPA ๊ตฌ์กฐ์์ ํ์ผ ๋จ์ ๋ชจ๋ํ → ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐํ → ๋ช ํํ ์ฑ ์ ๋ถ๋ฆฌ๊ฐ ๊ฐ๋ฅํด์ง
→ ๊ฒฐ๊ณผ์ ์ผ๋ก ์ค๋๋ ์ฐ๋ฆฌ๊ฐ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์ ๊ฒฝ ์ฐ๋ ์ด์ ๋,
๋ชจ๋ ์์คํ
(ESM)์ด ์ฝ๋๋ฅผ ์ญํ /๊ธฐ๋ฅ ๋จ์๋ก ์์ ํ๊ฒ ๋๋ ์ ์๋ ํ๊ฒฝ์ ์ ๊ณตํด์ฃผ๊ธฐ ๋๋ฌธ
- "๋๋๋ค"๋ ๊ฑด ์ญํ , ๊ธฐ๋ฅ, ์ฑ ์์ ๊ธฐ์ค์ผ๋ก ์ฝ๋๋ฅผ ๊ทธ๋ฃนํํ๋ค๋ ๋ป.
- ESM ๊ตฌ์กฐ๋ผ๋ฉด?
src/
โโโ auth/
โ โโโ login.ts
โโโ store/
โ โโโ product/
โ โโโ list.ts
์ด๋ ๊ฒ ๊ตฌ์กฐํ๋ ์ฝ๋๋ ํ์์ด ์ฝ๊ณ , ์๋ ํ์ ๋ ๋น ๋ฅด๋ค.
3. ์ฃผ์ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ ํจํด ๋น๊ต
3.1 Atomic Design ๊ตฌ์กฐ

https://atomicdesign.bradfrost.com/chapter-2/
'ํํ ๊ฐ๋ ์ UI์ ์์ฉํด‘์๊ฒ ์ชผ๊ฐ์ ์กฐ๋ฆฝํ์' by Brad Frost.
src/
โโโ components/
โ โโโ atoms/
โ โโโ molecules/
โ โโโ organisms/
โ โโโ templates/
- UI ๋ณต์ก๋ ๊ธฐ์ค์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ๊ณ์ธตํ
- ๋์์ธ ์์คํ ์ค์ฌ์ ํ๋ก์ ํธ์ ์ ํฉ
Atomic์ ๊ตฌ์ฑ ์๋ฏธ
- Atoms(์์): ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ UI ์์
- Button, Input ๋ฑ
- Molecules(๋ถ์): ๊ฐ๋จํ ์์๋ค์ ์กฐํฉ
- SearchForm ๋ฑ
- Organisms(์ ๊ธฐ์ฒด): ์๋ฏธ ์๋ ์น์
๋จ์ UI
- Header, ProductList ๋ฑ
- ์ปค์ง๊ธฐ ์ฌ์. ๋ค์ ๋ถํด.
- Templates: ํ์ด์ง ๊ตฌ์ฑ ๋ ์ด์์ ๊ตฌ์กฐ
- Sidebar + Header + Content ์์ญ
- ๊ตฌ์กฐ๋ง ๋ด๋นํ์.. Pages๋ ๊ตฌ๋ถ์ํด์ผํจ
- Pages: ์ค์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฉํ ์์ ํ ํ์ด์ง
- ๋ณดํต API๊ฐ ๋ค์ด๊ฐใท
์ฅ์ : ์๊ฐ์ ์ผ๋ก ๋ช
ํ, ์ปดํฌ๋ํธ ์ฌ์ฌ์ฉ ๊ตฌ์กฐ์ ์ข์
๋จ์ : ๋๋ฉ์ธ/๊ธฐ๋ฅ ์ค์ฌ ์ค๊ณ์๋ ๋ค์ ๊ฑฐ๋ฆฌ๊ฐ ์์
warning
- ์ญ์ฐธ์กฐ ๊ธ์ง
- ๊ณผ๋ํ ๋ถํด ์์ฌ
- ๋๋ฉ์ธ ๊ตฌ์กฐ๋ฅผ ๋ฏน์ค ํ ์๋ ์์.
- ๋๋๋๊ฒ์ด ๋ชฉํ๋ ์๋๋ค.
- ์ ์ฐํ ์ ์ฉ์ด ์ค์
3.2. Layered Architecture ๊ตฌ์กฐ (๊ณ์ธตํ)
src/
โโโ components/
โโโ pages/
โโโ services/
โโโ hooks/
โโโ utils/
- ์ญํ ๋ณ๋ก ๋๋ ํ ๋ฆฌ๋ฅผ ๋๋๋ ๊ฐ์ฅ ๋ฌด๋ํ ๋ฐฉ์์ด๋ค.
์ฅ์ : ์ง๊ด์ , ์ต์ํจ
๋จ์ : ๊ธฐ๋ฅ์ด ํฉ์ด์ ธ ์์ด ์์ง๋ ๋ฎ์, ์ ์ง๋ณด์ ์ด๋ ค์
3.3 Layered + Atomic ๊ตฌ์กฐ
src/
โโโ components/
โ โโโ atoms/
โ โโโ molecules/
โโโ pages/
โโโ services/
- LA ๊ตฌ์กฐ์ Atomic์ ๊ฒฐํฉ → UI๋ Atomic ๋ฐฉ์์ผ๋ก, ๋๋จธ์ง๋ ์ญํ ์ค์ฌ์ผ๋ก ๋ถ๋ฆฌ
์ฅ์ : ๋์์ธ ์์คํ
๊ณผ ์ฑ ๊ตฌ์กฐ ๊ณต์กด ๊ฐ๋ฅ
๋จ์ : ๋ณต์กํ ๊ตฌ์กฐ์์๋ ๊ฒฝ๊ณ๊ฐ ์ ๋งคํด์ง ์ ์์
3.4 Layered + Colocation ๊ตฌ์กฐ
- ์ญํ ๋จ์๋ก ๊ตฌ์กฐ๋ฅผ ์ ์งํ๋ฉด์, ๋ด๋ถ๋ ๊ธฐ๋ฅ ๋จ์๋ก ์ธ์ ๋ฐฐ์น
src/
โโโ components/
โ โโโ ProductCard/
โ โโโ ProductCard.tsx
โ โโโ ProductCard.module.css
โ โโโ ProductCard.test.tsx
์ฅ์ : ์ ์ง๋ณด์ ํธํจ, ์ฝ๋ ์ง์ค๋ ๋์
๋จ์ : ์ผ๊ด์ฑ ์์ด ์์ด๋ฉด ๋ณต์กํด์ง ์ ์์
4. Feature-Sliced Design (FSD) ๊ตฌ์กฐ
FSD๋ ๊ธฐ๋ฅ ์ค์ฌ์ผ๋ก ๋ถ๋ฆฌ๋๋ฉด์๋ ๊ฐ ๊ณ์ธต์ ์ฑ ์์ด ๋ช ํํ๊ฒ ๋๋๋ ๊ตฌ์กฐ.
๋๋ฉ์ธ, ๊ธฐ๋ฅ, ํํ์ ์ ์ ํ ๋ถ๋ฆฌํ์ฌ ์ ์ง๋ณด์์ฑ๊ณผ ํ์ ํจ์จ์ ๊ทน๋ํํ ์ ์๋ค.
src/
โโโ app/
โโโ entities/
โโโ features/
โโโ shared/
โโโ widgets/
โโโ pages/
- app: ์ฑ์ ์ง์
์ ๊ณผ ์ ์ญ ์ค์ ์ ๋ด๋น.
- ์: App.tsx, store.ts, ๋ผ์ฐํฐ ์ค์ ๋ฑ.
- ์ ์ญ ํ๋ก๋ฐ์ด๋, ์๋ฌ ๋ฐ์ด๋๋ฆฌ, ์ด๊ธฐ ๋ก๋ฉ ๋ก์ง ๋ฑ
- entities: ํต์ฌ ๋๋ฉ์ธ ๋จ์. ์ํ, ๋ชจ๋ธ, UI ๋ถ๋ฆฌ.
- features: ์ฌ์ฉ์ ๊ธฐ๋ฅ ๋จ์. ์ก์ ์ค์ฌ.
- shared: ๋ฒ์ฉ UI ๋ฐ ๋๊ตฌ.
- widgets: ์ฌ๋ฌ feature์ entity๋ฅผ ์กฐํฉํ UI ๋ธ๋ก.
- pages: ๋ผ์ฐํธ ๋จ์ ํ๋ฉด.
์ฅ์ : ์ญํ + ๊ธฐ๋ฅ + ๋๋ฉ์ธ ๋ถ๋ฆฌ๊ฐ ๋ช ํ, ๋๊ท๋ชจ ์ฑ์ ์ ํฉ
๋จ์ : ๋ฌ๋์ปค๋ธ ์์, ์ด๊ธฐ ๋์ ์ง์ ์ฅ๋ฒฝ ์กด์ฌ. ํธ๋ฏธ๋ก ์ธ๊ฑด ํธ๋ฏธ๋ก ์ฐ์..
5. FSD ์ ์ฉ ์์
5.1 ์นด์ดํฐ ์ฑ
src/
โโโ entities/Counter/
โ โโโ model/store.ts
โ โโโ ui/CounterDisplay.tsx
โโโ features/counterControl/
โ โโโ ui/CounterControls.tsx
โโโ widgets/CounterBox/
โ โโโ CounterBox.tsx
- ์ํ ๊ด๋ฆฌ (store.ts)๋ entity์ ์์น
- +, - ๋ฒํผ์ feature์์ ๊ธฐ๋ฅ ๋ด๋น
- ์ ์ฒด ๋ฐ์ค๋ widget์์ ์กฐ๋ฆฝ
entities/Counter/model/store.ts
- Store(state)์ ์ง์ค. ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๊ตฌํํ ์๋ ์์.
import { useState } from 'react'
export function useCounterStore() {
const [count, setCount] = useState(0)
const increment = () => setCount((c) => c + 1)
const decrement = () => setCount((c) => c - 1)
return { count, increment, decrement }
}
entities/Counter/ui/CounterDisplay.tsx
import React from 'react'
export const CounterDisplay = ({ count }: { count: number }) => {
return <h1>ํ์ฌ ์นด์ดํธ: {count}</h1>
}
features/counterControl/ui/CounterControls.tsx
import React from 'react'
export const CounterControls = ({
onIncrement,
onDecrement,
}: {
onIncrement: () => void
onDecrement: () => void
}) => {
return (
<div>
<button onClick={onDecrement}>-</button>
<button onClick={onIncrement}>+</button>
</div>
)
}
widgets/CounterBox/CounterBox.tsx
import { useCounterStore } from '@/entities/Counter/model/store'
import { CounterDisplay } from '@/entities/Counter/ui/CounterDisplay'
import { CounterControls } from '@/features/counterControl/ui/CounterControls'
export const CounterBox = () => {
const { count, increment, decrement } = useCounterStore()
return (
<div>
<CounterDisplay count={count} />
<CounterControls onIncrement={increment} onDecrement={decrement} />
</div>
)
}
'๐ ํ๋ก ํธ์๋(FE)' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| Next.js ์์ํ๊ธฐ (1) | 2026.01.22 |
|---|---|
| ํ๋ก ํธ์๋ ํ ์คํธ ๋๊ตฌ ( MSW, Vitest, React Testing Library ) (0) | 2026.01.21 |
| React ์ํ๊ด๋ฆฌ ( ์ง์ญ, ์ ์ญ, ์๋ฒ ์ปดํฌ๋ํธ ) (0) | 2026.01.20 |
| React ์ฑ๋ฅ ์ต์ ํ (0) | 2026.01.20 |
| CSR / SSR / SSG / ISR ๋ ๋๋ง ๋ฐฉ์ ๋น๊ต (1) | 2026.01.17 |