์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ ํ’€์Šคํƒ ์›น๊ฐœ๋ฐœ๊ณผ MERNยทMEAN ์Šคํƒ์„ํ™œ์šฉํ•œ ํ˜„๋Œ€์  ๊ฐœ๋ฐœ ํ™˜๊ฒฝ

๐Ÿš€ ํ’€์Šคํƒ ์›น๊ฐœ๋ฐœ๊ณผ MERNยทMEAN ์Šคํƒ์„
ํ™œ์šฉํ•œ ํ˜„๋Œ€์  ๊ฐœ๋ฐœ ํ™˜๊ฒฝ

Full-Stack Web Development ยท MERN ยท MEAN ยท ํ˜„๋Œ€ ๊ฐœ๋ฐœ ํŠธ๋ Œ๋“œ ์™„์ „ ์ •๋ณต
MongoDB Express React Angular Node.js ํ’€์Šคํƒ
ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ž์˜ ์„ธ๊ณ„ ๐ŸŒ M MongoDB ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค E Express.js ๋ฐฑ์—”๋“œ ํ”„๋ ˆ์ž„์›Œํฌ R React ํ”„๋ก ํŠธ์—”๋“œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ N Node.js ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ MEAN Angular ๋ฒ„์ „ React โ†’ Angular ๊ต์ฒด ์Šคํƒ JavaScript ํ•˜๋‚˜๋กœ ํ”„๋ก ํŠธ์—”๋“œ + ๋ฐฑ์—”๋“œ + DB ๋ชจ๋‘ ์ •๋ณต! ๐Ÿ”ฅ ํ’€์Šคํƒ ๊ฐœ๋ฐœ์˜ ํ•ต์‹ฌ ์Šคํƒ ์™„์ „ ๊ฐ€์ด๋“œ
๐Ÿ’ฌ ์นœ๊ตฌํ•œํ…Œ ์นดํ†ก ๋ฐ›์€ ๊ฒƒ ๊ฐ™์€ ์ƒํ™ฉ ใ…‹ใ…‹
"์•ผ ์š”์ฆ˜ ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ž ๋œ๋‹ค๊ณ  MERN ์Šคํƒ ๊ณต๋ถ€ํ•œ๋‹ค๋Š”๋ฐ... ๊ทธ๊ฒŒ ๋ญ”๋ฐ? ๐Ÿค” ๋‚˜๋„ ํ•ด์•ผ ํ•˜๋‚˜?"

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

๐ŸŒ 1. ํ’€์Šคํƒ ์›น๊ฐœ๋ฐœ์ด๋ž€ ๋ญ”๋ฐ?

์›น ๊ฐœ๋ฐœ์„ ์ฒ˜์Œ ์ ‘ํ•˜๋ฉด "ํ”„๋ก ํŠธ์—”๋“œ"๋ž‘ "๋ฐฑ์—”๋“œ"๋ผ๋Š” ๋ง์„ ์—„์ฒญ ๋งŽ์ด ๋“ฃ๊ฒŒ ๋จ.
๊ทผ๋ฐ ์ด ๋‘˜์„ ๋™์‹œ์— ๋‹ค ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐœ๋ฐœ์ž๋ฅผ ๋ฐ”๋กœ ํ’€์Šคํƒ(Full-Stack) ๊ฐœ๋ฐœ์ž๋ผ๊ณ  ๋ถˆ๋Ÿฌ! ๐ŸŽฏ

๐Ÿ–ฅ๏ธ ํ”„๋ก ํŠธ์—”๋“œ vs ๋ฐฑ์—”๋“œ vs ํ’€์Šคํƒ

๊ตฌ๋ถ„ ๋‹ด๋‹น ์˜์—ญ ์ฃผ์š” ๊ธฐ์ˆ 
ํ”„๋ก ํŠธ์—”๋“œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋Š” ํ™”๋ฉด, UI/UX HTML, CSS, JavaScript, React, Vue
๋ฐฑ์—”๋“œ ์„œ๋ฒ„, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค, API Node.js, Python, Java, DB
ํ’€์Šคํƒ ๐Ÿ”ฅ ํ”„๋ก ํŠธ + ๋ฐฑ์—”๋“œ ์ „๋ถ€ ์œ„์˜ ๋ชจ๋“  ๊ฒƒ + ๋ฐฐํฌ๊นŒ์ง€

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

๐Ÿ“Œ ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ž์˜ ํ•ต์‹ฌ ์—ญ๋Ÿ‰

โœ… ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ(๋ธŒ๋ผ์šฐ์ €)์—์„œ ๋™์ž‘ํ•˜๋Š” UI ๊ตฌํ˜„ ๋Šฅ๋ ฅ
โœ… ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋กœ์ง ๋ฐ API ์„ค๊ณ„/๊ฐœ๋ฐœ ๋Šฅ๋ ฅ
โœ… ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„ ๋ฐ ์ฟผ๋ฆฌ ์ž‘์„ฑ ๋Šฅ๋ ฅ
โœ… ํด๋ผ์šฐ๋“œ ๋ฐฐํฌ ๋ฐ DevOps ๊ธฐ์ดˆ ์ง€์‹
โœ… ๋ฒ„์ „ ๊ด€๋ฆฌ(Git) ๋ฐ ํ˜‘์—… ๋„๊ตฌ ํ™œ์šฉ ๋Šฅ๋ ฅ

์‹ค์ œ๋กœ ์Šคํƒ€ํŠธ์—…์ด๋‚˜ ์†Œ๊ทœ๋ชจ ํŒ€์—์„œ๋Š” ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ž ํ•œ ๋ช…์ด
์„œ๋น„์Šค ์ „์ฒด๋ฅผ ํ˜ผ์ž ๋งŒ๋“ค์–ด๋‚ด๋Š” ๊ฒฝ์šฐ๋„ ์—„์ฒญ ๋งŽ์•„.
๊ทธ๋ž˜์„œ ์š”์ฆ˜ ์ฑ„์šฉ ๊ณต๊ณ  ๋ณด๋ฉด "ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ž ์šฐ๋Œ€" ์ด๋Ÿฐ ๋ฌธ๊ตฌ ์ง„์งœ ์ž์ฃผ ๋ณด์ž„ ๐Ÿ‘€


โšก 2. MERN ์Šคํƒ - ํ˜„์žฌ ๊ฐ€์žฅ ํ•ซํ•œ ํ’€์Šคํƒ ์กฐํ•ฉ

ํ’€์Šคํƒ ๊ฐœ๋ฐœ์„ ๋ฐฐ์šฐ๋ ค๊ณ  ๊ฒ€์ƒ‰ํ•˜๋ฉด MERN ์Šคํƒ์ด๋ผ๋Š” ๋‹จ์–ด๊ฐ€ ์—„์ฒญ ๋งŽ์ด ๋‚˜์˜ด.
์ด๊ฒŒ ๋ญ”์ง€ ์ œ๋Œ€๋กœ ํŒŒํ—ค์ณ๋ณด์ž! ๐Ÿ”

๐Ÿ”ค MERN = MongoDB + Express.js + React + Node.js

๊ฐ ๊ธ€์ž๊ฐ€ ๊ธฐ์ˆ  ์ด๋ฆ„์˜ ์ฒซ ๊ธ€์ž๋ฅผ ๋”ฐ์˜จ ๊ฑฐ์•ผ.
์ด 4๊ฐ€์ง€ ๊ธฐ์ˆ ์„ ์กฐํ•ฉํ•ด์„œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด!

MERN ์Šคํƒ ๊ตฌ์กฐ๋„ ๐Ÿ‘ค ์‚ฌ์šฉ์ž ๋ธŒ๋ผ์šฐ์ € โš›๏ธ React ํ”„๋ก ํŠธ์—”๋“œ UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (ํด๋ผ์ด์–ธํŠธ) ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ ยท Virtual DOM ยท SPA ๊ตฌํ˜„ ๐Ÿš‚ Express.js ๋ฐฑ์—”๋“œ ์›น ํ”„๋ ˆ์ž„์›Œํฌ (์„œ๋ฒ„) REST API ยท ๋ผ์šฐํŒ… ยท ๋ฏธ๋“ค์›จ์–ด ์ฒ˜๋ฆฌ ๐Ÿƒ MongoDB NoSQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค JSON ํ˜•ํƒœ ๋ฌธ์„œ ์ €์žฅ ยท ์œ ์—ฐํ•œ ์Šคํ‚ค๋งˆ ๐ŸŸข Node.js JavaScript ๋Ÿฐํƒ€์ž„ Express ์‹คํ–‰ ํ™˜๊ฒฝ

๐Ÿƒ M - MongoDB (๋ชฝ๊ณ DB)

MERN์˜ ์ฒซ ๋ฒˆ์งธ M! MongoDB๋Š” ์ „ํ†ต์ ์ธ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(MySQL, PostgreSQL)์™€ ๋‹ฌ๋ฆฌ
NoSQL ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์•ผ.

๊ธฐ์กด SQL DB๋Š” ์—‘์…€ ํ‘œ์ฒ˜๋Ÿผ ํ–‰(row)๊ณผ ์—ด(column)๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š”๋ฐ,
MongoDB๋Š” JSON ํ˜•ํƒœ์˜ ๋ฌธ์„œ(Document)๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•จ.
์ด๊ฒŒ JavaScript๋ž‘ ์ฐฐ๋–ก๊ถํ•ฉ์ธ ์ด์œ ๊ฐ€ ๋ฐ”๋กœ ์—ฌ๊ธฐ ์žˆ์–ด! ๐ŸŽฏ

๐Ÿ“Œ MongoDB์˜ ํ•ต์‹ฌ ํŠน์ง•

โœ… ์Šคํ‚ค๋งˆ ์œ ์—ฐ์„ฑ: ๋ฏธ๋ฆฌ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ๋ฅผ ์ •ํ•˜์ง€ ์•Š์•„๋„ ๋จ
โœ… JSON/BSON ํ˜•์‹: JavaScript ๊ฐ์ฒด์™€ ์™„๋ฒฝ ํ˜ธํ™˜
โœ… ์ˆ˜ํ‰ ํ™•์žฅ(Sharding): ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์•„์ ธ๋„ ์„œ๋ฒ„ ์ถ”๊ฐ€๋กœ ํ™•์žฅ ๊ฐ€๋Šฅ
โœ… Mongoose ODM: Node.js์—์„œ MongoDB๋ฅผ ์‰ฝ๊ฒŒ ๋‹ค๋ฃจ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
โœ… Atlas ํด๋ผ์šฐ๋“œ: MongoDB ๊ณต์‹ ํด๋ผ์šฐ๋“œ ์„œ๋น„์Šค๋กœ ๋ฌด๋ฃŒ ์‹œ์ž‘ ๊ฐ€๋Šฅ

์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋•Œ ์ด๋Ÿฐ ์‹์œผ๋กœ ์ƒ๊ฒผ์–ด:

// MongoDB ๋ฌธ์„œ(Document) ์˜ˆ์‹œ
{
  "_id": "ObjectId('64a1b2c3d4e5f6789012')",
  "์ด๋ฆ„": "๊น€๊ฐœ๋ฐœ",
  "์ด๋ฉ”์ผ": "dev@example.com",
  "๋‚˜์ด": 28,
  "๊ธฐ์ˆ ์Šคํƒ": ["React", "Node.js", "MongoDB"],
  "ํ”„๋กœํ•„": {
    "์†Œ๊ฐœ": "ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ž ์ง€๋ง์ƒ",
    "๊ฒฝ๋ ฅ": 2
  }
}

๋ณด์ด์ง€? JavaScript ๊ฐ์ฒด๋ž‘ ๊ฑฐ์˜ ๋˜‘๊ฐ™์ด ์ƒ๊ฒผ์ž–์•„ ใ…‹ใ…‹ใ…‹
๊ทธ๋ž˜์„œ MERN ์Šคํƒ์—์„œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๊ฐ€ ์—„์ฒญ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ˜๋Ÿฌ๊ฐ€๋Š” ๊ฑฐ์•ผ! ๐ŸŒŠ

๐Ÿš‚ E - Express.js (์ต์Šคํ”„๋ ˆ์Šค)

Express.js๋Š” Node.js ์œ„์—์„œ ๋™์ž‘ํ•˜๋Š” ๋ฐฑ์—”๋“œ ์›น ํ”„๋ ˆ์ž„์›Œํฌ์•ผ.
Node.js๋งŒ์œผ๋กœ๋„ ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ, ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด ๋ณต์žกํ•ด์ง€๊ฑฐ๋“ .
Express๋Š” ๊ทธ๊ฑธ ์—„์ฒญ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋„๊ตฌ์ž„! ๐Ÿ› ๏ธ

// Express.js ๊ธฐ๋ณธ ์„œ๋ฒ„ ์˜ˆ์‹œ
const express = require('express');
const app = express();

// GET ์š”์ฒญ ์ฒ˜๋ฆฌ
app.get('/api/users', (req, res) => {
  res.json({ message: '์‚ฌ์šฉ์ž ๋ชฉ๋ก', users: [] });
});

// POST ์š”์ฒญ ์ฒ˜๋ฆฌ
app.post('/api/users', (req, res) => {
  const newUser = req.body;
  // DB์— ์ €์žฅํ•˜๋Š” ๋กœ์ง...
  res.status(201).json({ message: '์‚ฌ์šฉ์ž ์ƒ์„ฑ ์™„๋ฃŒ' });
});

app.listen(5000, () => {
  console.log('์„œ๋ฒ„ ์‹คํ–‰ ์ค‘! ํฌํŠธ: 5000 ๐Ÿš€');
});
๐Ÿ’š Express.js๊ฐ€ ์ข‹์€ ์ด์œ 
"์•ผ ์ด๊ฑฐ ์ง„์งœ ์ฝ”๋“œ ๋ช‡ ์ค„ ์•ˆ ๋˜๋Š”๋ฐ ์„œ๋ฒ„๊ฐ€ ๋งŒ๋“ค์–ด์ง€๋„ค?? ๐Ÿ˜ฎ"
๋งž์•„! Express๋Š” ๋ฏธ๋‹ˆ๋ฉ€ํ•˜๊ณ  ์œ ์—ฐํ•ด์„œ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ๊ณจ๋ผ์„œ ์“ธ ์ˆ˜ ์žˆ์–ด.
๋ฏธ๋“ค์›จ์–ด(Middleware) ์‹œ์Šคํ…œ ๋•๋ถ„์— ์ธ์ฆ, ๋กœ๊น…, ์—๋Ÿฌ์ฒ˜๋ฆฌ ๋“ฑ์„
๋ ˆ๊ณ  ๋ธ”๋ก์ฒ˜๋Ÿผ ์กฐ๋ฆฝํ•ด์„œ ์“ธ ์ˆ˜ ์žˆ๊ฑฐ๋“  ๐Ÿงฑ
๐Ÿ“Œ Express.js ์ฃผ์š” ๊ธฐ๋Šฅ

โœ… ๋ผ์šฐํŒ…(Routing): URL ๊ฒฝ๋กœ๋ณ„๋กœ ๋‹ค๋ฅธ ์ฒ˜๋ฆฌ ๋กœ์ง ์—ฐ๊ฒฐ
โœ… ๋ฏธ๋“ค์›จ์–ด(Middleware): ์š”์ฒญ-์‘๋‹ต ์‚ฌ์ด์— ๋ผ์–ด๋“œ๋Š” ํ•จ์ˆ˜๋“ค
โœ… REST API ๊ตฌ์ถ•: GET, POST, PUT, DELETE ๋“ฑ HTTP ๋ฉ”์„œ๋“œ ์ฒ˜๋ฆฌ
โœ… ์ •์  ํŒŒ์ผ ์„œ๋น™: HTML, CSS, ์ด๋ฏธ์ง€ ํŒŒ์ผ ์ œ๊ณต
โœ… ํ…œํ”Œ๋ฆฟ ์—”์ง„ ์ง€์›: EJS, Pug ๋“ฑ๊ณผ ์—ฐ๋™ ๊ฐ€๋Šฅ

โš›๏ธ R - React (๋ฆฌ์•กํŠธ)

React๋Š” Facebook(ํ˜„ Meta)์ด ๋งŒ๋“  ํ”„๋ก ํŠธ์—”๋“œ UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์•ผ.
2013๋…„์— ์˜คํ”ˆ์†Œ์Šค๋กœ ๊ณต๊ฐœ๋œ ์ดํ›„ ํ˜„์žฌ๊นŒ์ง€ ์ „ ์„ธ๊ณ„์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ์ด๋Š”
ํ”„๋ก ํŠธ์—”๋“œ ๊ธฐ์ˆ  ์ค‘ ํ•˜๋‚˜๋กœ ์ž๋ฆฌ์žก์•˜์–ด! ๐Ÿ“Š

2024๋…„ Stack Overflow ๊ฐœ๋ฐœ์ž ์„ค๋ฌธ์กฐ์‚ฌ ๊ธฐ์ค€์œผ๋กœ
React๋Š” ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ์›น ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ 1์œ„๋ฅผ ์ฐจ์ง€ํ–ˆ์–ด.

โš›๏ธ React์˜ ํ•ต์‹ฌ ๊ฐœ๋…๋“ค

1
์ปดํฌ๋„ŒํŠธ(Component)
UI๋ฅผ ๋…๋ฆฝ์ ์ด๊ณ  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์กฐ๊ฐ์œผ๋กœ ๋‚˜๋ˆ„๋Š” ๊ฐœ๋….
๋ ˆ๊ณ  ๋ธ”๋ก์ฒ˜๋Ÿผ ์ž‘์€ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์กฐํ•ฉํ•ด์„œ ํฐ ํ™”๋ฉด์„ ๋งŒ๋“ค์–ด!
2
Virtual DOM
์‹ค์ œ DOM์„ ์ง์ ‘ ์กฐ์ž‘ํ•˜์ง€ ์•Š๊ณ  ๊ฐ€์ƒ์˜ DOM์„ ๋จผ์ € ์—…๋ฐ์ดํŠธํ•œ ํ›„
๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„๋งŒ ์‹ค์ œ DOM์— ๋ฐ˜์˜ํ•˜๋Š” ๋ฐฉ์‹. ์„ฑ๋Šฅ์ด ์—„์ฒญ ์ข‹์•„์ง! โšก
3
JSX (JavaScript XML)
JavaScript ์ฝ”๋“œ ์•ˆ์— HTML์ฒ˜๋Ÿผ ์ƒ๊ธด ๋ฌธ๋ฒ•์„ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ™•์žฅ ๋ฌธ๋ฒ•.
์ฒ˜์Œ์—” ์ข€ ์–ด์ƒ‰ํ•˜์ง€๋งŒ ์ต์ˆ™ํ•ด์ง€๋ฉด ์—„์ฒญ ํŽธํ•จ ใ…‹ใ…‹
4
State & Props
State๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ ๋ฐ์ดํ„ฐ, Props๋Š” ๋ถ€๋ชจ์—์„œ ์ž์‹์œผ๋กœ ์ „๋‹ฌํ•˜๋Š” ๋ฐ์ดํ„ฐ.
์ด ๋‘ ๊ฐœ๋ฅผ ์ž˜ ์ดํ•ดํ•˜๋ฉด React์˜ 80%๋Š” ์ดํ•ดํ•œ ๊ฑฐ์•ผ!
5
Hooks (ํ›…์Šค)
React 16.8๋ถ€ํ„ฐ ๋„์ž…๋œ ๊ธฐ๋Šฅ์œผ๋กœ, ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋„
์ƒํƒœ ๊ด€๋ฆฌ์™€ ์ƒ๋ช…์ฃผ๊ธฐ ๊ธฐ๋Šฅ์„ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ.
useState, useEffect, useContext ๋“ฑ์ด ๋Œ€ํ‘œ์ !
// React ์ปดํฌ๋„ŒํŠธ ์˜ˆ์‹œ (ํ•จ์ˆ˜ํ˜• + Hooks)
import React, { useState, useEffect } from 'react';

function UserCard({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // API์—์„œ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => {
        setUser(data);
        setLoading(false);
      });
  }, [userId]);

  if (loading) return <div>๋กœ๋”ฉ ์ค‘... โณ</div>;

  return (
    <div className="user-card">
      <h2>{user.์ด๋ฆ„}</h2>
      <p>{user.์ด๋ฉ”์ผ}</p>
      <p>๊ธฐ์ˆ ์Šคํƒ: {user.๊ธฐ์ˆ ์Šคํƒ.join(', ')}</p>
    </div>
  );
}

๐ŸŸข N - Node.js (๋…ธ๋“œ์ œ์ด์—์Šค)

Node.js๋Š” ๋ธŒ๋ผ์šฐ์ € ๋ฐ–์—์„œ JavaScript๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š”
JavaScript ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์ด์•ผ.

์›๋ž˜ JavaScript๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ๋งŒ ๋Œ์•„๊ฐ€๋Š” ์–ธ์–ด์˜€๋Š”๋ฐ,
2009๋…„ Ryan Dahl์ด Node.js๋ฅผ ๋งŒ๋“ค๋ฉด์„œ ์„œ๋ฒ„์—์„œ๋„ JavaScript๋ฅผ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ๋์–ด!
์ด๊ฒŒ MERN ์Šคํƒ์ด ๊ฐ€๋Šฅํ•ด์ง„ ๊ทผ๋ณธ์ ์ธ ์ด์œ ์ž„ ๐ŸŒฑ

๐Ÿ“Œ Node.js์˜ ํ•ต์‹ฌ ํŠน์ง•

โœ… ๋น„๋™๊ธฐ I/O (Non-blocking): ํŒŒ์ผ ์ฝ๊ธฐ, DB ์กฐํšŒ ๋“ฑ์„ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋‹ค์Œ ์ž‘์—… ์ฒ˜๋ฆฌ
โœ… ์ด๋ฒคํŠธ ๋ฃจํ”„(Event Loop): ๋‹จ์ผ ์Šค๋ ˆ๋“œ๋กœ ๋†’์€ ๋™์‹œ์„ฑ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
โœ… NPM (Node Package Manager): 200๋งŒ ๊ฐœ ์ด์ƒ์˜ ํŒจํ‚ค์ง€ ์ƒํƒœ๊ณ„
โœ… ๋น ๋ฅธ ์‹คํ–‰ ์†๋„: V8 ์—”์ง„ ๊ธฐ๋ฐ˜์œผ๋กœ JavaScript๋ฅผ ๊ธฐ๊ณ„์–ด๋กœ ์ปดํŒŒ์ผ
โœ… ํฌ๋กœ์Šค ํ”Œ๋žซํผ: Windows, Mac, Linux ๋ชจ๋‘ ์ง€์›
๐Ÿ’ฌ "๊ทผ๋ฐ Node.js๊ฐ€ ๋‹จ์ผ ์Šค๋ ˆ๋“œ๋ฉด ๋А๋ฆฐ ๊ฑฐ ์•„๋‹ˆ์•ผ?"

์˜คํ•ดํ•˜๊ธฐ ์‰ฌ์šด ๋ถ€๋ถ„์ธ๋ฐ! ๐Ÿค”
Node.js๋Š” CPU๋ฅผ ๋งŽ์ด ์“ฐ๋Š” ์ž‘์—…(์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ, ๋ณต์žกํ•œ ๊ณ„์‚ฐ)์—” ์•ฝํ•˜์ง€๋งŒ,
I/O ์ž‘์—…(DB ์กฐํšŒ, ํŒŒ์ผ ์ฝ๊ธฐ, API ํ˜ธ์ถœ)์ด ๋งŽ์€ ์›น ์„œ๋ฒ„์—๋Š” ์—„์ฒญ ๊ฐ•ํ•ด!
์™œ๋ƒ๋ฉด I/O ์ž‘์—…์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ .
Netflix, LinkedIn, PayPal ๊ฐ™์€ ๋Œ€ํ˜• ์„œ๋น„์Šค๋“ค๋„ Node.js ์”€ ใ…‹ใ…‹ ๐Ÿ’ช

๐Ÿ…ฐ๏ธ 3. MEAN ์Šคํƒ - Angular๋ฅผ ํ’ˆ์€ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ๊ฐ•์ž

MERN ์Šคํƒ์„ ์•Œ์•˜์œผ๋ฉด ์ด์ œ MEAN ์Šคํƒ๋„ ์•Œ์•„์•ผ์ง€!
MEAN์€ MongoDB + Express.js + Angular + Node.js์˜ ์กฐํ•ฉ์ด์•ผ.
MERN์—์„œ React ๋Œ€์‹  Angular๊ฐ€ ๋“ค์–ด๊ฐ„ ๋ฒ„์ „์ด๋ผ๊ณ  ๋ณด๋ฉด ๋ผ! ๐Ÿ”„

MERN vs MEAN ์Šคํƒ ๋น„๊ต MERN ์Šคํƒ M - MongoDB E - Express.js R - React โš›๏ธ N - Node.js ๐ŸŸข VS MEAN ์Šคํƒ M - MongoDB E - Express.js A - Angular ๐Ÿ…ฐ๏ธ N - Node.js ๐ŸŸข

๐Ÿ…ฐ๏ธ Angular๋ž€?

Angular๋Š” Google์ด ๋งŒ๋“  TypeScript ๊ธฐ๋ฐ˜์˜ ํ”„๋ก ํŠธ์—”๋“œ ํ”„๋ ˆ์ž„์›Œํฌ์•ผ.
React๊ฐ€ "๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ"๋ผ๋ฉด, Angular๋Š” ์™„์ „ํ•œ "ํ”„๋ ˆ์ž„์›Œํฌ"์ž„.

์ด ์ฐจ์ด๊ฐ€ ์—„์ฒญ ์ค‘์š”ํ•œ๋ฐ, React๋Š” UI๋งŒ ๋‹ด๋‹นํ•˜๊ณ  ๋‚˜๋จธ์ง€(๋ผ์šฐํŒ…, ์ƒํƒœ๊ด€๋ฆฌ ๋“ฑ)๋Š”
๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ณจ๋ผ์„œ ์กฐํ•ฉํ•ด์•ผ ํ•ด.
๋ฐ˜๋ฉด Angular๋Š” ๋ชจ๋“  ๊ฒŒ ๋‹ค ๋‚ด์žฅ๋˜์–ด ์žˆ์–ด! ๐Ÿ—๏ธ

ํŠน์ง• React Angular
ํƒ€์ž… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์™„์ „ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ
์–ธ์–ด JavaScript (JSX) TypeScript (ํ•„์ˆ˜)
ํ•™์Šต ๊ณก์„  ์ƒ๋Œ€์ ์œผ๋กœ ์™„๋งŒ ๊ฐ€ํŒŒ๋ฆ„ (์ดˆ๊ธฐ ์ง„์ž…์žฅ๋ฒฝ ๋†’์Œ)
๋ฒˆ๋“ค ํฌ๊ธฐ ๊ฐ€๋ฒผ์›€ ๋ฌด๊ฑฐ์›€
์ฃผ์š” ์‚ฌ์šฉ์ฒ˜ ์Šคํƒ€ํŠธ์—…, ๋‹ค์–‘ํ•œ ๊ทœ๋ชจ ๋Œ€๊ธฐ์—…, ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ
๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ๋‹จ๋ฐฉํ–ฅ ์–‘๋ฐฉํ–ฅ (Two-way)
๐Ÿ’š Angular์˜ ๊ฐ•์ ์€ ๋ญ์•ผ?

Angular๋Š” ํŠนํžˆ ๋Œ€๊ทœ๋ชจ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ํ”„๋กœ์ ํŠธ์—์„œ ๋น›์„ ๋ฐœํ•ด!
TypeScript๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์“ฐ๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ž… ์•ˆ์ •์„ฑ์ด ๋†’๊ณ ,
ํŒ€ ๊ทœ๋ชจ๊ฐ€ ์ปค๋„ ์ฝ”๋“œ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์‰ฌ์›Œ.
Google, Microsoft, IBM ๊ฐ™์€ ๋Œ€๊ธฐ์—…๋“ค์ด Angular๋ฅผ ๋งŽ์ด ์“ฐ๋Š” ์ด์œ ๊ฐ€ ๋ฐ”๋กœ ์ด๊ฑฐ์•ผ ๐Ÿข
๐Ÿ“Œ Angular์˜ ํ•ต์‹ฌ ๊ฐœ๋…

โœ… ์ปดํฌ๋„ŒํŠธ(Component): UI์˜ ๊ธฐ๋ณธ ๊ตฌ์„ฑ ๋‹จ์œ„
โœ… ๋ชจ๋“ˆ(Module): ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ, ์„œ๋น„์Šค ๋“ฑ์„ ๋ฌถ๋Š” ๋‹จ์œ„
โœ… ์„œ๋น„์Šค(Service): ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋‹ด๋‹นํ•˜๋Š” ํด๋ž˜์Šค
โœ… ์˜์กด์„ฑ ์ฃผ์ž…(DI): ํ•„์š”ํ•œ ์„œ๋น„์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ฃผ์ž…ํ•˜๋Š” ํŒจํ„ด
โœ… RxJS: ๋ฐ˜์‘ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (Angular์™€ ์ฐฐ๋–ก)
โœ… Angular CLI: ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ, ๋นŒ๋“œ, ํ…Œ์ŠคํŠธ๋ฅผ ์ž๋™ํ™”ํ•˜๋Š” ๋„๊ตฌ
// Angular ์ปดํฌ๋„ŒํŠธ ์˜ˆ์‹œ (TypeScript)
import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-user-list',
  template: `
    <div *ngIf="loading">๋กœ๋”ฉ ์ค‘... โณ</div>
    <div *ngFor="let user of users" class="user-card">
      <h3>{{ user.์ด๋ฆ„ }}</h3>
      <p>{{ user.์ด๋ฉ”์ผ }}</p>
    </div>
  `
})
export class UserListComponent implements OnInit {
  users: any[] = [];
  loading = true;

  constructor(private userService: UserService) {}

  ngOnInit(): void {
    this.userService.getUsers().subscribe(data => {
      this.users = data;
      this.loading = false;
    });
  }
}

๐Ÿ› ๏ธ 4. MERN ์Šคํƒ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ธํŒ… - ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€

์ด๋ก ๋งŒ ์•Œ๋ฉด ๋ญํ•ด, ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์„ธํŒ…ํ•˜๋Š”์ง€ ์•Œ์•„์•ผ์ง€! ๐Ÿ”ง
MERN ์Šคํƒ์œผ๋กœ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•˜๋Š” ์ „์ฒด ํ๋ฆ„์„ ์‚ดํŽด๋ณด์ž.

๐Ÿ› ๏ธ MERN ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๊ตฌ์ถ• ํ๋ฆ„ 1๏ธโƒฃ Node.js ์„ค์น˜ nodejs.org โ†’ 2๏ธโƒฃ ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐํ™” npm init โ†’ 3๏ธโƒฃ ๋ฐฑ์—”๋“œ ๊ตฌ์ถ• Express + MongoDB โ†’ 4๏ธโƒฃ ํ”„๋ก ํŠธ์—”๋“œ ๊ตฌ์ถ• Create React App / Vite 5๏ธโƒฃ API ์—ฐ๋™ Axios / Fetch โ†’ 6๏ธโƒฃ ์ƒํƒœ ๊ด€๋ฆฌ Redux / Context API โ†’ 7๏ธโƒฃ ์ธ์ฆ ๊ตฌํ˜„ JWT / Session โ†’ 8๏ธโƒฃ ๋ฐฐํฌ Vercel / Heroku / AWS ์ด ํ๋ฆ„์„ ๋”ฐ๋ผ๊ฐ€๋ฉด ํ’€์Šคํƒ ์•ฑ ์™„์„ฑ! ๐ŸŽ‰ ์ฒ˜์Œ์—” ๋ณต์žกํ•ด ๋ณด์—ฌ๋„ ํ•˜๋‚˜์”ฉ ํ•˜๋ฉด ๋จ ใ…‹ใ…‹ ๐Ÿ’ช

๐Ÿ“ฆ ํ•„์ˆ˜ ํŒจํ‚ค์ง€ ์„ค์น˜

๋ฐฑ์—”๋“œ (์„œ๋ฒ„ ํด๋”)

# ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐํ™”
npm init -y

# ํ•ต์‹ฌ ํŒจํ‚ค์ง€ ์„ค์น˜
npm install express mongoose dotenv cors bcryptjs jsonwebtoken

# ๊ฐœ๋ฐœ์šฉ ํŒจํ‚ค์ง€
npm install --save-dev nodemon

ํ”„๋ก ํŠธ์—”๋“œ (ํด๋ผ์ด์–ธํŠธ ํด๋”)

# Vite๋กœ React ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ (์š”์ฆ˜ ํŠธ๋ Œ๋“œ!)
npm create vite@latest client -- --template react

# ๋˜๋Š” Create React App (์ „ํ†ต์ ์ธ ๋ฐฉ๋ฒ•)
npx create-react-app client

# ์ถ”๊ฐ€ ํŒจํ‚ค์ง€
npm install axios react-router-dom @reduxjs/toolkit react-redux

๐Ÿ“ MERN ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ

my-mern-app/
โ”œโ”€โ”€ ๐Ÿ“ server/          (๋ฐฑ์—”๋“œ)
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ models/      (MongoDB ์Šคํ‚ค๋งˆ)
โ”‚   โ”‚   โ””โ”€โ”€ User.js
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ routes/      (API ๋ผ์šฐํŠธ)
โ”‚   โ”‚   โ””โ”€โ”€ userRoutes.js
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ controllers/ (๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง)
โ”‚   โ”‚   โ””โ”€โ”€ userController.js
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ middleware/  (๋ฏธ๋“ค์›จ์–ด)
โ”‚   โ”‚   โ””โ”€โ”€ auth.js
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ config/      (์„ค์ • ํŒŒ์ผ)
โ”‚   โ”‚   โ””โ”€โ”€ db.js
โ”‚   โ”œโ”€โ”€ .env            (ํ™˜๊ฒฝ๋ณ€์ˆ˜)
โ”‚   โ””โ”€โ”€ server.js       (์ง„์ž…์ )
โ”‚
โ””โ”€โ”€ ๐Ÿ“ client/          (ํ”„๋ก ํŠธ์—”๋“œ)
    โ”œโ”€โ”€ ๐Ÿ“ src/
    โ”‚   โ”œโ”€โ”€ ๐Ÿ“ components/
    โ”‚   โ”œโ”€โ”€ ๐Ÿ“ pages/
    โ”‚   โ”œโ”€โ”€ ๐Ÿ“ hooks/
    โ”‚   โ”œโ”€โ”€ ๐Ÿ“ store/   (Redux)
    โ”‚   โ””โ”€โ”€ App.jsx
    โ””โ”€โ”€ package.json

๐Ÿ—๏ธ 5. MERN ์Šคํƒ ์‹ค์ „ ๊ฐœ๋ฐœ ํŒจํ„ด

ํ™˜๊ฒฝ ์„ธํŒ…์€ ํ–ˆ๋Š”๋ฐ, ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๊ฐœ๋ฐœํ•˜๋Š”์ง€ ํ•ต์‹ฌ ํŒจํ„ด๋“ค์„ ์•Œ์•„๋ณด์ž! ๐ŸŽฏ

๐Ÿ”— REST API ์„ค๊ณ„ ํŒจํ„ด

MERN ์Šคํƒ์—์„œ ํ”„๋ก ํŠธ์—”๋“œ(React)์™€ ๋ฐฑ์—”๋“œ(Express)๋Š”
REST API๋ฅผ ํ†ตํ•ด ํ†ต์‹ ํ•ด.
API ์„ค๊ณ„๋ฅผ ์ž˜ ํ•ด์•ผ ๋‚˜์ค‘์— ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ํŽธํ•ด์ง!

HTTP ๋ฉ”์„œ๋“œ URL ์˜ˆ์‹œ ๋™์ž‘
GET /api/users ์ „์ฒด ์‚ฌ์šฉ์ž ๋ชฉ๋ก ์กฐํšŒ
GET /api/users/:id ํŠน์ • ์‚ฌ์šฉ์ž ์กฐํšŒ
POST /api/users ์ƒˆ ์‚ฌ์šฉ์ž ์ƒ์„ฑ
PUT /api/users/:id ์‚ฌ์šฉ์ž ์ •๋ณด ์ „์ฒด ์ˆ˜์ •
PATCH /api/users/:id ์‚ฌ์šฉ์ž ์ •๋ณด ์ผ๋ถ€ ์ˆ˜์ •
DELETE /api/users/:id ์‚ฌ์šฉ์ž ์‚ญ์ œ

๐Ÿƒ Mongoose ์Šคํ‚ค๋งˆ & ๋ชจ๋ธ

// server/models/User.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
  ์ด๋ฆ„: {
    type: String,
    required: [true, '์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค'],
    trim: true,
    maxlength: [50, '์ด๋ฆ„์€ 50์ž ์ดํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค']
  },
  ์ด๋ฉ”์ผ: {
    type: String,
    required: true,
    unique: true,
    lowercase: true,
    match: [/^\S+@\S+\.\S+$/, '์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ ํ˜•์‹์ด ์•„๋‹™๋‹ˆ๋‹ค']
  },
  ๋น„๋ฐ€๋ฒˆํ˜ธ: {
    type: String,
    required: true,
    minlength: 8,
    select: false  // ์กฐํšŒ ์‹œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ์™ธ
  },
  ์—ญํ• : {
    type: String,
    enum: ['user', 'admin'],
    default: 'user'
  },
  ์ƒ์„ฑ์ผ: {
    type: Date,
    default: Date.now
  }
});

// ์ €์žฅ ์ „ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹ฑ
userSchema.pre('save', async function(next) {
  if (!this.isModified('๋น„๋ฐ€๋ฒˆํ˜ธ')) return next();
  this.๋น„๋ฐ€๋ฒˆํ˜ธ = await bcrypt.hash(this.๋น„๋ฐ€๋ฒˆํ˜ธ, 12);
  next();
});

module.exports = mongoose.model('User', userSchema);

๐Ÿ” JWT ์ธ์ฆ ๊ตฌํ˜„

MERN ์Šคํƒ์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ์ด๋Š” ์ธ์ฆ ๋ฐฉ์‹์€ JWT(JSON Web Token)์•ผ.
๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ ์„œ๋ฒ„๊ฐ€ ํ† ํฐ์„ ๋ฐœ๊ธ‰ํ•˜๊ณ , ํด๋ผ์ด์–ธํŠธ๋Š” ์ด ํ† ํฐ์„
์ดํ›„ ์š”์ฒญ๋งˆ๋‹ค ํ—ค๋”์— ๋‹ด์•„์„œ ๋ณด๋‚ด๋Š” ๋ฐฉ์‹์ด์•ผ!

// JWT ํ† ํฐ ์ƒ์„ฑ (๋กœ๊ทธ์ธ ์‹œ)
const jwt = require('jsonwebtoken');

const generateToken = (userId) => {
  return jwt.sign(
    { id: userId },
    process.env.JWT_SECRET,
    { expiresIn: '7d' }  // 7์ผ ํ›„ ๋งŒ๋ฃŒ
  );
};

// JWT ๊ฒ€์ฆ ๋ฏธ๋“ค์›จ์–ด
const protect = async (req, res, next) => {
  let token;
  
  if (req.headers.authorization?.startsWith('Bearer')) {
    token = req.headers.authorization.split(' ')[1];
  }
  
  if (!token) {
    return res.status(401).json({ message: '๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค' });
  }
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = await User.findById(decoded.id);
    next();
  } catch (err) {
    res.status(401).json({ message: '์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค' });
  }
};
๐Ÿ’ฌ "React์—์„œ API ํ˜ธ์ถœ์€ ์–ด๋–ป๊ฒŒ ํ•ด?"

Axios๋‚˜ ๊ธฐ๋ณธ Fetch API๋ฅผ ์“ฐ๋ฉด ๋ผ!
์š”์ฆ˜์€ React Query(TanStack Query)๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ์—„์ฒญ ํ•ซํ•จ ๐Ÿ”ฅ
์„œ๋ฒ„ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์—„์ฒญ ํŽธํ•˜๊ฒŒ ํ•ด์ค˜์„œ ์š”์ฆ˜ MERN ํ”„๋กœ์ ํŠธ์—์„œ ๋งŽ์ด ์”€!
// React์—์„œ Axios๋กœ API ํ˜ธ์ถœ
import axios from 'axios';

// Axios ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
const api = axios.create({
  baseURL: 'http://localhost:5000/api',
  headers: {
    'Content-Type': 'application/json'
  }
});

// ์š”์ฒญ ์ธํ„ฐ์…‰ํ„ฐ (ํ† ํฐ ์ž๋™ ์ฒจ๋ถ€)
api.interceptors.request.use((config) => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// ์‚ฌ์šฉ ์˜ˆ์‹œ
const fetchUsers = async () => {
  try {
    const { data } = await api.get('/users');
    return data;
  } catch (error) {
    console.error('์‚ฌ์šฉ์ž ์กฐํšŒ ์‹คํŒจ:', error.message);
  }
};

๐Ÿ”ง 6. ํ˜„๋Œ€์  ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ์™„์„ฑํ•˜๋Š” ๋„๊ตฌ๋“ค

MERN/MEAN ์Šคํƒ์„ ์“ด๋‹ค๊ณ  ๋์ด ์•„๋‹ˆ์•ผ!
ํ˜„๋Œ€์ ์ธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๋งŒ๋“ค๋ ค๋ฉด ์ด๋Ÿฐ ๋„๊ตฌ๋“ค๋„ ์•Œ์•„์•ผ ํ•ด ๐Ÿ‘‡

ํ˜„๋Œ€ ํ’€์Šคํƒ ๊ฐœ๋ฐœ ์ƒํƒœ๊ณ„ ๐ŸŒฟ MERN/MEAN ํ’€์Šคํƒ ์Šคํƒ ๐Ÿ™ Git/GitHub ๐Ÿณ Docker ๐Ÿ“˜ TypeScript โš™๏ธ CI/CD ๐Ÿงช ํ…Œ์ŠคํŒ… โ˜๏ธ ํด๋ผ์šฐ๋“œ ๋ฐฐํฌ ์ด ๋ชจ๋“  ๋„๊ตฌ๋“ค์ด ํ˜„๋Œ€ ํ’€์Šคํƒ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•ด! ๐Ÿš€

๐Ÿ“˜ TypeScript - ์ด์ œ ์„ ํƒ์ด ์•„๋‹Œ ํ•„์ˆ˜

์š”์ฆ˜ MERN/MEAN ํ”„๋กœ์ ํŠธ์—์„œ TypeScript๋Š” ๊ฑฐ์˜ ํ‘œ์ค€์ด ๋์–ด.
JavaScript์— ์ •์  ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•œ ์–ธ์–ด์ธ๋ฐ, ์ฒ˜์Œ์—” ๊ท€์ฐฎ์•„ ๋ณด์—ฌ๋„
ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๊ทธ ์ง„๊ฐ€๋ฅผ ๋ฐœํœ˜ํ•จ! ๐ŸŽฏ

๐Ÿ“Œ TypeScript๋ฅผ ์จ์•ผ ํ•˜๋Š” ์ด์œ 

โœ… ์ปดํŒŒ์ผ ํƒ€์ž„ ์—๋Ÿฌ ๊ฐ์ง€: ์‹คํ–‰ ์ „์— ํƒ€์ž… ์˜ค๋ฅ˜๋ฅผ ์žก์•„์คŒ
โœ… IDE ์ž๋™์™„์„ฑ: VS Code์—์„œ ์—„์ฒญ๋‚œ ์ž๋™์™„์„ฑ ์ง€์›
โœ… ๋ฆฌํŒฉํ† ๋ง ์•ˆ์ „์„ฑ: ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‹œ ์˜ํ–ฅ ๋ฒ”์œ„๋ฅผ ์‰ฝ๊ฒŒ ํŒŒ์•…
โœ… ํŒ€ ํ˜‘์—… ํ–ฅ์ƒ: ํƒ€์ž…์ด ๋ฌธ์„œ ์—ญํ• ์„ ํ•ด์„œ ์ฝ”๋“œ ์ดํ•ด๊ฐ€ ์‰ฌ์›Œ์ง
โœ… ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ ํ•„์ˆ˜: ์ฝ”๋“œ๋ฒ ์ด์Šค๊ฐ€ ์ปค์งˆ์ˆ˜๋ก TypeScript์˜ ๊ฐ€์น˜ ์ฆ๊ฐ€

๐Ÿณ Docker - ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ํ†ต์ผ์˜ ๊ตฌ์„ธ์ฃผ

"๋‚ด ์ปดํ“จํ„ฐ์—์„œ๋Š” ๋˜๋Š”๋ฐ ์™œ ์„œ๋ฒ„์—์„œ ์•ˆ ๋ผ?" ๐Ÿคฆ
์ด ๊ณ ํ†ต์„ ํ•ด๊ฒฐํ•ด์ฃผ๋Š” ๊ฒŒ ๋ฐ”๋กœ Docker์•ผ!

Docker๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๊ทธ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ์ปจํ…Œ์ด๋„ˆ๋ผ๋Š” ๋‹จ์œ„๋กœ ํŒจํ‚ค์ง•ํ•ด์„œ
์–ด๋””์„œ๋“  ๋™์ผํ•˜๊ฒŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜.

# docker-compose.yml (MERN ์Šคํƒ ์˜ˆ์‹œ)
version: '3.8'
services:
  # MongoDB
  mongodb:
    image: mongo:6.0
    ports:
      - "27017:27017"
    volumes:
      - mongo-data:/data/db
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: password

  # Express ์„œ๋ฒ„
  server:
    build: ./server
    ports:
      - "5000:5000"
    depends_on:
      - mongodb
    environment:
      MONGODB_URI: mongodb://admin:password@mongodb:27017/myapp

  # React ํด๋ผ์ด์–ธํŠธ
  client:
    build: ./client
    ports:
      - "3000:3000"
    depends_on:
      - server

volumes:
  mongo-data:
๐Ÿ’š Docker Compose ์“ฐ๋ฉด ๋ญ๊ฐ€ ์ข‹์•„?
๋ช…๋ น์–ด ํ•˜๋‚˜๋กœ MongoDB + Express + React ์ „๋ถ€ ์‹คํ–‰!
docker-compose up ์ด๊ฑฐ ํ•˜๋‚˜๋ฉด ๋ ใ…‹ใ…‹ใ…‹ ๐ŸŽ‰
ํŒ€์›๋“ค๋„ ๊ฐ™์€ ํ™˜๊ฒฝ์—์„œ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์–ด์„œ "๋‚ด ์ปด์—์„œ๋งŒ ๋จ" ๋ฌธ์ œ ํ•ด๊ฒฐ!

๐Ÿงช ํ…Œ์ŠคํŒ… - ์•ˆ ํ•˜๋ฉด ๋‚˜์ค‘์— ํ›„ํšŒํ•จ

๊ฐœ๋ฐœํ•˜๋‹ค ๋ณด๋ฉด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ์ด ๊ท€์ฐฎ๊ฒŒ ๋А๊ปด์ง€๋Š”๋ฐ,
๋‚˜์ค‘์— ๊ธฐ๋Šฅ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ฆฌํŒฉํ† ๋งํ•  ๋•Œ ํ…Œ์ŠคํŠธ๊ฐ€ ์—†์œผ๋ฉด ์ง„์งœ ์ง€์˜ฅ์ž„ ใ…‹ใ…‹ ๐Ÿ˜…

ํ…Œ์ŠคํŠธ ์ข…๋ฅ˜ ๋„๊ตฌ ์„ค๋ช…
๋‹จ์œ„ ํ…Œ์ŠคํŠธ Jest, Vitest ํ•จ์ˆ˜/์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ Supertest API ์—”๋“œํฌ์ธํŠธ ํ…Œ์ŠคํŠธ
E2E ํ…Œ์ŠคํŠธ Cypress, Playwright ์‹ค์ œ ๋ธŒ๋ผ์šฐ์ € ์‹œ๋‚˜๋ฆฌ์˜ค ํ…Œ์ŠคํŠธ
์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ React Testing Library React ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ํ…Œ์ŠคํŠธ

โ˜๏ธ 7. MERN/MEAN ์•ฑ ๋ฐฐํฌ ์ „๋žต

๊ฐœ๋ฐœ์„ ๋‹ค ํ–ˆ์œผ๋ฉด ์ด์ œ ์„ธ์ƒ์— ๊ณต๊ฐœํ•ด์•ผ์ง€! ๐ŸŒ
MERN/MEAN ์•ฑ์„ ๋ฐฐํฌํ•˜๋Š” ์ฃผ์š” ๋ฐฉ๋ฒ•๋“ค์„ ์•Œ์•„๋ณด์ž.

๐Ÿš€ ์ฃผ์š” ๋ฐฐํฌ ํ”Œ๋žซํผ ๋น„๊ต

ํ”Œ๋žซํผ ํŠน์ง• ์ถ”์ฒœ ์šฉ๋„ ๊ฐ€๊ฒฉ
Vercel Next.js ์ตœ์ ํ™”, ์ž๋™ ๋ฐฐํฌ ํ”„๋ก ํŠธ์—”๋“œ, Next.js ์•ฑ ๋ฌด๋ฃŒ ํ”Œ๋žœ ์žˆ์Œ
Railway ๊ฐ„ํŽธํ•œ ํ’€์Šคํƒ ๋ฐฐํฌ Express + MongoDB ๋ฌด๋ฃŒ ํ”Œ๋žœ ์žˆ์Œ
Render Heroku ๋Œ€์•ˆ, ๋ฌด๋ฃŒ ํ”Œ๋žœ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ๋ฌด๋ฃŒ ํ”Œ๋žœ ์žˆ์Œ
AWS ์ตœ๊ณ ์˜ ํ™•์žฅ์„ฑ ๋Œ€๊ทœ๋ชจ ํ”„๋กœ๋•์…˜ ์‚ฌ์šฉ๋Ÿ‰ ๊ธฐ๋ฐ˜
MongoDB Atlas MongoDB ๊ณต์‹ ํด๋ผ์šฐ๋“œ MongoDB ํ˜ธ์ŠคํŒ… ๋ฌด๋ฃŒ 512MB
๐Ÿ“Œ ์ดˆ๋ณด์ž ์ถ”์ฒœ ๋ฐฐํฌ ์กฐํ•ฉ

๐Ÿƒ DB: MongoDB Atlas (๋ฌด๋ฃŒ 512MB)
๐Ÿš‚ ๋ฐฑ์—”๋“œ: Render ๋˜๋Š” Railway (๋ฌด๋ฃŒ ํ”Œ๋žœ)
โš›๏ธ ํ”„๋ก ํŠธ์—”๋“œ: Vercel (๋ฌด๋ฃŒ, ์ž๋™ ๋ฐฐํฌ)

์ด ์กฐํ•ฉ์ด๋ฉด ์™„์ „ ๋ฌด๋ฃŒ๋กœ MERN ์•ฑ์„ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽ‰

๐Ÿ”„ CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•

์ฝ”๋“œ๋ฅผ pushํ•˜๋ฉด ์ž๋™์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜๊ณ  ๋ฐฐํฌ๊นŒ์ง€ ํ•ด์ฃผ๋Š”
CI/CD(์ง€์†์  ํ†ตํ•ฉ/์ง€์†์  ๋ฐฐํฌ) ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์ถ•ํ•˜๋ฉด
๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์ด ์—„์ฒญ ์˜ฌ๋ผ๊ฐ€!

# .github/workflows/deploy.yml (GitHub Actions ์˜ˆ์‹œ)
name: MERN ์•ฑ CI/CD

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Node.js ์„ค์ •
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      
      - name: ๋ฐฑ์—”๋“œ ํ…Œ์ŠคํŠธ
        run: |
          cd server
          npm install
          npm test
      
      - name: ํ”„๋ก ํŠธ์—”๋“œ ๋นŒ๋“œ
        run: |
          cd client
          npm install
          npm run build
  
  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Vercel ๋ฐฐํฌ
        run: npx vercel --prod --token=${{ secrets.VERCEL_TOKEN }}

๐ŸŒŸ 8. Next.js - MERN์˜ ์ง„ํ™”ํ˜•

์š”์ฆ˜ ํ’€์Šคํƒ ๊ฐœ๋ฐœ ํŠธ๋ Œ๋“œ๋ฅผ ์–˜๊ธฐํ•  ๋•Œ Next.js๋ฅผ ๋นผ๋†“์„ ์ˆ˜ ์—†์–ด!
React ๊ธฐ๋ฐ˜์˜ ํ’€์Šคํƒ ํ”„๋ ˆ์ž„์›Œํฌ์ธ๋ฐ, ์ด๊ฒŒ ์–ผ๋งˆ๋‚˜ ํ•ซํ•˜๋ƒ๋ฉด... ๐Ÿ”ฅ

๐Ÿ’ฌ "Next.js๊ฐ€ ๋ญ”๋ฐ ๋‹ค๋“ค ๋‚œ๋ฆฌ์•ผ?"

Next.js๋Š” React์— ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(SSR), ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ(SSG),
API Routes ๋“ฑ์„ ์ถ”๊ฐ€ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์•ผ.
์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด React + Express๋ฅผ ํ•˜๋‚˜๋กœ ํ•ฉ์นœ ๊ฒƒ ๊ฐ™์€ ๋А๋‚Œ! ๐Ÿคฉ

ํŠนํžˆ App Router(Next.js 13+)๊ฐ€ ๋‚˜์˜ค๋ฉด์„œ
์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ, ์ŠคํŠธ๋ฆฌ๋ฐ, ์„œ๋ฒ„ ์•ก์…˜ ๋“ฑ ํ˜์‹ ์ ์ธ ๊ธฐ๋Šฅ๋“ค์ด ์ถ”๊ฐ€๋์–ด.

โšก Next.js vs ๊ธฐ์กด MERN ๋น„๊ต

ํ•ญ๋ชฉ ๊ธฐ์กด MERN Next.js + MongoDB
๋ Œ๋”๋ง CSR (ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ) SSR, SSG, ISR, CSR ๋ชจ๋‘ ์ง€์›
SEO ์•ฝํ•จ (SPA ํ•œ๊ณ„) ๊ฐ•ํ•จ (์„œ๋ฒ„์—์„œ HTML ์ƒ์„ฑ)
API ์„œ๋ฒ„ ๋ณ„๋„ Express ์„œ๋ฒ„ ํ•„์š” API Routes๋กœ ๋‚ด์žฅ ์ฒ˜๋ฆฌ
๋ฐฐํฌ ๋ณต์žก๋„ ํ”„๋ก ํŠธ/๋ฐฑ์—”๋“œ ๋”ฐ๋กœ ๋ฐฐํฌ Vercel์— ํ•œ ๋ฒˆ์— ๋ฐฐํฌ
์ดˆ๊ธฐ ๋กœ๋”ฉ ๋А๋ฆผ (JS ๋ฒˆ๋“ค ๋กœ๋“œ ํ›„ ๋ Œ๋”) ๋น ๋ฆ„ (์„œ๋ฒ„์—์„œ HTML ์ „์†ก)
๐Ÿ“Œ 2024-2025 ํ’€์Šคํƒ ํŠธ๋ Œ๋“œ ์Šคํƒ

๐Ÿ”ฅ T3 Stack: Next.js + TypeScript + Tailwind CSS + tRPC + Prisma
๐Ÿ”ฅ MERN + Next.js: MongoDB + Express(API) + React(Next.js) + Node.js
๐Ÿ”ฅ Serverless: Vercel Functions + MongoDB Atlas + Next.js
๐Ÿ”ฅ BaaS ํ™œ์šฉ: Supabase/Firebase + Next.js (๋ฐฑ์—”๋“œ ์—†์ด ํ’€์Šคํƒ)

๐Ÿ’ก 9. MERN/MEAN ์‹ค๋ฌด ๊ฐœ๋ฐœ ๊ฟ€ํŒ

์ด๋ก ์€ ์ถฉ๋ถ„ํžˆ ์•Œ์•˜์œผ๋‹ˆ, ์‹ค์ œ ๊ฐœ๋ฐœํ•  ๋•Œ ๋„์›€ ๋˜๋Š” ๊ฟ€ํŒ๋“ค์„ ๋ชจ์•„๋ดค์–ด! ๐Ÿฏ

๐Ÿ” ๋ณด์•ˆ ํ•„์ˆ˜ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

1
ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ด€๋ฆฌ
DB ๋น„๋ฐ€๋ฒˆํ˜ธ, JWT ์‹œํฌ๋ฆฟ ๋“ฑ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋Š” ์ ˆ๋Œ€ ์ฝ”๋“œ์— ์ง์ ‘ ์“ฐ์ง€ ๋ง๊ณ 
.env ํŒŒ์ผ์— ์ €์žฅํ•˜๊ณ  .gitignore์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•ด!
2
์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ (Validation)
ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ฒ€์ฆํ•ด๋„ ์„œ๋ฒ„์—์„œ๋„ ๋ฐ˜๋“œ์‹œ ๊ฒ€์ฆํ•ด์•ผ ํ•ด.
Joi๋‚˜ express-validator ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ™œ์šฉ ์ถ”์ฒœ!
3
Rate Limiting
express-rate-limit์œผ๋กœ API ์š”์ฒญ ํšŸ์ˆ˜๋ฅผ ์ œํ•œํ•ด์„œ
DDoS ๊ณต๊ฒฉ์ด๋‚˜ ๋ธŒ๋ฃจํŠธํฌ์Šค ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•ด์•ผ ํ•ด!
4
CORS ์„ค์ •
ํ—ˆ์šฉ๋œ ๋„๋ฉ”์ธ์—์„œ๋งŒ API๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก
CORS ์„ค์ •์„ ๊ผผ๊ผผํžˆ ํ•ด์•ผ ํ•ด. ์™€์ผ๋“œ์นด๋“œ(*) ์‚ฌ์šฉ์€ ํ”„๋กœ๋•์…˜์—์„œ ๊ธˆ์ง€!
5
Helmet.js
Express ์•ฑ์— ๋ณด์•ˆ ๊ด€๋ จ HTTP ํ—ค๋”๋ฅผ ์ž๋™์œผ๋กœ ์„ค์ •ํ•ด์ฃผ๋Š” ๋ฏธ๋“ค์›จ์–ด.
npm install helmet ํ•˜๊ณ  app.use(helmet()) ํ•œ ์ค„์ด๋ฉด ๋!

โšก ์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ

๐Ÿ“Œ MongoDB ์„ฑ๋Šฅ ์ตœ์ ํ™”

โœ… ์ธ๋ฑ์Šค(Index) ์„ค์ •: ์ž์ฃผ ์กฐํšŒํ•˜๋Š” ํ•„๋“œ์— ์ธ๋ฑ์Šค ์ถ”๊ฐ€
โœ… Projection ์‚ฌ์šฉ: ํ•„์š”ํ•œ ํ•„๋“œ๋งŒ ์กฐํšŒ (์ „์ฒด ๋ฌธ์„œ X)
โœ… Pagination: ํ•œ ๋ฒˆ์— ๋ชจ๋“  ๋ฐ์ดํ„ฐ ์กฐํšŒ ๊ธˆ์ง€, ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ตฌํ˜„
โœ… Aggregation Pipeline: ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋Š” DB์—์„œ ์ฒ˜๋ฆฌ
๐Ÿ“Œ React ์„ฑ๋Šฅ ์ตœ์ ํ™”

โœ… React.memo: ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง ๋ฐฉ์ง€
โœ… useMemo, useCallback: ๊ฐ’/ํ•จ์ˆ˜ ๋ฉ”๋ชจ์ด์ œ์ด์…˜
โœ… Code Splitting: React.lazy + Suspense๋กœ ๋ฒˆ๋“ค ๋ถ„ํ• 
โœ… ์ด๋ฏธ์ง€ ์ตœ์ ํ™”: WebP ํ˜•์‹, lazy loading ์ ์šฉ
โœ… Virtual Scrolling: ๊ธด ๋ชฉ๋ก์€ react-window ์‚ฌ์šฉ
๐Ÿ’š ์žฌ๋Šฅ๋„ท์—์„œ ํ’€์Šคํƒ ๊ฐœ๋ฐœ ์žฌ๋Šฅ ๊ฑฐ๋ž˜๋„ ํ™œ๋ฐœํ•ด!

์‹ค์ œ๋กœ ์žฌ๋Šฅ๋„ท(jaenung.net)์—์„œ MERN/MEAN ์Šคํƒ ๊ธฐ๋ฐ˜์˜
์›น ๊ฐœ๋ฐœ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ํ”„๋ฆฌ๋žœ์„œ๋“ค์ด ๋งŽ์ด ํ™œ๋™ํ•˜๊ณ  ์žˆ์–ด.
ํ’€์Šคํƒ ๊ฐœ๋ฐœ ์‹ค๋ ฅ์„ ์Œ“์œผ๋ฉด ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ
์ž์‹ ์˜ ๊ฐœ๋ฐœ ์žฌ๋Šฅ์„ ์ˆ˜์ตํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๋„ ์ƒ๊ธฐ๋Š” ๊ฑฐ์ง€! ๐Ÿ’ฐ

๐Ÿ—บ๏ธ 10. MERN/MEAN ์Šคํƒ ํ•™์Šต ๋กœ๋“œ๋งต

"์–ด๋””์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์•ผ ํ•ด?" ๋ผ๋Š” ์งˆ๋ฌธ์„ ์ œ์ผ ๋งŽ์ด ๋ฐ›๋Š”๋ฐ,
๋‹จ๊ณ„๋ณ„ ํ•™์Šต ๋กœ๋“œ๋งต์„ ์ •๋ฆฌํ•ด๋ดค์–ด! ๐Ÿ“š

๐Ÿ—บ๏ธ MERN ์Šคํƒ ํ•™์Šต ๋กœ๋“œ๋งต 1๋‹จ๊ณ„ (1~2๊ฐœ์›”) HTML/CSS ๊ธฐ์ดˆ ยท JavaScript ํ•ต์‹ฌ (ES6+) ยท Git ๊ธฐ์ดˆ ยท ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ธํŒ… 2๋‹จ๊ณ„ (2~3๊ฐœ์›”) React ๊ธฐ์ดˆ ยท ์ปดํฌ๋„ŒํŠธ ยท State/Props ยท Hooks ยท React Router ยท ๊ฐ„๋‹จํ•œ SPA ์ œ์ž‘ 3๋‹จ๊ณ„ (2~3๊ฐœ์›”) Node.js ยท Express.js ยท REST API ์„ค๊ณ„ ยท MongoDB ยท Mongoose ยท JWT ์ธ์ฆ 4๋‹จ๊ณ„ (2~3๊ฐœ์›”) Redux/Context API ยท TypeScript ์ž…๋ฌธ ยท ํ…Œ์ŠคํŒ… ยท Docker ๊ธฐ์ดˆ ยท ํด๋ผ์šฐ๋“œ ๋ฐฐํฌ 5๋‹จ๊ณ„ (์ง€์†์ ์œผ๋กœ) Next.js ยท GraphQL ยท ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ยท CI/CD ยท ํฌํŠธํด๋ฆฌ์˜ค ํ”„๋กœ์ ํŠธ ยท ์˜คํ”ˆ์†Œ์Šค ๊ธฐ์—ฌ

๐Ÿ“š ์ถ”์ฒœ ํ•™์Šต ๋ฆฌ์†Œ์Šค

๋ถ„์•ผ ์ถ”์ฒœ ๋ฆฌ์†Œ์Šค
JavaScript MDN Web Docs, javascript.info, ๋ชจ๋˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ Deep Dive
React React ๊ณต์‹ ๋ฌธ์„œ (react.dev), Scrimba React ์ฝ”์Šค
Node.js/Express Node.js ๊ณต์‹ ๋ฌธ์„œ, The Odin Project
MongoDB MongoDB University (๋ฌด๋ฃŒ), Mongoose ๊ณต์‹ ๋ฌธ์„œ
ํ’€์Šคํƒ ํ”„๋กœ์ ํŠธ freeCodeCamp, Traversy Media (YouTube)
TypeScript TypeScript ๊ณต์‹ ํ•ธ๋“œ๋ถ, Matt Pocock์˜ Total TypeScript
๐Ÿ’ฌ ํฌํŠธํด๋ฆฌ์˜ค ํ”„๋กœ์ ํŠธ ์•„์ด๋””์–ด

๐Ÿ“ ๋ธ”๋กœ๊ทธ ํ”Œ๋žซํผ: CRUD + ์ธ์ฆ + ๋งˆํฌ๋‹ค์šด ์—๋””ํ„ฐ
๐Ÿ›’ ์ด์ปค๋จธ์Šค ์•ฑ: ์ƒํ’ˆ ๊ด€๋ฆฌ + ์žฅ๋ฐ”๊ตฌ๋‹ˆ + ๊ฒฐ์ œ ์—ฐ๋™
๐Ÿ’ฌ ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…: Socket.io + MongoDB + React
๐Ÿ“Š ๋Œ€์‹œ๋ณด๋“œ: ๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™” + REST API + ์ธ์ฆ
๐ŸŽฏ ํ•  ์ผ ๊ด€๋ฆฌ ์•ฑ: ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ธฐ ์ข‹์€ ํ”„๋กœ์ ํŠธ

์ด๋Ÿฐ ํ”„๋กœ์ ํŠธ๋“ค์„ GitHub์— ์˜ฌ๋ ค๋‘๋ฉด ์ทจ์—…ํ•  ๋•Œ ์—„์ฒญ ๋„์›€ ๋ผ! ๐Ÿ’ช

๐Ÿค” 11. MERN vs MEAN, ๋ญ˜ ์„ ํƒํ•ด์•ผ ํ•ด?

"MERN ๋ฐฐ์›Œ์•ผ ํ•ด? MEAN ๋ฐฐ์›Œ์•ผ ํ•ด?" ์ด ์งˆ๋ฌธ ์ง„์งœ ๋งŽ์ด ๋ฐ›๋Š”๋ฐ,
์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๋‹ˆ๊นŒ ์ œ๋Œ€๋กœ ์ •๋ฆฌํ•ด์ค„๊ฒŒ! ๐ŸŽฏ

โš›๏ธ MERN(React)์„ ์„ ํƒํ•ด์•ผ ํ•  ๋•Œ

โœ“
์Šคํƒ€ํŠธ์—…์ด๋‚˜ ์†Œ๊ทœ๋ชจ ํŒ€์—์„œ ๋น ๋ฅด๊ฒŒ ํ”„๋กœํ† ํƒ€์ž…์„ ๋งŒ๋“ค์–ด์•ผ ํ•  ๋•Œ
โœ“
ํ”„๋ฆฌ๋žœ์„œ๋กœ ๋‹ค์–‘ํ•œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•  ์˜ˆ์ •์ผ ๋•Œ (React ์ˆ˜์š”๊ฐ€ ์••๋„์ ์œผ๋กœ ๋งŽ์Œ)
โœ“
JavaScript์— ์ต์ˆ™ํ•˜๊ณ  TypeScript๋ฅผ ์•„์ง ์ž˜ ๋ชจ๋ฅผ ๋•Œ
โœ“
React Native๋กœ ๋ชจ๋ฐ”์ผ ์•ฑ๋„ ํ•จ๊ป˜ ๊ฐœ๋ฐœํ•  ๊ณ„ํš์ด ์žˆ์„ ๋•Œ
โœ“
Next.js๋กœ ํ™•์žฅํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์„ ๋•Œ

๐Ÿ…ฐ๏ธ MEAN(Angular)์„ ์„ ํƒํ•ด์•ผ ํ•  ๋•Œ

โœ“
๋Œ€๊ธฐ์—…์ด๋‚˜ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ํ™˜๊ฒฝ์—์„œ ์ผํ•  ์˜ˆ์ •์ผ ๋•Œ
โœ“
TypeScript๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ์ œ๋Œ€๋กœ ๋ฐฐ์šฐ๊ณ  ์‹ถ์„ ๋•Œ
โœ“
ํŒ€ ๊ทœ๋ชจ๊ฐ€ ํฌ๊ณ  ์ฝ”๋“œ ์ผ๊ด€์„ฑ์ด ์ค‘์š”ํ•œ ํ”„๋กœ์ ํŠธ์ผ ๋•Œ
โœ“
Java/C# ๊ฐ™์€ ๊ฐ์ฒด์ง€ํ–ฅ ์–ธ์–ด ๋ฐฐ๊ฒฝ์ด ์žˆ์–ด์„œ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ๊ฐ€ ํŽธํ•  ๋•Œ
โœ“
Google ์ƒํƒœ๊ณ„(Firebase, GCP)์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ
๐Ÿ“Œ 2024๋…„ ๊ธฐ์ค€ ์ทจ์—… ์‹œ์žฅ ํ˜„์‹ค

Stack Overflow 2024 ์„ค๋ฌธ ๊ธฐ์ค€์œผ๋กœ React๋Š” ์ „์ฒด ์›น ํ”„๋ ˆ์ž„์›Œํฌ ์ค‘
์‚ฌ์šฉ๋ฅ  1์œ„(39.5%)๋ฅผ ์ฐจ์ง€ํ•˜๊ณ  ์žˆ์–ด.
Angular๋Š” ์•ฝ 17.1%๋กœ 3์œ„๊ถŒ.

์ทจ์—…์„ ๋ชฉํ‘œ๋กœ ํ•œ๋‹ค๋ฉด React(MERN) ๋จผ์ € ๋ฐฐ์šฐ๋Š” ๊ฒŒ ํ˜„์‹ค์ ์œผ๋กœ ์œ ๋ฆฌํ•ด!
๋‹จ, ๋Œ€๊ธฐ์—… SI/๊ธˆ์œต๊ถŒ์„ ๋…ธ๋ฆฐ๋‹ค๋ฉด Angular๋„ ์ถฉ๋ถ„ํžˆ ๊ฐ€์น˜ ์žˆ์–ด. ๐Ÿ’ผ
๐Ÿ’š ๊ฒฐ๋ก ์€?

์†”์งํžˆ ๋งํ•˜๋ฉด ๋‘˜ ๋‹ค ๋ฐฐ์šฐ๋ฉด ์ œ์ผ ์ข‹์Œ ใ…‹ใ…‹ใ…‹
๊ทผ๋ฐ ์‹œ๊ฐ„์ด ์—†๋‹ค๋ฉด MERN(React) ๋จผ์ €!
React๋ฅผ ์ž˜ ์ดํ•ดํ•˜๋ฉด Angular ๋ฐฐ์šฐ๋Š” ๊ฑด ์ƒ๋Œ€์ ์œผ๋กœ ์‰ฌ์›Œ.
ํ•ต์‹ฌ ๊ฐœ๋…(์ปดํฌ๋„ŒํŠธ, ์ƒํƒœ๊ด€๋ฆฌ, ๋ผ์šฐํŒ…)์€ ๋น„์Šทํ•˜๊ฑฐ๋“ ! ๐ŸŽฏ

๊ทธ๋ฆฌ๊ณ  ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ํ”„๋ฆฌ๋žœ์„œ๋กœ ํ™œ๋™ํ•˜๋ ค๋ฉด
React ๊ธฐ๋ฐ˜ MERN ์Šคํƒ์ด ํ›จ์”ฌ ๋” ๋งŽ์€ ์˜๋ขฐ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด! ๐Ÿ’ฐ

๐ŸŽฏ 12. ์ •๋ฆฌ - ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ž๋กœ ๊ฐ€๋Š” ๊ธธ

์˜ค๋Š˜ ์—„์ฒญ ๋งŽ์€ ๋‚ด์šฉ์„ ๋‹ค๋ค˜๋Š”๋ฐ, ํ•ต์‹ฌ๋งŒ ๋‹ค์‹œ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ! ๐Ÿ“

๐Ÿ”‘ ํ•ต์‹ฌ ์š”์•ฝ

1
ํ’€์Šคํƒ = ํ”„๋ก ํŠธ์—”๋“œ + ๋ฐฑ์—”๋“œ + DB
JavaScript ํ•˜๋‚˜๋กœ ์ „์ฒด ์Šคํƒ์„ ์ปค๋ฒ„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒŒ MERN/MEAN์˜ ์ตœ๋Œ€ ์žฅ์ !
2
MERN = MongoDB + Express + React + Node.js
ํ˜„์žฌ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ํ’€์Šคํƒ ์กฐํ•ฉ. ์Šคํƒ€ํŠธ์—…๊ณผ ํ”„๋ฆฌ๋žœ์„œ์—๊ฒŒ ํŠนํžˆ ์œ ๋ฆฌ!
3
MEAN = MongoDB + Express + Angular + Node.js
TypeScript ๊ธฐ๋ฐ˜์˜ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์นœํ™”์  ์Šคํƒ. ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์— ๊ฐ•ํ•จ!
4
ํ˜„๋Œ€ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ = ์Šคํƒ + ๋„๊ตฌ๋“ค
TypeScript, Docker, CI/CD, ํ…Œ์ŠคํŒ…๊นŒ์ง€ ๊ฐ–์ถฐ์•ผ ์ง„์งœ ํ˜„๋Œ€์ ์ธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ!
5
Next.js๊ฐ€ ๋ฏธ๋ž˜
MERN์˜ ์ง„ํ™”ํ˜•์œผ๋กœ SSR, SSG, API Routes๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•˜๋Š” ํ’€์Šคํƒ ํ”„๋ ˆ์ž„์›Œํฌ.
2024-2025 ํŠธ๋ Œ๋“œ์˜ ํ•ต์‹ฌ!
"ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๋Š” ๊ฑด ํ•˜๋ฃจ์•„์นจ์— ๋˜๋Š” ๊ฒŒ ์•„๋‹ˆ์•ผ.
ํ•˜์ง€๋งŒ MERN ์Šคํƒ์ฒ˜๋Ÿผ ์ผ๊ด€๋œ ์–ธ์–ด(JavaScript)๋กœ ์ „์ฒด๋ฅผ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑด
์ง„์ž…์žฅ๋ฒฝ์„ ์—„์ฒญ ๋‚ฎ์ถฐ์ค€ ํ˜์‹ ์ด์•ผ. ๊พธ์ค€ํžˆ ํ•˜๋‚˜์”ฉ ์Œ“์•„๊ฐ€๋‹ค ๋ณด๋ฉด
์–ด๋А ์ˆœ๊ฐ„ ํ˜ผ์ž์„œ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋Š” ์ž์‹ ์„ ๋ฐœ๊ฒฌํ•˜๊ฒŒ ๋  ๊ฑฐ์•ผ! ๐Ÿš€"
๐Ÿ’ฌ ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•œ๋งˆ๋””!

์ด๋ก ๋งŒ ๊ณต๋ถ€ํ•˜์ง€ ๋ง๊ณ  ๋ฌด์กฐ๊ฑด ๋งŒ๋“ค์–ด๋ด! ๐Ÿ”จ
์ฒ˜์Œ์—” ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ผ๋„ ์ข‹๊ณ , ๊ฐ„๋‹จํ•œ ๋ธ”๋กœ๊ทธ๋ผ๋„ ์ข‹์•„.
์ง์ ‘ ๋งŒ๋“ค๋ฉด์„œ ๋ถ€๋”ชํžˆ๋Š” ์—๋Ÿฌ๋“ค์ด ์ง„์งœ ๊ณต๋ถ€์•ผ ใ…‹ใ…‹ใ…‹

Stack Overflow, GitHub, ๊ณต์‹ ๋ฌธ์„œ๊ฐ€ ๋„ค ์นœ๊ตฌ์•ผ.
์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋ฌด์„œ์›Œํ•˜์ง€ ๋ง๊ณ , ๊ตฌ๊ธ€๋ง ์‹ค๋ ฅ๋„ ๊ฐœ๋ฐœ ์‹ค๋ ฅ์ด์•ผ! ๐Ÿ’ช

ํ™”์ดํŒ…! ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ
๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0