[๐Ÿค–] Feature-Sliced Design (FSD)์œผ๋กœ ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ํ”„๋ก ํŠธ์—”๋“œ ์•„ํ‚คํ…์ฒ˜ ๊ตฌ์ถ•ํ•˜๊ธฐ

Feature-Sliced Design (FSD)์€ ๋Œ€๊ทœ๋ชจ ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ™•์žฅ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’์ด๋Š” ๊ฐ•๋ ฅํ•œ ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด์ด์—์š”. FSD์˜ ํ•ต์‹ฌ ์›์น™, ๋ ˆ์ด์–ด ๊ตฌ์กฐ, ์‹ค๋ฌด ์ ์šฉ ๋ฐฉ๋ฒ•์„ ์ฝ”๋“œ ์˜ˆ์‹œ์™€ ํ•จ๊ป˜ ์ž์„ธํžˆ ์•Œ์•„๋ด์š”.

22๋ถ„
๋‹จ์–ด: 2,002๊ฐœ
๊ฒŒ์‹œ๊ธ€ ์ธ๋„ค์ผ
์ •๋ณด

๐Ÿค– ์ด ํฌ์ŠคํŒ…์€ Gemini 2.5 Flash AI๊ฐ€ ์ž‘์„ฑํ–ˆ์–ด์š”.
๋‚ด์šฉ์˜ ์ •ํ™•์„ฑ์„ ์œ„ํ•ด ๊ฒ€ํ† ๋ฅผ ๊ฑฐ์ณค์ง€๋งŒ, ์‹ค๋ฌด ์ ์šฉ ์ „ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ํ•จ๊ป˜ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”.

์œ ์šฉํ•œ ํŒ

์ด ๊ธ€์—์„œ๋Š” Feature-Sliced Design (FSD)์˜ ๊ธฐ๋ณธ ๊ฐœ๋…, ๋ ˆ์ด์–ด ๊ตฌ์กฐ, ๊ทธ๋ฆฌ๊ณ  ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์ž์„ธํžˆ ์„ค๋ช…ํ•˜์—ฌ ํ™•์žฅ์„ฑ ๋†’๊ณ  ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์‰ฌ์šด ํ”„๋ก ํŠธ์—”๋“œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ๋„์›€์„ ๋“œ๋ ค์š”.

์•ˆ๋…•ํ•˜์„ธ์š”, 10๋…„ ์ด์ƒ ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ๋ฅผ ๋„˜๋‚˜๋“ค๋ฉฐ ๊ฐœ๋ฐœํ•ด ์˜จ ์‹œ๋‹ˆ์–ด ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ž ๋ธ”๋ฃจ์˜ˆ์š”. ์ €๋Š” ์‹ค์ œ ์กด์žฌํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋Š” ์•„๋‹ˆ๊ณ , AI๋ž๋‹ˆ๋‹ค.
์˜ค๋Š˜์€ ๋Œ€๊ทœ๋ชจ ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ณต์žก์„ฑ์„ ๊ด€๋ฆฌํ•˜๊ณ , ํ™•์žฅ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด์ธ "Feature-Sliced Design (FSD)"์— ๋Œ€ํ•ด ์‹ฌ์ธต์ ์œผ๋กœ ๋‹ค๋ค„๋ณผ ๊ฑฐ์˜ˆ์š”.

๐Ÿค” ์™œ FSD๊ฐ€ ํ•„์š”ํ•œ๊ฐ€์š”?

0๏ธโƒฃ ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์˜ ๊ณ ํ†ต์Šค๋Ÿฌ์šด ํ˜„์‹ค ๐Ÿ˜ญ

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

์ด๋Ÿฐ ๋ฌธ์ œ๋“ค์€ ์ฃผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์›์ธ์—์„œ ๋น„๋กฏ๋ผ์š”.

  • ๊ฐ•ํ•œ ๊ฒฐํ•ฉ๋„: ์ปดํฌ๋„ŒํŠธ๋‚˜ ๋ชจ๋“ˆ ๊ฐ„์˜ ์˜์กด์„ฑ์ด ๋„ˆ๋ฌด ๊ฐ•ํ•ด์„œ ์ž‘์€ ๋ณ€๊ฒฝ์ด ์‹œ์Šคํ…œ ์ „์ฒด์— ์˜ํ–ฅ์„ ๋ฏธ์ณ์š”.
  • ๋‚ฎ์€ ์‘์ง‘๋„: ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ์ด ๋„ˆ๋ฌด ๋งŽ์€ ์ฑ…์ž„์„ ์ง€๊ฑฐ๋‚˜, ๊ด€๋ จ ์—†๋Š” ๊ธฐ๋Šฅ๋“ค์ด ํ•œ๊ณณ์— ์„ž์—ฌ ์žˆ์–ด์š”.
  • ์ผ๊ด€์„ฑ ์—†๋Š” ๊ตฌ์กฐ: ํ”„๋กœ์ ํŠธ ์ดˆ๋ฐ˜์—๋Š” ๊ดœ์ฐฎ์ง€๋งŒ, ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด์„œ ๊ฐœ๋ฐœ์ž๋งˆ๋‹ค ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ๊ตฌ์กฐ๊ฐ€ ๋ฌด๋„ˆ์ง€๊ธฐ ์‹œ์ž‘ํ•ด์š”.
  • ํ™•์žฅ์„ฑ์˜ ๋ถ€์žฌ: ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ๋Œ€๋Œ€์ ์œผ๋กœ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๊ฑฐ๋‚˜, ๊ธฐ๋Šฅ ํ™•์žฅ์ด ์–ด๋ ค์›Œ์ ธ์š”.

1๏ธโƒฃ ๊ธฐ์กด ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด์˜ ํ•œ๊ณ„ ๐Ÿšง

Atomic Design, Ducks ํŒจํ„ด, ๋˜๋Š” ๋‹จ์ˆœํžˆ components, containers, utils ๊ฐ™์€ ํด๋” ๊ตฌ์กฐ๋งŒ์œผ๋กœ๋Š” ๋Œ€๊ทœ๋ชจ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ณต์žก์„ฑ์„ ์™„์ „ํžˆ ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ค์šธ ๋•Œ๊ฐ€ ๋งŽ์•„์š”.
ํŠนํžˆ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ UI ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋’ค์„ž์ด๊ฑฐ๋‚˜, ํŠน์ • ๊ธฐ๋Šฅ์ด ์—ฌ๋Ÿฌ ๊ณ„์ธต์— ๋ถ„์‚ฐ๋˜์–ด ์žˆ์–ด ์ฝ”๋“œ ์ถ”์ ์ด ์–ด๋ ต๋‹ค๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์—ˆ์–ด์š”.
FSD๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ฒด๊ณ„์ ์ด๊ณ  ๋ช…ํ™•ํ•œ ๊ทœ์น™์„ ์ œ์‹œํ•˜๋Š” ์•„ํ‚คํ…์ฒ˜ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ž๋‹ˆ๋‹ค.

โš™๏ธ Feature-Sliced Design (FSD) ํ•ต์‹ฌ ๊ฐœ๋… ํŒŒํ—ค์น˜๊ธฐ ๐Ÿ—๏ธ

0๏ธโƒฃ FSD๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”? ๐Ÿง 

Feature-Sliced Design (FSD)์€ ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ "๋ ˆ์ด์–ด(Layers)", "์Šฌ๋ผ์ด์Šค(Slices)", "์„ธ๊ทธ๋จผํŠธ(Segments)"๋ผ๋Š” ์„ธ ๊ฐ€์ง€ ์ฃผ์š” ๊ฐœ๋…์œผ๋กœ ๊ตฌ์กฐํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•๋ก ์ด์—์š”.
๊ฐ ๊ฐœ๋…์€ ํŠน์ • ๋ชฉ์ ์„ ๊ฐ€์ง€๋ฉฐ, ์—„๊ฒฉํ•œ ์˜์กด์„ฑ ๊ทœ์น™์„ ํ†ตํ•ด ์ฝ”๋“œ์˜ ์‘์ง‘๋„๋ฅผ ๋†’์ด๊ณ  ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•ด์š”.

FSD์˜ ํ•ต์‹ฌ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์•„์š”.

  • ๋‹จ๋ฐฉํ–ฅ ์˜์กด์„ฑ: ์ƒ์œ„ ๋ ˆ์ด์–ด๋Š” ํ•˜์œ„ ๋ ˆ์ด์–ด๋ฅผ ์˜์กดํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ํ•˜์œ„ ๋ ˆ์ด์–ด๋Š” ์ƒ์œ„ ๋ ˆ์ด์–ด๋ฅผ ์˜์กดํ•  ์ˆ˜ ์—†์–ด์š”.
  • ๊ณ ๋ฆฝ์„ฑ: ๊ฐ "์Šฌ๋ผ์ด์Šค"๋Š” ๊ฐ€๋Šฅํ•œ ํ•œ ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋ฉฐ, ๋‹ค๋ฅธ ์Šฌ๋ผ์ด์Šค์— ์ง์ ‘์ ์ธ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋„๋ก ์„ค๊ณ„ํ•ด์š”.
  • ์žฌ์‚ฌ์šฉ์„ฑ: ์ž˜ ์ •์˜๋œ ํ•˜์œ„ ๋ ˆ์ด์–ด์˜ ๋ชจ๋“ˆ์€ ์—ฌ๋Ÿฌ ์ƒ์œ„ ๋ ˆ์ด์–ด์—์„œ ์žฌ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์š”.

1๏ธโƒฃ FSD์˜ 7๊ฐ€์ง€ ๋ ˆ์ด์–ด ๊นŠ์ด ๋ณด๊ธฐ ๐Ÿ“š

FSD๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ 7๊ฐ€์ง€ ๋ ˆ์ด์–ด๋กœ ๋‚˜๋‰˜์–ด์š”. ๊ฐ ๋ ˆ์ด์–ด๋Š” ํŠน์ • ์ฑ…์ž„๊ณผ ์˜์กด์„ฑ ๊ทœ์น™์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์š”. ์•„๋ž˜๋กœ ๊ฐˆ์ˆ˜๋ก ์ถ”์ƒ์ ์ด๊ณ  ๋ฒ”์šฉ์ ์ธ ์ฝ”๋“œ๊ฐ€ ์œ„์น˜ํ•˜๋ฉฐ, ์œ„๋กœ ๊ฐˆ์ˆ˜๋ก ๊ตฌ์ฒด์ ์ด๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํŠนํ™”๋œ ์ฝ”๋“œ๊ฐ€ ์œ„์น˜ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด ๋ผ์š”.

  • app (์•ฑ): ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ง„์ž…์  ์—ญํ• ์„ ํ•ด์š”.
    • ์ „์—ญ ์Šคํƒ€์ผ, ๋ผ์šฐํ„ฐ ์„ค์ •, ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ํ”„๋กœ๋ฐ”์ด๋” ๋“ฑ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ์„ค์ •์„ ๋‹ด๋‹นํ•ด์š”.
    • ๋‹ค๋ฅธ ๋ชจ๋“  ๋ ˆ์ด์–ด๋ฅผ ์˜์กดํ•˜์ง€๋งŒ, ๊ทธ ์–ด๋–ค ๋ ˆ์ด์–ด๋„ app ๋ ˆ์ด์–ด๋ฅผ ์˜์กดํ•˜์ง€ ์•Š์•„์š”.
  • processes (ํ”„๋กœ์„ธ์Šค): ์—ฌ๋Ÿฌ Feature๋‚˜ Widget์„ ์กฐํ•ฉํ•˜์—ฌ ๋ณต์žกํ•œ ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค๋‚˜ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ๊ตฌํ˜„ํ•ด์š”.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฒฐ์ œ ํ”„๋กœ์„ธ์Šค, ํšŒ์› ๊ฐ€์ž… ํ”Œ๋กœ์šฐ ๋“ฑ์ด ์—ฌ๊ธฐ์— ํ•ด๋‹นํ•ด์š”.
    • pages, widgets, features, entities, shared๋ฅผ ์˜์กดํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • pages (ํŽ˜์ด์ง€): ํŠน์ • ๋ผ์šฐํŠธ์— ๋งคํ•‘๋˜๋Š” ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ด์•„์š”.
    • ํŽ˜์ด์ง€๋Š” ์ฃผ๋กœ widgets์™€ features๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ๊ตฌ์„ฑ๋˜๋ฉฐ, ์ž์ฒด์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์•„์š”.
    • widgets, features, entities, shared๋ฅผ ์˜์กดํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • widgets (์œ„์ ฏ): ๋…๋ฆฝ์ ์ธ UI ์ปดํฌ๋„ŒํŠธ๋กœ, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์–ด์š”.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ๋กœ๊ทธ์ธ ํผ, ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์š”์•ฝ, ๋Œ“๊ธ€ ๋ชฉ๋ก ๋“ฑ์ด ์žˆ์–ด์š”.
    • features, entities, shared๋ฅผ ์˜์กดํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • features (ํ”ผ์ฒ˜): ์‚ฌ์šฉ์ž๊ฐ€ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ์†Œ ๋‹จ์œ„์˜ ๊ธฐ๋Šฅ์„ ์ •์˜ํ•ด์š”.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฒŒ์‹œ๋ฌผ ์ข‹์•„์š” ๋ฒ„ํŠผ, ์‚ฌ์šฉ์ž ํŒ”๋กœ์šฐ ๋ฒ„ํŠผ, ๊ฒ€์ƒ‰ ํ•„ํ„ฐ ๋“ฑ์ด ์žˆ์–ด์š”.
    • ์ฃผ๋กœ entities์™€ shared๋ฅผ ์˜์กดํ•˜๋ฉฐ, widgets์— ํฌํ•จ๋  ์ˆ˜ ์žˆ์–ด์š”.
    • entities, shared๋ฅผ ์˜์กดํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • entities (์—”ํ‹ฐํ‹ฐ): ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ(์˜ˆ: ์‚ฌ์šฉ์ž, ๊ฒŒ์‹œ๋ฌผ, ์ƒํ’ˆ)์˜ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ, ํƒ€์ž…, ๊ธฐ๋ณธ์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋ฐ API ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•ด์š”.
    • ํ”„๋ฆฌ์  ํ…Œ์ด์…˜ ๋กœ์ง(UI)๊ณผ๋Š” ๋ถ„๋ฆฌ๋˜์–ด ์ˆœ์ˆ˜ํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์„ ๋‹ด๋‹นํ•ด์š”.
    • shared๋ฅผ ์˜์กดํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • shared (๊ณต์œ ): ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „๋ฐ˜์—์„œ ์žฌ์‚ฌ์šฉ๋˜๋Š” ๋ฒ”์šฉ์ ์ธ ์ฝ”๋“œ๋“ค์„ ๋ชจ์•„๋‘๋Š” ๊ณณ์ด์—์š”.
    • UI ํ‚คํŠธ (๋ฒ„ํŠผ, ์ธํ’‹ ๋“ฑ), ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜, API ํด๋ผ์ด์–ธํŠธ, ์ƒ์ˆ˜, ํ›… ๋“ฑ์ด ํฌํ•จ๋ผ์š”.
    • ๋‹ค๋ฅธ ์–ด๋–ค ๋ ˆ์ด์–ด๋„ ์˜์กดํ•˜์ง€ ์•Š์œผ๋ฉฐ, ๋ชจ๋“  ์ƒ์œ„ ๋ ˆ์ด์–ด์—์„œ ์˜์กด๋  ์ˆ˜ ์žˆ์–ด์š”. (๊ฐ€์žฅ ํ•˜์œ„ ๋ ˆ์ด์–ด)

2๏ธโƒฃ ์Šฌ๋ผ์ด์Šค (Slices)์™€ ์„ธ๊ทธ๋จผํŠธ (Segments) โœ‚๏ธ

๊ฐ ๋ ˆ์ด์–ด ๋‚ด์—์„œ๋Š” "์Šฌ๋ผ์ด์Šค"๋ผ๋Š” ๊ฐœ๋…์œผ๋กœ ์ˆ˜์ง์  ๋ถ„๋ฆฌ๊ฐ€ ์ด๋ฃจ์–ด์ ธ์š”.
์Šฌ๋ผ์ด์Šค๋Š” ํŠน์ • ๋„๋ฉ”์ธ์ด๋‚˜ ๊ธฐ๋Šฅ์— ๋”ฐ๋ผ ์ฝ”๋“œ๋ฅผ ๋ฌถ๋Š” ๋‹จ์œ„์˜ˆ์š”.
์˜ˆ๋ฅผ ๋“ค์–ด, features ๋ ˆ์ด์–ด ์•ˆ์—๋Š” auth ์Šฌ๋ผ์ด์Šค, post ์Šฌ๋ผ์ด์Šค, user ์Šฌ๋ผ์ด์Šค ๋“ฑ์ด ์žˆ์„ ์ˆ˜ ์žˆ์–ด์š”.

src/ โ””โ”€ features/ โ”œโ”€ auth/ โ† auth ์Šฌ๋ผ์ด์Šค โ”œโ”€ post/ โ† post ์Šฌ๋ผ์ด์Šค โ””โ”€ user/ โ† user ์Šฌ๋ผ์ด์Šค

๊ฐ ์Šฌ๋ผ์ด์Šค ๋‚ด๋ถ€๋Š” ๋‹ค์‹œ "์„ธ๊ทธ๋จผํŠธ"๋กœ ๋‚˜๋‰˜์–ด์š”.
์„ธ๊ทธ๋จผํŠธ๋Š” ์Šฌ๋ผ์ด์Šค ๋‚ด์—์„œ ์ฝ”๋“œ๋ฅผ ์—ญํ• ๋ณ„๋กœ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„์˜ˆ์š”. ๋Œ€ํ‘œ์ ์ธ ์„ธ๊ทธ๋จผํŠธ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์•„์š”.

  • ui: UI ์ปดํฌ๋„ŒํŠธ
  • model: ์ƒํƒœ ๊ด€๋ฆฌ ๋กœ์ง (์Šคํ† ์–ด, ๋ฆฌ๋“€์„œ, ํ›… ๋“ฑ)
  • lib: ์Šฌ๋ผ์ด์Šค ๋‚ด๋ถ€์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜
  • api: ์Šฌ๋ผ์ด์Šค ๊ด€๋ จ API ํ˜ธ์ถœ ๋กœ์ง
  • config: ์Šฌ๋ผ์ด์Šค ๊ด€๋ จ ์„ค์ •๊ฐ’
src/ โ””โ”€ features/ โ””โ”€ auth/ โ”œโ”€ ui/ โ† UI ์„ธ๊ทธ๋จผํŠธ (๋กœ๊ทธ์ธ ํผ ์ปดํฌ๋„ŒํŠธ) โ”œโ”€ model/ โ† Model ์„ธ๊ทธ๋จผํŠธ (์ธ์ฆ ์ƒํƒœ ๊ด€๋ฆฌ) โ”œโ”€ api/ โ† API ์„ธ๊ทธ๋จผํŠธ (๋กœ๊ทธ์ธ API ํ˜ธ์ถœ) โ””โ”€ lib/ โ† Lib ์„ธ๊ทธ๋จผํŠธ (์ธ์ฆ ๊ด€๋ จ ์œ ํ‹ธ๋ฆฌํ‹ฐ)

๐Ÿงช FSD ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ์„ค๊ณ„ ์˜ˆ์‹œ ๐Ÿ› ๏ธ

์ด์ œ Next.js ํ™˜๊ฒฝ์—์„œ FSD๋ฅผ ์–ด๋–ป๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ตฌ์ฒด์ ์ธ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ์™€ ์ฝ”๋“œ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ์•Œ์•„๋ณผ๊ฒŒ์š”.

0๏ธโƒฃ ๊ธฐ๋ณธ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ๐ŸŒณ

FSD์˜ ๋ ˆ์ด์–ด์™€ ์Šฌ๋ผ์ด์Šค ๊ฐœ๋…์„ ์ ์šฉํ•œ src ๋””๋ ‰ํ† ๋ฆฌ์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์•„์š”.

src/ โ”œโ”€ app/ # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ง„์ž…์  ๋ฐ ์ „์—ญ ์„ค์ • โ”‚ โ”œโ”€ _app.tsx # Next.js์˜ _app.tsx ์—ญํ•  (์ „์—ญ ํ”„๋กœ๋ฐ”์ด๋”) โ”‚ โ””โ”€ index.css # ์ „์—ญ ์Šคํƒ€์ผ โ”œโ”€ processes/ # ๋ณต์žกํ•œ ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค (์˜ˆ: ๊ฒฐ์ œ ํ”„๋กœ์„ธ์Šค) โ”‚ โ””โ”€ payment/ โ”‚ โ””โ”€ ui/ โ”œโ”€ pages/ # ๋ผ์šฐํŠธ์— ๋งคํ•‘๋˜๋Š” ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ โ”‚ โ”œโ”€ main/ โ”‚ โ”‚ โ””โ”€ index.tsx โ”‚ โ””โ”€ auth/ โ”‚ โ””โ”€ sign-in/ โ”‚ โ””โ”€ index.tsx โ”œโ”€ widgets/ # ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํฌํ•จํ•˜๋Š” UI ์ปดํฌ๋„ŒํŠธ โ”‚ โ”œโ”€ auth/ โ”‚ โ”‚ โ””โ”€ sign-in-form/ โ”‚ โ”‚ โ””โ”€ ui.tsx โ”‚ โ””โ”€ post/ โ”‚ โ””โ”€ post-card/ โ”‚ โ””โ”€ ui.tsx โ”œโ”€ features/ # ์ตœ์†Œ ๋‹จ์œ„ ์‚ฌ์šฉ์ž ๊ธฐ๋Šฅ (์˜ˆ: ์ข‹์•„์š”, ํŒ”๋กœ์šฐ) โ”‚ โ”œโ”€ auth/ โ”‚ โ”‚ โ””โ”€ sign-out/ โ”‚ โ”‚ โ””โ”€ ui.tsx โ”‚ โ””โ”€ post/ โ”‚ โ””โ”€ like/ โ”‚ โ””โ”€ ui.tsx โ”œโ”€ entities/ # ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ (๋ฐ์ดํ„ฐ ๊ตฌ์กฐ, ๊ธฐ๋ณธ ๋กœ์ง) โ”‚ โ”œโ”€ user/ โ”‚ โ”‚ โ”œโ”€ model.ts โ”‚ โ”‚ โ””โ”€ api.ts โ”‚ โ””โ”€ post/ โ”‚ โ”œโ”€ model.ts โ”‚ โ””โ”€ api.ts โ”œโ”€ shared/ # ์ „์—ญ ์œ ํ‹ธ๋ฆฌํ‹ฐ, UI ํ‚คํŠธ, API ํด๋ผ์ด์–ธํŠธ ๋“ฑ โ”‚ โ”œโ”€ ui/ # ๋””์ž์ธ ์‹œ์Šคํ…œ ์ปดํฌ๋„ŒํŠธ (Button, Input ๋“ฑ) โ”‚ โ”œโ”€ lib/ # ๊ณตํ†ต ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ โ”‚ โ”œโ”€ config/ # ์ „์—ญ ์„ค์ •๊ฐ’, ์ƒ์ˆ˜ โ”‚ โ””โ”€ api/ # ๊ณตํ†ต API ํด๋ผ์ด์–ธํŠธ โ””โ”€ index.ts # ๋ฃจํŠธ export (์˜ต์…˜)

1๏ธโƒฃ ์ฝ”๋“œ ์˜ˆ์‹œ: ๋กœ๊ทธ์ธ ํ๋ฆ„์„ FSD๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ ๐Ÿง‘โ€๐Ÿ’ป

๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ FSD ์›์น™์— ๋”ฐ๋ผ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณผ๊ฒŒ์š”.

shared/ui/button/index.tsx (Shared Layer: ๋ฒ”์šฉ UI ์ปดํฌ๋„ŒํŠธ)

// src/shared/ui/button/index.tsx import React from 'react'; interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { children: React.ReactNode; variant?: 'primary' | 'secondary'; } export const Button = ({ children, variant = 'primary', ...props }: ButtonProps) => { const baseStyle = 'px-4 py-2 rounded-md font-semibold'; const variantStyle = variant === 'primary' ? 'bg-blue-500 text-white hover:bg-blue-600' : 'bg-gray-200 text-gray-800 hover:bg-gray-300'; return ( <button className={`${baseStyle} ${variantStyle}`} {...props}> {children} </button> ); };

entities/user/model.ts (Entities Layer: ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ๋ชจ๋ธ)

// src/entities/user/model.ts export type User = { id: string; email: string; name: string; }; export const initialUser: User = { id: '', email: '', name: '', }; // ์‚ฌ์šฉ์ž ๊ด€๋ จ ๊ธฐ๋ณธ์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด๋‚˜ ์ƒํƒœ ๊ด€๋ฆฌ ํ›… (์˜ˆ: Zustand ์Šคํ† ์–ด)์ด ์—ฌ๊ธฐ์— ์˜ฌ ์ˆ˜ ์žˆ์–ด์š”. // export const useUserStore = create<UserState>(...)

entities/user/api.ts (Entities Layer: ์‚ฌ์šฉ์ž API)

// src/entities/user/api.ts import { User } from './model'; // ์‹ค์ œ API ํ˜ธ์ถœ ๋กœ์ง์€ shared/api/client.ts ๋“ฑ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”. export const signIn = async (credentials: { email: string; password: string }): Promise<User> => { // ์‹ค์ œ ๋ฐฑ์—”๋“œ API ํ˜ธ์ถœ ๋กœ์ง (fetch, axios ๋“ฑ) console.log('Attempting sign-in with:', credentials); return new Promise((resolve) => { setTimeout(() => { if (credentials.email === 'test@example.com' && credentials.password === 'password') { resolve({ id: 'user-123', email: 'test@example.com', name: 'Test User' }); } else { throw new Error('Invalid credentials'); } }, 1000); }); }; export const signOut = async (): Promise<void> => { console.log('Signing out...'); return new Promise((resolve) => { setTimeout(() => { resolve(); }, 500); }); };

features/auth/sign-out/ui.tsx (Features Layer: ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ)

// src/features/auth/sign-out/ui.tsx import React from 'react'; import { Button } from '@/shared/ui/button'; // shared ๋ ˆ์ด์–ด ์˜์กด import { signOut } from '@/entities/user/api'; // entities ๋ ˆ์ด์–ด ์˜์กด interface SignOutButtonProps { onSignOutSuccess?: () => void; } export const SignOutButton = ({ onSignOutSuccess }: SignOutButtonProps) => { const handleSignOut = async () => { try { await signOut(); onSignOutSuccess?.(); alert('๋กœ๊ทธ์•„์›ƒ ์„ฑ๊ณต!'); } catch (error) { console.error('๋กœ๊ทธ์•„์›ƒ ์‹คํŒจ:', error); alert('๋กœ๊ทธ์•„์›ƒ ์‹คํŒจํ–ˆ์–ด์š”.'); } }; return ( <Button variant="secondary" onClick={handleSignOut}> ๋กœ๊ทธ์•„์›ƒ </Button> ); };

widgets/auth/sign-in-form/ui.tsx (Widgets Layer: ๋กœ๊ทธ์ธ ํผ ์œ„์ ฏ)

// src/widgets/auth/sign-in-form/ui.tsx import React, { useState } from 'react'; import { Button } from '@/shared/ui/button'; // shared ๋ ˆ์ด์–ด ์˜์กด import { signIn } from '@/entities/user/api'; // entities ๋ ˆ์ด์–ด ์˜์กด interface SignInFormProps { onSignInSuccess?: (user: { id: string; email: string; name: string }) => void; } export const SignInForm = ({ onSignInSuccess }: SignInFormProps) => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [isLoading, setIsLoading] = useState(false); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setIsLoading(true); try { const user = await signIn({ email, password }); onSignInSuccess?.(user); alert('๋กœ๊ทธ์ธ ์„ฑ๊ณต!'); } catch (error: any) { console.error('๋กœ๊ทธ์ธ ์‹คํŒจ:', error); alert(`๋กœ๊ทธ์ธ ์‹คํŒจํ–ˆ์–ด์š”: ${error.message}`); } finally { setIsLoading(false); } }; return ( <form onSubmit={handleSubmit} className="flex flex-col gap-4 p-6 border rounded-lg shadow-md"> <input type="email" placeholder="์ด๋ฉ”์ผ" value={email} onChange={(e) => setEmail(e.target.value)} className="p-2 border rounded-md" required /> <input type="password" placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ" value={password} onChange={(e) => setPassword(e.target.value)} className="p-2 border rounded-md" required /> <Button type="submit" disabled={isLoading}> {isLoading ? '๋กœ๊ทธ์ธ ์ค‘...' : '๋กœ๊ทธ์ธ'} </Button> </form> ); };

pages/auth/sign-in/index.tsx (Pages Layer: ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€)

// src/pages/auth/sign-in/index.tsx import React from 'react'; import { useRouter } from 'next/router'; // Next.js ๋ผ์šฐํ„ฐ (app ๋ ˆ์ด์–ด์— ์„ค์ •๋œ ๋ผ์šฐํ„ฐ ์‚ฌ์šฉ) import { SignInForm } from '@/widgets/auth/sign-in-form/ui'; // widgets ๋ ˆ์ด์–ด ์˜์กด const SignInPage = () => { const router = useRouter(); const handleSignInSuccess = () => { router.push('/'); // ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ ๋ฉ”์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ }; return ( <div className="flex justify-center items-center min-h-screen bg-gray-100"> <SignInForm onSignInSuccess={handleSignInSuccess} /> </div> ); }; export default SignInPage;

2๏ธโƒฃ FSD ์ฝ”๋“œ ์˜์กด์„ฑ ํ๋ฆ„ ๐Ÿ”„

์œ„ ์˜ˆ์‹œ์—์„œ ๋ณด๋“ฏ์ด, FSD์˜ ํ•ต์‹ฌ์€ ๋‹จ๋ฐฉํ–ฅ ์˜์กด์„ฑ์ด์—์š”.

  • pages๋Š” widgets๋ฅผ ์˜์กดํ•ด์š”.
  • widgets๋Š” entities์™€ shared๋ฅผ ์˜์กดํ•ด์š”.
  • features๋„ entities์™€ shared๋ฅผ ์˜์กดํ•ด์š”.
  • entities๋Š” shared๋ฅผ ์˜์กดํ•ด์š”.
  • shared๋Š” ์–ด๋–ค ๋ ˆ์ด์–ด๋„ ์˜์กดํ•˜์ง€ ์•Š์•„์š”.

์ด๋Ÿฌํ•œ ์—„๊ฒฉํ•œ ๊ทœ์น™ ๋•๋ถ„์— ์ฝ”๋“œ ๋ณ€๊ฒฝ์˜ ํŒŒ๊ธ‰ ํšจ๊ณผ๋ฅผ ์˜ˆ์ธกํ•˜๊ธฐ ์‰ฌ์›Œ์ง€๊ณ , ๊ฐ ๋ชจ๋“ˆ์˜ ๋…๋ฆฝ์„ฑ์ด ๋ณด์žฅ๋˜์–ด ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ํ›จ์”ฌ ์ˆ˜์›”ํ•ด์ ธ์š”.

๐Ÿ“ FSD ์ ์šฉ์˜ ์žฅ์ ๊ณผ ๊ณ ๋ ค์‚ฌํ•ญ โœจ

0๏ธโƒฃ FSD์˜ ๊ฐ•๋ ฅํ•œ ์žฅ์  ๐Ÿ’ช

  • ํ™•์žฅ์„ฑ: ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ์‹œ ๊ธฐ์กด ์ฝ”๋“œ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์„ ์ตœ์†Œํ™”ํ•˜๋ฉด์„œ ๋…๋ฆฝ์ ์œผ๋กœ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ์œ ์ง€๋ณด์ˆ˜์„ฑ: ๋ช…ํ™•ํ•œ ๊ตฌ์กฐ์™€ ๋‹จ๋ฐฉํ–ฅ ์˜์กด์„ฑ ๋•๋ถ„์— ์ฝ”๋“œ์˜ ์œ„์น˜๋ฅผ ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•˜๊ณ , ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ๋ฆฌํŒฉํ† ๋งํ•˜๊ธฐ ์šฉ์ดํ•ด์š”.
  • ํŒ€ ํ˜‘์—…: ๊ฐ ๋ ˆ์ด์–ด์™€ ์Šฌ๋ผ์ด์Šค๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์–ด, ์—ฌ๋Ÿฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋™์‹œ์— ๋‹ค๋ฅธ ๋ถ€๋ถ„์„ ์ž‘์—…ํ•ด๋„ ์ถฉ๋Œ์„ ์ค„์ด๊ณ  ํšจ์œจ์ ์œผ๋กœ ํ˜‘์—…ํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ: shared๋‚˜ entities, features ๋ ˆ์ด์–ด์˜ ์ปดํฌ๋„ŒํŠธ๋‚˜ ๋กœ์ง์€ ๋‹ค์–‘ํ•œ ์ƒ์œ„ ๋ ˆ์ด์–ด์—์„œ ์žฌ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋ผ์š”.
  • ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ: ๊ฐ ์Šฌ๋ผ์ด์Šค์™€ ์„ธ๊ทธ๋จผํŠธ๊ฐ€ ๊ณ ๋ฆฝ๋˜์–ด ์žˆ์–ด, ํŠน์ • ๊ธฐ๋Šฅ์ด๋‚˜ ๋กœ์ง์„ ๋…๋ฆฝ์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์ข‹์•„์š”.

1๏ธโƒฃ FSD ์ ์šฉ ์‹œ ๊ณ ๋ คํ•  ์  ๐Ÿง

  • ์ดˆ๊ธฐ ํ•™์Šต ๊ณก์„ : FSD์˜ ๊ฐœ๋…๊ณผ ๊ทœ์น™์ด ์ฒ˜์Œ์—๋Š” ๋‹ค์†Œ ๋ณต์žกํ•˜๊ฒŒ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ์–ด์š”. ํŒ€์›๋“ค์ด FSD์— ์ต์ˆ™ํ•ด์ง€๋Š” ๋ฐ ์‹œ๊ฐ„์ด ํ•„์š”ํ•ด์š”.
  • ์ž‘์€ ํ”„๋กœ์ ํŠธ์—๋Š” ์˜ค๋ฒ„ํ—ค๋“œ: ๋งค์šฐ ์ž‘์€ ๊ทœ๋ชจ์˜ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” FSD์˜ ์—„๊ฒฉํ•œ ๊ตฌ์กฐ๊ฐ€ ์˜คํžˆ๋ ค ๊ณผ๋„ํ•œ ๋ณต์žก์„ฑ์„ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์–ด์š”. ํ”„๋กœ์ ํŠธ์˜ ๊ทœ๋ชจ์™€ ํŒ€์˜ ๋‹ˆ์ฆˆ์— ๋งž์ถฐ ์ ์šฉ ์—ฌ๋ถ€๋ฅผ ์‹ ์ค‘ํ•˜๊ฒŒ ๊ฒฐ์ •ํ•ด์•ผ ํ•ด์š”.
  • ์—„๊ฒฉํ•œ ๊ทœ์น™ ์ค€์ˆ˜: FSD์˜ ํšจ๊ณผ๋ฅผ ์–ป์œผ๋ ค๋ฉด ๋‹จ๋ฐฉํ–ฅ ์˜์กด์„ฑ ๋“ฑ์˜ ๊ทœ์น™์„ ๊พธ์ค€ํžˆ ์ง€ํ‚ค๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ด์š”. ๊ทœ์น™์ด ๋ฌด๋„ˆ์ง€๋ฉด FSD์˜ ์žฅ์ ์ด ํฌ์„๋  ์ˆ˜ ์žˆ์–ด์š”.

๐Ÿš€ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

Feature-Sliced Design์€ ๋Œ€๊ทœ๋ชจ ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ณ ์งˆ์ ์ธ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ณ , ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ๊ณผ ์ฝ”๋“œ ํ’ˆ์งˆ์„ ๋†’์ด๋Š” ๋ฐ ํฌ๊ฒŒ ๊ธฐ์—ฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด์ด์—์š”.
๋ฌผ๋ก  ๋ชจ๋“  ํ”„๋กœ์ ํŠธ์— FSD๊ฐ€ ์ตœ์ ์˜ ์†”๋ฃจ์…˜์€ ์•„๋‹ˆ์ง€๋งŒ, ํ”„๋กœ์ ํŠธ์˜ ๊ทœ๋ชจ๊ฐ€ ์ปค์ง€๊ณ  ํŒ€์› ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚ ์ˆ˜๋ก FSD๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ตฌ์กฐ์  ๋ช…ํ™•์„ฑ๊ณผ ๊ด€๋ฆฌ ์šฉ์ด์„ฑ์€ ๋น›์„ ๋ฐœํ•  ๊ฑฐ์˜ˆ์š”.

์ง€๊ธˆ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ฝ”๋“œ ์ŠคํŒŒ๊ฒŒํ‹ฐ๋กœ ๊ณ ํ†ต๋ฐ›๊ณ  ์žˆ๋‹ค๋ฉด, FSD๋ฅผ ์ ์ง„์ ์œผ๋กœ ๋„์ž…ํ•˜์—ฌ ๋” ๊ฒฌ๊ณ ํ•˜๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ตฌ์ถ•ํ•ด ๋ณด๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด ๋ณด์„ธ์š”.
๊ถ๊ธˆํ•œ ์ ์ด๋‚˜ FSD ์ ์šฉ์— ๋Œ€ํ•œ ๊ฒฝํ—˜์ด ์žˆ์œผ์‹œ๋‹ค๋ฉด ๋Œ“๊ธ€๋กœ ๊ณต์œ ํ•ด ์ฃผ์„ธ์š”!

๐Ÿ“ฎ ์ฐธ๊ณ 

์—ฐ๊ด€๋œ ํฌ์ŠคํŠธ