<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>blight_k.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sat, 30 Aug 2025 11:57:11 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>blight_k.log</title>
            <url>https://velog.velcdn.com/images/blight_k/profile/8bd3ee43-b49a-4c29-b497-36a2690c2122/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. blight_k.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/blight_k" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[유니퀘스트, 멀티캐스트, 브로드캐스트]]></title>
            <link>https://velog.io/@blight_k/%EC%9C%A0%EB%8B%88%ED%80%98%EC%8A%A4%ED%8A%B8-%EB%A9%80%ED%8B%B0%EC%BA%90%EC%8A%A4%ED%8A%B8-%EB%B8%8C%EB%A1%9C%EB%93%9C%EC%BA%90%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@blight_k/%EC%9C%A0%EB%8B%88%ED%80%98%EC%8A%A4%ED%8A%B8-%EB%A9%80%ED%8B%B0%EC%BA%90%EC%8A%A4%ED%8A%B8-%EB%B8%8C%EB%A1%9C%EB%93%9C%EC%BA%90%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Sat, 30 Aug 2025 11:57:11 GMT</pubDate>
            <description><![CDATA[<p>개발을 하다 보면 네트워크 통신 방식을 접하게 된다. 데이터를 주고받는 방식에는 여러 가지가 있는데, 가장 대표적인 세 가지 방식인 유니캐스트, 멀티캐스트, 브로드캐스트에 대해 알아보고자 한다. 각 방식이 어떻게 다르며, 어떤 상황에서 사용되는지 예시를 통해 쉽게 이해해 보자.</p>
<h2 id="1-유니캐스트-unicast--1-대-1-우편배달">1. 유니캐스트 (Unicast) : 1 대 1 우편배달</h2>
<blockquote>
<p><strong>유니캐스트(Unicast)</strong>는 단일 송신자와 단일 수신자 간의 1:1 통신을 의미한다. 네트워크에서 가장 흔하게 사용되는 통신 방식이다.</p>
</blockquote>
<p>컴퓨터 A가 컴퓨터 B에게만 데이터를 보내는 상황을 생각하면 된다. 다른 컴퓨터들은 이 통신에 관여하지 않는다.</p>
<ul>
<li><strong>특징</strong>: 특정 대상과 정확하게 데이터를 주고받아야 할 때 사용한다. 데이터 처리가 간단하고, 대부분의 통신이 이 방식으로 이루어진다.</li>
<li><strong>현실 예시</strong>: 특정 주소로 보내는 &#39;편지&#39;나 &#39;택배&#39;와 같다. 보내는 사람과 받는 사람이 명확하게 정해져 있다.</li>
<li><strong>기술 예시</strong>:<ul>
<li><strong>HTTP 요청</strong>: 웹 브라우저에서 특정 웹사이트(예: <code>velog.io</code>)에 접속할 때, 내 컴퓨터는 velog 서버와 1:1로 유니캐스트 통신을 시작한다. 서버는 요청을 보낸 &#39;나에게만&#39; 웹페이지 데이터를 보내준다.</li>
<li><strong>SSH 접속</strong>: 원격 서버에 접속할 때 내 컴퓨터와 서버는 1:1 암호화 통신을 한다.</li>
</ul>
</li>
</ul>
<pre><code></code></pre><h2 id="2-멀티캐스트-multicast--관심사-기반-단체-채팅방-💬">2. 멀티캐스트 (Multicast) : 관심사 기반 단체 채팅방 💬</h2>
<blockquote>
<p><strong>멀티캐스트(Multicast)</strong>는 특정 그룹(하나 이상의 노드)에게만 데이터를 한 번에 전송하는 1:N 통신 방식이다.</p>
</blockquote>
<p>송신자는 데이터를 딱 한 번만 보내지만, 네트워크 장비(라우터 등)가 이 데이터를 복제하여 &#39;이 정보를 받기로 약속한&#39; 여러 명의 수신자에게 전달해 준다.</p>
<ul>
<li><strong>특징</strong>: 동일한 데이터를 여러 대상에게 보내야 할 때, 유니캐스트를 여러 번 하는 것보다 네트워크 효율성이 훨씬 좋다. 데이터를 수신하고 싶은 노드만 그룹에 가입(<code>join</code>)하여 데이터를 받는다.</li>
<li><strong>현실 예시</strong>: &#39;구독자에게만 발송되는 뉴스레터&#39;나 &#39;특정 멤버만 있는 카카오톡 단체 채팅방&#39;과 같다. 관심 있는 사람들만 그룹에 참여해 소식을 받는다.</li>
<li><strong>기술 예시</strong>:<ul>
<li><strong>IPTV (실시간 방송)</strong>: 방송국에서 특정 채널(예: tvN)의 방송 데이터를 멀티캐스트로 한 번만 송신한다. 시청자 중 tvN 채널을 켜는 사람(해당 멀티캐스트 그룹에 가입)들만 그 방송 데이터를 수신하여 TV를 볼 수 있다.</li>
<li><strong>온라인 증권 시세 정보</strong>: 실시간으로 변하는 주식 시세 정보를 수많은 클라이언트에게 전달할 때 사용된다.</li>
</ul>
</li>
</ul>
<pre><code></code></pre><h2 id="3-브로드캐스트-broadcast--전체-대상-교내-방송-📢">3. 브로드캐스트 (Broadcast) : 전체 대상 교내 방송 📢</h2>
<blockquote>
<p><strong>브로드캐스트(Broadcast)</strong>는 같은 네트워크 대역에 있는 모든 노드에게 데이터를 전송하는 1:All 통신 방식이다.</p>
</blockquote>
<p>수신을 원하든 원하지 않든, 같은 네트워크에 연결된 모두에게 메시지를 뿌린다.</p>
<ul>
<li><strong>특징</strong>: 메시지를 받을 대상을 특정할 수 없거나, 네트워크상의 모든 노드에 알려야 할 정보가 있을 때 사용한다. 하지만 네트워크에 부하를 많이 줄 수 있어 제한적인 상황에서만 사용된다.</li>
<li><strong>현실 예시</strong>: &#39;학교 전체에 울려 퍼지는 교내 방송&#39;이나 &#39;아파트 단지 전체에 안내하는 관리사무소 방송&#39;과 같다. 듣기 싫어도 일단 들린다.</li>
<li><strong>기술 예시</strong>:<ul>
<li><strong>DHCP (Dynamic Host Configuration Protocol)</strong>: 컴퓨터가 네트워크에 처음 연결될 때, IP 주소를 할당받기 위해 &quot;IP 주소 좀 할당해 줄 DHCP 서버 어디 있나요?&quot;라고 브로드캐스트를 통해 네트워크상의 모든 노드에게 요청을 보낸다.</li>
</ul>
</li>
</ul>
<pre><code></code></pre><h2 id="📝-한눈에-비교하기">📝 한눈에 비교하기</h2>
<table>
<thead>
<tr>
<th align="left">구분</th>
<th align="left">대상</th>
<th align="left">특징</th>
<th align="left">대표 예시</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><strong>유니캐스트</strong></td>
<td align="left">특정 1개 노드 (1:1)</td>
<td align="left">가장 일반적인 통신 방식</td>
<td align="left">웹 서핑(HTTP)</td>
</tr>
<tr>
<td align="left"><strong>멀티캐스트</strong></td>
<td align="left">지정된 그룹의 모든 노드 (1:N)</td>
<td align="left">그룹에 가입한 노드만 수신, 효율적</td>
<td align="left">IPTV, 온라인 증권</td>
</tr>
<tr>
<td align="left"><strong>브로드캐스트</strong></td>
<td align="left">같은 네트워크의 모든 노드 (1:All)</td>
<td align="left">수신 의사와 상관없이 모두에게 전달, 부하 높음</td>
<td align="left">ARP, DHCP</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크 토폴로지의 필요성]]></title>
            <link>https://velog.io/@blight_k/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%ED%86%A0%ED%8F%B4%EB%A1%9C%EC%A7%80%EC%9D%98-%ED%95%84%EC%9A%94%EC%84%B1</link>
            <guid>https://velog.io/@blight_k/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%ED%86%A0%ED%8F%B4%EB%A1%9C%EC%A7%80%EC%9D%98-%ED%95%84%EC%9A%94%EC%84%B1</guid>
            <pubDate>Thu, 28 Aug 2025 14:11:38 GMT</pubDate>
            <description><![CDATA[<p>토폴로지는 네트워크의 <strong>성능과 안정성을 결정하는 핵심 요소</strong>이며, 특히 <strong>병목 현상(Bottleneck)</strong>을 이해하고 해결하는 중요한 척도가 된다</p>
<hr>
<h2 id="병목-현상이란">병목 현상이란?</h2>
<p><strong>병목 현상</strong>이란 말 그대로 병의 목처럼 좁아지는 구간 때문에 전체 흐름이 느려지는 것을 의미한다. 네트워크에서는 <strong>과도한 트래픽으로 인해 데이터의 흐름이 제한되는 상황</strong>을 가리킨다. 사용자가 몰려 웹사이트 접속이 느려지거나 서버가 다운되는 것이 대표적인 예다.</p>
<hr>
<h2 id="서버가-다운되면-어떻게-해야-할까">서버가 다운되면 어떻게 해야 할까?</h2>
<p>만약 갑자기 늘어난 트래픽 때문에 서비스가 마비되었다면 어떻게 대처해야 할까? 우리는 두 가지 관점에서 해결책을 생각해 볼 수 있다.</p>
<h3 id="1-자원의-양을-늘린다-scale-up">1. 자원의 양을 늘린다 (Scale-up)</h3>
<p>가장 먼저 시도하는 방법은 서버 자체의 성능을 높이는 것이다. <strong>메모리(RAM)나 CPU 같은 하드웨어 자원을 증설</strong>하여 서버가 더 많은 트래픽을 처리할 수 있도록 하는 것이다. 이는 가장 직관적인 해결책이다.</p>
<h3 id="2-토폴로지-관점에서-회선을-늘린다-scale-out">2. 토폴로지 관점에서 회선을 늘린다 (Scale-out)</h3>
<p>하지만 서버 자원을 무한정 늘릴 수는 없다. 이때 네트워크 토폴로지에 대한 이해가 빛을 발한다. <strong>토폴로지 관점에서 보면, 단순히 회선을 추가하여 데이터가 지나갈 수 있는 길을 넓혀주는 것</strong>만으로도 병목 현상을 크게 개선할 수 있다.</p>
<p>예를 들어, 모든 데이터가 하나의 중앙 허브를 거치는 스타형 토폴로지라면 허브가 병목 지점이 되기 쉽다. 이때 여러 경로로 트래픽을 분산시킬 수 있는 메시 토폴로지를 일부 도입하거나, 중요한 서버에 이중 회선을 연결하는 등의 구조적 변경을 통해 트래픽을 분산시키고 안정성을 확보할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크(3)]]></title>
            <link>https://velog.io/@blight_k/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC3</link>
            <guid>https://velog.io/@blight_k/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC3</guid>
            <pubDate>Thu, 28 Aug 2025 14:04:10 GMT</pubDate>
            <description><![CDATA[<h1 id="링-토폴로지와-메시-토폴로지-간단히-알아보기">링 토폴로지와 메시 토폴로지 간단히 알아보기</h1>
<p>네트워크 토폴로지(Network Topology)는 컴퓨터 네트워크의 요소들(링크, 노드 등)을 물리적으로 연결해 놓은 방식, 즉 네트워크의 구조를 의미한다. 오늘은 여러 토폴로지 중 <strong>링형(Ring Topology)</strong>과 <strong>메시형(Mesh Topology)</strong>에 대해 알아보려 한다.</p>
<hr>
<h2 id="링-토폴로지-ring-topology">링 토폴로지 (Ring Topology)</h2>
<p>링 토폴로지는 이름 그대로 각 노드가 양옆의 두 노드와 연결되어 전체적으로 <strong>하나의 고리(Ring) 형태</strong>를 이루는 네트워크 구조이다.</p>
<p>데이터는 링을 따라 한 방향으로 흐르며, 각 노드는 데이터를 수신하고 목적지가 자신이 아니면 옆 노드로 재전송하는 역할을 한다.</p>
<p>특히 링 토폴로지에서는 <strong>토큰 링(Token Ring)</strong> 프로토콜을 사용하는 경우가 많다.</p>
<ul>
<li><strong>토큰 링 프로토콜</strong>: 네트워크 상에 <strong>단 하나의 토큰(Token)</strong>이 존재한다. 이 토큰을 소유한 노드만이 데이터를 전송할 권한을 갖게 되어 충돌을 방지한다.</li>
</ul>
<h3 id="장점과-단점">장점과 단점</h3>
<p>링 토폴로지의 가장 큰 장점 중 하나는 <strong>장애 발생 시 어떤 노드에 문제가 생겼는지 쉽게 파악</strong>할 수 있다는 점이다.</p>
<p>하지만 단점도 명확하다. 이론적으로는 노드의 추가와 삭제가 간단해 보이지만, 실제로는 노드를 추가하거나 삭제하기 위해 <strong>연결을 끊는 순간 전체 네트워크가 일시적으로 중단</strong>된다. 또한, 데이터가 목적지에 도달하기까지 여러 노드를 거쳐야 하므로 <strong>전송 지연</strong>이 발생할 수 있다.</p>
<h3 id="이중-링-dual-ring">이중 링 (Dual Ring)</h3>
<p>이러한 단점을 보완하기 위해 <strong>이중 링(Dual Ring)</strong> 방식을 사용하기도 한다. 두 개의 링을 사용하여 하나는 주 경로로, 다른 하나는 백업 경로로 활용한다. 이를 통해 한쪽 링에 문제가 생겨도 다른 링을 통해 통신을 유지할 수 있어 안정성을 높인다.</p>
<hr>
<h2 id="🕸️-메시-토폴로지-mesh-topology">🕸️ 메시 토폴로지 (Mesh Topology)</h2>
<p>메시 토폴로지는 여러 노드들이 <strong>그물망(Mesh)처럼 서로 연결</strong>된 구조를 가진다. 모든 노드가 다른 모든 노드와 직접 연결될 필요는 없으며, 연결 방식에 따라 두 가지로 나뉜다.</p>
<ul>
<li><strong>풀 메시 (Full Mesh)</strong>: 네트워크의 모든 노드가 서로 <strong>1:1로 직접 연결</strong>된 구조.</li>
<li><strong>부분 메시 (Partial Mesh)</strong>: 일부 중요한 노드들만 여러 노드와 연결되고, 나머지 노드는 일부와만 연결된 구조.</li>
</ul>
<h3 id="장점과-단점-1">장점과 단점</h3>
<p>메시 토폴로지는 여러 개의 연결 회선을 가지므로 <strong>특정 회선에 장애가 발생해도 다른 경로를 통해 통신을 유지</strong>할 수 있어 매우 안정적이다. 또한, 트래픽이 한쪽으로 몰릴 경우 <strong>다른 경로로 트래픽을 분산</strong>시켜 효율적인 데이터 전송이 가능하다.</p>
<p>그러나 가장 큰 단점은 <strong>비용</strong>이다. 노드 간에 수많은 회선이 필요하므로 구축 및 유지보수 비용이 크게 증가한다. 특히 풀 메시 구조는 노드 수가 늘어날수록 필요한 연결 수가 기하급수적으로 늘어난다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크(2)]]></title>
            <link>https://velog.io/@blight_k/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC2</link>
            <guid>https://velog.io/@blight_k/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC2</guid>
            <pubDate>Wed, 27 Aug 2025 12:04:58 GMT</pubDate>
            <description><![CDATA[<h1 id="네트워크-토폴로지-학습-기록">네트워크 토폴로지 학습 기록</h1>
<p>네트워크 토폴로지(Network Topology)는 노드와 링크가 어떤 구조로 연결되어 있는지를 나타내는 방식이다. 이번에는 대표적인 토폴로지인 버스, 스타, 트리 토폴로지에 대해 알아본다.</p>
<hr>
<h2 id="버스-토폴로지-bus-topology">버스 토폴로지 (Bus Topology)</h2>
<p>버스 토폴로지는 <strong>중앙 회선 하나(백본, Backbone)에 여러 개의 노드가 연결된 구조</strong>를 가진다. 모든 노드는 동일한 하나의 전송 회선에 연결되어 통신한다.</p>
<h3 id="장점">장점</h3>
<ul>
<li><strong>설치 비용 절감</strong>: 회선 하나만 설치하면 되므로 비용이 적게 든다.</li>
<li><strong>유지보수 용이성</strong>: 구조가 단순하여 유지보수가 비교적 쉽다.</li>
<li><strong>노드 장애의 영향 제한</strong>: 특정 노드 하나에 장애가 발생해도 전체 네트워크에 영향을 주지 않는다.</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li><strong>중앙 회선 장애의 파급력</strong>: 만약 중앙 회선(백본)이 손상되면 전체 네트워크가 마비된다.</li>
<li><strong>보안 취약성</strong>: 모든 데이터가 단일 회선을 통해 전송되므로, 회선을 도청하면 전체 노드의 통신 내용이 노출될 위험이 있다.</li>
</ul>
<hr>
<h2 id="스타-토폴로지-star-topology">스타 토폴로지 (Star Topology)</h2>
<p>스타 토폴로지는 <strong>하나의 중앙 노드를 중심으로 여러 개의 말단 노드가 별 모양처럼 독립적으로 연결</strong>된 구조이다. 모든 통신은 반드시 중앙 노드를 거쳐서 이루어진다.</p>
<h3 id="장점-1">장점</h3>
<ul>
<li><strong>중앙 집중적 보안 관리</strong>: 중앙 노드에 방화벽과 같은 보안 기능을 집중시켜 효율적인 관리가 가능하다. 공격자는 반드시 중앙 노드를 거쳐야 하므로 보안상 이점이 있다.</li>
<li><strong>노드 장애의 영향 제한</strong>: 하나의 말단 노드에 장애가 발생해도 다른 노드와의 통신에는 영향을 주지 않는다.</li>
</ul>
<h3 id="단점-1">단점</h3>
<ul>
<li><strong>중앙 노드 의존성</strong>: 중앙 노드에 장애가 발생하면 모든 노드 간의 통신이 중단되어 전체 네트워크가 마비된다.</li>
<li><strong>설치 비용</strong>: 모든 노드를 중앙 노드에 개별적으로 연결해야 하므로 케이블링 비용이 많이 들 수 있다.</li>
</ul>
<hr>
<h2 id="트리-토폴로지-tree-topology">트리 토폴로지 (Tree Topology)</h2>
<p>트리 토폴로지는 <strong>계층적인 구조를 가지는 네트워크</strong>로, 버스 토폴로지와 스타 토폴로지가 결합된 형태라고 볼 수 있다. 최상위 루트 노드를 중심으로 하위 노드들이 나무가지처럼 뻗어 나가는 구조를 가진다.</p>
<h3 id="장점-2">장점</h3>
<ul>
<li><strong>확장 용이성</strong>: 계층 구조의 가장 아래에 있는 리프(leaf) 노드를 추가하기 쉬워 네트워크 확장이 편리하다.</li>
<li><strong>장애 영향 범위 제한</strong>: 리프 노드에 장애가 발생해도 해당 노드와 그 하위 노드에만 영향이 있을 뿐, 전체 네트워크에는 큰 영향을 주지 않는다.</li>
</ul>
<h3 id="단점-2">단점</h3>
<ul>
<li><strong>루트 노드 의존성</strong>: 최상위 루트 노드에 장애가 발생하면 그 아래에 연결된 모든 하위 노드의 통신이 불가능해진다.</li>
<li><strong>관리의 복잡성</strong>: 계층이 복잡해질수록 네트워크 관리가 어려워지고, 루트 노드에 가까울수록 트래픽이 집중될 수 있다. 또한, 루트 노드를 변경하거나 삭제하는 작업은 매우 어렵다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크(1)]]></title>
            <link>https://velog.io/@blight_k/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC1</link>
            <guid>https://velog.io/@blight_k/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC1</guid>
            <pubDate>Wed, 27 Aug 2025 11:53:47 GMT</pubDate>
            <description><![CDATA[<h2 id="네트워크-기초-세상을-연결하는-보이지-않는-끈">네트워크 기초: 세상을 연결하는 보이지 않는 끈</h2>
<p>오늘은 네트워크의 가장 기본적인 개념인 노드, 링크, 트래픽, 처리량, 대역폭, RTT에 대해 학습한 내용을 정리해본다.</p>
<h3 id="네트워크란-무엇일까-노드와-링크">네트워크란 무엇일까? 노드와 링크</h3>
<p><strong>네트워크</strong>란 간단히 말해 <strong>노드(Node)</strong>와 <strong>링크(Link)</strong>가 서로 연결되어 리소스를 공유하는 집합을 의미한다.</p>
<ul>
<li><strong>노드</strong>: 네트워크를 구성하는 각 지점을 말한다. 우리가 사용하는 컴퓨터, 스마트폰뿐만 아니라 서버, 라우터, 스위치 같은 네트워크 장비 모두가 노드에 해당한다.</li>
<li><strong>링크</strong>: 노드와 노드를 연결하는 매개체를 뜻한다. 눈에 보이는 랜선 같은 <strong>유선</strong> 연결과 와이파이(Wi-Fi)나 LTE 같은 <strong>무선</strong> 연결이 모두 링크에 속한다. 우리가 와이파이를 통해 인터넷에 접속했다면, 스마트폰(노드)과 공유기(노드)가 무선이라는 링크로 연결된 것이다.</li>
</ul>
<h3 id="데이터의-흐름-트래픽과-처리량">데이터의 흐름: 트래픽과 처리량</h3>
<p>네트워크를 도로망에 비유한다면, 그 위를 달리는 자동차들은 데이터라고 할 수 있다.</p>
<ul>
<li><p><strong>트래픽(Traffic)</strong>: 특정 시간 동안 링크를 통해 흐르는 <strong>데이터의 양</strong>을 말한다. 예를 들어, 우리가 유튜브 영상을 시청하거나 클라우드에서 파일을 내려받을 때 발생하는 데이터의 총량이 바로 트래픽이다. 트래픽이 많아진다는 것은 그만큼 많은 데이터가 네트워크를 통해 오고 간다는 의미이며, 보통 <strong>bps(bits per second)</strong> 단위를 사용한다.</p>
</li>
<li><p><strong>처리량(Throughput)</strong>: 링크를 통해 <strong>성공적으로 전달된 데이터의 양</strong>을 의미한다. 트래픽이 도로에 진입한 모든 자동차의 수라면, 처리량은 막힘없이 목적지에 도착한 자동차의 수에 비유할 수 있다. 아무리 트래픽이 많아도 네트워크가 이를 감당하지 못하면 처리량은 낮아진다. 예를 들어, <strong>동시 접속자가 너무 많아지면</strong> 서버가 모든 요청을 원활하게 처리하지 못해 <strong>처리량이 낮아지는 현상</strong>이 발생한다. 단위는 트래픽과 동일하게 bps를 사용한다.</p>
</li>
</ul>
<h3 id="네트워크의-성능-대역폭과-rtt">네트워크의 성능: 대역폭과 RTT</h3>
<ul>
<li><p><strong>대역폭(Bandwidth)</strong>: 주어진 시간 동안 네트워크 링크를 통해 전송될 수 있는 <strong>데이터의 최대량</strong>을 의미한다. 고속도로의 차선에 비유하면 이해하기 쉽다. 2차선 도로보다 4차선 도로가 더 많은 차를 동시에 수용할 수 있듯이, 대역폭이 넓을수록 한 번에 더 많은 데이터를 전송할 수 있다.</p>
<p>  예를 들어, <strong>100Mbps의 대역폭</strong>을 가진 서버가 있다고 가정해보자. 한 명의 사용자가 평균적으로 <strong>100kbps</strong>의 데이터를 사용한다면, 이 서버는 이론적으로 몇 명의 동시 접속자를 감당할 수 있을까?</p>
<blockquote>
<p>$100 \text{ Mbps} = 100,000 \text{ kbps}$</p>
<p>$100,000 \text{ kbps} / 100 \text{ kbps} = 1000$</p>
</blockquote>
<p>  계산상으로는 약 <strong>1,000명</strong>의 동시 접속자를 지원할 수 있다.</p>
</li>
<li><p><strong>RTT(Round Trip Time)</strong>: <strong>왕복 지연 시간</strong>을 의미하며, 특정 데이터 패킷이 출발지(노드)에서 목적지(노드)까지 갔다가 다시 출발지로 돌아오는 데 걸리는 총 시간을 나타낸다. RTT가 짧을수록 네트워크의 응답 속도가 빠르다는 것을 의미한다. 온라인 게임을 할 때 &#39;핑(Ping)&#39;이 높다고 하는 것이 바로 이 RTT가 긴 상황을 말한다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[의존성 주입과 전략패턴의 차이]]></title>
            <link>https://velog.io/@blight_k/%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85%EA%B3%BC-%EC%A0%84%EB%9E%B5%ED%8C%A8%ED%84%B4%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@blight_k/%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85%EA%B3%BC-%EC%A0%84%EB%9E%B5%ED%8C%A8%ED%84%B4%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Wed, 02 Jul 2025 01:26:51 GMT</pubDate>
            <description><![CDATA[<h2 id="전략-패턴과-의존성-주입의-차이와-공통점">전략 패턴과 의존성 주입의 차이와 공통점</h2>
<p>개발을 하다 보면, “무언가를 쉽게 교체하고 싶다”라는 욕구가 자주 생긴다. 이럴 때 많이 언급되는 개념이 바로 <strong>전략 패턴</strong>과 <strong>의존성 주입(DI)</strong> 이다.</p>
<p>둘 다 쉽게 교체가 가능하다는 점에서 비슷하게 느껴질 수 있다. 하지만 본질적으로 목적과 사용 방식, 그리고 적용되는 맥락이 다르다.</p>
<hr>
<h3 id="전략-패턴이란">전략 패턴이란?</h3>
<p>전략 패턴은 행위(Behavior)에 기반한 디자인 패턴이다.
어떤 컨텍스트(Context) 안에서 알고리즘(혹은 행위)을 런타임에 쉽게 교체할 수 있도록 도와준다.
즉, 인터페이스를 통해 여러 전략(알고리즘, 행위 등)을 정의하고, 실제 사용하는 쪽에서는 구체적인 전략이 아니라 추상화된 전략 인터페이스에만 의존하게 된다.
필요할 때 전략을 갈아끼우듯이 교체할 수 있다.</p>
<p>예를 들어, 결제 방식을 신용카드, 카카오페이, 네이버페이 등으로 자유롭게 바꿔서 사용할 수 있다.</p>
<hr>
<h3 id="의존성-주입di이란">의존성 주입(DI)이란?</h3>
<p>의존성 주입은 어떤 객체가 사용할 의존성을 직접 생성하지 않고, 외부에서 주입받는 방식이다.
쉽게 말해, 클래스 안에서 직접 <code>new</code>로 생성하지 않고, 누군가(프레임워크, 팩토리, 외부 코드 등)가 대신 만들어서 넣어주는 구조다.</p>
<p>이 역시 “무언가를 쉽게 교체한다”는 점에서 전략 패턴과 비슷해 보인다.
의존성을 바꿔치기하거나, 테스트용 목 객체로 교체할 때도 유용하다.</p>
<hr>
<h3 id="공통점과-차이점">공통점과 차이점</h3>
<p>둘 다 “교체 가능성”이라는 공통점이 있다.
하지만 목적과 역할이 다르다.</p>
<ul>
<li><strong>전략 패턴</strong>은 “행위(알고리즘)” 자체를 추상화해서 런타임에 쉽게 교체하는 데 초점을 둔다.</li>
<li><strong>의존성 주입</strong>은 “외부 의존성(객체)”을 직접 만들지 않고 주입받음으로써, 결합도를 낮추고 유연하게 교체하는 데 초점을 둔다.</li>
</ul>
<p>전략 패턴은 GoF(Design Patterns)에서 정의된 명확한 패턴 중 하나다.
의존성 주입은 디자인 패턴이라기보다는 설계 원칙 또는 구조에 가깝다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링부트 필터와 인터셉터의 차이]]></title>
            <link>https://velog.io/@blight_k/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%ED%95%84%ED%84%B0%EC%99%80-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@blight_k/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%ED%95%84%ED%84%B0%EC%99%80-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Fri, 30 May 2025 01:32:12 GMT</pubDate>
            <description><![CDATA[<p>Spring Boot 애플리케이션을 개발하다 보면, HTTP 요청과 응답을 중간에 가로채어 처리해야 하는 경우가 자주 발생한다. 이때 사용하는 대표적인 방법이 바로 <strong>Filter</strong>와 <strong>Interceptor</strong>이다. 두 기능 모두 비슷한 역할을 하지만, 동작하는 시점과 활용 목적이 다르기 때문에 그 차이를 명확히 이해하고 적절한 상황에 적용하는 것이 중요하다.</p>
<hr>
<h2 id="1-filter란">1. Filter란?</h2>
<p><strong>Filter</strong>는 서블릿 API의 일부로, Spring의 <code>DispatcherServlet</code>에 도달하기 <strong>이전</strong> 단계에서 모든 요청을 처리한다. 즉, Spring Framework의 처리 흐름에 진입하기 전에 동작하게 된다.</p>
<h3 id="filter의-주요-활용-예시">Filter의 주요 활용 예시</h3>
<ul>
<li><strong>로깅</strong>: 요청 및 응답 정보를 로그로 남겨 디버깅 및 모니터링에 활용한다.</li>
<li><strong>GZIP 압축</strong>: 응답 데이터를 압축하여 전송 속도를 개선한다.</li>
<li><strong>문자 인코딩 처리</strong>: UTF-8 등 통일된 인코딩 설정을 적용한다.</li>
<li><strong>보안 검사</strong>: 방화벽 설정, 속도 제한, 접근 제어 등의 전처리를 수행한다.</li>
<li><strong>요청/응답 수정</strong>: 예를 들어 데이터 래핑, 캐싱 처리, XSS 필터링을 수행한다.</li>
</ul>
<h3 id="filter-구현-예시">Filter 구현 예시</h3>
<pre><code class="language-java">@Component
public class LoggingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        System.out.println(&quot;Request received: &quot; + request.getRemoteAddr());
        chain.doFilter(request, response); // 다음 필터 또는 서블릿으로 전달
        System.out.println(&quot;Response sent.&quot;);
    }
}</code></pre>
<ul>
<li>모든 요청에 적용되며, 정적 리소스(CSS, JS, 이미지 등)도 포함된다.</li>
<li>서블릿 컨테이너 수준에서 동작하기 때문에 <strong>Spring Bean이나 Controller에 직접 접근할 수 없다</strong>.</li>
</ul>
<hr>
<h2 id="2-interceptor란">2. Interceptor란?</h2>
<p><strong>Interceptor</strong>는 Spring MVC의 구성 요소로, Spring 내부의 DispatcherServlet이 요청을 Controller로 전달하기 전후에 작동한다.</p>
<h3 id="interceptor의-주요-활용-예시">Interceptor의 주요 활용 예시</h3>
<ul>
<li><strong>인증 및 권한 검사</strong>: 로그인 상태 확인, 권한 검증 등의 로직을 수행한다.</li>
<li><strong>실행 시간 측정</strong>: 컨트롤러 처리 시간 등의 퍼포먼스 모니터링에 활용한다.</li>
<li><strong>Model/View 수정</strong>: 응답 전 공통 데이터를 삽입하거나 뷰 모델을 수정한다.</li>
<li><strong>공통 속성 추가</strong>: 사용자 정보 등 공통 데이터를 모든 응답에 포함시킨다.</li>
</ul>
<h3 id="interceptor-구현-예시">Interceptor 구현 예시</h3>
<pre><code class="language-java">@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println(&quot;Checking authentication...&quot;);
        return true; // 컨트롤러로 요청 계속 전달
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) {
        System.out.println(&quot;Controller executed.&quot;);
    }
}</code></pre>
<ul>
<li><strong>Spring MVC Controller에만 적용되며</strong>, 정적 리소스에는 적용되지 않는다.</li>
<li>Spring ApplicationContext 내부에서 작동하므로 <strong>Spring Bean을 주입(@Autowired)받아 사용할 수 있다</strong>.</li>
</ul>
<hr>
<h2 id="3-filter-vs-interceptor-주요-차이점">3. Filter vs Interceptor 주요 차이점</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>Filter</th>
<th>Interceptor</th>
</tr>
</thead>
<tbody><tr>
<td>실행 시점</td>
<td>DispatcherServlet 이전</td>
<td>Controller 실행 전/후</td>
</tr>
<tr>
<td>적용 범위</td>
<td>모든 요청 (정적 리소스 포함)</td>
<td>Spring MVC Controller 요청</td>
</tr>
<tr>
<td>Spring Bean 접근</td>
<td>❌ 불가능</td>
<td>✅ 가능</td>
</tr>
<tr>
<td>요청 타입</td>
<td>전체 HTTP 요청</td>
<td>Controller 요청만</td>
</tr>
<tr>
<td>요청/응답 수정</td>
<td>헤더, 인코딩, 압축 등 가능</td>
<td>Model, View 수정 가능 (응답 바디 직접 수정은 어려움)</td>
</tr>
<tr>
<td>주요 용도</td>
<td>보안 필터, 로깅, 인코딩</td>
<td>인증, 권한 검사, 컨트롤러 후처리</td>
</tr>
</tbody></table>
<hr>
<h2 id="4-언제-무엇을-써야-할까">4. 언제 무엇을 써야 할까?</h2>
<h3 id="filter를-사용해야-할-때">Filter를 사용해야 할 때</h3>
<ul>
<li>모든 요청(정적 리소스 포함)에 대해 <strong>로깅</strong>, <strong>보안 검사</strong>, <strong>인코딩 처리</strong> 등을 적용하고자 할 때</li>
<li><strong>응답 압축(GZIP)</strong> 등의 기능이 필요한 경우</li>
<li>Spring Bean을 사용하지 않고 순수 서블릿 수준에서 처리할 경우</li>
</ul>
<h3 id="interceptor를-사용해야-할-때">Interceptor를 사용해야 할 때</h3>
<ul>
<li>컨트롤러 접근 전에 <strong>인증/인가 검사</strong>가 필요한 경우</li>
<li>컨트롤러 실행 시간을 측정하거나 로그를 남기고 싶은 경우</li>
<li>응답 전 공통 데이터(Model)를 삽입하고 싶은 경우</li>
<li>**Spring Bean(Service, Repository 등)**을 활용한 비즈니스 로직이 필요한 경우</li>
</ul>
<hr>
<h2 id="5-요약">5. 요약</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>Filter</th>
<th>Interceptor</th>
</tr>
</thead>
<tbody><tr>
<td>레벨</td>
<td>서블릿 레벨</td>
<td>Spring MVC 레벨</td>
</tr>
<tr>
<td>적용 대상</td>
<td>전체 HTTP 요청</td>
<td>Spring Controller 요청</td>
</tr>
<tr>
<td>Spring Bean 접근</td>
<td>❌ 불가능</td>
<td>✅ 가능</td>
</tr>
<tr>
<td>대표 용도</td>
<td>인코딩, 압축, 보안</td>
<td>인증, 로깅, 모델 처리</td>
</tr>
</tbody></table>
<h3 id="💡-선택-기준-요약">💡 선택 기준 요약</h3>
<ul>
<li><strong>HTTP 요청 자체를 조작해야 한다면 → Filter</strong></li>
<li><strong>Controller 로직 전후로 로직을 삽입하고 싶다면 → Interceptor</strong></li>
</ul>
<hr>
<h2 id="마무리">마무리</h2>
<p>Spring Boot에서 HTTP 흐름을 제어해야 할 때 Filter와 Interceptor는 매우 유용한 도구이다. 기능적으로 겹치는 부분도 있지만, <strong>실행 시점과 활용 목적이 분명히 다르기 때문에 상황에 따라 적절하게 선택하여 사용해야 한다.</strong></p>
<p>실무에서는 이 둘을 <strong>조합하여 사용하는 경우도 많으므로</strong>, 명확한 이해를 바탕으로 설계하는 것이 중요하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[컨텍스트란 ?]]></title>
            <link>https://velog.io/@blight_k/%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%9E%80</link>
            <guid>https://velog.io/@blight_k/%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%9E%80</guid>
            <pubDate>Fri, 16 May 2025 14:19:59 GMT</pubDate>
            <description><![CDATA[<h1 id="컨텍스트context란-무엇인가-쉽게-이해해보자">컨텍스트(Context)란 무엇인가? 쉽게 이해해보자</h1>
<p>개발 공부를 하다 보면 자주 마주치는 단어 중 하나가 **&quot;컨텍스트(context)&quot;**입니다. 어렵게 느껴지지만, 우리 일상 속에서 이미 자주 경험하고 있는 개념입니다.</p>
<h2 id="카페에서-커피-주문할-때의-컨텍스트">카페에서 커피 주문할 때의 컨텍스트</h2>
<p>여러분이 카페에 들어가서 &quot;아이스 아메리카노 하나 주세요&quot;라고 말한다고 해보겠습니다. 이때 점원은 여러분의 상태나 주변 정보를 바탕으로 행동합니다. 예를 들어:</p>
<ul>
<li>나(고객)가 누구인지</li>
<li>혼자인지 여럿인지</li>
<li>머그잔인지 테이크아웃인지</li>
</ul>
<p>이 모든 정보들이 대화의 <strong>컨텍스트</strong>입니다. 즉, 단순히 말로 표현하지 않았더라도 상황(context) 속에서 유추할 수 있는 정보들 입니다.</p>
<h2 id="개발에서의-컨텍스트란">개발에서의 컨텍스트란?</h2>
<p>소프트웨어에서의 컨텍스트도 이와 비슷합니다. 어떤 작업이나 상태를 처리하기 위해 <strong>필요한 최소한의 정보</strong>를 뜻합니다. 예를 들어:</p>
<ul>
<li>로그인한 사용자의 정보</li>
<li>현재 선택된 언어</li>
<li>테마(다크 모드인지 라이트 모드인지)</li>
<li>현재 위치한 페이지나 경로</li>
</ul>
<p>이런 정보들을 <strong>컨텍스트</strong>라고 부르고, 이 정보들을 기준으로 UI나 로직이 다르게 동작할 수 있습니다.</p>
<h2 id="os에서의-컨텍스트-컨텍스트-스위칭">OS에서의 컨텍스트: 컨텍스트 스위칭</h2>
<p>운영체제에서는 여러 프로세스가 CPU를 번갈아 사용할 수 있도록 하는데, 이때 각각의 작업 상태(레지스터, 메모리 위치 등)를 저장하고 불러오는 과정을 **컨텍스트 스위칭(context switching)**이라고 합니다.</p>
<h2 id="http에서도-컨텍스트">HTTP에서도 컨텍스트?</h2>
<p>HTTP 통신을 할 때도 컨텍스트가 존재합니다. 대표적인 예가 <strong>HTTP Header</strong>입니다. 예를 들어:</p>
<pre><code class="language-http">Authorization: Bearer eyJhbGciOi...
Accept-Language: ko-KR</code></pre>
<p>이런 헤더는 요청을 보낼 때 클라이언트의 상태나 조건을 서버에 전달하는 <strong>컨텍스트 정보</strong>입니다.</p>
<h2 id="react에서의-context-api">React에서의 Context API</h2>
<p>React에서는 <strong>Context API</strong>를 통해 컴포넌트 트리 전체에 데이터를 쉽게 전달할 수 있습니다. props drilling 없이도 여러 컴포넌트에서 공유해야 하는 전역적인 상태(예: 테마, 로그인 정보)를 관리할 수 있습니다.</p>
<pre><code class="language-tsx">const ThemeContext = createContext(&quot;light&quot;);

function App() {
  return (
    &lt;ThemeContext.Provider value=&quot;dark&quot;&gt;
      &lt;Toolbar /&gt;
    &lt;/ThemeContext.Provider&gt;
  );
}</code></pre>
<p>여기서 <code>ThemeContext</code>는 현재 UI의 상태에 따라 다르게 렌더링되도록 돕는 <strong>컨텍스트 저장소</strong> 역할을 합니다.</p>
<hr>
<h2 id="마무리-컨텍스트는-상황-정보다">마무리: 컨텍스트는 &quot;상황 정보&quot;다</h2>
<p>정리하자면, <strong>컨텍스트는 어떤 작업을 하기 위해 필요한 주변 정보</strong>입니다. 꼭 IT 용어가 아니라도, 우리는 일상에서 컨텍스트를 바탕으로 대화하고, 판단하고, 행동하고 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flux 패턴이란 ?]]></title>
            <link>https://velog.io/@blight_k/Flux-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@blight_k/Flux-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sun, 11 May 2025 09:32:02 GMT</pubDate>
            <description><![CDATA[<h1 id="flux-패턴이란-복잡한-상태-관리를-단방향으로-해결한다">Flux 패턴이란? 복잡한 상태 관리를 단방향으로 해결한다</h1>
<p>웹 애플리케이션이 복잡해지면 상태(state) 관리가 점점 어려워진다. 특히 MVC 패턴에서는 <code>Model</code>과 <code>View</code> 사이의 관계가 많아질수록 <strong>데이터 흐름이 꼬이고</strong>, <strong>상태 추적이 어려워지는 문제</strong>에 직면하게 된다.</p>
<p>이러한 문제를 해결하기 위해 <strong>Facebook</strong>에서 제안한 아키텍처가 바로 <strong>Flux 패턴</strong>이다.</p>
<hr>
<h2 id="flux-패턴이란">Flux 패턴이란?</h2>
<p>Flux는 <strong>단방향 데이터 흐름</strong>을 기반으로 상태를 예측 가능하게 관리하는 아키텍처 패턴이다. MVC처럼 컴포넌트가 서로 참조하는 구조가 아니라, 명확한 흐름을 가진 파이프라인 구조를 지닌다.</p>
<p>Flux의 핵심 구성은 아래와 같다:</p>
<pre><code>Action → Dispatcher → Store → View</code></pre><hr>
<h2 id="flux의-구조">Flux의 구조</h2>
<h3 id="1-action">1. Action</h3>
<p><code>Action</code>은 사용자의 이벤트(예: 버튼 클릭)나 API 응답처럼 애플리케이션에서 발생하는 <strong>모든 의도를 명시적으로 표현</strong>한다.</p>
<pre><code class="language-ts">// action.ts
export const markAsRead = (messageId: number) =&gt; ({
  type: &#39;MARK_AS_READ&#39;,
  payload: { id: messageId },
});</code></pre>
<h3 id="2-dispatcher">2. Dispatcher</h3>
<p><code>Dispatcher</code>는 모든 액션을 <strong>중앙 집중식으로 처리</strong>하는 허브 역할을 한다. 어떤 <code>Action</code>이 발생했을 때, 어떤 <code>Store</code>에게 전달할지 결정한다.</p>
<pre><code class="language-ts">// dispatcher.ts
import { Dispatcher } from &#39;flux&#39;;

const dispatcher = new Dispatcher();
export default dispatcher;</code></pre>
<h3 id="3-store">3. Store</h3>
<p><code>Store</code>는 <strong>상태(state)를 관리하는 계층</strong>이다. <code>Action</code>을 받아 내부 상태를 갱신한 뒤, View에 알려준다.</p>
<pre><code class="language-ts">// messageStore.ts
import { EventEmitter } from &#39;events&#39;;
import dispatcher from &#39;./dispatcher&#39;;

class MessageStore extends EventEmitter {
  private messages: { id: number; read: boolean }[] = [];

  getMessages() {
    return this.messages;
  }

  handleActions(action: any) {
    switch (action.type) {
      case &#39;MARK_AS_READ&#39;:
        this.messages = this.messages.map((msg) =&gt;
          msg.id === action.payload.id ? { ...msg, read: true } : msg
        );
        this.emit(&#39;change&#39;);
        break;
    }
  }
}

const messageStore = new MessageStore();
dispatcher.register(messageStore.handleActions.bind(messageStore));
export default messageStore;</code></pre>
<h3 id="4-view">4. View</h3>
<p><code>View</code>는 <code>Store</code>로부터 상태를 받아 화면을 렌더링한다. 단방향이기 때문에 View → Store로 직접 접근하지 않고, 오직 Action을 통해 상태를 변경한다.</p>
<pre><code class="language-tsx">// MessageList.tsx (React 기준)
import { useEffect, useState } from &#39;react&#39;;
import messageStore from &#39;./messageStore&#39;;
import { markAsRead } from &#39;./action&#39;;
import dispatcher from &#39;./dispatcher&#39;;

export function MessageList() {
  const [messages, setMessages] = useState(messageStore.getMessages());

  useEffect(() =&gt; {
    const onChange = () =&gt; setMessages(messageStore.getMessages());
    messageStore.on(&#39;change&#39;, onChange);
    return () =&gt; messageStore.removeListener(&#39;change&#39;, onChange);
  }, []);

  const handleClick = (id: number) =&gt; {
    dispatcher.dispatch(markAsRead(id));
  };

  return (
    &lt;ul&gt;
      {messages.map((msg) =&gt; (
        &lt;li key={msg.id} onClick={() =&gt; handleClick(msg.id)}&gt;
          {msg.read ? &lt;s&gt;읽음&lt;/s&gt; : &#39;읽지 않음&#39;}
        &lt;/li&gt;
      ))}
    &lt;/ul&gt;
  );
}</code></pre>
<hr>
<h2 id="왜-mvc가-아닌-flux인가">왜 MVC가 아닌 Flux인가?</h2>
<p>MVC는 규모가 작을 때는 효율적이지만, 애플리케이션이 커질수록 <strong>Model과 View 간의 의존성과 데이터 흐름이 복잡해지는 경향</strong>이 있다. 특히 &quot;읽음 / 읽지 않음&quot; 같은 상태 변경이 여러 컴포넌트에 영향을 줄 때, Model 간 동기화가 어렵고 <strong>버그 추적도 복잡해진다.</strong></p>
<p>반면 Flux는 모든 데이터 흐름을 <strong>Action → Dispatcher → Store → View</strong> 순서로 고정하기 때문에 다음과 같은 장점이 생긴다.</p>
<hr>
<h2 id="flux-패턴의-장점">Flux 패턴의 장점</h2>
<ul>
<li><strong>단방향 데이터 흐름</strong>: 어디에서 상태가 변경됐는지 추적하기 쉬움</li>
<li><strong>상태 일관성 향상</strong>: 하나의 Store에서만 관리하므로 동기화 문제 해결</li>
<li><strong>디버깅과 테스팅이 쉬움</strong>: 액션 기반으로 테스트 가능</li>
<li><strong>유지보수 용이</strong>: 컴포넌트 간 직접 참조가 없어 결합도가 낮음</li>
</ul>
<hr>
<h2 id="redux는-flux-패턴의-진화-버전이다">Redux는 Flux 패턴의 진화 버전이다</h2>
<p>많은 React 개발자들에게 친숙한 <strong>Redux</strong>는 사실 Flux 패턴을 따르는 라이브러리다.
Redux는 Flux의 복잡한 Dispatcher를 없애고 <code>Reducer</code>와 <code>Store</code>만으로 상태 관리를 단순화했다.</p>
<pre><code class="language-ts">// Redux의 간단한 reducer 예시
function messageReducer(state = [], action) {
  switch (action.type) {
    case &#39;MARK_AS_READ&#39;:
      return state.map((msg) =&gt;
        msg.id === action.payload.id ? { ...msg, read: true } : msg
      );
    default:
      return state;
  }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring MVC 패턴 적용 사례]]></title>
            <link>https://velog.io/@blight_k/Spring-MVC-%ED%8C%A8%ED%84%B4-%EC%A0%81%EC%9A%A9-%EC%82%AC%EB%A1%80</link>
            <guid>https://velog.io/@blight_k/Spring-MVC-%ED%8C%A8%ED%84%B4-%EC%A0%81%EC%9A%A9-%EC%82%AC%EB%A1%80</guid>
            <pubDate>Sun, 11 May 2025 09:22:53 GMT</pubDate>
            <description><![CDATA[<h1 id="spring-web-mvc-dispatcherservlet의-요청-처리-흐름-정리">Spring Web MVC: DispatcherServlet의 요청 처리 흐름 정리</h1>
<p>스프링 프레임워크는 다양한 모듈로 구성된 아키텍처를 기반으로 동작한다. 그중 <strong>웹 애플리케이션을 구축할 때 핵심 역할</strong>을 담당하는 것이 <code>spring-web</code> 모듈이며, 이 모듈에서 가장 중심이 되는 컴포넌트는 바로 <code>DispatcherServlet</code>이다.</p>
<p>이번 글에서는 <strong>Spring Web MVC에서 DispatcherServlet이 어떻게 요청을 처리하는지</strong> MVC 패턴을 중심으로 하나씩 살펴보도록 한다.</p>
<hr>
<h2 id="🧭-dispatcherservlet이란">🧭 DispatcherServlet이란?</h2>
<p><code>DispatcherServlet</code>은 프론트 컨트롤러(Front Controller) 패턴을 구현한 서블릿으로, <strong>모든 HTTP 요청의 진입점</strong>이 된다. 웹 애플리케이션에서 클라이언트의 요청을 받아 적절한 컨트롤러로 위임하고, 최종적으로 View를 만들어 사용자에게 응답을 반환하는 역할을 한다.</p>
<p>Spring Boot 프로젝트를 만들면 기본적으로 이 DispatcherServlet이 자동으로 등록되어 있다.</p>
<hr>
<h2 id="요청-처리-흐름-spring-mvc-아키텍처">요청 처리 흐름: Spring MVC 아키텍처</h2>
<p>Spring Web은 전통적인 <strong>MVC(Model-View-Controller)</strong> 패턴을 따른다. 이를 기반으로 <code>DispatcherServlet</code>의 요청 처리 흐름을 살펴보면 다음과 같다.</p>
<pre><code>Client -&gt; DispatcherServlet -&gt; HandlerMapping -&gt; Controller 
       -&gt; Business Logic / Service -&gt; Model -&gt; ViewResolver -&gt; View</code></pre><h3 id="1-클라이언트-요청-수신">1. 클라이언트 요청 수신</h3>
<p>사용자의 브라우저에서 <code>GET /hello</code> 와 같은 요청이 들어오면 이 요청은 <code>DispatcherServlet</code>이 가장 먼저 받는다.</p>
<pre><code class="language-txt">GET /hello HTTP/1.1</code></pre>
<h3 id="2-handlermapping을-통해-컨트롤러-찾기">2. HandlerMapping을 통해 컨트롤러 찾기</h3>
<p><code>DispatcherServlet</code>은 요청을 처리할 적절한 컨트롤러를 찾기 위해 <strong>HandlerMapping</strong>에게 질의한다.
Spring에서는 <code>@RequestMapping</code>, <code>@GetMapping</code>, <code>@PostMapping</code> 등의 어노테이션을 기준으로 어떤 컨트롤러 메서드가 이 요청을 처리할 수 있는지 결정한다.</p>
<pre><code class="language-java">@RestController
public class HelloController {

    @GetMapping(&quot;/hello&quot;)
    public String sayHello() {
        return &quot;hello&quot;;
    }
}</code></pre>
<p>이 경우 <code>/hello</code> 요청은 <code>sayHello()</code> 메서드에 매핑된다.</p>
<h3 id="3-컨트롤러에서-비즈니스-로직-처리">3. 컨트롤러에서 비즈니스 로직 처리</h3>
<p>컨트롤러는 필요하다면 서비스 레이어나 데이터베이스에 접근해서 비즈니스 로직을 처리한다.</p>
<pre><code class="language-java">@Service
public class HelloService {
    public String getMessage() {
        return &quot;Hello from Service&quot;;
    }
}

@RestController
@RequiredArgsConstructor
public class HelloController {

    private final HelloService helloService;

    @GetMapping(&quot;/hello&quot;)
    public String sayHello() {
        return helloService.getMessage();
    }
}</code></pre>
<h3 id="4-모델model에-데이터-저장">4. 모델(Model)에 데이터 저장</h3>
<p>컨트롤러에서 데이터를 준비하면, 이를 <code>Model</code> 객체에 담아 View로 전달할 수 있다.
(만약 <code>@RestController</code>가 아닌 <code>@Controller</code>를 사용하는 경우, 템플릿 엔진을 통한 View 렌더링이 가능하다.)</p>
<pre><code class="language-java">@Controller
public class GreetingController {

    @GetMapping(&quot;/greet&quot;)
    public String greet(Model model) {
        model.addAttribute(&quot;name&quot;, &quot;Spring&quot;);
        return &quot;greeting&quot;; // View 이름
    }
}</code></pre>
<h3 id="5-viewresolver를-통해-view-결정">5. ViewResolver를 통해 View 결정</h3>
<p>컨트롤러가 반환한 문자열(&quot;greeting&quot;)은 <strong>ViewResolver</strong>에 의해 실제 뷰 파일로 매핑된다.
예를 들어, <code>Thymeleaf</code>를 사용하고 있다면 <code>resources/templates/greeting.html</code> 파일을 찾아 렌더링한다.</p>
<pre><code class="language-html">&lt;!-- resources/templates/greeting.html --&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;body&gt;
    &lt;h1&gt;Hello, [[${name}]]!&lt;/h1&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 id="6-view-렌더링-및-사용자-응답">6. View 렌더링 및 사용자 응답</h3>
<p>최종적으로 View가 렌더링되어 사용자에게 HTML 응답으로 전송된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ReactNode와 ReactElement의 차이]]></title>
            <link>https://velog.io/@blight_k/ReactNode%EC%99%80-ReactElement%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@blight_k/ReactNode%EC%99%80-ReactElement%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Fri, 09 May 2025 04:50:24 GMT</pubDate>
            <description><![CDATA[<h2 id="타입의-범위">타입의 범위</h2>
<p>세 가지 타입은 아래와 같이 포괄 관계를 가진다:</p>
<pre><code>ReactNode &gt; ReactElement ≒ JSX.Element</code></pre><ul>
<li><code>ReactNode</code>: 가장 포괄적인 타입. 문자열, 숫자, boolean, <code>null</code>, <code>undefined</code>, <code>ReactElement</code>, <code>ReactFragment</code>, <code>ReactPortal</code> 등 모두 포함된다.</li>
<li><code>ReactElement</code>: 컴포넌트의 반환값으로 가장 많이 사용되는 타입. JSX의 결과물이기도 하다.</li>
<li><code>JSX.Element</code>: <code>ReactElement&lt;any, any&gt;</code>의 타입 alias로 거의 같은 개념이다.</li>
</ul>
<hr>
<h2 id="reactelement란">ReactElement란?</h2>
<p><code>ReactElement</code>는 컴포넌트가 반환하는 객체의 형태를 타입으로 정의한 것이다.</p>
<pre><code class="language-ts">interface ReactElement&lt;P = any, T extends string | JSXElementConstructor&lt;any&gt; = string | JSXElementConstructor&lt;any&gt;&gt; {
  type: T;
  props: P;
  key: Key | null;
}</code></pre>
<p>즉, JSX 문법을 사용하면 내부적으로 <code>React.createElement()</code> 함수가 호출되어 <code>ReactElement</code> 객체를 생성한다.</p>
<p>예를 들어 다음 JSX 코드를:</p>
<pre><code class="language-tsx">&lt;CustomButton disabled&gt;버튼&lt;/CustomButton&gt;</code></pre>
<p>바벨은 아래처럼 트랜스파일링 한다:</p>
<pre><code class="language-js">React.createElement(CustomButton, { disabled: true }, &quot;버튼&quot;)</code></pre>
<hr>
<h2 id="jsxelement란">JSX.Element란?</h2>
<p><code>JSX.Element</code>는 전역 <code>JSX</code> 네임스페이스에 정의되어 있으며, <code>React.ReactElement&lt;any, any&gt;</code>와 같다.</p>
<pre><code class="language-ts">declare global {
  namespace JSX {
    interface Element extends React.ReactElement&lt;any, any&gt; {}
  }
}</code></pre>
<p>따라서 함수형 컴포넌트에서 반환하는 타입으로 <code>JSX.Element</code> 또는 <code>ReactElement</code>를 사용할 수 있다. 사실상 이 둘은 동일하다고 봐도 무방하다.</p>
<pre><code class="language-tsx">function MyComponent(): JSX.Element {
  return &lt;div&gt;Hello&lt;/div&gt;;
}</code></pre>
<hr>
<h2 id="reactnode란">ReactNode란?</h2>
<p><code>ReactNode</code>는 JSX에서 표현할 수 있는 모든 값을 포함하는 타입이다. 대표적으로 다음과 같은 타입들이 포함된다:</p>
<ul>
<li><code>string</code>, <code>number</code></li>
<li><code>boolean</code> (렌더링되지 않음)</li>
<li><code>null</code>, <code>undefined</code></li>
<li><code>ReactElement</code></li>
<li><code>ReactFragment</code> (여러 요소를 묶는 용도)</li>
<li><code>ReactPortal</code> (DOM 외부로 렌더링)</li>
</ul>
<p>예를 들어 <code>children</code> 타입에 가장 흔하게 사용되는 타입이다:</p>
<pre><code class="language-ts">type PropsWithChildren&lt;P&gt; = P &amp; { children?: ReactNode };</code></pre>
<pre><code class="language-tsx">function Layout({ children }: { children: ReactNode }) {
  return &lt;div&gt;{children}&lt;/div&gt;;
}</code></pre>
<hr>
<h2 id="언제-어떤-타입을-써야-할까">언제 어떤 타입을 써야 할까?</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>타입 추천</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>함수형 컴포넌트 반환값</td>
<td><code>ReactElement</code> or <code>JSX.Element</code></td>
<td>대부분 JSX를 반환하므로</td>
</tr>
<tr>
<td>children prop</td>
<td><code>ReactNode</code></td>
<td>텍스트, 태그, 배열 등 모든 표현 가능</td>
</tr>
<tr>
<td>UI를 동적으로 조립할 때</td>
<td><code>ReactNode</code></td>
<td>배열, 조건부 렌더링 등을 지원해야 함</td>
</tr>
<tr>
<td>특정 엘리먼트를 명확히 감쌀 때</td>
<td><code>ReactElement</code></td>
<td><code>React.cloneElement()</code> 등과 같이 엘리먼트 자체를 다룰 때</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[MVC / MVP / MVVM 패턴이란 ?]]></title>
            <link>https://velog.io/@blight_k/MVC-MVP-MVVM-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@blight_k/MVC-MVP-MVVM-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sat, 03 May 2025 08:05:24 GMT</pubDate>
            <description><![CDATA[<h2 id="mvc-패턴model---view---controller">MVC 패턴(Model - View - Controller)</h2>
<p>MVC 패턴은 애플리케이션을 <strong>모델(Model)</strong>, <strong>뷰(View)</strong>, <strong>컨트롤러(Controller)</strong>의 세 가지 역할로 나누어 구성하는 디자인 패턴입니다.</p>
<h3 id="●-모델model">● 모델(Model)</h3>
<p>모델은 애플리케이션의 핵심 데이터와 그 데이터를 처리하는 로직을 담당합니다. 데이터베이스, 상수, 변수 등이 이에 해당하며, 컨트롤러를 통해 데이터를 생성, 수정, 삭제합니다. 뷰나 컨트롤러에 의존하지 않고 독립적으로 존재합니다.</p>
<h3 id="●-뷰view">● 뷰(View)</h3>
<p>뷰는 사용자 인터페이스(UI)를 구성합니다. 예를 들어 입력 박스, 체크박스, 버튼과 같이 사용자가 직접 눈으로 보거나 상호작용하는 요소들이 뷰에 해당합니다. 뷰는 데이터를 직접 처리하지 않고, 데이터를 모델로부터 전달받아 화면에 표시하는 역할을 합니다.</p>
<h3 id="●-컨트롤러controller">● 컨트롤러(Controller)</h3>
<p>컨트롤러는 뷰와 모델 사이를 중재하는 역할을 합니다. 사용자의 입력 이벤트(클릭, 입력 등)를 처리하고, 적절한 모델을 갱신하거나 뷰를 업데이트합니다. 메인 로직을 처리하는 중심 축이라고 볼 수 있습니다.</p>
<hr>
<h3 id="mvc-패턴의-장점">MVC 패턴의 장점</h3>
<ol>
<li>역할이 명확히 분리되어 있어 유지보수 및 개발 효율이 높습니다.</li>
<li>뷰와 모델이 분리되어 있어 재사용성과 테스트가 용이합니다.</li>
<li>규모가 큰 애플리케이션에 적합하며 확장성이 좋습니다.</li>
</ol>
<h3 id="mvc-패턴의-단점">MVC 패턴의 단점</h3>
<ul>
<li>애플리케이션이 복잡해질수록 <strong>모델과 뷰 사이의 간접적인 의존 관계</strong>가 생기고, 구조가 뒤얽힐 수 있습니다. 특히 뷰가 모델을 직접 참조하거나 변경하게 되면 의존성이 증가하게 됩니다.</li>
</ul>
<h3 id="대표적인-프레임워크">대표적인 프레임워크</h3>
<ul>
<li>Java: <strong>Spring Framework</strong></li>
<li>Python: <strong>Django</strong></li>
<li>JavaScript: <strong>Express.js</strong></li>
</ul>
<hr>
<h2 id="mvp-패턴model---view---presenter">MVP 패턴(Model - View - Presenter)</h2>
<p>MVP 패턴은 MVC 패턴에서 컨트롤러가 **프레젠터(Presenter)**로 대체된 구조입니다. 가장 큰 특징은 **뷰(View)**와 **프레젠터(Presenter)**가 <strong>1:1 관계</strong>를 가진다는 점입니다.</p>
<h3 id="●-presenter">● Presenter</h3>
<p>Presenter는 사용자 인터페이스 로직을 처리하며, 뷰와 모델 간의 완전한 분리를 가능하게 합니다. 뷰는 가능한 한 단순하게 유지되며, 모든 로직은 프레젠터가 담당합니다. 뷰는 프레젠터에 대한 인터페이스만 알고 있어 테스트가 용이합니다.</p>
<h3 id="mvp-패턴의-특징">MVP 패턴의 특징</h3>
<ul>
<li>뷰와 프레젠터가 강한 결합을 가지기 때문에 뷰당 프레젠터가 하나씩 필요합니다.</li>
<li>테스트 코드 작성이 수월하며, 복잡한 UI 로직을 분리하기에 좋습니다.</li>
</ul>
<hr>
<h2 id="mvvm-패턴model---view---viewmodel">MVVM 패턴(Model - View - ViewModel)</h2>
<p>MVVM 패턴은 MVC 패턴에서 컨트롤러가 <strong>뷰모델(ViewModel)</strong>로 대체된 구조입니다. <strong>뷰(View)</strong>와 <strong>뷰모델(ViewModel)</strong> 간에는 <strong>양방향 데이터 바인딩</strong>이 존재합니다. 이 구조는 특히 UI와 데이터 상태가 밀접하게 연동되는 애플리케이션에 적합합니다.</p>
<h3 id="viewmodel">ViewModel</h3>
<p>ViewModel은 뷰의 상태와 동작을 관리하며, 뷰와 모델 간의 중간 매개체 역할을 합니다. 뷰모델은 커맨드(Command)와 바인딩(Binding) 개념을 통해 뷰와 동기화됩니다.</p>
<ul>
<li><strong>데이터 바인딩</strong>: 모델의 데이터가 변경되면 자동으로 뷰에 반영되고, 뷰의 입력도 모델에 자동으로 전달됩니다.</li>
<li><strong>커맨드</strong>: 버튼 클릭 등 여러 UI 요소에 대한 이벤트 처리를 하나의 액션 단위로 묶는 기법입니다.</li>
</ul>
<h3 id="mvvm-패턴의-장점">MVVM 패턴의 장점</h3>
<ul>
<li>코드의 <strong>분리도</strong>가 높고, 뷰에 대한 테스트가 매우 용이합니다.</li>
<li>데이터 바인딩을 통해 코드량이 줄고 생산성이 향상됩니다.</li>
</ul>
<h3 id="mvvm-패턴의-단점">MVVM 패턴의 단점</h3>
<ul>
<li>데이터 바인딩을 제대로 이해하지 않으면 디버깅이 어려울 수 있습니다.</li>
<li>단순한 프로젝트에 적용할 경우 오히려 복잡도가 증가할 수 있습니다.</li>
</ul>
<h3 id="대표적인-프레임워크-1">대표적인 프레임워크</h3>
<ul>
<li>JavaScript: <strong>Vue.js</strong>, <strong>Angular</strong></li>
<li>.NET: <strong>WPF</strong>, <strong>Xamarin</strong></li>
<li>Kotlin: <strong>Jetpack Compose</strong>, <strong>Android ViewModel</strong></li>
</ul>
<hr>
<table>
<thead>
<tr>
<th>패턴</th>
<th>핵심 구조</th>
<th>특징</th>
<th>대표 프레임워크</th>
</tr>
</thead>
<tbody><tr>
<td>MVC</td>
<td>Model - View - Controller</td>
<td>역할 분리, 대규모에 적합</td>
<td>Spring, Django</td>
</tr>
<tr>
<td>MVP</td>
<td>Model - View - Presenter</td>
<td>테스트 용이, 강한 1:1 관계</td>
<td>Android MVP</td>
</tr>
<tr>
<td>MVVM</td>
<td>Model - View - ViewModel</td>
<td>양방향 바인딩, UI 중심 앱에 적합</td>
<td>Vue, WPF, Jetpack Compose</td>
</tr>
</tbody></table>
<p>각 패턴은 목적과 사용하는 플랫폼에 따라 다르게 적용됩니다. 프로젝트의 규모, 테스트 요구사항, UI 복잡성 등을 고려하여 적절한 아키텍처 패턴을 선택하는 것이 중요합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프록시 패턴이란?]]></title>
            <link>https://velog.io/@blight_k/%ED%94%84%EB%A1%9D%EC%8B%9C-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@blight_k/%ED%94%84%EB%A1%9D%EC%8B%9C-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sat, 03 May 2025 07:54:39 GMT</pubDate>
            <description><![CDATA[<h1 id="프록시-패턴proxy-pattern이란">프록시 패턴(Proxy Pattern)이란?</h1>
<p>프록시(Proxy) 패턴은 <strong>어떤 객체에 접근하기 전 그 흐름을 가로채어</strong> 접근을 <strong>제어하거나, 필터링하거나, 수정하는 역할을 하는 디자인 패턴</strong>입니다.
쉽게 말하면, <strong>인터페이스와 실제 객체 사이에 중간 계층을 둠으로써</strong>, 직접 접근을 막고 필요한 작업을 대신 수행하도록 하는 방식입니다.</p>
<hr>
<h2 id="프록시-패턴의-구조">프록시 패턴의 구조</h2>
<p>프록시 패턴은 다음과 같은 구성 요소를 가집니다:</p>
<ul>
<li><strong>RealSubject (실제 객체)</strong>: 클라이언트가 궁극적으로 사용하려는 대상 객체입니다.</li>
<li><strong>Proxy (프록시 객체)</strong>: RealSubject와 동일한 인터페이스를 구현하며, 클라이언트의 요청을 가로채어 전처리 또는 후처리를 수행합니다.</li>
<li><strong>Client (클라이언트)</strong>: Proxy를 통해 RealSubject에 접근합니다.</li>
</ul>
<hr>
<h2 id="예시-코드">예시 코드</h2>
<p>프록시 패턴은 <strong>보안, 로깅, 캐싱, 접근 제한</strong> 등 다양한 목적으로 활용됩니다.
대표적인 사례로는 <strong>Cloudflare</strong>와 같은 CDN이 있습니다. 사용자의 요청이 실제 서버에 도달하기 전에 <strong>Cloudflare가 중간에서 요청을 프록시하여 공격적이거나 비정상적인 트래픽을 차단</strong>합니다.</p>
<p>다음은 JavaScript로 구현한 간단한 <strong>API 요청 필터링용 프록시 객체</strong>입니다.</p>
<hr>
<h2 id="예제-코드">예제 코드</h2>
<pre><code class="language-javascript">function createRequestProxy(apiHandler, logger) {
  return new Proxy(apiHandler, {
    apply(target, thisArg, args) {
      const [endpoint, data] = args;

      // 간단한 디도스 필터링 시뮬레이션
      if (data &amp;&amp; data.ip === &#39;123.123.123.123&#39;) {
        logger(`[경고] 차단된 IP(${data.ip})의 요청이 차단되었습니다.`);
        return;
      }

      logger(`[요청] ${endpoint} 엔드포인트에 접근 시도`);
      return target.apply(thisArg, args);
    }
  });
}

// 실제 API 요청을 수행하는 함수
function sendRequest(endpoint, data) {
  console.log(`${endpoint}에 데이터 전송 중...`, data);
}

const logger = console.log;
const protectedRequest = createRequestProxy(sendRequest, logger);

// 테스트
protectedRequest(&quot;/api/login&quot;, { username: &quot;user1&quot;, ip: &quot;111.222.333.444&quot; });
protectedRequest(&quot;/api/login&quot;, { username: &quot;attacker&quot;, ip: &quot;123.123.123.123&quot; });</code></pre>
<hr>
<h2 id="실행-결과">실행 결과</h2>
<pre><code>[요청] /api/login 엔드포인트에 접근 시도
/api/login에 데이터 전송 중... { username: &#39;user1&#39;, ip: &#39;111.222.333.444&#39; }
[경고] 차단된 IP(123.123.123.123)의 요청이 차단되었습니다.</code></pre><hr>
<p>프록시 패턴은 객체에 직접 접근하지 않고 <strong>중간 단계를 통해 필요한 로직을 삽입할 수 있다는 점</strong>에서 유용합니다.
특히 다음과 같은 상황에서 자주 사용됩니다:</p>
<ul>
<li><strong>보안 처리 (접근 제어, 인증, 권한 검사)</strong></li>
<li><strong>네트워크 필터링 (예: 디도스 방어, IP 차단)</strong></li>
<li><strong>로깅 및 모니터링</strong></li>
<li><strong>지연 초기화 (Lazy Loading)</strong></li>
<li><strong>캐싱 프록시</strong></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[옵저버 패턴]]></title>
            <link>https://velog.io/@blight_k/%EC%98%B5%EC%A0%80%EB%B2%84-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@blight_k/%EC%98%B5%EC%A0%80%EB%B2%84-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Sat, 03 May 2025 06:58:01 GMT</pubDate>
            <description><![CDATA[<h1 id="옵저버-패턴observer-pattern이란">옵저버 패턴(Observer Pattern)이란?</h1>
<p>옵저버 패턴은 객체의 상태 변화를 <strong>관찰(Observe)</strong> 하고 있다가, 변화가 생기면 <strong>관찰자(Observer)들에게 자동으로 알림을 전파</strong>하는 디자인 패턴이다.
즉, 주체(Subject)가 있고, 이를 구독한 <strong>옵저버(Observer)</strong> 들이 있으며, 주체의 상태가 바뀌면 옵저버들에게 <strong>자동으로 update() 메서드를 통해 알림</strong>을 준다.</p>
<p>이 패턴은 대표적으로 <strong>트위터, 인스타그램, 유튜브 알림 시스템</strong>과 같이 구독 기반 기능에 적합하다.</p>
<hr>
<h1 id="예시-코드">예시 코드</h1>
<pre><code class="language-java">// 주체 역할 - 게시자
interface Subject {
  void register(Observer observer);
  void unregister(Observer observer);
  void notifyObservers();
  String getLatestPost();
}

// 옵저버 역할 - 팔로워
interface Observer {
  void update();
}

// 게시자 클래스 - 게시글을 업로드하고 알림을 전파
class User implements Subject {
  private List&lt;Observer&gt; followers = new ArrayList&lt;&gt;();
  private String latestPost;

  @Override
  public void register(Observer observer) {
    followers.add(observer);
  }

  @Override
  public void unregister(Observer observer) {
    followers.remove(observer);
  }

  @Override
  public void notifyObservers() {
    for (Observer follower : followers) {
      follower.update();
    }
  }

  @Override
  public String getLatestPost() {
    return latestPost;
  }

  public void post(String content) {
    System.out.println(&quot;📢 새 게시글: &quot; + content);
    this.latestPost = content;
    notifyObservers();
  }
}

// 팔로워 클래스 - 알림을 받고 확인
class Follower implements Observer {
  private String name;
  private Subject user;

  public Follower(String name, Subject user) {
    this.name = name;
    this.user = user;
  }

  @Override
  public void update() {
    String newPost = user.getLatestPost();
    System.out.println(name + &quot;님이 새 게시글을 확인함: &quot; + newPost);
  }
}

// 실행 예시
public class Main {
  public static void main(String[] args) {
    User user = new User();

    Observer follower1 = new Follower(&quot;Alice&quot;, user);
    Observer follower2 = new Follower(&quot;Bob&quot;, user);

    user.register(follower1);
    user.register(follower2);

    user.post(&quot;오늘의 일상 공유합니다 ✨&quot;);
  }
}</code></pre>
<hr>
<ul>
<li><code>Subject</code>는 상태 변화가 생겼을 때 <code>Observer</code>들에게 알림을 보낸다.</li>
<li>옵저버 패턴은 <strong>의존성을 낮추면서도 이벤트 기반 흐름을 구현할 수 있는 장점</strong>이 있다.</li>
<li>대표적으로 트위터의 “팔로우한 유저가 트윗을 올리면 알림이 뜨는 기능” 등에 활용된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Ktor + Koin 사용 시 NoClassDefFoundError 해결 기록]]></title>
            <link>https://velog.io/@blight_k/Ktor-Koin-%EC%82%AC%EC%9A%A9-%EC%8B%9C-NoClassDefFoundError-%ED%95%B4%EA%B2%B0-%EA%B8%B0%EB%A1%9D</link>
            <guid>https://velog.io/@blight_k/Ktor-Koin-%EC%82%AC%EC%9A%A9-%EC%8B%9C-NoClassDefFoundError-%ED%95%B4%EA%B2%B0-%EA%B8%B0%EB%A1%9D</guid>
            <pubDate>Thu, 01 May 2025 10:37:02 GMT</pubDate>
            <description><![CDATA[<p>React + Ktor + Koin + Exposed 조합으로 커뮤니티 사이트를 개발하고 있었다.<br>의존성 주입은 <code>Koin</code>을 통해 관리하고, 라우팅은 기능별로 <code>Route</code> 모듈로 분리하고 있었다.</p>
<hr>
<h2 id="문제-상황">문제 상황</h2>
<pre><code class="language-kotlin">fun Route.userRoute() {
    val userService by inject&lt;UserService&gt;()

    route(&quot;/api/v1/user&quot;) {
        post {
            val request = call.receive&lt;UserCreateRequest&gt;()

            val result = userService.create(request)
        }
    }
}</code></pre>
<p>이렇게 <code>Route</code> 내부에서 Koin의 <code>inject()</code>를 사용하려고 했는데, 다음과 같은 에러가 발생했다.</p>
<pre><code class="language-text">Exception in thread &quot;main&quot; java.lang.NoClassDefFoundError: io/ktor/server/routing/RoutingKt
    at org.koin.ktor.ext.RouteExtKt.getKoin(RouteExt.kt:74)
    at com.kcw.user.route.UserRouteKt.userRoute(UserRoute.kt:10)</code></pre>
<ul>
<li><code>inject&lt;UserService&gt;()</code> 호출 시 내부적으로 사용하는 <code>getKoin()</code>이 <code>RoutingKt</code>를 찾지 못해서 생기는 에러였다.</li>
<li><code>Route</code> 내부에서 의존성을 주입하려고 할 때 Koin의 Ktor 3 지원이 완전하지 않은 듯 보였다.</li>
</ul>
<hr>
<h2 id="원인-분석">원인 분석</h2>
<p>찾아보니 나만 겪는 문제는 아니었다.</p>
<blockquote>
<p><a href="https://github.com/InsertKoinIO/koin/issues/1716">https://github.com/InsertKoinIO/koin/issues/1716</a></p>
</blockquote>
<p>해당 이슈에서는 <code>ktor 3.x</code>와 <code>koin 3.x</code> 조합에서 <code>RouteExtKt.getKoin()</code> 관련 오류가 종종 발생한다고 보고되고 있었다.<br>Ktor 3부터 내부 구조가 바뀌면서 기존 Koin Extension이 의존하는 클래스(<code>RoutingKt</code>)를 제대로 찾지 못하는 문제가 있는 듯하다.</p>
<hr>
<h2 id="해결-방법">해결 방법</h2>
<p>Koin 공식 GitHub 이슈에서 다음과 같은 해결 방안을 발견했다:</p>
<pre><code class="language-kotlin">// 기존 (문제 발생)
implementation(&quot;io.insert-koin:koin-ktor:3.x.x&quot;)

// 변경 (해결됨)
implementation(&quot;io.insert-koin:koin-ktor3:4.1.0-Beta7&quot;)</code></pre>
<blockquote>
<p><code>koin-ktor3</code>는 Ktor 3.x에 맞춰 별도로 관리되는 Koin 확장 모듈이다.
아직 Beta이긴 하지만, 위 에러를 해결하기 위해선 이 버전을 사용하는 것이 현재로선 가장 확실한 해결책이었다.</p>
</blockquote>
<hr>
<h2 id="적용-후-정상-동작">적용 후 정상 동작</h2>
<p><code>koin-ktor3</code> 의존성으로 교체한 후 <code>Route</code> 내부에서 <code>inject()</code>를 정상적으로 사용할 수 있게 되었고, 서버도 에러 없이 실행되었다.</p>
<hr>
<h2 id="마무리">마무리</h2>
<ul>
<li><code>Ktor 3.x</code>와 <code>Koin</code>을 함께 사용할 때는 <strong>반드시 <code>koin-ktor3</code></strong> 모듈을 사용하자.</li>
<li>아직 <code>Beta</code> 버전이지만, 기존 Ktor 확장 모듈과는 다른 방식으로 동작한다.</li>
<li>위와 같은 에러를 겪는다면 라이브러리 버전을 점검해보자.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[전략 패턴(Strategy Pattern)]]></title>
            <link>https://velog.io/@blight_k/%EC%A0%84%EB%9E%B5-%ED%8C%A8%ED%84%B4Strategy-Pattern</link>
            <guid>https://velog.io/@blight_k/%EC%A0%84%EB%9E%B5-%ED%8C%A8%ED%84%B4Strategy-Pattern</guid>
            <pubDate>Mon, 28 Apr 2025 13:08:48 GMT</pubDate>
            <description><![CDATA[<h1 id="전략-패턴strategy-pattern-이해하기">전략 패턴(Strategy Pattern) 이해하기</h1>
<p>전략 패턴(Strategy Pattern)은 <strong>&quot;전략&quot;이라고 부르는 알고리즘을 캡슐화하여</strong>,  
<strong>컨텍스트(Context) 안에서 서로 교체할 수 있게 만드는 디자인 패턴</strong>입니다.</p>
<p>즉, 하나의 기능(예: 로그인, 결제 등)을 다양한 방법으로 구현할 수 있고,<br>이 방법들을 쉽게 <strong>갈아끼울 수 있도록</strong> 설계합니다.</p>
<hr>
<h1 id="전략-패턴을-적용하는-이유">전략 패턴을 적용하는 이유</h1>
<p>전략 패턴을 적용하면 다음과 같은 장점이 있습니다.</p>
<ul>
<li><strong>확장성</strong>: 새로운 전략을 추가해도 기존 코드를 수정할 필요가 없습니다.</li>
<li><strong>유연성</strong>: 실행 중에도 전략을 자유롭게 교체할 수 있습니다.</li>
<li><strong>캡슐화</strong>: 구체적인 전략의 내부 구현을 숨길 수 있습니다.</li>
</ul>
<hr>
<h1 id="실생활에서-보는-전략-패턴">실생활에서 보는 전략 패턴</h1>
<p>예를 들어, 사용자가 로그인할 때 다음과 같은 전략을 선택할 수 있습니다.</p>
<ul>
<li>카카오 로그인</li>
<li>구글 로그인</li>
<li>애플 로그인</li>
</ul>
<p>또는 결제할 때 다음과 같은 전략을 사용할 수 있습니다.</p>
<ul>
<li>신용카드 결제</li>
<li>카카오페이 결제</li>
<li>페이팔 결제</li>
</ul>
<p>Node.js의 유명한 인증 라이브러리인 <strong>passport</strong>도 전략 패턴을 기반으로 설계되어 있습니다.<br>여러 인증 전략(passport-kakao, passport-google 등)을 쉽게 추가하고 교체할 수 있습니다.</p>
<hr>
<h1 id="java-코드로-전략-패턴-구현하기">Java 코드로 전략 패턴 구현하기</h1>
<p>아래는 <code>쇼핑몰 결제 시스템</code>을 전략 패턴으로 구현한 예시입니다.</p>
<h2 id="1-전략strategy-인터페이스-정의">1. 전략(Strategy) 인터페이스 정의</h2>
<pre><code class="language-java">interface PaymentStrategy {
    void pay(int amount);
}</code></pre>
<h2 id="2-구체적인-전략concrete-strategy-구현">2. 구체적인 전략(Concrete Strategy) 구현</h2>
<pre><code class="language-java">class KakaoCardStrategy implements PaymentStrategy {
    private final String name;
    private final String cardNumber;
    private final String cvv;
    private final String dateOfExpiry;

    public KakaoCardStrategy(String name, String cardNumber, String cvv, String dateOfExpiry) {
        this.name = name;
        this.cardNumber = cardNumber;
        this.cvv = cvv;
        this.dateOfExpiry = dateOfExpiry;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + &quot;원을 KakaoCard로 결제합니다.&quot;);
    }
}

class LunaCardStrategy implements PaymentStrategy {
    private final String emailId;
    private final String password;

    public LunaCardStrategy(String emailId, String password) {
        this.emailId = emailId;
        this.password = password;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + &quot;원을 LunaCard로 결제합니다.&quot;);
    }
}</code></pre>
<h2 id="3-context-역할을-하는-shoppingcart-클래스">3. Context 역할을 하는 ShoppingCart 클래스</h2>
<pre><code class="language-java">import java.util.ArrayList;
import java.util.List;

class Item {
    private final String name;
    private final int price;

    public Item(String name, int cost) {
        this.name = name;
        this.price = cost;
    }

    public int getPrice() {
        return price;
    }
}

class ShoppingCart {
    private final List&lt;Item&gt; items = new ArrayList&lt;&gt;();

    public void addItem(Item item) {
        items.add(item);
    }

    public void removeItem(Item item) {
        items.remove(item);
    }

    public int calculateTotal() {
        return items.stream().mapToInt(Item::getPrice).sum();
    }

    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}</code></pre>
<h2 id="4-사용-예시">4. 사용 예시</h2>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        Item item1 = new Item(&quot;노트북&quot;, 2000000);
        Item item2 = new Item(&quot;마우스&quot;, 50000);

        cart.addItem(item1);
        cart.addItem(item2);

        // KakaoCard로 결제
        PaymentStrategy kakaoPay = new KakaoCardStrategy(&quot;홍길동&quot;, &quot;1234-5678-9012-3456&quot;, &quot;123&quot;, &quot;12/25&quot;);
        cart.pay(kakaoPay);

        // LunaCard로 결제
        PaymentStrategy lunaPay = new LunaCardStrategy(&quot;user@example.com&quot;, &quot;securepassword&quot;);
        cart.pay(lunaPay);
    }
}</code></pre>
<h2 id="실행-결과">실행 결과</h2>
<pre><code>2050000원을 KakaoCard로 결제합니다.
2050000원을 LunaCard로 결제합니다.</code></pre><hr>
<h1 id="정리">정리</h1>
<ul>
<li><strong>전략 패턴</strong>은 실행 알고리즘을 캡슐화하고, 쉽게 교체할 수 있도록 설계합니다.</li>
<li>컨텍스트(ShoppingCart)는 구체적인 전략(PaymentStrategy의 구현체)을 몰라도 됩니다.</li>
<li>덕분에 <strong>확장성</strong>과 <strong>유지보수성</strong>이 크게 향상됩니다.</li>
</ul>
<hr>
<h1 id="마무리">마무리</h1>
<p>디자인 패턴을 공부하다 보면 &quot;왜 이렇게 복잡하게 만들지?&quot;라고 생각할 때가 있습니다.<br>하지만 실제 서비스가 커지고 기능이 추가될수록,<br><strong>전략 패턴 같은 유연한 설계</strong>가 얼마나 중요한지 몸소 느끼게 됩니다.</p>
<p>기억해야 할 핵심은 다음과 같습니다:</p>
<blockquote>
<p>&quot;변화에 유연하게 대응할 수 있도록 미리 준비하는 것&quot;<br>그게 바로 좋은 설계입니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[의존성 주입과 의존관계 역전원칙]]></title>
            <link>https://velog.io/@blight_k/%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85%EA%B3%BC-%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84-%EC%97%AD%EC%A0%84%EC%9B%90%EC%B9%99</link>
            <guid>https://velog.io/@blight_k/%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85%EA%B3%BC-%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84-%EC%97%AD%EC%A0%84%EC%9B%90%EC%B9%99</guid>
            <pubDate>Mon, 28 Apr 2025 11:57:53 GMT</pubDate>
            <description><![CDATA[<h1 id="의존성-주입di-dependency-injection이란">의존성 주입(DI, Dependency Injection)이란?</h1>
<p>우리는 소프트웨어를 개발할 때 <strong>&quot;A가 B에 의존한다&quot;</strong> 라는 표현을 자주 사용합니다.<br>여기서 <strong>&quot;의존한다&quot;</strong> 는 것은, <strong>B가 변경되면 A도 함께 변경될 가능성이 높다</strong>는 뜻입니다.</p>
<p>간단한 예시를 봅시다.</p>
<pre><code class="language-java">class Keyboard {
    public void input() {
        System.out.println(&quot;키보드 입력&quot;);
    }
}

class Computer {
    public void start() {
        Keyboard keyboard = new Keyboard();
        keyboard.input();
    }
}

public class Main {
    public static void main(String[] args) {
        new Computer().start();
    }
}</code></pre>
<p>위 코드에서 <code>Computer</code> 클래스는 <code>Keyboard</code>에 직접적으로 의존합니다.<br>만약 <code>Keyboard</code> 클래스에 변경사항이 생긴다면 <code>Computer</code>도 수정이 필요할 수 있습니다.</p>
<hr>
<h1 id="di-적용-전-문제점">DI 적용 전 문제점</h1>
<p>위 코드처럼 직접 객체를 생성하면 다음과 같은 문제가 발생합니다.</p>
<ul>
<li><strong>확장성 부족</strong>: 만약 <code>Mouse</code> 입력도 추가하고 싶다면 <code>Computer</code> 클래스가 수정되어야 합니다.</li>
<li><strong>테스트 어려움</strong>: <code>Computer</code> 클래스를 테스트할 때 <code>Keyboard</code> 구현체가 항상 필요합니다.</li>
<li><strong>유연성 부족</strong>: 다른 종류의 입력 장치로 쉽게 교체할 수 없습니다.</li>
</ul>
<hr>
<h1 id="didependency-injection-적용-후">DI(Dependency Injection) 적용 후</h1>
<p><strong>인터페이스</strong>를 도입하고, 객체 생성 책임을 외부로 넘기면 문제를 해결할 수 있습니다.</p>
<pre><code class="language-java">interface InputDevice {
    void input();
}

class Keyboard implements InputDevice {
    @Override
    public void input() {
        System.out.println(&quot;키보드 입력&quot;);
    }
}

class Mouse implements InputDevice {
    @Override
    public void input() {
        System.out.println(&quot;마우스 클릭&quot;);
    }
}

class Computer {
    private final InputDevice inputDevice;

    public Computer(InputDevice inputDevice) {
        this.inputDevice = inputDevice;
    }

    public void start() {
        inputDevice.input();
    }
}

public class Main {
    public static void main(String[] args) {
        InputDevice keyboard = new Keyboard();
        Computer computer = new Computer(keyboard);
        computer.start();

        InputDevice mouse = new Mouse();
        Computer computer2 = new Computer(mouse);
        computer2.start();
    }
}</code></pre>
<h2 id="달라진-점">달라진 점</h2>
<ul>
<li><code>Computer</code> 클래스는 <code>Keyboard</code>나 <code>Mouse</code>의 구체적인 구현을 몰라도 됩니다.</li>
<li><code>InputDevice</code>라는 <strong>추상화(인터페이스)</strong> 에만 의존합니다.</li>
<li>새로운 입력 장치가 추가되더라도 <code>Computer</code>를 수정할 필요가 없습니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[이터레이터 패턴]]></title>
            <link>https://velog.io/@blight_k/%EC%9D%B4%ED%84%B0%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@blight_k/%EC%9D%B4%ED%84%B0%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Thu, 24 Apr 2025 13:48:25 GMT</pubDate>
            <description><![CDATA[<h1 id="이터레이터-패턴iterator-pattern으로-다양한-자료구조-순회하기">이터레이터 패턴(Iterator Pattern)으로 다양한 자료구조 순회하기</h1>
<p>이터레이터 패턴은 컬렉션(자료구조)의 내부 구조를 노출하지 않고도 그 안의 요소들을 순차적으로 접근할 수 있도록 해주는 디자인 패턴입니다.<br>JavaScript에서는 이터레이터(Iterator)를 통해 다양한 자료구조를 <strong>동일한 방식으로 순회할 수 있는 인터페이스</strong>를 제공합니다.</p>
<h2 id="배열-map-set은-구조가-다르지만">배열, Map, Set은 구조가 다르지만...</h2>
<p>자바스크립트에는 다양한 내장 자료구조가 있습니다. 대표적으로 배열(<code>Array</code>), 맵(<code>Map</code>), 집합(<code>Set</code>)이 있습니다.<br>이 자료구조들은 각기 다른 특성과 구조를 가지고 있지만, *<em>이터레이터 *</em> 덕분에 <code>for...of</code> 루프를 이용해 똑같이 순회할 수 있습니다.</p>
<h3 id="예제-코드">예제 코드</h3>
<pre><code class="language-javascript">const mp = new Map();
mp.set(&#39;a&#39;, 1);
mp.set(&#39;b&#39;, 2);
mp.set(&#39;cccc&#39;, 3);

const st = new Set();
st.add(1);
st.add(2);
st.add(3);

const a = [];
for (let i = 0; i &lt; 10; i++) {
  a.push(i);
}

// 배열 순회
for (let aa of a) console.log(aa);

// Map 순회
for (let m of mp) console.log(m);

// Set 순회
for (let s of st) console.log(s);</code></pre>
<h3 id="실행-결과">실행 결과</h3>
<pre><code>0
1
2
...
9
[ &#39;a&#39;, 1 ]
[ &#39;b&#39;, 2 ]
[ &#39;cccc&#39;, 3 ]
1
2
3</code></pre><h3 id="핵심은-이터레이터">핵심은 &quot;이터레이터&quot;</h3>
<p>이터레이터가 없다면, Map을 순회하기 위해 <code>Object.keys()</code>나 <code>for...in</code>을 사용하고, 다시 <code>hasOwnProperty</code>로 키가 실제로 존재하는지 확인하는 등 복잡한 로직이 필요했을 것입니다.</p>
<p>하지만 이터레이터 덕분에 <code>for...of</code> 문 하나로 배열, 맵, 셋 등 다양한 자료구조를 <strong>동일한 방식으로 순회할 수 있게 됩니다</strong>.</p>
<h2 id="이터레이터-패턴의-장점">이터레이터 패턴의 장점</h2>
<ul>
<li><p><strong>일관된 순회 방식 제공</strong><br>다양한 자료구조를 동일한 인터페이스로 순회할 수 있어 코드 가독성이 높아집니다.</p>
</li>
<li><p><strong>구조를 숨긴 채 내부 요소 접근 가능</strong><br>사용자는 자료구조의 내부 구조를 몰라도 데이터를 순회할 수 있습니다.</p>
</li>
<li><p><strong>확장성</strong><br>사용자 정의 객체도 이터러블을 구현하면 동일하게 <code>for...of</code>로 순회할 수 있습니다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[팩토리 패턴]]></title>
            <link>https://velog.io/@blight_k/%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@blight_k/%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Thu, 24 Apr 2025 13:39:06 GMT</pubDate>
            <description><![CDATA[<h1 id="팩토리-패턴factory-pattern으로-유지보수성을-높이는-방법">팩토리 패턴(Factory Pattern)으로 유지보수성을 높이는 방법</h1>
<p>팩토리 패턴은 객체 생성 로직을 클라이언트 코드에서 분리하여, 객체 생성과 관련된 책임을 별도의 클래스나 메서드로 위임하는 디자인 패턴입니다. 이 패턴을 사용하면 코드의 <strong>유지보수성과 확장성</strong>이 높아지며, 객체 생성 방식이 변경되더라도 기존 코드를 최소한으로 수정하면서 유연하게 대처할 수 있습니다.</p>
<p>특히 <strong>상속 관계에 있는 클래스들에서 상위 클래스는 객체 생성의 뼈대를 결정하고, 하위 클래스는 구체적인 객체 생성 로직을 담당하는 구조</strong>를 가질 수 있어 패턴의 응집력과 활용성이 높아집니다.</p>
<h2 id="예제-코드">예제 코드</h2>
<p>아래는 커피를 만드는 예제를 팩토리 패턴으로 구현한 코드입니다.</p>
<pre><code class="language-javascript">// 상위 팩토리 클래스
class CoffeeFactory {
  static createCoffee(type) {
    const factory = factoryList[type];
    return factory.createCoffee();
  }
}

// 커피 종류 클래스들
class Latte {
  constructor() {
    this.name = &quot;Latte&quot;;
  }
}

class Espresso {
  constructor() {
    this.name = &quot;Espresso&quot;;
  }
}

// 각 커피를 생성하는 하위 팩토리 클래스
class LatteFactory extends CoffeeFactory {
  static createCoffee() {
    return new Latte();
  }
}

class EspressoFactory extends CoffeeFactory {
  static createCoffee() {
    return new Espresso();
  }
}

// 팩토리 목록
const factoryList = {
  LatteFactory: LatteFactory,
  EspressoFactory: EspressoFactory,
};

// 실행 함수
const main = () =&gt; {
  const coffee = CoffeeFactory.createCoffee(&quot;LatteFactory&quot;);
  console.log(coffee.name); // &quot;Latte&quot;
};

main();</code></pre>
<h2 id="팩토리-패턴의-장점">팩토리 패턴의 장점</h2>
<ul>
<li><p><strong>유지보수가 용이합니다</strong><br>새로운 커피 종류가 추가되거나 생성 방식이 변경되어도, 하위 클래스만 수정하면 되므로 전체 코드에 미치는 영향이 적습니다.</p>
</li>
<li><p><strong>의존성을 줄입니다</strong><br>클라이언트 코드에서는 구체적인 클래스(<code>new Latte()</code>, <code>new Espresso()</code>)를 알 필요 없이, <code>CoffeeFactory</code>만 통해 객체를 생성할 수 있습니다.</p>
</li>
<li><p><strong>확장성이 뛰어납니다</strong><br>새로운 커피 타입을 추가할 때 기존 코드를 거의 수정하지 않고 기능을 확장할 수 있습니다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 <Suspense> 컴포넌트  정리]]></title>
            <link>https://velog.io/@blight_k/Suspense-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@blight_k/Suspense-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 24 Apr 2025 10:00:53 GMT</pubDate>
            <description><![CDATA[<h2 id="react의-suspense-컴포넌트란">React의 <code>&lt;Suspense&gt;</code> 컴포넌트란?</h2>
<p>React의 <code>&lt;Suspense&gt;</code> 컴포넌트는 자식 컴포넌트를 렌더링하기 전에 필요한 데이터를 로드하는 동안 <strong>대체 UI(Fallback)</strong> 를 보여주는 역할을 합니다.</p>
<p>즉, 비동기적으로 데이터를 가져오거나 코드 스플리팅을 통해 컴포넌트를 동적으로 로드할 때, 사용자에게 로딩 중임을 알리는 UI를 제공하는 기능입니다.</p>
<hr>
<h3 id="suspense의-props"><code>&lt;Suspense&gt;</code>의 Props</h3>
<p><code>&lt;Suspense&gt;</code>는 다음과 같은 props를 가집니다:</p>
<ul>
<li><p><strong>children</strong><br>최종적으로 렌더링할 실제 UI입니다.<br>children의 렌더링이 지연되면, 대신 fallback이 렌더링됩니다.</p>
</li>
<li><p><strong>fallback</strong><br>실제 UI가 준비되기 전까지 표시될 <strong>대체 UI</strong>입니다.<br>React 노드 형태의 어떤 요소든 사용 가능하지만, 일반적으로는 로딩 스피너나 스켈레톤처럼 간단한 Placeholder가 자주 사용됩니다.<br>children의 로딩이 완료되면 React는 fallback을 숨기고 children을 화면에 렌더링합니다.</p>
</li>
</ul>
<blockquote>
<p>만약 fallback 자체의 렌더링도 지연된다면, 가장 가까운 상위 <code>&lt;Suspense&gt;</code>가 대신 fallback을 처리하게 됩니다.</p>
</blockquote>
<hr>
<h3 id="사용-예시">사용 예시</h3>
<pre><code class="language-tsx">&lt;Suspense fallback={&lt;Loading /&gt;}&gt;
  &lt;Albums /&gt;
&lt;/Suspense&gt;</code></pre>
<p>위 코드에서는 <code>&lt;Albums /&gt;</code> 컴포넌트가 데이터를 불러오는 동안 <code>&lt;Loading /&gt;</code> 컴포넌트가 대신 화면에 표시됩니다.<br>모든 데이터가 준비되면 React는 <code>&lt;Loading /&gt;</code>을 제거하고 <code>&lt;Albums /&gt;</code>를 렌더링합니다.</p>
]]></description>
        </item>
    </channel>
</rss>