Ver3.5 ๐ ํ์คํ ์น๊ฐ๋ฐ๊ณผ MERNยทMEAN ์คํ์ํ์ฉํ ํ๋์ ๊ฐ๋ฐ ํ๊ฒฝ

๐ ํ์คํ ์น๊ฐ๋ฐ๊ณผ MERNยทMEAN ์คํ์
ํ์ฉํ ํ๋์ ๊ฐ๋ฐ ํ๊ฒฝ
"์ผ ์์ฆ ํ์คํ ๊ฐ๋ฐ์ ๋๋ค๊ณ 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๊ฐ์ง ๊ธฐ์ ์ ์กฐํฉํด์ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ์ฒ์๋ถํฐ ๋๊น์ง ๋ง๋ค ์ ์์ด!
๐ M - MongoDB (๋ชฝ๊ณ DB)
MERN์ ์ฒซ ๋ฒ์งธ M! MongoDB๋ ์ ํต์ ์ธ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค(MySQL, PostgreSQL)์ ๋ฌ๋ฆฌ
NoSQL ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ผ.
๊ธฐ์กด SQL DB๋ ์์
ํ์ฒ๋ผ ํ(row)๊ณผ ์ด(column)๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋๋ฐ,
MongoDB๋ JSON ํํ์ ๋ฌธ์(Document)๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํจ.
์ด๊ฒ JavaScript๋ ์ฐฐ๋ก๊ถํฉ์ธ ์ด์ ๊ฐ ๋ฐ๋ก ์ฌ๊ธฐ ์์ด! ๐ฏ
โ ์คํค๋ง ์ ์ฐ์ฑ: ๋ฏธ๋ฆฌ ํ ์ด๋ธ ๊ตฌ์กฐ๋ฅผ ์ ํ์ง ์์๋ ๋จ
โ 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๋ ๋ฏธ๋๋ฉํ๊ณ ์ ์ฐํด์ ํ์ํ ๊ธฐ๋ฅ๋ง ๊ณจ๋ผ์ ์ธ ์ ์์ด.
๋ฏธ๋ค์จ์ด(Middleware) ์์คํ ๋๋ถ์ ์ธ์ฆ, ๋ก๊น , ์๋ฌ์ฒ๋ฆฌ ๋ฑ์
๋ ๊ณ ๋ธ๋ก์ฒ๋ผ ์กฐ๋ฆฝํด์ ์ธ ์ ์๊ฑฐ๋ ๐งฑ
โ ๋ผ์ฐํ (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์ ํต์ฌ ๊ฐ๋ ๋ค
UI๋ฅผ ๋ ๋ฆฝ์ ์ด๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์กฐ๊ฐ์ผ๋ก ๋๋๋ ๊ฐ๋ .
๋ ๊ณ ๋ธ๋ก์ฒ๋ผ ์์ ์ปดํฌ๋ํธ๋ค์ ์กฐํฉํด์ ํฐ ํ๋ฉด์ ๋ง๋ค์ด!
์ค์ DOM์ ์ง์ ์กฐ์ํ์ง ์๊ณ ๊ฐ์์ DOM์ ๋จผ์ ์ ๋ฐ์ดํธํ ํ
๋ณ๊ฒฝ๋ ๋ถ๋ถ๋ง ์ค์ DOM์ ๋ฐ์ํ๋ ๋ฐฉ์. ์ฑ๋ฅ์ด ์์ฒญ ์ข์์ง! โก
JavaScript ์ฝ๋ ์์ HTML์ฒ๋ผ ์๊ธด ๋ฌธ๋ฒ์ ์ธ ์ ์๊ฒ ํด์ฃผ๋ ํ์ฅ ๋ฌธ๋ฒ.
์ฒ์์ ์ข ์ด์ํ์ง๋ง ์ต์ํด์ง๋ฉด ์์ฒญ ํธํจ ใ ใ
State๋ ์ปดํฌ๋ํธ ๋ด๋ถ์ ๋ฐ์ดํฐ, Props๋ ๋ถ๋ชจ์์ ์์์ผ๋ก ์ ๋ฌํ๋ ๋ฐ์ดํฐ.
์ด ๋ ๊ฐ๋ฅผ ์ ์ดํดํ๋ฉด React์ 80%๋ ์ดํดํ ๊ฑฐ์ผ!
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 ์คํ์ด ๊ฐ๋ฅํด์ง ๊ทผ๋ณธ์ ์ธ ์ด์ ์ ๐ฑ
โ ๋น๋๊ธฐ I/O (Non-blocking): ํ์ผ ์ฝ๊ธฐ, DB ์กฐํ ๋ฑ์ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋ค์ ์์ ์ฒ๋ฆฌ
โ ์ด๋ฒคํธ ๋ฃจํ(Event Loop): ๋จ์ผ ์ค๋ ๋๋ก ๋์ ๋์์ฑ ์ฒ๋ฆฌ ๊ฐ๋ฅ
โ NPM (Node Package Manager): 200๋ง ๊ฐ ์ด์์ ํจํค์ง ์ํ๊ณ
โ ๋น ๋ฅธ ์คํ ์๋: V8 ์์ง ๊ธฐ๋ฐ์ผ๋ก JavaScript๋ฅผ ๊ธฐ๊ณ์ด๋ก ์ปดํ์ผ
โ ํฌ๋ก์ค ํ๋ซํผ: Windows, Mac, Linux ๋ชจ๋ ์ง์
์คํดํ๊ธฐ ์ฌ์ด ๋ถ๋ถ์ธ๋ฐ! ๐ค
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๊ฐ ๋ค์ด๊ฐ ๋ฒ์ ์ด๋ผ๊ณ ๋ณด๋ฉด ๋ผ! ๐
๐ ฐ๏ธ Angular๋?
Angular๋ Google์ด ๋ง๋ TypeScript ๊ธฐ๋ฐ์ ํ๋ก ํธ์๋ ํ๋ ์์ํฌ์ผ.
React๊ฐ "๋ผ์ด๋ธ๋ฌ๋ฆฌ"๋ผ๋ฉด, Angular๋ ์์ ํ "ํ๋ ์์ํฌ"์.
์ด ์ฐจ์ด๊ฐ ์์ฒญ ์ค์ํ๋ฐ, React๋ UI๋ง ๋ด๋นํ๊ณ ๋๋จธ์ง(๋ผ์ฐํ
, ์ํ๊ด๋ฆฌ ๋ฑ)๋
๊ฐ๋ฐ์๊ฐ ์ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ณจ๋ผ์ ์กฐํฉํด์ผ ํด.
๋ฐ๋ฉด Angular๋ ๋ชจ๋ ๊ฒ ๋ค ๋ด์ฅ๋์ด ์์ด! ๐๏ธ
| ํน์ง | React | Angular |
|---|---|---|
| ํ์ | ๋ผ์ด๋ธ๋ฌ๋ฆฌ | ์์ ํ ํ๋ ์์ํฌ |
| ์ธ์ด | JavaScript (JSX) | TypeScript (ํ์) |
| ํ์ต ๊ณก์ | ์๋์ ์ผ๋ก ์๋ง | ๊ฐํ๋ฆ (์ด๊ธฐ ์ง์ ์ฅ๋ฒฝ ๋์) |
| ๋ฒ๋ค ํฌ๊ธฐ | ๊ฐ๋ฒผ์ | ๋ฌด๊ฑฐ์ |
| ์ฃผ์ ์ฌ์ฉ์ฒ | ์คํํธ์ , ๋ค์ํ ๊ท๋ชจ | ๋๊ธฐ์ , ์ํฐํ๋ผ์ด์ฆ |
| ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ | ๋จ๋ฐฉํฅ | ์๋ฐฉํฅ (Two-way) |
Angular๋ ํนํ ๋๊ท๋ชจ ์ํฐํ๋ผ์ด์ฆ ํ๋ก์ ํธ์์ ๋น์ ๋ฐํด!
TypeScript๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ์ฐ๊ธฐ ๋๋ฌธ์ ํ์ ์์ ์ฑ์ด ๋๊ณ ,
ํ ๊ท๋ชจ๊ฐ ์ปค๋ ์ฝ๋ ์ผ๊ด์ฑ์ ์ ์งํ๊ธฐ ์ฌ์.
Google, Microsoft, IBM ๊ฐ์ ๋๊ธฐ์ ๋ค์ด 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 ์คํ์ผ๋ก ๊ฐ๋ฐ ํ๊ฒฝ์ ๊ตฌ์ถํ๋ ์ ์ฒด ํ๋ฆ์ ์ดํด๋ณด์.
๐ฆ ํ์ ํจํค์ง ์ค์น
๋ฐฑ์๋ (์๋ฒ ํด๋)
# ํ๋ก์ ํธ ์ด๊ธฐํ
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: '์ ํจํ์ง ์์ ํ ํฐ์
๋๋ค' });
}
};
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 ์คํ์ ์ด๋ค๊ณ ๋์ด ์๋์ผ!
ํ๋์ ์ธ ๊ฐ๋ฐ ํ๊ฒฝ์ ๋ง๋ค๋ ค๋ฉด ์ด๋ฐ ๋๊ตฌ๋ค๋ ์์์ผ ํด ๐
๐ TypeScript - ์ด์ ์ ํ์ด ์๋ ํ์
์์ฆ MERN/MEAN ํ๋ก์ ํธ์์ TypeScript๋ ๊ฑฐ์ ํ์ค์ด ๋์ด.
JavaScript์ ์ ์ ํ์
์ ์ถ๊ฐํ ์ธ์ด์ธ๋ฐ, ์ฒ์์ ๊ท์ฐฎ์ ๋ณด์ฌ๋
ํ๋ก์ ํธ๊ฐ ์ปค์ง์๋ก ๊ทธ ์ง๊ฐ๋ฅผ ๋ฐํํจ! ๐ฏ
โ ์ปดํ์ผ ํ์ ์๋ฌ ๊ฐ์ง: ์คํ ์ ์ ํ์ ์ค๋ฅ๋ฅผ ์ก์์ค
โ 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:
๋ช ๋ น์ด ํ๋๋ก 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๋ 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 ์ ์ก) |
๐ฅ 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 ์ค๋ฌด ๊ฐ๋ฐ ๊ฟํ
์ด๋ก ์ ์ถฉ๋ถํ ์์์ผ๋, ์ค์ ๊ฐ๋ฐํ ๋ ๋์ ๋๋ ๊ฟํ๋ค์ ๋ชจ์๋ดค์ด! ๐ฏ
๐ ๋ณด์ ํ์ ์ฒดํฌ๋ฆฌ์คํธ
DB ๋น๋ฐ๋ฒํธ, JWT ์ํฌ๋ฆฟ ๋ฑ ๋ฏผ๊ฐํ ์ ๋ณด๋ ์ ๋ ์ฝ๋์ ์ง์ ์ฐ์ง ๋ง๊ณ
.env ํ์ผ์ ์ ์ฅํ๊ณ .gitignore์ ์ถ๊ฐํด์ผ ํด!
ํด๋ผ์ด์ธํธ์์ ๊ฒ์ฆํด๋ ์๋ฒ์์๋ ๋ฐ๋์ ๊ฒ์ฆํด์ผ ํด.
Joi๋ express-validator ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ ์ถ์ฒ!
express-rate-limit์ผ๋ก API ์์ฒญ ํ์๋ฅผ ์ ํํด์DDoS ๊ณต๊ฒฉ์ด๋ ๋ธ๋ฃจํธํฌ์ค ๊ณต๊ฒฉ์ ๋ฐฉ์ดํด์ผ ํด!
ํ์ฉ๋ ๋๋ฉ์ธ์์๋ง API๋ฅผ ํธ์ถํ ์ ์๋๋ก
CORS ์ค์ ์ ๊ผผ๊ผผํ ํด์ผ ํด. ์์ผ๋์นด๋(*) ์ฌ์ฉ์ ํ๋ก๋์ ์์ ๊ธ์ง!
Express ์ฑ์ ๋ณด์ ๊ด๋ จ HTTP ํค๋๋ฅผ ์๋์ผ๋ก ์ค์ ํด์ฃผ๋ ๋ฏธ๋ค์จ์ด.
npm install helmet ํ๊ณ app.use(helmet()) ํ ์ค์ด๋ฉด ๋!
โก ์ฑ๋ฅ ์ต์ ํ ํ
โ ์ธ๋ฑ์ค(Index) ์ค์ : ์์ฃผ ์กฐํํ๋ ํ๋์ ์ธ๋ฑ์ค ์ถ๊ฐ
โ Projection ์ฌ์ฉ: ํ์ํ ํ๋๋ง ์กฐํ (์ ์ฒด ๋ฌธ์ X)
โ Pagination: ํ ๋ฒ์ ๋ชจ๋ ๋ฐ์ดํฐ ์กฐํ ๊ธ์ง, ํ์ด์ง๋ค์ด์ ๊ตฌํ
โ Aggregation Pipeline: ๋ณต์กํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ DB์์ ์ฒ๋ฆฌ
โ React.memo: ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง ๋ฐฉ์ง
โ useMemo, useCallback: ๊ฐ/ํจ์ ๋ฉ๋ชจ์ด์ ์ด์
โ Code Splitting: React.lazy + Suspense๋ก ๋ฒ๋ค ๋ถํ
โ ์ด๋ฏธ์ง ์ต์ ํ: WebP ํ์, lazy loading ์ ์ฉ
โ Virtual Scrolling: ๊ธด ๋ชฉ๋ก์ react-window ์ฌ์ฉ
์ค์ ๋ก ์ฌ๋ฅ๋ท(jaenung.net)์์ MERN/MEAN ์คํ ๊ธฐ๋ฐ์
์น ๊ฐ๋ฐ ์๋น์ค๋ฅผ ์ ๊ณตํ๋ ํ๋ฆฌ๋์๋ค์ด ๋ง์ด ํ๋ํ๊ณ ์์ด.
ํ์คํ ๊ฐ๋ฐ ์ค๋ ฅ์ ์์ผ๋ฉด ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์
์์ ์ ๊ฐ๋ฐ ์ฌ๋ฅ์ ์์ตํํ ์ ์๋ ๊ธฐํ๋ ์๊ธฐ๋ ๊ฑฐ์ง! ๐ฐ
๐บ๏ธ 10. MERN/MEAN ์คํ ํ์ต ๋ก๋๋งต
"์ด๋์๋ถํฐ ์์ํด์ผ ํด?" ๋ผ๋ ์ง๋ฌธ์ ์ ์ผ ๋ง์ด ๋ฐ๋๋ฐ,
๋จ๊ณ๋ณ ํ์ต ๋ก๋๋งต์ ์ ๋ฆฌํด๋ดค์ด! ๐
๐ ์ถ์ฒ ํ์ต ๋ฆฌ์์ค
| ๋ถ์ผ | ์ถ์ฒ ๋ฆฌ์์ค |
|---|---|
| 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)์ ์ ํํด์ผ ํ ๋
๐ ฐ๏ธ MEAN(Angular)์ ์ ํํด์ผ ํ ๋
Stack Overflow 2024 ์ค๋ฌธ ๊ธฐ์ค์ผ๋ก React๋ ์ ์ฒด ์น ํ๋ ์์ํฌ ์ค
์ฌ์ฉ๋ฅ 1์(39.5%)๋ฅผ ์ฐจ์งํ๊ณ ์์ด.
Angular๋ ์ฝ 17.1%๋ก 3์๊ถ.
์ทจ์ ์ ๋ชฉํ๋ก ํ๋ค๋ฉด React(MERN) ๋จผ์ ๋ฐฐ์ฐ๋ ๊ฒ ํ์ค์ ์ผ๋ก ์ ๋ฆฌํด!
๋จ, ๋๊ธฐ์ SI/๊ธ์ต๊ถ์ ๋ ธ๋ฆฐ๋ค๋ฉด Angular๋ ์ถฉ๋ถํ ๊ฐ์น ์์ด. ๐ผ
์์งํ ๋งํ๋ฉด ๋ ๋ค ๋ฐฐ์ฐ๋ฉด ์ ์ผ ์ข์ ใ ใ ใ
๊ทผ๋ฐ ์๊ฐ์ด ์๋ค๋ฉด MERN(React) ๋จผ์ !
React๋ฅผ ์ ์ดํดํ๋ฉด Angular ๋ฐฐ์ฐ๋ ๊ฑด ์๋์ ์ผ๋ก ์ฌ์.
ํต์ฌ ๊ฐ๋ (์ปดํฌ๋ํธ, ์ํ๊ด๋ฆฌ, ๋ผ์ฐํ )์ ๋น์ทํ๊ฑฐ๋ ! ๐ฏ
๊ทธ๋ฆฌ๊ณ ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ํ๋ฆฌ๋์๋ก ํ๋ํ๋ ค๋ฉด
React ๊ธฐ๋ฐ MERN ์คํ์ด ํจ์ฌ ๋ ๋ง์ ์๋ขฐ๋ฅผ ๋ฐ์ ์ ์์ด! ๐ฐ
๐ฏ 12. ์ ๋ฆฌ - ํ์คํ ๊ฐ๋ฐ์๋ก ๊ฐ๋ ๊ธธ
์ค๋ ์์ฒญ ๋ง์ ๋ด์ฉ์ ๋ค๋ค๋๋ฐ, ํต์ฌ๋ง ๋ค์ ์ ๋ฆฌํด๋ณผ๊ฒ! ๐
๐ ํต์ฌ ์์ฝ
JavaScript ํ๋๋ก ์ ์ฒด ์คํ์ ์ปค๋ฒํ ์ ์๋ ๊ฒ MERN/MEAN์ ์ต๋ ์ฅ์ !
ํ์ฌ ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ํ์คํ ์กฐํฉ. ์คํํธ์ ๊ณผ ํ๋ฆฌ๋์์๊ฒ ํนํ ์ ๋ฆฌ!
TypeScript ๊ธฐ๋ฐ์ ์ํฐํ๋ผ์ด์ฆ ์นํ์ ์คํ. ๋๊ท๋ชจ ํ๋ก์ ํธ์ ๊ฐํจ!
TypeScript, Docker, CI/CD, ํ ์คํ ๊น์ง ๊ฐ์ถฐ์ผ ์ง์ง ํ๋์ ์ธ ๊ฐ๋ฐ ํ๊ฒฝ!
MERN์ ์งํํ์ผ๋ก SSR, SSG, API Routes๋ฅผ ๋ชจ๋ ์ง์ํ๋ ํ์คํ ํ๋ ์์ํฌ.
2024-2025 ํธ๋ ๋์ ํต์ฌ!
ํ์ง๋ง MERN ์คํ์ฒ๋ผ ์ผ๊ด๋ ์ธ์ด(JavaScript)๋ก ์ ์ฒด๋ฅผ ๋ฐฐ์ธ ์ ์๋ค๋ ๊ฑด
์ง์ ์ฅ๋ฒฝ์ ์์ฒญ ๋ฎ์ถฐ์ค ํ์ ์ด์ผ. ๊พธ์คํ ํ๋์ฉ ์์๊ฐ๋ค ๋ณด๋ฉด
์ด๋ ์๊ฐ ํผ์์ ์๋น์ค๋ฅผ ๋ง๋ค์ด๋ด๋ ์์ ์ ๋ฐ๊ฒฌํ๊ฒ ๋ ๊ฑฐ์ผ! ๐"
์ด๋ก ๋ง ๊ณต๋ถํ์ง ๋ง๊ณ ๋ฌด์กฐ๊ฑด ๋ง๋ค์ด๋ด! ๐จ
์ฒ์์ ํฌ๋๋ฆฌ์คํธ๋ผ๋ ์ข๊ณ , ๊ฐ๋จํ ๋ธ๋ก๊ทธ๋ผ๋ ์ข์.
์ง์ ๋ง๋ค๋ฉด์ ๋ถ๋ชํ๋ ์๋ฌ๋ค์ด ์ง์ง ๊ณต๋ถ์ผ ใ ใ ใ
Stack Overflow, GitHub, ๊ณต์ ๋ฌธ์๊ฐ ๋ค ์น๊ตฌ์ผ.
์๋ฌ ๋ฉ์์ง ๋ฌด์์ํ์ง ๋ง๊ณ , ๊ตฌ๊ธ๋ง ์ค๋ ฅ๋ ๊ฐ๋ฐ ์ค๋ ฅ์ด์ผ! ๐ช
ํ์ดํ ! ๐ฅ๐ฅ๐ฅ
๊ด๋ จ ํค์๋
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.

๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.