๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

FSD(FEATURE-SLICED DESIGN) ํด๋” ๊ตฌ์กฐ ์™„์ „ ์ •๋ณต

๐Ÿค” "์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ, ์ด๊ฒŒ ์ตœ์„ ์ผ๊นŒ?"

ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค ๋ณด๋ฉด ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ํŒŒ์ผ์ด ๋‚œ์žกํ•ด์ง€๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ค์›Œ์ง€๋Š” ๊ฒฝํ—˜์„ ํ•ด๋ดค์„ ๊ฒƒ์ด๋‹ค.

 

์ปดํฌ๋„ŒํŠธ๋Š” ์–ด๋””์— ๋‘ฌ์•ผ ํ• ๊นŒ?
๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ ์–ด๋””์— ๋ฐฐ์น˜ํ•ด์•ผ ํ• ๊นŒ?
API ํ˜ธ์ถœ ๋กœ์ง์€ ์–ด๋””์— ๋‘ฌ์•ผ ํ•˜์ง€?
ํŽ˜์ด์ง€๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ๊ด€๋ฆฌ๊ฐ€ ์ ์  ํž˜๋“ค์–ด์ง€๋Š”๋ฐ...


์ด ๊ณ ๋ฏผ์„ ํ•ด๊ฒฐํ•ด ์ค„ ํด๋” ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋กœ FSD(Feature-Sliced Design) ์ด๋‹ค.


๐Ÿ”ฅ FSD(Feature-Sliced Design)๋ž€?

FSD๋Š” ๊ธฐ๋Šฅ(Feature) ์ค‘์‹ฌ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ๋Ÿฌ์‹œ์•„ ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ์ฒ˜์Œ ์ •๋ฆฝ๋œ ํด๋” ๊ตฌ์กฐ์ด๋‹ค.
๊ธฐ์กด์˜ ํŽ˜์ด์ง€(Page)-์ปดํฌ๋„ŒํŠธ(Component)-์„œ๋น„์Šค(Service) ๋ฐฉ์‹๊ณผ ๋‹ฌ๋ฆฌ, ๊ธฐ๋Šฅ ๋‹จ์œ„๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ๋‚˜๋ˆ ์„œ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ ๋‹ค๊ณ  ํ•œ๋‹ค.

 

๐Ÿ“‚ FSD ํด๋” ๊ตฌ์กฐ ํ•œ๋ˆˆ์— ๋ณด๊ธฐ

๐Ÿ“‚ src
 โ”ฃ ๐Ÿ“‚ app       # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ ์„ค์ • (๋ผ์šฐํŒ…, ๊ธ€๋กœ๋ฒŒ ์„ค์ • ๋“ฑ)
 โ”ฃ ๐Ÿ“‚ shared    # ํ”„๋กœ์ ํŠธ ์ „์—ญ์—์„œ ๊ณต์œ ๋˜๋Š” UI ์ปดํฌ๋„ŒํŠธ, ์œ ํ‹ธ ํ•จ์ˆ˜, hooks ๋“ฑ
 โ”ฃ ๐Ÿ“‚ entities  # ํ•ต์‹ฌ ๋„๋ฉ”์ธ ๋ชจ๋ธ๊ณผ ๊ด€๋ จ๋œ ์ƒํƒœ ๊ด€๋ฆฌ, API ์ •์˜
 โ”ฃ ๐Ÿ“‚ features  # ๊ฐœ๋ณ„์ ์ธ ๊ธฐ๋Šฅ ๋‹จ์œ„ (๋กœ๊ทธ์ธ, ๊ฒ€์ƒ‰, ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋“ฑ)
 โ”ฃ ๐Ÿ“‚ widgets   # ์—ฌ๋Ÿฌ ๊ฐœ์˜ feature๋ฅผ ์กฐํ•ฉํ•œ UI ๋ธ”๋ก (ํ—ค๋”, ์‚ฌ์ด๋“œ๋ฐ”, ๋Œ€์‹œ๋ณด๋“œ ๋“ฑ)
 โ”ฃ ๐Ÿ“‚ pages     # ํŽ˜์ด์ง€ ๋‹จ์œ„์˜ ๊ตฌ์„ฑ ์š”์†Œ (ex. ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€, ํ”„๋กœํ•„ ํŽ˜์ด์ง€)
 โ”— ๐Ÿ“‚ processes # ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์™€ ๊ธฐ๋Šฅ์„ ๊ฒฐํ•ฉํ•˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ํ๋ฆ„ ๋‹จ์œ„

๐Ÿง FSD ํด๋” ๊ตฌ์กฐ ์ƒ์„ธ ๋ถ„์„

1๏ธโƒฃ app/ → ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐ ์„ค์ •

  • index.tsx ๋˜๋Š” App.tsx ์œ„์น˜
  • ๋ผ์šฐํŒ…, ํ…Œ๋งˆ, ์ „์—ญ ์ƒํƒœ ์„ค์ • ๋“ฑ ํฌํ•จ

๐Ÿ“Œ ์˜ˆ์‹œ

app/
 โ”ฃ providers/       # ์ƒํƒœ ๊ด€๋ฆฌ, ํ…Œ๋งˆ ์ œ๊ณต
 โ”ฃ routes/          # ๋ผ์šฐํŒ… ์„ค์ •
 โ”— App.tsx         # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ง„์ž…์ 

2๏ธโƒฃ shared/ → ๋ชจ๋“  ๊ณณ์—์„œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์š”์†Œ

  • ๊ณตํ†ต UI ์ปดํฌ๋„ŒํŠธ (๋ฒ„ํŠผ, ์ธํ’‹, ๋ชจ๋‹ฌ ๋“ฑ)
  • ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜, hooks, ์Šคํƒ€์ผ ํŒŒ์ผ

๐Ÿ“Œ ์˜ˆ์‹œ

shared/
 โ”ฃ ui/          # ๋ฒ„ํŠผ, ์ž…๋ ฅ ํ•„๋“œ ๋“ฑ ๊ณตํ†ต UI
 โ”ฃ api/         # HTTP ์š”์ฒญ ํ•จ์ˆ˜
 โ”ฃ hooks/       # ์ปค์Šคํ…€ ํ›…
 โ”ฃ lib/         # ํ—ฌํผ ํ•จ์ˆ˜, ํฌ๋งทํ„ฐ ๋“ฑ
 โ”— styles/      # ์ „์—ญ ์Šคํƒ€์ผ

3๏ธโƒฃ entities/ → ๋„๋ฉ”์ธ ๋ชจ๋ธ๊ณผ ๊ด€๋ จ๋œ ์ฝ”๋“œ

  • API ํ˜ธ์ถœ, ์ƒํƒœ ๊ด€๋ฆฌ, ํƒ€์ž… ์ •์˜ ๋“ฑ
  • ์˜ˆ๋ฅผ ๋“ค์–ด User, Product ๋“ฑ์˜ ์—”ํ„ฐํ‹ฐ ๊ด€๋ฆฌ

๐Ÿ“Œ ์˜ˆ์‹œ

entities/
 โ”ฃ user/       # ์‚ฌ์šฉ์ž ๊ด€๋ จ API, ์ƒํƒœ ๊ด€๋ฆฌ
 โ”ฃ product/    # ์ƒํ’ˆ ๊ด€๋ จ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
 โ”— cart/       # ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ

4๏ธโƒฃ features/ → ๋…๋ฆฝ์ ์ธ ๊ธฐ๋Šฅ ๋‹จ์œ„

  • ๋กœ๊ทธ์ธ, ํšŒ์›๊ฐ€์ž…, ๊ฒ€์ƒ‰, ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋“ฑ
  • ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์—์„œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๐Ÿ“Œ ์˜ˆ์‹œ

features/
 โ”ฃ auth/       # ๋กœ๊ทธ์ธ, ํšŒ์›๊ฐ€์ž…
 โ”ฃ search/     # ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ
 โ”ฃ cart/       # ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๊ธฐ๋Šฅ
 โ”— profile/    # ํ”„๋กœํ•„ ์ˆ˜์ • ๊ธฐ๋Šฅ

5๏ธโƒฃ widgets/ → UI ๋ธ”๋ก ์กฐํ•ฉ (ํ—ค๋”, ์‚ฌ์ด๋“œ๋ฐ” ๋“ฑ)

  • ์—ฌ๋Ÿฌ feature๋ฅผ ์กฐํ•ฉํ•˜์—ฌ UI๋ฅผ ๊ตฌ์„ฑ
  • ํŽ˜์ด์ง€์™€ ๋…๋ฆฝ์ ์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๐Ÿ“Œ ์˜ˆ์‹œ

widgets/
 โ”ฃ navbar/     # ๋‚ด๋น„๊ฒŒ์ด์…˜ ๋ฐ”
 โ”ฃ sidebar/    # ์‚ฌ์ด๋“œ๋ฐ”
 โ”ฃ dashboard/  # ๋Œ€์‹œ๋ณด๋“œ
 โ”— footer/     # ํ‘ธํ„ฐ

6๏ธโƒฃ pages/ → ๋ผ์šฐํŠธ ๋‹จ์œ„์˜ ํŽ˜์ด์ง€

  • ๊ฐ๊ฐ์˜ ํŽ˜์ด์ง€๋Š” feature์™€ widget์„ ์กฐํ•ฉํ•˜์—ฌ ๊ตฌ์„ฑ

๐Ÿ“Œ ์˜ˆ์‹œ

pages/
 โ”ฃ home/       # ํ™ˆ ํŽ˜์ด์ง€
 โ”ฃ login/      # ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€
 โ”ฃ profile/    # ํ”„๋กœํ•„ ํŽ˜์ด์ง€
 โ”— dashboard/  # ๋Œ€์‹œ๋ณด๋“œ

7๏ธโƒฃ processes/ → ๋น„์ฆˆ๋‹ˆ์Šค ํ๋ฆ„ ๊ด€๋ฆฌ

  • ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€, ์œ„์ ฏ, ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด ํ๋ฆ„์„ ์ •์˜

๐Ÿ“Œ ์˜ˆ์‹œ

processes/
 โ”ฃ checkout/   # ๊ฒฐ์ œ ํ”„๋กœ์„ธ์Šค (์žฅ๋ฐ”๊ตฌ๋‹ˆ → ๊ฒฐ์ œ → ์™„๋ฃŒ)
 โ”ฃ onboarding/ # ์‹ ๊ทœ ์‚ฌ์šฉ์ž ์˜จ๋ณด๋”ฉ ํ”Œ๋กœ์šฐ
 โ”— auth-flow/  # ๋กœ๊ทธ์ธ → ๊ถŒํ•œ ์ฒดํฌ → ๋Œ€์‹œ๋ณด๋“œ

๐ŸŽฏ FSD ๊ตฌ์กฐ์˜ ์žฅ์ 

โœ… ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด → ๊ธฐ๋Šฅ๋ณ„๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์–ด ์ˆ˜์ •ํ•˜๊ธฐ ์‰ฌ์›€
โœ… ํ™•์žฅ์„ฑ → ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ๊ธฐ์กด ์ฝ”๋“œ์— ์˜ํ–ฅ์„ ์ตœ์†Œํ™”
โœ… ์žฌ์‚ฌ์šฉ์„ฑ ์ฆ๊ฐ€ → shared/, widgets/ ํด๋” ๋•๋ถ„์— ์ค‘๋ณต ์ฝ”๋“œ ๊ฐ์†Œ
โœ… ๋„๋ฉ”์ธ ์ค‘์‹ฌ ์„ค๊ณ„ → ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ UI๊ฐ€ ์ ์ ˆํžˆ ๋ถ„๋ฆฌ๋จ


๐Ÿš€ FSD, ์ ์šฉํ•ด ๋ณผ๊นŒ?

๐Ÿ”ฅ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์–ด๋–ค ํด๋” ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‚˜์š”?
์ฒ˜์Œ์—๋Š” ์ต์ˆ™ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ์ง„๊ฐ€๋ฅผ ๋ฐœํœ˜ํ•˜๋Š” ๊ตฌ์กฐ์ธ ๊ฒƒ ๊ฐ™๋‹ค. ํŠนํžˆ ํ”„๋ก ํŠธ์—”๋“œ ์•„ํ‚คํ…์ฒ˜์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์ด ๋งŽ๋‹ค๋ฉด ํ•œ ๋ฒˆ ์ ์šฉํ•ด๋ณด๋Š” ๊ฒƒ๋„ ์ถ”์ฒœํ•œ๋‹ค!