{"@attributes":{"version":"2.0"},"channel":{"title":"\ubc8c\ub808 \uc7a1\ub294 \uc0ac\ub78c","link":"https:\/\/mk-develop.tistory.com\/","description":"\uc774\uac8c \uc65c\uc548\ub420\uae4c\uc694","language":"ko","pubDate":"Thu, 7 May 2026 13:45:01 +0900","generator":"TISTORY","ttl":"100","managingEditor":"MaKa_","image":{"title":"\ubc8c\ub808 \uc7a1\ub294 \uc0ac\ub78c","url":"https:\/\/tistory1.daumcdn.net\/tistory\/5882107\/attach\/cfcf6b5f6884420b93274237df062704","link":"https:\/\/mk-develop.tistory.com"},"item":[{"title":"Codex Multi Agent, Custom Agent \uc138\ud305\ud558\uae30","link":"https:\/\/mk-develop.tistory.com\/entry\/Codex-Multi-Agent-Custom-Agent-%EC%84%B8%ED%8C%85%ED%95%98%EA%B8%B0","description":"<h3 style=\"text-align: justify;\" data-ke-size=\"size23\">\uac1c\uc694<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\" style=\"text-align: justify;\">\ub4dc\ub514\uc5b4 Codex\uc5d0\uc11c Subagent \uc989 Multi Agent\ub97c \uc815\uc2dd\uc73c\ub85c \uc9c0\uc6d0\ud55c\ub2e4.<br><a href=\"https:\/\/developers.openai.com\/codex\/subagents\" target=\"_blank\"><span>https:\/\/developers.openai.com\/codex\/subagents<\/span><\/a><\/p><figure data-ke-type=\"opengraph\" data-og-title=\"Subagents \u2013 Codex | OpenAI Developers\" data-ke-align=\"alignCenter\" data-og-description=\"Use subagents and custom agents in Codex\" data-og-host=\"developers.openai.com\" data-og-source-url=\"https:\/\/developers.openai.com\/codex\/subagents\" data-og-image=\"https:\/\/blog.kakaocdn.net\/dna\/cBqiQg\/dJMb8U8TIbn\/AAAAAAAAAAAAAAAAAAAAACDsKbhD3_9fbw3e0Jn1NUDAt-5Oh8rHuHa78URUtM3r\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1774969199&amp;allow_ip=&amp;allow_referer=&amp;signature=T1uSB2U2H%2BpBTFccCTQYAiCm5mE%3D\" data-og-url=\"https:\/\/developers.openai.com\/codex\/subagents\/\"><a href=\"https:\/\/developers.openai.com\/codex\/subagents\/\" target=\"_blank\" data-source-url=\"https:\/\/developers.openai.com\/codex\/subagents\"><div class=\"og-image\" style=\"background-image: url('https:\/\/blog.kakaocdn.net\/dna\/cBqiQg\/dJMb8U8TIbn\/AAAAAAAAAAAAAAAAAAAAACDsKbhD3_9fbw3e0Jn1NUDAt-5Oh8rHuHa78URUtM3r\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1774969199&amp;allow_ip=&amp;allow_referer=&amp;signature=T1uSB2U2H%2BpBTFccCTQYAiCm5mE%3D')\"> <\/div><div class=\"og-text\"><p class=\"og-title\">Subagents \u2013 Codex | OpenAI Developers<\/p><p class=\"og-desc\">Use subagents and custom agents in Codex<\/p><p class=\"og-host\">developers.openai.com<\/p><\/div><\/a><\/figure><p data-ke-size=\"size16\" style=\"text-align: justify;\">\ud574\ub2f9 \uae30\ub2a5\uc744 \uc798 \uc0ac\uc6a9\ud558\uba74 <b>\ubcf5\uc7a1\ud55c \uba85\ub839\uc744 \ubcd1\ub82c\ub85c \ucc98\ub9ac<\/b>\ud560 \uc218 \uc788\ub2e4.<br>\uc774\ub97c \uc774\uc6a9\ud558\uc5ec \ub098\ub9cc\uc758 AI \uac1c\ubc1c\ud300\uc744 \ub9cc\ub4e4 \uc218 \uc788\uc9c0 \uc54a\uc744\uae4c?\ub77c\ub294 \uc0dd\uac01\uc73c\ub85c Subagent\ub4e4\uc744 \uc138\ud305\ud574 \ubcf4\uc558\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 style=\"text-align: justify;\" data-ke-size=\"size23\">Agent \uad6c\uc870<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\" style=\"text-align: justify;\">\ud574\ub2f9 \uae30\ub2a5\uc744 \uc0ac\uc6a9\ud558\uae30 \uc804\uc5d0 \uba3c\uc800 Codex\uc758 Agent \uad6c\uc870\ub97c \uc774\ud574\ud574\uc57c \ud55c\ub2e4.<br>&nbsp;<br>Subagent\ub97c \uc0ac\uc6a9\ud560 \uacbd\uc6b0 \uc77c\ubc18\uc801\uc73c\ub85c \uc0ac\uc6a9\uc790\uc758 \uba85\ub839\uc744 \ubc1b\uc544 \uc791\uc5c5\uc744 \ucc98\ub9ac\ud558\ub294 agent\ub294 <b>Subagent workflow<\/b>\uac00 \ub41c\ub2e4.<br>Subagent workflow\ub294 \uc5d0\uc774\uc804\ud2b8\ub97c \ubcd1\ub82c\ub85c \uc2e4\ud589\ud558\uace0 \uadf8 \uacb0\uacfc\ub97c \uacb0\ud569\ud55c\ub2e4.<br>&nbsp;<br>Codex\ub294 \uba85\ub839\uc744 \ucc98\ub9ac\ud558\uba74\uc11c \ud544\uc694\uc2dc <b>Subagent<\/b>\ub97c \uc0dd\uc131\ud55c\ub2e4.<br>Subagent\ub294 \ud2b9\uc815 \uc791\uc5c5\uc744 \ucc98\ub9ac\ud558\ub3c4\ub85d \uc791\uc5c5\uc744 \uc704\uc784\ubc1b\uc740 \uc5d0\uc774\uc804\ud2b8\uc774\ub2e4.<br>&nbsp;<br>\ud130\ubbf8\ub110\uc5d0\uc11c Codex\ub97c \uc0ac\uc6a9\ud560 \uacbd\uc6b0 \/agent\ub97c \uc0ac\uc6a9\ud558\uc5ec \uc5d0\uc774\uc804\ud2b8\ub4e4\uc744 \ud655\uc778\ud558\uace0 \uc804\ud658\ud560 \uc218 \uc788\ub2e4.<br>\uc774\ub97c <b>Agent thread<\/b>\ub77c\uace0 \ud55c\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 style=\"text-align: justify;\" data-ke-size=\"size23\">Multi Agent \ud65c\uc131\ud654\ud558\uae30<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\" style=\"text-align: justify;\">\uba3c\uc800 Codex\uc758 Multi Agent\ub97c \ud65c\uc131\ud654\ud574\uc57c \ud55c\ub2e4.<br><b>Codex Settings &gt; \uad6c\uc131<\/b>\uc5d0 \ub4e4\uc5b4\uac00\uc11c config.toml\uc5d0 \ub2e4\uc74c \ub0b4\uc6a9\uc744 \ucd94\uac00\ud55c\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"979\" data-origin-height=\"421\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/dypmaB\/dJMcacihuOE\/lYfi81mcw7eknpm4Fo1fp0\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/dypmaB\/dJMcacihuOE\/lYfi81mcw7eknpm4Fo1fp0\/img.png\" data-alt=\"Codex Settings\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/dypmaB\/dJMcacihuOE\/lYfi81mcw7eknpm4Fo1fp0\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdypmaB%2FdJMcacihuOE%2FlYfi81mcw7eknpm4Fo1fp0%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"979\" height=\"421\" data-origin-width=\"979\" data-origin-height=\"421\"\/><\/span><figcaption>Codex Settings<\/figcaption>\n<\/figure>\n<blockquote data-ke-style=\"style2\">config.toml<\/blockquote><pre data-ke-type=\"codeblock\" class=\"bash\" data-ke-language=\"bash\"><code>[features]\nmulti_agent = true\n\n[agents]\nmax_threads = 6\nmax_depth = 1<\/code><\/pre><p data-ke-size=\"size16\" style=\"text-align: justify;\">&nbsp;<br>max_threads\uc640 max_depth\ub294 \uac01\uac01 6\uacfc 1\uc774 \uae30\ubcf8\uac12\uc774\ub2e4.<br>&nbsp;<br>max_threads\ub294 \uc0ac\uc6a9\uc790\uac00 \uc815\uc758\ud558\uba74 \ub418\ub098 <b>2026\ub144 3\uc6d4 \uacf5\uc2dd\ubb38\uc11c \uae30\uc900 max_depth\ub294 1\uc744 \ucd08\uacfc\ud558\uc9c0 \uc54a\ub294 \uac83\uc744 \uad8c\uc7a5<\/b>\ud55c\ub2e4.<br>&nbsp;<br>\uc65c\ub0d0\ud558\uba74 max_depth\uac00 1\uc744 \ucd08\uacfc\ud560 \uacbd\uc6b0 \uc704\uc784 \uba85\ub839\uc774 \uad11\ubc94\uc704\ud574\uc838 \ubd88\ud544\uc694\ud55c \ud1a0\ud070 \uc18c\ubaa8, \ubd88\ud544\uc694\ud55c \uc7ac\uadc0\ub85c \uc778\ud55c \uc608\uce21\ud560 \uc218 \uc5c6\ub294 \uc704\ud5d8\uc774 \uc0dd\uae38 \uc218 \uc788\uae30 \ub54c\ubb38\uc774\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 style=\"text-align: justify;\" data-ke-size=\"size23\">Custom Agent \ub9cc\ub4e4\uae30<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\" style=\"text-align: justify;\">\uba3c\uc800 \ud504\ub85c\uc81d\ud2b8\uc758 root\uc5d0 .codex\ub77c\ub294 \ud3f4\ub354\ub97c \uc0dd\uc131\ud558\uace0 \uadf8 \uc548\uc5d0 <b>agents\ub77c\ub294<\/b> \ud3f4\ub354\ub97c \uc0dd\uc131\ud55c\ub2e4.<br>&nbsp;<br>\uc774\uc81c \ud574\ub2f9 \ud30c\uc77c\uc5d0 \uc790\uc2e0\uc774 \uc0dd\uc131\ud558\uace0 \uc2f6\uc740 \uc5d0\uc774\uc804\ud2b8\uba85\uc73c\ub85c toml \ud30c\uc77c\uc744 \ub9cc\ub4e0\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"181\" data-origin-height=\"92\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/blmrrq\/dJMcaiJwg65\/0YXAa0eFX9nIlNMITk75GK\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/blmrrq\/dJMcaiJwg65\/0YXAa0eFX9nIlNMITk75GK\/img.png\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/blmrrq\/dJMcaiJwg65\/0YXAa0eFX9nIlNMITk75GK\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fblmrrq%2FdJMcaiJwg65%2F0YXAa0eFX9nIlNMITk75GK%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"181\" height=\"92\" data-origin-width=\"181\" data-origin-height=\"92\"\/><\/span><\/figure>\n<p data-ke-size=\"size16\" style=\"text-align: justify;\">\uac01 toml \ud30c\uc77c\uc5d4 \ub2e4\uc74c \ud56d\ubaa9\uc774 \ubc18\ub4dc\uc2dc \ud3ec\ud568\ub418\uc5b4\uc57c \ud55c\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"356\" data-origin-height=\"129\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/drSl0D\/dJMcaduEBV9\/OZkMmE30uEcB3lPxyfktPK\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/drSl0D\/dJMcaduEBV9\/OZkMmE30uEcB3lPxyfktPK\/img.png\" data-alt=\"\ud544\uc218 \ud3ec\ud568 \ud56d\ubaa9\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/drSl0D\/dJMcaduEBV9\/OZkMmE30uEcB3lPxyfktPK\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdrSl0D%2FdJMcaduEBV9%2FOZkMmE30uEcB3lPxyfktPK%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"356\" height=\"129\" data-origin-width=\"356\" data-origin-height=\"129\"\/><\/span><figcaption>\ud544\uc218 \ud3ec\ud568 \ud56d\ubaa9<\/figcaption>\n<\/figure>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style8\"><p data-ke-size=\"size16\" style=\"text-align: justify;\">\uc774\ub97c \ubc14\ud0d5\uc73c\ub85c \uc5d0\uc774\uc804\ud2b8\ub97c \ub9cc\ub4e4\uba74 \ub2e4\uc74c\uacfc \uac19\uc774 \uc0dd\uc131\ud560 \uc218 \uc788\ub2e4.<\/p><blockquote data-ke-style=\"style2\">writer.toml<\/blockquote><pre data-ke-type=\"codeblock\" class=\"bash\" data-ke-language=\"bash\"><code>name = \"writer\"\ndescription = \"Document the developed content.\"\nmodel = \"gpt-5.4\"\nmodel_reasoning_effort = \"high\"\ndeveloper_instructions = \"\"\"\nWhen a request to create a document is received, I use Notion MCP to write the document.\nI organize the implementation details, remaining risks or items requiring verification, and problems encountered during implementation and their solutions in detail.\n\"\"\"\n\n[mcp_servers.notion]\nurl = \"https:\/\/mcp.notion.com\/mcp\"<\/code><\/pre><blockquote data-ke-style=\"style2\">broswer-debugger.toml<\/blockquote><pre data-ke-type=\"codeblock\" class=\"bash\" data-ke-language=\"bash\"><code>name = \"browser_debugger\"\ndescription = \"UI debugger that uses browser tooling to reproduce issues and capture evidence.\"\nmodel = \"gpt-5.4\"\nmodel_reasoning_effort = \"high\"\nsandbox_mode = \"workspace-write\"\ndeveloper_instructions = \"\"\"\nReproduce the issue in the browser, capture exact steps, and report what the UI actually does.\nUse browser tooling for screenshots, console output, and network evidence.\nDo not edit application code.\n\"\"\"\n\n[mcp_servers.playwright]\ncommand = \"npx\"\nargs = [\"@playwright\/mcp@latest\"]<\/code><\/pre><blockquote data-ke-style=\"style2\">ui-fixer.toml<\/blockquote><pre data-ke-type=\"codeblock\" class=\"bash\" data-ke-language=\"bash\"><code>name = \"ui_fixer\"\ndescription = \"Implementation-focused agent for small, targeted fixes after the issue is understood.\"\nmodel = \"gpt-5.4\"\nmodel_reasoning_effort = \"high\"\ndeveloper_instructions = \"\"\"\nOwn the fix once the issue is reproduced.\nMake the smallest defensible change, keep unrelated files untouched, and validate only the behavior you changed.\nAlso verify browser performance.\nIf you need to test the browser, use browser-debugger agent.\n\"\"\"\n\n[[skills.config]]\npath = \"..\/..\/.agents\/skills\/vercel-react-best-practices\"\nenabled = true<\/code><\/pre><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style8\"><p data-ke-size=\"size16\" style=\"text-align: justify;\">model, model_reasoning_effort, skill, mcp server\uc640 \uac19\uc740 \uc18d\uc131\uc740 \uc120\ud0dd\uc0ac\ud56d\uc774\ub2e4.<br>&nbsp;<br>\ub9cc\uc57d \uc5d0\uc774\uc804\ud2b8\uc5d0 <b>mcp \uc11c\ubc84\ub098 skill \ub4f1\uc744<\/b> <b>\uc815\uc758\ud558\uc9c0 \uc54a\ub294\ub2e4\uba74<\/b> <b>\ubd80\ubaa8 \uc5d0\uc774\uc804\ud2b8\uc758 \uc124\uc815\uc744 \uadf8\ub300\ub85c \uc0c1\uc18d<\/b>\ubc1b\ub294\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 style=\"text-align: justify;\" data-ke-size=\"size23\">\ud504\ub860\ud2b8\uc5d4\ub4dc\uc5d0\uc11c \uc0ac\uc6a9\ud558\uae30 \uc88b\uc740 Agent \uc2a4\ud0ac<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\" style=\"text-align: justify;\">\uc2a4\ud0ac \uc18d\uc131\uc5d0 \ubb34\uc5c7\uc744 \ub123\uc5b4\uc57c \ud560\uc9c0 \ubaa8\ub97c \uc218 \uc788\ub2e4.<br>&nbsp;<br>\ud504\ub860\ud2b8\uc5d4\ub4dc\uc5d0\uc11c \uc0ac\uc6a9\ud558\uae30 \uc88b\uc740 \uc2a4\ud0ac\uc744 \uac04\ub7b5\ud558\uac8c \uc18c\uac1c\ud55c\ub2e4.<br>&nbsp;<br><a href=\"https:\/\/github.com\/vercel-labs\/skills\" target=\"_blank\"><span>https:\/\/github.com\/vercel-labs\/skills<\/span><\/a><\/p><figure data-ke-type=\"opengraph\" data-og-title=\"GitHub - vercel-labs\/skills: The open agent skills tool - npx skills\" data-ke-align=\"alignCenter\" data-og-description=\"The open agent skills tool - npx skills. Contribute to vercel-labs\/skills development by creating an account on GitHub.\" data-og-host=\"github.com\" data-og-source-url=\"https:\/\/github.com\/vercel-labs\/skills\" data-og-image=\"https:\/\/blog.kakaocdn.net\/dna\/bgCXIs\/dJMb9hC1rua\/AAAAAAAAAAAAAAAAAAAAAG5lb3PvTQOU961375kPiUbYMo9YKbZsOFaLo5G1NUHE\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1774969199&amp;allow_ip=&amp;allow_referer=&amp;signature=QBo3sF6i8G9lWCeqOVxNhfA7o6I%3D\" data-og-url=\"https:\/\/github.com\/vercel-labs\/skills\"><a href=\"https:\/\/github.com\/vercel-labs\/skills\" target=\"_blank\" data-source-url=\"https:\/\/github.com\/vercel-labs\/skills\"><div class=\"og-image\" style=\"background-image: url('https:\/\/blog.kakaocdn.net\/dna\/bgCXIs\/dJMb9hC1rua\/AAAAAAAAAAAAAAAAAAAAAG5lb3PvTQOU961375kPiUbYMo9YKbZsOFaLo5G1NUHE\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1774969199&amp;allow_ip=&amp;allow_referer=&amp;signature=QBo3sF6i8G9lWCeqOVxNhfA7o6I%3D')\"> <\/div><div class=\"og-text\"><p class=\"og-title\">GitHub - vercel-labs\/skills: The open agent skills tool - npx skills<\/p><p class=\"og-desc\">The open agent skills tool - npx skills. Contribute to vercel-labs\/skills development by creating an account on GitHub.<\/p><p class=\"og-host\">github.com<\/p><\/div><\/a><\/figure><p data-ke-size=\"size16\" style=\"text-align: justify;\"><a href=\"https:\/\/github.com\/nextlevelbuilder\/ui-ux-pro-max-skill\" target=\"_blank\"><span>https:\/\/github.com\/nextlevelbuilder\/ui-ux-pro-max-skill<\/span><\/a><\/p><figure data-ke-type=\"opengraph\" data-og-title=\"GitHub - nextlevelbuilder\/ui-ux-pro-max-skill: An AI SKILL that provide design intelligence for building professional UI\/UX mult\" data-ke-align=\"alignCenter\" data-og-description=\"An AI SKILL that provide design intelligence for building professional UI\/UX multiple platforms - nextlevelbuilder\/ui-ux-pro-max-skill\" data-og-host=\"github.com\" data-og-source-url=\"https:\/\/github.com\/nextlevelbuilder\/ui-ux-pro-max-skill\" data-og-image=\"https:\/\/blog.kakaocdn.net\/dna\/nidOt\/dJMb88F42VV\/AAAAAAAAAAAAAAAAAAAAAI20eOFVbdaQBsjgOLiB86I_rNaUru55tobNTwuMcuL6\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1774969199&amp;allow_ip=&amp;allow_referer=&amp;signature=BVsHt8VD%2FS0TjmqI15bRcS7VGdY%3D\" data-og-url=\"https:\/\/github.com\/nextlevelbuilder\/ui-ux-pro-max-skill\"><a href=\"https:\/\/github.com\/nextlevelbuilder\/ui-ux-pro-max-skill\" target=\"_blank\" data-source-url=\"https:\/\/github.com\/nextlevelbuilder\/ui-ux-pro-max-skill\"><div class=\"og-image\" style=\"background-image: url('https:\/\/blog.kakaocdn.net\/dna\/nidOt\/dJMb88F42VV\/AAAAAAAAAAAAAAAAAAAAAI20eOFVbdaQBsjgOLiB86I_rNaUru55tobNTwuMcuL6\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1774969199&amp;allow_ip=&amp;allow_referer=&amp;signature=BVsHt8VD%2FS0TjmqI15bRcS7VGdY%3D')\"> <\/div><div class=\"og-text\"><p class=\"og-title\">GitHub - nextlevelbuilder\/ui-ux-pro-max-skill: An AI SKILL that provide design intelligence for building professional UI\/UX mult<\/p><p class=\"og-desc\">An AI SKILL that provide design intelligence for building professional UI\/UX multiple platforms - nextlevelbuilder\/ui-ux-pro-max-skill<\/p><p class=\"og-host\">github.com<\/p><\/div><\/a><\/figure><p data-ke-size=\"size16\" style=\"text-align: justify;\"><a href=\"https:\/\/github.com\/vercel-labs\/agent-skills\" target=\"_blank\"><span>https:\/\/github.com\/vercel-labs\/agent-skills<\/span><\/a><\/p><figure data-ke-type=\"opengraph\" data-og-title=\"GitHub - vercel-labs\/agent-skills: Vercel's official collection of agent skills\" data-ke-align=\"alignCenter\" data-og-description=\"Vercel's official collection of agent skills. Contribute to vercel-labs\/agent-skills development by creating an account on GitHub.\" data-og-host=\"github.com\" data-og-source-url=\"https:\/\/github.com\/vercel-labs\/agent-skills\" data-og-image=\"https:\/\/blog.kakaocdn.net\/dna\/eN5p9\/dJMb9eTPNZF\/AAAAAAAAAAAAAAAAAAAAAKL4WTquY47WxTqAYFpzlLZydNqcoMSTlfvWv-JG5BT_\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1774969199&amp;allow_ip=&amp;allow_referer=&amp;signature=yEjnnf8X%2FUrV5CaELS3JxSH8EeI%3D\" data-og-url=\"https:\/\/github.com\/vercel-labs\/agent-skills\"><a href=\"https:\/\/github.com\/vercel-labs\/agent-skills\" target=\"_blank\" data-source-url=\"https:\/\/github.com\/vercel-labs\/agent-skills\"><div class=\"og-image\" style=\"background-image: url('https:\/\/blog.kakaocdn.net\/dna\/eN5p9\/dJMb9eTPNZF\/AAAAAAAAAAAAAAAAAAAAAKL4WTquY47WxTqAYFpzlLZydNqcoMSTlfvWv-JG5BT_\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1774969199&amp;allow_ip=&amp;allow_referer=&amp;signature=yEjnnf8X%2FUrV5CaELS3JxSH8EeI%3D')\"> <\/div><div class=\"og-text\"><p class=\"og-title\">GitHub - vercel-labs\/agent-skills: Vercel's official collection of agent skills<\/p><p class=\"og-desc\">Vercel's official collection of agent skills. Contribute to vercel-labs\/agent-skills development by creating an account on GitHub.<\/p><p class=\"og-host\">github.com<\/p><\/div><\/a><\/figure><p data-ke-size=\"size16\" style=\"text-align: justify;\">&nbsp;<br>\uc774 \uc678\uc5d0\ub3c4 \ub2e4\uc591\ud55c \ubd84\uc57c\uc758 \uc2a4\ud0ac\uc774 Github\ub97c \ud1b5\ud574 \uc624\ud508\uc18c\uc2a4\ub85c \ub9ce\uc774 \uacf5\uc720\ub418\uace0 \uc788\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 style=\"text-align: justify;\" data-ke-size=\"size23\">\uc2e4\uc81c \uc0ac\uc6a9 \uc608\uc2dc<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\" style=\"text-align: justify;\">Agent\ub97c \uc2e4\uc81c\ub85c \uc0ac\uc6a9\ud558\uba74 \ub2e4\uc74c\uacfc \uac19\uc774 \ub3d9\uc791\ud55c\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"402\" data-origin-height=\"582\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/p3c0S\/dJMcahKFzcC\/3bryKtrbjEeKStT2J5kBik\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/p3c0S\/dJMcahKFzcC\/3bryKtrbjEeKStT2J5kBik\/img.png\" data-alt=\"Subagent \uc0dd\uc131\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/p3c0S\/dJMcahKFzcC\/3bryKtrbjEeKStT2J5kBik\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp3c0S%2FdJMcahKFzcC%2F3bryKtrbjEeKStT2J5kBik%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"402\" height=\"582\" data-origin-width=\"402\" data-origin-height=\"582\"\/><\/span><figcaption>Subagent \uc0dd\uc131<\/figcaption>\n<\/figure>\n<p data-ke-size=\"size16\" style=\"text-align: justify;\">&nbsp;<br>\uc704 \uc0ac\uc9c4\ucc98\ub7fc \uc0ac\uc6a9\uc790\uac00 \ud2b9\uc815 \uc5d0\uc774\uc804\ud2b8\ub97c \uc0ac\uc6a9\ud558\ub77c\uace0 \uba85\ub839\ud558\uba74 \uc54c\uc544\uc11c Boole\uc774\ub77c\ub294 \uc5d0\uc774\uc804\ud2b8\ub97c \uc0dd\uc131\ud558\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub2e4.<br>&nbsp;<br>\uc0dd\uc131\ub41c \uc5d0\uc774\uc804\ud2b8\ub294 \uc774\ud6c4 @ \ubb38\uc790\ub85c \uc9c1\uc811 \ud0dc\uadf8 \ud558\uc5ec \uc0ac\uc6a9\ud560 \uc218\ub3c4 \uc788\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"409\" data-origin-height=\"238\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/btGWCp\/dJMcabczIUE\/upB6Nnf20yGoz6YkLy1mNk\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/btGWCp\/dJMcabczIUE\/upB6Nnf20yGoz6YkLy1mNk\/img.png\" data-alt=\"\uc0dd\uc131\ub41c \uc11c\ube0c\uc5d0\uc774\uc804\ud2b8 \ud0dc\uadf8\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/btGWCp\/dJMcabczIUE\/upB6Nnf20yGoz6YkLy1mNk\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtGWCp%2FdJMcabczIUE%2FupB6Nnf20yGoz6YkLy1mNk%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"409\" height=\"238\" data-origin-width=\"409\" data-origin-height=\"238\"\/><\/span><figcaption>\uc0dd\uc131\ub41c \uc11c\ube0c\uc5d0\uc774\uc804\ud2b8 \ud0dc\uadf8<\/figcaption>\n<\/figure>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 style=\"text-align: justify;\" data-ke-size=\"size23\">\uc8fc\uc758\ud560 \uc810<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\" style=\"text-align: justify;\">Codex\uc758 \ud604 Multi Agent \uae30\ub2a5\uc740 \uc77d\uae30 \uc791\uc5c5\uc5d0 \ucd5c\uc801\ud654\ub418\uc5b4 \uc788\ub2e4.<br>&nbsp;<br>\ucf54\ub4dc\ub97c \ud3b8\uc9d1\ud558\ub294 \uc4f0\uae30 \uc791\uc5c5\uc740 \ube44\ud6a8\uc728\uc801\uc77c \uc218 \uc788\ub2e4.<br>&nbsp;<br>\uc65c\ub0d0\ud558\uba74 \uc5d0\uc774\uc804\ud2b8\ub07c\ub9ac \ubcd1\ub82c\ub85c \ucc98\ub9ac\ud558\ub294 \uacfc\uc815\uc5d0\uc11c \ucf54\ub4dc \ucda9\ub3cc\uc774 \ubc1c\uc0dd\ud560 \uc218 \uc788\uace0 \uc774\ub97c \ubc14\ub85c\uc7a1\uae30 \uc704\ud55c \uc624\ubc84\ud5e4\ub4dc\uac00 \uc99d\uac00\ud558\ub294 \ud604\uc0c1\uc774 \ubc1c\uc0dd\ud560 \uc218 \uc788\uae30 \ub54c\ubb38\uc774\ub2e4.<br>&nbsp;<br>\ub54c\ubb38\uc5d0 \ub3c5\ub9bd\uc801\uc73c\ub85c \ubcd1\ub82c \ucc98\ub9ac\uac00 \ud544\uc694\ud55c \uc791\uc5c5\uc5d0 \uc0ac\uc6a9\ud558\ub294 \uac83\uc744 \uad8c\uc7a5\ud55c\ub2e4.&nbsp;<\/p>","category":["\uae30\ud0c0","AI"],"author":"MaKa_","guid":"https:\/\/mk-develop.tistory.com\/65","comments":"https:\/\/mk-develop.tistory.com\/entry\/Codex-Multi-Agent-Custom-Agent-%EC%84%B8%ED%8C%85%ED%95%98%EA%B8%B0#entry65comment","pubDate":"Tue, 31 Mar 2026 14:59:35 +0900"},{"title":"60\ud68c SQLD \uc804\uacf5\uc790 \ud569\uaca9 \ud6c4\uae30","link":"https:\/\/mk-develop.tistory.com\/entry\/60%ED%9A%8C-SQLD-%EC%A0%84%EA%B3%B5%EC%9E%90-%ED%95%A9%EA%B2%A9-%ED%9B%84%EA%B8%B0","description":"<h3 data-ke-size=\"size23\">\uac1c\uc694<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc774\ubc88\uc5d0 \uc81c 60\ud68c SQLD \uc2dc\ud5d8\uc744 \uc751\uc2dc\ud558\uc600\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc774\ub825\uc11c\uc5d0 \uc790\uaca9\uc99d \ub780\uc774 \ud56d\uc0c1 \ube44\uc5b4\uc788\uc5b4 \uc62c\ud574 \uc0c1\ubc18\uae30 \uc548\uc5d0 \uae30\ubcf8\uc801\uc778 \uc790\uaca9\uc99d\uc740 \ubaa8\ub450 \ucde8\ub4dd\ud558\ub294 \uac83\uc744 \ubaa9\ud45c\ub85c \uc7a1\uc558\ub2e4.<\/p>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">\uacf5\ubd80 \uc790\ub8cc<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"458\" data-origin-height=\"621\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/d7GtxC\/dJMb996Q4lV\/YvQkkAhYW89LkAsIrxPJdk\/img.jpg\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/d7GtxC\/dJMb996Q4lV\/YvQkkAhYW89LkAsIrxPJdk\/img.jpg\" data-alt=\"\ub178\ub7ad\uc774\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/d7GtxC\/dJMb996Q4lV\/YvQkkAhYW89LkAsIrxPJdk\/img.jpg\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7GtxC%2FdJMb996Q4lV%2FYvQkkAhYW89LkAsIrxPJdk%2Fimg.jpg\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"292\" height=\"396\" data-origin-width=\"458\" data-origin-height=\"621\"\/><\/span><figcaption>\ub178\ub7ad\uc774<\/figcaption>\n<\/figure>\n<\/p>\n<p data-ke-size=\"size16\">\uacf5\ubd80\ub294 \ub178\ub7ad\uc774\uc640 \uce5c\uad6c\ub4e4\uc5d0\uac8c \ubc1b\uc740 SQLD pdf\ub97c \uc0ac\uc6a9\ud558\uc600\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">pdf\ub97c \uc774\uc6a9\ud558\uc5ec \uae30\ubcf8\uc801\uc778 \uc774\ub860\uc744 \uacf5\ubd80\ud558\uace0 \ub178\ub7ad\uc774\ub97c 1\ud68c\ub3c5 \ud558\uc600\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">pdf 1\ud68c\ub3c5\uc740 \ud558\ub8e8 \ud3c9\uade0 30\ubd84~1\uc2dc\uac04\uc529 \uc77c\uc8fc\uc77c, \ub178\ub7ad\uc774\ub294 1\uacfc\ubaa9, 2\uacfc\ubaa9 1, 2\uacfc\ubaa9 2\ub97c \ud558\ub8e8\uc5d0 \ud55c \uacfc\ubaa9\uc529 \uc9c4\ud589\ud558\uc600\ub2e4.<span style=\"color: #9d9d9d;\"><s>(\uc2dc\ud5d8 6\uc2dc\uac04 \uc804\uae4c\uc9c0 \uc601\ud63c\uc758 \ubcbc\ub77d\uce58\uae30)<\/s><\/span><\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ub178\ub7ad\uc774\ub294 \uc2e4\uc81c \uc2dc\ud5d8\uc5d0 \ube44\ud574 \ubb38\uc81c \ub09c\uc774\ub3c4\uac00 \ub9ce\uc774 \uc5b4\ub824\uc6b4 \ud3b8\uc774\uc5c8\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc6d0\ub798 \uacc4\ud68d\uc740 \uc2dc\ud5d8 \uc804\uae4c\uc9c0 \ub178\ub7ad\uc774\ub97c 1\ud68c\ub3c5 \ud558\uace0 \uc624\ub2f5\ub178\ud2b8\uae4c\uc9c0 \uc644\ubcbd\ud558\uac8c \ud558\ub294 \uac83\uc774\uc5c8\uc9c0\ub9cc \uadc0\ucc28\ub2c8\uc998\uc744 \uc774\uae30\uc9c0 \ubabb\ud558\uace0 \uc2dc\ud5d8 \ub2f9\uc77c\ub0a0 \uc0c8\ubcbd\uae4c\uc9c0 \ubb38\uc81c\ub9cc \uaca8\uc6b0\uaca8\uc6b0 1\ud68c\ub3c5 \ud588\ub2e4.<\/p>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">\uc2dc\ud5d8 \uacb0\uacfc<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"493\" data-origin-height=\"371\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/qLK7q\/dJMcabp5Ayq\/K4WKp5weSZsJUVkfFKz2M1\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/qLK7q\/dJMcabp5Ayq\/K4WKp5weSZsJUVkfFKz2M1\/img.png\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/qLK7q\/dJMcabp5Ayq\/K4WKp5weSZsJUVkfFKz2M1\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqLK7q%2FdJMcabp5Ayq%2FK4WKp5weSZsJUVkfFKz2M1%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"493\" height=\"371\" data-origin-width=\"493\" data-origin-height=\"371\"\/><\/span><\/figure>\n<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">60\ud68c \uc2dc\ud5d8 \uacb0\uacfc\ub294 3\uc6d4 20\uc77c\uc5d0 \ubc1c\ud45c\ub418\uc5c8\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ucd1d\uc810 70\uc810\uc73c\ub85c \ud569\uaca9\ud558\uc600\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p style=\"color: #333333; text-align: start;\" data-ke-size=\"size16\">\ucee4\ubba4\ub2c8\ud2f0 \ud6c4\uae30\ub4e4\uc744 \uc880 \uc0b4\ud3b4\ubcf4\ub2c8 60\ud68c\uc758 \uacbd\uc6b0 \uae30\ucd9c\uc5d0\uc11c \ubb38\uc81c\uac00 \uc880 \ub9ce\uc774 \ucd9c\uc81c\ub418\uc5c8\ub2e4\uace0 \ud55c\ub2e4.<\/p>\n<p style=\"color: #333333; text-align: start;\" data-ke-size=\"size16\">&nbsp;<\/p>\n<p style=\"color: #333333; text-align: start;\" data-ke-size=\"size16\">\uae30\ucd9c\ubb38\uc81c\ub97c \uac00\uc9c0\uace0 \uc788\ub2e4\uba74 \ub9ce\uc774 \ud480\uc5b4\ubcf4\uba74 \ub3c4\uc6c0\uc774 \ub420 \uac83 \uac19\ub2e4.<\/p>\n<p style=\"color: #333333; text-align: start;\" data-ke-size=\"size16\">&nbsp;<\/p>\n<p style=\"color: #333333; text-align: start;\" data-ke-size=\"size16\">\ub098\ub294 \uae30\ucd9c\ubb38\uc81c\uac00 \uc874\uc7ac\ud55c\ub2e4\ub294\uac78 \uc2dc\ud5d8 \ub2f9\uc77c\ub0a0\uc5d0 \uc54c\uc544\uc11c \ud55c \ud68c\ucc28\ub3c4 \ud480\uc5b4\ubcf4\uc9c0 \ubabb\ud588\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc544\ub9ac\uc1a1\ud55c \ubb38\uc81c\uac00 \uc880 \uc788\uc5c8\ub294\ub370 \ub2e4\ud589\ud788 \uc6b4\uc774 \uc88b\uc558\ub358 \uac83 \uac19\ub2e4.<\/p>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">\ud5a5\ud6c4 \uacc4\ud68d<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc800\ubc88 \ud68c\ucc28 \uc815\ucc98\uae30\ub97c \ub5a8\uc5b4\uc84c\ub294\ub370 \uc774\uc81c \uc815\ucc98\uae30\ub9cc \ucde8\ub4dd\ud558\uba74 \uc790\uaca9\uc99d\uc740 \uc5bc\ucd94 \ub9c8\ubb34\ub9ac \ub420 \uac83 \uac19\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc62c\ud574\ubd80\ud130 \uc5c5\uacc4\uc5d0 AI AGENT \uc5ed\ub7c9\uc774 \ubcf8\uaca9\uc801\uc73c\ub85c \ubd80\uc0c1\ud558\ub294 \uac83 \uac19\uc740\ub370 \ud604\uc7ac \uc9c4\ud589\ud558\uace0 \uc788\ub294 \ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c AI\ub97c \uae4e\ub294 \ub9db\uc774 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc62c\ud574\ub294 \ubc18\ub4dc\uc2dc \ucde8\ubf40\ud574\uc57c\uc9c0..<\/p>","category":["\uc774\uc57c\uae30\/\uc77c\uc0c1","sqld"],"author":"MaKa_","guid":"https:\/\/mk-develop.tistory.com\/64","comments":"https:\/\/mk-develop.tistory.com\/entry\/60%ED%9A%8C-SQLD-%EC%A0%84%EA%B3%B5%EC%9E%90-%ED%95%A9%EA%B2%A9-%ED%9B%84%EA%B8%B0#entry64comment","pubDate":"Thu, 26 Mar 2026 00:08:24 +0900"},{"title":"Notion MCP\ub97c \uc0ac\uc6a9\ud558\uc5ec swagger \ub300\uc2e0 \uc0ac\uc6a9\ud558\uae30","link":"https:\/\/mk-develop.tistory.com\/entry\/Notion-MCP%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-swagger-%EB%8C%80%EC%8B%A0-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0","description":"<h3 data-ke-size=\"size23\">\uac1c\uc694<\/h3>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc694\uc998 MCP\ub77c\ub294 \ud504\ub85c\ud1a0\ucf5c\uc774 \ud654\uc81c\uac00 \ub418\uace0 \uc788\ub2e4.<br \/>MCP\ub294 Model Context Protocol\uc758 \uc57d\uc790\ub85c <span style=\"color: #0a0a0a;\">AI \ubaa8\ub378(LLM)\uc774 \uc678\ubd80 \ub370\uc774\ud130, \ub3c4\uad6c, \uc2dc\uc2a4\ud15c\uacfc \ud45c\uc900\ud654\ub41c \ubc29\uc2dd\uc73c\ub85c \uc5f0\uacb0\ub418\ub3c4\ub85d \ud558\ub294 \uc778\ud130\ud398\uc774\uc2a4\uc774\ub2e4.<\/span><br \/>&nbsp;<br \/><span style=\"color: #0a0a0a;\">\uc774\ubc88\uc5d0 \uc9c4\ud589\ud558\ub294 \ud300 \ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c\ub294 \uac1c\ubc1c \uc804\uc5d0 Notion database\uc5d0 API \uc694\uccad\uc744 \uc815\ub9ac\ud558\uc600\ub2e4.<\/span><br \/>&nbsp;<br \/><span style=\"color: #0a0a0a;\">\uadf8\ub807\ub2e4\uba74 llm \ubaa8\ub378\uc774 Notion database\ub97c \uc9c1\uc811 \uc811\uadfc\ud574\uc11c \uc77d\uc740 \ud6c4 \ub2f5\ubcc0\uc744 \uc900\ub2e4\uba74 \ub354\uc6b1 \uc815\ud655\ub3c4\uac00 \ub192\uc544\uc9c0\uc9c0 \uc54a\uc744\uae4c? \ub77c\ub294 \uc0dd\uac01\uc744 \ud558\uac8c \ub418\uc5c8\ub2e4.<\/span><br \/>&nbsp;<br \/><span style=\"color: #0a0a0a;\">\ubcf8 \uae00\uc740 \ud14c\uc2a4\ud2b8 \uc218\ud589 \uc808\ucc28\uc640 \uacb0\uacfc\uc5d0 \ub300\ud574 \ub2e4\ub8ec\ub2e4.<\/span><br \/>&nbsp;<br \/><span style=\"color: #0a0a0a;\">\uc218\ud589 \ud658\uacbd<\/span><br \/><span style=\"color: #0a0a0a;\">Node.js 22.14.0<\/span><br \/><span style=\"color: #0a0a0a;\">AI Agent: Codex<\/span><br \/><span style=\"color: #0a0a0a;\">MCP: Notion<\/span><br \/><span style=\"color: #0a0a0a;\">IDE: VS Code<\/span><\/p>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">Codex \uc124\uc815<\/h3>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">Codex \uc6b0\uce21 \uc0c1\ub2e8\uc758 \uc124\uc815 &rArr; Codex \uc124\uc815 &rArr; config.toml \uc5f4\uae30 \uc120\ud0dd \ud6c4 \uc544\ub798\uc640 \uac19\uc774 \uc791\uc131<\/p>\n<pre class=\"bash\" data-ke-type=\"codeblock\" data-ke-language=\"bash\"><code>[mcp_servers.notion]\nurl = \"https:\/\/mcp.notion.com\/mcp\"<\/code><\/pre>\n<p data-ke-size=\"size16\">&nbsp;<br \/>\ud130\ubbf8\ub110\uc5d0<span style=\"color: #ee2323;\"> <\/span><span style=\"color: #ee2323;\">codex mcp login notion<\/span> \uc785\ub825 \ud6c4 \uc778\uc99d<\/p>\n<p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"567\" data-origin-height=\"762\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/bFyUWK\/dJMcaaYvn1I\/cXDFneM23JLsBipfsg0JqK\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/bFyUWK\/dJMcaaYvn1I\/cXDFneM23JLsBipfsg0JqK\/img.png\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/bFyUWK\/dJMcaaYvn1I\/cXDFneM23JLsBipfsg0JqK\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFyUWK%2FdJMcaaYvn1I%2FcXDFneM23JLsBipfsg0JqK%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"329\" height=\"442\" data-origin-width=\"567\" data-origin-height=\"762\"\/><\/span><\/figure>\n<\/p>\n<p data-ke-size=\"size16\">\uac8c\uc2a4\ud2b8 \uc790\uaca9\uc73c\ub85c\ub294 MCP\uc5d0 \uc5f0\uacb0\uc774 \ub418\uc9c0 \uc54a\uc73c\ubbc0\ub85c \uba64\ubc84 \uc774\uc0c1\uc758 \uad8c\ud55c\uc774 \uc788\ub294\uc9c0 \ud655\uc778\uc774 \ud544\uc694\ud558\ub2e4.<br \/>&nbsp;<br \/>\uc774\ud6c4 Codex\uc5d0\uac8c Notion MCP \ub3c4\uad6c \uc870\ud68c\ub97c \uc694\uccad\ud558\uace0 \ub2e4\uc74c\uacfc \uac19\uc740 \uc751\ub2f5\uc774 \uc628\ub2e4\uba74 \uc5f0\uacb0\uc774 \uc131\uacf5\uc801\uc73c\ub85c \uc644\ub8cc\ub418\uc5c8\uc74c\uc744 \uc758\ubbf8\ud55c\ub2e4.<\/p>\n<p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"386\" data-origin-height=\"519\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/duJOf0\/dJMb996nFsV\/DEewidrmxy8Vnz3I90kEBk\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/duJOf0\/dJMb996nFsV\/DEewidrmxy8Vnz3I90kEBk\/img.png\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/duJOf0\/dJMb996nFsV\/DEewidrmxy8Vnz3I90kEBk\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FduJOf0%2FdJMb996nFsV%2FDEewidrmxy8Vnz3I90kEBk%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"386\" height=\"519\" data-origin-width=\"386\" data-origin-height=\"519\"\/><\/span><\/figure>\n<\/p>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">API \ubd88\ub7ec\uc624\uae30 \ud14c\uc2a4\ud2b8<\/h3>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\ub178\uc158\uc758 API database\ub97c \uc131\uacf5\uc801\uc73c\ub85c \ubd88\ub7ec\uc624\ub294\uc9c0 \uc5ec\ubd80\ub97c \uccb4\ud06c\ud55c\ub2e4.<\/p>\n<p><figure class=\"imagegridblock\">\n  <div class=\"image-container\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/nwYaM\/dJMcai3f3h4\/8KtKUxWZFGSOhBfYL6HJ01\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/nwYaM\/dJMcai3f3h4\/8KtKUxWZFGSOhBfYL6HJ01\/img.png\" data-origin-width=\"375\" data-origin-height=\"437\" style=\"width: 25.1624%;\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/nwYaM\/dJMcai3f3h4\/8KtKUxWZFGSOhBfYL6HJ01\/img.png\" alt=\"\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnwYaM%2FdJMcai3f3h4%2F8KtKUxWZFGSOhBfYL6HJ01%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"375\" height=\"437\"\/><\/span><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/ozTUa\/dJMcaiPI9yC\/YHI06n6yZSMn9ircA7FGkK\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/ozTUa\/dJMcaiPI9yC\/YHI06n6yZSMn9ircA7FGkK\/img.png\" data-origin-width=\"372\" data-origin-height=\"377\" style=\"width: 28.9337%;\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/ozTUa\/dJMcaiPI9yC\/YHI06n6yZSMn9ircA7FGkK\/img.png\" alt=\"\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FozTUa%2FdJMcaiPI9yC%2FYHI06n6yZSMn9ircA7FGkK%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"372\" height=\"377\"\/><\/span><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/zxl1i\/dJMcag5vQ3U\/nOoBkk2G0JikASFj4daKj0\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/zxl1i\/dJMcag5vQ3U\/nOoBkk2G0JikASFj4daKj0\/img.png\" data-origin-width=\"376\" data-origin-height=\"253\" style=\"width: 43.5783%;\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/zxl1i\/dJMcag5vQ3U\/nOoBkk2G0JikASFj4daKj0\/img.png\" alt=\"\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzxl1i%2FdJMcag5vQ3U%2FnOoBkk2G0JikASFj4daKj0%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"376\" height=\"253\"\/><\/span><\/div>\n<\/figure>\n<\/p>\n<p data-ke-size=\"size16\">\uc704 \uc0ac\uc9c4\ucc98\ub7fc API\ub97c \uc815\ud655\ud558\uac8c \uc870\ud68c\ud574\uc624\ub294 \uac83\uc744 \ud655\uc778\ud560 \uc218 \uc788\uc5c8\ub2e4.<br \/>&nbsp;<br \/>\ub2e8 \ucc98\uc74c\ubd80\ud130 \ubc14\ub85c \uc6d0\ud558\ub294 \uacb0\uacfc\uac00 \ub098\uc624\uc9c4 \uc54a\uc558\ub2e4. \ub54c\ubb38\uc5d0 \uc9c0\uce68\uc744 \uc62c\ubc14\ub974\uac8c \uc791\uc131\ud574\uc57c \ud560 \ud544\uc694\ub97c \ub290\uaf08\ub2e4.<\/p>","category":"\uae30\ud0c0","author":"MaKa_","guid":"https:\/\/mk-develop.tistory.com\/63","comments":"https:\/\/mk-develop.tistory.com\/entry\/Notion-MCP%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-swagger-%EB%8C%80%EC%8B%A0-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0#entry63comment","pubDate":"Wed, 11 Feb 2026 18:54:24 +0900"},{"title":"[\uc790\ub8cc\uad6c\uc870] \uc791\uc5c5 \uae30\ubc18 CRDT : Protocol(Operation based CRDTs: protocol )","link":"https:\/\/mk-develop.tistory.com\/entry\/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%9E%91%EC%97%85-%EA%B8%B0%EB%B0%98-CRDT-ProtocolOperation-based-CRDTs-protocol","description":"<h3 data-ke-size=\"size23\">\uac1c\uc694<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc774\uc804 \uae00\uc5d0\uc11c\ub294 \uc0c1\ud0dc \uae30\ubc18 CRDT\uc5d0 \ub300\ud574\uc11c \uc54c\uc544\ubcf4\uc558\ub2e4.<\/p>\n<p data-ke-size=\"size16\"><a href=\"https:\/\/mk-develop.tistory.com\/entry\/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-CRDT-%EC%8B%A4%EC%8B%9C%EA%B0%84-%ED%98%91%EC%97%85-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85\" target=\"_blank\" rel=\"noopener\">2025.11.26 - [CS\/\uc790\ub8cc\uad6c\uc870(data structure)] - [\uc790\ub8cc\uad6c\uc870] CRDT - \uc2e4\uc2dc\uac04 \ud611\uc5c5 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \uc704\ud55c \ub370\uc774\ud130 \ud0c0\uc785<\/a><\/p>\n<figure id=\"og_1764330624041\" contenteditable=\"false\" data-ke-type=\"opengraph\" data-ke-align=\"alignCenter\" data-og-type=\"article\" data-og-title=\"[\uc790\ub8cc\uad6c\uc870] CRDT - \uc2e4\uc2dc\uac04 \ud611\uc5c5 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \uc704\ud55c \ub370\uc774\ud130 \ud0c0\uc785\" data-og-description=\"\uac1c\uc694\uc694\uc998\uc5d0 \uc5f0\uad6c\uc2e4 \ud615\uacfc \uc0c8\ub85c\uc6b4 \ud504\ub85c\uc81d\ud2b8\ub97c \uc2dc\uc791\ud558\uc600\ub2e4. \ud504\ub85c\uc81d\ud2b8\uc5d0 \uc694\uad6c\ub418\ub294 \uae30\uc220 \uc911 \ud558\ub098\ub85c \uc5ec\ub7ec \uc0ac\uc6a9\uc790\uc640 \uc2e4\uc2dc\uac04\uc73c\ub85c \ud611\uc5c5\uc774 \uac00\ub2a5\ud574\uc57c \ud55c\ub2e4\ub294 \ud56d\ubaa9\uc774 \uc788\ub2e4. \uc6b0\ub9ac\ub294 \uc2e4\uc2dc\uac04 \ud611\uc5c5 \ud504\ub85c\uadf8\ub7a8\uc73c\" data-og-host=\"mk-develop.tistory.com\" data-og-source-url=\"https:\/\/mk-develop.tistory.com\/entry\/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-CRDT-%EC%8B%A4%EC%8B%9C%EA%B0%84-%ED%98%91%EC%97%85-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85\" data-og-url=\"https:\/\/mk-develop.tistory.com\/entry\/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-CRDT-%EC%8B%A4%EC%8B%9C%EA%B0%84-%ED%98%91%EC%97%85-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85\" data-og-image=\"https:\/\/scrap.kakaocdn.net\/dn\/qyDsz\/hyZOJXr2UR\/7QZJPt6zovi5aFhIO0XvD0\/img.gif?width=762&amp;height=190&amp;face=0_0_762_190,https:\/\/scrap.kakaocdn.net\/dn\/IkqGE\/hyZOuAoXSV\/Xxg7t26GMxvEs4qyhwI0Y0\/img.gif?width=762&amp;height=190&amp;face=0_0_762_190\"><a href=\"https:\/\/mk-develop.tistory.com\/entry\/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-CRDT-%EC%8B%A4%EC%8B%9C%EA%B0%84-%ED%98%91%EC%97%85-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85\" target=\"_blank\" rel=\"noopener\" data-source-url=\"https:\/\/mk-develop.tistory.com\/entry\/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-CRDT-%EC%8B%A4%EC%8B%9C%EA%B0%84-%ED%98%91%EC%97%85-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85\">\n<div class=\"og-image\" style=\"background-image: url('https:\/\/scrap.kakaocdn.net\/dn\/qyDsz\/hyZOJXr2UR\/7QZJPt6zovi5aFhIO0XvD0\/img.gif?width=762&amp;height=190&amp;face=0_0_762_190,https:\/\/scrap.kakaocdn.net\/dn\/IkqGE\/hyZOuAoXSV\/Xxg7t26GMxvEs4qyhwI0Y0\/img.gif?width=762&amp;height=190&amp;face=0_0_762_190');\">&nbsp;<\/div>\n<div class=\"og-text\">\n<p class=\"og-title\" data-ke-size=\"size16\">[\uc790\ub8cc\uad6c\uc870] CRDT - \uc2e4\uc2dc\uac04 \ud611\uc5c5 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \uc704\ud55c \ub370\uc774\ud130 \ud0c0\uc785<\/p>\n<p class=\"og-desc\" data-ke-size=\"size16\">\uac1c\uc694\uc694\uc998\uc5d0 \uc5f0\uad6c\uc2e4 \ud615\uacfc \uc0c8\ub85c\uc6b4 \ud504\ub85c\uc81d\ud2b8\ub97c \uc2dc\uc791\ud558\uc600\ub2e4. \ud504\ub85c\uc81d\ud2b8\uc5d0 \uc694\uad6c\ub418\ub294 \uae30\uc220 \uc911 \ud558\ub098\ub85c \uc5ec\ub7ec \uc0ac\uc6a9\uc790\uc640 \uc2e4\uc2dc\uac04\uc73c\ub85c \ud611\uc5c5\uc774 \uac00\ub2a5\ud574\uc57c \ud55c\ub2e4\ub294 \ud56d\ubaa9\uc774 \uc788\ub2e4. \uc6b0\ub9ac\ub294 \uc2e4\uc2dc\uac04 \ud611\uc5c5 \ud504\ub85c\uadf8\ub7a8\uc73c<\/p>\n<p class=\"og-host\" data-ke-size=\"size16\">mk-develop.tistory.com<\/p>\n<\/div>\n<\/a><\/figure>\n<p data-ke-size=\"size16\">CRDT\ub294 \ud06c\uac8c \ub450 \uc885\ub958\ub85c \ub098\ub25c\ub2e4\uace0 \ud588\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ubc14\ub85c<b> \uc791\uc5c5 \uae30\ubc18 CRDT<\/b>\uc640 <b>\uc0c1\ud0dc \uae30\ubc18 CRDT<\/b>\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ubcf8 \uae00\uc5d0\uc11c\ub294 \uc791\uc5c5 \uae30\ubc18 CRDT\uc911 \ud558\ub098\uc778 <b>Protocol<\/b>\uc5d0 \ub300\ud574 \ub2e4\ub8ec\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ubcf8 \uae00\uc744 \uc644\ubcbd\ud558\uac8c \uc774\ud574\ud558\uae30 \uc704\ud574\uc120 <b>\uc774\ubca4\ud2b8\uc18c\uc2f1<\/b>\uacfc <b>vector clock<\/b>\uc5d0 \ub300\ud55c \uc774\ud574\uac00 \ud544\uc694\ud558\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ucc38\uace0\ud55c \uae00\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<p data-ke-size=\"size16\"><a href=\"https:\/\/www.bartoszsypytkowski.com\/operation-based-crdts-protocol\/\" target=\"_blank\" rel=\"noopener&nbsp;noreferrer\">https:\/\/www.bartoszsypytkowski.com\/operation-based-crdts-protocol\/<\/a><\/p>\n<figure id=\"og_1764330681246\" contenteditable=\"false\" data-ke-type=\"opengraph\" data-ke-align=\"alignCenter\" data-og-type=\"article\" data-og-title=\"Operation based CRDTs: protocol\" data-og-description=\"Today we'll continue a series about CRDTs, this time however we'll stray from the path of state-based CRDTs and start talking about their operation-based relatives. The major difference that we need to cover, is the center of gravity of this approach: the \" data-og-host=\"www.bartoszsypytkowski.com\" data-og-source-url=\"https:\/\/www.bartoszsypytkowski.com\/operation-based-crdts-protocol\/\" data-og-url=\"https:\/\/www.bartoszsypytkowski.com\/operation-based-crdts-protocol\/\" data-og-image=\"https:\/\/scrap.kakaocdn.net\/dn\/r9Bg0\/hyZOlwLpeE\/CHb8bMenDVbmxLEa4gmOYK\/img.png?width=1243&amp;height=967&amp;face=0_0_1243_967,https:\/\/scrap.kakaocdn.net\/dn\/Bmpen\/hyZOy3S5o5\/UmNvS18ckCiknKkqPRnce0\/img.png?width=1246&amp;height=964&amp;face=0_0_1246_964\"><a href=\"https:\/\/www.bartoszsypytkowski.com\/operation-based-crdts-protocol\/\" target=\"_blank\" rel=\"noopener\" data-source-url=\"https:\/\/www.bartoszsypytkowski.com\/operation-based-crdts-protocol\/\">\n<div class=\"og-image\" style=\"background-image: url('https:\/\/scrap.kakaocdn.net\/dn\/r9Bg0\/hyZOlwLpeE\/CHb8bMenDVbmxLEa4gmOYK\/img.png?width=1243&amp;height=967&amp;face=0_0_1243_967,https:\/\/scrap.kakaocdn.net\/dn\/Bmpen\/hyZOy3S5o5\/UmNvS18ckCiknKkqPRnce0\/img.png?width=1246&amp;height=964&amp;face=0_0_1246_964');\">&nbsp;<\/div>\n<div class=\"og-text\">\n<p class=\"og-title\" data-ke-size=\"size16\">Operation based CRDTs: protocol<\/p>\n<p class=\"og-desc\" data-ke-size=\"size16\">Today we'll continue a series about CRDTs, this time however we'll stray from the path of state-based CRDTs and start talking about their operation-based relatives. The major difference that we need to cover, is the center of gravity of this approach: the<\/p>\n<p class=\"og-host\" data-ke-size=\"size16\">www.bartoszsypytkowski.com<\/p>\n<\/div>\n<\/a><\/figure>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h2 data-ke-size=\"size26\"><b>Operation based CRDTs: protocol<\/b><\/h2>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc5f0\uc0b0 \uae30\ubc18 CRDT\uc5d0\uc11c \uc0ac\uc6a9\ub418\ub294 \ud575\uc2ec \ubcf5\uc81c \ud504\ub85c\ud1a0\ucf5c\uc740 <b>&lsquo;Reliable Causal Broadcast(RCB)&rsquo;<\/b>\ub77c\uace0 \uc124\uba85\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\ud558\uc9c0\ub9cc \uc774\uac74 \uc2e4\uc81c \ud2b9\uc815 \uc54c\uace0\ub9ac\uc998 \uc774\ub984\uc774\ub77c\uae30\ubcf4\ub2e4\ub294, \uc774 \ud504\ub85c\ud1a0\ucf5c\uc774 \ucda9\uc871\ud574\uc57c \ud558\ub294 <b>&lsquo;\uc694\uad6c\uc0ac\ud56d\ub4e4\uc758 \uc9d1\ud569&rsquo;<\/b>\uc744 \uac00\ub9ac\ud0a4\ub294 \ud45c\ud604\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc989 RCB\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\">\n<li><b>Reliable<\/b> : \uba54\uc138\uc9c0\uac00 \uc720\uc2e4\ub418\uba74 \uc548\ub428<\/li>\n<li><b>Causal<\/b> : \uc778\uacfc\uad00\uacc4(\uc6d0\uc778 - \uacb0\uacfc) \uc21c\uc11c\ub97c \ubcf4\uc7a5\ud574\uc57c \ud568<\/li>\n<li><b>Broadcast<\/b> : \ubaa8\ub4e0 \ub178\ub4dc\uc5d0 \uc804\ud30c\ub418\uc5b4\uc57c \ud568<\/li>\n<\/ul>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h2 data-ke-size=\"size26\">Reliability<\/h2>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">CRDT\uc5d0\uc11c <b>\uc2e0\ub8b0\uc131<\/b>\uc740 <b>\ub85c\uceec\uc5d0\uc11c \ubcfc \uc218 \uc788\ub294 \ubaa8\ub4e0 \uc5c5\ub370\uc774\ud2b8\ub294 \uacb0\uad6d \ub2e4\ub978 \ud53c\uc5b4\uc5d0\uac8c\ub3c4 \ubcf4\uc5ec\uc838\uc57c \ud55c\ub2e4.<\/b> \ub77c\ub294 \uac83\uc744 \uc758\ubbf8\ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ub2f9\uc5f0\ud55c \ub9d0\ucc98\ub7fc \ub4e4\ub9ac\uc9c0\ub9cc \uc2e4\uc81c\ub85c \uc774\uac00 \uc9c0\ucf1c\uc9c0\uc9c0 \uc54a\ub294 \uc0c1\ud669\ub4e4\uc774 \uc790\uc8fc \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc2dc\uc2a4\ud15c\uc774 \uacc4\uc18d \uc791\ub3d9\ud574\uc57c \ud558\ub294\ub370 \uc8fc\uae30\uc801\uc73c\ub85c \uc5f0\uacb0\uc774 \ub04a\uae30\ub294 \uacbd\uc6b0, \ub85c\uceec\uc5d0\uc11c \uc0c1\ud0dc\ub97c \uc5c5\ub370\uc774\ud2b8 \ud588\ub294\ub370 \ud558\ud544 \uadf8 \uc2dc\uc810\uc5d0 \uc2dc\uc2a4\ud15c\uc774 \uc885\ub8cc\ub418\uc5c8\ub2e4\uac00 \ub2e4\uc2dc \ubcf5\uad6c\ub418\ub294 \uacbd\uc6b0. \ub85c\uceec\uc5d0\uc11c \ucee4\ubc0b\uc744 \ud55c \uacbd\uc6b0\uc5d0\ub3c4 \ub2e4\ub978 \ud53c\uc5b4\uc5d0\uac8c \uc774 \uc5c5\ub370\uc774\ud2b8\ub97c \uc804\uc1a1\ud574\uc57c \ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ub9cc\uc57d \uadf8\ub807\uac8c \ud558\uc9c0 \ubabb\ud55c\ub2e4\uba74 desynchronized state \uc989 \ube44\ub3d9\uae30\ud654 \uc0c1\ud0dc\uc5d0 \ube60\uc9c0\uac8c \ub41c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ub354 \uc911\uc694\ud55c \uac83\uc740 CRDT\ub294 \uc751\ub2f5\uacfc \uc5c5\ub370\uc774\ud2b8\uac00 \ub3d9\uc2dc\uc5d0 \uc77c\uc5b4\ub098\ub294 \uac83\uc73c\ub85c \uc54c\ub824\uc838 \uc788\ub2e4\ub294 \uac83\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc6b0\ub9ac\ub294 \ub2e4\ub978 \ub178\ub4dc\uac00 \uc5c5\ub370\uc774\ud2b8\ub97c \ubc1b\uc558\ub294\uc9c0 \ud655\uc778\ud560 \ub54c \uae4c\uc9c0 \uae30\ub2e4\ub838\ub2e4\uac00 \ub85c\uceec\uc5d0 \ubc18\uc601\ud560 \ud544\uc694\uac00 \uc5c6\ub2e4.<\/p>\n<p data-ke-size=\"size16\">CRDT\ub294 \uc624\ud504\ub77c\uc778 \ubaa8\ub4dc\ub97c \ud3ec\ud568\ud574\uc11c \uac01 \ub178\ub4dc\uac00 \ub3c5\ub9bd\uc801\uc73c\ub85c \ub3d9\uc791\ud558\ub3c4\ub85d \uc124\uacc4\ub418\uc5c8\uace0 \uadf8 \ud2b9\uc131\uc744 \uc720\uc9c0\ud574\uc57c \ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\"><b>\uc774\ubca4\ud2b8\uc18c\uc2f1<\/b>\uc774\ub77c\ub294 \ubc29\uc2dd\uc774 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\uc774 \ubc29\uc2dd\uc740 \uc791\uc5c5 \uae30\ubc18 CRDT\uc5d0 \ud544\uc694\ub85c \ud558\ub294 \uc870\uac74\ub4e4\uacfc \ub9e4\uc6b0 \uc798 \ub9de\ub294\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\ubaa8\ub4e0 \uc5c5\ub370\uc774\ud2b8\ub97c <b>\uc774\ubca4\ud2b8\ub85c \uc800\uc7a5<\/b>\ud574\ub450\uace0, <b>\ud544\uc694\ud560 \ub54c \ub2e4\uc2dc \uc7ac\uc0dd<\/b>\ud560 \uac83\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\ub0a8\uc740 \ubb38\uc81c\ub294 \uc774 <b>\uc774\ubca4\ud2b8\ub4e4\uc744 \uc5b4\ub5bb\uac8c \ub2e4\ub978 \ub178\ub4dc\ub4e4\uc5d0\uac8c \ubcf5\uc81c\ud560 \uac83\uc778\uc9c0<\/b>\ub2e4.<\/p>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h2 data-ke-size=\"size26\">Causality<\/h2>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc774 \ubb38\uc81c\ub97c Kafka\ub098 Pulsar\uc640 \uac19\uc740 \uc774\ubca4\ud2b8 \ub85c\uadf8 \uc2dc\uc2a4\ud15c\uc744 \uc0ac\uc6a9\ud574\uc11c \ud574\uacb0\ud560 \uc218 \uc788\ub294\uc9c0\uc5d0 \ub300\ud574 \ubb3c\uc744 \uc218 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uadf8\ub7ec\ub098 \uc6b0\ub9ac\ub294 \uc774\ubbf8 \uc774\uac83\uc5d0 \ub300\ud55c \ub2f5\uc744 \uc54c\uace0 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">CRDT\uc5d0\uc11c \uc6d0\ud558\ub294 \uac83\uc740 <b>\uac01 \ub178\ub4dc\uac00 \uc644\uc804\ud788 \ub3c5\ub9bd\uc801\uc73c\ub85c \ub3d9\uc791\ud558\ub294 \uac83<\/b>\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ud558\uc9c0\ub9cc \ub300\ubd80\ubd84\uc758 \ubd84\uc0b0 \uc774\ubca4\ud2b8 \ub85c\uadf8 \uc2dc\uc2a4\ud15c\uc740 \uc774\ubca4\ud2b8\ub97c \uc800\uc7a5\ud560 \ub54c <b>\uc804\uccb4 \uc774\ubca4\ud2b8 \uc21c\uc11c\ub97c \ubaa8\ub4e0 \ub178\ub4dc\uac00 \ub3d9\uc77c\ud558\uac8c \ubcf4\ub3c4\ub85d \ud569\uc758<\/b>\ud574\uc57c \ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc989 \uc774 \uc774\ubca4\ud2b8\ub294 1\ubc88, \uc800 \uc774\ubca4\ud2b8\ub294 2\ubc88 \uc774\ub7ec\ud55c \uc21c\uc11c\ub97c <b>\ud074\ub7ec\uc2a4\ud130 \uc804\uccb4\uac00 \uac19\uc774 \ub9de\ucdb0\uc57c \ud558\uae30 \ub54c\ubb38\uc5d0<\/b>, \ub178\ub4dc\ub07c\ub9ac \ubc18\ub4dc\uc2dc <b>\uc11c\ub85c \ud1b5\uc2e0\ud574\uc11c \uc870\uc728<\/b>\ud574\uc57c \ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ub54c\ubb38\uc5d0 Kafka\ub098 Pulsar\uac19\uc740 \uc2dc\uc2a4\ud15c\uc740 \uac01 \ub178\ub4dc\uac00 \ud63c\uc790\uc11c \uc774\ubca4\ud2b8 \uc21c\uc11c\ub97c \uacb0\uc815\ud574\uc11c \uae30\ub85d\ud560 \uc218 \uc5c6\uace0, \uc624\ud504\ub77c\uc778 \uc0c1\ud0dc\uc5d0\uc11c\ub294 \uc544\uc608 \uc815\uc0c1\uc801\uc73c\ub85c \ub3d9\uc791\ud560 \uc218 \uc5c6\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc5ec\uae30\uc11c <b>\uc778\uacfc\uc131 - happens before \uad00\uacc4<\/b>\uac00 \uc911\uc694\ud574\uc9c4\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\"><b>\ubaa8\ub4e0 \uc774\ubca4\ud2b8\uac00 \uac01\uac01 \uc5b4\ub5a4 \uc21c\uc11c\ub85c \uc77c\uc5b4\ub0ac\ub294\uc9c0 \uc804\uccb4\uac00 \uacf5\uc720\ud558\ub294 \ud558\ub098\uc758 \uc808\ub300\uc801 \uc21c\uc11c\ub97c \uc720\uc9c0\ud558\uba74\uc11c<\/b>, \ub3d9\uc2dc\uc5d0 <b>\uac01 \ub178\ub4dc\uac00 \uc11c\ub85c \uc0c1\uad00\uc5c6\uc774 \ub3c5\ub9bd\uc801\uc73c\ub85c \uc774\ubca4\ud2b8\ub97c \uae30\ub85d<\/b>\ud558\uac8c \ud558\ub294\uac74 \ub458 \ub2e4 \ucda9\uc871\ud560 \uc218 \uc5c6\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\uc6b0\ub9ac\ub294 \ucf00\uc774\ud06c\ub97c \uba39\uc73c\uba74\uc11c \ub3d9\uc2dc\uc5d0 \uc774\ub97c \uac00\uc9c0\uace0 \uc788\uc744\uc21c \uc5c6\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc6b0\ub9ac\uac00 \uc81c\uacf5\ud560 \uc218 \uc788\ub294 \ucd5c\uace0\uc758 \ubcf4\uc7a5\uc740 <b>\uc774\ubca4\ud2b8 \uc804\uccb4\uc5d0 \ub300\ud55c \uc644\ubcbd\ud55c \uc21c\uc11c<\/b>\uac00 \uc544\ub2c8\ub77c <b>\ud544\uc694\ud55c \uacf3\uc5d0\uc11c\ub9cc \uc720\uc9c0\ub418\ub294 \ubd80\ubd84\uc801\uc778 \uc21c\uc11c<\/b>\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\uc774\uac83\uc744 <b>\uc778\uacfc\uc801 \uc21c\uc11c(causal ordering)<\/b>\ub77c\uace0 \ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uadf8\ub807\ub2e4\uba74 \uc778\uacfc\uc801 \uc21c\uc11c\ub294 \ubb34\uc5c7\uc744 \uc758\ubbf8\ud558\ub294\uac00?<\/p>\n<ol style=\"list-style-type: decimal;\" data-ke-list-type=\"decimal\">\n<li><b>\ub2e8\uc77c \ub178\ub4dc(\ub610\ub294 \ub2e8\uc77c Actor) \ub0b4\ubd80\uc5d0\uc11c \uc77c\uc5b4\ub09c \uc774\ubca4\ud2b8 \uc21c\uc11c\ub294 \ubcf4\uc7a5\ud560 \uc218 \uc788\ub2e4.<\/b>\n<ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\">\n<li>\uc608\ub97c \ub4e4\uc5b4 Alice\uac00 \uba3c\uc800 A\ub97c \uc4f0\uace0 \uadf8 \ub2e4\uc74c\uc5d0 B\ub97c \uc37c\ub2e4\uba74 \uc5b4\ub5a4 \ub178\ub4dc\uc5d0\uc11c \uc774 \uc774\ubca4\ud2b8\ub4e4\uc744 \uc77d\ub4e0, \ud56d\uc0c1 A &rarr; B \uc21c\uc11c\ub85c \ubcf4\uc778\ub2e4.<\/li>\n<li>\uc989 \ud55c \uc0ac\ub78c\uc774 \uc2a4\uc2a4\ub85c \ub9cc\ub4e0 \uc774\ubca4\ud2b8\ub4e4\uc758 \uc21c\uc11c\ub294 \uc808\ub300 \ub4a4\ubc14\ub00c\uc9c0 \uc54a\ub294\ub2e4.<\/li>\n<\/ul>\n<\/li>\n<li><b>\uc11c\ub85c \ub2e4\ub978 \ub178\ub4dc\uc5d0\uc11c \ub3d9\uc2dc\uc5d0 \uc77c\uc5b4\ub09c(concurrent) \uc774\ubca4\ud2b8\uc758 \uc21c\uc11c\ub294 \ubcf4\uc7a5\ud560 \uc218 \uc5c6\ub2e4.<\/b>\n<ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\">\n<li>Alice\ub294 A\ub97c \uc37c\uace0 Ben\uc740 \uac19\uc740 \uc2dc\uc810\uc5d0 B\ub97c \uc37c\ub2e4.<\/li>\n<li>\uc774 \ub458\uc744 <b>\uc11c\ub85c \uc0c1\ub300\uc758 \uc774\ubca4\ud2b8\ub97c \ubaa8\ub974\ub294 \uc0c1\ud0dc\uc5d0\uc11c \uc791\uc131\ud588\uc73c\ubbc0\ub85c<\/b> <b>\ub3d9\uc2dc\uc131(concurrency) \uad00\uacc4<\/b>\uc774\ub2e4.<\/li>\n<li>\uc774\ub97c \ub098\uc911\uc5d0 \uac01 \ub178\ub4dc\uac00 \uc11c\ub85c \ubcf5\uc81c\ud558\uba74 \uc5b4\ub5a4 \ub178\ub4dc\ub294 A &rarr; B \uc21c\uc11c\ub85c \ud569\uccd0\uc9c8 \uc218 \uc788\uace0 \uc5b4\ub5a4 \ub178\ub4dc\ub294 B &rarr; A \uc21c\uc11c\ub85c \ud569\uccd0\uc9c8 \uc218 \uc788\ub2e4.<\/li>\n<li>\uc989 <b>\uc804\uccb4 \ud074\ub7ec\uc2a4\ud130\uc5d0\uc11c \ub3d9\uc77c\ud55c \uc21c\uc11c\ub97c \uac15\uc81c\ud560 \uc218 \uc5c6\ub2e4.<\/b><\/li>\n<\/ul>\n<\/li>\n<li><b>\uc778\uacfc\uc131\uc774 \uc788\ub294 \uacbd\uc6b0(\ud55c \uc774\ubca4\ud2b8\uac00 \ub2e4\ub978 \uc774\ubca4\ud2b8\uc758 \uc6d0\uc778\uc774 \ub418\ub294 \uacbd\uc6b0) \uc11c\ub85c \ub2e4\ub978 \ub178\ub4dc\uc5d0\uc11c \uc77c\uc5b4\ub09c \uc77c\uc774\ub354\ub77c\ub3c4 \uc774\ubca4\ud2b8 \uc21c\uc11c\ub97c \ubcf4\uc7a5\ud560 \uc218 \uc788\ub2e4.<\/b>\n<ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\">\n<li>Alice\uac00 \uc774\ubca4\ud2b8 A\ub97c \uc791\uc131<\/li>\n<li>Ben\uc740 \uc774\ubca4\ud2b8 A\ub97c \ubcf4\uace0 B\ub77c\ub294 \uc751\ub2f5\uc744 \uc791\uc131(A happens before B)<\/li>\n<li>Sam\uc740 \uc774\ubca4\ud2b8 A\ub97c \ubcf4\uace0 C\ub77c\ub294 \uc751\ub2f5\uc744 \uc791\uc131(A happens before C)<\/li>\n<li><b>B\uc640 C\ub294 \uc11c\ub85c \ub3c5\ub9bd\uc801\uc73c\ub85c \ub3d9\uc2dc\uc5d0 \ub9cc\ub4e4\uc5b4\uc9d0<\/b> \uadf8\ub7ec\ubbc0\ub85c <b>A &rarr; B &rarr; C<\/b> \/ <b>A &rarr; C &rarr; B<\/b> \uc774\ub807\uac8c \uc774\ubca4\ud2b8\uac00 \ubcf5\uc81c\ub420 \uc218 \uc788\uc74c<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p data-ke-size=\"size16\">\uc6b0\ub9ac\ub294 \ubcf4\ud1b5 \uc774\ubca4\ud2b8 \uc21c\uc11c\ub77c\uace0 \ud558\uba74 \ud558\ub098\uc758 linear timeline\uc744 \ub5a0\uc62c\ub9b0\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ud558\uc9c0\ub9cc \ubd80\ubd84 \uc21c\uc11c\ub294 linear timeline\uc774 \uc544\ub2c8\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc774\ub97c \uc2dc\uac01\uc801\uc73c\ub85c \uc774\ud574\ud558\ub824\uba74, <b>\ubd80\ubd84 \uc21c\uc11c\ub294 \uc9c1\uc120\uc774 \uc544\ub2c8\ub77c tree \uad6c\uc870\ucc98\ub7fc \uc0dd\uae34 \uac83<\/b>\uc774\ub77c\uace0 \uc0dd\uac01\ud558\uba74 \ub41c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uac00\uc7a5 \uc88b\uc740 \uc608\ub294 <b>git \uc800\uc7a5\uc18c<\/b>\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\uc11c\ub85c \ub2e4\ub978 \uc0ac\ub78c\ub4e4\uc774 \ub3d9\uc2dc\uc5d0 \ucee4\ubc0b\ud558\uba74 <b>\ube0c\ub79c\uce58\uac00 \uc5ec\ub7ec \uac1c\ub85c \uac08\ub77c\uc9c0\uace0<\/b> \ub098\uc911\uc5d0 \ub3d9\uae30\ud654(merge)\ub97c \ud558\uba74 <b>\uadf8 \ube0c\ub79c\uce58\ub4e4\uc774 \ud569\uccd0\uc9c4\ub2e4.<\/b><\/p>\n<p data-ke-size=\"size16\">\uc804\uc5ed \uc21c\uc11c\ub97c \ub9cc\ub4e4 \ub54c\ub294 \ud754\ud788 \ud0c0\uc784\uc2a4\ud0ec\ud504(\ub0a0\uc9dc\ub098 \uc21c\uc11c \ubc88\ud638)\ub97c \uc0ac\uc6a9\ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ud558\uc9c0\ub9cc \ubd80\ubd84 \uc21c\uc11c\ub97c \ud310\ub2e8\ud558\uae30\uc5d4 \ud0c0\uc784\uc2a4\ud0ec\ud504\ub9cc\uc73c\ub85c\ub294 \ucda9\ubd84\ud558\uc9c0 \uc54a\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\uc65c\ub0d0\ud558\uba74 <b>\ub2e8\uc21c\ud55c \ud0c0\uc784\uc2a4\ud0ec\ud504 \ud558\ub098\ub9cc\uc73c\ub85c\ub294 \ub450 \uc774\ubca4\ud2b8\uac00 \ub3d9\uc2dc\uc131\uc778\uc9c0\ub97c \uad6c\ubcc4\ud560 \uc218 \uc5c6\uae30 \ub54c\ubb38\uc774\ub2e4.<\/b><\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc989 \ud0c0\uc784\uc2a4\ud0ec\ud504\ub9cc \uac00\uc9c0\uace0\ub294 <b>\uc11c\ub85c \ub2e4\ub978 \uc774\ubca4\ud2b8 \ub450\uac1c\uac00 \uc11c\ub85c \uc778\uacfc\uc801\uc73c\ub85c \uc774\uc5b4\uc838 \uc788\ub294\uc9c0, \uc544\ub2c8\uba74 \ub3c5\ub9bd\uc801\uc73c\ub85c \ub3d9\uc2dc\uc5d0 \ubc1c\uc0dd\ud55c \uac83\uc778\uc9c0<\/b> \uc54c \uc218 \uc5c6\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc6b0\ub9ac\ub294 \uc774 \ubb38\uc81c\ub97c \ud574\uacb0\ud558\uae30 \uc704\ud574 <b>vector clocks<\/b>\uc744 \uc0ac\uc6a9\ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\uc774\uc81c \uc2dc\ub098\ub9ac\uc624 \ud558\ub098\ub97c \ub5a0\uc62c\ub824 \ubcfc\uac83\uc774\ub2e4.<\/p>\n<ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\">\n<li>Alice\ub294 \uc774\ubca4\ud2b8 A\ub97c \ubcf4\ub0c8\ub2e4.<\/li>\n<li>A\ub294 Ben\uc5d0\uac8c \ubcf5\uc81c\ub418\uc5c8\uc9c0\ub9cc Sam\uc5d0\uac8c\ub294 \uc5f0\uacb0\uc774 \ub04a\uaca8\uc11c \uc544\uc9c1 \ubcf5\uc81c\ub418\uc9c0 \uc54a\uc558\ub2e4.<\/li>\n<li>Ben\uc740 A\ub97c \ubc1b\uc740 \ub4a4 \uc774\ub97c \uae30\ubc18\uc73c\ub85c \uc774\ubca4\ud2b8 B\ub97c \uc0dd\uc131\ud55c\ub2e4.<\/li>\n<li>Sam\uc740 Alice\uc640\ub294 \uc5f0\uacb0\ub418\uc5b4\uc788\uc9c0 \uc54a\uc9c0\ub9cc Ben\uacfc\ub294 \ud1b5\uc2e0\uc774 \uac00\ub2a5\ud558\uae30 \ub54c\ubb38\uc5d0 Ben &rarr; Sam \ubc29\ud5a5\uc758 \ubcf5\uc81c\ub294 \uacc4\uc18d \uc9c4\ud589\ub41c\ub2e4.<\/li>\n<\/ul>\n<p data-ke-size=\"size16\">\uc774 \uc0c1\uc0c1\uc744 \ub300\ud654\ub85c \ub098\ud0c0\ub0b4\uba74 \uc544\ub798\uc640 \uac19\ub2e4.<\/p>\n<p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"1246\" data-origin-height=\"964\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/WNX2b\/dJMcaiuXRsX\/MewWvhqFRR2aVEFT0fVARk\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/WNX2b\/dJMcaiuXRsX\/MewWvhqFRR2aVEFT0fVARk\/img.png\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/WNX2b\/dJMcaiuXRsX\/MewWvhqFRR2aVEFT0fVARk\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWNX2b%2FdJMcaiuXRsX%2FMewWvhqFRR2aVEFT0fVARk%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"623\" height=\"482\" data-origin-width=\"1246\" data-origin-height=\"964\"\/><\/span><\/figure>\n<\/p>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h2 data-ke-size=\"size26\">Replication<\/h2>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc9c0\uae08\uae4c\uc9c0\ucc98\ub7fc, \ub2e8\uc21c\ud55c push \ubc29\uc2dd\uc758 \uc54c\ub9bc \uc804\ub2ec\ub85c\ub294 \ubb38\uc81c\uac00 \ud574\uacb0\ub418\uc9c0 \uc54a\ub294\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\ub9cc\uc57d Bob\uc774 \uc790\uc2e0\uc758 <b>\uc774\ubca4\ud2b8 B<\/b>\ub9cc Sam\uc5d0\uac8c \ubcf4\ub0b8\ub2e4\uba74 Sam\uc740 \uadf8 \uc804\uc5d0 Bob\uc774 \uc54c\uace0 \uc788\ub358 <b>\uc774\uc804 \uc774\ubca4\ud2b8 A<\/b>\ub97c \ubc1b\uc9c0 \ubabb\ud558\uac8c \ub41c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\uc989 Sam\uc774 \ubcf4\uac8c \ub418\ub294 \uc774\ubca4\ud2b8 \uae30\ub85d\uc740 <b>\ubd88\uc644\uc804\ud55c \ud788\uc2a4\ud1a0\ub9ac<\/b>\uac00 \ub418\uc5b4\ubc84\ub9b0\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc774 \ubb38\uc81c\ub97c \ud574\uacb0\ud558\uae30 \uc704\ud574, \uc5c5\uacc4\uc5d0\uc11c\ub294 \uc77c\ubc18\uc801\uc73c\ub85c \uc0ac\uc6a9\ub418\ub294 \ub450 \uac00\uc9c0 \ubc29\ubc95\uc774 \uc788\ub2e4.<\/p>\n<ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\">\n<li><b>Hiding non-continuous segments of the event stream(\ubd88\uc5f0\uc18d\uc801\uc778 \uc774\ubca4\ud2b8 \uc2a4\ud2b8\ub9bc \uc228\uae30\uae30)<\/b>\n<ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\">\n<li>\uac01 \ud53c\uc5b4\ub294 <b>\uc790\uc2e0\uc774 \uc0dd\uc131\ud55c \uc774\ubca4\ud2b8\ub97c \ub2e4\ub978 \ub178\ub4dc\uc5d0\uac8c push<\/b>\ud558\ub294 \ubc29\uc2dd\uc73c\ub85c \ubcf5\uc81c\ud55c\ub2e4. \uadf8\ub7f0\ub370 <b>\uc774\ubca4\ud2b8\ub97c \ubc1b\ub294 \ucabd receiver\ub294 \ubc1b\uc740 \uc774\ubca4\ud2b8 \uc548\uc5d0 \uad6c\uba85 hole\uc774 \uc788\ub294\uc9c0 \ucd94\uc801<\/b>\ud55c\ub2e4. \uc608\ub97c \ub4e4\uc5b4 \ud0c0\uc784\uc2a4\ud0ec\ud504\uac00 {A:1, B:1} \uadf8\ub9ac\uace0 {A:2, B:3} \uc778 \uc774\ubca4\ud2b8\ub97c \ubc1b\uc73c\uba74 \uc6b0\ub9ac\ub294 <b>B:2 \ub77c\ub294 \uc774\ubca4\ud2b8\uac00 \uc911\uac04\uc5d0 \uc788\uc5c8\ub294\ub370, \uadf8\uac78 \ubc1b\uc9c0 \ubabb\ud588\uad6c\ub098<\/b> \ub77c\uace0 \uc608\uce21\ud560 \uc218 \uc788\ub2e4. \ub204\ub77d\ub41c \uc774\ubca4\ud2b8 B:2\ub97c \ubc1b\uae30 \uc804\uae4c\uc9c0 <b>B:3 \uc774\ud6c4\uc758 \ubaa8\ub4e0 \uc774\ubca4\ud2b8\ub97c invisible \ud558\ub3c4\ub85d \ud45c\uc2dc<\/b>\ud55c\ub2e4.<\/li>\n<li>\uc774 \ubc29\uc2dd\uc740 \ubb38\uc81c\uac00 \uc0dd\uae38 \uc218 \uc788\ub2e4. \uc608\ub97c \ub4e4\uc5b4 \ud55c \ud53c\uc5b4\uac00 \uc815\ub9d0 \uc624\ub7ab\ub3d9\uc548 \uc624\ud504\ub77c\uc778\uc774\uc5c8\ub2e4\uac00 \ub4a4\ub2a6\uac8c \uc544\uc8fc \uc624\ub798\ub41c \uc774\ubca4\ud2b8 \ud558\ub098\ub97c \uc804\uc1a1\ud55c\ub2e4\uace0 \uac00\uc815\ud574 \ubcf4\uaca0\ub2e4. \uadf8\ub7ec\uba74 <b>\ub2e4\ub978 \ud53c\uc5b4\ub4e4\uc740 \uadf8 \ub204\ub77d\ub41c \uc774\ubca4\ud2b8\uac00 \ub3c4\ucc29\ud560 \ub54c \uae4c\uc9c0 \uadf8 \uc774\ud6c4\uc758 \ubaa8\ub4e0 \uc774\ubca4\ud2b8\ub97c invisible \uc0c1\ud0dc\ub85c \uacc4\uc18d \uc313\uc544\ub450\uc5b4\uc57c \ud55c\ub2e4.<\/b> \uadf8 <b>invisible event\ub4e4\uc758 backlog\ub294 \uacc4\uc18d\ud574\uc11c \ucee4\uc9c0\uba70<\/b>, \uc2ec\uc9c0\uc5b4 <b>\uc601\uc6d0\ud788 \uacc4\uc18d\ub420 \uc218 \uc788\ub2e4.<\/b><\/li>\n<\/ul>\n<\/li>\n<li><b>Allowing replication of other peer&rsquo;s events(\ub2e4\ub978 \ud53c\uc5b4\uc758 \uc774\ubca4\ud2b8\uae4c\uc9c0 \ubcf5\uc81c\ud558\ub3c4\ub85d \ud5c8\uc6a9\ud558\uae30)<\/b>\n<ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\">\n<li>\ub450 \ubc88\uc9f8 \ubc29\ubc95\uc740 \uac01 \ud53c\uc5b4\uac00 \uc790\uc2e0\uc774 \ub9cc\ub4e0 \uc774\ubca4\ud2b8 \ubfd0 \uc544\ub2c8\ub77c \ub2e4\ub978 \ud53c\uc5b4\uac00 \uc0dd\uc131\ud55c \uc774\ubca4\ud2b8\ub3c4 \ud568\uaed8 \ubcf5\uc81c\ud558\ub3c4\ub85d \ub9cc\ub4dc\ub294 \uac83\uc774\ub2e4. \uc55e\uc758 \uc608\uc2dc\ub97c \uc0ac\uc6a9\ud574\uc11c \uc124\uba85\ud558\uba74 <b>Sam\uc740<\/b> Alice\uc640 \uc5f0\uacb0\uc774 \ub04a\uaca8 \uc788\uc5b4\uc11c <b>Alice\uac00 \ub9cc\ub4e0 \uc774\ubca4\ud2b8 A\ub97c \uc9c1\uc811 \ubc1b\uc744 \uc218 \uc5c6\ub2e4.<\/b> \ud558\uc9c0\ub9cc <b>Sam\uc740 Bob\uacfc\ub294 \uc5f0\uacb0\ub418\uc5b4 \uc788\ub2e4.<\/b> \ub530\ub77c\uc11c <b>Bob\uc774 \uc790\uc2e0\uc758 \uc774\ubca4\ud2b8 B\uc640 \ud568\uaed8 Bob\uc774 \uc774\ubbf8 \uac00\uc9c0\uace0 \uc788\ub294 Alice\uc758 \uc774\ubca4\ud2b8 A\ub3c4 Sam\uc5d0\uac8c \uc804\ub2ec\ud560 \uc218 \uc788\ub2e4.<\/b> \uc774\ub807\uac8c \ud558\uba74 \uc774\ubca4\ud2b8 \uc2a4\ud2b8\ub9bc \ud0c0\uc784\ub77c\uc778\uc5d0 \uad6c\uba4d\uc774 \uc0dd\uae30\ub294 \ubb38\uc81c\ub97c \ub9c9\uc744 \uc218 \uc788\ub2e4.<\/li>\n<li>\ud558\uc9c0\ub9cc \uc774 \ubc29\uc2dd\uc740 <b>\uc911\ubcf5 \ubb38\uc81c\uac00 \uc5c4\uccad\ub098\uac8c \ubc1c\uc0dd<\/b>\ud55c\ub2e4. \uc65c\ub0d0\ud558\uba74 \uc804\uccb4 \ud53c\uc5b4 \uc218\uac00 N\uc77c \uacbd\uc6b0 <b>\uac01 \ud53c\uc5b4\uac00 \ub2e4\ub978 \ubaa8\ub4e0 \ud53c\uc5b4\uc758 \uc774\ubca4\ud2b8\uae4c\uc9c0 \ubcf5\uc81c\ud558\ub294 \uad6c\uc870<\/b>\uc774\uae30\uc5d0 \uacb0\uad6d \ub124\ud2b8\uc6cc\ud06c\uc5d0 \ub5a0\ub2e4\ub2c8\ub294 \uba54\uc2dc\uc9c0 \uc218\ub294 (N - 1)^2 \uc218\uc900\uc774 \ub41c\ub2e4.<\/li>\n<li>\uc6b0\ub9ac\ub294 \uc774 \ubb38\uc81c\ub97c \uc5b4\ub5bb\uac8c \ud574\uacb0\ud560 \uc218 \uc788\uc744\uae4c? \uc774\ub97c \uac1c\uc120\ud558\uae30 \uc704\ud574 <b>\uc9c0\uae08\uae4c\uc9c0\ub294 sender\uac00 receiver\uc5d0\uac8c \uc9c1\uc811 push\ud558\ub294 \ubc29\uc2dd<\/b>\uc774\uc5c8\ub2e4\uba74 \uc774\uc81c\ub294 <b>receiver\uac00 sender\uc5d0\uac8c \ud544\uc694\ud55c \uc774\ubca4\ud2b8\ub97c pull \ud558\ub294 \ubc29\uc2dd<\/b>\uc73c\ub85c \ubc14\uafc0 \uc218 \uc788\ub2e4. \uc774 \ubc29\uc2dd\uc740 \uc911\ubcf5 \uc804\uc1a1\uc744 \uc904\uc774\uace0 \ubcf5\uc81c \ud6a8\uc728\uc744 \uc62c\ub9b4 \uc218 \uc788\ub2e4.<\/li>\n<li>\uadf8\ub7ec\ub098 pull \uae30\ubc18 \ubaa8\ub378\ub9cc\uc73c\ub85c\ub294 \uc911\ubcf5 \uc804\uc1a1 \ubb38\uc81c\ub97c \uc644\uc804\ud788 \ud574\uacb0\ud560 \uc218 \uc5c6\ub2e4. \uadf8\ub798\uc11c \uc6b0\ub9ac\ub294 \uc5ec\uae30\uc5d0 \ucd94\uac00\uc801\uc778 \uc694\uc18c \ud558\ub098\ub97c \ub354 \ub123\ub294\ub2e4. \ubc14\ub85c <b>pull \uc694\uccad\uc744 \ubcf4\ub0bc \ub54c \uadf8 \uc694\uccad \uc548\uc5d0 \uc9c0\uae08\uae4c\uc9c0 pull \uc694\uccad\uc744 \ubcf4\ub0b8 \ud53c\uc5b4\uac00 \uc774\ubbf8 \uad00\ucc30\ud55c \ubaa8\ub4e0 \uc774\ubca4\ud2b8\ub97c \ub098\ud0c0\ub0b4\ub294 \ud0c0\uc784\uc2a4\ud0ec\ud504<\/b>\ub97c \ud568\uaed8 \ubcf4\ub0b4\ub294 \uac83\uc774\ub2e4. \uc774 \ud0c0\uc784\uc2a4\ud0ec\ud504\ub294 <b>\ub0b4\uac00 \uc5b4\ub290 \uc9c0\uc810\uae4c\uc9c0\uc758 \uc774\ubca4\ud2b8\ub294 \uc774\ubbf8 \ubd24\uc5b4<\/b> \ub77c\ub294 \uc815\ubcf4\ub97c sender\uc5d0\uac8c \uc804\ub2ec\ud558\ub294 \uc5ed\ud560\uc744 \ud55c\ub2e4. \uc774 \uc815\ubcf4\ub97c \ud1b5\ud574 sender\ub294 \uc790\uae30 \uc774\ubca4\ud2b8 \uc2a4\ud2b8\ub9bc\uc5d0\uc11c <b>\uc5b4\ub5a4 \uc774\ubca4\ud2b8\ub294 \ubcf4\ub0b4\uc9c0 \uc54a\uc544\ub3c4 \ub418\ub294\uc9c0 \ud310\ub2e8\ud560 \uc218 \uc788\ub294 \ud78c\ud2b8<\/b>\ub97c \uc5bb\uac8c \ub41c\ub2e4. \ud558\uc9c0\ub9cc \uc774\uac83\ub9cc\uc73c\ub85c\ub3c4 \uc911\ubcf5\uc744 \uc644\uc804\ud788 \ud53c\ud560 \uc218 \uc788\ub294 \uac83\uc740 \uc544\ub2c8\ub2e4. \uc65c\ub0d0\ud558\uba74 \uc5ec\ub7ec \ud53c\uc5b4 \uac04\uc758 \ubcf5\uc81c\ub294 \ub300\uac8c \ub3d9\uc2dc\uc5d0 \uc9c4\ud589\ub418\uae30 \ub54c\ubb38\uc774\ub2e4. \ub54c\ubb38\uc5d0 <b>receiver\ub294 \uc7a0\uc7ac\uc801\uc73c\ub85c \uc911\ubcf5\ub420 \uc218 \uc788\ub294 \uc774\ubca4\ud2b8\ub4e4\uc744 \uc9c1\uc811 \uac10\uc9c0\ud558\uace0 \uac74\ub108\ub6f0\ub294 \ub85c\uc9c1<\/b>\uc744 \ubc18\ub4dc\uc2dc \uac16\uace0 \uc788\uc5b4\uc57c \ud55c\ub2e4.<\/li>\n<\/ul>\n<figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"1243\" data-origin-height=\"967\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/bupjJD\/dJMcaajrgIx\/vWKuP28ZPiaPkXak9psKuk\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/bupjJD\/dJMcaajrgIx\/vWKuP28ZPiaPkXak9psKuk\/img.png\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/bupjJD\/dJMcaajrgIx\/vWKuP28ZPiaPkXak9psKuk\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbupjJD%2FdJMcaajrgIx%2FvWKuP28ZPiaPkXak9psKuk%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"624\" height=\"485\" data-origin-width=\"1243\" data-origin-height=\"967\"\/><\/span><\/figure>\n\uc774\ub807\uac8c \ud558\uc5ec\uc11c \uc6b0\ub9ac\ub294 \ubb38\uc81c\ub97c \uc644\uc804\ud788 \uc81c\uac70\ud558\uc9c0\ub294 \uc54a\uc558\uc9c0\ub9cc, \ubb38\uc81c\uc758 \uc2ec\uac01\uc131\uc744 \ud06c\uac8c \ub0ae\ucd9c \uc218 \uc788\ub2e4.<\/li>\n<\/ul>\n<p data-ke-size=\"size16\">&nbsp;<\/p>","category":["CS\/\uc790\ub8cc\uad6c\uc870(data structure)","\uc790\ub8cc\uad6c\uc870"],"author":"MaKa_","guid":"https:\/\/mk-develop.tistory.com\/62","comments":"https:\/\/mk-develop.tistory.com\/entry\/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%9E%91%EC%97%85-%EA%B8%B0%EB%B0%98-CRDT-ProtocolOperation-based-CRDTs-protocol#entry62comment","pubDate":"Fri, 28 Nov 2025 20:59:28 +0900"},{"title":"[\uc790\ub8cc\uad6c\uc870] CRDT - \uc2e4\uc2dc\uac04 \ud611\uc5c5 \uc560\ud50c\ub9ac\ucf00\uc774\uc158\uc744 \uc704\ud55c \ub370\uc774\ud130 \ud0c0\uc785","link":"https:\/\/mk-develop.tistory.com\/entry\/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-CRDT-%EC%8B%A4%EC%8B%9C%EA%B0%84-%ED%98%91%EC%97%85-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85","description":"<h3 data-ke-size=\"size23\">\uac1c\uc694<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">\uc694\uc998\uc5d0 \uc5f0\uad6c\uc2e4 \ud615\uacfc \uc0c8\ub85c\uc6b4 \ud504\ub85c\uc81d\ud2b8\ub97c \uc2dc\uc791\ud558\uc600\ub2e4.<br>&nbsp;<br>\ud504\ub85c\uc81d\ud2b8\uc5d0 \uc694\uad6c\ub418\ub294 \uae30\uc220 \uc911 \ud558\ub098\ub85c \uc5ec\ub7ec \uc0ac\uc6a9\uc790\uc640 \uc2e4\uc2dc\uac04\uc73c\ub85c \ud611\uc5c5\uc774 \uac00\ub2a5\ud574\uc57c \ud55c\ub2e4\ub294 \ud56d\ubaa9\uc774 \uc788\ub2e4.<br>&nbsp;<br>\uc6b0\ub9ac\ub294 \uc2e4\uc2dc\uac04 \ud611\uc5c5 \ud504\ub85c\uadf8\ub7a8\uc73c\ub85c \ub178\uc158, Figma, Google Docs\uc640 \uac19\uc740 \ud504\ub85c\uadf8\ub7a8\uc744 \uc0ac\uc6a9\ud55c\ub2e4.<br>&nbsp;<br>\uadf8\ub807\ub2e4\uba74 \uc704\uc640 \uac19\uc740 \ud504\ub85c\uadf8\ub7a8\uc740 \ub3c4\ub300\uccb4 \uc5b4\ub5bb\uac8c \uc2e4\uc2dc\uac04\uc73c\ub85c \ud611\uc5c5\uc774 \uac00\ub2a5\ud558\uac8c \ub9cc\ub4e4\uc5c8\uc744\uae4c?<br>&nbsp;<br>\uc774\ub294 CRDT\ub97c \uc0ac\uc6a9\ud558\uc600\uae30\uc5d0 \uac00\ub2a5\ud558\ub2e4.<br>&nbsp;<br>\uadf8\ub807\ub2e4\uba74 CRDT\uac00 \ubb34\uc5c7\uc778\uac00? \uc774\uc5d0 \ub300\ud574 \uac04\ub2e8\ud558\uac8c \uc54c\uc544\ubcf4\uc558\uace0 \uc774\ud574\ud558\uae30 \uc27d\uac8c \uc815\ub9ac\ud574 \ubcf4\uc558\ub2e4.<br><br>\ubcf8 \uae00\uc5d0\uc11c\ub294 <b>\ud53c\uc5b4<\/b>\ub77c\ub294 \uc6a9\uc5b4\uac00 \ub4f1\uc7a5\ud55c\ub2e4.<br>\ud53c\uc5b4\ub294 <b>\uc11c\ub85c\uac04\uc758 \ucef4\ud4e8\ud130<\/b>\ub77c\uace0 \uc0dd\uac01\ud558\uba70 \uc77d\uc73c\uba74 \ub41c\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">CRDT - Conflict-free Replicated Data Type<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">CRDT\ub294 Conflict-free Replicated Data Type\uc758 \uc904\uc784\ub9d0\uc774\ub2e4. \uc9c1\uc5ed\ud558\uba74 <b>\ucda9\ub3cc \uc5c6\ub294 \ubcf5\uc81c\ub41c \ub370\uc774\ud130 \ud0c0\uc785<\/b>\uc774\ub77c\ub294 \ub73b\uc774\ub2e4.<br>&nbsp;<br>\ub370\uc774\ud130 \ud0c0\uc785\uc774\ub77c\ub294 \uac83\uc740 <b>\uc790\ub8cc \uad6c\uc870\uc911 \ud558\ub098<\/b>\ub77c\ub294 \uc758\ubbf8\uc774\ub2e4.<br>&nbsp;<br>\ubc95\uce59\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p><ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\"><li>\uac01 \ucef4\ud4e8\ud130\ub294 \uc11c\ub85c \ub2e4\ub978 \ucef4\ud4e8\ud130\ub97c \ud655\uc778\ud558\uae30 \uc704\ud55c <b>\ub124\ud2b8\uc6cc\ud06c \uc694\uccad \uc5c6\uc774<\/b>\ub3c4 \uc790\uccb4 \uc0c1\ud0dc\ub97c \uc989\uc2dc \uc5c5\ub370\uc774\ud2b8\ud560 \uc218 \uc788\ub2e4.<\/li><li>\uac01 \ucef4\ud4e8\ud130\ub07c\ub9ac\ub294 \uc11c\ub85c \ub2e4\ub978 \uc2dc\uac04\uc5d0 \uc11c\ub85c \ub2e4\ub978 \uc0c1\ud0dc\ub97c \uac00\uc9c8 \uc218 \uc788\uc9c0\ub9cc <b>\ucd5c\uc885\uc801\uc73c\ub85c \ud558\ub098\uc758 \ud569\uc758\ub41c \uc0c1\ud0dc\ub85c \uc218\ub834<\/b>\ud55c\ub2e4.<\/li><\/ul><p data-ke-size=\"size16\">\uc704 \ubc95\uce59 \ub355\ubd84\uc5d0 <b>\uc911\uc559 \uc11c\ubc84\uc5d0\uc11c \ubcc0\uacbd \uc0ac\ud56d\uc744 \ub3d9\uae30\ud654\ud560 \ud544\uc694 \uc5c6\uc774<\/b> Google Docs \ubc0f Figma\uc640 \uac19\uc740 \ud611\uc5c5 \uc571\uc744 \uad6c\ucd95\ud558\ub294\ub370 \uc720\uc6a9\ud558\uac8c \uc0ac\uc6a9\ud560 \uc218 \uc788\ub2e4.<br>&nbsp;<br>CRDT\ub294 \ud06c\uac8c \ub450 \uac00\uc9c0 \ud0c0\uc785\uc778 <b>\uc0c1\ud0dc \uae30\ubc18 CRDT<\/b>\uc640 <b>\uc791\uc5c5 \uae30\ubc18 CRDT<\/b>\uac00 \uc788\ub2e4.<br>&nbsp;<br>\uc0c1\ud0dc \uae30\ubc18 CRDT\ub294 <b>\ud53c\uc5b4 \uac04\uc5d0 \uc804\uccb4 \uc0c1\ud0dc\ub97c \uc804\uc1a1\ud558\uace0, \ubaa8\ub4e0 \uc0c1\ud0dc\ub97c \ubcd1\ud569<\/b>\ud558\uc5ec \uc0c8 \uc0c1\ud0dc\ub97c \uc5bb\ub294\ub2e4.<br>&nbsp;<br>\uc791\uc5c5 \uae30\ubc18 CRDT\ub294 <b>\uc0ac\uc6a9\uc790\uac00 \uc218\ud589\ud558\ub294 \uc791\uc5c5\ub9cc \uc804\uc1a1\ud558\uace0 \uc774\ub97c \uc0ac\uc6a9\ud558\uc5ec \uc0c8 \uc0c1\ud0dc\ub97c \uacc4\uc0b0<\/b>\ud55c\ub2e4.<br>&nbsp;<br>\uc774\ub807\uac8c\ub9cc \ubcf4\uba74 \uc791\uc5c5 \uae30\ubc18 CRDT\uac00 \uc0c1\ud0dc \uae30\ubc18 CRDT\ubcf4\ub2e4 \ud6e8\uc52c \uc88b\uc544 \ubcf4\uc778\ub2e4.<br>&nbsp;<br>\uc608\ub97c \ub4e4\uc5b4, \uc0ac\uc6a9\uc790\uac00 \ubaa9\ub85d\uc758 \ud55c \ud56d\ubaa9\uc744 \uc5c5\ub370\uc774\ud2b8\ud558\uba74 <b>\uc791\uc5c5 \uae30\ubc18 CRDT\ub294 \ud574\ub2f9 \uc5c5\ub370\uc774\ud2b8\uc5d0 \ub300\ud55c \uc124\uba85\ub9cc \uc804\uc1a1<\/b>\ud560 \uc218 \uc788\uc9c0\ub9cc <b>\uc0c1\ud0dc \uae30\ubc18 CRDT\ub294 \uc804\uccb4 \ubaa9\ub85d\uc744 \uc804\uc1a1<\/b>\ud574\uc57c \ud55c\ub2e4.<br>&nbsp;<br>\ud558\uc9c0\ub9cc <b>\uc791\uc5c5 \uae30\ubc18 CRDT\ub294 <span style=\"color: #EE2323;\">\ud1b5\uc2e0 \ucc44\ub110\uc5d0 \uc81c\uc57d\uc744 \uac00\ud55c\ub2e4<\/span>\ub294 trade-off\uac00 \uc874\uc7ac<\/b>\ud55c\ub2e4.<br>&nbsp;<br>\uba54\uc138\uc9c0\ub294 \uac01 \ucef4\ud4e8\ud130\uc5d0\uac8c \uc815\ud655\ud788 \ud55c \ubc88, \uc21c\uc11c\uc5d0 \ub9de\uac8c \uc804\ub2ec\ub418\uc5b4\uc57c \ud55c\ub2e4.<br>&nbsp;<br>\ub610 \ub2e4\ub978 CRDT\ub85c\ub294 <b>\ucef4\ud4e8\ud130\uac00 \uc11c\ub85c \uc8fc\uace0\ubc1b\uc544\uc57c \ud558\ub294 \uc0c1\ud0dc\uc758 \ud558\uc704 \uc9d1\ud569\uc744 \ud611\uc0c1<\/b>\ud560 \uc218 \uc788\ub294 <b>\ub378\ud0c0 CRDT<\/b>\uc640 <b>\ud558\uc774\ube0c\ub9ac\ub4dc CRDT<\/b>\uac00 \uc788\ub2e4.<br>&nbsp;<br>\ub378\ud0c0 CRDT\uc640 \ud558\uc774\ube0c\ub9ac\ub4dc CRDT\ub294 \uc791\uc5c5 \uae30\ubc18 CRDT\uc640 \uc0c1\ud0dc \uae30\ubc18 CRDT\ub97c \ud63c\ud569\ud55c \uac83\uc774\ub2e4.<br>&nbsp;<br>\uadf8\ub7ec\ub098 \uadfc\ubcf8\uc801\uc778 trade off\ub294 \uc5ec\uc804\ud558\ub2e4.<br>&nbsp;<br><b>\uc11c\ub85c \ub2e4\ub978 \ucef4\ud4e8\ud130\uac04\uc5d0 \ubcf4\ub0b4\ub294 \ub370\uc774\ud130\uac00 \uc801\uc744\uc218\ub85d \ud1b5\uc2e0\uc5d0 \ub300\ud55c \uc81c\uc57d\uc774 \ub354 \ub9ce\ub2e4.<\/b><br>&nbsp;<br>\ubcf8 \uae00\uc5d0\uc11c\ub294 \uc0c1\ud0dc \uae30\ubc18 CRDT\uc5d0 \ub300\ud574\uc11c\ub9cc \ub2e4\ub8ec\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">CRDT\uc758 \uad6c\ud604\uccb4\uc640 \uaddc\uce59<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">\uc790\ub8cc \uad6c\uc870\ub294 \uc800\ub9c8\ub2e4\uc758 \uad6c\ud604\uccb4\uc640 \uaddc\uce59\uc744 \uac00\uc9c4\ub2e4.<br>&nbsp;<br>\uc608\ub97c \ub4e4\uc5b4 \uc2a4\ud0dd\uc740 \ub370\uc774\ud130\ub97c \uc9d1\uc5b4\ub123\ub294 push, \ub370\uc774\ud130\ub97c \uc81c\uac70\ud558\ub294 pop\uc774\ub77c\ub294 \uad6c\ud604\uccb4\ub97c \uac00\uc9c0\uace0 \uc788\uace0 \ud6c4\uc785\uc120\ucd9c\uc774\ub77c\ub294 \uaddc\uce59\uc744 \uac00\uc9c4\ub2e4.<br>&nbsp;<br>CRDT\ub3c4 \uc790\ub8cc\uad6c\uc870\uc774\ub2e4. \ub54c\ubb38\uc5d0 \uae30\ubcf8\uc801\uc778 \uad6c\ud604\uccb4\uc640 \uaddc\uce59\uc774 \uc874\uc7ac\ud55c\ub2e4.<br>&nbsp;<\/p><h4 data-ke-size=\"size20\">CRDT\uc758 \uad6c\ud604\uccb4<\/h4><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>interface CRDT&lt;T, S&gt; {\n\tvalue: T;\n\tstate: S;\n\tmerge(state: S): void;\n}<\/code><\/pre><p data-ke-size=\"size16\">CRDT\uc758 \uad6c\ud604\uccb4\ub294 \ucd5c\uc18c \uc138 \uac00\uc9c0\ub97c \ud3ec\ud568\ud55c\ub2e4.<\/p><ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\"> \n <li><b>\uac12(value) T<\/b> \n  <ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\"> \n   <li>\uc2e4\uc81c\ub85c \uc4f0\ub294 \uac12<\/li> \n  <\/ul> <\/li> \n <li><b>\uc0c1\ud0dc(state) S<\/b> \n  <ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\"> \n   <li>\uac12\uc744 \uc5b4\ub5bb\uac8c \ubcd1\ud569\ud560\uc9c0 \uacb0\uc815\ud558\uae30 \uc704\ud55c \uc0c1\ud0dc(\uba54\ud0c0\ub370\uc774\ud130)<\/li> \n   <li>\ub2e4\ub978 \ud53c\uc5b4\ub97c \uc5c5\ub370\uc774\ud2b8\ud558\uae30 \uc704\ud574 \uc804\uccb4 state\uac00 \uc9c1\ub82c\ud654\ub418\uc5b4 \uc804\uc1a1<\/li> \n  <\/ul> <\/li> \n <li><b>\ubcd1\ud569 \ud568\uc218(merge function) merge<\/b> \n  <ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\"> \n   <li>\ub2e4\ub978 \ud53c\uc5b4\uc5d0\uc11c \ubc1b\uc740 \uc0c1\ud0dc\ub97c \uac00\uc838\uc640 \ub85c\uceec \uc0c1\ud0dc\uc640 \ubcd1\ud569\ud558\ub294 \ud568\uc218<\/li> \n  <\/ul> <\/li> \n<\/ul><p data-ke-size=\"size16\"><b>\uc5ec\uae30\uc11c<\/b> <b>\ubcd1\ud569 \ud568\uc218\ub294 \ub2e4\uc74c \uc138 \uac00\uc9c0 \uc870\uac74\uc744 \ub9cc\uc871\ud574\uc57c \ud55c\ub2e4.<\/b><\/p><ol style=\"list-style-type: decimal;\" data-ke-list-type=\"decimal\"> \n <li>\uac00\ud658\uc131(commutativity) \n  <ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\"> \n   <li>\uc0c1\ub300\ub294 \uc5b4\ub5a4 \uc21c\uc11c\ub85c\ub4e0 \ubcd1\ud569\ud560 \uc218 \uc788\ub2e4. A\uc640 B \uac01\uac01\uc758 \uc0c1\ud0dc\ub97c \uc790\uc2e0\uc758 \uc0c1\ud0dc\uc5d0 \ubcd1\ud569 \ud574 \ub3d9\uc77c\ud55c \uacb0\uacfc\uc5d0 \ub3c4\ub2ec\ud55c\ub2e4. (<b>A <\/b>V<b> B)<\/b><\/li> \n  <\/ul> <\/li> \n <li>\uacb0\ud569\uc131(associativity) \n  <ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\"> \n   <li>\uc138 \uac1c \uc774\uc0c1\uc758 \uc0c1\ud0dc\ub97c \ubcd1\ud569\ud560 \ub54c \uba3c\uc800 \ubcd1\ud569\ud558\ub294 \uc0c1\ud0dc\ub294 \uc911\uc694\ud558\uc9c0 \uc54a\ub2e4. \uc5b4\ub5bb\uac8c\ub4e0 \ubaa8\ub4e0 \uc0c1\ud0dc\ub97c \ubc1b\uc73c\uba74 \uc5b4\ub5a4 \uc21c\uc11c\ub4e0 \ubcd1\ud569\ud560 \uc218 \uc788\uc73c\uba70 \uacb0\uacfc\ub294 \ub3d9\uc77c\ud558\ub2e4. (<b>A<\/b> V <b>B<\/b>) V <b>C<\/b> = <b>A<\/b> V (<b>B<\/b> V <b>C<\/b>)<\/li> \n  <\/ul> <\/li> \n <li>\ud56d\ub4f1\uc131(idempotence) \n  <ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\"> \n   <li>\uac19\uc740 \uc0c1\ud0dc\ub97c \uc5ec\ub7ec \ubc88 \ubcd1\ud569\ud574\ub3c4 \uacb0\uacfc\uac00 \ubc14\ub00c\uc9c0 \uc54a\ub294\ub2e4. <b>A<\/b> V <b>A<\/b> = <b>A<\/b><b><\/b><\/li> \n  <\/ul> <\/li> \n<\/ol><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\uc0c1\ud0dc \uae30\ubc18 CRDT - Last Write Wins Register<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">CPU\uc5d0\uc11c \ub808\uc9c0\uc2a4\ud130\ub294 \ud558\ub098\uc758 \uac12\uc744 \uc800\uc7a5\ud558\ub294 \ub2e8\uc77c \uacf5\uac04\uc774\ub2e4.<br>&nbsp;<br>\uc774\ub7ec\ud55c \ub808\uc9c0\uc2a4\ud130\uc758 \uc804\ud1b5\uc744 CRDT\ub294 \uadf8\ub300\ub85c \uac00\uc838\uc654\ub2e4.<br>&nbsp;<br><b>\ub808\uc9c0\uc2a4\ud130\ub294 CRDT\uc758 \uac00\uc7a5 \ub2e8\uc21c\ud55c \ud615\ud0dc\uc774\uba70 \uc774\ub97c \ud1a0\ub300\ub85c \uad6c\ud604\ud55c \uac83\uc774 Last Write Wins Register(LWW Register)\uc774\ub2e4.<\/b><br>&nbsp;<br>LWW Register\uc740 <b>\ub2e8\uc21c\ud788 \uac12\uc774 \uc5c5\ub370\uc774\ud2b8 \ub420 \ub54c \ub9c8\ub2e4 \uc99d\uac00\ud558\ub294 \uc815\uc218\ub85c \ud45c\ud604\ub418\ub294 \ud0c0\uc784\uc2a4\ud0ec\ud504\ub97c \uc0ac\uc6a9<\/b>\ud558\uc5ec <b>\uac00\uc7a5 \ucd5c\uadfc\uc5d0 \uc791\uc131\ub41c \uac12\uc73c\ub85c \ud604\uc7ac \uac12\uc744 \ub36e\uc5b4\uc4f4\ub2e4. <\/b><br>&nbsp;<br>\uc608\ub97c \ub4e4\uba74 \uc544\ub798\uc758 \uc0ac\uc9c4\uacfc \uac19\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"524\" data-origin-height=\"179\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/5aBUA\/dJMcaacEKXe\/kQ248KG33mmKty5rnJP2f0\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/5aBUA\/dJMcaacEKXe\/kQ248KG33mmKty5rnJP2f0\/img.png\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/5aBUA\/dJMcaacEKXe\/kQ248KG33mmKty5rnJP2f0\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5aBUA%2FdJMcaacEKXe%2FkQ248KG33mmKty5rnJP2f0%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"524\" height=\"179\" data-origin-width=\"524\" data-origin-height=\"179\"\/><\/span><\/figure>\n<p data-ke-size=\"size16\">&nbsp;<br>\uadf8\ub807\ub2e4\uba74 \uc758\ubb38\uc774 \ub4e4 \uc218 \uc788\ub2e4.<br>&nbsp;<br>\ubcf4\ud1b5 timestamp\ub77c\uace0 \ud55c\ub2e4\uba74 \ucef4\ud4e8\ud130\uc758 \ud604\uc7ac \uc2dc\uac04\uc744 \ub098\ud0c0\ub0b8\ub2e4. \ud558\uc9c0\ub9cc LWW Register\uc5d0\uc120 timestamp\uc5d0 \uc815\uc218\uac00 \ub4e4\uc5b4\uac04\ub2e4.<br>&nbsp;<br>\uc774\uc640 \uac19\uc774 \uc124\uacc4\ub41c \uc774\uc720\ub294 <b>\ucef4\ud4e8\ud130\uac04\uc758 \uc2dc\uac04\uc744 \uc815\ud655\ud558\uac8c \ub3d9\uae30\ud654\ud558\ub294 \uac83\uc774 \ub9e4\uc6b0 \uc5b4\ub835\uae30 \ub54c\ubb38<\/b>\uc774\ub2e4.<br>&nbsp;<br>LWW Register\uc740 \ub2e4\uc74c \uc21c\uc11c\ub85c \uc791\ub3d9\ud55c\ub2e4.<\/p><ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\"><li><b>\uc218\uc2e0\ub41c \ud0c0\uc784\uc2a4\ud0ec\ud504\uac00 \ub85c\uceec \ud0c0\uc784\uc2a4\ud0ec\ud504\ubcf4\ub2e4 \uc791\uc73c\uba74<\/b> \ub808\uc9c0\uc2a4\ud130\uc758 \uc0c1\ud0dc\uac00 \ubcc0\uacbd\ub418\uc9c0 \uc54a\ub294\ub2e4.<\/li><li><b>\uc218\uc2e0\ub41c \ud0c0\uc784\uc2a4\ud0ec\ud504\uac00 \ub85c\uceec \ud0c0\uc784\uc2a4\ud0ec\ud504\ubcf4\ub2e4 \ud06c\uba74 \ub808\uc9c0\uc2a4\ud130\ub294 \ub85c\uceec \uac12\uc744 \uc218\uc2e0\ub41c \uac12\uc73c\ub85c \ub36e\uc5b4\uc4f4\ub2e4.<\/b> \ub610\ud55c \uc218\uc2e0\ub41c \ud0c0\uc784\uc2a4\ud0ec\ud504\uc640 \ub9c8\uc9c0\ub9c9\uc73c\ub85c \uac12\uc744 \uc791\uc131\ud55c <b>\ud53c\uc5b4\uc758 \uace0\uc720 \uc2dd\ubcc4\uc790\ub97c \uc800\uc7a5<\/b>\ud55c\ub2e4.<\/li><li>\ub85c\uceec \ucef4\ud4e8\ud130 ID\uc640 \uc218\uc2e0 \uc0c1\ud0dc\uc758 \ucef4\ud4e8\ud130 ID\ub97c \ube44\uad50\ud558\uc5ec \uc5f0\uacb0\uc774 \ub04a\uc5b4\uc9c4\ub2e4.<\/li><\/ul><p data-ke-size=\"size16\">\uc544\ub798 \uc0ac\uc9c4\uacfc \uac19\uc774 \ub3d9\uc791\ud55c\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"762\" data-origin-height=\"190\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/ynV0U\/dJMcahXabgU\/Thx72ubEy82kvrLKujtgqK\/img.gif\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/ynV0U\/dJMcahXabgU\/Thx72ubEy82kvrLKujtgqK\/img.gif\" data-alt=\"LWW Register\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/ynV0U\/dJMcahXabgU\/Thx72ubEy82kvrLKujtgqK\/img.gif\" srcset=\"https:\/\/blog.kakaocdn.net\/dn\/ynV0U\/dJMcahXabgU\/Thx72ubEy82kvrLKujtgqK\/img.gif\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"762\" height=\"190\" data-origin-width=\"762\" data-origin-height=\"190\"\/><\/span><figcaption>LWW Register<\/figcaption>\n<\/figure>\n<p data-ke-size=\"size16\">\ubcc0\ud654\uac00 \uc788\uc744 \ub54c \ub9c8\ub2e4 timestamp\uac00 1\uc529 \ub298\uc5b4\ub098\uace0, \uc218\uc2e0\uc790\ub3c4 \ub370\uc774\ud130\ub97c \ubc1b\uc73c\uba74 \ub370\uc774\ud130 \ucd5c\uc2e0\ud654\uc640 \ud568\uaed8 timestamp\uac00 \uac31\uc2e0\ub418\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub2e4.<br>&nbsp;<br>\uc774 \uc0ac\uc9c4\uc5d0\uc11c\ub294 \ub2e4\uc74c \ubcc0\ud654\ub4e4\ub3c4 \ud655\uc778\uc774 \uac00\ub2a5\ud558\ub2e4.<\/p><ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\"> \n <li>\ub9cc\uc57d \ub124\ud2b8\uc6cc\ud06c\ub97c \ub044\uace0 Bob\uc5d0\uac8c \uba87\uac00\uc9c0 \uc5c5\ub370\uc774\ud2b8\ub97c \ud558\uace0 \ub2e4\uc2dc \ucf20\ub2e4\uba74? \n  <ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\"> \n   <li>\ud0c0\uc784\uc2a4\ud0ec\ud504\uac00 Bob\uc758 \ud0c0\uc784\uc2a4\ud0ec\ud504\ub97c \ucd08\uacfc\ud560 \ub54c\uae4c\uc9c0 \uac70\ubd80\ub41c\ub2e4.<\/li> \n  <\/ul> <\/li> \n <li>\ub3d9\uc77c\ud55c \uc124\uc815\uc73c\ub85c, \ub124\ud2b8\uc6cc\ud06c\ub97c \ub2e4\uc2dc \ucf1c\uace0 Bob\uc5d0\uc11c Alice\ub85c \uc5c5\ub370\uc774\ud2b8\ub97c \ubcf4\ub0b4\uba74? \n  <ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\"> \n   <li>\ud0c0\uc784\uc2a4\ud0ec\ud504\uac00 \ub3d9\uae30\ud654\ub418\uace0 Alice\uac00 Bob\uc5d0\uac8c \ub2e4\uc2dc \uc791\uc131\ud560 \uc218 \uc788\ub2e4.<\/li> \n  <\/ul> <\/li> \n <li>\uc9c0\uc5f0 \uc2dc\uac04\uc744 \ub298\ub9ac\uace0 \ub450 \ucef4\ud4e8\ud130\uc5d0\uc11c \ub3d9\uc2dc\uc5d0 \uc5c5\ub370\uc774\ud2b8\ub97c \ubcf4\ub0b8\ub2e4\uba74? \n  <ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\"> \n   <li>Alice\ub294 Bob\uc758 \uc5c5\ub370\uc774\ud2b8\ub97c \uc218\ub77d\ud558\uc9c0\ub9cc Bob\uc740 Alice\uc758 \uc5c5\ub370\uc774\ud2b8\ub97c \uac70\ubd80\ud55c\ub2e4. Bob\uc758 ID\uac00 \ub354 \ud06c\uae30 \ub54c\ubb38\uc5d0 \ud0c0\uc784\uc2a4\ud0ec\ud504 \ud0c0\uc774\ub97c \ub04a\ub294\ub2e4.<\/li> \n  <\/ul> <\/li> \n<\/ul><p data-ke-size=\"size16\">LWW Register\ub97c class\ub85c \uad6c\ud604\ud558\uba74 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>class LWWRegister&lt;T&gt; {\n&nbsp;&nbsp;readonly id: string;\n&nbsp;&nbsp;state: [peer: string, timestamp: number, value: T];\n\n&nbsp;&nbsp;get value() { \n&nbsp;&nbsp;&nbsp;&nbsp;return this.state[2];\n&nbsp;&nbsp;}\n&nbsp;&nbsp;constructor(id: string, state: [string, number, T]) {\n&nbsp;&nbsp;&nbsp;&nbsp;this.id = id;\n&nbsp;&nbsp;&nbsp;&nbsp;this.state = state;\n&nbsp;&nbsp;}\n&nbsp;&nbsp;set(value: T) {\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \ub85c\uceec ID\ub85c \ud53c\uc5b4 ID \uc124\uc815, \ub85c\uceec \ud0c0\uc784\uc2a4\ud0ec\ud504\ub97c 1 \uc99d\uac00\uc2dc\ud0a4\uace0 \uac12 \uc124\uc815\n&nbsp;&nbsp;&nbsp;&nbsp;this.state = [this.id, this.state[1] + 1, value];\n&nbsp;&nbsp;}\n&nbsp;&nbsp;merge(state: [peer: string, timestamp: number, value: T]) {\n&nbsp;&nbsp;&nbsp;&nbsp;const [remotePeer, remoteTimestamp] = state;\n&nbsp;&nbsp;&nbsp;&nbsp;const [localPeer, localTimestamp] = this.state;\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \ub85c\uceec \ud0c0\uc784\uc2a4\ud0ec\ud504\uac00 \uc6d0\uaca9 \ud0c0\uc784\uc2a4\ud0ec\ud504\ubcf4\ub2e4 \ud06c\uba74 \ub4e4\uc5b4\uc624\ub294 \uac12\uc744 \ubb34\uc2dc\n&nbsp;&nbsp;&nbsp;&nbsp;if (localTimestamp &gt; remoteTimestamp) return;\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \ud0c0\uc784\uc2a4\ud0ec\ud504\ub294 \ub3d9\uc77c\ud558\uc9c0\ub9cc \ub85c\uceec \ud53c\uc5b4 ID\uac00 \uc6d0\uaca9 \ud53c\uc5b4 ID\ubcf4\ub2e4 \ud06c\uba74 \ub4e4\uc5b4\uc624\ub294 \uac12\uc744 \ubb34\uc2dc\n&nbsp;&nbsp;&nbsp;&nbsp;if (localTimestamp === remoteTimestamp &amp;&amp; localPeer &gt; remotePeer) return;\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74 \ub85c\uceec \uc0c1\ud0dc\ub97c \uc6d0\uaca9 \uc0c1\ud0dc\ub85c \ub36e\uc5b4\uc4f0\uae30\n&nbsp;&nbsp;&nbsp;&nbsp;this.state = state;\n&nbsp;&nbsp;}\n}<\/code><\/pre><ul style=\"list-style-type: disc;\" data-ke-list-type=\"disc\"> \n <li>state \n  <ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\"> \n   <li>\ub808\uc9c0\uc2a4\ud130\uc5d0 \ub9c8\uc9c0\ub9c9\uc73c\ub85c \uc791\uc131\ud55c \ud53c\uc5b4 ID, \ub9c8\uc9c0\ub9c9\uc73c\ub85c \uc791\uc131\ub41c \ud0c0\uc784\uc2a4\ud0ec\ud504, \ub808\uc9c0\uc2a4\ud130\uc5d0 \uc800\uc7a5\ub41c \ud29c\ud50c<\/li> \n  <\/ul> <\/li> \n <li>value \n  <ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\"> \n   <li>\uc0c1\ub300 \ud29c\ud50c\uc758 \ub9c8\uc9c0\ub9c9 \uc694\uc18c<\/li> \n  <\/ul> <\/li> \n <li>merge \n  <ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\"> \n   <li>\uc704\uc5d0\uc11c \uc124\uba85\ud55c \uc54c\uace0\ub9ac\uc998\uc744 \uad6c\ud604\ud558\ub294 \uba54\uc11c\ub4dc<\/li> \n  <\/ul> <\/li> \n <li>set \n  <ul style=\"list-style-type: circle;\" data-ke-list-type=\"circle\"> \n   <li>\ucd08\uae30\uac12\uc744 \uc138\ud305<\/li> \n   <li>\ub808\uc9c0\uc2a4\ud130\uc758 \uac12\uc744 \ub85c\uceec\ub85c \uc124\uc815, \ub85c\uceec \uba54\ud0c0\ub370\uc774\ud130 \uc5c5\ub370\uc774\ud2b8, \ub85c\uceec \ud0c0\uc784\uc2a4\ud0ec\ud504\ub97c 1 \uc99d\uac00\uc2dc\ud0b4(\ucd5c\uc2e0\ud654)<\/li> \n  <\/ul> <\/li> \n<\/ul><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\uc0c1\ud0dc \uae30\ubc18 CRDT - Last Write Wins Map<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">\ub300\ubd80\ubd84\uc758 \ud504\ub85c\uadf8\ub7a8\uc740 \ud558\ub098 \uc774\uc0c1\uc758 \uac12\uc744 \ud3ec\ud568\ud558\ubbc0\ub85c LWW Register\ubcf4\ub2e4 \ub354 \ubcf5\uc7a1\ud55c CRDT\uac00 \ud544\uc694\ud558\ub2e4.<br>&nbsp;<br>\uc774\ub97c \uc704\ud55c CRDT\ub85c Last Write Wins Map(LWW Map)\uc774 \uc788\ub2e4.<br>&nbsp;<br>LWW Register\ub294 \uad6c\ud604\uccb4\ub85c value, state, merge\ub97c \uac00\uc84c\ub2e4.<br>&nbsp;<br>LWW Map\ub3c4 \uc774 \uac1c\ub150\uc744 \ube44\uc2b7\ud558\uac8c \ub530\ub77c\uac04\ub2e4.<br>&nbsp;<\/p><h4 data-ke-size=\"size20\">\uac12(Value)<\/h4><p data-ke-size=\"size16\">\uac12\uc740 \ub2e4\uc74c\uacfc \uac19\uc774 \uc815\uc758\ub41c\ub2e4.<\/p><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>type Value&lt;T&gt; = {\n&nbsp;&nbsp;[key: string]: T;\n};<\/code><\/pre><p data-ke-size=\"size16\">\uac01 \uac1c\ubcc4 \ub9f5 \uac12\uc758 \ud0c0\uc785\uc774 T\uc778 \uacbd\uc6b0 \uc804\uccb4 LWW Map\uc758 \uac12\uc740 \ubb38\uc790\uc5f4 \ud0a4\uc640 T\uac12\uc758 \ub9e4\ud551\uc774\ub2e4.<br>&nbsp;<br>\uadf8\ub807\ub2e4\uba74 <b>T\uac12\uc5d4 \ubb34\uc5c7\uc774 \uc624\ub294\uac00? \uc65c \uc81c\ub124\ub9ad\uc774\uc9c0?<\/b><br>&nbsp;<br>\uc774\ub294 \uc0c1\ud0dc \ud0c0\uc785\uc5d0\uc11c \uc54c \uc218 \uc788\ub2e4.<br>&nbsp;<\/p><h4 data-ke-size=\"size20\">\ud0c0\uc785(State)<\/h4><p data-ke-size=\"size16\">\ud0c0\uc785\uc740 \ub2e4\uc74c\uacfc \uac19\uc774 \uc815\uc758\ub41c\ub2e4.<\/p><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>type State&lt;T&gt; = {\n&nbsp;&nbsp;[key: string]: LWWRegister&lt;T | null&gt;[\"state\"];\n};<\/code><\/pre><p data-ke-size=\"size16\">\uc704\uc758 value\ub9cc \ubcf4\uba74 \uc77c\ubc18 \uac12\uc744 \ubcf4\uad00\ud558\ub294 \uac83 \uac19\uc9c0\ub9cc \uc2e4\uc81c\ub85c\ub294 <b>\uc704\uc5d0\uc11c \uc124\uba85\ud588\ub358 LWW Register\ub97c \ubcf4\uad00<\/b>\ud55c\ub2e4.<br>&nbsp;<br>\uc989 <b>\uac01 \ud0a4\uc758 \uc0c1\ud0dc\ub294 \ud574\ub2f9 \ud0a4\uc758 LWW Register \uc0c1\ud0dc<\/b>\uc774\ub2e4.<br>&nbsp;<br>LWW Register\uc758 \ud0c0\uc785\uc774 \uc720\ub2c8\uc628 <b>T | null<\/b> \uc778\uac83\ub3c4 \uc774\uc720\uac00 \uc788\ub2e4. \uc774\ub294 \ud5a5\ud6c4 \uc124\uba85\ud55c\ub2e4.<br>&nbsp;<\/p><h4 data-ke-size=\"size20\">\ubcd1\ud569 \ud568\uc218(Merge)<\/h4><p data-ke-size=\"size16\">\ubcf5\uc7a1\ud55c CRDT\ub294 <b>\uc791\uc740 CRDT\ub4e4\uc744 \uc870\ud569<\/b>\ud574\uc11c \ub9cc\ub4e4 \uc218 \uc788\ub2e4.<br>&nbsp;<br>\ubcd1\ud569\ud560 \ub54c\ub294 <b>\ubd80\ubaa8 CRDT\uac00 \uac01 \uc790\uc2dd CRDT\uc758 \uc0c1\ud0dc \uc870\uac01\uc744 \uadf8 \uc790\uc2dd\uc758 merge() \ud568\uc218\ub85c \ub118\uaca8\uc8fc\uba74 \ub41c\ub2e4.<\/b><br>&nbsp;<br>\uc774\uac78 <b>\uc7ac\uadc0\uc801\uc73c\ub85c \uacc4\uc18d \uc911\ucca9<\/b>\ud574\ub098\uac08 \uc218 \uc788\uace0, \uacb0\uad6d <b>\uac00\uc7a5 \uc791\uc740 \uc6d0\uc2dc CRDT\uac00 \uc2e4\uc81c \ubcd1\ud569\uc744 \ucc98\ub9ac<\/b>\ud55c\ub2e4.<br>&nbsp;<br>LWW Map \ubcd1\ud569 \ud568\uc218\ub294 \uc704\uc758 \uad00\uc810\uc5d0\uc11c \ubcf4\uba74 \uac04\ub2e8\ud558\ub2e4.<br>&nbsp;<br>\uac01 \ud0a4\ub97c \uc21c\ud68c\ud558\uace0 \ud574\ub2f9 \ud0a4\uc5d0 \ub4e4\uc5b4\uc624\ub294 \uc0c1\ud0dc\ub97c LWW Register\uc5d0 \ubcd1\ud569\ud558\ub3c4\ub85d \uc804\ub2ec\ud55c\ub2e4.<br>&nbsp;<br>\uc774\ub97c \uc2dc\uac01\uc801\uc73c\ub85c \ubcf4\uba74 \uc544\ub798\uc640 \uac19\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"760\" data-origin-height=\"238\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/OXGy0\/dJMcacheWmK\/gWPXb71KCnjCZRSNczJe70\/img.gif\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/OXGy0\/dJMcacheWmK\/gWPXb71KCnjCZRSNczJe70\/img.gif\" data-alt=\"LWWMap-fast\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/OXGy0\/dJMcacheWmK\/gWPXb71KCnjCZRSNczJe70\/img.gif\" srcset=\"https:\/\/blog.kakaocdn.net\/dn\/OXGy0\/dJMcacheWmK\/gWPXb71KCnjCZRSNczJe70\/img.gif\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"760\" height=\"238\" data-origin-width=\"760\" data-origin-height=\"238\"\/><\/span><figcaption>LWWMap-fast<\/figcaption>\n<\/figure>\n<p data-ke-size=\"size16\">\uc9c0\uc5f0 \uc2dc\uac04\uc744 \ub298\ub824\uc11c \ubcf4\uba74 \uc544\ub798\uc640 \uac19\ub2e4.<br>\uac01 \ucef4\ud4e8\ud130\uac00 \ud0c0\uc784\uc2a4\ud0ec\ud504\uac00 \ub354 \ub192\uc740 \uc5c5\ub370\uc774\ud2b8 \uac12\uc740 \uc218\ub77d\ud558\uace0 \ud0c0\uc784\uc2a4\ud0ec\ud504\uac00 \ub354 \ub0ae\uc740 \uac12\uc740 \uac70\ubd80\ud558\ub294 \uac83\uc744 \ubcfc \uc218 \uc788\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"760\" data-origin-height=\"238\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/lO8XR\/dJMcag41aVd\/ZyMKwnbuWJuYf0gMxkrVu1\/img.gif\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/lO8XR\/dJMcag41aVd\/ZyMKwnbuWJuYf0gMxkrVu1\/img.gif\" data-alt=\"LWWMap-latency\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/lO8XR\/dJMcag41aVd\/ZyMKwnbuWJuYf0gMxkrVu1\/img.gif\" srcset=\"https:\/\/blog.kakaocdn.net\/dn\/lO8XR\/dJMcag41aVd\/ZyMKwnbuWJuYf0gMxkrVu1\/img.gif\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"760\" height=\"238\" data-origin-width=\"760\" data-origin-height=\"238\"\/><\/span><figcaption>LWWMap-latency<\/figcaption>\n<\/figure>\n<p data-ke-size=\"size16\">\ubcd1\ud569 \ud568\uc218\uc758 \uad6c\ud604\uccb4\ub294 LWW Map\uc758 \ud074\ub798\uc2a4\uc5d0\uc11c \uc790\uc138\ud788 \uc124\uba85\ud55c\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">Last Write Wins Map - Class \uad6c\uc870<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h4 data-ke-size=\"size20\">\uc0dd\uc131\uc790(Constructor)<\/h4><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>class LWWMap&lt;T&gt; {\n&nbsp;&nbsp;readonly id = \"\";\n&nbsp;&nbsp;#data = new Map&lt;string, LWWRegister&lt;T | null&gt;&gt;();\n\n&nbsp;&nbsp;constructor(id: string, state: State&lt;T&gt;) {\n&nbsp;&nbsp;&nbsp;&nbsp;this.id = id;\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \ucd08\uae30 \uc0c1\ud0dc\uc758 \uac01 \ud0a4\uc5d0 \ub300\ud574 \uc0c8 \ub808\uc9c0\uc2a4\ud130\ub97c \uc0dd\uc131\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;for (const [key, register] of Object.entries(state)) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.#data.set(key, new LWWRegister(this.id, register));\n&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;}\n}<\/code><\/pre><p data-ke-size=\"size16\">#data\ub294 LWW Register \uc778\uc2a4\ud134\uc2a4\uc5d0 \ub300\ud55c \ud0a4 \ub9f5\uc744 \ubcf4\uc720\ud55c private \ud504\ub85c\ud37c\ud2f0\uc774\ub2e4.<br>&nbsp;<br>\uae30\uc874 \uc0c1\ud0dc\ub85c<b> LWW Map\uc744 \uc0c8\ub85c \ub9cc\ub4e4\ub824\uba74<\/b>(\uc778\uc2a4\ud134\uc2a4\ud654) <b>\uc0c1\ud0dc\ub97c \ubc18\ubcf5<\/b>\ud558\uace0 <b>\uac01 LWW Register\ub97c \ub2e4\uc2dc \ub9cc\ub4e4\uc5b4\uc57c \ud55c\ub2e4.<\/b>(\uc778\uc2a4\ud134\uc2a4\ud654)<br>&nbsp;<br>\uc65c\ub0d0\ud558\uba74 <b>LWWRegister\uc740 \uac1d\uccb4\uc774\uae30 \ub54c\ubb38<\/b>\uc774\ub2e4.<br>&nbsp;<br>CRDT\uc5d0\uc11c\ub294 \uc55e\uc11c \uc124\uba85\ud588\ub4ef value, state, merge \uc138 \uac00\uc9c0 \uc18d\uc131\uc774 \ud544\uc694\ud558\ub2e4.<br>&nbsp;<\/p><h4 data-ke-size=\"size20\">value<\/h4><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>get value() {\n&nbsp;&nbsp;&nbsp;&nbsp;const value: Value&lt;T&gt; = {};\n\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uac01 \uac12\uc774 \ud574\ub2f9 \ud0a4\uc758 \ub808\uc9c0\uc2a4\ud130 \uac12\uc73c\ub85c \uc124\uc815\ub41c \uac1d\uccb4\ub97c \uad6c\ucd95\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;for (const [key, register] of this.#data.entries()) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (register.value !== null) value[key] = register.value;\n&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;return value;\n&nbsp;&nbsp;}<\/code><\/pre><p data-ke-size=\"size16\">key\ub97c \ubc18\ubcf5\ud558\uace0 \uac01 ket\uc5d0 register.value \uc989 \ub808\uc9c0\uc2a4\ud130\uc758 \uac12\uc744 \uac00\uc838\uc624\ub294 getter \ud568\uc218 \uc5ed\ud560\uc744 \ud55c\ub2e4.<br>&nbsp;<\/p><h4 data-ke-size=\"size20\">state<\/h4><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>get state() {\n&nbsp;&nbsp;&nbsp;&nbsp;const state: State&lt;T&gt; = {};\n\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uac01 \uac12\uc774 \ud574\ub2f9 \ud0a4\uc5d0\uc11c \ub808\uc9c0\uc2a4\ud130\uc758 \uc804\uccb4 \uc0c1\ud0dc\ub85c \uc124\uc815\ub41c \uac1d\uccb4\ub97c \uad6c\ucd95\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;for (const [key, register] of this.#data.entries()) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (register) state[key] = register.state;\n&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;return state;\n&nbsp;&nbsp;}<\/code><\/pre><div> <span style=\"color: #000000;\" data-token-index=\"0\">#data<\/span>\uc758 \ud0a4\ub97c \ubc18\ubcf5\ud558\uace0 \ud574\ub2f9 \ud0a4\uc5d0 \uc800\uc7a5\ub41c \ub808\uc9c0\uc2a4\ud130\uc5d0 \uc791\uc5c5\uc744 \uc804\ub2ec\ud55c\ub2e4. \n<\/div><p data-ke-size=\"size16\">&nbsp;<\/p><h4 data-ke-size=\"size20\">merge<\/h4><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>merge(state: State&lt;T&gt;) {\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uac01 \ud0a4\uc758 \ub808\uc9c0\uc2a4\ud130\ub97c \ud574\ub2f9 \ud0a4\uc758 \uc218\uc2e0 \uc0c1\ud0dc\uc640 \uc7ac\uadc0\uc801\uc73c\ub85c \ubcd1\ud569\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;for (const [key, remote] of Object.entries(state)) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const local = this.#data.get(key);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \ub808\uc9c0\uc2a4\ud130\uac00 \uc774\ubbf8 \uc874\uc7ac\ud558\uba74 \ub4e4\uc5b4\uc624\ub294 \uc0c1\ud0dc\uc640 \ubcd1\ud569\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (local) local.merge(remote);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74, \ub4e4\uc5b4\uc624\ub294 \uc0c1\ud0dc\uc640 \ud568\uaed8 \uc0c8\ub85c\uc6b4 `LWWRegister`\ub97c \uc778\uc2a4\ud134\uc2a4\ud654\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else this.#data.set(key, new LWWRegister(this.id, remote));\n&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;}<\/code><\/pre><p data-ke-size=\"size16\">\uba3c\uc800 <b>\ub9e4\uac1c\ubcc0\uc218\ub85c \ub4e4\uc5b4\uc628 state\ub97c \ubc18\ubcf5<\/b>\ud55c\ub2e4.<br>&nbsp;<br>\uc65c\ub0d0\ud558\uba74 \ub9e4\uac1c\ubcc0\uc218\ub85c \ub4e4\uc5b4\uc628 state\uc5d0 #data\uc758 <b>\ud0a4\uac00 \ub204\ub77d\ub41c \uacbd\uc6b0<\/b> <b>\ud574\ub2f9 \ud0a4\ub97c \uac74\ub4dc\ub9b4 \ud544\uc694\uac00 \uc5c6\ub2e4\ub294 \uac83\uc744 \uc54c \uc218 \uc788\uae30 \ub54c\ubb38<\/b>\uc774\ub2e4.<br>&nbsp;<br>\uc774 \ub54c\ubb38\uc5d0 LWWRegister\uac00 T | null \uc774\ub77c\ub294 \uc720\ub2c8\uc628 \ud0c0\uc785\uc744 \uac00\uc9c4\ub2e4.<br>&nbsp;<br>\ub2e4\ub978 \ud53c\uc5b4\uac00 \ub9f5\uc5d0\uc11c \ud0a4\ub97c \uc0ad\uc81c\ud55c \uacbd\uc6b0(\uc608\ub97c \ub4e4\uc5b4 \ud30c\uc77c\uc744 \ub2e4\ub978 \ucef4\ud4e8\ud130\uc5d0\uc11c \uc0ad\uc81c\ud55c \uacbd\uc6b0) \ub2e4\ub978 \ucef4\ud4e8\ud130\uc758 \ub9f5\uc5d0\uc11c\ub3c4 \ud0a4\ub97c \uc81c\uac70\ud574\uc57c \ud558\uae30 \ub54c\ubb38\uc774\ub2e4.<br>&nbsp;<br>\ub4e4\uc5b4\uc624\ub294 \uc0c1\ud0dc\uc758 \uac01 \ud0a4\uc5d0 \ub300\ud574 <b>\ud574\ub2f9 \ud0a4\uc758 \ub85c\uceec \ub808\uc9c0\uc2a4\ud130\ub97c \uac00\uc838\uc628\ub2e4.<\/b><br>&nbsp;<br>\ub9cc\uc57d \ud0a4\ub97c \ucc3e\uc73c\uba74 \uac01 \ucef4\ud4e8\ud130\uac00 \uc774\ubbf8 \uc54c\uace0 \uc788\ub294 \uae30\uc874 \ud0a4\ub97c \uc5c5\ub370\uc774\ud2b8 \ud558\ub294 \uac83\uc774\ubbc0\ub85c \ud574\ub2f9 \ud0a4\uc5d0\uc11c \ub4e4\uc5b4\uc624\ub294 \uc0c1\ud0dc\uc640 \ud574\ub2f9 \ub808\uc9c0\uc2a4\ud130\uc758 merge \uba54\uc11c\ub4dc\ub97c \ud638\ucd9c\ud574 \ubcd1\ud569\ud55c\ub2e4.<br>&nbsp;<br>\ub9cc\uc57d \ud0a4\ub97c \ucc3e\uc9c0 \ubabb\ud55c\ub2e4\uba74 \uac01 \ucef4\ud4e8\ud130\uac00 \ub9f5\uc5d0 \uc0c8 \ud0a4\ub97c \ucd94\uac00\ud55c \uac83\uc774\ub2e4.<br>&nbsp;<br>\ub54c\ubb38\uc5d0 \ud0a4\uc5d0\uc11c \ub4e4\uc5b4\uc624\ub294 \uc0c1\ud0dc\ub97c \uc0ac\uc6a9\ud558\uc5ec \uc0c8\ub85c\uc6b4 LWW Register\ub97c \ub9cc\ub4e0\ub2e4.(\uc778\uc2a4\ud134\uc2a4\ud654)<br>&nbsp;<br>value, state, merge\ub294 CRDT\uc758 \uae30\ubcf8\uc801\uc778 \uad6c\ud604\uccb4\uc774\ub2e4.<br>\uc774\uc5d0 \ub354\ud574 LWW Map\uc740 Map \uc790\ub8cc\uad6c\uc870\uc5d0\uc11c \uc77c\ubc18\uc801\uc73c\ub85c \uc0ac\uc6a9\ub418\ub294 \uba54\uc11c\ub4dc\uc778 set, get, delete, has\ub97c \uad6c\ud604\ud574\uc57c \ud55c\ub2e4.<br>&nbsp;<\/p><h4 data-ke-size=\"size20\">set<\/h4><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>&nbsp;&nbsp;set(key: string, value: T) {\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uc8fc\uc5b4\uc9c4 \ud0a4\uc5d0\uc11c \ub808\uc9c0\uc2a4\ud130\ub97c \uac00\uc838\uc635\ub2c8\ub2e4\n&nbsp;&nbsp;&nbsp;&nbsp;const register = this.#data.get(key);\n&nbsp;&nbsp;&nbsp;&nbsp;\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \ub808\uc9c0\uc2a4\ud130\uac00 \uc774\ubbf8 \uc874\uc7ac\ud558\uba74 \uac12\uc744 \uc124\uc815\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;if (register) register.set(value);\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74 \uac12\uc73c\ub85c \uc0c8 `LWWRegister`\ub97c \uc778\uc2a4\ud134\uc2a4\ud654\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;else this.#data.set(key, new LWWRegister(this.id, [this.id, 1, value]));\n&nbsp;&nbsp;}<\/code><\/pre><p data-ke-size=\"size16\">LWW Register\uc640 \ub611\uac19\ub2e4.<br>key\uc640 value\ub97c \ub9e4\uac1c\ubcc0\uc218\ub85c \ubc1b\uace0 \ud574\ub2f9 \ud0a4\uc5d0 \ud574\ub2f9\ud558\ub294 register\ub97c \uac00\uc838\uc628\ub2e4.<br>\uc774\ubbf8 \ub808\uc9c0\uc2a4\ud130\uac00 \uc874\uc7ac\ud558\uba74 \uac12\uc744 \uc124\uc815\ud558\uace0 \uc5c6\uc73c\uba74 \uc0c8\ub85c\uc6b4 LWWRegister\ub97c \ub9cc\ub4e0\ub2e4.<br>\uac01 \ucef4\ud4e8\ud130\uc758 ID, \ud0c0\uc784\uc2a4\ud0ec\ud504 1, value\uac12\uc774 \ub4e4\uc5b4\uac04\ub2e4.(\ucd08\uae30\uac12 \uc138\ud305)<\/p><h4 data-ke-size=\"size20\">get<\/h4><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>&nbsp;&nbsp;get(key: string) {\n&nbsp;&nbsp;&nbsp;&nbsp;return this.#data.get(key)?.value ?? undefined;\n&nbsp;&nbsp;}<\/code><\/pre><p data-ke-size=\"size16\">key\ub97c \ub9e4\uac1c\ubcc0\uc218\ub85c \ubc1b\ub294\ub2e4.<br>&nbsp;<br>\ub9cc\uc57d \ud0a4\uc5d0 \ud574\ub2f9\ud558\ub294 \ub808\uc9c0\uc2a4\ud130\uac00 \uc874\uc7ac\ud55c\ub2e4\uba74 \uac00\uc838\uc628\ub2e4.<br>&nbsp;<br>\uc5c6\uc73c\uba74 undefined\uc774\ub2e4.<br>&nbsp;<br>\uac01 register\ub294 \uc704\uc5d0 \uc124\uba85\ud588\ub4ef\uc774 T | null\uc758 \ud0c0\uc785\uc744 \uac00\uc9c4\ub2e4. \ub54c\ubb38\uc5d0 null\uc778 \uacbd\uc6b0\uc5d4 undefined\ub97c \ubc1b\uc544\uc628\ub2e4.<\/p><h4 data-ke-size=\"size20\">delete<\/h4><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>&nbsp;&nbsp;delete(key: string) {\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ register\uac00 \uc874\uc7ac\ud558\ub294 \uacbd\uc6b0 null\ub85c \ucc98\ub9ac\n&nbsp;&nbsp;&nbsp;&nbsp;this.#data.get(key)?.set(null);\n&nbsp;&nbsp;}<\/code><\/pre><p data-ke-size=\"size16\">key\ub97c \ub9e4\uac1c\ubcc0\uc218\ub85c \ubc1b\ub294\ub2e4.<br>&nbsp;<br><b>key\uc5d0 \ud574\ub2f9\ud558\ub294 register\uac00 \uc874\uc7ac\ud560 \uacbd\uc6b0 null\ub85c \uc124\uc815<\/b>\ud55c\ub2e4.<br>&nbsp;<br>\uc989 delete\ub97c \uc218\ud589\ud558\ub354\ub77c\ub3c4 \uba54\ud0c0\ub370\uc774\ud130\ub294 \uacc4\uc18d \uc720\uc9c0\ub41c\ub2e4.<br>&nbsp;<br>\uc774\ub97c \ud1b5\ud574 \uc544\uc9c1 \ud0a4\uac00 \uc5c6\ub294 \uc0c1\ud0dc\uc77c\uc9c0\ub77c\ub3c4 \uc0ad\uc81c\ub418\uc5c8\ub294\uc9c0 \uad6c\ubd84\ud560 \uc218 \uc788\ub2e4.<br>&nbsp;<br>\uc774\ub97c <b>\ud23c\uc2a4\ud1a4<\/b>\uc774\ub77c\uace0 \ud558\uba70 \uacfc\uac70 CRDT\uc758 \uc720\uc0b0\uc774\ub77c\uace0 \ud55c\ub2e4.<br>&nbsp;<br>\uc65c \uacfc\uac70 CRDT\uc758 \uc720\uc0b0\uc778\uc9c0\ub294 \ud6c4\uc5d0 \uc124\uba85\ud55c\ub2e4.<br>&nbsp;<br>\ub9cc\uc57d \ud23c\uc2a4\ud1a4 \uc5c6\uc774 CRDT\ub97c \uc218\ud589\ud558\uba74 \uc544\ub798\uc640 \uac19\uc774 \ub3d9\uc791\ud55c\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"750\" data-origin-height=\"360\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/HQqda\/dJMcahCQNAe\/5tQIYWjSheXPxge2o5oVwK\/img.gif\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/HQqda\/dJMcahCQNAe\/5tQIYWjSheXPxge2o5oVwK\/img.gif\" data-alt=\"no-tombstone\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/HQqda\/dJMcahCQNAe\/5tQIYWjSheXPxge2o5oVwK\/img.gif\" srcset=\"https:\/\/blog.kakaocdn.net\/dn\/HQqda\/dJMcahCQNAe\/5tQIYWjSheXPxge2o5oVwK\/img.gif\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"750\" height=\"360\" data-origin-width=\"750\" data-origin-height=\"360\"\/><\/span><figcaption>no-tombstone<\/figcaption>\n<\/figure>\n<p data-ke-size=\"size16\">alice\ub294 \ub124\ud2b8\uc6cc\ud06c\ub97c \ub044\uace0 fooo\ub77c\ub294 \ud0a4\ub97c \ub4f1\ub85d\ud588\ub2e4.<br>\uc774\ud6c4 \ub124\ud2b8\uc6cc\ud06c\ub97c \uc5f0\uacb0\ud588\ub2e4.<br>&nbsp;<br>bob\uc740 fooo\uac00 \ub4f1\ub85d\ub418\uc5c8\ub294\uc9c0 \uc804\ud600 \ubaa8\ub978\ub2e4.<br>\ub54c\ubb38\uc5d0 \uadf8\ub0e5 fooo\ub97c \uc81c\uac70\ud574 \ubc84\ub9ac\ub294 \ubaa8\uc2b5\uc774\ub2e4.<br>&nbsp;<br>\uc774\ub294 \ub9d0\uc774 \uc548\ub41c\ub2e4.<br>&nbsp;<br>\ud23c\uc2a4\ud1a4 \ubc29\uc2dd\uc744 \uc81c\ub300\ub85c \uc801\uc6a9\ud558\uba74 \uc544\ub798\uc640 \uac19\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"752\" data-origin-height=\"324\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/AmWLj\/dJMcafZk06l\/N49kjlcleHlGKmtgCConz1\/img.gif\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/AmWLj\/dJMcafZk06l\/N49kjlcleHlGKmtgCConz1\/img.gif\" data-alt=\"tombstone\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/AmWLj\/dJMcafZk06l\/N49kjlcleHlGKmtgCConz1\/img.gif\" srcset=\"https:\/\/blog.kakaocdn.net\/dn\/AmWLj\/dJMcafZk06l\/N49kjlcleHlGKmtgCConz1\/img.gif\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"752\" height=\"324\" data-origin-width=\"752\" data-origin-height=\"324\"\/><\/span><figcaption>tombstone<\/figcaption>\n<\/figure>\n<p data-ke-size=\"size16\">\uc774 \uc0ac\uc9c4\uc744 \ubcf4\uba74 null\uc778 \uac12\uc774 Map\uc5d0 \uacc4\uc18d \ub0a8\uc544\uc788\ub294 \uac83\uc744 \uc54c \uc218 \uc788\ub2e4.<br>&nbsp;<br>\uc989 \uc774 \uc0ac\uc9c4\uc5d0\uc11c \ud23c\uc2a4\ud1a4 \ubc29\uc2dd\uc774 \uacfc\uac70 CRDT\uc758 \uc720\uc0b0\uc778\uc9c0 \uc54c \uc218 \uc788\ub2e4.<br>&nbsp;<br>\uc65c \uacfc\uac70 CRDT\uc758 \uc720\uc0b0\uc778\uac00?<br>&nbsp;<br>\uc800\ub807\uac8c \uacc4\uc18d null\ub85c key\ub97c \ubc29\uce58\ud574 \ub450\uba74 \uba54\ubaa8\ub9ac\ub97c \uacc4\uc18d \uc7a1\uc544\uba39\uace0, \ub370\uc774\ud130\uac00 \uacc4\uc18d \ucee4\uc9c0\uace0, \uc131\ub2a5\uc774 \uc800\ud558\ub418\uba70, \uc624\ubc84\ud5e4\ub4dc\uac00 \uc99d\uac00\ud55c\ub2e4.<br>&nbsp;<br>\uadf8\ub798\uc11c \uc694\uc998\uc740 garbage collection\uc744 \uc218\ud589\ud55c\ub2e4\uace0 \ud55c\ub2e4.<\/p><h4 data-ke-size=\"size20\">has<\/h4><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>has(key: string) {\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \ub808\uc9c0\uc2a4\ud130\uac00 \uc874\uc7ac\ud558\uc9c0 \uc54a\uac70\ub098 \uac12\uc774 null\uc774\uba74 \ub9f5\uc5d0 \ud0a4\uac00 \ud3ec\ud568\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;return this.#data.get(key)?.value !== null;\n&nbsp;&nbsp;}<\/code><\/pre><p data-ke-size=\"size16\">\ub808\uc9c0\uc2a4\ud130\uac00 \uc874\uc7ac\ud558\uc9c0 \uc54a\uac70\ub098 \uac12\uc774 null\uc774\uba74 \ub9f5\uc5d0 \ud574\ub2f9 \ud0a4\uac00 \uc5c6\ub294 \uac83\uc73c\ub85c \uac04\uc8fc\ud55c\ub2e4.<br>&nbsp;<br>\ud0a4\uac00 \ub9f5\uc5d0 \uc874\uc7ac\ud558\ub294\uc9c0 \uc544\ub2cc\uc9c0\ub97c \ub098\ud0c0\ub0b4\ub294 boolean \uac12\uc744 \ubc18\ud658\ud55c\ub2e4.<br>&nbsp;<\/p><h4 data-ke-size=\"size20\">\uc804\uccb4 class \ucf54\ub4dc<\/h4><p data-ke-size=\"size16\">\uc704\uc758 \uba54\uc11c\ub4dc\ub4e4\uc744 \uc804\ubd80 \ud3ec\ud568\ud55c class \ucf54\ub4dc\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>class LWWMap&lt;T&gt; {\n&nbsp;&nbsp;readonly id: string;\n&nbsp;&nbsp;#data = new Map&lt;string, LWWRegister&lt;T | null&gt;&gt;();\n\n&nbsp;&nbsp;constructor(id: string, state: State&lt;T&gt;) {\n&nbsp;&nbsp;&nbsp;&nbsp;this.id = id;\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \ucd08\uae30 \uc0c1\ud0dc\uc758 \uac01 \ud0a4\uc5d0 \ub300\ud574 \uc0c8 \ub808\uc9c0\uc2a4\ud130\ub97c \uc0dd\uc131\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;for (const [key, register] of Object.entries(state)) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.#data.set(key, new LWWRegister(this.id, register));\n&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;}\n&nbsp;&nbsp;get value() {\n&nbsp;&nbsp;&nbsp;&nbsp;const value: Value&lt;T&gt; = {};\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uac01 \uac12\uc774 \ud574\ub2f9 \ud0a4\uc758 \ub808\uc9c0\uc2a4\ud130 \uac12\uc73c\ub85c \uc124\uc815\ub41c \uac1d\uccb4\ub97c \uad6c\ucd95\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;for (const [key, register] of this.#data.entries()) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (register.value !== null) value[key] = register.value;\n&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;return value;\n&nbsp;&nbsp;}\n&nbsp;&nbsp;get state() {\n&nbsp;&nbsp;&nbsp;&nbsp;const state: State&lt;T&gt; = {};\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uac01 \uac12\uc774 \ud574\ub2f9 \ud0a4\uc5d0\uc11c \ub808\uc9c0\uc2a4\ud130\uc758 \uc804\uccb4 \uc0c1\ud0dc\ub85c \uc124\uc815\ub41c \uac1d\uccb4\ub97c \uad6c\ucd95\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;for (const [key, register] of this.#data.entries()) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (register) state[key] = register.state;\n&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;return state;\n&nbsp;&nbsp;}\n&nbsp;&nbsp;has(key: string) {\n&nbsp;&nbsp;&nbsp;&nbsp;return this.#data.get(key)?.value !== null;\n&nbsp;&nbsp;}\n&nbsp;&nbsp;get(key: string) {\n&nbsp;&nbsp;&nbsp;&nbsp;return this.#data.get(key)?.value;\n&nbsp;&nbsp;}\n&nbsp;&nbsp;set(key: string, value: T) {\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uc8fc\uc5b4\uc9c4 \ud0a4\uc5d0\uc11c \ub808\uc9c0\uc2a4\ud130\ub97c \uac00\uc838\uc635\ub2c8\ub2e4\n&nbsp;&nbsp;&nbsp;&nbsp;const register = this.#data.get(key);\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \ub808\uc9c0\uc2a4\ud130\uac00 \uc774\ubbf8 \uc874\uc7ac\ud558\uba74 \uac12\uc744 \uc124\uc815\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;if (register) register.set(value);\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74 \uac12\uc73c\ub85c \uc0c8 `LWWRegister`\ub97c \uc778\uc2a4\ud134\uc2a4\ud654\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;else this.#data.set(key, new LWWRegister(this.id, [this.id, 1, value]));\n&nbsp;&nbsp;}\n&nbsp;&nbsp;delete(key: string) {\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ register\uac00 \uc874\uc7ac\ud558\ub294 \uacbd\uc6b0 null\ub85c \ucc98\ub9ac\n&nbsp;&nbsp;&nbsp;&nbsp;this.#data.get(key)?.set(null);\n&nbsp;&nbsp;}\n&nbsp;&nbsp;merge(state: State&lt;T&gt;) {\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uac01 \ud0a4\uc758 \ub808\uc9c0\uc2a4\ud130\ub97c \ud574\ub2f9 \ud0a4\uc758 \uc218\uc2e0 \uc0c1\ud0dc\uc640 \uc7ac\uadc0\uc801\uc73c\ub85c \ubcd1\ud569\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;for (const [key, remote] of Object.entries(state)) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const local = this.#data.get(key);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \ub808\uc9c0\uc2a4\ud130\uac00 \uc774\ubbf8 \uc874\uc7ac\ud558\uba74 \ub4e4\uc5b4\uc624\ub294 \uc0c1\ud0dc\uc640 \ubcd1\ud569\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (local) local.merge(remote);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74, \ub4e4\uc5b4\uc624\ub294 \uc0c1\ud0dc\uc640 \ud568\uaed8 \uc0c8\ub85c\uc6b4 `LWWRegister`\ub97c \uc778\uc2a4\ud134\uc2a4\ud654\ud569\ub2c8\ub2e4.\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else this.#data.set(key, new LWWRegister(this.id, remote));\n&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;}\n}<\/code><\/pre><h3 data-ke-size=\"size23\">\ucc38\uace0\uc790\ub8cc<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">Blog<br><a href=\"https:\/\/junghan92.medium.com\/%EB%B2%88%EC%97%AD-crdt%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B8%ED%84%B0%EB%9E%99%ED%8B%B0%EB%B8%8C-%EC%9E%85%EB%AC%B8-818403128cca\" target=\"_blank\"><span>https:\/\/junghan92.medium.com\/%EB%B2%88%EC%97%AD-crdt%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B8%ED%84%B0%EB%9E%99%ED%8B%B0%EB%B8%8C-%EC%9E%85%EB%AC%B8-818403128cca<\/span><\/a><br>&nbsp;<br>\uc6d0\ubb38<br><a href=\"https:\/\/jakelazaroff.com\/words\/an-interactive-intro-to-crdts\/\" target=\"_blank\"><span>https:\/\/jakelazaroff.com\/words\/an-interactive-intro-to-crdts\/<\/span><\/a><\/p><figure data-ke-type=\"opengraph\" data-og-title=\"An Interactive Intro to CRDTs | jakelazaroff.com\" data-ke-align=\"alignCenter\" data-og-description=\"CRDTs don't have to be all academic papers and math jargon. Learn what CRDTs are and how they work through interactive visualizations and code samples.\" data-og-host=\"jakelazaroff.com\" data-og-source-url=\"https:\/\/jakelazaroff.com\/words\/an-interactive-intro-to-crdts\/\" data-og-image=\"https:\/\/blog.kakaocdn.net\/dna\/oLctT\/hyZNAnnMNH\/AAAAAAAAAAAAAAAAAAAAABi-_UWXbeg8nYSfdOf_-ZJanlgQOwEofigsGOG8lI33\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1764514799&amp;allow_ip=&amp;allow_referer=&amp;signature=MGMVktepsul7CzJUWkRRw9MLQ54%3D\" data-og-url=\"https:\/\/jakelazaroff.com\/words\/an-interactive-intro-to-crdts\/\"><a href=\"https:\/\/jakelazaroff.com\/words\/an-interactive-intro-to-crdts\/\" target=\"_blank\" data-source-url=\"https:\/\/jakelazaroff.com\/words\/an-interactive-intro-to-crdts\/\"><div class=\"og-image\" style=\"background-image: url('https:\/\/blog.kakaocdn.net\/dna\/oLctT\/hyZNAnnMNH\/AAAAAAAAAAAAAAAAAAAAABi-_UWXbeg8nYSfdOf_-ZJanlgQOwEofigsGOG8lI33\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1764514799&amp;allow_ip=&amp;allow_referer=&amp;signature=MGMVktepsul7CzJUWkRRw9MLQ54%3D')\"> <\/div><div class=\"og-text\"><p class=\"og-title\">An Interactive Intro to CRDTs | jakelazaroff.com<\/p><p class=\"og-desc\">CRDTs don't have to be all academic papers and math jargon. Learn what CRDTs are and how they work through interactive visualizations and code samples.<\/p><p class=\"og-host\">jakelazaroff.com<\/p><\/div><\/a><\/figure><p data-ke-size=\"size16\">&nbsp;<\/p>","category":["CS\/\uc790\ub8cc\uad6c\uc870(data structure)","\uc790\ub8cc\uad6c\uc870"],"author":"MaKa_","guid":"https:\/\/mk-develop.tistory.com\/61","comments":"https:\/\/mk-develop.tistory.com\/entry\/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-CRDT-%EC%8B%A4%EC%8B%9C%EA%B0%84-%ED%98%91%EC%97%85-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85#entry61comment","pubDate":"Wed, 26 Nov 2025 18:35:29 +0900"},{"title":"AI \uc5c6\uc774 \ud22c\ub450\ub9ac\uc2a4\ud2b8 \uad6c\ud604\uae30","link":"https:\/\/mk-develop.tistory.com\/entry\/AI-%EC%97%86%EC%9D%B4-%ED%88%AC%EB%91%90%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EA%B5%AC%ED%98%84%EA%B8%B0","description":"<h3 data-ke-size=\"size23\">\uac1c\uc694<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">\uc694\uc998 Javascript\uc640 React \uae30\ubcf8&amp;\uc2ec\ud654 \uacf5\ubd80\ub97c \ud558\uba70 \uc9c0\ub0c8\ub2e4.<br>&nbsp;<br>\ud68c\uc0ac\uc5d0 \uc9c0\uc6d0\uc11c\ub294 \uacc4\uc18d \ub123\uace0 \uc788\uc9c0\ub9cc \uacc4\uc18d\ud574\uc11c \uc11c\ub958 \ud0c8\ub77d\uc774 \ubc18\ubcf5\ub418\uc5c8\uace0 \ub098\ub294 \uc8fc\ubcc0 \uc0ac\ub78c\ub4e4\uc758 \ub4e3\uae30 \uc88b\uc740 \ub9d0\uc774 \uc544\ub2cc \ud655\uc2e4\ud55c \uc790\uae30 \uac1d\uad00\ud654\uac00 \ud544\uc694\ud558\ub2e4\uace0 \uc0dd\uac01\ud588\ub2e4.<br>&nbsp;<br>\ud504\ub85c\uc81d\ud2b8\ub97c \uc548\ud55c\uc9c0\ub3c4 3\uac1c\uc6d4\uc774 \uc9c0\ub098\uace0 \uc788\uae30\uc5d0 \uc7ac\ubc0c\ub294 \ubb34\uc5b8\uac00\ub97c \ub9cc\ub4e4\uace0 \uc2f6\ub2e4\ub294 \uc0dd\uac01\ub3c4 \ub4e4\uc5c8\ub2e4.<br>&nbsp;<br>\ud558\uc9c0\ub9cc \ubb34\ud131\ub300\uace0 \ud300\uc6d0\uc744 \ubaa8\uc544\uc11c \uaddc\ubaa8 \uc788\ub294 \ud504\ub85c\uc81d\ud2b8\ub97c \ud558\uae30\uc5d4 \uacf5\ubd80\ub97c \uc704\ud55c \ud504\ub85c\uc81d\ud2b8\uac00 \uc548\ub420 \uac83 \uac19\uc558\ub2e4.<br>&nbsp;<br>\ub54c\ubb38\uc5d0 \uc774\ubc88\uc5d0\ub294 \uc81c\ub300\ub85c \uacf5\ubd80\ub97c \ud560 \uc218 \uc788\ub294 \ubb34\uc5b8\uac00\ub97c \ub9cc\ub4e4\uc790\uace0 \uacb0\uc2ec\ud588\ub2e4.<br>&nbsp;<br>\uc8fc\uc81c\ub294 Todo List\ub85c \uc815\ud588\ub2e4.<br>&nbsp;<br>Todo List? AI \uc4f0\uba74 \ub108\ubb34 \uc27d\uac8c \ub9cc\ub4e4 \uc218 \uc788\ub294 \ud504\ub85c\uc81d\ud2b8 \uc544\ub2cc\uac00? \ub77c\uace0 \uc0dd\uac01\ud560 \uc218 \uc788\ub2e4.<br>&nbsp;<br>\ub54c\ubb38\uc5d0 \ub098\ub294 \uc140\ud504\ub85c \uc871\uc1c4\ub97c \ucc44\uc6b0\uae30\ub85c \ud588\ub2e4.<br>&nbsp;<br><b>1. AI\ub97c \uc0ac\uc6a9\ud558\uc9c0 \uc54a\uae30<\/b><br><b>2. \ubaa8\ub974\ub294 \uac83\uc740 \uac80\uc0c9&amp;\uacf5\uc2dd\ubb38\uc11c\ub9cc \ucc38\uace0\ud558\uae30<\/b><br><b>3. \uc704 \uc0ac\ud56d\uc744 \uc9c0\ud0a4\uba74\uc11c \ucf54\ub4dc \ud488\uc9c8, \ud655\uc7a5\uc131\ub3c4 \ucc59\uae38 \uac83<\/b><br>&nbsp;<br>\uac04\ub2e8\ud55c \uae30\ub2a5\ub9cc \uc788\ub294 \ud504\ub85c\uc81d\ud2b8\uc77c\uc218 \uc788\uc9c0\ub9cc Todo List\ub3c4 \uc0c1\ud0dc\uad00\ub9ac\uc640 \ucd5c\uc801\ud654 \ub4f1 \uc2e0\uacbd \uc4f8 \ubd80\ubd84\uc774 \ub9ce\uae30\uc5d0 \ud55c\ubc88 \ub9cc\ub4e4\uc5b4 \ubcf4\uae30\ub85c \ud588\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\uc694\uad6c\uc0ac\ud56d<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">\uc694\uad6c\uc0ac\ud56d\uc740 \ub2e4\uc74c\uacfc \uac19\uc774 \uad6c\uc131\ud558\uc600\ub2e4.<br>&nbsp;<br>1. \ub2e4\ud06c\ubaa8\ub4dc\ub97c \uc9c0\uc6d0\ud55c\ub2e4.<br>2. \uc0ac\uc6a9\uc790\ub294 Todo list\ub97c \ub4f1\ub85d\ud560 \uc218 \uc788\ub2e4. \uae38\uc774\ub294 30\uc790\ub85c \uc81c\ud55c\ub41c\ub2e4.<br>3. \uc0ac\uc6a9\uc790\ub294 \uc644\ub8cc \uc5ec\ubd80\ub97c \uccb4\ud06c\ud560 \uc218 \uc788\ub2e4.<br>4. \uc0ac\uc6a9\uc790\ub294 \uc774\ubbf8 \ub4f1\ub85d\ub41c \ud560 \uc77c\uc744 \uc218\uc815\ud560 \uc218 \uc788\ub2e4.<br>5. \uc0ac\uc6a9\uc790\ub294 \ub4f1\ub85d\ub41c \uc77c\uc744 \uc0ad\uc81c\ud560 \uc218 \uc788\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\ub2e4\ud06c \ubaa8\ub4dc\ub97c \uad6c\ud604\ud558\uae30 \uc704\ud55c \ub77c\uc774\ube0c\ub7ec\ub9ac \ud0d0\uc0c9<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">&nbsp;<br>\ud504\ub85c\uc81d\ud2b8 \uc9c4\ud589\uc5d0 \uc55e\uc11c \uc5b4\ub5a4 \ub77c\uc774\ube0c\ub7ec\ub9ac\ub97c \uc0ac\uc6a9\ud560 \uc9c0 \ud0d0\uc0c9\ud558\ub294 \uc2dc\uac04\uc744 \uac00\uc84c\ub2e4.<br>\uc77c\ubc18\uc801\uc778 Todo List\ub77c\uba74 React\uc5d0 \uc788\ub294 \uae30\ubcf8 \ud6c5\uacfc JS\uc758 \uba54\uc11c\ub4dc\ub4e4\uc744 \uc0ac\uc6a9\ud558\uc5ec \uad6c\ud604\ud560 \uc218 \uc788\uc9c0\ub9cc \ub2e4\ud06c \ubaa8\ub4dc\ub97c \uad6c\ud604\ud558\uae30 \uc704\ud568\uc774\uc5c8\ub2e4.<br>&nbsp;<br>\uba3c\uc800 <b>CSS \ub77c\uc774\ube0c\ub7ec\ub9ac<\/b>\ub97c \ud0d0\uc0c9\ud558\uc600\ub2e4.<br>&nbsp;<br>\uc774\uc804\uc5d0 \ub9ce\uc774 \uc0ac\uc6a9\ud574\uc11c \uc775\uc219\ud558\uace0 <b>zero-runtime \ub77c\uc774\ube0c\ub7ec\ub9ac\uc778 tailwind<\/b>\ub97c \uc0ac\uc6a9\ud560\uae4c \ud588\uc9c0\ub9cc tailwind\ub294 \ub2e4\ud06c \ubaa8\ub4dc \ub514\uc790\uc778 \uc2dc dark: \ub77c\ub294 \ud0a4\uc6cc\ub4dc\ub97c \uc55e\uc5d0 \ud56d\uc0c1 \ubd99\ud600\uc11c \uad6c\ud604\ud574\uc57c \ud588\uc5c8\ub2e4.<br>&nbsp;<br>\ub54c\ubb38\uc5d0 \ud5a5\ud6c4 \ud655\uc7a5\uc131\uc774 \ub5a8\uc5b4\uc9c0\uc9c0 \uc54a\uc744\uae4c \uc0dd\uac01\ud588\ub2e4.<br>&nbsp;<br>\uadf8\ub798\uc11c zero-runtime\uc774 \uc544\ub2c8\ub354\ub77c\ub3c4 \ub514\uc790\uc778 \uc2dc\uc2a4\ud15c \uad00\ub9ac\uac00 \uc6a9\uc774\ud55c <b>CSS-in-JS<\/b> <b>\ub77c\uc774\ube0c\ub7ec\ub9ac<\/b>\ub97c \uc0ac\uc6a9\ud558\uae30\ub85c \ud588\ub2e4.<br>&nbsp;<br>\ud6c4\ubcf4\uc5d0 \ub4e4\uc740 \ub77c\uc774\ube0c\ub7ec\ub9ac\ub294 2\uac00\uc9c0\uc600\ub2e4.<br>&nbsp;<br>1. styled-component<br>2. emotion<br>&nbsp;<br>styled-component\ub294 \ud604\uc7ac \uc720\uc9c0 \uad00\ub9ac \uc0c1\ud0dc\uc5d0 \uc788\ub2e4.<br>\ucd94\uac00\uc801\uc778 \uae30\ub2a5 \uc5c5\ub370\uc774\ud2b8\ub294 \uc9c0\uc6d0\ud558\uc9c0 \uc54a\uace0 \uc788\uc5b4 \ubc30\uc81c\ud558\uc600\ub2e4.<br>&nbsp;<br><b>emotion \ub77c\uc774\ube0c\ub7ec\ub9ac\ub294 \ub7f0\ud0c0\uc784 \uc624\ubc84\ud5e4\ub4dc\uac00 \uc874\uc7ac<\/b>\ud558\uc9c0\ub9cc <b>\ud544\uc694 \uc5c6\ub294 \uc2a4\ud0c0\uc77c\uc744 \ucd5c\uc18c\ud55c\uc73c\ub85c \uc0bd\uc785<\/b>\ud558\uace0 <b>\ubc88\ub4e4 \ud06c\uae30\uac00 \uc791\uae30\uc5d0<\/b> emotion\uc744 \uc0ac\uc6a9\ud558\uae30\ub85c \ud588\ub2e4.<br>&nbsp;<br>\ud68c\uace0\ub97c \uc4f0\uba74\uc11c \uc54c\uac8c \ub41c \uc0ac\uc2e4\uc778\ub370 \ud574\uc678\uc5d0\uc11c\ub294 React \ud504\ub85c\uc81d\ud2b8 \ud55c\uc815\uc73c\ub85c <b>Linaria<\/b>\ub97c \ub300\uc548\uc73c\ub85c \ub9ce\uc774 \uc0ac\uc6a9\ud558\ub294 \uac83 \uac19\uc73c\ubbc0\ub85c \uace0\ub824\ud574\ubcfc\ub9cc \ud588\ub358 \uac83 \uac19\ub2e4.<br>&nbsp;<br>\uc804\uc5ed \ub77c\uc774\ube0c\ub7ec\ub9ac\ub294 <b>Zustand<\/b>\ub97c \uc0ac\uc6a9\ud558\uc600\ub2e4.<br>&nbsp;<br>\uac00\ub3c5\uc131\uc774 \uc88b\uace0, boiler plate code\uac00 redux\uc640\ub294 \ube44\uad50\ud560 \uc218 \uc5c6\uc744 \uc815\ub3c4\ub85c \uc801\uace0, \uc0ac\uc6a9 \ubc29\ubc95\ub3c4 \ubcf5\uc7a1\ud558\uc9c0 \uc54a\uc544\uc11c \ub9ce\uc774\ub4e4 \uc0ac\uc6a9\ud558\ub294 \ub77c\uc774\ube0c\ub7ec\ub9ac\uae30\uc5d0 \uc544\uc8fc \ucd5c\uace0\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\ub2e4\ud06c \ubaa8\ub4dc\uac00 \uc801\uc6a9\ub41c \uacf5\ud1b5 \ucef4\ud3ec\ub10c\ud2b8 \uad6c\ud604<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">\ud504\ub85c\uc81d\ud2b8\uc5d0 \ud544\uc694\ud55c UI \ucef4\ud3ec\ub10c\ud2b8\ub97c \uba3c\uc800 \uad6c\ud604\ud558\uc600\ub2e4.<br>&nbsp;<br>TodoList\ub97c \uad6c\ud604\ud558\uba70 \ud544\uc694\ud55c \uad6c\uc131 \uc694\uc18c\ub294 \ucd1d 5\uac1c\ub85c \uc7a1\uc558\ub2e4.<br>&nbsp;<br>1. Button<br>2. Card<br>3. Header<br>4. Input<br>5. TouchableOpacity<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"1829\" data-origin-height=\"913\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/JboHP\/dJMcahbIHRP\/Kt758h6tvc3KDOipjDkFgK\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/JboHP\/dJMcahbIHRP\/Kt758h6tvc3KDOipjDkFgK\/img.png\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/JboHP\/dJMcahbIHRP\/Kt758h6tvc3KDOipjDkFgK\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJboHP%2FdJMcahbIHRP%2FKt758h6tvc3KDOipjDkFgK%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"700\" height=\"349\" data-origin-width=\"1829\" data-origin-height=\"913\"\/><\/span><\/figure>\n<p data-ke-size=\"size16\">document.body\uc640 \uc704 5\uac1c \ucef4\ud3ec\ub10c\ud2b8\uac00 themeStore\ub97c subscribe\ud558\uace0 store\uc758 \uc0c1\ud0dc\uc5d0 \ub530\ub77c \ub514\uc790\uc778\uc774 toggle\ub418\ub3c4\ub85d \uad6c\uc131\ud558\uc600\ub2e4.<br>&nbsp;<br>\uc0c9\uc0c1 \ucf54\ub4dc\ub294 Chrome\uc758 \ub514\uc790\uc778 \uc2dc\uc2a4\ud15c\uc744 \ucc38\uace0\ud558\uc600\ub2e4.<\/p><blockquote data-ke-style=\"style2\">styles\/theme.ts<\/blockquote><pre data-ke-type=\"codeblock\" class=\"javascript\" data-ke-language=\"javascript\"><code>\/**\n * background: \ubc30\uacbd\n * surface: \uce74\ub4dc, \ucee8\ud14c\uc774\ub108 \ubc30\uacbd\n * text: \ud14d\uc2a4\ud2b8\n * textSecondary: \ub35c \uac15\uc870\ub41c \ud14d\uc2a4\ud2b8\n * border: \ud14c\ub450\ub9ac\n * inputBackground: input\uc758 \ubc30\uacbd\uc0c9\n * inputBorder: input\uc758 \ud14c\ub450\ub9ac\n * buttonBackground: \ubc84\ud2bc \ubc30\uacbd\uc0c9\n * buttonText: \ubc84\ud2bc \ud14d\uc2a4\ud2b8\n * buttonHover: \ubc84\ud2bc hover\n * divider: \uacbd\uacc4\uc120\n * accent: \ud3ec\ucee4\uc2a4&amp;\ud558\uc774\ub77c\uc774\ud2b8\n *\/\nexport const PRIMARY = {\n&nbsp;&nbsp;background: '#FFFFFF',\n&nbsp;&nbsp;surface: '#F7F7F7',\n&nbsp;&nbsp;text: '#000000',\n&nbsp;&nbsp;textSecondary: '#555555',\n&nbsp;&nbsp;border: '#E0E0E0',\n&nbsp;&nbsp;inputBackground: '#FFFFFF',\n&nbsp;&nbsp;inputBorder: '#CCCCCC',\n&nbsp;&nbsp;inputText: '#000000',\n&nbsp;&nbsp;buttonBackground: '#007BFF',\n&nbsp;&nbsp;buttonText: '#FFFFFF',\n&nbsp;&nbsp;buttonHover: '#0056B3',\n&nbsp;&nbsp;divider: '#E0E0E0',\n&nbsp;&nbsp;accent: '#66AFE9',\n}\n\n\/**\n * background: \ubc30\uacbd\n * surface: \uce74\ub4dc, \ucee8\ud14c\uc774\ub108 \ubc30\uacbd\n * text: \ud14d\uc2a4\ud2b8\n * textSecondary: \ub35c \uac15\uc870\ub41c \ud14d\uc2a4\ud2b8\n * border: \ud14c\ub450\ub9ac\n * inputBackground: input\uc758 \ubc30\uacbd\uc0c9\n * inputBorder: input\uc758 \ud14c\ub450\ub9ac\n * buttonBackground: \ubc84\ud2bc \ubc30\uacbd\uc0c9\n * buttonText: \ubc84\ud2bc \ud14d\uc2a4\ud2b8\n * buttonHover: \ubc84\ud2bc hover\n * divider: \uacbd\uacc4\uc120\n * accent: \ud3ec\ucee4\uc2a4&amp;\ud558\uc774\ub77c\uc774\ud2b8\n *\/\nexport const DARKMODE = {\n&nbsp;&nbsp;background: '#121212',\n&nbsp;&nbsp;surface: '#1E1E1E',\n&nbsp;&nbsp;text: '#E8EAED',\n&nbsp;&nbsp;textSecondary: '#B0B0B0',\n&nbsp;&nbsp;border: '#2D2D2D',\n&nbsp;&nbsp;inputBackground: '#242424',\n&nbsp;&nbsp;inputBorder: '#3A3A3A',\n&nbsp;&nbsp;inputText: '#E8EAED',\n&nbsp;&nbsp;buttonBackground: '#0A84FF',\n&nbsp;&nbsp;buttonText: '#FFFFFF',\n&nbsp;&nbsp;buttonHover: '#1E6FFB',\n&nbsp;&nbsp;divider: '#303030',\n&nbsp;&nbsp;accent: '#339CFF',\n}<\/code><\/pre><p data-ke-size=\"size16\">AI\uac00 \uc5c6\uc73c\ub2c8 \uc8fc\uc11d\ub2e4\ub294\uac8c \ub9cc\ub9cc\uce58 \uc54a\uc558\ub2e4.<br>&nbsp;<br>\ub2e4\uc74c\uc73c\ub85c store\ub97c \uad6c\ud604\ud558\uc600\ub2e4.<\/p><blockquote data-ke-style=\"style2\">store\/themeStore.ts<\/blockquote><pre data-ke-type=\"codeblock\" class=\"javascript\" data-ke-language=\"javascript\"><code>import { create } from \"zustand\";\n\ntype theme = 'primary' | 'dark';\ninterface themeStore {\n&nbsp;&nbsp;theme: theme,\n&nbsp;&nbsp;toggleTheme: () =&gt; void\n}\nconst useTheme = create&lt;themeStore&gt;((set) =&gt; ({\n&nbsp;&nbsp;theme: 'primary',\n&nbsp;&nbsp;toggleTheme: () =&gt; set((state) =&gt; ({ theme: state.theme === 'primary' ? 'dark' : 'primary' })),\n}))\n\nexport default useTheme;<\/code><\/pre><p data-ke-size=\"size16\">\uac04\ub2e8\ud558\uac8c \uad6c\ud604\ud558\uc600\ub2e4.<br>&nbsp;<br>\ub2e4\uc74c\uc73c\ub85c UI\ub97c \uad6c\ud604\ud558\uc600\ub2e4.<br>&nbsp;<br>UI\uc5d0\uc11c \uace0\ub824\ud55c \uc0ac\ud56d\uc740 2\uac00\uc9c0\uc774\ub2e4.<br>&nbsp;<br><b>1. \uacb0\ud569\ub3c4\ub97c \ucd5c\ub300\ud55c \uc57d\ud558\uac8c<\/b><br><b>2. UI\uc5d0 \ub9de\ub294 Attribute\ub4e4\uc744 \uc81c\uc57d \uc5c6\uc774 \ubaa8\ub450 \uc0ac\uc6a9 \uac00\ub2a5\ud574\uc57c \ud568<\/b><\/p><blockquote data-ke-style=\"style2\">ui\/Button.tsx<\/blockquote><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>import { css } from \"@emotion\/css\";\nimport { DARKMODE, PRIMARY } from \"..\/styles\/theme\";\nimport useTheme from \"..\/store\/themeStore\";\n\nconst baseButtonStyle = css`\n&nbsp;&nbsp;border-radius: 8px;\n&nbsp;&nbsp;padding: 0.6em 1.2em;\n`\nconst primaryStyle = css`\n&nbsp;&nbsp;${baseButtonStyle};\n&nbsp;&nbsp;background-color: ${PRIMARY.buttonBackground};\n&nbsp;&nbsp;color: ${PRIMARY.buttonText};\n&nbsp;&nbsp;&amp;:hover{\n&nbsp;&nbsp;&nbsp;&nbsp;background-color: ${PRIMARY.buttonHover};\n&nbsp;&nbsp;}\n`;\nconst darkStyle = css`\n&nbsp;&nbsp;${baseButtonStyle};\n&nbsp;&nbsp;background-color: ${DARKMODE.buttonBackground};\n&nbsp;&nbsp;color: ${DARKMODE.buttonText};\n&nbsp;&nbsp;&amp;:hover{\n&nbsp;&nbsp;&nbsp;&nbsp;background-color: ${DARKMODE.buttonHover}\n&nbsp;&nbsp;}\n`;\ninterface ButtonProps extends React.ButtonHTMLAttributes&lt;HTMLButtonElement&gt; {\n&nbsp;&nbsp;readonly children: React.ReactNode;\n}\nconst Button = (props: ButtonProps) =&gt; {\n&nbsp;&nbsp;const { theme } = useTheme();\n&nbsp;&nbsp;const { children, ...rest } = props;\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;button\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;className={theme == 'primary' ? primaryStyle : darkStyle}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{...rest}\n&nbsp;&nbsp;&nbsp;&nbsp;&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{children}\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/button&gt;\n&nbsp;&nbsp;);\n};\n\nexport default Button;<\/code><\/pre><blockquote data-ke-style=\"style2\">ui\/Card.tsx<\/blockquote><pre data-ke-type=\"codeblock\" class=\"javascript\" data-ke-language=\"javascript\"><code>import { css } from \"@emotion\/css\";\nimport { DARKMODE, PRIMARY } from \"..\/styles\/theme\";\nimport useTheme from \"..\/store\/themeStore\";\n\nconst baseCardStyle = css`\n&nbsp;&nbsp;border-radius: 5px;\n&nbsp;&nbsp;border: 1px solid;\n&nbsp;&nbsp;display: flex;\n&nbsp;&nbsp;flex-direction: row;\n&nbsp;&nbsp;gap: 10px;\n&nbsp;&nbsp;align-items: center;\n&nbsp;&nbsp;padding: 1.5rem;\n&nbsp;&nbsp;justify-content: space-between;\n&nbsp;&nbsp;width: 100%;\n&nbsp;&nbsp;box-sizing: border-box;\n`;\n\nconst primaryStyle = css`\n&nbsp;&nbsp;${baseCardStyle};\n&nbsp;&nbsp;background-color: ${PRIMARY.surface};\n&nbsp;&nbsp;color: ${PRIMARY.text};\n&nbsp;&nbsp;border-color: ${PRIMARY.inputBorder};\n`;\n\nconst darkStyle = css`\n&nbsp;&nbsp;${baseCardStyle};\n&nbsp;&nbsp;background-color: ${DARKMODE.surface};\n&nbsp;&nbsp;color: ${DARKMODE.text};\n&nbsp;&nbsp;border-color: ${DARKMODE.inputBorder};\n`;\n\ninterface CardProps{\n&nbsp;&nbsp;readonly children?: React.ReactNode;\n}\nconst Card = (props: CardProps) =&gt; {\n&nbsp;&nbsp;const { theme } = useTheme();\n&nbsp;&nbsp;const {children} = props;\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;div className={theme === 'primary' ? primaryStyle : darkStyle }&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{children}\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/div&gt;\n&nbsp;&nbsp;);\n};\n\nexport default Card;<\/code><\/pre><blockquote data-ke-style=\"style2\">ui\/Header.tsx<\/blockquote><pre data-ke-type=\"codeblock\" class=\"javascript\" data-ke-language=\"javascript\"><code>import { css } from \"@emotion\/css\";\nimport TouchableOpacity from \".\/TouchableOpacity\";\nimport { IoIosArrowBack } from \"react-icons\/io\";\nimport { IoIosArrowForward } from \"react-icons\/io\";\nimport useTheme from \"..\/store\/themeStore\";\n\nconst headerStyle = css`\n&nbsp;&nbsp;background-color: transparent;\n&nbsp;&nbsp;font-size: 25px;\n&nbsp;&nbsp;display: flex;\n&nbsp;&nbsp;flex-direction: row;\n&nbsp;&nbsp;justify-content: space-between;\n&nbsp;&nbsp;max-width: 100%;\n&nbsp;&nbsp;width: 100vw;\n`;\n\ninterface HeaderProps {\n&nbsp;&nbsp;title: string;\n&nbsp;&nbsp;left?: boolean;\n&nbsp;&nbsp;right?: boolean;\n};\n\nconst Header = (props: HeaderProps) =&gt; {\n&nbsp;&nbsp;const {theme} = useTheme();\n&nbsp;&nbsp;const { title, left, right } = props;\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;header className={headerStyle}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{left ? &lt;BackBtn \/&gt; : &lt;div&gt;&lt;\/div&gt;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;h1\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;style={\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;theme === 'primary' ? {color: \"black\", margin: 0}:{color: \"white\", margin: 0}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{title}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/h1&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{right ? &lt;ForwardBtn \/&gt; : &lt;div&gt;&lt;\/div&gt;}\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/header&gt;\n&nbsp;&nbsp;);\n};\n\nexport default Header;\n\n\/\/ theme store\uac00 \uc5c6\uc744 \uacbd\uc6b0 \uc9c0\uc6b0\uace0 \uadf8\ub0e5 \uc0ac\uc6a9\ud574\ub3c4 \ubb34\ubc29\n\nconst BackBtn = () =&gt; {\n&nbsp;&nbsp;const {theme} = useTheme();\n&nbsp;&nbsp;const goBack = () =&gt; {\n&nbsp;&nbsp;&nbsp;&nbsp;history.back();\n&nbsp;&nbsp;}\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;TouchableOpacity onClick={goBack}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;IoIosArrowBack size={25} color={theme === 'primary' ? 'black' : 'white'} \/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/TouchableOpacity&gt;\n&nbsp;&nbsp;)\n}\n\nconst ForwardBtn = () =&gt; {\n&nbsp;&nbsp;const { theme } = useTheme();\n\n&nbsp;&nbsp;const goForward = () =&gt; {\n&nbsp;&nbsp;&nbsp;&nbsp;history.forward();\n&nbsp;&nbsp;}\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;TouchableOpacity onClick={goForward}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;IoIosArrowForward size={25} color={theme === 'primary' ? 'black' : 'white'} \/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/TouchableOpacity&gt;\n&nbsp;&nbsp;)\n}<\/code><\/pre><p data-ke-size=\"size16\">Header\ub294 left, right\ub97c props\ub85c \uc8fc\uba74 \uac01\uac01 \ub4a4\ub85c \uac00\uae30, \uc55e\uc73c\ub85c \uac00\uae30 \ubc84\ud2bc\uc774 \ud65c\uc131\ud654 \ub418\ub3c4\ub85d \ub9cc\ub4e4\uc5c8\ub2e4.<br>\ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c \uc2e4\uc81c\ub85c \uc0ac\uc6a9\ub418\uc9c4 \uc54a\uc558\ub2e4.<br>&nbsp;<\/p><blockquote data-ke-style=\"style2\">ui\/Input.tsx<\/blockquote><pre data-ke-type=\"codeblock\" class=\"javascript\" data-ke-language=\"javascript\"><code>import { css } from \"@emotion\/css\";\nimport { DARKMODE, PRIMARY } from \"..\/styles\/theme\";\nimport useTheme from \"..\/store\/themeStore\";\n\nconst inputBaseStyle = `\n&nbsp;&nbsp;border: 1px solid;\n&nbsp;&nbsp;padding: 0.6rem 1rem;\n&nbsp;&nbsp;width: 100%;\n&nbsp;&nbsp;max-width: 400px;\n&nbsp;&nbsp;min-width: 160px;\n&nbsp;&nbsp;box-sizing: border-box;\n&nbsp;&nbsp;border-radius: 5px;\n`;\n\nconst primaryStyle = css`\n&nbsp;&nbsp;${inputBaseStyle};\n&nbsp;&nbsp;background-color: ${PRIMARY.inputBackground};\n&nbsp;&nbsp;color: ${PRIMARY.inputText};\n&nbsp;&nbsp;border-color: ${PRIMARY.inputBorder};\n`;\n\nconst darkStyle = css`\n&nbsp;&nbsp;${inputBaseStyle};\n&nbsp;&nbsp;background-color: ${DARKMODE.inputBackground};\n&nbsp;&nbsp;color: ${DARKMODE.inputText};\n&nbsp;&nbsp;border-color: ${DARKMODE.inputBorder};\n`;\n\ninterface InputProps extends React.InputHTMLAttributes&lt;HTMLInputElement&gt;{\n&nbsp;&nbsp;ref?: React.Ref&lt;HTMLInputElement&gt;;\n}\nconst Input = (props: InputProps) =&gt; {\n&nbsp;&nbsp;const { theme } = useTheme();\n&nbsp;&nbsp;const { ref: inputRef, className, ...rest } = props;\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;input\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;className={theme === 'primary' ? primaryStyle : darkStyle}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref={inputRef}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{...rest}\n&nbsp;&nbsp;&nbsp;&nbsp;&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/input&gt;\n&nbsp;&nbsp;);\n};\n\nexport default Input;<\/code><\/pre><blockquote data-ke-style=\"style2\">ui\/TouchableOpacity.tsx<\/blockquote><pre data-ke-type=\"codeblock\" class=\"javascript\" data-ke-language=\"javascript\"><code>import { css } from \"@emotion\/css\";\nimport type React from \"react\";\n\nconst touchableStyle = css`\n&nbsp;&nbsp;background-color: transparent;\n&nbsp;&nbsp;border: none;\n&nbsp;&nbsp;color: inherit;\n`;\n\ninterface TouchableOpacityProps extends React.ButtonHTMLAttributes&lt;HTMLButtonElement&gt; {\n&nbsp;&nbsp;readonly children: React.ReactNode;\n}\nconst TouchableOpacity = (props: TouchableOpacityProps) =&gt; {\n&nbsp;&nbsp;const { children, ...rest} = props;\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;button className={touchableStyle} {...rest}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{children}\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/button&gt;\n&nbsp;&nbsp;);\n};\n\nexport default TouchableOpacity;<\/code><\/pre><p data-ke-size=\"size16\">TouchableOpacity\ub294 React Native\uc5d0\uc11c \uc601\uac10\uc744 \uc5bb\uc5b4\uc11c \uad6c\ud604\ud588\ub2e4.<br>&nbsp;<br>\ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c \uc0ac\uc6a9\ud55c \uc544\uc774\ucf58 \ubc84\ud2bc\uac19\uc740 \uacbd\uc6b0 \ubcc4\ub3c4\uc758 \ub514\uc790\uc778 \uc2dc\uc2a4\ud15c \uc5c6\uc774 \ubd80\ubaa8 \uc694\uc18c\ub97c \ub530\ub77c\uac00\uae30\ub9cc \ud558\uba74 \ub418\uae30\uc5d0 \uc774\ub97c \uc9c1\uc811 \uad6c\ud604\ud558\uc600\ub2e4.<br>&nbsp;<br>\uc704\uc758 \uad6c\uc870\ub300\ub85c \uad6c\ud604\ud55c \ud6c4 \ubaa8\ub4dc \ud1a0\uae00 \ubc84\ud2bc\uc744 \uac04\ub2e8\ud558\uac8c \uad6c\ud604\ud558\uc600\ub2e4.<br>&nbsp;<\/p><blockquote data-ke-style=\"style2\">components\/ThemeToggleBtn.tsx<\/blockquote><pre data-ke-type=\"codeblock\" class=\"javascript\" data-ke-language=\"javascript\"><code>import TouchableOpacity from \"..\/ui\/TouchableOpacity\";\nimport { CiLight } from \"react-icons\/ci\";\nimport { CiDark } from \"react-icons\/ci\";\nimport useTheme from \"..\/store\/themeStore\";\n\nconst ThemeToggleBtn = () =&gt; {\n&nbsp;&nbsp;const { theme, toggleTheme } = useTheme();\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;TouchableOpacity onClick={toggleTheme}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{theme === 'primary' ? &lt;CiDark size={25} \/&gt; : &lt;CiLight color=\"orange\" size={25}\/&gt;}\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/TouchableOpacity&gt;\n&nbsp;&nbsp;)\n};\n\nexport default ThemeToggleBtn;<\/code><\/pre><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\uae30\ub2a5 \uad6c\ud604<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">\uc0c1\ud0dc \uad00\ub9ac\uac00 \uaf64\ub098 \ubcf5\uc7a1\ud558\ubbc0\ub85c <b>useReducer \ud6c5\uc744 \uc0ac\uc6a9<\/b>\ud558\uc600\ub2e4.<\/p><blockquote data-ke-style=\"style2\">components\/TodoList.tsx<\/blockquote><pre data-ke-type=\"codeblock\" class=\"javascript\" data-ke-language=\"javascript\"><code>import { useCallback, useReducer } from \"react\";\nimport Header from \"..\/ui\/Header\";\nimport TodoListContainer from \".\/TodoListContainer\";\nimport TodoWriter from \".\/TodoWriter\";\nimport type { Todo } from \"..\/types\/todolist\";\n\nconst ActionKind ={\n&nbsp;&nbsp;ADD_TODO : 'ADD_TODO',\n&nbsp;&nbsp;EDIT_TODO : 'EDIT_TODO',\n&nbsp;&nbsp;COMPLETE_TODO : 'COMPLETE_TODO',\n&nbsp;&nbsp;DELETE_TODO : 'DELETE_TODO',\n} as const;\n\ntype ActionType =\n&nbsp;&nbsp;| { type: typeof ActionKind.ADD_TODO; payload: Todo }\n&nbsp;&nbsp;| { type: typeof ActionKind.EDIT_TODO; payload: { id: string; task: string, isEdit: boolean } }\n&nbsp;&nbsp;| { type: typeof ActionKind.COMPLETE_TODO; payload: { id: string } }\n&nbsp;&nbsp;| { type: typeof ActionKind.DELETE_TODO; payload: { id: string } };\n\nconst INITAL_STATE: Todo[] = [];\n\nfunction reducer(state: Todo[], action: ActionType): Todo[] {\n&nbsp;&nbsp;switch (action.type) {\n&nbsp;&nbsp;&nbsp;&nbsp;case ActionKind.ADD_TODO:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return [ ...state, action.payload];\n&nbsp;&nbsp;&nbsp;&nbsp;case ActionKind.EDIT_TODO:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!action.payload.isEdit) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return state.map((item) =&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.id === action.payload.id ? { ...item, isEdit: !action.payload.isEdit } : item\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return state.map((item) =&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.id === action.payload.id ? { ...item, task: action.payload.task, isEdit: !action.payload.isEdit } : item\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;case ActionKind.DELETE_TODO:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return state.filter((item) =&gt; item.id !== action.payload.id);\n&nbsp;&nbsp;&nbsp;&nbsp;case ActionKind.COMPLETE_TODO:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return state.map((item) =&gt; \n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.id === action.payload.id ? {...item, isCompleted: !item.isCompleted} : item\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)\n&nbsp;&nbsp;&nbsp;&nbsp;default: return state;\n&nbsp;&nbsp;}\n}\nconst TodoList = () =&gt; {\n&nbsp;&nbsp;const [todo, dispatch] = useReducer(reducer, INITAL_STATE);\n\n&nbsp;&nbsp;const noTaskAlert = useCallback(() =&gt; {\n&nbsp;&nbsp;&nbsp;&nbsp;alert(\"\ud560 \uc77c\uc744 \uc785\ub825\ud558\uc138\uc694\");\n&nbsp;&nbsp;},[])\n&nbsp;&nbsp;\n&nbsp;&nbsp;const addTodo = useCallback((task: string) =&gt; {\n&nbsp;&nbsp;&nbsp;&nbsp;if (!task) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;noTaskAlert();\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;\n&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;const params: Todo = {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id: Date.now().toString(),\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isCompleted: false,\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;task: task,\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isEdit: false,\n&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;dispatch({ type: ActionKind.ADD_TODO, payload: params });\n&nbsp;&nbsp;}, []);\n&nbsp;&nbsp;\n&nbsp;&nbsp;const completeTodo = useCallback((id: string) =&gt; {\n&nbsp;&nbsp;&nbsp;&nbsp;dispatch({ type: ActionKind.COMPLETE_TODO, payload: {id} });\n&nbsp;&nbsp;}, []);\n&nbsp;&nbsp;\n&nbsp;&nbsp;const editTodo = useCallback((id: string, newTask: string, isEdit: boolean) =&gt; {\n&nbsp;&nbsp;&nbsp;&nbsp;if (!newTask) {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;noTaskAlert();\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;\n&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;dispatch({ type: ActionKind.EDIT_TODO, payload: { id, task: newTask, isEdit: isEdit } });\n&nbsp;&nbsp;}, []);\n\n&nbsp;&nbsp;const deleteTodo = useCallback((id: string) =&gt; {\n&nbsp;&nbsp;&nbsp;&nbsp;dispatch({ type: ActionKind.DELETE_TODO, payload: {id} });\n&nbsp;&nbsp;},[]);\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Header title=\"TODO LIST\"\/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;TodoWriter addTodo={addTodo} \/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;TodoListContainer\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;todo={todo}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;completeTodo={completeTodo}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;editTodo={editTodo}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deleteTodo={deleteTodo}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/&gt;\n&nbsp;&nbsp;);\n};\n\nexport default TodoList;<\/code><\/pre><p data-ke-size=\"size16\">TodoList\uc640 \uad00\ub828\ub41c \uc0c1\ud0dc, \ud568\uc218\ub97c \uad00\ub9ac\ud558\ub294 \ucef4\ud3ec\ub10c\ud2b8\uc774\ub2e4.<br>&nbsp;<br>props\ub85c \ub118\uaca8\uc8fc\ub294 \ud568\uc218\ub294 rerendering\uc2dc \uc7ac\uc0dd\uc131\ub420 \ud544\uc694\uac00 \uc5c6\ub2e4.<br>&nbsp;<br>\ub54c\ubb38\uc5d0 \ubaa8\ub450 \uba54\ubaa8\uc774\uc81c\uc774\uc158\ud558\uc600\ub2e4.<br>&nbsp;<br>ActionType\uc5d0\uc11c \uc880 \uc560\ub97c \uba39\uc5c8\ub2e4.<br>&nbsp;<br>useReducer\ub97c \ub9ce\uc774 \uc0ac\uc6a9\ud574\ubcf4\uc9c0 \uc54a\uc544\uc11c \uc775\uc219\ud558\uc9c0 \uc54a\uc558\uace0, type\ub9c8\ub2e4 \ub2e4\ub978 \ub9e4\uac1c\ubcc0\uc218\uac00 \ud544\uc694\ud588\ub294\ub370 \uc774\ub97c \uad6c\ud604\ud574 \ubcf8\uc801\uc774 \uc5c6\uc5b4\uc11c \uc880 \ud5e4\uba68\ub2e4.<br>&nbsp;<\/p><blockquote data-ke-style=\"style2\">components\/TodoWriter.tsx<\/blockquote><pre data-ke-type=\"codeblock\" class=\"javascript\" data-ke-language=\"javascript\"><code>import { css } from \"@emotion\/css\";\nimport ThemeToggleBtn from \".\/ThemeToggleBtn\";\nimport Input from \"..\/ui\/Input\";\nimport Button from \"..\/ui\/Button\";\nimport { useState } from \"react\";\nconst writeArea = css`\n&nbsp;&nbsp;display: flex;\n&nbsp;&nbsp;flex-direction: row;\n&nbsp;&nbsp;gap: 15px;\n&nbsp;&nbsp;justify-content: center;\n&nbsp;&nbsp;margin-top: 20px;\n&nbsp;&nbsp;padding: 10px;\n`;\ninterface TodoWriterprops{\n&nbsp;&nbsp;addTodo: (task: string) =&gt; void;\n}\nconst TodoWriter = ({ addTodo }: TodoWriterprops) =&gt; {\n&nbsp;&nbsp;const [task, setTask] = useState&lt;string&gt;('');\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;div className={writeArea}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ThemeToggleBtn \/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Input\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;placeholder=\"\ud560 \uc77c\uc744 \uc791\uc131\ud558\uc138\uc694\"\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value={task}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;onChange={(e)=&gt;setTask(e.target.value)}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxLength={30} \/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Button onClick={() =&gt; { addTodo(task); setTask(''); }}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ADD\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/Button&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/div&gt;\n&nbsp;&nbsp;);\n};\n\nexport default TodoWriter;<\/code><\/pre><p data-ke-size=\"size16\">TodoList\uc5d0 task\ub97c \ucd94\uac00\ud558\ub294 \ucef4\ud3ec\ub10c\ud2b8\uc774\ub2e4.<br>&nbsp;<br>Input\uc5d0 \uc785\ub825\ud55c task\ub97c props\ub85c \ubc1b\uc740 addTodo \ud568\uc218\uc758 \ub9e4\uac1c\ubcc0\uc218\ub85c \ub118\uaca8\uc900\ub2e4.<br>&nbsp;<\/p><blockquote data-ke-style=\"style2\">components\/TodoListContainer.tsx<\/blockquote><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>import { css } from \"@emotion\/css\";\nimport type { Todo } from \"..\/types\/todolist\";\nimport TodoListItem from \".\/TodoListItem\";\n\nconst listContainerStyle = css`\n&nbsp;&nbsp;display: flex;\n&nbsp;&nbsp;flex-direction: column;\n&nbsp;&nbsp;gap: 15px;\n&nbsp;&nbsp;justify-content: center;\n&nbsp;&nbsp;max-width: 700px;\n&nbsp;&nbsp;margin: 20px auto;\n&nbsp;&nbsp;padding: 0px 20px;\n`;\ninterface TodoListContainerProps{\n&nbsp;&nbsp;todo: Todo[];\n&nbsp;&nbsp;completeTodo: (id: string) =&gt; void;\n&nbsp;&nbsp;editTodo: (id: string, newTask: string, isEdit: boolean) =&gt; void;\n&nbsp;&nbsp;deleteTodo: (id: string) =&gt; void;\n}\nconst TodoListContainer = (props: TodoListContainerProps) =&gt; {\n&nbsp;&nbsp;const { todo, completeTodo, editTodo, deleteTodo } = props;\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;div className={listContainerStyle}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{todo &amp;&amp; todo.map((item) =&gt; (\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;TodoListItem todo={item} key={item.id} completeTodo={completeTodo} editTodo={editTodo} deleteTodo={deleteTodo}\/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;))}\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/div&gt;\n&nbsp;&nbsp;);\n};\n\nexport default TodoListContainer;<\/code><\/pre><p data-ke-size=\"size16\">\uc55e\uc11c \uad6c\ud604\ud55c Card \ucef4\ud3ec\ub10c\ud2b8\ub294 \ubd80\ubaa8 \uc694\uc18c\uc758 \ub808\uc774\uc544\uc6c3\uc5d0 \uc601\ud5a5\uc744 \ubc1b\ub294\ub2e4.<br>&nbsp;<br>\ub54c\ubb38\uc5d0 task\ub4e4\uc774 \ub80c\ub354\ub9c1\ub418\uae30 \uc704\ud55c \ub808\uc774\uc544\uc6c3\uc744 \uc7a1\uc544\uc8fc\ub294 \uc5ed\ud560\uc744 \ud55c\ub2e4.<br>&nbsp;<\/p><blockquote data-ke-style=\"style2\">components\/TodoListItem.tsx<\/blockquote><pre data-ke-type=\"codeblock\" class=\"typescript\" data-ke-language=\"typescript\"><code>import { MdCheckBoxOutlineBlank, MdDelete, MdEdit, MdOutlineCheckBox, MdCheck } from \"react-icons\/md\";\nimport Card from \"..\/ui\/Card\";\nimport type { Todo } from \"..\/types\/todolist\";\nimport TouchableOpacity from \"..\/ui\/TouchableOpacity\";\nimport { memo, useState } from \"react\";\nimport Input from \"..\/ui\/Input\";\n\ninterface TodoListItemProps{\n&nbsp;&nbsp;todo: Todo;\n&nbsp;&nbsp;completeTodo: (id: string) =&gt; void;\n&nbsp;&nbsp;editTodo: (id: string, newTask: string, isEdit: boolean) =&gt; void;\n&nbsp;&nbsp;deleteTodo: (id: string) =&gt; void;\n}\nconst ICON_SIZE = 20;\nconst TodoListItem = (props: TodoListItemProps) =&gt; {\n&nbsp;&nbsp;const { todo, completeTodo, editTodo, deleteTodo } = props;\n&nbsp;&nbsp;const { id, isCompleted, isEdit, task } = todo;\n&nbsp;&nbsp;const [editText, setEditText] = useState&lt;string&gt;(task);\n&nbsp;&nbsp;return (\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;Card&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;TouchableOpacity onClick={()=&gt;completeTodo(id)}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{!isCompleted ? &lt;MdCheckBoxOutlineBlank size={ICON_SIZE} \/&gt; : &lt;MdOutlineCheckBox size={ICON_SIZE} \/&gt;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/TouchableOpacity&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{!isEdit ?\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span&gt;{todo.task}&lt;\/span&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Input\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value={editText}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;onChange={(e) =&gt; setEditText(e.target.value)}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;autoFocus\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;placeholder=\"\uc218\uc815\ud558\uc138\uc694\"\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;div&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;TouchableOpacity onClick={()=&gt;editTodo(id, editText, isEdit)}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{!isEdit ?\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MdEdit size={ICON_SIZE} \/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MdCheck size={ICON_SIZE}\/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/TouchableOpacity&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;TouchableOpacity onClick={()=&gt;deleteTodo(id)}&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;MdDelete size={ICON_SIZE} \/&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/TouchableOpacity&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/div&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;\/Card&gt;\n&nbsp;&nbsp;);\n};\n\nexport default memo(\n&nbsp;&nbsp;TodoListItem,\n&nbsp;&nbsp;(prevProps: TodoListItemProps, nextProps: TodoListItemProps) =&gt; prevProps.todo === nextProps.todo);<\/code><\/pre><p data-ke-size=\"size16\">props\ub85c \ubc1b\uc740 todo\uc5d0 \ub530\ub77c \uc870\uac74\ubd80 \ub80c\ub354\ub9c1\uc744 \uc218\ud589\ud558\ub294 \ucef4\ud3ec\ub10c\ud2b8\uc774\ub2e4.<br>&nbsp;<br>task \uc218\uc815\ub3c4 \uc5ec\uae30\uc11c \uc218\ud589\ud55c\ub2e4.<br>&nbsp;<br>task \uc218\uc815\uc744 \ub9e1\ub294 \ucef4\ud3ec\ub10c\ud2b8\ub294 \ub530\ub85c \ubd84\ub9ac\ub97c \ud560\uae4c \uace0\ubbfc\ud588\ub294\ub370 \uc131\ub2a5\uc0c1 \ud070 \ubb38\uc81c\uac00 \uc788\uc744\uae4c..? \uc2f6\uc5b4\uc11c \uadf8\ub0e5 \uc548\ub098\ub234\ub2e4. <s><span style=\"color: #9D9D9D;\">\uadc0\ucc2e\uc558\ub2e4.<\/span><\/s><br>&nbsp;<br><span style=\"color: #000000;\">props\ub85c \ubc1b\uc740 todo\uc758 \uba54\ubaa8\ub9ac \uc8fc\uc18c\uac00 \ubcc0\ud558\uc9c0 \uc54a\uc73c\uba74 rerendering \ub418\uc9c0 \uc54a\ub3c4\ub85d \uba54\ubaa8\uc774\uc81c\uc774\uc158 \ud558\uc600\ub2e4.<\/span><\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\uacb0\uacfc<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"400\" data-origin-height=\"215\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/bwPxkI\/dJMcabJljrg\/MALzevDi9ngfZY0XlpLoJ0\/img.gif\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/bwPxkI\/dJMcabJljrg\/MALzevDi9ngfZY0XlpLoJ0\/img.gif\" data-alt=\"\uc644\uc131\ud488\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/bwPxkI\/dJMcabJljrg\/MALzevDi9ngfZY0XlpLoJ0\/img.gif\" srcset=\"https:\/\/blog.kakaocdn.net\/dn\/bwPxkI\/dJMcabJljrg\/MALzevDi9ngfZY0XlpLoJ0\/img.gif\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"400\" height=\"215\" data-origin-width=\"400\" data-origin-height=\"215\"\/><\/span><figcaption>\uc644\uc131\ud488<\/figcaption>\n<\/figure>\n<p data-ke-size=\"size16\">\ucd5c\uc885\uc801\uc73c\ub85c \uc644\uc131\ud55c \uacb0\uacfc\ubb3c\uc774\ub2e4.<br>&nbsp;<br>\ub514\uc790\uc778\uc740 \ud22c\ubc15\ud558\uc9c0\ub9cc \ub098\ub984 \uc7a5\uc778 \uc815\uc2e0\uc73c\ub85c \ub9cc\ub4e4\uc5c8\ub2e4. <s><span style=\"color: #9D9D9D;\">\ucf54\ub4dc\uc5d0 \ube44\ud574 \uadf8\ub807\uc9c0 \ubabb\ud55c \uacb0\uacfc\ubb3c<\/span><\/s><\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\ud6c4\uae30<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">AI\uc5c6\uc774 \uad6c\ud604\ud558\uba74\uc11c \ubaa8\ub974\ub294 \uac83\ub4e4\uc744 \uc9c1\uc811 \uac80\uc0c9\ud574\uac00\uba70 \ucc3e\uc558\ub294\ub370 \uc2dc\uac04\uc774 2022\ub144\uc5d0\uc11c \uba48\ucd98 \ub4ef\ud55c \ub290\ub08c\uc774 \ub4e4\uc5c8\ub2e4.<br>&nbsp;<br>\ub300\ubd80\ubd84\uc758 \uac80\uc0c9 \uacb0\uacfc\uac00 2021~2022\ub144\uc5d0 \uba38\ubb3c\ub7ec \uc788\uc5c8\uae30 \ub54c\ubb38\uc774\ub2e4.<br>&nbsp;<br>AI\uac00 \uc8fc\ub294 \ucf54\ub4dc\ub3c4 legacy\uc9c0\ub9cc \uac80\uc0c9 \uc5d4\uc9c4\uc740 \uadf8\ubcf4\ub2e4 \ub354\ud55c legacy\uc774\ub2e4.<br>&nbsp;<br>\ud655\uc2e4\ud788 \uc2dc\ub300\uac00 \ub9ce\uc774 \ubcc0\ud588\uc74c\uc744 \ub290\ub080\ub2e4.<br>&nbsp;<br>\ud558\uc9c0\ub9cc AI \uc5c6\uc774 \uc790\uc5f0\uc2a4\ub7fd\uac8c \uc0bd\uc9c8\ud558\ub294\uac8c \uac1c\ubc1c \uc18d\ub3c4\ub294 \ub354\ub514\ub354\ub77c\ub3c4 \uba38\ub9ac\uc18d\uc5d0 \ub354 \ub9ce\uc774 \ub0a8\ub294 \uac83 \uac19\ub2e4.<br>&nbsp;<br>\uc5ed\uc2dc \uac1c\ubc1c\uc790\ub294 \uac16\uac00\uc9c0 \uc81c\uc57d\uacfc \uc0bd\uc9c8\uc774 \uc131\uc7a5\uc758 \uc9c0\ub984\uae38\uc778 \uac83 \uac19\ub2e4.<br><br>\uadf8\ub9ac\uace0 \ub09c \uc544\uc9c1 \uac08\uae38\uc774 \uba3c \uac83 \uac19\ub2e4. AI \uc5c6\uc774 \uac1c\ubc1c\ud558\ub824\ub2c8 Todo List \ub108\ubb34 \uc5b4\ub835\ub2e4.<br>&nbsp;<br>\ud558\uc9c0\ub9cc \uc5b4\ub835\ub354\ub77c\ub3c4 \ubc14\uc774\ube0c\ucf54\ub354\uac00 \ub418\uace0 \uc2f6\uc9c4 \uc54a\ub2e4.<br>&nbsp;<br>\ub2e4\uc74c \uc131\uc7a5 \ubaa9\ud45c\ub294 \uac80\uc0c9\ub3c4 \uc81c\ud55c\ud55c \ud6c4 \ud504\ub85c\uc81d\ud2b8 \uad6c\ud604\ud558\uae30\uc774\ub2e4.<br>&nbsp;<br>\uc694\uc998\ub4e4\uc5b4 \ubb54\uac00 \ub9cc\ub4e4\uace0 \uc2f6\ub2e4\ub294 \uc0dd\uac01\uc774 \uba38\ub9ac\uc18d\uc5d0 \uac00\ub4dd\ud55c\ub370 \ucde8\uc5c5\uc774 \ube60\ub978 \uc2dc\uc77c \ub0b4\uc5d0 \ub420 \uac83 \uac19\uc9c0 \uc54a\uc544\uc11c \uc7ac\ubc0c\ub294 \uc8fc\uc81c\ub97c \ud558\ub098 \uc0dd\uac01\ud574\ub0b8 \ud6c4 \uc0ac\uc774\ub4dc \ud504\ub85c\uc81d\ud2b8\ub97c \uc9c4\ud589\ud574 \ubcf4\ub824 \ud55c\ub2e4.<\/p>","category":["\uc774\uc57c\uae30\/\ud68c\uace0","React"],"author":"MaKa_","guid":"https:\/\/mk-develop.tistory.com\/60","comments":"https:\/\/mk-develop.tistory.com\/entry\/AI-%EC%97%86%EC%9D%B4-%ED%88%AC%EB%91%90%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EA%B5%AC%ED%98%84%EA%B8%B0#entry60comment","pubDate":"Mon, 17 Nov 2025 00:52:49 +0900"},{"title":"[React] useEffectEvent \ud6c5","link":"https:\/\/mk-develop.tistory.com\/entry\/React-useEffectEvent-%ED%9B%85","description":"<h3 data-ke-size=\"size23\">\uac1c\uc694<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">React \uacf5\uc2dd \ubb38\uc11c\ub97c \uc0b4\ud3b4\ubcf4\ub2e4\uac00, 19\ubc84\uc804\uc5d0\uc11c useEffectEvent \ud6c5\uc774 \uc2e4\ud5d8 \ub2e8\uacc4(Experimental)\uc5d0\uc11c \uc815\uc2dd \ud6c5\uc73c\ub85c \ubcc0\uacbd\ub41c \uac83\uc744 \ubcf4\uace0 \ub354 \uc790\uc138\ud788 \uc54c\uc544\ubcf4\uae30 \uc704\ud574 \uacf5\ubd80\ud574\ubcf4\uc558\ub2e4.<\/p>\n<p data-ke-size=\"size16\"><a href=\"https:\/\/ko.react.dev\/reference\/react\/useEffectEvent\" target=\"_blank\" rel=\"noopener&nbsp;noreferrer\">https:\/\/ko.react.dev\/reference\/react\/useEffectEvent<\/a><\/p>\n<figure id=\"og_1762863821349\" contenteditable=\"false\" data-ke-type=\"opengraph\" data-ke-align=\"alignCenter\" data-og-type=\"website\" data-og-title=\"useEffectEvent &ndash; React\" data-og-description=\"The library for web and native user interfaces\" data-og-host=\"ko.react.dev\" data-og-source-url=\"https:\/\/ko.react.dev\/reference\/react\/useEffectEvent\" data-og-url=\"https:\/\/ko.react.dev\/reference\/react\/useEffectEvent\" data-og-image=\"https:\/\/scrap.kakaocdn.net\/dn\/jTSlu\/hyZNlJ1hhB\/8uf3dwdil90vyGP4zfALvK\/img.png?width=1080&amp;height=567&amp;face=0_0_1080_567,https:\/\/scrap.kakaocdn.net\/dn\/bzskiv\/hyZMGuoinl\/FkiLGdQjkGDe7EuwanV0H1\/img.png?width=1080&amp;height=567&amp;face=0_0_1080_567\"><a href=\"https:\/\/ko.react.dev\/reference\/react\/useEffectEvent\" target=\"_blank\" rel=\"noopener\" data-source-url=\"https:\/\/ko.react.dev\/reference\/react\/useEffectEvent\">\n<div class=\"og-image\" style=\"background-image: url('https:\/\/scrap.kakaocdn.net\/dn\/jTSlu\/hyZNlJ1hhB\/8uf3dwdil90vyGP4zfALvK\/img.png?width=1080&amp;height=567&amp;face=0_0_1080_567,https:\/\/scrap.kakaocdn.net\/dn\/bzskiv\/hyZMGuoinl\/FkiLGdQjkGDe7EuwanV0H1\/img.png?width=1080&amp;height=567&amp;face=0_0_1080_567');\">&nbsp;<\/div>\n<div class=\"og-text\">\n<p class=\"og-title\" data-ke-size=\"size16\">useEffectEvent &ndash; React<\/p>\n<p class=\"og-desc\" data-ke-size=\"size16\">The library for web and native user interfaces<\/p>\n<p class=\"og-host\" data-ke-size=\"size16\">ko.react.dev<\/p>\n<\/div>\n<\/a><\/figure>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<h3 data-ke-size=\"size23\">\uc65c \ub9cc\ub4e4\uc5b4\uc9c4 \ud6c5\uc778\uac00?<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc774\ubca4\ud2b8 \ud578\ub4e4\ub7ec\ub97c useEffect \ud6c5\uc744 \uc0ac\uc6a9\ud574\uc11c \ub4f1\ub85d\ud55c\ub2e4\uba74 \ub2e4\uc74c\uacfc \uac19\uc774 \uc791\uc131\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre id=\"code_1762864096599\" class=\"javascript\" data-ke-language=\"javascript\" data-ke-type=\"codeblock\"><code>function MyComponent() {\n  const [count, setCount] = useState(0);\n\n  useEffect(() =&gt; {\n    function onClick() {\n      console.log(count); \/\/ \ud56d\uc0c1 0\ub9cc \ucd9c\ub825\ub428\n    }\n    window.addEventListener('click', onClick);\n    return () =&gt; window.removeEventListener('click', onClick);\n  }, []); \/\/ \uc758\uc874\uc131\uc774 \uc5c6\uae30 \ub54c\ubb38\n\n  return &lt;button onClick={() =&gt; setCount((c) =&gt; c + 1)}&gt;\uc99d\uac00&lt;\/button&gt;;\n}<\/code><\/pre>\n<p data-ke-size=\"size16\">\uc704 \ucf54\ub4dc\ub294 \ubb38\uc81c\uac00 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">onClick \uc774\ubca4\ud2b8\ub97c \uc218\ud589\ud558\uba74 count\ub97c \ucd9c\ub825\ud558\uc9c0\ub9cc \ud074\ub9ad\ud560 \ub54c \ub9c8\ub2e4 1\uc529 \uc99d\uac00\ud558\ub294\uac8c \uc544\ub2cc 0\ub9cc \ucd9c\ub825\ub41c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc758\uc874\uc131 \ubc30\uc5f4\uc5d0 \uc544\ubb34\uac83\ub3c4 \ub4e4\uc5b4\uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">onClick \ud568\uc218\uac00 \uae30\uc5b5\ud558\ub294 count\uc758 \uac12\uc740 \ud56d\uc0c1 0\uc778 <b>stale closure \ubb38\uc81c\uac00 \ubc1c\uc0dd<\/b>\ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc774\ub294 \ubcf4\ud1b5 \uc544\ub798\uc640 \uac19\uc774 \ud574\uacb0\ud560 \uc218 \uc788\ub2e4.<\/p>\n<pre id=\"code_1762864362400\" class=\"javascript\" data-ke-language=\"javascript\" data-ke-type=\"codeblock\"><code>useEffect(() =&gt; {\n  function onClick() {\n    console.log(count);\n  }\n  window.addEventListener('click', onClick);\n  return () =&gt; window.removeEventListener('click', onClick);\n}, [count]);<\/code><\/pre>\n<p data-ke-size=\"size16\">\uc774\ub807\uac8c\ub9cc \ud574\ub3c4 \ubb38\uc81c\ub294 \uc5c6\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ud558\uc9c0\ub9cc \uc774 \ucf54\ub4dc \ub54c\ubb38\uc5d0 \ucef4\ud3ec\ub10c\ud2b8\uac00 \ub80c\ub354\ub9c1 \ub420 \ub54c \ub9c8\ub2e4 \ub9e4\ubc88 eventListener\uac00 \ub4f1\ub85d\ub418\uc5c8\ub2e4\uac00 \uc0ad\uc81c\ub41c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc65c\ub0d0\ud558\uba74 useEffect\ub294 ComponentDidMount, ComponentDidUpdate, ComponentWillUnmount \uc774 3\uac1c\uc758 \uc0dd\uba85\uc8fc\uae30\ub97c \ub300\uccb4\ud558\ub294 \ud6c5\uc774\uae30 \ub54c\ubb38\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\ub2f9\uc7a5\uc758 count \ud558\ub098\ub9cc \uc758\uc874\uc131\uc73c\ub85c \uad00\ub9ac\ud55c\ub2e4\uba74 \uadf8\ub807\uac8c \ud070 \ubb38\uc81c\ub294 \uc77c\uc5b4\ub098\uc9c0 \uc54a\uc744 \uc218 \uc788\uc9c0\ub9cc \uc544\ub798\uc640 \uac19\uc740 \uc774\ubca4\ud2b8\ub77c\uba74?<\/p>\n<pre id=\"code_1762864671611\" class=\"javascript\" data-ke-language=\"javascript\" data-ke-type=\"codeblock\"><code>function CanvasEditor({ scale, tool, user, color }) {\n  const [x, setX] = useState(0);\n  const [y, setY] = useState(0);\n  const [dragging, setDragging] = useState(false);\n\n  useEffect(() =&gt; {\n    function onMouseMove(e) {\n      if (!dragging) return;\n      console.log(\n        'x:', x,\n        'y:', y,\n        'scale:', scale,\n        'tool:', tool,\n        'user:', user.name,\n        'color:', color\n      );\n    }\n\n    window.addEventListener('mousemove', onMouseMove);\n    return () =&gt; window.removeEventListener('mousemove', onMouseMove);\n\n  \/\/ dependency explosion\n  }, [x, y, dragging, scale, tool, user, color]);\n}<\/code><\/pre>\n<p data-ke-size=\"size16\">x, y, dragging, scale, tool \ub4f1 \ub9ce\uc740 \ubcc0\uc218\ub4e4\uc774 \uc758\uc874\uc131 \ubc30\uc5f4\uc5d0 \ub4e4\uc5b4\uac00\uc788\uace0 \uc774 \uc911 \ud558\ub098\ub77c\ub3c4 \ubcc0\uacbd\ub418\uba74 \uc0dd\uba85\uc8fc\uae30\ub97c \ub2e4\uc2dc \uc218\ud589\ud558\uac8c \ub418\uba74\uc11c \ub9ac\uc2a4\ub108\uac00 \ub9e4\ubc88 \ub4f1\ub85d&amp;\ud574\uc81c \ub420 \uac83\uc774\ub2e4.<\/p>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">useEffectEvent<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc704\uc640\uac19\uc740 \ubb38\uc81c\ub97c \ud574\uacb0\ud558\uae30 \uc704\ud574 \ub098\uc628 \ud6c5\uc774 useEffectEvent\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">useEffectEvent \ud6c5\uc758 \ubaa9\uc801\uc740 <b>\ud56d\uc0c1 \ucd5c\uc2e0 \uac12\uc5d0 \uc811\uadfc\ud560 \uc218 \uc788\ub294 \uc548\uc815\uc801\uc778 \ucf5c\ubc31<\/b> \uc774\ub2e4.<\/p>\n<pre id=\"code_1762864906518\" class=\"javascript\" data-ke-language=\"javascript\" data-ke-type=\"codeblock\"><code>const onSomething = useEffectEvent(callback)<\/code><\/pre>\n<p data-ke-size=\"size16\">&nbsp;\uc0ac\uc6a9 \ubc29\ubc95\uc740 \uac04\ub2e8\ud558\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">useEffectEvent \ud6c5\uc758 \ub9e4\uac1c\ubcc0\uc218\ub85c callback \ud568\uc218\ub97c \ub118\uaca8\uc8fc\uae30\ub9cc \ud558\uba74 \ub41c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ubc18\ud658\uac12\uc740 <b>Effect Event Function<\/b>\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">Effect Event Function\uc744 \ubc18\ud658\ud558\uae30 \ub54c\ubb38\uc5d0 useEffect, useLayoutEffect, useInsertionEffect \ud6c5\uc758 \ub0b4\ubd80\uc5d0\uc11c \ud638\ucd9c\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc0ac\uc6a9 \uc608\uc2dc\ub294 \uc544\ub798\uc640 \uac19\ub2e4.<\/p>\n<pre id=\"code_1762864955345\" class=\"javascript\" data-ke-language=\"javascript\" data-ke-type=\"codeblock\"><code>import { useEffectEvent } from 'react';\n\nfunction MyComponent() {\n  const [count, setCount] = useState(0);\n\n  const handleClick = useEffectEvent(() =&gt; {\n    console.log(count); \/\/ \ud56d\uc0c1 \ucd5c\uc2e0 count \ucd9c\ub825\n  });\n\n  useEffect(() =&gt; {\n    window.addEventListener('click', handleClick);\n    return () =&gt; window.removeEventListener('click', handleClick);\n  }, []); \/\/ \uc758\uc874\uc131 \ubc30\uc5f4 \uc5c6\uc5b4\ub3c4\ub428\n}<\/code><\/pre>\n<p data-ke-size=\"size16\">count\uac00 \ubcc0\uacbd\ub420 \ub54c \ub9c8\ub2e4 \ub9ac\uc2a4\ub108\uac00 \ub9e4\ubc88 \ub4f1\ub85d&amp;\uc0ad\uc81c\ub418\ub294 \ubb38\uc81c\uac00 \ud574\uacb0\ub418\uace0 handleclick \ud568\uc218\ub294 \ud56d\uc0c1 \ucd5c\uc2e0 count\uac12\uc744 \ucc38\uc870\ud560 \uc218 \uc788\uac8c \ub418\uc5c8\ub2e4.<\/p>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">\uc8fc\uc758\uc0ac\ud56d<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\"><span style=\"color: #ee2323;\">useEffectEvent\ub85c \ub9cc\ub4e0 \ud568\uc218\ub294 \ubc18\ub4dc\uc2dc useEffect \uacc4\uc5f4 \ud6c5 \uc548\uc5d0\uc11c\ub9cc \ud638\ucd9c\ud574\uc57c \ud55c\ub2e4.<\/span><\/p>\n<p data-ke-size=\"size16\">\ub54c\ubb38\uc5d0 \uc0ac\uc6a9\ud560 useEffect \ubc14\ub85c \uc704\uc5d0 \uc120\uc5b8\ud558\ub294 \uac83\uc774 \uc88b\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\ub2e4\ub978 \ucef4\ud3ec\ub10c\ud2b8\ub098 \ud6c5\uc5d0 \ud568\uc218\ub97c \ub118\uae38 \uc218 \uc5c6\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">useEffectEvent\ub294 <span style=\"color: #ee2323;\">\uc758\uc874\uc131 \ubc30\uc5f4\uc744 \uc904\uc774\uae30 \uc704\ud55c \ud568\uc218\uac00 \uc544\ub2c8\ub2e4.<\/span><\/p>\n<p data-ke-size=\"size16\">useEffectEvent\ub294 \uc624\ub85c\uc9c0 <b>stale closure \ubc29\uc9c0\uc6a9\uc774\ub2e4<\/b>.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\"><span style=\"color: #000000;\">\ubc18\ub4dc\uc2dc \uc774\ubca4\ud2b8 \ud578\ub4e4\ub7ec \ub0b4\ubd80\uc5d0\uc11c\ub9cc \ub3d9\uc791\ud558\ub294 \ub85c\uc9c1\uc73c\ub85c \uc791\uc131\ud574\uc57c \ud55c\ub2e4.<\/span><\/p>\n<p data-ke-size=\"size16\"><span style=\"color: #000000;\">React State\ub97c \uc9c1\uc811 \ubcc0\uacbd\ud558\ub294 \uc774\ubca4\ud2b8\uc5d0 \uc774 \ud6c5\uc744 \uc0ac\uc6a9\ud558\ub294 \uac83\uc740 \ubd80\uc801\ud569\ud558\ub2e4.<\/span><\/p>","category":"React","author":"MaKa_","guid":"https:\/\/mk-develop.tistory.com\/59","comments":"https:\/\/mk-develop.tistory.com\/entry\/React-useEffectEvent-%ED%9B%85#entry59comment","pubDate":"Tue, 11 Nov 2025 21:51:33 +0900"},{"title":"\ud1a0\uc2a4 \uc11c\ub958\ud569\uaca9 \ud6c4\uae30","link":"https:\/\/mk-develop.tistory.com\/entry\/%ED%86%A0%EC%8A%A4-%EC%84%9C%EB%A5%98%ED%95%A9%EA%B2%A9","description":"<h3 data-ke-size=\"size23\">\uac1c\uc694<\/h3>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc720\ub808\uce74\ub97c \uc218\ub8cc\ud558\uace0 \ucde8\uc900\uc0dd\uc774 \ub41c\uc9c0 2\uac1c\uc6d4\uc774 \ub418\uc5b4\uac04\ub2e4.<br \/>&nbsp;<br \/>2025\ub144 10\uc6d4 \uae30\uc900, \uc2e0\uc785 \uac1c\ubc1c\uc790\uac00 \ucc44\uc6a9\ubb38\uc744 \ub6ab\uae30\ub294 \ub354\uc6b1 \uc5b4\ub824\uc6cc\uc9c0\uace0 \uc788\ub2e4.<br \/>&nbsp;<br \/><a href=\"https:\/\/mk-develop.tistory.com\/entry\/LG%EC%9C%A0%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%9C%A0%EB%A0%88%EC%B9%B4-SW-%EA%B5%90%EC%9C%A1%EA%B3%BC%EC%A0%95-2%EA%B8%B0-%EC%88%98%EB%A3%8C-%ED%9B%84%EA%B8%B0\" target=\"_blank\" rel=\"noopener\"><span>2025.08.16 - [\uc774\uc57c\uae30\/\uc77c\uc0c1] - LG\uc720\ud50c\ub7ec\uc2a4 \uc720\ub808\uce74 SW \uad50\uc721\uacfc\uc815 2\uae30 \uc218\ub8cc \ud6c4\uae30<\/span><\/a><\/p>\n<figure data-ke-type=\"opengraph\" data-og-title=\"LG\uc720\ud50c\ub7ec\uc2a4 \uc720\ub808\uce74 SW \uad50\uc721\uacfc\uc815 2\uae30 \uc218\ub8cc \ud6c4\uae30\" data-ke-align=\"alignCenter\" data-og-description=\"\uac1c\uc694\ub4dc\ub514\uc5b4 \uae38\ub2e4\uba74 \uae38\uc5c8\uace0 \uc9e7\ub2e4\uba74 \uc5c4\uccad \uc21c\uc2dd\uac04\uc5d0 \uc9c0\ub098\uac14\ub358 7\uac1c\uc6d4\uac04\uc758 \uc720\ub808\uce74 2\uae30 \uacfc\uc815\uc774 \ub05d\uc774 \ub0ac\ub2e4.\uc218\ub8cc\uc2dd\uc740 OT\uc640 \uac19\uc740 \uc7a5\uc18c\uc778 LG U+ \ub9c8\uace1\uc0ac\uc625\uc5d0\uc11c \uc9c4\ud589\ub410\ub2e4.\uc218\ub8cc\uc2dd \ub2f9\uc77c \uc785\uad6c\uc5d0\uc11c\ubd80\ud130 \uc774\ub807\uac8c \uc131\" data-og-host=\"mk-develop.tistory.com\" data-og-source-url=\"https:\/\/mk-develop.tistory.com\/entry\/LG%EC%9C%A0%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%9C%A0%EB%A0%88%EC%B9%B4-SW-%EA%B5%90%EC%9C%A1%EA%B3%BC%EC%A0%95-2%EA%B8%B0-%EC%88%98%EB%A3%8C-%ED%9B%84%EA%B8%B0\" data-og-image=\"https:\/\/blog.kakaocdn.net\/dna\/cPWSxK\/hyZLgO40kK\/AAAAAAAAAAAAAAAAAAAAAIL6GTbkIpU-2cRKR9C1XeLUnMQ0cRE0cXdxP5hDWPA9\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1761922799&amp;allow_ip=&amp;allow_referer=&amp;signature=D5QQyyaDne%2F8wne1GtghJQCsSBU%3D\" data-og-url=\"https:\/\/mk-develop.tistory.com\/entry\/LG%EC%9C%A0%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%9C%A0%EB%A0%88%EC%B9%B4-SW-%EA%B5%90%EC%9C%A1%EA%B3%BC%EC%A0%95-2%EA%B8%B0-%EC%88%98%EB%A3%8C-%ED%9B%84%EA%B8%B0\"><a href=\"https:\/\/mk-develop.tistory.com\/entry\/LG%EC%9C%A0%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%9C%A0%EB%A0%88%EC%B9%B4-SW-%EA%B5%90%EC%9C%A1%EA%B3%BC%EC%A0%95-2%EA%B8%B0-%EC%88%98%EB%A3%8C-%ED%9B%84%EA%B8%B0\" target=\"_blank\" rel=\"noopener\" data-source-url=\"https:\/\/mk-develop.tistory.com\/entry\/LG%EC%9C%A0%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%9C%A0%EB%A0%88%EC%B9%B4-SW-%EA%B5%90%EC%9C%A1%EA%B3%BC%EC%A0%95-2%EA%B8%B0-%EC%88%98%EB%A3%8C-%ED%9B%84%EA%B8%B0\">\n<div class=\"og-image\" style=\"background-image: url('https:\/\/blog.kakaocdn.net\/dna\/cPWSxK\/hyZLgO40kK\/AAAAAAAAAAAAAAAAAAAAAIL6GTbkIpU-2cRKR9C1XeLUnMQ0cRE0cXdxP5hDWPA9\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1761922799&amp;allow_ip=&amp;allow_referer=&amp;signature=D5QQyyaDne%2F8wne1GtghJQCsSBU%3D');\">&nbsp;<\/div>\n<div class=\"og-text\">\n<p class=\"og-title\" data-ke-size=\"size16\">LG\uc720\ud50c\ub7ec\uc2a4 \uc720\ub808\uce74 SW \uad50\uc721\uacfc\uc815 2\uae30 \uc218\ub8cc \ud6c4\uae30<\/p>\n<p class=\"og-desc\" data-ke-size=\"size16\">\uac1c\uc694\ub4dc\ub514\uc5b4 \uae38\ub2e4\uba74 \uae38\uc5c8\uace0 \uc9e7\ub2e4\uba74 \uc5c4\uccad \uc21c\uc2dd\uac04\uc5d0 \uc9c0\ub098\uac14\ub358 7\uac1c\uc6d4\uac04\uc758 \uc720\ub808\uce74 2\uae30 \uacfc\uc815\uc774 \ub05d\uc774 \ub0ac\ub2e4.\uc218\ub8cc\uc2dd\uc740 OT\uc640 \uac19\uc740 \uc7a5\uc18c\uc778 LG U+ \ub9c8\uace1\uc0ac\uc625\uc5d0\uc11c \uc9c4\ud589\ub410\ub2e4.\uc218\ub8cc\uc2dd \ub2f9\uc77c \uc785\uad6c\uc5d0\uc11c\ubd80\ud130 \uc774\ub807\uac8c \uc131<\/p>\n<p class=\"og-host\" data-ke-size=\"size16\">mk-develop.tistory.com<\/p>\n<\/div>\n<\/a><\/figure>\n<p data-ke-size=\"size16\">\ubb3c\ub860 \uc774\ub7ec\ud55c \uc0ac\ud68c \ub3d9\ud5a5\uc740 \uc774\ubbf8 \uc54c\uace0 \uc788\uc5c8\uae30\uc5d0 \uc774\uc804 \ud68c\uace0\uc758 \ub9c8\uc9c0\ub9c9 \uc904\uc5d0\uc11c \uc801\uc5b4 \ub454\uac83\ucc98\ub7fc \ub9c8\uc74c\uc744 \ub3c5\ud558\uac8c \uba39\uc5b4\uc57c \uaca0\ub2e4\uace0 \uc0dd\uac01\ud558\uace0 \uc0b4\uc544\uc654\ub2e4.<br \/>&nbsp;<br \/>\ubd88\ud655\uc2e4\ud55c \ubbf8\ub798\ub294 \uc5ec\uc804\ud558\uc9c0\ub9cc \uc9c0\uae08\uae4c\uc9c0 \ud574\uc654\ub358\uac83\ucc98\ub7fc \uc5b8\uc81c \uc62c\uc9c0 \ubaa8\ub974\ub294 \uae30\ud68c\ub97c \ub300\ube44\ud558\uae30 \uc704\ud574 \uc720\ub808\uce74 \uce5c\uad6c\ub4e4\uacfc \uc2a4\ud130\ub514, \uac1c\uc778\uacf5\ubd80, \uc6b4\ub3d9\uc744 \ud558\uba70 \uc9c0\ub0b4\uace0 \uc788\uc5c8\ub2e4.<br \/>&nbsp;<br \/>1\uac1c\uc6d4 \ubc18\ub9cc\uc5d0 7kg\ub97c \uac10\ub7c9\ud588\uace0, \uc11c\uc6b8\uc744 \uc624\uac00\uba70 \uc2a4\ud130\ub514\ub97c \ud558\uace0, \ud504\ub85c\uc81d\ud2b8\ub97c \ubcf5\uae30\ud558\uba70 \ud3ec\ud2b8\ud3f4\ub9ac\uc624\uc758 \uc11c\ube44\uc2a4\ub97c \ub2e4\uc2dc \uc7ac\uc624\ud508\ud588\ub2e4.<br \/>&nbsp;<br \/>&nbsp;\uadf8\ub807\uac8c \uc9c0\ub0b4\ub358 \uc911 \uccab \ubc88\uc9f8 \uae30\ud68c\uac00 \ucc3e\uc544\uc654\ub2e4.<\/p>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">\uc11c\ub958 \ud569\uaca9<\/h3>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"763\" data-origin-height=\"410\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/kU239\/dJMb9hW7Ok7\/Hgt6FU86Dx5wFFTH075bGk\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/kU239\/dJMb9hW7Ok7\/Hgt6FU86Dx5wFFTH075bGk\/img.png\" data-alt=\"\uccab \uc11c\ub958 \ud569\uaca9\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/kU239\/dJMb9hW7Ok7\/Hgt6FU86Dx5wFFTH075bGk\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkU239%2FdJMb9hW7Ok7%2FHgt6FU86Dx5wFFTH075bGk%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"534\" height=\"287\" data-origin-width=\"763\" data-origin-height=\"410\"\/><\/span><figcaption>\uccab \uc11c\ub958 \ud569\uaca9<\/figcaption>\n<\/figure>\n<\/p>\n<p data-ke-size=\"size16\">\uc5b4\uc548\uc774 \ubc99\ubc99\ud588\ub2e4.<br \/>&nbsp;<br \/>\ucc98\uc74c\uc73c\ub85c \uc11c\ub958 \ud569\uaca9\uc744 \ud588\ub294\ub370 \uc2ec\uc9c0\uc5b4 \uadf8 \uae30\uc5c5\uc774 \ud1a0\uc2a4\uc600\ub2e4.<br \/>&nbsp;<br \/>\uc2e0\uc785 \ucc44\uc6a9 \uacf5\uace0\ub294 \uc11c\ub958\uc5d0\uc11c \ubaa8\ub450 \ub5a8\uc5b4\uc84c\ub294\ub370 \ud1a0\uc2a4 \uc11c\ub958\uc804\ud615\uc740 \ud1b5\uacfc\ud588\ub2e4\ub294\uac8c \ubbff\uae30\uc9c0 \uc54a\uc558\ub2e4.<br \/>&nbsp;<br \/>\ucd5c\uace0\uc758 \ud504\ub860\ud2b8\uc5d4\ub4dc \uac1c\ubc1c\uc790\uac00 \ub418\uace0 \uc2f6\uc740 \uc0ac\ub78c\ub4e4\uc740 \ub204\uad6c\ub098 \ud55c\ubc88\ucbe4\uc740 \uafc8\uafd4\ubd24\uc744 \ud68c\uc0ac\uc5d0\uc11c \uae30\ud68c\ub97c \uc8fc\uc5c8\ub2e4.<\/p>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">\uacfc\uc81c \uc804\ud615<\/h3>\n<hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"1014\" data-origin-height=\"406\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/pn4tV\/dJMb89dIBlZ\/SOyVwe5j3fytf1iZKIKjI0\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/pn4tV\/dJMb89dIBlZ\/SOyVwe5j3fytf1iZKIKjI0\/img.png\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/pn4tV\/dJMb89dIBlZ\/SOyVwe5j3fytf1iZKIKjI0\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpn4tV%2FdJMb89dIBlZ%2FSOyVwe5j3fytf1iZKIKjI0%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"538\" height=\"215\" data-origin-width=\"1014\" data-origin-height=\"406\"\/><\/span><\/figure>\n<\/p>\n<p data-ke-size=\"size16\">\uacfc\uc81c \uc804\ud615\uc744 \ubcf4\uac8c \ub418\uc5c8\ub2e4.<br \/>&nbsp;<br \/>\uc815\ub9d0 \uadc0\uc911\ud55c \uae30\ud68c\ub77c\uace0 \uc0dd\uac01\ud588\uace0, \ucd5c\uc120\uc744 \ub2e4\ud574 \ub3c4\uc804\ud574\uc57c\uaca0\ub2e4\uace0 \uc0dd\uac01\ud588\ub2e4.<br \/>&nbsp;<br \/>\uc57c\uac04\uc54c\ubc14\ub97c \ub05d\ub0b4\uace0 \ucabd\uc7a0\uc744 \uc790\uace0 \uc77c\uc5b4\ub09c \ud6c4 \ubc14\ub85c \uacfc\uc81c\ub97c \ubcf4\uc558\ub2e4.<br \/>&nbsp;<br \/>\uc11c\ub958\uc5d0 \ubd99\uc5c8\uc744 \ub54c \ubd80\ud130, \uacfc\uc81c\ub97c \ubcf4\uae30 \uc804\uae4c\uc9c0, \uacfc\uc81c\ub97c \uc218\ud589\ud558\uba74\uc11c\ub3c4 \ub108\ubb34 \ub5a8\ub838\ub2e4.<br \/>&nbsp;<br \/>\uacb0\uacfc\uac00 \uc5b4\ub5bb\uac8c \ub420 \uc9c4 \ubaa8\ub974\uaca0\uc9c0\ub9cc \uc774\ubc88 \ub3c4\uc804\uc774 \uacc4\uc18d\ud574\uc11c \uc774\uc5b4\uc84c\uc73c\uba74 \uc88b\uaca0\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">+ 2025-10-26 \ucd94\uac00<\/p>\n<p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"1011\" data-origin-height=\"474\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/bUgkf6\/dJMb83EABQq\/AKxX9bQ1iA5ernmjDfHMcK\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/bUgkf6\/dJMb83EABQq\/AKxX9bQ1iA5ernmjDfHMcK\/img.png\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/bUgkf6\/dJMb83EABQq\/AKxX9bQ1iA5ernmjDfHMcK\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUgkf6%2FdJMb83EABQq%2FAKxX9bQ1iA5ernmjDfHMcK%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"525\" height=\"246\" data-origin-width=\"1011\" data-origin-height=\"474\"\/><\/span><\/figure>\n<\/p>\n<p data-ke-size=\"size16\">\uacb0\uacfc\uc801\uc73c\ub860 \uacfc\uc81c\uc5d0\uc11c \ud0c8\ub77d\ud558\uac8c \ub418\uc5c8\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc65c \ud0c8\ub77d\ud588\ub294\uc9c0\ub294 \uc54c \uac83 \uac19\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc624\ud788\ub824 \uc774\ubc88 \uacfc\uc81c \uacbd\ud5d8\uc744 \ud1b5\ud574 \ub0b4 \ubd80\uc871\ud55c \ubd80\ubd84\uc774 \ubb34\uc5c7\uc778\uc9c0 \ub2e4\uc2dc\ud55c\ubc88 \ubcf5\uae30\ud574\ubcf4\ub294 \uae30\ud68c\uac00 \ub41c \uac83 \uac19\ub2e4.<\/p>","category":"\uc774\uc57c\uae30\/\uc77c\uc0c1","author":"MaKa_","guid":"https:\/\/mk-develop.tistory.com\/58","comments":"https:\/\/mk-develop.tistory.com\/entry\/%ED%86%A0%EC%8A%A4-%EC%84%9C%EB%A5%98%ED%95%A9%EA%B2%A9#entry58comment","pubDate":"Mon, 20 Oct 2025 00:26:03 +0900"},{"title":"\ub514\uc2a4\ucf54\ub4dc \ub178\ub798\ubd07 \uc81c\uc791\uae30","link":"https:\/\/mk-develop.tistory.com\/entry\/%EB%94%94%EC%8A%A4%EC%BD%94%EB%93%9C-%EB%85%B8%EB%9E%98%EB%B4%87-%EC%A0%9C%EC%9E%91%EA%B8%B0","description":"<h3 data-ke-size=\"size23\">\uac1c\uc694<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\ud3c9\uc18c\uc5d0 \uad00\uc2ec\uc774 \ub9ce\uc558\ub358 \ub514\uc2a4\ucf54\ub4dc \ubd07\uc744 \uc774\ubc88\uc5d0 \ub9cc\ub4e4\uc5c8\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\ubcf4\ud1b5 \ub178\ub798\ubd07 \uac19\uc740 \uacbd\uc6b0\uc5d4 \ub178\ub798\ud558\ub294 \ud558\ub9ac\ubcf4\uac19\uc740 \uc798 \uc54c\ub824\uc9c4 \ubd07\ub4e4\uc744 \uc0ac\uc6a9\ud558\uba74 \ub418\uc9c0\ub9cc \uc774\ub7ec\ud55c \ubd07\ub4e4\uc740 \uac00\ub054 \uba85\ub839\uc5b4\uac00 \uc218\ud589\uc774 \uc798 \uc548\ub418\ub294 \ubb38\uc81c\uac00 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ubd07\uc744 \uc9c1\uc811 \uad6c\ud604\ud55c\ub2e4\uba74 \uc774\ub7ec\ud55c \uc774\uc288\uc5d0 \ubc14\ub85c \ub300\ucc98\ud560 \uc218 \uc788\uace0 \uc815\ucc45\uc774 \uacc4\uc18d \ubc14\ub00c\ub294 \uc720\ud29c\ube0c \ud2b9\uc131\uc0c1 \uacc4\uc18d\ud574\uc11c \uc720\uc9c0\ubcf4\uc218\ub97c \ud574\uc918\uc57c \ud558\uae30\uc5d0 \uc9c0\uc18d\uc801\uc778 \uc720\uc9c0\ubcf4\uc218 \uacbd\ud5d8\ub3c4 \ud560 \uc218 \uc788\uc744 \uac83\uc774\ub77c \uc0dd\uac01\ud558\uc600\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">discord.js \uc624\ud508\uc18c\uc2a4\ub97c \uc0ac\uc6a9\ud558\uc5ec \uad6c\ud604\ud558\uc600\ub2e4.<\/p>\n<p data-ke-size=\"size16\"><a href=\"https:\/\/discord.js.org\/\" target=\"_blank\" rel=\"noopener&nbsp;noreferrer\">https:\/\/discord.js.org\/<\/a><\/p>\n<figure id=\"og_1759604270042\" contenteditable=\"false\" data-ke-type=\"opengraph\" data-ke-align=\"alignCenter\" data-og-type=\"website\" data-og-title=\"discord.js\" data-og-description=\"discord.js is a powerful Node.js module that allows you to interact with the Discord API very easily. It takes a much more object-oriented approach than most other JS Discord libraries, making your bot's code significantly tidier and easier to comprehend.\" data-og-host=\"discord.js.org\" data-og-source-url=\"https:\/\/discord.js.org\/\" data-og-url=\"https:\/\/discord.js.org\/\" data-og-image=\"https:\/\/scrap.kakaocdn.net\/dn\/2IjVb\/hyZKtnTsTR\/uyJnSm5P572i58LEsYITGk\/img.png?width=1200&amp;height=630&amp;face=0_0_1200_630,https:\/\/scrap.kakaocdn.net\/dn\/odwfq\/hyZKdykORU\/H6WCEJWZIKPfMTnK6XxWQ1\/img.png?width=1200&amp;height=630&amp;face=0_0_1200_630\"><a href=\"https:\/\/discord.js.org\/\" target=\"_blank\" rel=\"noopener\" data-source-url=\"https:\/\/discord.js.org\/\">\n<div class=\"og-image\" style=\"background-image: url('https:\/\/scrap.kakaocdn.net\/dn\/2IjVb\/hyZKtnTsTR\/uyJnSm5P572i58LEsYITGk\/img.png?width=1200&amp;height=630&amp;face=0_0_1200_630,https:\/\/scrap.kakaocdn.net\/dn\/odwfq\/hyZKdykORU\/H6WCEJWZIKPfMTnK6XxWQ1\/img.png?width=1200&amp;height=630&amp;face=0_0_1200_630');\">&nbsp;<\/div>\n<div class=\"og-text\">\n<p class=\"og-title\" data-ke-size=\"size16\">discord.js<\/p>\n<p class=\"og-desc\" data-ke-size=\"size16\">discord.js is a powerful Node.js module that allows you to interact with the Discord API very easily. It takes a much more object-oriented approach than most other JS Discord libraries, making your bot's code significantly tidier and easier to comprehend.<\/p>\n<p class=\"og-host\" data-ke-size=\"size16\">discord.js.org<\/p>\n<\/div>\n<\/a><\/figure>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ubcf8 \uae00\uc5d0\uc11c\ub294 \ub514\uc2a4\ucf54\ub4dc \ub178\ub798\ubd07\uc744 \uad6c\ud604\ud558\uae30 \uc704\ud574 \uacf5\ubd80\ud55c \ub0b4\uc6a9\uc744 \uc815\ub9ac\ud574 \ubcf4\ub824 \ud55c\ub2e4.<\/p>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">Youtube \uc2a4\ud2b8\ub9bc<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc720\ud29c\ube0c\ub294 \uc601\uc0c1\uc774\ub098 \uc74c\uc131\uc744 chunk \ub2e8\uc704\ub85c \uc804\uc1a1\ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">\uc601\uc0c1 \uc2a4\ud2b8\ub9bc\uc740 \ud654\uc9c8\ubcc4\ub85c \uc874\uc7ac\ud558\uace0 \uc74c\uc131 \uc2a4\ud2b8\ub9bc\uc740 \uc74c\uc131\ub9cc \ub530\ub85c \uc874\uc7ac\ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ub514\uc2a4\ucf54\ub4dc \ub178\ub798\ubd07 \uc81c\uc791\uc5d0 \ud544\uc694\ud55c \uc2a4\ud2b8\ub9bc\uc740 \uc74c\uc131 \uc2a4\ud2b8\ub9bc\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc720\ud29c\ube0c\ub85c\ubd80\ud130 \ubc1b\uc740 \uc74c\uc131 \uc2a4\ud2b8\ub9bc\uc744 \ub514\uc2a4\ucf54\ub4dc \uc74c\uc131 \ucc44\ub110\uc5d0 \uc804\uc1a1\ud558\uba74 \ubd07\uc5d0\uc11c \uc74c\uc545\uc774 \uc7ac\uc0dd\ub41c\ub2e4.<\/p>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">FFmpeg<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">FFmpeg\ub294 \uc624\ub514\uc624\uc640 \ube44\ub514\uc624\ub97c \ub2e4\ub8e8\ub294 \uc624\ud508\uc18c\uc2a4 \ud234\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ub3d9\uc601\uc0c1\uc774\ub098 \uc74c\uc131 \ud30c\uc77c\uc744 \uc778\ucf54\ub529, \ub514\ucf54\ub529, \ubcc0\ud658, \uc2a4\ud2b8\ub9ac\ubc0d \ud560 \uc218 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc720\ud29c\ube0c\ub85c\ubd80\ud130 \ubc1b\uc740 \uc74c\uc131 \uc2a4\ud2b8\ub9bc\uc740 \ubc14\ub85c \uc0ac\uc6a9\ud558\uc9c0 \ubabb\ud558\ub294 \uacbd\uc6b0\uac00 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc774\ub7f0 \uacbd\uc6b0\ub97c \uc0ac\uc804\uc5d0 \ubc29\uc9c0\ud558\uae30 \uc704\ud574 FFmpeg\ub97c \ud1b5\ud574 \ub514\uc2a4\ucf54\ub4dc \ubcf4\uc774\uc2a4 \ud3ec\ub9f7\uc778 raw PCM\uc73c\ub85c \ubcc0\ud658\ud574\uc57c \ud55c\ub2e4.<\/p>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">\uc720\ud29c\ube0c \ucfe0\ud0a4 \ucd94\ucd9c<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc5f0\ub839 \uc81c\ud55c, \uad6d\uac00 \uc81c\ud55c\ub4f1\uc758 \uc774\uc720\ub85c \uc601\uc0c1 \uc811\uadfc\uc774 \ub9c9\ud788\ub294 \uacbd\uc6b0\uac00 \ubc1c\uc0dd\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ub54c\ubb38\uc5d0 \uc720\ud29c\ube0c\uc758 \ucfe0\ud0a4\ub97c \ucd94\ucd9c\ud558\uc600\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ud06c\ub86c\uc758 \ud655\uc7a5 \ud504\ub85c\uadf8\ub7a8\uc778 EditThisCookie(V3)\ub97c \uc0ac\uc6a9\ud558\uc600\ub2e4.<\/p>\n<p data-ke-size=\"size16\"><a href=\"https:\/\/chromewebstore.google.com\/detail\/editthiscookie-v3\/ojfebgpkimhlhcblbalbfjblapadhbol?hl=ko&amp;utm_source=ext_sidebar\" target=\"_blank\" rel=\"noopener&nbsp;noreferrer\">https:\/\/chromewebstore.google.com\/detail\/editthiscookie-v3\/ojfebgpkimhlhcblbalbfjblapadhbol?hl=ko&amp;utm_source=ext_sidebar<\/a><\/p>\n<figure id=\"og_1759670489187\" contenteditable=\"false\" data-ke-type=\"opengraph\" data-ke-align=\"alignCenter\" data-og-type=\"website\" data-og-title=\"EditThisCookie (V3) - Chrome \uc6f9 \uc2a4\ud1a0\uc5b4\" data-og-description=\"EditThisCookie\ub294 \ucfe0\ud0a4 \uad00\ub9ac\uc790\uc785\ub2c8\ub2e4. \uc774\uac83\uc744 \uc774\uc6a9\ud558\uc5ec \ucfe0\ud0a4\ub97c \ucd94\uac00\ud558\uace0, \uc0ad\uc81c\ud558\uace0, \ud3b8\uc9d1\ud558\uace0, \ucc3e\uace0, \ubcf4\ud638\ud558\uac70\ub098 \ub9c9\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4!\" data-og-host=\"chromewebstore.google.com\" data-og-source-url=\"https:\/\/chromewebstore.google.com\/detail\/editthiscookie-v3\/ojfebgpkimhlhcblbalbfjblapadhbol?hl=ko&amp;utm_source=ext_sidebar\" data-og-url=\"https:\/\/chromewebstore.google.com\/detail\/editthiscookie-v3\/ojfebgpkimhlhcblbalbfjblapadhbol\" data-og-image=\"https:\/\/scrap.kakaocdn.net\/dn\/BEhbp\/hyZKejNMgt\/oiSGKzO3toPwUuoDeYg5KK\/img.jpg?width=128&amp;height=128&amp;face=0_0_128_128\"><a href=\"https:\/\/chromewebstore.google.com\/detail\/editthiscookie-v3\/ojfebgpkimhlhcblbalbfjblapadhbol?hl=ko&amp;utm_source=ext_sidebar\" target=\"_blank\" rel=\"noopener\" data-source-url=\"https:\/\/chromewebstore.google.com\/detail\/editthiscookie-v3\/ojfebgpkimhlhcblbalbfjblapadhbol?hl=ko&amp;utm_source=ext_sidebar\">\n<div class=\"og-image\" style=\"background-image: url('https:\/\/scrap.kakaocdn.net\/dn\/BEhbp\/hyZKejNMgt\/oiSGKzO3toPwUuoDeYg5KK\/img.jpg?width=128&amp;height=128&amp;face=0_0_128_128');\">&nbsp;<\/div>\n<div class=\"og-text\">\n<p class=\"og-title\" data-ke-size=\"size16\">EditThisCookie (V3) - Chrome \uc6f9 \uc2a4\ud1a0\uc5b4<\/p>\n<p class=\"og-desc\" data-ke-size=\"size16\">EditThisCookie\ub294 \ucfe0\ud0a4 \uad00\ub9ac\uc790\uc785\ub2c8\ub2e4. \uc774\uac83\uc744 \uc774\uc6a9\ud558\uc5ec \ucfe0\ud0a4\ub97c \ucd94\uac00\ud558\uace0, \uc0ad\uc81c\ud558\uace0, \ud3b8\uc9d1\ud558\uace0, \ucc3e\uace0, \ubcf4\ud638\ud558\uac70\ub098 \ub9c9\uc744 \uc218 \uc788\uc2b5\ub2c8\ub2e4!<\/p>\n<p class=\"og-host\" data-ke-size=\"size16\">chromewebstore.google.com<\/p>\n<\/div>\n<\/a><\/figure>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc720\ud29c\ube0c \ud648\uc5d0\uc11c \ud574\ub2f9 \ud655\uc7a5 \ud504\ub85c\uadf8\ub7a8\uc744 \ud1b5\ud574 \ucfe0\ud0a4\ub97c \uc27d\uac8c \ube7c\ub0bc \uc218 \uc788\ub2e4.<\/p>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">Queue<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\ub178\ub798 \uc7ac\uc0dd \ubaa9\ub85d\uc740 \ud050\ub85c \uad00\ub9ac\ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc5ec\uae30\uc11c \uc8fc\uc758\ud560 \uc810\uc740 <b>\ubd07\uc740 \uc5ec\ub7ec \uc11c\ubc84\uc5d0 \uc874\uc7ac\ud560 \uc218 \uc788\ub2e4<\/b>\ub294 \uac83\uc774\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">A\uc11c\ubc84\uc5d0\uc11c \uc7ac\uc0dd\ud55c \ub178\ub798 \ubaa9\ub85d\uacfc B \uc11c\ubc84\uc5d0\uc11c \uc7ac\uc0c1\ud55c \ub178\ub798 \ubaa9\ub85d\uc740 \uacb9\uccd0\uc120 \uc548\ub41c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc74c\uc131 \uc2a4\ud2b8\ub9bc \ub610\ud55c \ub2e4\ub978 \uacf5\uac04\uc5d0\uc11c \uc77d\uc5b4\uc640\uc57c \ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uadf8\ub807\uac8c \ud558\uc9c0 \uc54a\uc73c\uba74 <b>\ub2e4\ub978 \uc11c\ubc84\uc5d0\uc11c \uc7ac\uc0dd\ub418\uace0 \uc788\ub294 \ub178\ub798\uac00 \ud0c0 \uc11c\ubc84\uc5d0 \uc1a1\ucd9c\ub418\ub294 \uc704\ud5d8<\/b>\uc774 \uc788\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uac01 \uc11c\ubc84\uc758 \uc7ac\uc0dd \ubaa9\ub85d\uc744 \uad00\ub9ac\ud560 \ud050\ub97c \uba3c\uc800 \uad6c\ud604\ud55c\ub2e4.<\/p>\n<pre id=\"code_1759909105362\" class=\"javascript\" data-ke-language=\"javascript\" data-ke-type=\"codeblock\"><code>import {\n  joinVoiceChannel,\n  createAudioPlayer,\n  createAudioResource,\n  AudioPlayerStatus,\n  VoiceConnectionStatus,\n  NoSubscriberBehavior,\n  entersState,\n  demuxProbe,\n  generateDependencyReport,\n  StreamType\n} from \"@discordjs\/voice\";\n\nclass GuildQueue {\n  constructor(guildId, voiceChannel) {\n    this.guildId = guildId;\n    this.voiceChannel = voiceChannel;\n    this.textChannelId = null;\n    this.queue = [];\n    this.lock = false;\n    this.destroyed = false;\n\n    this.player = createAudioPlayer({\n      behaviors: { noSubscriber: NoSubscriberBehavior.Play },\n    });\n\n    this.player\n      .on(AudioPlayerStatus.Buffering, () =&gt; console.log('[player] buffering'))\n      .on(AudioPlayerStatus.Playing,   () =&gt; console.log('[player] playing  '))\n      .on(AudioPlayerStatus.Idle,      () =&gt; this.#onIdle())\n      .on('error', (e) =&gt; {\n        console.error(`[player error] ${guildId}`, e);\n        this.#onIdle();\n      });\n\n    this.connection = joinVoiceChannel({\n      channelId: voiceChannel.id,\n      guildId: voiceChannel.guild.id,\n      adapterCreator: voiceChannel.guild.voiceAdapterCreator,\n      selfDeaf: true,\n      selfMute: false,\n    });\n\n    \/\/ \uc5f0\uacb0 \uc548\uc815\ud654\n    this.ready = entersState(this.connection, VoiceConnectionStatus.Ready, 20_000).catch(\n      async (e) =&gt; {\n        console.error(\"[voice connect failed]\", e);\n        await this.destroy();\n      }\n    );\n\n    this.connection\n      .on(VoiceConnectionStatus.Disconnected, async () =&gt; {\n        try {\n          await Promise.race([\n            entersState(this.connection, VoiceConnectionStatus.Signalling, 5_000),\n            entersState(this.connection, VoiceConnectionStatus.Connecting, 5_000),\n          ]);\n        } catch {\n          await this.destroy();\n        }\n      })\n      .on(\"error\", (e) =&gt; console.error(\"[voice error]\", e));\n\n    this.connection.subscribe(this.player);\n  }\n\n  setTextChannel(id) {\n    this.textChannelId = id;\n  }\n\n  enqueue(track) {\n    this.queue.push(track);\n    void this.#process();\n  }\n\n  skip() {\n    this.player.stop(true);\n  }\n\n  pause() {\n    this.player.pause(true);\n  }\n\n  resume() {\n    this.player.unpause();\n  }\n\n  async leave() {\n    await this.destroy();\n  }\n\n  async destroy() {\n    if (this.destroyed) return;\n    this.destroyed = true;\n    try {\n      this.queue = [];\n      this.player.stop(true);\n      this.connection?.destroy();\n    } catch (_) {}\n  }\n\n  async #onIdle() {\n    await this.#process(true);\n  }\n\n  async #process(shiftOnIdle = false) {\n    if (this.lock || this.destroyed) return;\n    if (shiftOnIdle) this.queue.shift();\n    if (this.queue.length === 0) return;\n\n    this.lock = true;\n    const current = this.queue[0];\n\n    try {\n      await this.ready; \/\/ \ubcf4\uc774\uc2a4 \uc5f0\uacb0 \uc900\ube44 \ubcf4\uc7a5\n      const resource = await makeOpusResource(current);\n      \/\/ metadata\ub294 resource \uc0dd\uc131 \uc2dc \uc774\ubbf8 \ud3ec\ud568 \uac00\ub2a5\ud558\uc9c0\ub9cc, \uc5ec\uae30\uc120 \uac04\ub2e8\ud654\n      this.player.play(resource);\n      try {\n        if (this.textChannelId) {\n          const channel = await this.voiceChannel.client.channels.fetch(this.textChannelId).catch(() =&gt; null);\n          if (channel?.isTextBased?.()) {\n            await channel.send(`  \uc9c0\uae08 \uc7ac\uc0dd: **${current.title}** &lt;${current.url}&gt;`);\n          }\n        }\n      } catch (_) { \/* \uc804\uc1a1 \uc2e4\ud328\ub294 \uc870\uc6a9\ud788 \ubb34\uc2dc *\/ }\n    } catch (e) {\n      console.error(\"[play error]\", e);\n      \/\/ \uc2e4\ud328\ud55c \ud2b8\ub799 \uc81c\uac70 \ud6c4 \ub2e4\uc74c\uc73c\ub85c\n      this.queue.shift();\n      await delay(100);\n      this.lock = false;\n      return this.#process();\n    }\n\n    this.lock = false;\n  }\n}<\/code><\/pre>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uc11c\ubc84\ubcc4\ub85c \uc7ac\uc0dd\ud55c \ub178\ub798\uc758 \uc74c\uc131 \uc2a4\ud2b8\ub9bc\uc744 \uc77d\uc5b4\uc62c \uc218 \uc788\ub3c4\ub85d \uad6c\ud604\ud55c\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\ubcf8 \uae00\uc758 \ubd07 \uc2e4\ud589 \ud658\uacbd\uc740 raspberrypi5\uc774\ub2e4.<\/p>\n<pre id=\"code_1759910980160\" class=\"javascript\" data-ke-language=\"javascript\" data-ke-type=\"codeblock\"><code>import fs from 'node:fs';\nimport os from 'node:os';\n\n\/* \ud2b9\uc815 \uc11c\ubc84\uc5d0\uc11c \uc74c\uc545 \uc7ac\uc0dd \uc2dc \uc74c\uc131 \uc2a4\ud2b8\ub9ac\ubc0d \ud30c\uc77c\uc744 \uc800\uc7a5\ud560 \ud3f4\ub354 \uc0dd\uc131\ud558\ub294 \ud568\uc218*\/\nasync function makeYtTempDir(tag='yt') {\n  const prefix = path.join(os.tmpdir(), `${tag}-`);\n  const dir = await mkdtemp(prefix);\n  console.log('[ytdlp tmp] created:', dir);\n  try { fs.writeFileSync(path.join(dir, '__alive.txt'), new Date().toISOString()); } catch {}\n  return dir;\n}\n\nasync function spawnYtDlpFfmpeg(input, container = 'ogg') {\n  const url = normalizeToWatchUrl(input);\n  const TMPDIR = await makeYtTempDir('ytdlp');\n  const cookieFile = writeTempCookieFileFromEnv?.(TMPDIR) ?? writeTempCookieFileFromEnv();\n\n  \/\/ 1) yt-dlp\uac00 \ub124\ud2b8\uc6cc\ud06c\/\ud5e4\ub354\/\ucfe0\ud0a4\ub97c \ucc98\ub9ac\ud574\uc11c \"\ubc14\uc774\ud2b8\"\ub97c stdout\uc73c\ub85c \ub0b4\ubcf4\ub0b4\ub3c4\ub85d\n  \/\/    \uc624\ub514\uc624 \uc804\uc6a9 \uc6b0\uc120(m4a -&gt; webm -&gt; best)\n  const ytdlpArgs = [\n    '--ignore-config', '--no-warnings', '--force-ipv4',\n    '--no-part', '--no-keep-fragments',\n    '--paths', `temp:${TMPDIR}`,\n    '--cache-dir', TMPDIR,\n    ...(cookieFile ? ['--cookies', cookieFile] : []),\n    '-f', 'bestaudio[ext=m4a]\/bestaudio[ext=webm]\/bestaudio\/best',\n    '-o', '-',            \/\/ &lt;-- \ud45c\uc900\ucd9c\ub825\uc73c\ub85c \ub0b4\ubcf4\ub0b4\ub77c\n    '--no-playlist',\n    url,\n  ];\n  const ytdlp = await ytDlpLaunch(ytdlpArgs, {\n    cwd: TMPDIR,\n    env: { ...process.env,\n      XDG_CACHE_HOME: TMPDIR,\n      YTDLP_HOME: TMPDIR,             \/\/ yt-dlp\uac00 \ucc38\uace0\ud558\ub294 \uc0ac\uc6a9\uc790 \ub514\ub809\ud130\ub9ac\n      HOME: process.env.HOME ?? TMPDIR,\n      TMPDIR, TEMP: TMPDIR, TMP: TMPDIR,\n    },\n  });\n  ytdlp.once('spawn', () =&gt; console.log('[yt-dlp] cwd=', TMPDIR));\n  \/\/ 2) ffmpeg\ub294 \ub124\ud2b8\uc6cc\ud06c\ub85c \uc544\ubb34 \uac83\ub3c4 \ubc1b\uc9c0 \uc54a\uace0, stdin\ub9cc \ub514\ucf54\ub4dc\/\uc7ac\uc778\ucf54\ub4dc\n  \/\/    \ucee8\ud14c\uc774\ub108\ubcc4 \ud504\ub9ac\uc14b\n  const plans = {\n    ogg:  { args: ['-vn','-ac','2','-ar','48000','-c:a','libopus','-b:a','128k','-f','ogg','pipe:1'],  type: StreamType.OggOpus },\n    webm: { args: ['-vn','-ac','2','-ar','48000','-c:a','libopus','-b:a','128k','-f','webm','pipe:1'], type: StreamType.WebmOpus },\n    raw:  { args: ['-vn','-ac','2','-ar','48000','-f','s16le','pipe:1'],                               type: StreamType.Raw },\n  };\n  const plan = plans[container] ?? plans.ogg;\n\n  const ff = spawn(getFfmpegBin(), [\n    '-i', 'pipe:0',       \/\/ &lt;-- \uc785\ub825\uc744 \ud45c\uc900\uc785\ub825\uc5d0\uc11c \ubc1b\ub294\ub2e4\n    ...plan.args,\n  ], {\n    stdio: ['pipe', 'pipe', 'pipe'],\n    cwd: TMPDIR,\n    env: { ...process.env, TMPDIR },\n   });\n\n  \/\/ \ud30c\uc774\ud504 \uc5f0\uacb0: yt-dlp.stdout -&gt; ffmpeg.stdin\n  ytdlp.stdout.pipe(ff.stdin);\n\n  \/\/ \ub514\ubc84\uadf8(\ucd08\uae30 \uc5d0\ub7ec \ud655\uc778\uc6a9)\n  let ffErr = '';\n  ff.stderr.on('data', d =&gt; {\n    if (ffErr.length &lt; 1000) {\n      ffErr = d.toString();\n      if (ffErr.length &lt; 600) console.log('[ffmpeg stderr]', d.toString().trim());\n    }\n  });\n  ytdlp.stderr.on('data', d =&gt; {\n    const s = d.toString();\n    if (\/error|warning\/i.test(s)) console.log('[yt-dlp stderr]', s.trim());\n  });\n\n  \/\/ \ud504\ub85c\uc138\uc2a4 \uc218\uba85 \uad00\ub9ac(\ud544\uc694\uc2dc):\n  ff.on('close', () =&gt; { try { ytdlp.kill('SIGKILL'); } catch {} });\n  ytdlp.on('close', () =&gt; { try { ff.stdin.end(); } catch {} });\n\n  const cleanup = () =&gt; {\n    try { ytdlp.stdout.unpipe(ff.stdin); } catch {}\n    try { ff.stdin.end(); } catch {}\n    try { ff.kill('SIGKILL'); } catch {}\n    try { ytdlp.kill('SIGKILL'); } catch {}\n  };\n\n  \/\/ \ud30c\uc774\ud504 \uc5d0\ub7ec\ub294 \uc870\uc6a9\ud788 \ubb34\uc2dc (EPIPE \ub4f1)\n  ff.stdin.on('error', (e) =&gt; { if (e.code !== 'EPIPE') console.warn('[ff stdin]', e); });\n  ff.stdout.on('error', (e) =&gt; { if (e.code !== 'EPIPE') console.warn('[ff stdout]', e); });\n  ytdlp.stdout.on('error', (e) =&gt; { if (e.code !== 'EPIPE') console.warn('[ytdlp stdout]', e); });\n\n  \/\/ \uc0c1\ub300\uac00 \uba3c\uc800 \uc8fd\uc73c\uba74 \uc11c\ub85c \ub04a\uae30\n  ff.on('close', () =&gt; { try { ytdlp.kill('SIGKILL'); } catch {} });\n  ytdlp.on('close', () =&gt; { try { ff.stdin.end(); } catch {} });\n\n  return { stream: ff.stdout, type: plan.type, cleanup };\n}<\/code><\/pre>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/><hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<h3 data-ke-size=\"size23\">\ub9c8\ubb34\ub9ac<\/h3>\n<hr contenteditable=\"false\" data-ke-type=\"horizontalRule\" data-ke-style=\"style6\" \/>\n<p data-ke-size=\"size16\">\uc704\uc5d0 \ucf54\ub4dc \ubcf4\uba74 \ub290\ub08c\uc774 \uc624\uc2dc\ub294 \ubd84\ub4e4\ub3c4 \uc788\uaca0\uc9c0\ub9cc.. \ub300\ubd80\ubd84 \ubc14\uc774\ube0c \ucf54\ub529\uc73c\ub85c \uad6c\ud604\ud558\uc600\ub2e4.<\/p>\n<p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"373\" data-origin-height=\"413\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/k5vFI\/btsQ3Xx34sj\/J0NwxdFmKzA7IPP7hjpxRk\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/k5vFI\/btsQ3Xx34sj\/J0NwxdFmKzA7IPP7hjpxRk\/img.png\" data-alt=\"\uc815\uc0c1 \uc601\uc5c5 \uc911\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/k5vFI\/btsQ3Xx34sj\/J0NwxdFmKzA7IPP7hjpxRk\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk5vFI%2FbtsQ3Xx34sj%2FJ0NwxdFmKzA7IPP7hjpxRk%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"373\" height=\"413\" data-origin-width=\"373\" data-origin-height=\"413\"\/><\/span><figcaption>\uc815\uc0c1 \uc601\uc5c5 \uc911<\/figcaption>\n<\/figure>\n<\/p>\n<p data-ke-size=\"size16\">\uadf8\ub798\ub3c4 \ub098\ub984 \ubd07\uc740 \uc798 \ub3cc\uc544\uac04\ub2e4.<\/p>\n<p data-ke-size=\"size16\">&nbsp;<\/p>\n<p data-ke-size=\"size16\">\uac00\uae4c\uc6b4 \uc0ac\ub78c\ub4e4\uc758 \uc11c\ubc84\uc5d0 \ucd94\uac00\ud574\uc900 \uc0c1\ud669\uc778\ub370 \ud544\uc694\ud560 \ub54c\ub9c8\ub2e4 \uae30\ub2a5\uc744 \ud655\uc7a5\ud574 \ub098\uac00\ub824\uace0 \ud55c\ub2e4.<\/p>","category":["\uc774\uc57c\uae30\/\uc77c\uc0c1","Bot"],"author":"MaKa_","guid":"https:\/\/mk-develop.tistory.com\/57","comments":"https:\/\/mk-develop.tistory.com\/entry\/%EB%94%94%EC%8A%A4%EC%BD%94%EB%93%9C-%EB%85%B8%EB%9E%98%EB%B4%87-%EC%A0%9C%EC%9E%91%EA%B8%B0#entry57comment","pubDate":"Wed, 8 Oct 2025 17:50:00 +0900"},{"title":"Uble AWS \ube44\uc6a9 \uc808\uac10\uc744 \uc704\ud55c \ub77c\uc988\ubca0\ub9ac\ud30c\uc774 \uc11c\ubc84 \uc774\uc804\uae30","link":"https:\/\/mk-develop.tistory.com\/entry\/Uble-AWS-%EB%B9%84%EC%9A%A9-%EC%B5%9C%EC%A0%81%ED%99%94%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4-%EC%84%9C%EB%B2%84-%EC%9D%B4%EC%A0%84%EA%B8%B0","description":"<h3 data-ke-size=\"size23\">\uac1c\uc694<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">UBLE\uc740 \ud558\ub8e8 1\ub9cc\uc6d0\uc758 \uc11c\ubc84 \ube44\uc6a9\uc73c\ub85c \uc778\ud574 \uc11c\ube44\uc2a4\ub97c \uc7a0\uc2dc \uc911\ub2e8\ud560 \uc218 \ubc16\uc5d0 \uc5c6\uc5c8\ub2e4.<br>&nbsp;<br><a href=\"https:\/\/mk-develop.tistory.com\/entry\/LG%EC%9C%A0%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%9C%A0%EB%A0%88%EC%B9%B4-2%EA%B8%B0-%EC%9C%B5%ED%95%A9%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0\" target=\"_blank\"><span>2025.09.05 - [\uc774\uc57c\uae30\/\ud68c\uace0] - LG\uc720\ud50c\ub7ec\uc2a4 \uc720\ub808\uce74 2\uae30 \uc735\ud569\ud504\ub85c\uc81d\ud2b8 \ud68c\uace0<\/span><\/a><\/p><figure data-ke-type=\"opengraph\" data-og-title=\"LG\uc720\ud50c\ub7ec\uc2a4 \uc720\ub808\uce74 2\uae30 \uc735\ud569\ud504\ub85c\uc81d\ud2b8 \ud68c\uace0\" data-ke-align=\"alignCenter\" data-og-description=\"\uac1c\uc694LG\uc720\ud50c\ub7ec\uc2a4 \uc720\ub808\uce74 \uacfc\uc815\uc758 \ub9c8\uc9c0\ub9c9 \ud504\ub85c\uc81d\ud2b8\uc778 \uc735\ud569 \ud504\ub85c\uc81d\ud2b8\uac00 \ub9c8\ubb34\ub9ac\ub418\uc5c8\ub2e4. \uc0ac\uc2e4 \ud504\ub85c\uc81d\ud2b8\ub294 \ubc8c\uc368 3\uc8fc \uc804\uc5d0 \ub05d\ub0ac\uc9c0\ub9cc, \uc774\uc81c\uc57c \uc774\ub807\uac8c \ud68c\uace0\ub97c \uc815\ub9ac\ud574 \ubcf8\ub2e4. \uc774\ubc88 \uc735\ud569 \ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c\ub294 \ub2e4\uc2dc\" data-og-host=\"mk-develop.tistory.com\" data-og-source-url=\"https:\/\/mk-develop.tistory.com\/entry\/LG%EC%9C%A0%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%9C%A0%EB%A0%88%EC%B9%B4-2%EA%B8%B0-%EC%9C%B5%ED%95%A9%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0\" data-og-image=\"https:\/\/blog.kakaocdn.net\/dna\/dsGV8j\/hyZJoe0uWA\/AAAAAAAAAAAAAAAAAAAAANvROOIzTbs7BcXYDGZGUfkxA_L-Y6T2ebyDz6F7JJ9n\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1759244399&amp;allow_ip=&amp;allow_referer=&amp;signature=VTVtmKhq8EY3D4sQBeCs322GTg0%3D\" data-og-url=\"https:\/\/mk-develop.tistory.com\/entry\/LG%EC%9C%A0%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%9C%A0%EB%A0%88%EC%B9%B4-2%EA%B8%B0-%EC%9C%B5%ED%95%A9%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0\"><a href=\"https:\/\/mk-develop.tistory.com\/entry\/LG%EC%9C%A0%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%9C%A0%EB%A0%88%EC%B9%B4-2%EA%B8%B0-%EC%9C%B5%ED%95%A9%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0\" target=\"_blank\" data-source-url=\"https:\/\/mk-develop.tistory.com\/entry\/LG%EC%9C%A0%ED%94%8C%EB%9F%AC%EC%8A%A4-%EC%9C%A0%EB%A0%88%EC%B9%B4-2%EA%B8%B0-%EC%9C%B5%ED%95%A9%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0\"><div class=\"og-image\" style=\"background-image: url('https:\/\/blog.kakaocdn.net\/dna\/dsGV8j\/hyZJoe0uWA\/AAAAAAAAAAAAAAAAAAAAANvROOIzTbs7BcXYDGZGUfkxA_L-Y6T2ebyDz6F7JJ9n\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1759244399&amp;allow_ip=&amp;allow_referer=&amp;signature=VTVtmKhq8EY3D4sQBeCs322GTg0%3D')\"> <\/div><div class=\"og-text\"><p class=\"og-title\">LG\uc720\ud50c\ub7ec\uc2a4 \uc720\ub808\uce74 2\uae30 \uc735\ud569\ud504\ub85c\uc81d\ud2b8 \ud68c\uace0<\/p><p class=\"og-desc\">\uac1c\uc694LG\uc720\ud50c\ub7ec\uc2a4 \uc720\ub808\uce74 \uacfc\uc815\uc758 \ub9c8\uc9c0\ub9c9 \ud504\ub85c\uc81d\ud2b8\uc778 \uc735\ud569 \ud504\ub85c\uc81d\ud2b8\uac00 \ub9c8\ubb34\ub9ac\ub418\uc5c8\ub2e4. \uc0ac\uc2e4 \ud504\ub85c\uc81d\ud2b8\ub294 \ubc8c\uc368 3\uc8fc \uc804\uc5d0 \ub05d\ub0ac\uc9c0\ub9cc, \uc774\uc81c\uc57c \uc774\ub807\uac8c \ud68c\uace0\ub97c \uc815\ub9ac\ud574 \ubcf8\ub2e4. \uc774\ubc88 \uc735\ud569 \ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c\ub294 \ub2e4\uc2dc<\/p><p class=\"og-host\">mk-develop.tistory.com<\/p><\/div><\/a><\/figure><p data-ke-size=\"size16\">\uc11c\ube44\uc2a4\ub97c \uc6b4\uc601\ud55c\ub2e4\ub294 \uac83\uc740 \uadf8\ub9cc\ud07c \ube44\uc6a9 \ubb38\uc81c\uac00 \ubc1c\uc0dd\ud55c\ub2e4.<br>&nbsp;<br>\ud504\ub85c\uc81d\ud2b8 \ub2f9\uc2dc\uc5d4 \uc720\ub808\uce74\uc5d0\uc11c \uc11c\ubc84 \ube44\uc6a9\uc744 \uc9c0\uc6d0\ud574 \uc8fc\uc5c8\uc9c0\ub9cc \uc218\ub8cc\ud55c \uc774\ud6c4\uc778 \ud604 \uc2dc\uc810\uc5d0\uc11c\ub294 \ube44\uc6a9 \ubb38\uc81c\uc5d0\uc11c \uc790\uc720\ub86d\uc9c0 \ubabb\ud588\ub2e4.<br>&nbsp;<br>\uc6b4\uc601 \ube44\uc6a9\uc744 \uc808\uac10\ud558\ub294 \uac83 \ub610\ud55c \uc911\uc694\ud558\ub2e4\uace0 \uc0dd\uac01\ud55c\ub2e4. \uc774\ub97c \uc0dd\uac01\ud558\uc9c0 \uc54a\uc73c\uba74 \uc11c\ube44\uc2a4\uac00 \ucee4\uc9c8 \ub54c \uc6c3\uace0 \uc788\ub294\uac74 Vercel\uc774\ub098 AWS\uc77c \uac83\uc774\ub2e4.<br>&nbsp;<br>\uc11c\ubc84 \ube44\uc6a9 \uc9c0\uc6d0\uc774 \ub04a\uae30\uace0 \ub098\uc11c \uc5b4\ub5bb\uac8c \uc800\ube44\uc6a9\uc73c\ub85c \uc11c\ube44\uc2a4\ub97c \uc720\uc9c0\ud560 \uc9c0 \uace0\ubbfc\uc744 \ub9ce\uc774 \ud588\uc5c8\ub2e4.<br>&nbsp;<br>\ucde8\uc900\uc0dd\uc73c\ub85c\uc368 \uc11c\ubc84 \uc720\uc9c0\uc5d0 \ub9ce\uc740 \ub3c8\uc744 \uc4f8\uc218\ub294 \uc5c6\uae30\uc5d0 <b>\uc5f0\uac04 5000\uc6d0\uc758 \ube44\uc6a9\uc774 \ub4dc\ub294 \ub77c\uc988\ubca0\ub9ac\ud30c\uc774\uc5d0 \uc11c\ubc84\ub97c \uc774\uc804<\/b>\ud558\ub294 \uc791\uc5c5\uc744 \uc9c4\ud589\ud558\uc600\ub2e4.<br>&nbsp;<br>\uc774\ub825\uc11c\uc640 \ud3ec\ud2b8\ud3f4\ub9ac\uc624\uac00 Uble \uc704\uc8fc\ub85c \uc791\uc131\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \ucc44\uc6a9 \ub2f4\ub2f9\uc790 \ubd84\ub4e4\uc774 \uc11c\ube44\uc2a4\ub97c \uccb4\ud5d8\ud574 \ubcfc \uc218 \uc788\uac8c \ub300\ubd80\ubd84\uc758 \uae30\ub2a5\uc774 \uc815\uc0c1\uc801\uc73c\ub85c \ub3d9\uc791\ud558\ub3c4\ub85d \ud558\ub294 \uac83\uc744 \ubaa9\ud45c\ub85c \uc7a1\uc558\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\uc11c\ubc84 \uc124\uacc4 \ud30c\uc545\ud558\uae30<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"9497\" data-origin-height=\"6106\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/Tsak5\/btsQCL4S6xI\/GlFgAAg6vQyW8GgmYp0UH0\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/Tsak5\/btsQCL4S6xI\/GlFgAAg6vQyW8GgmYp0UH0\/img.png\" data-alt=\"Uble System Architecture\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/Tsak5\/btsQCL4S6xI\/GlFgAAg6vQyW8GgmYp0UH0\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTsak5%2FbtsQCL4S6xI%2FGlFgAAg6vQyW8GgmYp0UH0%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"582\" height=\"374\" data-origin-width=\"9497\" data-origin-height=\"6106\"\/><\/span><figcaption>Uble System Architecture<\/figcaption>\n<\/figure>\n<p data-ke-size=\"size16\">\uc778\ud504\ub77c\ub294 \uc8fc\ub85c \ubc31\uc5d4\ub4dc \ud300\uc6d0\ubd84\ub4e4\uc774 \ub9e1\uc544\uc11c \uc9c4\ud589\ud558\uc600\ub2e4.<br>&nbsp;<br>\ud574\ub2f9 \uc544\ud0a4\ud14d\ucc98\ub97c \uac04\uc18c\ud654\ud558\uc5ec \ub77c\uc988\ubca0\ub9ac\ud30c\uc774\uc758 \ub85c\uceec \ud658\uacbd \uc911\uc2ec\uc73c\ub85c \uc774\uc804\uc744 \uc9c4\ud589\ud558\uc600\ub2e4.<br><br>PostgreSQL\uacfc Redis\ub294 \ub85c\uceec \uae30\ubc18\uc73c\ub85c \ub3cc\ub9ac\uace0, FastAPI, ElisticSearch \uc11c\ubc84\ub294 Docker\ub97c \ud65c\uc6a9\ud574 \ucee8\ud14c\uc774\ub108\ub85c \uc2e4\ud589\ud558\uba74 \ub420 \uac83\uc73c\ub85c \ubcf4\uc600\ub2e4.<br>&nbsp;<br>\ub610\ud55c \uae30\uc874\uc5d0 S3\uc5d0 \uc800\uc7a5\ub418\uc5b4 \uc788\ub358 \ube0c\ub79c\ub4dc \uc774\ubbf8\uc9c0\ub294 \ub85c\uceec \ud3f4\ub354\uc5d0 \uc815\ub9ac\ud55c \ub4a4, Nginx\ub97c \ud1b5\ud574 \uc11c\ube59\ud558\ub294 \ubc29\uc2dd\uc73c\ub85c \ub300\uccb4\ud558\uba74 \ucda9\ubd84\ud558\uaca0\ub2e4\uace0 \ud310\ub2e8\ud558\uc600\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">Redis\uc640 PostgreSQL \uc5f0\uacb0<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">\uae30\uc874 \uad6c\uc870\uc5d0\uc11c\ub294 Private subnet\uc5d0 PostgreSQL, Redis\ub97c \uc62c\ub824\ub193\uc558\ub2e4.<br>&nbsp;<br>\ub2e8\uc21c\ud788 \ub370\uc774\ud130\ub97c \ucc38\uc870\ud560 \ubfd0\uc774\ubbc0\ub85c application.yml\uc744 \uc218\uc815\ud558\uc5ec \ub85c\uceec\uc5d0 \uc5f0\uacb0\ud558\uc600\ub2e4.<br>&nbsp;<br>\ub370\uc774\ud130\ub294 \uc774\uc804\uc5d0 \ubc31\uc5c5\ud574 \ub454 csv \ud30c\uc77c\uc744 \uc774\uc6a9\ud558\uc5ec \ub85c\uceec DB\uc5d0 \uc801\uc6a9\ud558\uc600\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">ElisticSearch &amp; FastAPI \uad6c\ub3d9<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">ElisticSearch\ub294 \uaf64\ub098 \uba54\ubaa8\ub9ac\ub97c \ub9ce\uc774 \ucc28\uc9c0\ud558\uae30 \ub54c\ubb38\uc5d0 \uc774\ubd80\ubd84\uc774 \ub9ce\uc774 \ud798\ub4e4\uc5c8\ub2e4.<br>&nbsp;<br>\ubc31\uc5d4\ub4dc \ud300\uc6d0\ubd84\ub4e4\uc758 \ub9d0\uc5d0 \ub530\ub974\uba74, \uae30\uc874 AWS \ud658\uacbd\uc5d0\uc11c\ub294 \uba54\ubaa8\ub9ac\ub97c 20GB \uc0ac\uc6a9\ud558\uc168\ub2e4\uace0 \ud558\uc168\ub294\ub370 \ub77c\uc988\ubca0\ub9ac\ud30c\uc774\uc758 \uba54\ubaa8\ub9ac\ub294 8GB\ubc16\uc5d0 \ub418\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc774\ub2e4.<br>&nbsp;<br>\uc2e4\uc81c\ub85c \ubc31\uc5d4\ub4dc\ubd84\ub4e4\uc774 \ub530\ub85c \ub0a8\uaca8\uc8fc\uc2e0 \ubb38\uc11c\ub300\ub85c \uc2e4\ud589\ud558\uc600\uc744 \ub54c \uba54\ubaa8\ub9ac \ubd80\ud558\ub85c \uc778\ud574 \uac15\uc81c \uc7ac\ubd80\ud305\uc774 \ub418\uc5c8\uc5c8\ub2e4.<br>&nbsp;<br>\ub0b4 \ubaa9\ud45c\ub294 \uc5b4\ub514\uae4c\uc9c0\ub098 <b>\uc77c\ub2e8 \uc11c\ube44\uc2a4\ub97c \uc774\uc6a9\ud560 \uc218 \uc788\uac8c\ub9cc \ud558\ub294 \uac83<\/b>\uc774\uc5c8\uae30 \ub54c\ubb38\uc5d0 \uba54\ubaa8\ub9ac\ub97c 512mb\ub9cc \ud560\ub2f9\ud558\ub3c4\ub85d \uc124\uc815\ud558\uc600\ub2e4.<br>&nbsp;<br>\uc18d\ub3c4\ub294 \ub9ce\uc774 \ub290\ub824\uc9c0\uaca0\uc9c0\ub9cc \uc774\uac8c \ucd5c\uc120\uc774\uc5c8\ub2e4.<br>&nbsp;<br>256mb\ubd80\ud130 \uc2dc\uc791\ud574\uc11c \uac00\uc6a9 \uac00\ub2a5\ud55c \uba54\ubaa8\ub9ac\ub97c \ub298\ub9ac\uae30 \uc704\ud574 \uc11c\ubc84\ub97c \uaed0\ub2e4 \ucf1c\uac00\uba70 \ud14c\uc2a4\ud2b8\ub97c \uc9c4\ud589\ud558\uc600\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\ube0c\ub79c\ub4dc \uc774\ubbf8\uc9c0 \uc801\uc6a9\ud558\uae30<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">\uae30\uc874 \uad6c\uc870\uc5d0\uc11c\ub294 AWS\uc758 S3\uc5d0 \ube0c\ub79c\ub4dc \uc774\ubbf8\uc9c0\ub4e4\uc744 \uc800\uc7a5\ud574 \ub450\uc5c8\uace0 \uc774\ub97c \ubc1b\uc544\uc654\ub2e4.<br>&nbsp;<br>S3\ub97c \ub300\uccb4\ud558\uae30 \uc704\ud574 nginx\uc5d0 \ud3f4\ub354\ub97c \ub744\uc6b0\uace0, \ud3f4\ub354 \uc548\uc5d0 \ube0c\ub79c\ub4dc \uc774\ubbf8\uc9c0\ub4e4\uc744 \uc800\uc7a5\ud574 \ub450\uba74 \ub418\uaca0\ub2e4\uace0 \ud310\ub2e8\ud558\uc600\ub2e4.<br>&nbsp;<br>\uc0ac\uc9c4\uc740 \ub300\ub7b5 150\uc5ec\uc7a5 \uc815\ub3c4 \ub418\uc5c8\ub294\ub370 \uc0ac\uc9c4 \ubc31\uc5c5\uc744 \uc548\ud574 \ub450\uc154\uc11c \ucc98\uc74c\ubd80\ud130 \ud558\ub098\ud558\ub098 \ub178\uac00\ub2e4 \ud574\uc11c \ub123\uc5c8\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"1120\" data-origin-height=\"63\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/dh8g87\/btsQAFlgMAv\/S0ZWEXfSY8UsRej9IM1mE0\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/dh8g87\/btsQAFlgMAv\/S0ZWEXfSY8UsRej9IM1mE0\/img.png\" data-alt=\"\uae30\uc874 \uc774\ubbf8\uc9c0 \uacbd\ub85c\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/dh8g87\/btsQAFlgMAv\/S0ZWEXfSY8UsRej9IM1mE0\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdh8g87%2FbtsQAFlgMAv%2FS0ZWEXfSY8UsRej9IM1mE0%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"1120\" height=\"63\" data-origin-width=\"1120\" data-origin-height=\"63\"\/><\/span><figcaption>\uae30\uc874 \uc774\ubbf8\uc9c0 \uacbd\ub85c<\/figcaption>\n<\/figure>\n<p data-ke-size=\"size16\">\ubc31\uc5c5\ud574\ub454 \uc81c\ud734\ucc98 \ub370\uc774\ud130\uc5d4 S3 \uacbd\ub85c\uac00 \uc800\uc7a5\ub418\uc5b4 \uc788\uc5c8\ub294\ub370 \uc774\ub97c Nginx \uc11c\ube59 \uacbd\ub85c\uc5d0 \ub9de\uac8c replace \ud558\uc600\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\uacb0\uacfc<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"1352\" data-origin-height=\"924\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/cmCZAi\/btsQAPtXpYO\/N8aIGcNs4EhOwoTjE0REL0\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/cmCZAi\/btsQAPtXpYO\/N8aIGcNs4EhOwoTjE0REL0\/img.png\" data-alt=\"\uc11c\ube44\uc2a4\ub97c \ub2e4\uc2dc \uc2dc\uc791\ud55c Uble\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/cmCZAi\/btsQAPtXpYO\/N8aIGcNs4EhOwoTjE0REL0\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmCZAi%2FbtsQAPtXpYO%2FN8aIGcNs4EhOwoTjE0REL0%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"581\" height=\"397\" data-origin-width=\"1352\" data-origin-height=\"924\"\/><\/span><figcaption>\uc11c\ube44\uc2a4\ub97c \ub2e4\uc2dc \uc2dc\uc791\ud55c Uble<\/figcaption>\n<\/figure>\n<p data-ke-size=\"size16\">\uacb0\uacfc\uc801\uc73c\ub85c \ub300\ubd80\ubd84\uc758 \uae30\ub2a5\uc740 \uc6d0\ud65c\ud558\uac8c \ub3d9\uc791\ud55c\ub2e4.<br>&nbsp;<br>\ub2e4\ub9cc \ucd94\ucc9c \uc2dc\uc2a4\ud15c\uacfc \uacc4\uc808 \uce74\ud14c\uace0\ub9ac\ub294 \uc6d0\ud65c\ud558\uac8c \uc791\ub3d9\ud558\uc9c0 \uc54a\ub294\ub2e4.<br>&nbsp;<br>\ubb38\uc81c\ub97c \ud574\uacb0\ud558\uace0 \uc2f6\uc9c0\ub9cc \ub0b4\uac00 \uac1c\ubc1c\ud55c \uc11c\ubc84\uac00 \uc544\ub2c8\uace0, \uba85\ud655\ud55c \uc5d0\ub7ec \ub85c\uadf8\uac00 \ucd9c\ub825\ub418\uc9c0 \uc54a\uc544 \ubb38\uc81c \uc6d0\uc778\uc744 \ud30c\uc545\ud558\uae30 \uc5b4\ub824\uc6cc \ud574\uacb0\ud558\uc9c4 \ubabb\ud558\uace0 \uc788\ub2e4.<\/p><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><h3 data-ke-size=\"size23\">\ub9c8\ubb34\ub9ac<\/h3><hr data-ke-type=\"horizontalRule\" data-ke-style=\"style6\"><p data-ke-size=\"size16\">Uble\uc5d0\ub294 \uc0ac\uc6a9\uc790\uc758 \uc11c\ube44\uc2a4 \uc774\uc6a9 \ub3d9\ud5a5\uc744 \ud30c\uc545\ud558\uae30 \uc704\ud55c Hotjar \uc2a4\ud06c\ub9bd\ud2b8\uac00 \uc801\uc6a9\ub418\uc5b4 \uc788\ub2e4.<br>&nbsp;<br>\uac00\ub054 Hotjar\uc5d0 \ub179\ud654\ub41c \uc0c8\ub85c\uc6b4 \uc138\uc158\uc744 \ubcf4\uba74 \ub85c\uadf8\uc778\uc744 \ud560\uc9c0 \ub9d0\uc9c0 \uace0\ubbfc\ud558\ub294 \uacbd\uc6b0\uac00 \ubcf4\uc778\ub2e4.<br>&nbsp;<br>\uc544\ub9c8\ub3c4 \ub0b4 \uc774\ub825\uc11c\ub098 \ud3ec\ud2b8\ud3f4\ub9ac\uc624\ub97c \ubcf4\uc2e0 \ucc44\uc6a9 \ub2f4\ub2f9\uad00 \ub2d8\uc774 \uc544\ub2d0\uae4c \uc608\uce21\ud574 \ubcf8\ub2e4.<br>&nbsp;<br>\uacb0\uacfc\uc801\uc73c\ub85c \ub85c\uadf8\uc778\uc744 \ub204\ub974\uc2dc\ub294 \ubd84\uc740 \ub9ce\uc774 \uc5c6\uc5c8\ub2e4.<br>&nbsp;<br>\uc11c\ube44\uc2a4\uc5d0 \ucc98\uc74c \uc785\uc7a5\ud558\ub294 \ubd84\uc758 \uc785\uc7a5\uc5d0\uc11c \uc0dd\uac01\ud574\ubcf4\uba74 \ub85c\uadf8\uc778\uc744 \ub204\ub974\uae30 \ub9ce\uc774 \ucc1d\ucc1d\ud560 \uac83 \uac19\uae34 \ud558\ub2e4.<br>&nbsp;<br><a href=\"https:\/\/mk-develop.tistory.com\/entry\/Linux-%ED%95%B4%EC%99%B8-%EC%95%84%EC%9D%B4%ED%94%BC-%EC%A0%91%EC%86%8D-%EC%B0%A8%EB%8B%A8%EC%9D%84-%EC%9C%84%ED%95%9C-ufw-%EB%B0%A9%ED%99%94%EB%B2%BD-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95\" target=\"_blank\"><span>2025.03.02 - [\uae30\ud0c0] - Linux \ud574\uc678 \uc544\uc774\ud53c \uc811\uc18d \ucc28\ub2e8\uc744 \uc704\ud55c ufw \ubc29\ud654\ubcbd \uc124\uc815 \ubc29\ubc95<\/span><\/a><\/p><figure data-ke-type=\"opengraph\" data-og-title=\"Linux \ud574\uc678 \uc544\uc774\ud53c \uc811\uc18d \ucc28\ub2e8\uc744 \uc704\ud55c ufw \ubc29\ud654\ubcbd \uc124\uc815 \ubc29\ubc95\" data-ke-align=\"alignCenter\" data-og-description=\"\uac1c\uc694\ubcf8\uac00\uc5d0 \uc788\ub294 MySQL \uc11c\ubc84\ub97c \uc0ac\uc6a9\ud560 \uc77c\uc774 \uc788\uc5b4\uc11c \uc11c\uc6b8\uc5d0\uc11c \uc678\ubd80 \uc811\uc18d\uc744 \uc2dc\ub3c4\ud558\uc600\ub294\ub370 \uc811\uc18d\uc774 \uac70\ubd80\ub2f9\ud588\ub2e4.\ubcf8\uac00\uc5d0\uc11c \ub77c\uc988\ubca0\ub9ac\ud30c\uc774\ub97c \ud655\uc778\ud558\uc600\ub354\ub2c8 \uc804\uc6d0\uc774 \uaebc\uc838 \uc788\uc5c8\ub2e4.\ub9c8\uc9c0\ub9c9\uc73c\ub85c \uc811\uc18d\ud588\uc744 \ub54c p\" data-og-host=\"mk-develop.tistory.com\" data-og-source-url=\"https:\/\/mk-develop.tistory.com\/entry\/Linux-%ED%95%B4%EC%99%B8-%EC%95%84%EC%9D%B4%ED%94%BC-%EC%A0%91%EC%86%8D-%EC%B0%A8%EB%8B%A8%EC%9D%84-%EC%9C%84%ED%95%9C-ufw-%EB%B0%A9%ED%99%94%EB%B2%BD-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95\" data-og-image=\"https:\/\/blog.kakaocdn.net\/dna\/LAS94\/hyZI1MxWox\/AAAAAAAAAAAAAAAAAAAAAPF8WUKAyiadQb2rApBdhx-YYwGTvWOH3QwGW_ZF5OyE\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1759244399&amp;allow_ip=&amp;allow_referer=&amp;signature=phDdYUnefFRGNd0Wgx5CsxYXcCE%3D\" data-og-url=\"https:\/\/mk-develop.tistory.com\/entry\/Linux-%ED%95%B4%EC%99%B8-%EC%95%84%EC%9D%B4%ED%94%BC-%EC%A0%91%EC%86%8D-%EC%B0%A8%EB%8B%A8%EC%9D%84-%EC%9C%84%ED%95%9C-ufw-%EB%B0%A9%ED%99%94%EB%B2%BD-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95\"><a href=\"https:\/\/mk-develop.tistory.com\/entry\/Linux-%ED%95%B4%EC%99%B8-%EC%95%84%EC%9D%B4%ED%94%BC-%EC%A0%91%EC%86%8D-%EC%B0%A8%EB%8B%A8%EC%9D%84-%EC%9C%84%ED%95%9C-ufw-%EB%B0%A9%ED%99%94%EB%B2%BD-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95\" target=\"_blank\" data-source-url=\"https:\/\/mk-develop.tistory.com\/entry\/Linux-%ED%95%B4%EC%99%B8-%EC%95%84%EC%9D%B4%ED%94%BC-%EC%A0%91%EC%86%8D-%EC%B0%A8%EB%8B%A8%EC%9D%84-%EC%9C%84%ED%95%9C-ufw-%EB%B0%A9%ED%99%94%EB%B2%BD-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95\"><div class=\"og-image\" style=\"background-image: url('https:\/\/blog.kakaocdn.net\/dna\/LAS94\/hyZI1MxWox\/AAAAAAAAAAAAAAAAAAAAAPF8WUKAyiadQb2rApBdhx-YYwGTvWOH3QwGW_ZF5OyE\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1759244399&amp;allow_ip=&amp;allow_referer=&amp;signature=phDdYUnefFRGNd0Wgx5CsxYXcCE%3D')\"> <\/div><div class=\"og-text\"><p class=\"og-title\">Linux \ud574\uc678 \uc544\uc774\ud53c \uc811\uc18d \ucc28\ub2e8\uc744 \uc704\ud55c ufw \ubc29\ud654\ubcbd \uc124\uc815 \ubc29\ubc95<\/p><p class=\"og-desc\">\uac1c\uc694\ubcf8\uac00\uc5d0 \uc788\ub294 MySQL \uc11c\ubc84\ub97c \uc0ac\uc6a9\ud560 \uc77c\uc774 \uc788\uc5b4\uc11c \uc11c\uc6b8\uc5d0\uc11c \uc678\ubd80 \uc811\uc18d\uc744 \uc2dc\ub3c4\ud558\uc600\ub294\ub370 \uc811\uc18d\uc774 \uac70\ubd80\ub2f9\ud588\ub2e4.\ubcf8\uac00\uc5d0\uc11c \ub77c\uc988\ubca0\ub9ac\ud30c\uc774\ub97c \ud655\uc778\ud558\uc600\ub354\ub2c8 \uc804\uc6d0\uc774 \uaebc\uc838 \uc788\uc5c8\ub2e4.\ub9c8\uc9c0\ub9c9\uc73c\ub85c \uc811\uc18d\ud588\uc744 \ub54c p<\/p><p class=\"og-host\">mk-develop.tistory.com<\/p><\/div><\/a><\/figure><p data-ke-size=\"size16\">\ubc30\ud3ec \uacc4\uc815\uc740 root\uad8c\ud55c\uc744 \uc8fc\uc9c0 \uc54a\uc558\ub2e4. \ud639\uc2dc \ubaa8\ub97c \ud638\uc2a4\ud2b8 \ud0c8\ucde8\uc5d0 \ub300\ube44\ud558\uae30 \uc704\ud568\uc774\ub2e4.<br>\ub610\ud55c \ud55c\uad6d IP\ub9cc \uc811\uc18d \uac00\ub2a5\ud558\uace0 \ub370\uc774\ud130\ubca0\uc774\uc2a4 \ube44\ubc00\ubc88\ud638\ub294 \ub09c\uc218 30\uc790 \uc774\uc0c1\uc73c\ub85c \uc774\ub8e8\uc5b4\uc838 \uc788\uae30\uc5d0 \uc5b4\ub290\uc815\ub3c4 \ubcf4\uc548\uc744 \ucc59\uae34 \uc11c\ubc84\ub77c\uace0 \uc790\ubd80\ud560 \uc218 \uc788\ub2e4.<br>&nbsp;<br>\ub9cc\uc57d \uc774 \uae00\uc744 \ubcf4\uc2e0\ub2e4\uba74 \uc548\uc2ec\ud558\uace0 \uc11c\ube44\uc2a4\uc5d0 \uc785\uc7a5\ud558\uc154\ub3c4 \ub41c\ub2e4\uace0 \uc598\uae30\ub97c \ub4dc\ub9ac\uace0 \uc2f6\ub2e4.<br>&nbsp;<br>\ub9c8\uc774\ud398\uc774\uc9c0\uc5d0\uc11c \uc2a4\ud06c\ub864 \ud558\ub2e8\uc5d0 \ud68c\uc6d0 \ud0c8\ud1f4 \ubc84\ud2bc\uc744 \uc228\uaca8\ub450\uc5c8\ub2e4.<\/p><figure class=\"imageblock alignCenter\" data-ke-mobileStyle=\"widthOrigin\" data-origin-width=\"1387\" data-origin-height=\"171\"><span data-url=\"https:\/\/blog.kakaocdn.net\/dn\/b4inqf\/btsQCBg7zwL\/ujkW0CoROk4vrIjlD4nQFk\/img.png\" data-phocus=\"https:\/\/blog.kakaocdn.net\/dn\/b4inqf\/btsQCBg7zwL\/ujkW0CoROk4vrIjlD4nQFk\/img.png\" data-alt=\"\uc228\uaca8\ub454 \ud68c\uc6d0 \uc774\ud0c8 \ub85c\uc9c1\"><img src=\"https:\/\/blog.kakaocdn.net\/dn\/b4inqf\/btsQCBg7zwL\/ujkW0CoROk4vrIjlD4nQFk\/img.png\" srcset=\"https:\/\/img1.daumcdn.net\/thumb\/R1280x0\/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4inqf%2FbtsQCBg7zwL%2FujkW0CoROk4vrIjlD4nQFk%2Fimg.png\" onerror=\"this.onerror=null; this.src='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png'; this.srcset='\/\/t1.daumcdn.net\/tistory_admin\/static\/images\/no-image-v1.png';\" loading=\"lazy\" width=\"1387\" height=\"171\" data-origin-width=\"1387\" data-origin-height=\"171\"\/><\/span><figcaption>\uc228\uaca8\ub454 \ud68c\uc6d0 \uc774\ud0c8 \ub85c\uc9c1<\/figcaption>\n<\/figure>\n<p data-ke-size=\"size16\">\uc11c\ube44\uc2a4 \uc774\ud0c8 \ub610\ud55c \uc5b8\uc81c\ub4e0\uc9c0 \ub9c8\uc74c\ub300\ub85c \uac00\ub2a5\ud558\ub2c8 \uad6c\uacbd\uc774\ub77c\ub3c4 \ud574\ubcf4\uc168\uc73c\uba74 \ud558\ub294 \ubc14\ub7a8\uc774\ub2e4.<br>&nbsp;<br>\uc774\ubd80\ubd84\uc5d0 \ub300\ud574\uc11c \uace0\ubbfc\uc744 \ud588\uc5c8\ub294\ub370 \uae30\ud68d \ub2e8\uacc4\uc5d0\uc11c \uba54\uc778 \uc11c\ube44\uc2a4\uc758 \uc811\uadfc \uad8c\ud55c\uc744 \uc5b4\ub290\uc815\ub3c4 \uc644\ud654\ud560\uac78 \uadf8\ub7ac\ub098 \uc2f6\uae30\ub3c4 \ud558\ub2e4..<br>&nbsp;<br><a href=\"https:\/\/www.u-ble.com\/\" target=\"_self\"><span>https:\/\/www.u-ble.com\/<\/span><\/a><\/p><figure data-ke-type=\"opengraph\" data-og-title=\"Uble\" data-ke-align=\"alignCenter\" data-og-description=\"U+ \uba64\ubc84\uc2ed \ud61c\ud0dd, \uc9c0\ub3c4\ub85c \ud55c\ub208\uc5d0! \uc9c0\uae08 \ub0b4 \uc8fc\ubcc0 \uc81c\ud734\ucc98\ub97c \ucc3e\uc544\ubcf4\uc138\uc694.\" data-og-host=\"www.u-ble.com\" data-og-source-url=\"https:\/\/www.u-ble.com\/\" data-og-image=\"https:\/\/blog.kakaocdn.net\/dna\/bcLgUx\/hyZIWdl5eP\/AAAAAAAAAAAAAAAAAAAAAL7Tyy50uJRInRrTq3cQxKRu9B827KfaWZFX7IVVWyh7\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1759244399&amp;allow_ip=&amp;allow_referer=&amp;signature=MtkscJirsRCT5%2FZz%2BhTSEaG8Pb8%3D\" data-og-url=\"https:\/\/www.u-ble.com\/\"><a href=\"https:\/\/www.u-ble.com\/\" target=\"_blank\" data-source-url=\"https:\/\/www.u-ble.com\/\"><div class=\"og-image\" style=\"background-image: url('https:\/\/blog.kakaocdn.net\/dna\/bcLgUx\/hyZIWdl5eP\/AAAAAAAAAAAAAAAAAAAAAL7Tyy50uJRInRrTq3cQxKRu9B827KfaWZFX7IVVWyh7\/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;expires=1759244399&amp;allow_ip=&amp;allow_referer=&amp;signature=MtkscJirsRCT5%2FZz%2BhTSEaG8Pb8%3D')\"> <\/div><div class=\"og-text\"><p class=\"og-title\">Uble<\/p><p class=\"og-desc\">U+ \uba64\ubc84\uc2ed \ud61c\ud0dd, \uc9c0\ub3c4\ub85c \ud55c\ub208\uc5d0! \uc9c0\uae08 \ub0b4 \uc8fc\ubcc0 \uc81c\ud734\ucc98\ub97c \ucc3e\uc544\ubcf4\uc138\uc694.<\/p><p class=\"og-host\">www.u-ble.com<\/p><\/div><\/a><\/figure><p data-ke-size=\"size16\">\ub9ce\uc740 \ubc29\ubb38 \ubd80\ud0c1\ub4dc\ub9bd\ub2c8\ub2e4.<br>&nbsp;<\/p>","category":["\uae30\ud0c0","AWS","backend","\ub77c\uc988\ubca0\ub9ac\ud30c\uc774"],"author":"MaKa_","guid":"https:\/\/mk-develop.tistory.com\/56","comments":"https:\/\/mk-develop.tistory.com\/entry\/Uble-AWS-%EB%B9%84%EC%9A%A9-%EC%B5%9C%EC%A0%81%ED%99%94%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4-%EC%84%9C%EB%B2%84-%EC%9D%B4%EC%A0%84%EA%B8%B0#entry56comment","pubDate":"Tue, 16 Sep 2025 22:52:18 +0900"}]}}