Ver2.5 ๐ฆ Deno์ TypeScript, ๊ฐ๋ฐ ์ฌ์ ํ๋๋ฅผ ๋ฐ๊พธ๋ ๋ฏธ์น ์กฐํฉ!

๐ฆ Deno์ TypeScript, ๊ฐ๋ฐ ์ฌ์ ํ๋๋ฅผ ๋ฐ๊พธ๋ ๋ฏธ์น ์กฐํฉ!
์๋
, ์ฝ๋ฉ ๋ฉ์ดํธ! ๐ ์ค๋ ์ข ํฅ๋ฏธ๋ก์ด ์ด์ผ๊ธฐ๋ฅผ ํด๋ณผ๊น ํด.
์๋ฐ์คํฌ๋ฆฝํธ ์ฌ์ ํ์ฑ์ฒ๋ผ ๋ฑ์ฅํด์ "ํ๋, ์ด์ ์๋๊ฐ ๋ณํ์ต๋๋ค"๋ฅผ ์ธ์น๊ณ ์๋ ๋
์, ๋ฐ๋ก Deno(๋ฐ๋
ธ)์ ๋ํ ์ด์ผ๊ธฐ์ผ.
์๋ง ๋ง์ ์น๊ตฌ๋ค์ด Node.js์ ํ์์ ์๋ฝํ๊ฒ ์๋ฒ๋ฅผ ๋ง๋ค๊ณ , ์คํฌ๋ฆฝํธ๋ฅผ ๋๋ฆฌ๊ณ ์์์ ๊ฑฐ์ผ. ๋๋ ๊ทธ๋ฌ๊ฑฐ๋ . Node.js๋ ์ฐ๋ฆฌ์๊ฒ ์๋ฒ์ฌ์ด๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ผ๋ ์ ์ธ๊ณ๋ฅผ ์ด์ด์ค ๊ณ ๋ง์ด ์กด์ฌ์ง. ๊ทธ๋ฐ๋ฐ ๋ง์ด์ผ, ๊ทธ Node.js๋ฅผ ๋ง๋ค์๋ ์ฒ์ฌ ๊ฐ๋ฐ์, ๋ผ์ด์ธ ๋ฌ(Ryan Dahl)์ด "์... ๋ด๊ฐ Node.js ๋ง๋ค ๋ ๋ช ๊ฐ์ง ํํ๋๋ ๊ฒ ์์ด"๋ผ๋ฉด์ ์์ ํ ์๋ก์ด ๋ฐํ์์ ๋ค๊ณ ๋ํ๋ฌ์ด. ๊ทธ๊ฒ ๋ฐ๋ก Deno์ผ. ๐ฆ
Deno๋ ๊ทธ๋ฅ 'Node.js 2.0' ๊ฐ์ ๊ฒ ์๋์ผ.
ํ์๋ถํฐ ๋ค๋ฅธ ์ฒ ํ์ ๊ฐ์ง๊ณ ํ์ด๋ฌ์ด. ๋ณด์์ ๊ธฐ๋ณธ! ํ์
์คํฌ๋ฆฝํธ๋ ๋ค์ดํฐ๋ธ! ์ด ๋ ๊ฐ์ง๋ง ๋ค์ด๋ ๊ฐ์ด์ด ๋ฐ์ง ์์? ๋ง์น ์ต์ ํ ์ค๋งํธํฐ์ด ๋ฐฉ์๋ฐฉ์ง๊ณผ ์ต๊ณ ์ ์นด๋ฉ๋ผ๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ๋ฌ๊ณ ๋์ค๋ ๊ฒ์ฒ๋ผ, Deno๋ ๊ฐ๋ฐ์์๊ฒ ๊ฐ์ฅ ํ์ํ๋ ๊ธฐ๋ฅ๋ค์ ๊ธฐ๋ณธ์ผ๋ก ํ๊ณ ์ธ์์ ๋์์ด.
์ด ๊ธ์์๋ Deno๊ฐ ๋๋์ฒด ๋ญ๊ณ , Node.js๋์ ๋ญ๊ฐ ๋ค๋ฅธ์ง, ๊ทธ๋ฆฌ๊ณ Deno์ ์ํผ์ ํํธ๋์ธ ํ์ ์คํฌ๋ฆฝํธ(TypeScript)๋ฅผ ํจ๊ป ์ฌ์ฉํ์ ๋ ์ด๋ค ์๋์ง๊ฐ ํญ๋ฐํ๋์ง ์์ฃผ ํํ ํธ์ด๋ณผ ๊ฑฐ์ผ. "์, Deno... ์ด๋ฆ์ ๋ค์ด๋ดค๋๋ฐ..." ํ๋ ์น๊ตฌ๋ค์ด๋ผ๋ฉด ์ค๋ ์ด ๊ธ์ ๋ค ์ฝ๊ณ ๋์ "์, ๋น์ฅ ์จ๋ณด๊ณ ์ถ๋ค!"๋ผ๊ณ ์ธ์น๊ฒ ๋ ์ง๋ ๋ชฐ๋ผ. ๐
์, ๊ทธ๋ผ ๋ณธ๊ฒฉ์ ์ผ๋ก Deno์ ๋งค๋ ฅ์ ๋น ์ ธ๋ณผ ์ค๋น ๋์ด?
Let's dive in! ๐
Deno์ ์ฒ ํ: ๋ญ๊ฐ ๊ทธ๋ ๊ฒ ๋ค๋ฅธ๋ฐ? (feat. ํ์คํฐ ๊ฐ์ฑ)
Deno๋ฅผ ๊ทธ๋ฅ '์ข ๋ ๋์ Node.js'๋ผ๊ณ ์๊ฐํ๋ฉด ์ญ์ญํด.
Deno๋ ์์ ํ ๋ค๋ฅธ ํ์ ์ง๋ ค๊ณ ๋์๊ฑฐ๋ . ๋ง์น MP3 ํ๋ ์ด์ด๊ฐ ์ง๋ฐฐํ๋ ์์ฅ์ ์์ดํ์ด ๋ฑ์ฅํ ๊ฒ์ฒ๋ผ, ๊ธฐ์กด์ ๋ถํธํจ์ ๊ทผ๋ณธ์ ์ผ๋ก ํด๊ฒฐํ๋ ค๋ ์๋์ผ. Deno์ ํต์ฌ ์ฒ ํ, ๋ฑ 4๊ฐ์ง๋ง ์ง์ด๋ณด์.
1. ๐ ๋ณด์์ ์์ด๋ค: "ํ๋ฝ ์์ด๋ ์๋ฌด๊ฒ๋ ๋ชป ํด!"
Node.js๋ฅผ ์จ๋ณธ ์น๊ตฌ๋ค์ ์ ๊ฑฐ์ผ. `npm install`๋ก ํจํค์ง๋ฅผ ์ค์นํ๊ณ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๋ฉด, ๊ทธ ์คํฌ๋ฆฝํธ๋ ๋ด ์ปดํจํฐ์ ํ์ผ ์์คํ , ๋คํธ์ํฌ, ํ๊ฒฝ ๋ณ์ ๋ฑ ๊ฑฐ์ ๋ชจ๋ ๊ฒ์ ์ ๊ทผํ ์ ์์ด. ์ด๊ฑด ๋ง์น ์ฒ์ ๋ณด๋ ์ฌ๋์๊ฒ ์ฐ๋ฆฌ ์ง ํ๊ด๋ฌธ ๋น๋ฐ๋ฒํธ๋ฅผ ์๋ ค์ฃผ๋ ๊ฒ๊ณผ ๊ฐ์. ๋ฌผ๋ก ๋๋ถ๋ถ์ ํจํค์ง๋ ์ฐฉํ์ง๋ง, ์ ์์ ์ธ ์ฝ๋๊ฐ ์จ์ด์๋ค๋ฉด? ๋์ฐํ์ง. ๐ฑ
Deno๋ ์ฌ๊ธฐ์ ๋ฐ์์ ์ ํ์ ํด. "๊ธฐ๋ณธ์ ์ผ๋ก๋ ์๋ฌด๊ฒ๋ ๋ชป ํ๊ฒ ๋ง๊ณ , ํ์ํ ๊ถํ๋ง ๋ช ์์ ์ผ๋ก ํ์ฉํด์ฃผ์!" ์ด๊ฒ ๋ฐ๋ก Deno์ 'Secure by Default' ์ฒ ํ์ด์ผ.
์๋ฅผ ๋ค์ด, ์ด๋ค ์ฝ๋๊ฐ ๋คํธ์ํฌ๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํ๋ฉด, ์ฐ๋ฆฌ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ ๋ --allow-net ํ๋๊ทธ๋ฅผ ๋ถ์ฌ์ค์ผ ํด. ํ์ผ์ ์ฝ๊ณ ์ถ์ผ๋ฉด --allow-read, ์ฐ๊ณ ์ถ์ผ๋ฉด --allow-write ํ๋๊ทธ๊ฐ ํ์ํ์ง.
# ์ด ์ฝ๋๋ ๋คํธ์ํฌ ์ ๊ทผ ๊ถํ์ด ์์ด์ ์๋ฌ ๋ฐ์!
deno run my_server.ts
# "my_server.ts์ผ, ๋๋ ๋คํธ์ํฌ๋ฅผ ์ฌ์ฉํด๋ ์ข์!" ๋ผ๊ณ ํ๋ฝํด์ฃผ๋ ๊ฒ
deno run --allow-net my_server.ts
์ด๊ฑด ๋ง์น ํด๋ฝ ์์ ์งํค๋ ๋ฉ์น ํฐ ๊ฐ๋ ๊ฐ์. "์ ๋ถ์ฆ ๋ณด์ฌ์ฃผ์ธ์. ๋ชฉ์ ์ด ๋ญ์ฃ ?"๋ผ๊ณ ์ผ์ผ์ด ํ์ธํ๋ ๊ฑฐ์ง. ์ฒ์์ ์ข ๊ท์ฐฎ์ ์ ์์ง๋ง, ๋ด ์์คํ ์ ์์ ํ๊ฒ ์ง์ผ์ค๋ค๋ ์ผ๋ง๋ ๋ ๋ ํด? ์ด ๋ณด์ ๋ชจ๋ธ ํ๋๋ง์ผ๋ก๋ Deno๋ฅผ ์จ์ผ ํ ์ด์ ๋ ์ถฉ๋ถํ๋ค๊ณ ๋ด.
Deno์ ์ด๋ฐ ๋ณด์ ๋ชจ๋ธ์ '์๋๋ฐ์ค' ํ๊ฒฝ์์ ์ฝ๋๋ฅผ ์คํํ๋ค๊ณ ํํํด. ์์ด๋ค์ด ์์ ํ ๋ชจ๋ ์์(sandbox) ์์์๋ง ๋ ธ๋ ๊ฒ์ฒ๋ผ, ์ฝ๋๋ ๊ฒฉ๋ฆฌ๋ ํ๊ฒฝ์์ ์ ํด์ง ๊ถํ ๋ด์์๋ง ์คํ๋๋๋ก ํ๋ ๊ฑฐ์ง. ๋๋ถ์ ์ฐ๋ฆฌ๋ ํจ์ฌ ๋ ์์ฌํ๊ณ ์ธ๋ถ ์ฝ๋๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋ผ.
2. ๐ ํ์ ์คํฌ๋ฆฝํธ๋ ๊ตญ๋ฃฐ์ด์ง: "์ค์ ? ๊ทธ๊ฒ ๋ญ๋ฐ ๋จน๋ ๊ฑด๊ฐ?"
์์ฆ ์น ๊ฐ๋ฐ ์ฌ์์ ํ์ ์คํฌ๋ฆฝํธ๋ ์ ํ์ด ์๋ ํ์๊ฐ ๋์ด๊ฐ๊ณ ์์ด. ์๋ฐ์คํฌ๋ฆฝํธ์ ์ ์ฐํจ์ด ๋๋ก๋ ๋ฐ๋ชฉ์ ์ก๋ '๋ฐํ์ ์๋ฌ'์ ์ฃผ๋ฒ์ด ๋๋๊น. ํ์ ์คํฌ๋ฆฝํธ๋ ์ฝ๋๋ฅผ ์คํํ๊ธฐ ์ ์ ํ์ ์ ์ฒดํฌํด์ ์ด๋ฐ ์ค์๋ฅผ ๋ฏธ๋ฆฌ ๋ง์์ฃผ๋ ๋ ๋ ํ ์ง์๊ตฐ์ด์ผ.
๊ทธ๋ฐ๋ฐ Node.js์์ ํ์
์คํฌ๋ฆฝํธ๋ฅผ ์ฐ๋ ค๋ฉด ์ด๋ ์ด?
์ผ๋จ `typescript`, `ts-node`, `@types/node` ๊ฐ์ ํจํค์ง๋ค์ ์ค์นํ๊ณ , `tsconfig.json`์ด๋ผ๋ ๋ณต์กํ ์ค์ ํ์ผ์ ๋ง๋ค์ด์ ์ปดํ์ผ ์ต์
์ ํ๋ํ๋ ์ง์ ํด์ค์ผ ํ์ง. ์ด์ฌ์์๊ฒ๋ ์ด ๊ณผ์ ์์ฒด๊ฐ ํ๋์ ๊ฑฐ๋ํ ์ฅ๋ฒฝ์ด์์ด.
Deno๋ ์ด ๋ชจ๋ ๊ณผ์ ์ ์์ ๋ฒ๋ ธ์ด. ๊ทธ๋ฅ `.ts` ํ์ฅ์๋ก ํ์ผ์ ๋ง๋ค๊ณ ์ฝ๋๋ฅผ ์ง๋ฉด ๋. Deno ๋ฐํ์ ์์ฒด๊ฐ ํ์ ์คํฌ๋ฆฝํธ ์ปดํ์ผ๋ฌ(์ ํํ๋ Rust๋ก ๋ง๋ค์ด์ง SWC)๋ฅผ ๋ด์ฅํ๊ณ ์์ด์, ์ฐ๋ฆฌ๊ฐ `deno run` ๋ช ๋ น์ ๋ด๋ฆฌ๋ฉด ์์์ ํ์ ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๋ณํํด์ ์คํํด์ค.
// my_script.ts
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet("Deno"));
// ๊ทธ๋ฅ ์คํํ๋ฉด ๋! ๋ณ๋์ ์ปดํ์ผ ๊ณผ์ ์ด ํ์ ์๋ค.
// $ deno run my_script.ts
// Output: Hello, Deno!
์ด๊ฑด ์ ๋ง ํ๋ช ์ด์ผ. ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฐ๊ธฐ ์ํ ํ๋ค์ ์ ๋ก๋ก ๋ง๋ค์ด๋ฒ๋ฆฐ ๊ฑฐ์ง. ๋๋ถ์ ์ฐ๋ฆฌ๋ ์ค๋กฏ์ด ๋น์ฆ๋์ค ๋ก์ง์๋ง ์ง์คํ ์ ์๊ฒ ๋์ด. Deno์ ํ์ ์คํฌ๋ฆฝํธ์ ์กฐํฉ์ ๋ง์น ์๋ฉ๋ฆฌ์นด๋ ธ์ ์น์ฆ์ผ์ดํฌ, ์ผ๊ฒน์ด๊ณผ ์์ฃผ์ฒ๋ผ ๋ผ๋ ค์ผ ๋ ์ ์๋ ์๋ฒฝํ ํ์ด๋ง์ด๋ผ๊ณ ํ ์ ์์ด. ์ฐฐ๋ก๊ถํฉ ๊ทธ ์์ฒด! โจ
3. ๐ฆ ๋ชจ๋ ์์คํ ์ ํ๋ํ: "npm๊ณผ package.json์ ์ด์ ์๋ "
Node.js ์ํ๊ณ์ ์ฌ์ฅ์ `npm`๊ณผ `package.json`์ด์์ด. ํ์ํ ํจํค์ง๋ฅผ `npm`์ผ๋ก ์ค์นํ๋ฉด `node_modules`๋ผ๋ ๊ฑฐ๋ํ ๋ธ๋ํ์ด ์๊ธฐ๊ณ , `package.json`์ ์์กด์ฑ์ด ๊ธฐ๋ก๋์ง. ๊ทธ๋ฆฌ๊ณ ์ฝ๋์์๋ `require('express')` ๊ฐ์ CommonJS ๋ฐฉ์์ผ๋ก ๋ชจ๋์ ๋ถ๋ฌ์์ด.
Deno๋ ์ด ๋ฐฉ์์ ๊ณผ๊ฐํ ์๋ณ์ ๊ณ ํ์ด. ๋์ ์น ํ์ค์ธ ES Modules(ESM)์ ์ ๋ฉด์ ์ผ๋ก ์ฑํํ์ง. ๊ทธ๋ฆฌ๊ณ ๋ชจ๋์ `npm` ๊ฐ์ ์ค์ ์ ์ฅ์์์ ๋ค์ด๋ฐ๋ ๊ฒ ์๋๋ผ, URL์ ํตํด ์ง์ ์ํฌํธํด.
// Node.js (CommonJS)
const express = require('express');
// Deno (ES Modules)
import { Application } from "https://deno.land/std@0.224.0/http/mod.ts";
URL๋ก ๋ชจ๋์ ๊ฐ์ ธ์จ๋ค๋, ์ฒ์์ ์ข ์ด์ํ ์ ์์ด. "์ ๋ฌ๋ค ์ URL ์ฃผ์ ๋ฐ๋๊ฑฐ๋ ์ฌ๋ผ์ง๋ฉด ๋ด ํ๋ก์ ํธ๋ ๋งํ๋ ๊ฑฐ ์๋?" ๋ผ๋ ๊ฑฑ์ ๋ ๋ค ์ ์์ง. ํ์ง๋ง Deno๋ ํ๋ฒ ์ํฌํธํ ๋ชจ๋์ ๋ก์ปฌ์ ์บ์ฑํด๋๊ธฐ ๋๋ฌธ์ ๋งค๋ฒ ๋ค์ด๋ก๋ํ์ง ์์. ๊ทธ๋ฆฌ๊ณ `deno.json`(๋๋ `deno.jsonc`) ํ์ผ์ `imports` ๋งต์ ์ฌ์ฉํ๋ฉด ์์กด์ฑ์ `package.json`์ฒ๋ผ ๊น๋ํ๊ฒ ๊ด๋ฆฌํ๊ณ ๋ฒ์ ๋ ๊ณ ์ ํ ์ ์์ด.
์ด ๋ฐฉ์์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ ํ์ค์ํ์ผ. ๋๊ตฌ๋ ์์ ์ ์๋ฒ๋ GitHub ์ ์ฅ์์ ์ฝ๋๋ฅผ ์ฌ๋ ค๋๊ณ URL๋ก ๊ณต์ ํ ์ ์์ด. `npm`์ด๋ผ๋ ํ๋์ ๊ฑฐ๋ํ ํ๋ซํผ์ ์์กดํ ํ์๊ฐ ์๋ ๊ฑฐ์ง. ์น์ด ๋์ํ๋ ๋ฐฉ์๊ณผ ๋๊ฐ์ด, ํ์ดํผ๋งํฌ๋ก ์ฝ๋๋ฅผ ์ฐ๊ฒฐํ๋ ๊ฑฐ์ผ. ์ ๋ง '์น'์ค๋ฌ์ด ๋ฐฉ์์ด์ง ์์?
4. ๐ ๏ธ ์ฌ์ธ์ ํด์ฒด์ธ: "๊ฐ๋ฐ์ ํ์ํ ๊ฑด ๋ค ์ค๋นํด๋จ์ด"
Node.js๋ก ํ๋ก์ ํธ๋ฅผ ํ๋ ์์ํ๋ ค๋ฉด ๋ญ๊ฐ ํ์ํ์ง?
์ฝ๋ ํฌ๋งทํฐ๋ก๋ `Prettier`, ์ฝ๋ ํ์ง ๊ฒ์ฌ ๋๊ตฌ๋ก๋ `ESLint`, ํ
์คํธ ๋ฌ๋๋ก๋ `Jest`๋ `Mocha`, ๋ฒ๋ค๋ฌ๋ก๋ `Webpack`์ด๋ `Rollup`... ๊ฐ๊ธฐ ๋ค๋ฅธ ๋๊ตฌ๋ค์ ์กฐํฉํด์ '๋๋ง์ ๊ฐ๋ฐ ํ๊ฒฝ'์ ๊ตฌ์ถํด์ผ ํ์ด. ๋ฌผ๋ก ์์ ๋๊ฐ ๋๋ค๋ ์ฅ์ ๋ ์์ง๋ง, ๋งค๋ฒ ํ๋ก์ ํธ๋ฅผ ์์ํ ๋๋ง๋ค ์ด ์ค์ ์ง์ฅ์ ๋น ์ง๋ ๊ฑด ๊ฝค๋ ํผ๊ณคํ ์ผ์ด์ผ.
Deno๋ "๊ทธ๋ฐ ๊ท์ฐฎ์ ๊ฑด ๋ด๊ฐ ๋ค ํด์ค๊ฒ!"๋ผ๊ณ ๋งํด. Deno๋ ๋ฐํ์ ์์ฒด์ ํ์์ ์ธ ๊ฐ๋ฐ ๋๊ตฌ๋ค์ ๋ชจ๋ ๋ด์ฅํ๊ณ ์์ด. ์ด๊ฑธ 'ํด์ฒด์ธ(Toolchain)'์ด๋ผ๊ณ ๋ถ๋ฌ.
- ์ฝ๋ ํฌ๋งทํฐ:
deno fmt- Prettier์ฒ๋ผ ์ฝ๋๋ฅผ ์์๊ฒ ์ ๋ ฌํด์ค. - ๋ฆฐํฐ:
deno lint- ESLint์ฒ๋ผ ์ฝ๋์ ์ ์ฌ์ ์ธ ๋ฌธ์ ์ ์ ์ฐพ์์ค. - ํ
์คํธ ๋ฌ๋:
deno test- Jest์ฒ๋ผ ํ ์คํธ ์ฝ๋๋ฅผ ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ์ค. - ์์กด์ฑ ๊ฒ์ฌ๊ธฐ:
deno info- ๋ด ์ฝ๋์ ์์กด์ฑ ํธ๋ฆฌ๋ฅผ ํ๋์ ๋ณด์ฌ์ค. - ๋ฌธ์ ์์ฑ๊ธฐ:
deno doc- ์ฝ๋ ์ฃผ์์ ๊ธฐ๋ฐ์ผ๋ก ๋ฉ์ง ๋ฌธ์๋ฅผ ๋ง๋ค์ด์ค.
์ด ๋ชจ๋ ๊ฒ Deno๋ฅผ ์ค์นํ๋ ์๊ฐ ๋ฐ๋ก ์ฌ์ฉ ๊ฐ๋ฅํด. ๋ณ๋์ ์ค์น๋ ๋ณต์กํ ์ค์ ํ์ผ ์์ด, ๋ช ๋ น์ด ํ๋๋ก ๋ชจ๋ ๊ฑธ ํด๊ฒฐํ ์ ์๋ ๊ฑฐ์ง. ๊ฐ๋ฐ ๊ฒฝํ(DX, Developer Experience)์ด ์์ง ์์นํ๋ ์๋ฆฌ๊ฐ ๋ค๋ฆฌ์ง ์์? ๐
์ด๋, Deno์ ์ฒ ํ์ด ์ข ์๋ฟ์?
์ ๋ฆฌํ์๋ฉด Deno๋ ๋ ์์ ํ๊ณ , ๋ ํ๋์ ์ด๊ณ , ๋ ํธ๋ฆฌํ ๊ฐ๋ฐ ํ๊ฒฝ์ ์งํฅํด. ๊ธฐ์กด์ ๋ณต์ก์ฑ์ ๊ฑท์ด๋ด๊ณ ๋ณธ์ง์ ์ง์คํ์๋ Deno์ ๋ฏธ๋๋ฉ๋ฆฌ์ฆ ์ฒ ํ์ ์์ฆ ํธ๋ ๋์๋ ์ ๋ง๋ ๊ฒ ๊ฐ์. ์, ๊ทธ๋ผ ์ด์ ์ด๋ก ์ ๊ทธ๋งํ๊ณ ์ง์ Deno์ ์ธ๊ณ๋ก ๋ค์ด๊ฐ ๋ณด์! ๐ป
๐ ๏ธ ์, ์ด์ ์ง์ ๋ง์ ธ๋ณด์: Deno ์ค์น์ ์ฒซ๊ฑธ์
๋ฐฑ๋ฌธ์ด ๋ถ์ฌ์ผ๊ฒฌ! Deno๊ฐ ์๋ฌด๋ฆฌ ์ข๋ค๊ณ ๋ง๋ก๋ง ๋ค์ด๋ด์ผ ๊ฐ์ด ์ ์ค์ง.
์ง์ ๋ด ์ปดํจํฐ์ ์ค์นํ๊ณ "Hello, Deno!"๋ฅผ ์ธ์ณ๋ณด๋ ๊ฒ๋งํผ ํ์คํ ๊ฑด ์์ด. ์ค์น ๊ณผ์ ์ ๋๋ผ์ธ ์ ๋๋ก ๊ฐ๋จํ๋ ๊ฒ๋จน์ง ๋ง๊ณ ๋ฐ๋ผ์ ๋ด. ๋ ์ธ ๊ณ ! ๐จ
1. Deno ์ค์นํ๊ธฐ: ๋ช ๋ น์ด ํ ์ค์ด๋ฉด ๋!
Deno๋ ๋ณต์กํ ์ค์น ํ๋ก๊ทธ๋จ ์์ด, ํฐ๋ฏธ๋(๋๋ PowerShell)์์ ๋ช ๋ น์ด ํ ์ค๋ง ์ ๋ ฅํ๋ฉด ์ค์น๊ฐ ์๋ฃ๋ผ. ์ ๋ง์ด์ผ!
macOS ๋๋ Linux ์ฌ์ฉ์ (Shell):
ํฐ๋ฏธ๋์ ์ด๊ณ ์๋ ๋ช ๋ น์ด๋ฅผ ๋ณต์ฌํด์ ๋ถ์ฌ๋ฃ์ด ๋ด.
curl -fsSL https://deno.land/x/install/install.sh | sh
์ด ๋ช ๋ น์ด๋ Deno ๊ณต์ ํํ์ด์ง์์ ์ค์น ์คํฌ๋ฆฝํธ๋ฅผ ๋ค์ด๋ก๋ํด์ ๋ฐ๋ก ์คํํ๋ ๊ฑฐ์ผ. ์ค์น๊ฐ ๋๋๋ฉด ํ๊ฒฝ ๋ณ์ ์ค์ ์ ๋ํ ์๋ด๊ฐ ๋์ฌ ํ ๋ฐ, ํฐ๋ฏธ๋์ ํ์๋๋ ๊ฒฝ๋ก๋ฅผ `~/.zshrc`๋ `~/.bash_profile` ๊ฐ์ ์ ์ค์ ํ์ผ์ ์ถ๊ฐํด์ฃผ๋ฉด ๋ผ. (๋ณดํต์ ์์์ ์ ํด์ค!)
Windows ์ฌ์ฉ์ (PowerShell):
PowerShell์ ๊ด๋ฆฌ์ ๊ถํ์ผ๋ก ์คํํ๊ณ ์๋ ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํด ์ค.
irm https://deno.land/x/install/install.ps1 | iex
๋ง์ฐฌ๊ฐ์ง๋ก ์คํฌ๋ฆฝํธ๊ฐ ์์์ Deno๋ฅผ ์ค์นํ๊ณ ํ๊ฒฝ ๋ณ์๊น์ง ์ค์ ํด์ค ๊ฑฐ์ผ. ์ฐธ ์ฝ์ง? ๐
์ค์น๊ฐ ์ ๋๋์ง ํ์ธํด๋ณผ๊น?
ํฐ๋ฏธ๋์ ์๋ก ์ด๊ณ ์๋ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํด ๋ด.
deno --version
์๋์ฒ๋ผ Deno, V8, TypeScript์ ๋ฒ์ ์ ๋ณด๊ฐ ๋ฉ์ง๊ฒ ์ถ๋ ฅ๋๋ค๋ฉด ์ฑ๊ณต์ ์ผ๋ก ์ค์น๋ ๊ฑฐ์ผ! ๐
deno 1.44.2 (release, x86_64-apple-darwin)
v8 12.5.202.6
typescript 5.4.5
V8์ ๊ตฌ๊ธ์์ ๋ง๋ ์ด๊ณ ์ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ด์ผ. ์ฐ๋ฆฌ๊ฐ ์ฐ๋ ํฌ๋กฌ ๋ธ๋ผ์ฐ์ ์ Node.js์ ์ฌ์ฅ์ด ๋ฐ๋ก ์ด V8 ์์ง์ด์ง. Deno ์ญ์ V8 ์์ง์ ๊ธฐ๋ฐ์ผ๋ก ๋ง๋ค์ด์ก๊ธฐ ๋๋ฌธ์ ์์ฃผ ๋น ๋ฅธ ์๋๋ก ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ์คํํ ์ ์์ด. Deno๋ Node.js์ ์ฌ์ฅ์ ๊ณต์ ํ์ง๋ง, ๊ทธ ์ฌ์ฅ์ ๋๋ฌ์ผ ํ๊ฒฝ(๋ฐํ์)์ ์์ ํ ์๋กญ๊ฒ ์ค๊ณํ ๊ฑฐ๋ผ๊ณ ์๊ฐํ๋ฉด ์ฌ์.
2. ์ฒซ ๋ฒ์งธ Deno ์คํฌ๋ฆฝํธ: Welcome, TypeScript!
์ด์ ์ง์ง ์ฝ๋๋ฅผ ์ง๋ณผ ์๊ฐ์ด์ผ.
์ข์ํ๋ ์ฝ๋ ์๋ํฐ(VS Code๋ฅผ ๊ฐ๋ ฅ ์ถ์ฒํด!)๋ฅผ ์ด๊ณ , `welcome.ts`๋ผ๋ ์ด๋ฆ์ผ๋ก ์ ํ์ผ์ ๋ง๋ค์ด๋ด. ํ์ฅ์๊ฐ `.js`๊ฐ ์๋๋ผ `.ts`์ธ ๊ฑฐ ๋ณด์ด์ง? ์ฐ๋ฆฐ ์ฒ์๋ถํฐ ํ์
์คํฌ๋ฆฝํธ๋ก ์์ํ ๊ฑฐ์ผ!
ํ์ผ์ ์๋ ๋ด์ฉ์ ์ ๋ ฅํด ๋ณด์.
// welcome.ts
// ๊ฐ๋จํ ์ธํฐํ์ด์ค๋ฅผ ์ ์ํด์ ๊ฐ์ฒด์ ๋ชจ์์ ๊ฐ์ ํด๋ณด์.
interface Person {
name: string;
age: number;
}
const me: Person = {
name: "Jaenung Talent",
age: 10
};
function createGreeting(person: Person): string {
// ํ์
์คํฌ๋ฆฝํธ ๋๋ถ์ person.name๊ณผ person.age๋ฅผ ์์ ํ๊ฒ ์ฌ์ฉํ ์ ์์ด.
return `์๋
! ๋ด ์ด๋ฆ์ ${person.name}์ด๊ณ , ${person.age}์ด์ด์ผ. Deno์ ์ธ๊ณ์ ์จ ๊ฑธ ํ์ํด!`;
}
// Deno์ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ `colors` ๋ชจ๋์ ๊ฐ์ ธ์๋ณด์.
// URL๋ก ์ง์ ์ํฌํธํ๋ Deno์ ๋ฐฉ์!
import { bold, yellow } from "https://deno.land/std@0.224.0/fmt/colors.ts";
const greetingMessage = createGreeting(me);
// ์ฝ์์ ์ถ๋ ฅํ ๋ ์๊น๋ ์
ํ๋ณด์!
console.log(bold(yellow(greetingMessage)));
์ฝ๋๊ฐ ์ด๋ค ์ผ์ ํ๋์ง ๊ฐ๋จํ ์ดํด๋ณผ๊น?
- `Person`์ด๋ผ๋ `interface`๋ฅผ ๋ง๋ค์ด์ `name`์ ๋ฌธ์์ด, `age`๋ ์ซ์์ฌ์ผ ํ๋ค๊ณ ํ์ ์ ์ ํด์คฌ์ด.
- `me`๋ผ๋ ์์๋ฅผ ๋ง๋ค ๋ `Person` ํ์ ์ ์ง์ ํด์, ๋ง์ฝ `age`์ ๋ฌธ์์ด์ ๋ฃ์ผ๋ ค๊ณ ํ๋ฉด ์๋ํฐ์์ ๋ฐ๋ก ์๋ฌ๋ฅผ ํ์ํด์ค ๊ฑฐ์ผ. ์ด๊ฒ ํ์ ์คํฌ๋ฆฝํธ์ ํ์ด์ง! ๐ช
- `createGreeting` ํจ์๋ `Person` ํ์ ์ ๊ฐ์ฒด๋ฅผ ๋ฐ์์ ์ธ์ฌ๋ง ๋ฌธ์์ด์ ๋ง๋ค์ด์ค.
- `import` ๊ตฌ๋ฌธ์ ๋ด๋ด. `https://deno.land/std...` ๋ก ์์ํ๋ URL์์ `colors` ๋ชจ๋์ ์ง์ ๊ฐ์ ธ์ค๊ณ ์์ด. `npm install` ๊ฐ์ ๊ฑด ํ์ ์์ด!
- ๋ง์ง๋ง์ผ๋ก `colors` ๋ชจ๋์ ์ฌ์ฉํด์ ์ฝ์์ ์ถ๋ ฅ๋๋ ๋ฉ์์ง๋ฅผ ๊ตต๊ณ ๋ ธ๋์์ผ๋ก ๊พธ๋ฉฐ์คฌ์ด.
์, ์ด์ ์ด ํ์ผ์ ์คํํด๋ณผ๊น?
ํฐ๋ฏธ๋์์ `welcome.ts` ํ์ผ์ด ์๋ ๊ฒฝ๋ก๋ก ์ด๋ํ ๋ค์, ์๋ ๋ช
๋ น์ด๋ฅผ ์คํํด ๋ด.
deno run welcome.ts
์ฒ์ ์คํํ๋ฉด Deno๊ฐ `https://deno.land/...` ์์ ๋ชจ๋์ ๋ค์ด๋ก๋ํ๊ณ ์ปดํ์ผํ๋๋ผ ์ฝ๊ฐ์ ๋ฉ์์ง๊ฐ ๋ฐ ๊ฑฐ์ผ. ๊ทธ๋ฆฌ๊ณ ์ ์ ํ, ํฐ๋ฏธ๋์ ์ด๋ ๊ฒ ์์ ๋ฉ์์ง๊ฐ ๋ํ๋ ๊ฑฐ์ผ.
Download https://deno.land/std@0.224.0/fmt/colors.ts
...
Check file:///path/to/your/project/welcome.ts
<b><span style="color: yellow;">์๋
! ๋ด ์ด๋ฆ์ Jaenung Talent์ด๊ณ , 10์ด์ด์ผ. Deno์ ์ธ๊ณ์ ์จ ๊ฑธ ํ์ํด!</span></b>
์ด๋? ๋ณ๋์ ์ค์ ํ๋ ์์ด ํ์
์คํฌ๋ฆฝํธ ํ์ผ์ด ๊ทธ๋ฅ ๋ฟ
ํ๊ณ ์คํ๋์ด.
URL์์ ๋ชจ๋๋ ์์์ ์ฐฉ์ฐฉ ๊ฐ์ ธ์ค๊ณ ๋ง์ด์ผ. ์ด๊ฒ ๋ฐ๋ก Deno์ ๊ธฐ๋ณธ ํด๋์ค์ผ. ๐
3. ๋ณด์ ์๋๋ฐ์ค ์ฒดํํ๊ธฐ: ๊ฐ๋จํ ์น ์๋ฒ ๋์ฐ๊ธฐ
Deno์ ํต์ฌ ์ฒ ํ ์ค ํ๋์ธ '๋ณด์'์ ์ง์ ์ฒดํํด๋ณด์.
์ด๋ฒ์๋ ์์ฃผ ๊ฐ๋จํ ์น ์๋ฒ๋ฅผ ๋ง๋๋ ์ฝ๋๋ฅผ ์์ฑํด๋ณผ ๊ฑฐ์ผ. `server.ts`๋ผ๋ ์ ํ์ผ์ ๋ง๋ค๊ณ ์๋ ์ฝ๋๋ฅผ ๋ฃ์ด๋ด.
// server.ts
import { serve } from "https://deno.land/std@0.224.0/http/server.ts";
console.log("์น ์๋ฒ๊ฐ http://localhost:8000 ์์ ์คํ ์ค์
๋๋ค...");
// Deno.serve๋ ๋ค์ด์ค๋ HTTP ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ ์ ๊ณตํด.
serve((_req: Request) => {
// ๋ชจ๋ ์์ฒญ์ ๋ํด "Hello from Deno Server!" ๋ผ๋ ์๋ต์ ๋ณด๋ธ๋ค.
return new Response("Hello from Deno Server!", {
headers: { "content-type": "text/plain" },
});
});
์ด ์ฝ๋๋ Deno ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ `http/server` ๋ชจ๋์ ์ฌ์ฉํด์ 8000๋ฒ ํฌํธ์์ ์น ์๋ฒ๋ฅผ ์คํํ๋ ์ฝ๋์ผ. ์ด์ ์ด ์๋ฒ๋ฅผ ์คํํด๋ณผ๊น?
deno run server.ts
์ด๋ผ? ์ด๋ฒ์๋ ์ฝ๋๊ฐ ๋ฐ๋ก ์คํ๋์ง ์๊ณ , ๋ญ๊ฐ ์๋ฌ ๋ฉ์์ง๊ฐ ๋ฐ ๊ฑฐ์ผ.
error: Uncaught (in promise) PermissionDenied: Requires net access to "0.0.0.0:8000", run again with the --allow-net flag.
at ...
๋ฉ์์ง๋ฅผ ์ ์ฝ์ด๋ด. `PermissionDenied`, ์ฆ ๊ถํ์ด ๊ฑฐ๋ถ๋์๋ค๋ ๋ป์ด์ผ.
๋คํธ์ํฌ์ ์ ๊ทผํ๋ ค๋ฉด --allow-net ํ๋๊ทธ๊ฐ ํ์ํ๋ค๊ณ ์น์ ํ๊ฒ ์๋ ค์ฃผ๋ค. ์ด๊ฒ ๋ฐ๋ก Deno์ ๋ณด์ ์๋๋ฐ์ค๊ฐ ์๋ํ๋ ๋ฐฉ์์ด์ผ. ์ฝ๋๊ฐ ๋ง์๋๋ก ๋คํธ์ํฌ์ ์ ์ํ๋ ๊ฑธ ๋ง์์ค ๊ฑฐ์ง.
์ด์ Deno๊ฐ ์ํค๋ ๋๋ก ๊ถํ์ ๋ถ์ฌํด์ ๋ค์ ์คํํด๋ณด์.
deno run --allow-net server.ts
์ด์ ํฐ๋ฏธ๋์ "์น ์๋ฒ๊ฐ http://localhost:8000 ์์ ์คํ ์ค์ ๋๋ค..." ๋ผ๋ ๋ฉ์์ง๊ฐ ๋จ๊ณ ๋ฉ์ถฐ์์ ๊ฑฐ์ผ. ์ฑ๊ณต์ ์ผ๋ก ์๋ฒ๊ฐ ์คํ๋ ๊ฑฐ์ผ! ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ์ด๊ณ ์ฃผ์์ฐฝ์ `http://localhost:8000`์ ์ ๋ ฅํด๋ด. ํ๋ฉด์ "Hello from Deno Server!"๊ฐ ๋ณด์ธ๋ค๋ฉด, ๋ ๋ฐฉ๊ธ Deno๋ก ์ฒซ ์น ์๋ฒ๋ฅผ ๋์ด ๊ฑฐ์ผ! ์ถํํด! ๐ฅณ
--allow-net ์ฒ๋ผ ๋ชจ๋ ๋คํธ์ํฌ๋ฅผ ํ์ฉํ๋ ๋์ , --allow-net=google.com ์ฒ๋ผ ํน์ ๋๋ฉ์ธ๋ง ํ์ฉํ ์๋ ์์ด. ํ์ผ์ ์ฝ์ ๋๋ --allow-read=/path/to/my_data ์ฒ๋ผ ํน์ ๋๋ ํ ๋ฆฌ๋ง ํ์ฉํ๋ ๊ฒ ์ข์. ํ์ํ ๋งํผ๋ง, ์ต์ํ์ ๊ถํ์ ๋ถ์ฌํ๋ ๊ฒ์ด Deno์ ๋ณด์ ์ฒ ํ์ ์ ๋๋ก ํ์ฉํ๋ ๋ฐฉ๋ฒ์ด์ผ!
์ฌ๊ธฐ๊น์ง ์ ๋ฐ๋ผ์๋ค๋ฉด, ๋ ์ด๋ฏธ Deno์ ํ์ธต ๊ฐ๊น์์ง ๊ฑฐ์ผ.
์ค์น๋ถํฐ ์คํ, ๊ทธ๋ฆฌ๊ณ Deno์ ํต์ฌ ๊ธฐ๋ฅ์ธ ํ์
์คํฌ๋ฆฝํธ ๋ค์ดํฐ๋ธ ์ง์๊ณผ ๋ณด์ ์๋๋ฐ์ค๊น์ง ๋ชจ๋ ๊ฒฝํํด๋ดค์ด. ๋ค์ ์ฑํฐ์์๋ Deno์ ์ํผ์ ๋จ์ง, ํ์
์คํฌ๋ฆฝํธ๋ฅผ ์ด๋ป๊ฒ ๋ ๊ธฐ๊น๋๊ฒ ํ์ฉํ ์ ์๋์ง ๊น์ด ํ๊ณ ๋ค์ด ๋ณผ๊ฒ. ๊ธฐ๋ํด๋ ์ข์! ๐
๐ ํ์ ์คํฌ๋ฆฝํธ์ Deno: ์ด๊ฑด ์ด๋ช ์ด์ผ! (ํ์์ ์๋์ง)
์์์ Deno๋ ํ์
์คํฌ๋ฆฝํธ๋ฅผ ๋ค์ดํฐ๋ธ๋ก ์ง์ํ๋ค๊ณ ํ์ง?
์ด๊ฒ ๊ทธ๋ฅ "ํ์
์คํฌ๋ฆฝํธ ํ์ผ์ ์คํํ ์ ์๋ค" ์ ๋์ ์๋ฏธ๊ฐ ์๋์ผ. Deno์ ๋ชจ๋ ์ค๊ณ๋ ํ์
์คํฌ๋ฆฝํธ๋ฅผ ์ต์ฐ์ ์ผ๋ก ๊ณ ๋ คํด์ ๋ง๋ค์ด์ก์ด. Deno์ ํ์
์คํฌ๋ฆฝํธ๊ฐ ๋ง๋๋ฉด ์ด๋ค ๋ง๋ฒ ๊ฐ์ ์ผ์ด ๋ฒ์ด์ง๋์ง, ์ ์ด ์กฐํฉ์ด '์ด๋ช
'์ด๋ผ๊ณ ๊น์ง ๋ถ๋ฆฌ๋์ง ํ๋ฒ ์ ๋๋ก ์์๋ณด์.
1. ์ค์ ์ง์ฅ์์์ ํด๋ฐฉ: `tsconfig.json`์ด ํ์ ์๋ค!
Node.js์์ ํ์
์คํฌ๋ฆฝํธ ํ๋ก์ ํธ๋ฅผ ์์ํ ๋ ๊ฐ์ฅ ๋จผ์ ํ๋ ์ผ์ด ๋ญ์ผ?
๋ฐ๋ก `tsconfig.json` ํ์ผ์ ๋ง๋๋ ๊ฑฐ์ง. ์ด ํ์ผ ์์๋ `target`, `module`, `strict`, `esModuleInterop`, `outDir` ๋ฑ๋ฑ... ์๋ง์ ์ต์
๋ค์ด ์ฐ๋ฆฌ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ณ ์์ด. ๊ฐ ์ต์
์ด ๋ญ ์๋ฏธํ๋์ง, ๋ด ํ๋ก์ ํธ์๋ ์ด๋ค ๊ฐ์ ์ค์ ํด์ผ ํ๋์ง ์์๋ด๋ ๊ฒ๋ง์ผ๋ก๋ ํ๋ฃจ๊ฐ ๋ค ๊ฐ. ๐คฏ
Deno๋ ์ด ๊ณ ํต์ ์์ ํ ์์ ๋ฒ๋ ธ์ด.
Deno๋ ์ด๋ฏธ ์น ํ์ค๊ณผ ์ต์ ์๋ฐ์คํฌ๋ฆฝํธ(ECMAScript) ๊ธฐ๋ฅ์ ์ต์ ํ๋ ๊ธฐ๋ณธ ์ปดํ์ผ๋ฌ ์ต์
์ ๋ด์ฅํ๊ณ ์์ด. ๊ทธ๋์ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ `tsconfig.json` ํ์ผ์ด ์์ ํ์๊ฐ ์์ด.
๊ทธ๋ฅ `.ts` ํ์ผ์ ๋ง๋ค๊ณ , ์ต์ ํ์ ์คํฌ๋ฆฝํธ ๋ฌธ๋ฒ์ผ๋ก ๋ง์๊ป ์ฝ๋ฉํ๋ฉด ๋ผ. Deno๊ฐ ์์์ ๋ค ์ฒ๋ฆฌํด์ค ํ ๋๊น. ์ด๊ฑด ๋ง์น ์ด์ ๋ฉดํ๋ฅผ ๋ฐ์๋ง์ ํ์ต์ ์์จ์ฃผํ ์๋์ฐจ๋ฅผ ๋ฐ์ ๊ธฐ๋ถ์ด์ผ. ์ฐ๋ฆฌ๋ ๊ทธ๋ฅ ๋ชฉ์ ์ง๋ง ์ ๋ ฅํ๋ฉด ๋๋ ๊ฑฐ์ง.
๋ฌผ๋ก ์์ฃผ ํน๋ณํ ๊ฒฝ์ฐ, ์๋ฅผ ๋ค์ด JSX(React ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ฌ์ฉํ๋)์ ๋์ ๋ฐฉ์์ ๋ฐ๊พธ๊ฑฐ๋ ์คํ์ ์ธ ๋ฐ์ฝ๋ ์ดํฐ ๊ธฐ๋ฅ์ ์ฐ๊ณ ์ถ์ ๋๋ ์ปดํ์ผ๋ฌ ์ต์ ์ ์์ ํด์ผ ํ ์๋ ์์ด. ๊ทธ๋ด ๋ ํ๋ก์ ํธ ๋ฃจํธ์ `deno.json` ๋๋ `deno.jsonc` ํ์ผ์ ๋ง๋ค๊ณ `compilerOptions` ํค๋ฅผ ์ถ๊ฐํด์ ์ํ๋ ์ค์ ์ ๋ฎ์ด์ธ ์ ์์ด. ํ์ง๋ง ์ด๊ฑด ์ ๋ง ์์ธ์ ์ธ ๊ฒฝ์ฐ๊ณ , 95% ์ด์์ ํ๋ก์ ํธ์์๋ ํ์ ์๋ค๋ ์ฌ์ค!
// deno.jsonc
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "react"
}
}
2. ์๋ฒฝํ๊ฒ ํ์ดํ๋ Deno API: ์๋์์ฑ์ ์ถ๋ณต
Deno์ ๋ ๋ค๋ฅธ ๊ฐ๋ ฅํจ์ ๋ฐํ์ ์์ฒด์ ๋ชจ๋ API๊ฐ ์ฒ์๋ถํฐ ํ์ ์คํฌ๋ฆฝํธ๋ก ์์ฑ๋๊ณ ์๋ฒฝํ๊ฒ ํ์ดํ(Typing)๋์ด ์๋ค๋ ์ ์ด์ผ. ์ด๊ฒ ์ ์ค์ํ๋๋ฉด, ์ฐ๋ฆฌ๊ฐ ์ฝ๋๋ฅผ ์์ฑํ ๋ ๊ฐ๋ฐ ๋๊ตฌ(ํนํ VS Code)์ ์์ฒญ๋ ๋์์ ๋ฐ์ ์ ์๊ธฐ ๋๋ฌธ์ด์ผ.
์๋ฅผ ๋ค์ด, Deno๋ก ํ์ผ์ ์ฝ๋ ์ฝ๋๋ฅผ ์์ฑํ๋ค๊ณ ์์ํด๋ด.
์๋ํฐ์ `Deno.` ์ด๋ผ๊ณ ์
๋ ฅํ๋ ์๊ฐ, Deno๊ฐ ์ ๊ณตํ๋ ๋ชจ๋ ๊ธฐ๋ฅ๋ค(`readFile`, `writeFile`, `serve`, `test` ๋ฑ)์ด ๋ชฉ๋ก์ผ๋ก ์ซ ๋ . ๊ทธ๋ฆฌ๊ณ `Deno.readFile`์ ์ ํํ๋ฉด, ์ด ํจ์๊ฐ ์ด๋ค ์ธ์(ํ์ผ ๊ฒฝ๋ก)๋ฅผ ํ์๋ก ํ๊ณ , ์ด๋ค ํ์
(Promise<Uint8Array>)์ ๊ฐ์ ๋ฐํํ๋์ง ๋ช
ํํ๊ฒ ๋ณด์ฌ์ค.
์ด๊ฑด ๊ทธ๋ฅ ํธ์ ๊ธฐ๋ฅ์ด ์๋์ผ. ๊ฐ๋ฐ์ ํจ๋ฌ๋ค์์ ๋ฐ๊พธ๋ ๊ฑฐ์ผ.
๋ ์ด์ ๋ฌธ์๋ฅผ ์ฐพ์ ํค๋งฌ ํ์๊ฐ ์๊ณ , ํจ์์ ๋ฐํ ๊ฐ์ด ๋ญ์ง ๋ชฐ๋ผ์ `console.log`๋ฅผ ์ฐ์ด๋ณผ ํ์๋ ์์ด. ์ฝ๋๋ฅผ ์์ฑํ๋ ๋์์ ์ค์๊ฐ ์ค์ด๋ค๊ณ , ์์ฐ์ฑ์ ํญ๋ฐ์ ์ผ๋ก ์ฆ๊ฐํด. ๋ง์น ๋ด๋น๊ฒ์ด์
์ด ์ค์๊ฐ ๊ตํต ์ ๋ณด๋ฅผ ๋ฐ์ํด์ ์ต์ ์ ๊ฒฝ๋ก๋ฅผ ์๋ดํด์ฃผ๋ ๊ฒ๊ณผ ๊ฐ์.
Node.js์์๋ `@types/node`๋ผ๋ ๋ณ๋์ ํ์ ์ ์ ํจํค์ง๋ฅผ ์ค์นํด์ผ ์ด๋ฐ ๊ธฐ๋ฅ์ ์จ์ ํ ๋๋ฆด ์ ์์์ง๋ง, Deno์์๋ ์ด ๋ชจ๋ ๊ฒ์ด ๊ธฐ๋ณธ์ด์ผ. Deno๋ ํ์ด๋ ๋๋ถํฐ ํ์ ์คํฌ๋ฆฝํธ DNA๋ฅผ ๊ฐ์ง๊ณ ํ์ด๋ ๊ฑฐ์ง.
3. ์๊ฒฉ ํ์ ์ฒดํฌ: URL๋ก ์ํฌํธํ ๋ชจ๋๋ ์์ ํ๊ฒ
Deno์ ๊ฐ์ฅ ํฐ ํน์ง ์ค ํ๋๊ฐ URL๋ก ๋ชจ๋์ ์ํฌํธํ๋ ๊ฑฐ๋ผ๊ณ ํ์ง?
์ฌ๊ธฐ์ ํ์
์คํฌ๋ฆฝํธ์์ ์๋์ง๊ฐ ๋ ํ ๋ฒ ํญ๋ฐํด. Deno๋ URL๋ก ๊ฐ์ ธ์จ ์๊ฒฉ ๋ชจ๋์ ํ์
์ ๋ณด๊น์ง ์๋ฒฝํ๊ฒ ๋ถ์ํ๊ณ ์ฒดํฌํด์ค.
์๋ฅผ ๋ค์ด, ์ ๋ช ํ Deno ์น ํ๋ ์์ํฌ์ธ `Oak`๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํด๋ณด์.
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
const router = new Router();
router.get("/", (ctx) => {
// ctx ๊ฐ์ฒด์ ๋ญ๊ฐ ๋ค์ด์๋์ง ์ด๋ป๊ฒ ์์ง?
// ํ์
์คํฌ๋ฆฝํธ ๋๋ถ์ ctx์ ํ์
์ ์๋ฒฝํ๊ฒ ์ถ๋ก ํ ์ ์๋ค!
ctx.response.body = "Hello Oak!";
});
// ๋ง์ฝ ์กด์ฌํ์ง ์๋ ์์ฑ์ ์ ๊ทผํ๋ ค๊ณ ํ๋ฉด?
router.get("/error", (ctx) => {
// ctx.response.boddy = "Oops!"; // 'boddy'๋ผ๋ ์์ฑ์ ์์ด์! -> ํ์
์๋ฌ ๋ฐ์!
});
app.use(router.routes());
app.use(router.allowedMethods());
await app.listen({ port: 8000 });
์ ์ฝ๋์์ `ctx`๋ผ๋ ์ปจํ
์คํธ ๊ฐ์ฒด๋ฅผ ๋ด๋ด.
์ฐ๋ฆฌ๋ `oak` ๋ชจ๋์ ์์ค ์ฝ๋๋ฅผ ์ง์ ๋ณด์ง ์์์ง๋ง, Deno์ VS Code๋ `https://deno.land/x/oak/mod.ts` ํ์ผ์ ๋ถ์ํด์ `ctx` ๊ฐ์ฒด๊ฐ ์ด๋ค ์์ฑ(`request`, `response` ๋ฑ)๊ณผ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๋์ง ์ ํํ ์๊ณ ์์ด. ๊ทธ๋์ `ctx.response.body`๋ ์๋์์ฑ์ด ๋์ง๋ง, ๋ง์ฝ ์ฐ๋ฆฌ๊ฐ `ctx.response.boddy`๋ผ๊ณ ์คํ๋ฅผ ๋ด๋ฉด ์ฆ์ "๊ทธ๋ฐ ์์ฑ์ `response` ๊ฐ์ฒด์ ์กด์ฌํ์ง ์์ต๋๋ค."๋ผ๊ณ ๋นจ๊ฐ ์ค์ ๊ทธ์ด์ค.
์ด๊ฑด ์ ๋ง ๋๋จํ ๊ธฐ๋ฅ์ด์ผ. ์ธํฐ๋ท ๋๋จธ์ ์๋ ์ฝ๋๊น์ง ๋ง์น ๋ด ๋ก์ปฌ ํ๋ก์ ํธ์ ์๋ ์ฝ๋์ฒ๋ผ ํ์ ์ ์๋ฒฝํ๊ฒ ๊ฒ์ฌํด์ฃผ๋ ๊ฑฐ์ง. ๋๋ถ์ ์ฐ๋ฆฌ๋ `npm`์์ ๋ค์ด๋ก๋ํ ํจํค์ง๋ , URL๋ก ๊ฐ์ ธ์จ ๋ชจ๋์ด๋ ์๊ด์์ด ์ผ๊ด๋๊ณ ์์ ์ ์ธ ๊ฐ๋ฐ ๊ฒฝํ์ ์ ์งํ ์ ์์ด. ์ฌ๋ฅ์ ๊ณต์ ํ๋ ํ๋ซํผ **์ฌ๋ฅ๋ท**์์ ๋ค์ํ ์ ๋ฌธ๊ฐ๋ค์ ์คํฌ์ ๋ฏฟ๊ณ ํ์ฉํ๋ ๊ฒ์ฒ๋ผ, Deno์์๋ ์ ์ธ๊ณ ๊ฐ๋ฐ์๋ค์ด ๋ง๋ ๋ชจ๋์ ํ์ ๊ฑฑ์ ์์ด ์์ ํ๊ฒ ๊ฐ์ ธ๋ค ์ธ ์ ์๋ ๊ฑฐ์ผ.
4. `deno test`์ ํ์ ์คํฌ๋ฆฝํธ: ๋ ๊ฒฌ๊ณ ํ ํ ์คํธ ์ฝ๋ ์์ฑ
Deno์ ๋ด์ฅ๋ ํ
์คํธ ๋ฌ๋ `deno test` ์ญ์ ํ์
์คํฌ๋ฆฝํธ์ ํ์์ ์ธ ๊ถํฉ์ ์๋ํด.
ํ
์คํธ ์ฝ๋๋ ๋น์ฐํ ํ์
์คํฌ๋ฆฝํธ๋ก ์์ฑํ ์ ์๊ณ , ์ด๋ฅผ ํตํด ํจ์ฌ ๋ ๋ช
ํํ๊ณ ๊ฒฌ๊ณ ํ ํ
์คํธ๋ฅผ ๋ง๋ค ์ ์์ด.
์๋ฅผ ๋ค์ด, ๋ ์ซ์๋ฅผ ๋ํ๋ ๊ฐ๋จํ ํจ์๋ฅผ ํ ์คํธํ๋ค๊ณ ํด๋ณด์.
// add.ts
export function add(a: number, b: number): number {
return a + b;
}
// add.test.ts
import { assertEquals } from "https://deno.land/std@0.224.0/assert/mod.ts";
import { add } from "./add.ts";
Deno.test("add ํจ์๋ ๋ ์ซ์๋ฅผ ์ ํํ ๋ํด์ผ ํ๋ค", () => {
const result = add(2, 3);
assertEquals(result, 5);
});
Deno.test("add ํจ์์ ๋ฌธ์๋ฅผ ๋ฃ์ผ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?", () => {
// const result = add(2, "3"); // ์ด ์ค์ ํ์
์๋ฌ ๋๋ฌธ์ ์ปดํ์ผ์กฐ์ฐจ ๋์ง ์๋๋ค!
// ๋๋ถ์ ์๋ชป๋ ํ
์คํธ๋ฅผ ์ฌ์ ์ ๋ฐฉ์งํ ์ ์๋ค.
});
ํฐ๋ฏธ๋์์ `deno test`๋ฅผ ์คํํ๋ฉด Deno๋ `*.test.ts`, `*_test.ts` ๊ฐ์ ํจํด์ ํ์ผ์ ์ฐพ์์ ํ ์คํธ๋ฅผ ์คํํด์ค. ์ ์ฝ๋์์ ์ค์ํ ์ ์ `add` ํจ์๋ `number` ํ์ ์ ์ธ์๋ง ๋ฐ๋๋ก ์ ์๋์ด ์๋ค๋ ๊ฑฐ์ผ. ๋ง์ฝ ์ฐ๋ฆฌ๊ฐ ์ค์๋ก ํ ์คํธ ์ฝ๋์์ `add(2, "3")`์ฒ๋ผ ์๋ชป๋ ํ์ ์ ์ธ์๋ฅผ ์ ๋ฌํ๋ ค๊ณ ํ๋ฉด, ํ ์คํธ๋ฅผ ์คํํ๊ธฐ๋ ์ ์ ํ์ ์คํฌ๋ฆฝํธ๊ฐ "์ด๋ด, `add` ํจ์๋ ์ซ์๋ฅผ ๊ธฐ๋ํ๊ณ ์๋๋ฐ ์ ๋ฌธ์๋ฅผ ๋ฃ๋ ๊ฑฐ์ผ?"๋ผ๋ฉฐ ์๋ฌ๋ฅผ ๋ฐ์์์ผ.
์ด์ฒ๋ผ ํ์ ์คํฌ๋ฆฝํธ๋ ํ ์คํธ ์ฝ๋์ ์ ๋ขฐ๋๋ฅผ ๋์ฌ์ฃผ๊ณ , ์๋ชป๋ ํ ์คํธ ์ผ์ด์ค๋ฅผ ์์ฑํ๋ ์ค์๋ฅผ ์์ฒ์ ์ผ๋ก ์ฐจ๋จํด์ค. ๋ฒ๊ทธ๋ฅผ ์ก๊ธฐ ์ํด ํ ์คํธ๋ฅผ ํ๋ ๊ฑด๋ฐ, ๊ทธ ํ ์คํธ ์ฝ๋ ์์ฒด์ ๋ฒ๊ทธ๊ฐ ์๋ค๋ฉด ์ ๋ง ๋๊ฐํ๊ฒ ์ง? Deno์ ํ์ ์คํฌ๋ฆฝํธ๋ ์ด๋ฐ ์ํฉ์ ๋ฏธ์ฐ์ ๋ฐฉ์งํด์ฃผ๋ ์ต๊ณ ์ ์์ ์ฅ์น์ผ.
๊ฒฐ๋ก ์ ์ผ๋ก, Deno์๊ฒ ํ์
์คํฌ๋ฆฝํธ๋ ๊ทธ์ '์ง์ํ๋ ์ธ์ด' ์ค ํ๋๊ฐ ์๋์ผ.
Deno์ ๋ณด์, ๋ชจ๋ ์์คํ
, ๋ด์ฅ ๋๊ตฌ ๋ฑ ๋ชจ๋ ํต์ฌ ๊ธฐ๋ฅ์ด ํ์
์คํฌ๋ฆฝํธ์ ์ ๊ธฐ์ ์ผ๋ก ๊ฒฐํฉํ์ฌ ๊ฐ๋ฐ์์๊ฒ ์ต๊ณ ์ ๊ฒฝํ์ ์ ์ฌํ๋๋ก ์ค๊ณ๋์์ด. Deno๋ฅผ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ๊ณง ํ์
์คํฌ๋ฆฝํธ์ ํ์ 200% ํ์ฉํ๋ค๋ ๊ฒ๊ณผ ๊ฐ์ ์๋ฏธ์ผ. ์ด ํ์์ ์ธ ์กฐํฉ, ์ ์จ๋ณผ ์ด์ ๊ฐ ์๊ฒ ์ง? ๐
๐ Deno ์ํ๊ณ ํํ: ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์๋ํํฐ ๋ชจ๋
์ข์ ๋ฐํ์์ ๊ทธ ์์ฒด๋ก๋ ํ๋ฅญํด์ผ ํ์ง๋ง, ๊ฒฐ๊ตญ ์ผ๋ง๋ ํ๋ถํ๊ณ ์ธ๋งํ '๋ถํ(๋ชจ๋)'๋ค์ ์ ๊ณตํ๋๋์ ๋ฐ๋ผ ์ฑํจ๊ฐ ๊ฐ๋ ค. Node.js๊ฐ ์ฑ๊ณตํ ์ ์์๋ ๊ฐ์ฅ ํฐ ์ด์ ์ค ํ๋๋ `npm`์ด๋ผ๋ ๊ฑฐ๋ํ ์ํ๊ณ ๋๋ถ์ด์์ง. Deno๋ ์ด ์ํ๊ณ ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ํ๊ณ ์์๊น? Deno์ ๋ฌด๊ธฐ๊ณ , ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์๋ํํฐ ๋ชจ๋์ ์ธ๊ณ๋ก ๋ ๋๋ณด์. ๐บ๏ธ
1. Deno์ ๊ณต์ ๋ณด๋ฌผ์ฐฝ๊ณ : ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ (Deno Standard Library)
Deno๋ `deno.land/std` ๋ผ๋ ํน๋ณํ ์ฃผ์๋ฅผ ํตํด ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ(Standard Library)๋ฅผ ์ ๊ณตํด. ์ด๊ฑด Deno ํ์ด ์ง์ ๋ง๋ค๊ณ ๊ด๋ฆฌํ๋, ํ์ง์ด ๋ณด์ฅ๋ ๊ณต์ ๋ชจ๋ ๋ชจ์์ง์ด์ผ. Node.js์ `fs`, `path`, `http` ๊ฐ์ ๋ด์ฅ ๋ชจ๋๊ณผ ๋น์ทํ ์ญํ ์ ํ์ง๋ง, ๋ช ๊ฐ์ง ์ค์ํ ์ฐจ์ด์ ์ด ์์ด.
- ์ธ๋ถ ๋ชจ๋ ํํ: Node.js์ ๋ด์ฅ ๋ชจ๋์ ๋ฐํ์์ ํฌํจ๋์ด ์์ง๋ง, Deno์ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ธ๋ถ ๋ชจ๋์ฒ๋ผ URL๋ก ์ํฌํธํด์ ์ฌ์ฉํด. ์ด๋ Deno ๋ฐํ์ ์์ฒด์ ํฌ๊ธฐ๋ฅผ ์๊ณ ๊ฐ๋ณ๊ฒ ์ ์งํ๋ ๋ฐ ๋์์ด ๋ผ.
- ๋ฒ์ ๋ช
์: URL์
@0.224.0์ฒ๋ผ ๋ฒ์ ์ ๋ช ์ํด์ ์ฌ์ฉํด์ผ ํด. ์ด๋ฅผ ํตํด ๋ด ํ๋ก์ ํธ๊ฐ ํน์ ๋ฒ์ ์ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์กดํ๋๋ก ๋ง๋ค ์ ์์ด. ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ ๋ฐ์ดํธ๋์ด๋ ๋ด ์ฝ๋๊ฐ ๊ฐ์๊ธฐ ๋ง๊ฐ์ง๋ ์ผ์ ๋ฐฉ์งํ ์ ์์ง. (๋ฒ์ ๊ด๋ฆฌ๊ฐ ํจ์ฌ ๋ช ํํด!) - ์๊ฒฉํ ์ฝ๋ ๋ฆฌ๋ทฐ: Deno์ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํฌํจ๋๋ ๋ชจ๋ ์ฝ๋๋ Deno ํต์ฌ ํ์ ์ฒ ์ ํ ๋ฆฌ๋ทฐ๋ฅผ ๊ฑฐ์ณ. ๊ทธ๋์ ์ฐ๋ฆฌ๋ ์ด ๋ชจ๋๋ค์ ์์ฌํ๊ณ ์ฌ์ฉํ ์ ์์ด.
ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์๋ ์ ๋ง ์ ์ฉํ ๊ฒ๋ค์ด ๋ง์. ๋ช ๊ฐ์ง๋ง ๋ง๋ณด๊ธฐ๋ก ๋ณผ๊น?
// ํ์ผ ์์คํ
๋ค๋ฃจ๊ธฐ (fs)
import { ensureDir } from "https://deno.land/std@0.224.0/fs/ensure_dir.ts";
await ensureDir("./my_dir"); // my_dir ๋๋ ํ ๋ฆฌ๊ฐ ์์ผ๋ฉด ๋ง๋ค์ด์ค!
// ๊ฒฝ๋ก ๋ค๋ฃจ๊ธฐ (path)
import { join } from "https://deno.land/std@0.224.0/path/mod.ts";
const fullPath = join("/users/deno", "project", "file.ts"); // OS์ ๋ง์ถฐ ๊ฒฝ๋ก๋ฅผ ํฉ์ณ์ค.
// HTTP ์๋ฒ ๋ง๋ค๊ธฐ (http)
import { serve } from "https://deno.land/std@0.224.0/http/server.ts";
// ์ด๊ฑด ์์์ ์ด๋ฏธ ์จ๋ดค์ง?
// ํ๊ฒฝ ๋ณ์ ๋ค๋ฃจ๊ธฐ (dotenv)
import { load } from "https://deno.land/std@0.224.0/dotenv/mod.ts";
const env = await load(); // .env ํ์ผ์ ๋ณ์๋ค์ ๊ฐ์ฒด๋ก ๋ถ๋ฌ์์ค.
const apiKey = env["API_KEY"];
// Assertion (ํ
์คํธํ ๋ ์ ์ฉ)
import { assertEquals } from "https://deno.land/std@0.224.0/assert/mod.ts";
assertEquals(1 + 1, 2);
์ด ์ธ์๋ CSV ํ์ฑ, ์น์์ผ, UUID ์์ฑ ๋ฑ ๊ฐ๋ฐ์ ๊ผญ ํ์ํ ๋๋ถ๋ถ์ ๊ธฐ๋ฅ๋ค์ด ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํฌํจ๋์ด ์์ด. ์ฌ๋งํ ๊ธฐ๋ฅ์ ์ธ๋ถ ๋ชจ๋์ ์ฐพ๊ธฐ ์ ์ ๋จผ์ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์๋์ง ํ์ธํด๋ณด๋ ์ต๊ด์ ๋ค์ด๋ ๊ฒ ์ข์. ๋ง์น ์๋ฆฌ๋ฅผ ์์ํ๊ธฐ ์ ์ ๋์ฅ๊ณ ์ ์๋ ๊ธฐ๋ณธ ์ฌ๋ฃ๋ถํฐ ํ์ธํ๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ผ. ๐
2. ์ ์ธ๊ณ ๊ฐ๋ฐ์๋ค์ ๋์ดํฐ: ์๋ํํฐ ๋ชจ๋ (deno.land/x)
ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ณต์ ๋ ์ํผ๋ผ๋ฉด, ์๋ํํฐ ๋ชจ๋์ ์ ์ธ๊ณ ์ ฐํ๋ค์ด ๊ฐ์์ ๋น๋ฒ์ ๊ณต์ ํ๋ ๊ฑฐ๋ํ ๋ ์ํผ ๋ถ๊ณผ ๊ฐ์. Deno๋ `deno.land/x` ๋ผ๋ ๊ณต์ ์๋ํํฐ ๋ชจ๋ ํธ์คํ ์๋น์ค๋ฅผ ์ ๊ณตํด. `npm`๊ณผ ๋น์ทํ ์ญํ ์ ํ์ง๋ง, ํจํค์ง๋ฅผ ์ง์ ์ ์ฅํ๋ ๊ฒ ์๋๋ผ GitHub ๊ฐ์ ๊ณณ์ ์๋ ์ฝ๋ ์ ์ฅ์์ ๋ํ '๋ฐ๋ก๊ฐ๊ธฐ'๋ฅผ ์ ๊ณตํ๋ ๋ฐฉ์์ด์ผ.
`deno.land/x`์ ์ฌ๋ผ์จ ๋ชจ๋๋ค์ ๋๊ตฌ๋ ์ฝ๊ฒ URL๋ก ๊ฐ์ ธ๋ค ์ธ ์ ์์ด.
// Express.js์ ๋น์ทํ ๊ฒฝํ์ ์ ๊ณตํ๋ ์น ํ๋ ์์ํฌ, Oak
import { Application } from "https://deno.land/x/oak@v16.0.0/mod.ts";
// ORM(๊ฐ์ฒด ๊ด๊ณ ๋งคํ) ๋ผ์ด๋ธ๋ฌ๋ฆฌ, DenoDB
import { Database, Model, DataTypes } from "https://deno.land/x/denodb@v1.4.0/mod.ts";
`deno.land/x`์ ์ฅ์ ์ ๋ค์๊ณผ ๊ฐ์.
- ์ ๋ขฐ์ฑ: GitHub ์ ์ฅ์์ ํ๊ทธ(๋ฒ์ )๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฝ๋๋ฅผ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์, ํ๋ฒ ๋ฑ๋ก๋ ๋ฒ์ ์ ์ฝ๋๋ ์ ๋ ๋ณ๊ฒฝ๋์ง ์์. (Immutable)
- ๊ฐ๋ ์ฑ: `deno.land/x/oak` ์ฒ๋ผ ์งง๊ณ ๊ธฐ์ตํ๊ธฐ ์ฌ์ด URL์ ์ ๊ณตํด.
- ๊ฒ์ ๋ฐ ๋ฌธ์: ์น์ฌ์ดํธ์์ ๋ชจ๋์ ์ฝ๊ฒ ๊ฒ์ํ ์ ์๊ณ , ์๋์ผ๋ก ์์ฑ๋ ๋ฌธ์๋ฅผ ๋ฐ๋ก ํ์ธํ ์ ์์ด.
์์ ์๋ ๊ทธ๋ฌ์ด. ์ด๊ฒ Deno์ ๊ฐ์ฅ ํฐ ์ฝ์ ์ค ํ๋์์ง. ํ์ง๋ง Deno ํ๋ ์ด ๋ฌธ์ ๋ฅผ ์๊ณ ์์๊ณ , ์์ฃผ ๋ฉ์ง ํด๊ฒฐ์ฑ ์ ๋ด๋จ์ด! ๋ฐ๋ก npm specifier์ผ. ์ด์ Deno ์ฝ๋์์ `npm:` ์ ๋์ฌ๋ฅผ ์ฌ์ฉํด์ ์๋ง์ npm ํจํค์ง๋ฅผ ์ง์ ์ํฌํธํ ์ ์์ด!
// npm์ ์๋ ์ ๋ช
ํ ์ ํธ๋ฆฌํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ, lodash๋ฅผ Deno์์ ๋ฐ๋ก ์ฌ์ฉํ๊ธฐ
import lodash from "npm:lodash";
console.log(lodash.capitalize("hello world")); // -> "Hello world"
// React๋ Deno์์ ๋ฐ๋ก ์ธ ์ ์์ด!
import React from "npm:react";
import ReactDOM from "npm:react-dom/client";
์ด ๊ธฐ๋ฅ ๋๋ถ์ Deno๋ ๊ฑฐ๋ํ Node.js/npm ์ํ๊ณ๋ฅผ ํ์ ์๊ฒ ๋์์ด. Deno์ ์ฅ์ ์ ๊ทธ๋๋ก ๋๋ฆฌ๋ฉด์, ํ์ํ ๋ ๊ฒ์ฆ๋ npm ํจํค์ง๋ฅผ ๊ฐ์ ธ๋ค ์ธ ์ ์๊ฒ ๋ ๊ฑฐ์ง. ์ด๊ฑด ์ ๋ง '๊ฒ์ ์ฒด์ธ์ '๋ผ๊ณ ํ ์ ์์ด. ๐
3. ํ๋ก์ ํธ์ ์ฒญ์ฌ์ง: `deno.json`๊ณผ Import Maps
URL๋ก ๋ชจ๋์ ์ํฌํธํ๋ ๋ฐฉ์์ ์ง๊ด์ ์ด์ง๋ง, ํ๋ก์ ํธ๊ฐ ์ปค์ง๋ฉด ๋ช ๊ฐ์ง ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์์ด.
๋ชจ๋ ํ์ผ์ ๊ธธ๊ณ ๋ณต์กํ URL์ ๋ฐ๋ณตํด์ ์จ์ผ ํ๊ณ , ์์กดํ๋ ๋ชจ๋์ ๋ฒ์ ์ ํ๊บผ๋ฒ์ ์
๋ฐ์ดํธํ๊ธฐ๋ ๊น๋ค๋กญ์ง. `package.json`์ด ๊ทธ๋ฆฌ์์ง๋ ์๊ฐ์ด์ผ.
Deno๋ ์ด ๋ฌธ์ ๋ฅผ Import Maps๋ผ๋ ๊ธฐ๋ฅ์ผ๋ก ํด๊ฒฐํด.
ํ๋ก์ ํธ ๋ฃจํธ์ `deno.json` ๋๋ `deno.jsonc` ํ์ผ์ ๋ง๋ค๊ณ , ๊ทธ ์์ `imports`๋ผ๋ ๊ฐ์ฒด๋ฅผ ์ ์ํ๋ ๊ฑฐ์ผ. ์ฌ๊ธฐ์ ๋ชจ๋์ '๋ณ๋ช
'๊ณผ ์ค์ URL์ ๋งคํํด๋๋ฉด, ์ฝ๋์์๋ ์งง์ ๋ณ๋ช
์ผ๋ก ๋ชจ๋์ ์ํฌํธํ ์ ์์ด.
์๋ฅผ ๋ค์ด, `deno.jsonc` ํ์ผ์ ์ด๋ ๊ฒ ์์ฑํ๋ ๊ฑฐ์ผ.
// deno.jsonc
{
"imports": {
"std/": "https://deno.land/std@0.224.0/",
"oak": "https://deno.land/x/oak@v16.0.0/mod.ts",
"react": "npm:react@18.2.0"
}
}
์ด๋ ๊ฒ ์ค์ ํด๋๋ฉด, ์ด์ ์ฐ๋ฆฌ ์ฝ๋์์๋ ์ด๋ ๊ฒ ๊น๋ํ๊ฒ ๋ชจ๋์ ์ํฌํธํ ์ ์์ด.
// main.ts
import { Application } from "oak"; // "oak"๋ deno.jsonc์ ์ ์๋ URL๋ก ํด์๋๋ค.
import { join } from "std/path/mod.ts"; // "std/" ์ญ์ ๋ง์ฐฌ๊ฐ์ง!
import React from "react";
const app = new Application();
// ...
์ด๋? ์ฝ๋๊ฐ ํจ์ฌ ๊นจ๋ํด์ก์ง?
๋ง์ฝ `oak` ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฒ์ ์ ์
๋ฐ์ดํธํ๊ณ ์ถ๋ค๋ฉด, `deno.jsonc` ํ์ผ์ URL ํ ์ค๋ง ์์ ํ๋ฉด ํ๋ก์ ํธ ์ ์ฒด์ ์ ์ฉ๋ผ. ์์กด์ฑ ๊ด๋ฆฌ๊ฐ ํจ์ฌ ์ฌ์์ง๋ ๊ฑฐ์ง. `deno.json` ํ์ผ์ `package.json`์ฒ๋ผ ํ๋ก์ ํธ์ ์ค์ , ์คํฌ๋ฆฝํธ ์คํ (`deno task`), ๋ฆฐํฐ/ํฌ๋งทํฐ ์ค์ ๋ฑ ๋ค์ํ ์ญํ ์ ํ๋ Deno ํ๋ก์ ํธ์ ์ฌ์ฅ๊ณผ๋ ๊ฐ์ ํ์ผ์ด์ผ.
Deno์ ์ํ๊ณ๋ Node.js๋งํผ ์ค๋๋์ง๋ ์์์ง๋ง, ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๋ ๋ ๋ ํ ๊ธฐ๋ฐ ์์ `deno.land/x`๋ผ๋ ํ๋ฐํ ๋์ดํฐ, ๊ทธ๋ฆฌ๊ณ `npm:` ํธํ์ฑ์ด๋ผ๋ ๊ฐ๋ ฅํ ๋ฌด๊ธฐ๊น์ง ๊ฐ์ถ๋ฉฐ ๋น ๋ฅด๊ฒ ์ฑ์ฅํ๊ณ ์์ด. ์ด์ "Deno๋ ์ธ๋งํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์ด์..."๋ผ๋ ๋ง์ ์๋ง์ด ๋ ๊ฑฐ์ง. ์ด์ ์ด ์ฌ๋ฃ๋ค์ ๊ฐ์ง๊ณ ์ง์ง ์๋ฆฌ๋ฅผ ๋ง๋ค์ด ๋ณผ ์๊ฐ์ด์ผ! ๋ค์ ์ฑํฐ์์๋ ์ค์ ๋ก ๊ฐ๋จํ REST API ์๋ฒ๋ฅผ ๋ง๋ค์ด๋ณด๋ฉด์ Deno์ ํ์ ์คํฌ๋ฆฝํธ์ ์ค์ ํ์ฉ๋ฒ์ ์ตํ๋ณผ๊ฒ. ๐จโ๐ณ
๐ ์ค์ ! Deno์ TypeScript๋ก REST API ๋ง๋ค๊ธฐ (feat. Oak)
์ด๋ก ๊ณต๋ถ๋ ์ถฉ๋ถํ ํ์ด. ์ด์ ์ง์ง ์ค๋ ฅ์ ๋ณด์ฌ์ค ์๊ฐ์ด์ผ! ๐งโ๐ป
์ง๊ธ๊น์ง ๋ฐฐ์ด Deno์ ํ์
์คํฌ๋ฆฝํธ ์ง์์ ์ด๋์ํด์ ๊ฐ๋จํ 'ํ ์ผ ๋ชฉ๋ก(Todo List)'์ ๊ด๋ฆฌํ๋ REST API ์๋ฒ๋ฅผ ๋ง๋ค์ด ๋ณผ ๊ฑฐ์ผ. ์ด ๊ณผ์ ์ ๋ฐ๋ผ์ค๋ฉด Deno ํ๋ก์ ํธ์ ๊ตฌ์กฐ๋ ์ด๋ป๊ฒ ์ก๋์ง, ์น ํ๋ ์์ํฌ๋ ์ด๋ป๊ฒ ์ฐ๋์ง, ํ์
์คํฌ๋ฆฝํธ๋ก ์ด๋ป๊ฒ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ์ ์ํ๋์ง ํ์คํ๊ฒ ๊ฐ์ ์ก์ ์ ์์ ๊ฑฐ์ผ.
์ฐ๋ฆฌ๋ ์น ํ๋ ์์ํฌ๋ก Oak๋ฅผ ์ฌ์ฉํ ๊ฑฐ์ผ. Oak๋ Node.js์ Express.js์ ์๊ฐ์ ๋ฐ์ ๋ง๋ค์ด์ง Deno์ฉ ๋ฏธ๋ค์จ์ด ํ๋ ์์ํฌ์ผ. Express๋ฅผ ์จ๋ณธ ์น๊ตฌ๋ค์ด๋ผ๋ฉด ์์ฃผ ์น์ํ๊ฒ ๋๊ปด์ง ๊ฑฐ์ผ.
1. ํ๋ก์ ํธ ๊ตฌ์กฐ ์ก๊ธฐ ๋ฐ ์์กด์ฑ ์ค์
๋จผ์ ํ๋ก์ ํธ ํด๋๋ฅผ ํ๋ ๋ง๋ค๊ณ , ๊ทธ ์์ ํ์ํ ํ์ผ๋ค์ ์์ฑํ์.
ํฐ๋ฏธ๋์์ ์๋ ๋ช
๋ น์ด๋ฅผ ์ฐจ๋ก๋๋ก ์
๋ ฅํด ๋ด.
mkdir deno-todo-api
cd deno-todo-api
touch main.ts routes.ts controllers.ts types.ts deno.jsonc
๊ฐ ํ์ผ์ ์ญํ ์ ๋๋ต ์ด๋:
deno.jsonc: ํ๋ก์ ํธ ์ค์ ๋ฐ ์์กด์ฑ ๊ด๋ฆฌ (Import Maps)types.ts: ์ฐ๋ฆฌ ์ฑ์์ ์ฌ์ฉํ ๋ฐ์ดํฐ ํ์ ์ ์ (e.g., Todo)controllers.ts: ์ค์ ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ (e.g., ํ ์ผ ์ถ๊ฐ, ์ญ์ )routes.ts: URL ๊ฒฝ๋ก์ ์ปจํธ๋กค๋ฌ ํจ์ ์ฐ๊ฒฐ (๋ผ์ฐํ )main.ts: ์ ํ๋ฆฌ์ผ์ด์ ์ ์์์ . ์๋ฒ๋ฅผ ์ค์ ํ๊ณ ์คํ.
์ด์ `deno.jsonc` ํ์ผ์ ์ด๊ณ , ์ฐ๋ฆฌ ํ๋ก์ ํธ์ ํ์ํ ์์กด์ฑ์ Import Maps๋ก ์ ์ํ์.
// deno.jsonc
{
"imports": {
"oak": "https://deno.land/x/oak@v16.0.0/mod.ts",
"uuid": "https://deno.land/std@0.224.0/uuid/mod.ts"
}
}
์ฐ๋ฆฌ๋ ์น ํ๋ ์์ํฌ์ธ `oak`์, ๊ฐ ํ ์ผ ํญ๋ชฉ์ ๊ณ ์ ํ ID๋ฅผ ๋ถ์ฌํ๊ธฐ ์ํ `uuid` ๋ชจ๋์ ์ฌ์ฉํ ๊ฑฐ์ผ. ์ด๋ ๊ฒ ๋ฏธ๋ฆฌ ์ ์ํด๋๋ฉด ์ฝ๋์์๋ `import { ... } from "oak";` ์ฒ๋ผ ์งง๊ฒ ์ธ ์ ์์ง.
2. ํ์ ์ ์ํ๊ธฐ (`types.ts`)
๊ฐ์ฅ ๋จผ์ ํ ์ผ์ ์ฐ๋ฆฌ ์ ํ๋ฆฌ์ผ์ด์
์์ ๋ค๋ฃฐ ๋ฐ์ดํฐ์ '๋ชจ์'์ ์ ์ํ๋ ๊ฑฐ์ผ.
์ด๊ฒ ๋ฐ๋ก ํ์
์คํฌ๋ฆฝํธ์ ํต์ฌ์ด์ง! `types.ts` ํ์ผ์ ์ด๊ณ `Todo` ํ์
์ ์ ์ํ์.
// types.ts
// ํ ์ผ(Todo) ํญ๋ชฉ ํ๋์ ๋ชจ์์ ์ ์ํ๋ ์ธํฐํ์ด์ค
export interface Todo {
id: string; // ๊ณ ์ ์๋ณ์
title: string; // ํ ์ผ ๋ด์ฉ
isCompleted: boolean; // ์๋ฃ ์ฌ๋ถ
}
์ด๋ ๊ฒ `interface`๋ก ํ์ ์ ์ ์ํด๋๋ฉด, ์์ผ๋ก ์ฐ๋ฆฌ ์ฝ๋์์ `Todo` ๊ฐ์ฒด๋ฅผ ๋ค๋ฃฐ ๋ `id`, `title`, `isCompleted` ์์ฑ์ด ์ฌ๋ฐ๋ฅธ ํ์ ์ผ๋ก ์กด์ฌํ๋์ง ํ์ ์คํฌ๋ฆฝํธ๊ฐ ํญ์ ๊ฐ์ํด์ค ๊ฑฐ์ผ. ์คํ๋ ์๋ชป๋ ๋ฐ์ดํฐ ํ์ ์ผ๋ก ์ธํ ๋ฒ๊ทธ๋ฅผ ์์ฒ ๋ด์ํ ์ ์์ด.
3. ์ปจํธ๋กค๋ฌ ๋ก์ง ์์ฑํ๊ธฐ (`controllers.ts`)
์ด์ ์ค์ ๊ธฐ๋ฅ, ์ฆ ๋น์ฆ๋์ค ๋ก์ง์ ๋ด๋นํ ์ปจํธ๋กค๋ฌ๋ฅผ ๋ง๋ค ์ฐจ๋ก์ผ.
์ปจํธ๋กค๋ฌ๋ "๋ชจ๋ ํ ์ผ ๋ชฉ๋ก์ ๋ณด์ฌ์ค", "์๋ก์ด ํ ์ผ์ ์ถ๊ฐํด์ค" ๊ฐ์ ์์ฒญ์ ๋ฐ์์ ์ฒ๋ฆฌํ๋ ํจ์๋ค์ ๋ชจ์์ด์ผ. ์ง๊ธ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋์ ๊ฐ๋จํ ๋ฐฐ์ด์ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ ๊ฒ.
// controllers.ts
import { Todo } from "./types.ts";
import { v1 as uuidV1 } from "uuid"; // ๊ณ ์ ID ์์ฑ์ ์ํด uuid ๋ชจ๋ ์ฌ์ฉ
// ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋์ ์ฌ์ฉํ ๋ฉ๋ชจ๋ฆฌ ๋ด ๋ฐฐ์ด
let todos: Todo[] = [
{
id: "1",
title: "Deno ๊ณต๋ถํ๊ธฐ",
isCompleted: true,
},
{
id: "2",
title: "REST API ๋ง๋ค๊ธฐ",
isCompleted: false,
},
];
// GET /todos - ๋ชจ๋ ํ ์ผ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ
export const getTodos = ({ response }: { response: any }) => {
response.status = 200;
response.body = {
success: true,
data: todos,
};
};
// GET /todos/:id - ํน์ ํ ์ผ ๊ฐ์ ธ์ค๊ธฐ
export const getTodo = ({ params, response }: { params: { id: string }; response: any }) => {
const todo = todos.find((t) => t.id === params.id);
if (todo) {
response.status = 200;
response.body = {
success: true,
data: todo,
};
} else {
response.status = 404;
response.body = {
success: false,
message: "ํด๋น ID์ ํ ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค.",
};
}
};
// POST /todos - ์๋ก์ด ํ ์ผ ์ถ๊ฐํ๊ธฐ
export const addTodo = async ({ request, response }: { request: any; response: any }) => {
if (!request.hasBody) {
response.status = 400;
response.body = { success: false, message: "์์ฒญ ๋ณธ๋ฌธ์ด ๋น์ด์์ต๋๋ค." };
return;
}
const { title } = await request.body.json();
const newTodo: Todo = {
id: uuidV1.generate() as string, // ๊ณ ์ ID ์์ฑ
title,
isCompleted: false,
};
todos.push(newTodo);
response.status = 201;
response.body = {
success: true,
data: newTodo,
};
};
// PUT /todos/:id - ํ ์ผ ์์ ํ๊ธฐ
export const updateTodo = async ({ params, request, response }: { params: { id: string }; request: any; response: any }) => {
const todo = todos.find((t) => t.id === params.id);
if (todo) {
const { title, isCompleted } = await request.body.json();
const updatedTodos = todos.map((t) =>
t.id === params.id ? { ...t, title: title ?? t.title, isCompleted: isCompleted ?? t.isCompleted } : t
);
todos = updatedTodos;
response.status = 200;
response.body = {
success: true,
data: todos.find(t => t.id === params.id),
};
} else {
response.status = 404;
response.body = {
success: false,
message: "ํด๋น ID์ ํ ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค.",
};
}
};
// DELETE /todos/:id - ํ ์ผ ์ญ์ ํ๊ธฐ
export const deleteTodo = ({ params, response }: { params: { id: string }; response: any }) => {
const initialLength = todos.length;
todos = todos.filter((t) => t.id !== params.id);
if (todos.length < initialLength) {
response.status = 200;
response.body = {
success: true,
message: "ํ ์ผ์ด ์ฑ๊ณต์ ์ผ๋ก ์ญ์ ๋์์ต๋๋ค.",
};
} else {
response.status = 404;
response.body = {
success: false,
message: "ํด๋น ID์ ํ ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค.",
};
}
};
์ฝ๋๊ฐ ์ข ๊ธธ์ง๋ง, ์์ธํ ๋ณด๋ฉด ๊ฐ ํจ์๊ฐ ํ๋ ์ผ์ ๋ช
ํํด.
`getTodos`๋ ์ ์ฒด `todos` ๋ฐฐ์ด์ ๋ฐํํ๊ณ , `addTodo`๋ ์์ฒญ ๋ณธ๋ฌธ์์ `title`์ ๋ฐ์ ์ `Todo` ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ๋ฐฐ์ด์ ์ถ๊ฐํ๋ ์์ด์ผ. ์ฌ๊ธฐ์๋ ํ์
์คํฌ๋ฆฝํธ์ ํ์ด ๋๋ฌ๋. `newTodo`๋ฅผ ๋ง๋ค ๋ ์ฐ๋ฆฌ๊ฐ `types.ts`์์ ์ ์ํ `Todo` ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํด์, ๊ฐ์ฒด๊ฐ ์ฌ๋ฐ๋ฅธ ๋ชจ์์ ๊ฐ์ถ๋๋ก ๊ฐ์ ํ๊ณ ์์ด.
4. ๋ผ์ฐํฐ ์ค์ ํ๊ธฐ (`routes.ts`)
์ด์ ์ปจํธ๋กค๋ฌ ํจ์๋ค์ ๋ง๋ค์์ผ๋, ์ด๋ค URL ๊ฒฝ๋ก๋ก ์์ฒญ์ด ์์ ๋ ์ด๋ค ํจ์๋ฅผ ์คํํ ์ง ์ฐ๊ฒฐํด์ฃผ๋ '๊ตํต๊ฒฝ์ฐฐ' ์ญํ ์ด ํ์ํด. ์ด๊ฒ ๋ฐ๋ก ๋ผ์ฐํฐ(Router)์ผ. `routes.ts` ํ์ผ์ ์ด๊ณ Oak์ ๋ผ์ฐํฐ๋ฅผ ์ค์ ํ์.
// routes.ts
import { Router } from "oak";
import {
getTodos,
getTodo,
addTodo,
updateTodo,
deleteTodo,
} from "./controllers.ts";
const router = new Router();
// RESTful API ์๋ํฌ์ธํธ ์ค์
router
.get("/todos", getTodos) // ๋ชจ๋ ํ ์ผ ์กฐํ
.get("/todos/:id", getTodo) // ํน์ ํ ์ผ ์กฐํ
.post("/todos", addTodo) // ์ ํ ์ผ ์ถ๊ฐ
.put("/todos/:id", updateTodo) // ํ ์ผ ์์
.delete("/todos/:id", deleteTodo); // ํ ์ผ ์ญ์
export default router;
์ฝ๋๊ฐ ์ ๋ง ์ง๊ด์ ์ด์ง?
GET ์์ฒญ์ด `/todos`๋ก ์ค๋ฉด `getTodos` ํจ์๋ฅผ, POST ์์ฒญ์ด `/todos`๋ก ์ค๋ฉด `addTodo` ํจ์๋ฅผ ์คํํ๋ผ๊ณ ๋ช
์์ ์ผ๋ก ์๋ ค์ฃผ๋ ๊ฑฐ์ผ. ์ด๋ ๊ฒ ๋ผ์ฐํ
๋ก์ง์ ๋ณ๋์ ํ์ผ๋ก ๋ถ๋ฆฌํ๋ฉด ์ฝ๋๊ฐ ํจ์ฌ ๊น๋ํ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฌ์์ ธ.
5. ์๋ฒ ์คํํ๊ธฐ (`main.ts`)
๋๋์ด ๋ง์ง๋ง ๋จ๊ณ์ผ!
๋ชจ๋ ์กฐ๊ฐ๋ค์ ๋ชจ์์ ์ ํ๋ฆฌ์ผ์ด์
์ ์์ฑํ๊ณ ์๋ฒ๋ฅผ ์คํ์ํค๋ `main.ts` ํ์ผ์ ์์ฑํ์.
// main.ts
import { Application } from "oak";
import router from "./routes.ts";
const PORT = 8000;
const app = new Application();
// ๋ก๊น
๋ฏธ๋ค์จ์ด ์ถ๊ฐ (๋ชจ๋ ์์ฒญ์ ์ฝ์์ ๊ธฐ๋ก)
app.use(async (ctx, next) => {
await next();
const rt = ctx.response.headers.get("X-Response-Time");
console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`);
});
// ์๋ต ์๊ฐ ์ธก์ ๋ฏธ๋ค์จ์ด
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.response.headers.set("X-Response-Time", `${ms}ms`);
});
// ๋ผ์ฐํฐ ๋ฏธ๋ค์จ์ด ๋ฑ๋ก
app.use(router.routes());
app.use(router.allowedMethods()); // OPTIONS, 405 Method Not Allowed ๋ฑ ์๋ ์ฒ๋ฆฌ
console.log(`๐ฆ Deno ์๋ฒ๊ฐ http://localhost:${PORT} ์์ ์คํ ์ค์
๋๋ค...`);
await app.listen({ port: PORT });
`main.ts`์์๋ Oak ์ ํ๋ฆฌ์ผ์ด์ ์ธ์คํด์ค๋ฅผ ๋ง๋ค๊ณ , ์ฐ๋ฆฌ๊ฐ ์์ฑํ ๋ผ์ฐํฐ๋ฅผ ๋ฏธ๋ค์จ์ด๋ก ๋ฑ๋กํ์ด. ์ถ๊ฐ๋ก ๋ชจ๋ ์์ฒญ์ ๋ํ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๊ณ ์๋ต ์๊ฐ์ ์ธก์ ํ๋ ๊ฐ๋จํ ๋ฏธ๋ค์จ์ด๋ ๋ฃ์ด๋ดค์ด. ์ด๋ฐ ๊ฒ ๋ฐ๋ก ๋ฏธ๋ค์จ์ด์ ํ์ด์ผ. ์์ฒญ๊ณผ ์๋ต ์ฌ์ด์์ ๋ค์ํ ๊ณตํต ์์ ์ ์ฒ๋ฆฌํ ์ ์์ง.
6. API ์๋ฒ ์คํ ๋ฐ ํ ์คํธ
์, ๋ชจ๋ ์ค๋น๊ฐ ๋๋ฌ์ด. ํฐ๋ฏธ๋์์ ์๋ฒ๋ฅผ ์คํํด๋ณด์!
๋คํธ์ํฌ ์ ๊ทผ ๊ถํ์ ์ฃผ๋ `โallow-net` ํ๋๊ทธ๋ฅผ ์์ง ๋ง.
deno run --allow-net main.ts
ํฐ๋ฏธ๋์ "๐ฆ Deno ์๋ฒ๊ฐ http://localhost:8000 ์์ ์คํ ์ค์
๋๋ค..." ๋ฉ์์ง๊ฐ ๋จ๋ฉด ์ฑ๊ณต!
์ด์ API๊ฐ ์ ์๋ํ๋์ง ํ
์คํธํด๋ด์ผ์ง. ์น ๋ธ๋ผ์ฐ์ ๋ Postman, ํน์ ํฐ๋ฏธ๋์ `curl` ๋ช
๋ น์ด๋ฅผ ์ฌ์ฉํด์ ํ
์คํธํ ์ ์์ด.
1. ๋ชจ๋ ํ ์ผ ๋ชฉ๋ก ์กฐํ (GET)
curl http://localhost:8000/todos
2. ์๋ก์ด ํ ์ผ ์ถ๊ฐ (POST)
curl -X POST -H "Content-Type: application/json" -d '{"title": "Deno ํ๋ก์ ํธ ๋ฐฐํฌํ๊ธฐ"}' http://localhost:8000/todos
3. ํน์ ํ ์ผ ์์ (PUT) (ID๊ฐ 2์ธ ํญ๋ชฉ์ ์๋ฃ ์ฒ๋ฆฌ)
curl -X PUT -H "Content-Type: application/json" -d '{"isCompleted": true}' http://localhost:8000/todos/2
4. ํ ์ผ ์ญ์ (DELETE) (ID๊ฐ 1์ธ ํญ๋ชฉ ์ญ์ )
curl -X DELETE http://localhost:8000/todos/1
์ด๋? ์ฐ๋ฆฌ๊ฐ ์ ์ํ ๋๋ก API๊ฐ ์๋ฒฝํ๊ฒ ๋์ํ๋ ๊ฑธ ํ์ธํ ์ ์์ ๊ฑฐ์ผ.
์ด ๊ณผ์ ์์ ์ฐ๋ฆฌ๋ Deno ํ๋ก์ ํธ์ ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ๊ณ , ํ์
์คํฌ๋ฆฝํธ๋ก ์์ ํ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ๋ง๋ค๊ณ , Oak ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํด ๊น๋ํ๊ฒ ๋ผ์ฐํ
๊ณผ ์ปจํธ๋กค๋ฌ ๋ก์ง์ ๋ถ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ์ด. ์ด ์ ๋๋ฉด Deno๋ก ์ด๋ค ์ ํ๋ฆฌ์ผ์ด์
์ด๋ ๋ง๋ค ์ ์๋ค๋ ์์ ๊ฐ์ด ์๊ธฐ์ง ์์? ๐
๋ฌผ๋ก ์ค์ ํ๋ก๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๋, ์๋ฌ ์ฒ๋ฆฌ, ์ฌ์ฉ์ ์ธ์ฆ ๋ฑ ๋ ๋ง์ ๊ฒ๋ค์ด ํ์ํ๊ฒ ์ง๋ง, ์ค๋ ๋ง๋ ์ด ์์ API ์๋ฒ๋ Deno์ ํ์ ์คํฌ๋ฆฝํธ์ ๊ฐ๋ ฅํจ์ ๊ฒฝํํ๊ธฐ์ ์ถฉ๋ถํ, ์์ฃผ ํ๋ฅญํ ์ฒซ๊ฑธ์์ด์ผ. ์ด ๊ฒฝํ์ ๋ฐํ์ผ๋ก ๋ ๋ณต์กํ๊ณ ๋ฉ์ง ํ๋ก์ ํธ์ ๋์ ํด๋ณด๊ธธ ๋ฐ๋ผ! ํน์ ๊ฐ๋ฐํ๋ค ๋งํ๊ฑฐ๋ ๋ ๊น์ ์ง์์ด ํ์ํ๋ค๋ฉด, **์ฌ๋ฅ๋ท** ๊ฐ์ ํ๋ซํผ์์ Deno ์ ๋ฌธ๊ฐ์ ๋์์ ๋ฐ๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด ๋ ์ ์์ ๊ฑฐ์ผ. ๐
๐ Deno, ๊ทธ ๋๋จธ์ ์ธ๊ณ: ์ํ๊ณ์ ๋ฏธ๋
์ฐ๋ฆฌ๋ Deno์ ๊ธฐ๋ณธ ์ฒ ํ๋ถํฐ ์ค์ API ๊ฐ๋ฐ๊น์ง, ๊ฝค๋ ๊ธด ์ฌ์ ์ ํจ๊ปํ์ด.
ํ์ง๋ง Deno์ ์ธ๊ณ๋ ์ฌ๊ธฐ์ ๋๋์ง ์์. Deno๋ฅผ ๋๋ฌ์ผ ์ํ๊ณ๋ ์ง๊ธ ์ด ์๊ฐ์๋ ํ๋ฐํ๊ฒ ์ฑ์ฅํ๋ฉฐ ์๋ก์ด ๊ฐ๋ฅ์ฑ์ ์ด์ด๊ฐ๊ณ ์์ด. ๋ง์ง๋ง์ผ๋ก Deno์ ๋ฏธ๋๋ฅผ ์ฟ๋ณผ ์ ์๋ ๋ช ๊ฐ์ง ํฅ๋ฏธ๋ก์ด ์ฃผ์ ๋ค์ ์ดํด๋ณด๋ฉฐ ์ด์ผ๊ธฐ๋ฅผ ๋ง๋ฌด๋ฆฌํ๋ ค๊ณ ํด.
1. Deno Deploy: ์๋ฒ ์๋ ์๋ฒ, ์ฃ์ง ์ปดํจํ ์ ์๋
์๋ฒ๋ฅผ ๋ง๋ค์์ผ๋ฉด ์ด์ ๋ฐฐํฌ๋ฅผ ํด์ผ์ง.
๋ณดํต์ AWS EC2๋ DigitalOcean ๊ฐ์ ํด๋ผ์ฐ๋ ์๋ฒ๋ฅผ ๋น๋ ค์, ๊ทธ ์์ Deno๋ฅผ ์ค์นํ๊ณ , ์ฝ๋๋ฅผ ์ฌ๋ฆฌ๊ณ , ํ๋ก์ธ์ค ๋งค๋์ (pm2 ๊ฐ์)๋ก ์คํํ๋ ๋ณต์กํ ๊ณผ์ ์ ๊ฑฐ์ณ์ผ ํ์ด.
Deno ํ์ ์ด ๋ฐฐํฌ ๊ณผ์ ๋ง์ ํ์ ํ๊ณ ์ถ์๋ ๋ด. ๊ทธ๋์ Deno Deploy๋ผ๋ ์์ฒด ์๋ฒ๋ฆฌ์ค ํ๋ซํผ์ ๋ง๋ค์์ด. ์ด๊ฑด ๊ทธ๋ฅ ํ๋ฒํ ์๋ฒ๋ฆฌ์ค๊ฐ ์๋์ผ. ์ ์ธ๊ณ ์์ญ ๊ฐ์ ๋ฐ์ดํฐ ์ผํฐ์ ๋ด ์ฝ๋๋ฅผ ๋ถ์ฐ์์ผ ๋๊ณ , ์ฌ์ฉ์์ ๊ฐ์ฅ ๊ฐ๊น์ด ์์น์์ ์ฝ๋๋ฅผ ์คํํ๋ '์ฃ์ง ์ปดํจํ (Edge Computing)' ํ๊ฒฝ์ ์ ๊ณตํด.
์ด๊ฒ ๋ฌด์จ ๋ง์ด๋๋ฉด, ๋ฏธ๊ตญ์ ์๋ ์ฌ์ฉ์๋ ๋ฏธ๊ตญ ์๋ฒ์์, ์ ๋ฝ์ ์๋ ์ฌ์ฉ์๋ ์ ๋ฝ ์๋ฒ์์ ๋ด ์ฝ๋๊ฐ ์คํ๋๋ค๋ ๊ฑฐ์ผ. ๋ฌผ๋ฆฌ์ ์ธ ๊ฑฐ๋ฆฌ๊ฐ ๊ฐ๊น์์ง๋ ๋น์ฐํ ์๋ต ์๋๋ ์์ฒญ๋๊ฒ ๋นจ๋ผ์ง๊ฒ ์ง? โก
Deno Deploy์ ๊ฐ์ฅ ๋ฉ์ง ์ ์ ์ฌ์ฉ๋ฒ์ด ๊ธฐ๊ฐ ๋งํ๊ฒ ๊ฐ๋จํ๋ค๋ ๊ฑฐ์ผ. GitHub ์ ์ฅ์์ ์ฝ๋๋ฅผ ํธ์ํ๊ธฐ๋ง ํ๋ฉด, Deno Deploy๊ฐ ์์์ ์ ์ธ๊ณ์ ์ฝ๋๋ฅผ ๋ฐฐํฌํด์ค. ๋ณ๋์ ์ค์ ? ๋น๋ ๊ณผ์ ? ๊ฑฐ์ ํ์ ์์ด. Deno๊ฐ ์ถ๊ตฌํ๋ '๋จ์ํจ์ ๋ฏธํ'์ด ๋ฐฐํฌ ๊ณผ์ ๊น์ง ์ด์ด์ง ๊ฑฐ์ง.
2. Deno์ ์๋ก์ด ๋ ๊ฐ, Fresh ํ๋ ์์ํฌ
Oak๊ฐ Express.js ๊ฐ์ ์ ํต์ ์ธ ์๋ฒ์ฌ์ด๋ ๋ ๋๋ง(SSR) ํ๋ ์์ํฌ๋ผ๋ฉด, Deno ์ํ๊ณ์๋ Fresh๋ผ๋ ์์ฃผ ์ ์ ํ๊ณ ํ์ ์ ์ธ ํ๋ ์์ํฌ๋ ์์ด. Fresh๋ React์ ์ฐฝ์์ ์ค ํ ๋ช ์ธ Jordan Walke์ ์ํฅ์ ๋ฐ์ '์์ผ๋๋ ์ํคํ ์ฒ(Islands Architecture)'๋ผ๋ ๊ฐ๋ ์ ๊ธฐ๋ฐ์ผ๋ก ํด.
์ด๊ฒ ๋ญ๋๋ฉด, ์น ํ์ด์ง๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก๋ ์ ์ ์ธ HTML๋ก ๋ง๋ค์ด์ ์์ฃผ ๋น ๋ฅด๊ฒ ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ฃผ๊ณ , ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ๊ผญ ํ์ํ ๋ถ๋ถ(์: ์ด๋ฏธ์ง ์บ๋ฌ์ , ์ธํฐ๋ํฐ๋ธํ ๋ฒํผ)๋ง '์ฌ(Island)'์ฒ๋ผ ๋ ๋ฆฝ์ ์ผ๋ก ๋ก๋ํด์ ์ํธ์์ฉ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ๋ฐฉ์์ด์ผ.
๊ฒฐ๊ณผ๋? ์์ฒญ๋๊ฒ ๋น ๋ฅธ ์ด๊ธฐ ๋ก๋ฉ ์๋! ์ฌ์ฉ์์๊ฒ ๋ถํ์ํ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๋ณด๋ด์ง ์๊ธฐ ๋๋ฌธ์ ์น์ฌ์ดํธ ์ฑ๋ฅ์ด ๊ทน์ ์ผ๋ก ํฅ์๋ผ. ๋น๋ ๊ณผ์ ๋ ํ์ ์๊ณ , ๋ชจ๋ ๋ ๋๋ง์ ์๋ฒ(์ฃ์ง)์์ ์ฆ์ ์ผ์ด๋. Deno Deploy์ ํจ๊ป ์ฌ์ฉํ๋ฉด ๊ทธ์ผ๋ง๋ก ํ์์ ๊ถํฉ์ ์๋ํ์ง.
๋ธ๋ก๊ทธ๋ ๋ฌธ์ ์ฌ์ดํธ, ๊ฐ๋จํ ์ผํ๋ชฐ์ฒ๋ผ ์ฝํ ์ธ ์ค์ฌ์ ์น์ฌ์ดํธ๋ฅผ ๋ง๋ ๋ค๋ฉด Fresh๋ ์ ๋ง ๋งค๋ ฅ์ ์ธ ์ ํ์ง๊ฐ ๋ ๊ฑฐ์ผ.
3. WebAssembly(WASM)์์ ๋ง๋จ: ๋ธ๋ผ์ฐ์ ๋ฅผ ๋์ด
Deno๋ WebAssembly(WASM)๋ฅผ ์ผ๊ธ ์๋ฏผ(First-class citizen)์ผ๋ก ์ง์ํด. WebAssembly๋ C++, Rust, Go ๊ฐ์ ๊ณ ์ฑ๋ฅ ์ธ์ด๋ก ์์ฑ๋ ์ฝ๋๋ฅผ ์น ๋ธ๋ผ์ฐ์ ๋ Deno ๊ฐ์ ํ๊ฒฝ์์ ๋ค์ดํฐ๋ธ์ ๊ฐ๊น์ด ์๋๋ก ์คํํ ์ ์๊ฒ ํด์ฃผ๋ ๊ธฐ์ ์ด์ผ.
์ด๊ฒ ์ ์ค์ํ๋๋ฉด, ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ์ฒ๋ฆฌํ๊ธฐ์ ๋๋ฌด ๋ฌด๊ฑฐ์ด ์์ ๋ค, ์๋ฅผ ๋ค์ด ๋น๋์ค ์ธ์ฝ๋ฉ, ์ด๋ฏธ์ง ์ฒ๋ฆฌ, ๋ณต์กํ ๊ณผํ ๊ณ์ฐ ๊ฐ์ ๊ฒ๋ค์ ๊ณ ์ฑ๋ฅ ์ธ์ด์ ๋งก๊ธฐ๊ณ , Deno๋ ์ด WASM ๋ชจ๋์ ์ฝ๊ฒ ๋ถ๋ฌ์์ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ด์ผ. Deno๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ํธ๋ฆฌํจ๊ณผ Rust ๊ฐ์ ์์คํ ์ธ์ด์ ์ฑ๋ฅ์ ๋ชจ๋ ์ทจํ ์ ์๋ ๊ฐ๋ ฅํ ํ๋ซํผ์ผ๋ก ์งํํ๊ณ ์๋ ๊ฑฐ์ง.
4. ๊ทธ๋์, Deno๋ Node.js๋ฅผ ๋์ฒดํ ๊น?
์ด ๊ธ์ ๋ค ์ฝ๊ณ ๋๋ฉด ์ด๋ฐ ์ง๋ฌธ์ด ์๊ธธ ๊ฑฐ์ผ. "์, Deno ์ ๋ง ์ข๋ค. ๊ทธ๋ผ ์ด์ Node.js๋ ๋ฒ๋ฆฌ๊ณ Deno๋ก ๊ฐ์ํ์ผ ํ๋?"
๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด, "์ํฉ์ ๋ฐ๋ผ ๋ค๋ฅด๋ค"๊ฐ ์ ๋ต์ด์ผ. ๐ค
Node.js๋ 2009๋ ๋ถํฐ ์ง๊ธ๊น์ง 10๋ ์ด ๋๋ ์๊ฐ ๋์ ๊ฑฐ๋ํ๊ณ ์ฑ์ํ ์ํ๊ณ๋ฅผ ๊ตฌ์ถํ์ด. ๊ฒ์ฆ๋ ์๋ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ๋ฐฉ๋ํ ์ปค๋ฎค๋ํฐ ์๋ฃ, ์ฑ์ฉ ์์ฅ์์์ ์๋์ ์ธ ์์ ๋ฑ์ ์ ๋ ๋ฌด์ํ ์ ์๋ ์ฅ์ ์ด์ผ. ๋๊ท๋ชจ์ ๋ณต์กํ ์ํฐํ๋ผ์ด์ฆ ์ ํ๋ฆฌ์ผ์ด์ ์ด๋, ์ด๋ฏธ Node.js ๊ธฐ๋ฐ์ผ๋ก ์ ๋์๊ฐ๊ณ ์๋ ํ๋ก์ ํธ๋ฅผ ๊ตณ์ด Deno๋ก ์ฎ๊ธธ ํ์๋ ์์ ์๋ ์์ด.
๋ฐ๋ฉด์, ์๋ก์ด ๊ฐ์ธ ํ๋ก์ ํธ๋ ์คํํธ์ ์ MVP(์ต์ ๊ธฐ๋ฅ ์ ํ)๋ฅผ ๋ง๋ค ๋, ํน์ ์คํฌ๋ฆฝํ , ์ปค๋งจ๋๋ผ์ธ ๋๊ตฌ(CLI)๋ฅผ ๊ฐ๋ฐํ ๋๋ Deno๊ฐ ์ ๋ง ๊ฐ๋ ฅํ ๋ฌด๊ธฐ๊ฐ ๋ ์ ์์ด. ๋ณ๋์ ์ค์ ์์ด ๋ฐ๋ก ํ์ ์คํฌ๋ฆฝํธ๋ก ๊ฐ๋ฐ์ ์์ํ ์ ์๊ณ , ๋ด์ฅ ํด์ฒด์ธ์ผ๋ก ๊ฐ๋ฐ ๊ฒฝํ์ด ํจ์ฌ ์พ์ ํ๋ฉฐ, ๋ณด์ ๋ชจ๋ธ ๋๋ถ์ ๋ ์์ ํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ง. ํนํ Deno Deploy๋ Fresh ๊ฐ์ ์ต์ ๊ธฐ์ ์ ํ์ฉํ๊ณ ์ถ๋ค๋ฉด Deno๋ ์ต๊ณ ์ ์ ํ์ด์ผ.
Deno๋ Node.js๋ฅผ ์ฃฝ์ด๊ธฐ ์ํด ๋์จ 'ํฌ๋ฌ'๊ฐ ์๋์ผ.
Node.js๋ฅผ ๋ง๋ค๋ฉด์ ๋๊ผ๋ ์์ฌ์์ ๊ตํ ์ผ์, ๋ ํ๋์ ์ด๊ณ ์์ ํ๋ฉฐ ํธ๋ฆฌํ ๊ฐ๋ฐ ํ๊ฒฝ์ ์ ๊ณตํ๋ ค๋ '๋์'์ด์ '์งํ'์ ๊ฐ๊น๋ค๊ณ ์๊ฐํด. ๋์ ๊ฒฝ์ ๊ด๊ณ์ด๋ฉด์๋, `npm:` ํธํ์ฑ์ฒ๋ผ ์๋ก๋ฅผ ๋ณด์ํ๋ฉฐ ํจ๊ป ์๋ฐ์คํฌ๋ฆฝํธ ์๋ฒ์ฌ์ด๋ ์ํ๊ณ๋ฅผ ๋์ฑ ํ์ฑํ๊ฒ ๋ง๋ค์ด๊ฐ๊ณ ์์ด.
์ค๋ ์ฐ๋ฆฌ๋ Deno๋ผ๋ ์๋ก์ด ๊ณต๋ฃก์ ๋ฑ์ ์ฌ๋ผํ ํ์
์คํฌ๋ฆฝํธ๋ผ๋ ๋ ๊ฐ๋ฅผ ๋ฌ๊ณ ๋ฉ์ง ๋นํ์ ํด๋ดค์ด.
์ด ๊ฒฝํ์ด ๋์ ๊ฐ๋ฐ์๋ก์์ ์ฌ์ ์ ์๋ก์ด ์๊ฐ๊ณผ ์ฆ๊ฑฐ์์ ์ฃผ์๊ธฐ๋ฅผ ๋ฐ๋ผ. ์ธ์์ ๋น ๋ฅด๊ฒ ๋ณํ๊ณ , ๊ฐ๋ฐ์์๊ฒ ๊ฐ์ฅ ์ค์ํ ๋ฌด๊ธฐ๋ ์๋ก์ด ๊ธฐ์ ์ ๋๋ ค์ํ์ง ์๊ณ ๋ฐฐ์ฐ๋ ค๋ ํธ๊ธฐ์ฌ์ผ ๊ฑฐ์ผ.
์ง๊ธ ๋น์ฅ ๊ฑฐ์ฐฝํ ํ๋ก์ ํธ๋ฅผ ์์ํ์ง ์์๋ ์ข์.
๊ฐ๋จํ ์คํฌ๋ฆฝํธ ํ๋๋ผ๋ Deno๋ก ์ง๋ณด๋ ๊ฑด ์ด๋จ๊น? ๊ทธ ์์ ํ ๊ฑธ์์ด ๋๋ฅผ ๋ ๋์ ์ธ๊ณ๋ก ์ด๋์ด ์ค ๊ฑฐ์ผ. Happy coding! ๐ฅณ
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.