๐Ÿš€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐํ™” ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค ๐Ÿ’ป

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐํ™” ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค ๐Ÿ’ป

 

 

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

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐํ™”๋Š” ๋งˆ์น˜ ๋ ˆ๊ณ  ๋ธ”๋ก ์Œ“๊ธฐ์™€ ๋น„์Šทํ•ด์š”. ๊ธฐ์ดˆ๋ฅผ ํƒ„ํƒ„ํžˆ ๋‹ค์ง€๊ณ , ๊ทธ ์œ„์— ์ฐจ๊ณก์ฐจ๊ณก ๋ธ”๋ก์„ ์Œ“์•„ ์˜ฌ๋ฆฌ๋“ฏ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฑฐ์ฃ . ์ž, ๊ทธ๋Ÿผ ์šฐ๋ฆฌ ํ•จ๊ป˜ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ์„ธ๊ณ„๋กœ ๋น ์ ธ๋ณผ๊นŒ์š”? ๐ŸŠโ€โ™‚๏ธ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐํ™” ๊ฐœ์š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐํ™” ๊ฐœ์š” ํ”„๋กœ์ ํŠธ ์„ค์ • ํด๋” ๊ตฌ์กฐ ์ฝ”๋“œ ๊ตฌ์„ฑ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค ์ ์šฉ

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

์ž, ์ด์ œ ๊ฐ ์š”์†Œ๋“ค์„ ํ•˜๋‚˜์”ฉ ์ž์„ธํžˆ ์‚ดํŽด๋ณผ๊นŒ์š”? ์ค€๋น„๋˜์…จ๋‚˜์š”? ๊ทธ๋Ÿผ ๊ณ ๊ณ ์”ฝ~! ๐Ÿš—๐Ÿ’จ

1. ํ”„๋กœ์ ํŠธ ์„ค์ •: ๊ธฐ์ดˆ๋ฅผ ํƒ„ํƒ„ํžˆ! ๐Ÿ—๏ธ

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

1.1 tsconfig.json: ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ์‹ฌ์žฅ ๐Ÿ’–

tsconfig.json ํŒŒ์ผ์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์ ํŠธ์˜ ์‹ฌ์žฅ๊ณผ๋„ ๊ฐ™์•„์š”. ์ด ํŒŒ์ผ์—์„œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์˜ต์…˜์„ ์„ค์ •ํ•˜๊ณ , ํ”„๋กœ์ ํŠธ์˜ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์ฃ .

๐Ÿšจ ์ฃผ์˜! tsconfig.json ํŒŒ์ผ์€ ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ์— ์œ„์น˜ํ•ด์•ผ ํ•ด์š”.

์ž, ๊ทธ๋Ÿผ tsconfig.json ํŒŒ์ผ์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ํ•œ๋ฒˆ ๋ณผ๊นŒ์š”?

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "**/*.spec.ts"]
}

์šฐ์™€~ ๋ญ”๊ฐ€ ๋ณต์žกํ•ด ๋ณด์ด์ฃ ? ํ•˜์ง€๋งŒ ๊ฑฑ์ • ๋งˆ์„ธ์š”. ํ•˜๋‚˜์”ฉ ๋œฏ์–ด๋ณผ๊ฒŒ์š”! ๐Ÿ˜‰

  • compilerOptions: ์ปดํŒŒ์ผ๋Ÿฌ ์˜ต์…˜์„ ์„ค์ •ํ•˜๋Š” ๋ถ€๋ถ„์ด์—์š”.
    • target: ์ปดํŒŒ์ผ๋œ JavaScript์˜ ๋ฒ„์ „์„ ์ง€์ •ํ•ด์š”. ์—ฌ๊ธฐ์„œ๋Š” ES5๋กœ ์„ค์ •ํ–ˆ๋„ค์š”.
    • module: ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์„ ์ง€์ •ํ•ด์š”. CommonJS๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์š”.
    • strict: ์—„๊ฒฉํ•œ ํƒ€์ž… ์ฒดํฌ๋ฅผ ํ™œ์„ฑํ™”ํ•ด์š”. ๋ฒ„๊ทธ๋ฅผ ๋ฏธ๋ฆฌ ์žก์„ ์ˆ˜ ์žˆ์–ด์„œ ์ข‹๋‹ต๋‹ˆ๋‹ค!
    • esModuleInterop: CommonJS ๋ชจ๋“ˆ์„ ES6 ๋ชจ๋“ˆ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜์š”.
    • outDir: ์ปดํŒŒ์ผ๋œ ํŒŒ์ผ์ด ์ €์žฅ๋  ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ง€์ •ํ•ด์š”.
    • rootDir: ์†Œ์Šค ํŒŒ์ผ์ด ์žˆ๋Š” ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ง€์ •ํ•ด์š”.
  • include: ์ปดํŒŒ์ผํ•  ํŒŒ์ผ๋“ค์„ ์ง€์ •ํ•ด์š”. ์—ฌ๊ธฐ์„œ๋Š” src ํด๋” ์•„๋ž˜์˜ ๋ชจ๋“  ํŒŒ์ผ์„ ํฌํ•จํ•˜๊ณ  ์žˆ์–ด์š”.
  • exclude: ์ปดํŒŒ์ผ์—์„œ ์ œ์™ธํ•  ํŒŒ์ผ๋“ค์„ ์ง€์ •ํ•ด์š”. node_modules์™€ ํ…Œ์ŠคํŠธ ํŒŒ์ผ๋“ค์„ ์ œ์™ธํ•˜๊ณ  ์žˆ๋„ค์š”.

์ด๋ ‡๊ฒŒ ์„ค์ •ํ•˜๋ฉด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•ด์•ผ ํ• ์ง€ ์•Œ ์ˆ˜ ์žˆ์–ด์š”. ๋งˆ์น˜ ์š”๋ฆฌ์‚ฌ์—๊ฒŒ ๋ ˆ์‹œํ”ผ๋ฅผ ์ฃผ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ฃ ! ๐Ÿณ

1.2 package.json: ํ”„๋กœ์ ํŠธ์˜ ์‹ ๋ถ„์ฆ ๐Ÿ“‡

package.json ํŒŒ์ผ์€ ํ”„๋กœ์ ํŠธ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๊ณ  ์žˆ์–ด์š”. ํ”„๋กœ์ ํŠธ์˜ ์ด๋ฆ„, ๋ฒ„์ „, ์˜์กด์„ฑ ๋“ฑ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์ฃ . npm์œผ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋ฉด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ํŒŒ์ผ์ด์—์š”.

{
  "name": "my-awesome-project",
  "version": "1.0.0",
  "description": "A super cool TypeScript project",
  "main": "dist/index.js",
  "scripts": {
    "start": "node dist/index.js",
    "build": "tsc",
    "dev": "ts-node src/index.ts"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {
    "@types/express": "^4.17.11",
    "typescript": "^4.2.4",
    "ts-node": "^9.1.1"
  }
}

์—ฌ๊ธฐ์„œ ์ฃผ๋ชฉํ•  ๋งŒํ•œ ๋ถ€๋ถ„์€ scripts์˜ˆ์š”. ์ด ๋ถ€๋ถ„์—์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ๋นŒ๋“œํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๋ช…๋ น์–ด๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์˜ˆ๋ฅผ ๋“ค์–ด, npm run build๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ปดํŒŒ์ผ๋Ÿฌ(tsc)๊ฐ€ ์‹คํ–‰๋˜์–ด ํ”„๋กœ์ ํŠธ๋ฅผ ๋นŒ๋“œํ•˜๊ฒŒ ๋˜์ฃ .

๊ทธ๋ฆฌ๊ณ  dependencies์™€ devDependencies์—์„œ๋Š” ํ”„๋กœ์ ํŠธ์— ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋“ค์„ ๊ด€๋ฆฌํ•ด์š”. dependencies๋Š” ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋“ค์ด๊ณ , devDependencies๋Š” ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋งŒ ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋“ค์ด์—์š”.

๐Ÿ’ก ๊ฟ€ํŒ: package.json ํŒŒ์ผ์„ ์ž˜ ๊ด€๋ฆฌํ•˜๋ฉด ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ํ˜‘์—…ํ•  ๋•Œ ์ •๋ง ํŽธํ•ด์š”. ํ”„๋กœ์ ํŠธ๋ฅผ ํด๋ก ํ•˜๊ณ  npm install๋งŒ ์‹คํ–‰ํ•˜๋ฉด ๋ชจ๋“  ์˜์กด์„ฑ์„ ํ•œ ๋ฒˆ์— ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ ์š”!

์ž, ์ด์ œ ํ”„๋กœ์ ํŠธ์˜ ๊ธฐ์ดˆ ์„ค์ •์€ ๋๋‚ฌ์–ด์š”. ์ด๋ ‡๊ฒŒ ํƒ„ํƒ„ํ•œ ๊ธฐ์ดˆ๋ฅผ ๋‹ค์กŒ์œผ๋‹ˆ, ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋ฅผ ์žก์•„๋ณผ๊นŒ์š”? ๋‹ค์Œ ์„น์…˜์—์„œ ํด๋” ๊ตฌ์กฐ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•ด์š”! ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ

ํ”„๋กœ์ ํŠธ ์„ค์ • ์š”์•ฝ ํ”„๋กœ์ ํŠธ ์„ค์ • ์š”์•ฝ tsconfig.json - ์ปดํŒŒ์ผ๋Ÿฌ ์˜ต์…˜ ์„ค์ • - ํฌํ•จ/์ œ์™ธ ํŒŒ์ผ ์ง€์ • - ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ ์ง€์ • package.json - ํ”„๋กœ์ ํŠธ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ - ์Šคํฌ๋ฆฝํŠธ ์ •์˜ - ์˜์กด์„ฑ ๊ด€๋ฆฌ

์ด ๊ทธ๋ฆผ์„ ๋ณด๋ฉด ํ”„๋กœ์ ํŠธ ์„ค์ •์˜ ํ•ต์‹ฌ ์š”์†Œ๋“ค์„ ํ•œ๋ˆˆ์— ๋ณผ ์ˆ˜ ์žˆ์ฃ ? tsconfig.json๊ณผ package.json, ์ด ๋‘ ํŒŒ์ผ๋งŒ ์ž˜ ์„ค์ •ํ•ด๋„ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ๋Š” ๋ฐ˜์€ ์„ฑ๊ณตํ•œ ๊ฑฐ๋‚˜ ๋‹ค๋ฆ„์—†์–ด์š”! ๐Ÿ‘

2. ํด๋” ๊ตฌ์กฐ: ์ •๋ฆฌ์ •๋ˆ์˜ ๋ฏธํ•™ ๐Ÿ—‚๏ธ

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

2.1 ๊ธฐ๋ณธ ํด๋” ๊ตฌ์กฐ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์ ํŠธ์˜ ๊ธฐ๋ณธ์ ์ธ ํด๋” ๊ตฌ์กฐ๋Š” ์ด๋ ‡๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์–ด์š”:

my-project/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ index.ts
โ”‚   โ”œโ”€โ”€ config/
โ”‚   โ”œโ”€โ”€ models/
โ”‚   โ”œโ”€โ”€ controllers/
โ”‚   โ”œโ”€โ”€ services/
โ”‚   โ””โ”€โ”€ utils/
โ”œโ”€โ”€ dist/
โ”œโ”€โ”€ tests/
โ”œโ”€โ”€ node_modules/
โ”œโ”€โ”€ package.json
โ””โ”€โ”€ tsconfig.json

์šฐ์™€~ ๋ญ”๊ฐ€ ๋ณต์žกํ•ด ๋ณด์ด์ฃ ? ํ•˜์ง€๋งŒ ๊ฑฑ์ • ๋งˆ์„ธ์š”. ํ•˜๋‚˜์”ฉ ์„ค๋ช…ํ•ด ๋“œ๋ฆด๊ฒŒ์š”! ๐Ÿ˜Š

  • src/: ์†Œ์Šค ์ฝ”๋“œ๊ฐ€ ์œ„์น˜ํ•˜๋Š” ํด๋”์˜ˆ์š”. ์—ฌ๊ธฐ์— ๋ชจ๋“  TypeScript ํŒŒ์ผ๋“ค์ด ๋“ค์–ด๊ฐ€์š”.
  • dist/: ์ปดํŒŒ์ผ๋œ JavaScript ํŒŒ์ผ๋“ค์ด ์ €์žฅ๋˜๋Š” ํด๋”์˜ˆ์š”. ๋ฐฐํฌํ•  ๋•Œ๋Š” ์ด ํด๋”์˜ ๋‚ด์šฉ์„ ์‚ฌ์šฉํ•ด์š”.
  • tests/: ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ €์žฅํ•˜๋Š” ํด๋”์˜ˆ์š”. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ๋“ฑ์ด ์—ฌ๊ธฐ์— ๋“ค์–ด๊ฐ€์š”.
  • node_modules/: npm์œผ๋กœ ์„ค์น˜ํ•œ ํŒจํ‚ค์ง€๋“ค์ด ์ €์žฅ๋˜๋Š” ํด๋”์˜ˆ์š”. ์ด ํด๋”๋Š” .gitignore์— ์ถ”๊ฐ€ํ•ด์„œ ๋ฒ„์ „ ๊ด€๋ฆฌ์—์„œ ์ œ์™ธํ•˜๋Š” ๊ฒŒ ์ข‹์•„์š”.

src/ ํด๋” ์•ˆ์˜ ๊ตฌ์กฐ๋ฅผ ์ข€ ๋” ์ž์„ธํžˆ ์‚ดํŽด๋ณผ๊นŒ์š”?

  • index.ts: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ง„์ž…์ ์ด์—์š”. ์—ฌ๊ธฐ์„œ ์•ฑ์„ ์‹œ์ž‘ํ•˜๊ณ  ํ•„์š”ํ•œ ๋ชจ๋“ˆ๋“ค์„ ๋ถˆ๋Ÿฌ์™€์š”.
  • config/: ์„ค์ • ํŒŒ์ผ๋“ค์„ ๋ชจ์•„๋‘๋Š” ํด๋”์˜ˆ์š”. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์ •๋ณด, ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋“ฑ์„ ์—ฌ๊ธฐ์— ์ €์žฅํ•ด์š”.
  • models/: ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์„ ์ •์˜ํ•˜๋Š” ํด๋”์˜ˆ์š”. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ๋‚˜ ์ธํ„ฐํŽ˜์ด์Šค ๋“ฑ์ด ์—ฌ๊ธฐ์— ๋“ค์–ด๊ฐ€์š”.
  • controllers/: ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋“ค์ด ์œ„์น˜ํ•ด์š”.
  • services/: ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์„œ๋น„์Šค๋“ค์ด ์œ„์น˜ํ•ด์š”.
  • utils/: ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋“ค์„ ๋ชจ์•„๋‘๋Š” ํด๋”์˜ˆ์š”.

๐ŸŽจ ๋””์ž์ธ ํŒ: ํด๋” ๊ตฌ์กฐ๋Š” ํ”„๋กœ์ ํŠธ์˜ ํŠน์„ฑ์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ฒŒ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ค‘์š”ํ•œ ๊ฑด ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๊ฑฐ์˜ˆ์š”!

2.2 ๋ชจ๋“ˆํ™”: ์ž‘์€ ์กฐ๊ฐ๋“ค์˜ ํ•ฉ์ฃผ ๐Ÿงฉ

ํด๋” ๊ตฌ์กฐ๋ฅผ ์žก์„ ๋•Œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฑด ๋ชจ๋“ˆํ™”์˜ˆ์š”. ๊ฐ ํด๋”๋Š” ํŠน์ •ํ•œ ์—ญํ• ์„ ๊ฐ€์ง„ ๋ชจ๋“ˆ๋“ค์„ ํฌํ•จํ•˜๊ณ  ์žˆ์–ด์•ผ ํ•ด์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๋„ ๋†’์•„์ง€๊ณ , ์œ ์ง€๋ณด์ˆ˜๋„ ์‰ฌ์›Œ์ง„๋‹ต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณผ๊นŒ์š”? ์ด๋Ÿฐ ์‹์œผ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์–ด์š”:

src/
โ”œโ”€โ”€ models/
โ”‚   โ””โ”€โ”€ User.ts
โ”œโ”€โ”€ controllers/
โ”‚   โ””โ”€โ”€ UserController.ts
โ”œโ”€โ”€ services/
โ”‚   โ””โ”€โ”€ UserService.ts
โ””โ”€โ”€ utils/
    โ””โ”€โ”€ passwordHash.ts

์ด๋ ‡๊ฒŒ ๊ตฌ์„ฑํ•˜๋ฉด ์‚ฌ์šฉ์ž์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ๋กœ์ง์ด ๊น”๋”ํ•˜๊ฒŒ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์ฃ ? ๐Ÿ‘Œ

2.3 ๋ช…๋ช… ๊ทœ์น™: ์ด๋ฆ„์ง“๊ธฐ์˜ ์˜ˆ์ˆ  ๐ŸŽจ

ํด๋”์™€ ํŒŒ์ผ์˜ ์ด๋ฆ„์„ ์ง€์„ ๋•Œ๋Š” ์ผ๊ด€๋œ ๊ทœ์น™์„ ๋”ฐ๋ฅด๋Š” ๊ฒŒ ์ข‹์•„์š”. ๋ณดํ†ต ์ด๋Ÿฐ ๊ทœ์น™๋“ค์„ ๋งŽ์ด ์‚ฌ์šฉํ•ด์š”:

  • ํด๋” ์ด๋ฆ„์€ ๋ณต์ˆ˜ํ˜•์œผ๋กœ: models, controllers, services
  • ํŒŒ์ผ ์ด๋ฆ„์€ PascalCase๋กœ: UserController.ts, AuthMiddleware.ts
  • ์ธํ„ฐํŽ˜์ด์Šค๋Š” I๋กœ ์‹œ์ž‘: IUser.ts
  • ํƒ€์ž…์€ T๋กœ ์‹œ์ž‘: TUserResponse.ts

์ด๋ ‡๊ฒŒ ๊ทœ์น™์„ ์ •ํ•ด๋‘๋ฉด ํŒ€์›๋“ค๊ณผ ํ˜‘์—…ํ•  ๋•Œ๋„ ํ˜ผ๋ž€์„ ์ค„์ผ ์ˆ˜ ์žˆ์–ด์š”. ๋งˆ์น˜ ๊ตํ†ต ์‹ ํ˜ธ์™€ ๊ฐ™์€ ๊ฑฐ์ฃ ! ๐Ÿšฆ

ํด๋” ๊ตฌ์กฐ ์‹œ๊ฐํ™” ํด๋” ๊ตฌ์กฐ ์‹œ๊ฐํ™” my-project src index.ts config/ models/ controllers/ services/ dist tests node_modules

์ด ๊ทธ๋ฆผ์„ ๋ณด๋ฉด ํ”„๋กœ์ ํŠธ์˜ ํด๋” ๊ตฌ์กฐ๊ฐ€ ํ•œ๋ˆˆ์— ๋“ค์–ด์˜ค์ฃ ? src ํด๋” ์•ˆ์— ์—ฌ๋Ÿฌ ํ•˜์œ„ ํด๋”๋“ค์ด ์žˆ๊ณ , ๊ทธ ์˜†์— dist, tests, node_modules ํด๋”๊ฐ€ ์žˆ์–ด์š”. ์ด๋ ‡๊ฒŒ ๊ตฌ์กฐํ™”ํ•˜๋ฉด ํ”„๋กœ์ ํŠธ๊ฐ€ ํ›จ์”ฌ ์ •๋ˆ๋˜์–ด ๋ณด์ด๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ๋„ ์‰ฌ์›Œ์ ธ์š”! ๐Ÿ˜ƒ

์ž, ์ด์ œ ํด๋” ๊ตฌ์กฐ์— ๋Œ€ํ•ด ์•Œ์•„๋ดค์–ด์š”. ์ด๋ ‡๊ฒŒ ์ž˜ ์ •๋ฆฌ๋œ ๊ตฌ์กฐ ์œ„์— ์ฝ”๋“œ๋ฅผ ์Œ“์•„์˜ฌ๋ฆฌ๋ฉด ํ›จ์”ฌ ํšจ์œจ์ ์ธ ๊ฐœ๋ฐœ์ด ๊ฐ€๋Šฅํ•ด์งˆ ๊ฑฐ์˜ˆ์š”. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์‹ค์ œ๋กœ ์ด ๊ตฌ์กฐ ์•ˆ์— ์–ด๋–ป๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ์ข‹์„์ง€ ์•Œ์•„๋ณด๋„๋ก ํ• ๊ฒŒ์š”! ์ค€๋น„๋˜์…จ๋‚˜์š”? ๊ณ ๊ณ ์”ฝ~! ๐Ÿš€

3. ์ฝ”๋“œ ๊ตฌ์„ฑ: ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ๊ฝƒ ๐ŸŒธ

์ž, ์ด์ œ ์ง„์งœ ๊ฟ€์žผ ํŒŒํŠธ๊ฐ€ ์™”์–ด์š”! ์ฝ”๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑํ•˜๋Š๋ƒ์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ฒœ๊ตญ์ด ๋  ์ˆ˜๋„, ์ง€์˜ฅ์ด ๋  ์ˆ˜๋„ ์žˆ๋‹ต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์ง‘์ค‘ํ•ด์ฃผ์„ธ์š”! ๐Ÿ‘€

3.1 ์ธํ„ฐํŽ˜์ด์Šค์™€ ํƒ€์ž…: ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ์‹ฌ์žฅ โค๏ธ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ๊ฐ€์žฅ ํฐ ์žฅ์ ์€ ๋ญ๋‹ค? ๋ฐ”๋กœ 'ํƒ€์ž…'์ด์ฃ ! ์ธํ„ฐํŽ˜์ด์Šค์™€ ํƒ€์ž…์„ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ์ฝ”๋“œ์˜ ์•ˆ์ •์„ฑ๊ณผ ๊ฐ€๋…์„ฑ์„ ํฌ๊ฒŒ ๋†’์ผ ์ˆ˜ ์žˆ์–ด์š”.

// models/User.ts
interface IUser {
  id: number;
  name: string;
  email: string;
  age?: number;  // ์„ ํƒ์  ์†์„ฑ
}

type TUserResponse = Omit<iuser>;  // email์„ ์ œ์™ธํ•œ User ํƒ€์ž…
</iuser>

์—ฌ๊ธฐ์„œ IUser๋Š” ์‚ฌ์šฉ์ž์˜ ๊ธฐ๋ณธ ์ •๋ณด๋ฅผ ์ •์˜ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์˜ˆ์š”. TUserResponse๋Š” IUser์—์„œ email์„ ์ œ์™ธํ•œ ํƒ€์ž…์ด์—์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด API ์‘๋‹ต์—์„œ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ์ œ์™ธํ•  ์ˆ˜ ์žˆ์ฃ .

๐Ÿ’ก ๊ฟ€ํŒ: ์ธํ„ฐํŽ˜์ด์Šค๋Š” ํ™•์žฅ์ด ๊ฐ€๋Šฅํ•˜๊ณ , ํƒ€์ž…์€ ์œ ๋‹ˆ์˜จ์ด๋‚˜ ์ธํ„ฐ์„น์…˜ ๊ฐ™์€ ๊ณ ๊ธ‰ ํƒ€์ž… ์—ฐ์‚ฐ์ด ๊ฐ€๋Šฅํ•ด์š”. ์ƒํ™ฉ์— ๋งž๊ฒŒ ์‚ฌ์šฉํ•˜์„ธ์š”!

3.2 ํด๋ž˜์Šค์™€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ: ๊ฐ์ฒด์ง€ํ–ฅ์˜ ์ •์ˆ˜ ๐ŸŽญ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ํด๋ž˜์Šค์™€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•  ์ˆ˜ ์žˆ์–ด์š”. ํŠนํžˆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ๋ฉ”ํƒ€ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ด์ฃ .

// controllers/UserController.ts
import { Controller, Get, Post, Body } from 'some-framework';
import { UserService } from '../services/UserService';
import { IUser } from '../models/User';

@Controller('users')
export class UserController {
  constructor(private userService: UserService) {}

  @Get()
  async getAllUsers(): Promise<iuser> {
    return this.userService.getAllUsers();
  }

  @Post()
  async createUser(@Body() userData: IUser): Promise<iuser> {
    return this.userService.createUser(userData);
  }
}
</iuser></iuser>

์ด ์˜ˆ์ œ์—์„œ๋Š” @Controller, @Get, @Post ๊ฐ™์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด ๋ผ์šฐํŒ…์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์–ด์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๊น”๋”ํ•ด์ง€๊ณ  ๊ฐ€๋…์„ฑ๋„ ์ข‹์•„์ง€์ฃ !

3.3 ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ: Promise์™€ async/await์˜ ํ–ฅ์—ฐ ๐ŸŽญ

ํ˜„๋Œ€ ์›น ๊ฐœ๋ฐœ์—์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋Š” ํ•„์ˆ˜์ฃ . ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” Promise์™€ async/await๋ฅผ ์‚ฌ์šฉํ•ด ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ๋™๊ธฐ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด์š”.

// services/UserService.ts
import { IUser } from '../models/User';
import { UserRepository } from '../repositories/UserRepository';

export class UserService {
  constructor(private userRepo: UserRepository) {}

  async getAllUsers(): Promise<iuser> {
    try {
      return await this.userRepo.findAll();
    } catch (error) {
      console.error('Failed to get users:', error);
      throw error;
    }
  }

  async createUser(userData: IUser): Promise<iuser> {
    try {
      return await this.userRepo.create(userData);
    } catch (error) {
      console.error('Failed to create user:', error);
      throw error;
    }
  }
}
</iuser></iuser>

์—ฌ๊ธฐ์„œ๋Š” async /await๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์–ด์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๋ธ”๋กœํ‚น๋˜์ง€ ์•Š๊ณ  ํšจ์œจ์ ์œผ๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค.

3.4 ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜: ์žฌ์‚ฌ์šฉ์„ฑ์˜ ๊ทน๋Œ€ํ™” ๐Ÿ”„

ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋‹ค ๋ณด๋ฉด ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ๋“ค์ด ์žˆ์–ด์š”. ์ด๋Ÿฐ ๊ธฐ๋Šฅ๋“ค์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค์–ด ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์–ด์š”.

// utils/stringUtils.ts
export function capitalize(str: string): string {
  return str.charAt(0).toUpperCase() + str.slice(1);
}

export function truncate(str: string, length: number): string {
  return str.length > length ? str.substring(0, length) + '...' : str;
}

// utils/dateUtils.ts
export function formatDate(date: Date): string {
  return date.toISOString().split('T')[0];
}

์ด๋ ‡๊ฒŒ ๋งŒ๋“  ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋“ค์€ ํ”„๋กœ์ ํŠธ ์ „์ฒด์—์„œ ์‰ฝ๊ฒŒ importํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ฝ”๋“œ ์ค‘๋ณต์„ ์ค„์ด๊ณ  ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๋ฐ ํฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค!

3.5 ์—๋Ÿฌ ์ฒ˜๋ฆฌ: ์•ˆ์ „ํ•œ ์ฝ”๋“œ์˜ ๋น„๊ฒฐ ๐Ÿ›ก๏ธ

์—๋Ÿฌ ์ฒ˜๋ฆฌ๋Š” ์•ˆ์ •์ ์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“œ๋Š” ๋ฐ ํ•„์ˆ˜์ ์ด์—์š”. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ์ปค์Šคํ…€ ์—๋Ÿฌ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋” ์„ธ๋ฐ€ํ•œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ด์š”.

// utils/errors.ts
export class AppError extends Error {
  constructor(public statusCode: number, message: string) {
    super(message);
    this.name = 'AppError';
  }
}

export class NotFoundError extends AppError {
  constructor(message: string = 'Resource not found') {
    super(404, message);
    this.name = 'NotFoundError';
  }
}

// services/UserService.ts
import { NotFoundError } from '../utils/errors';

export class UserService {
  // ...

  async getUserById(id: number): Promise<iuser> {
    const user = await this.userRepo.findById(id);
    if (!user) {
      throw new NotFoundError(`User with id ${id} not found`);
    }
    return user;
  }
}
</iuser>

์ด๋ ‡๊ฒŒ ์ปค์Šคํ…€ ์—๋Ÿฌ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—๋Ÿฌ์˜ ์ข…๋ฅ˜๋ฅผ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๊ณ , ์ ์ ˆํ•œ HTTP ์ƒํƒœ ์ฝ”๋“œ๋„ ์‰ฝ๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”.

3.6 ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ด€๋ฆฌ: ์•ˆ์ „ํ•˜๊ณ  ์œ ์—ฐํ•œ ์„ค์ • ๐Ÿ”

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์ •๋ณด๋‚˜ API ํ‚ค ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋Š” ์ฝ”๋“œ์— ์ง์ ‘ ์ž‘์„ฑํ•˜๋ฉด ์•ˆ ๋ผ์š”. ๋Œ€์‹  ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

// config/env.ts
import dotenv from 'dotenv';

dotenv.config();

export const ENV = {
  NODE_ENV: process.env.NODE_ENV || 'development',
  PORT: process.env.PORT || 3000,
  DB_URL: process.env.DB_URL || 'mongodb://localhost:27017/myapp',
  JWT_SECRET: process.env.JWT_SECRET || 'your-secret-key'
};

// ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ ์‚ฌ์šฉํ•  ๋•Œ
import { ENV } from './config/env';

console.log(`Server running on port ${ENV.PORT}`);

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์„ค์ •์„ ์‰ฝ๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , ๋ฏผ๊ฐํ•œ ์ •๋ณด๋„ ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ ๊ตฌ์„ฑ ์š”์†Œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ ๊ตฌ์„ฑ ์š”์†Œ ์ธํ„ฐํŽ˜์ด์Šค์™€ ํƒ€์ž… ํด๋ž˜์Šค์™€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ด€๋ฆฌ

์ด ๊ทธ๋ฆผ์€ ์šฐ๋ฆฌ๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ์‚ดํŽด๋ณธ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ ๊ตฌ์„ฑ์˜ ์ฃผ์š” ์š”์†Œ๋“ค์„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์–ด์š”. ๊ฐ๊ฐ์˜ ์š”์†Œ๋“ค์ด ์„œ๋กœ ์กฐํ™”๋กญ๊ฒŒ ์ž‘๋™ํ•  ๋•Œ, ์šฐ๋ฆฌ์˜ ์ฝ”๋“œ๋Š” ๋”์šฑ ๊ฐ•๋ ฅํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค! ๐ŸŒˆ

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

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ์„ธ๊ณ„์—์„œ ์ฆ๊ฒ๊ฒŒ ์ฝ”๋”ฉํ•˜์„ธ์š”! ํ™”์ดํŒ…! ๐Ÿ’ช๐Ÿ˜„