<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>live_in_truth.log</title>
        <link>https://velog.io/</link>
        <description>참 되게 살자</description>
        <lastBuildDate>Thu, 12 Feb 2026 00:49:52 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>live_in_truth.log</title>
            <url>https://velog.velcdn.com/images/live_in_truth/profile/332bc4dd-8011-456e-b12a-ea4a28052456/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. live_in_truth.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/live_in_truth" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[자바스크립트가 아직도 싱글인 이유]]></title>
            <link>https://velog.io/@live_in_truth/%EC%95%84%EC%A7%81%EB%8F%84-%EC%8B%B1%EA%B8%80%EC%9D%B4%EB%9D%BC-%EC%8B%B1%EA%B8%80%EB%B2%99%EA%B8%80%ED%95%9C-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A5%BC-%EC%8B%B1%EA%B7%B8%EB%9F%BD%EA%B2%8C-%ED%83%90%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@live_in_truth/%EC%95%84%EC%A7%81%EB%8F%84-%EC%8B%B1%EA%B8%80%EC%9D%B4%EB%9D%BC-%EC%8B%B1%EA%B8%80%EB%B2%99%EA%B8%80%ED%95%9C-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A5%BC-%EC%8B%B1%EA%B7%B8%EB%9F%BD%EA%B2%8C-%ED%83%90%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 12 Feb 2026 00:49:52 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/live_in_truth/post/2f3d17d2-dffd-4158-9b64-e3dd7eda1c40/image.png" alt=""></p>
<blockquote>
<p>&quot;<strong><em>왜 자바스크립트는 스레드를 하나만 쓰면서 동시에 여러 일을 하는 것처럼 보일까?&quot;</em></strong> 이 질문에 답하기 위해서는 자바스크립트의 실행 엔진뿐만 아니라, 이를 둘러싼 런타임 환경(Browser, Node.js)의 구조를 이해해야 한다.</p>
</blockquote>
<blockquote>
<p>본 글에서는 자바스크립트가 왜 <strong>싱글 스레드</strong> 노선을 택했는지, 그리고 비동기 처리의 핵심인 이벤트 루프와 <code>await</code>의 필요성에 대해 기술적인 관점에서 분석한다.</p>
</blockquote>
<hr>
<h2 id="1-자바스크립트는-왜-싱글-스레드인가">1. 자바스크립트는 왜 싱글 스레드인가?</h2>
<blockquote>
<p>멀티 스레드는 여러 작업을 병렬로 처리할 수 있어 효율적으로 보이지만, 그만큼 복잡한 문제를 동반한다. 자바스크립트가 싱글 스레드 모델을 유지하는 이유는 <strong>크게 두 가지</strong>로 요약할 수 있다.</p>
</blockquote>
<h3 id="자원-공유와-동기화-문제deadlock--race-condition">자원 공유와 동기화 문제(Deadlock &amp; Race Condition)</h3>
<blockquote>
<p>멀티 스레드 환경에서는 <strong>여러 스레드가 동일한 자원(메모리 등)에 동시에 접근</strong>할 수 있다. 이때 <strong>자원을 선점</strong>하기 위한 <strong>경쟁 상태(Race Condition)</strong>가 발생하거나, 서로의 작업이 끝나기를 무한정 기다리는 <strong>데드락(Deadlock)</strong> 상태에 빠질 위험이 크다. 자바스크립트는 이러한 복잡한 동기화 문제를 피하고 설계의 단순함을 유지하기 위해 싱글 스레드를 선택했다.</p>
</blockquote>
<h3 id="dom-조작의-일관성">DOM 조작의 일관성</h3>
<blockquote>
<p><strong>자바스크립트의 주된 역할은 웹 페이지의 UI를 조작</strong>하는 것이다. 만약 여러 스레드가 동시에 같은 DOM 요소에 접근하여 하나는 삭제하고, 하나는 수정을 시도한다면 화면은 예측 불가능한 상태가 될 것이다. 싱글 스레드 방식은 한 번에 하나의 작업만 수행함으로써 UI 렌더링의 일관성을 보장한다.</p>
</blockquote>
<hr>
<h2 id="2-어떻게-싱글로-멀티인척-작동할까">2. 어떻게 싱글로 멀티인척 작동할까?</h2>
<blockquote>
<p>자바스크립트 엔진 자체는 싱글 스레드이지만, 실제 자바스크립트가 실행되는 <strong>런타임(Browser/Node.js)</strong>은 멀티 스레드처럼 동작한다.</p>
</blockquote>
<h3 id="비동기-작업의-흐름">비동기 작업의 흐름</h3>
<blockquote>
<ol>
<li><strong>Call Stack:</strong> 자바스크립트 엔진의 메인 스레드로, 현재 실행 중인 함수들이 쌓인다.</li>
<li><strong>Web API:</strong> 브라우저에서 제공하는 멀티 스레드 영역이다. <code>setTimeout</code>, <code>fetch</code>, DOM 이벤트 등이 여기서 처리된다. 자바스크립트 엔진은 시간이 오래 걸리는 작업을 여기에 던지고 다음 코드를 실행한다.</li>
<li><strong>Task Queue &amp; Event Loop:</strong> Web API에서 완료된 작업의 콜백 함수들이 대기하는 곳이다. <strong>이벤트 루프(Event Loop)</strong>는 Call Stack이 비어있는지 끊임없이 확인하며, 비어있을 때 큐에 쌓인 작업을 스택으로 옮겨 실행한다.</li>
</ol>
</blockquote>
<h3 id="태스크-큐의-우선순위-매크로-vs-마이크로">태스크 큐의 우선순위: 매크로 vs 마이크로</h3>
<blockquote>
<p>모든 비동기 작업이 같은 대기열에 서는 것은 아니다. 큐는 크게 두 종류로 나뉘며 엄격한 우선순위를 가진다.</p>
</blockquote>
<table>
<thead>
<tr>
<th>구분</th>
<th>종류</th>
<th>처리 시점</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Microtask Queue</strong></td>
<td><code>Promise.then</code>, <code>MutationObserver</code></td>
<td>현재 실행 중인 작업이 끝나면 <strong>가장 먼저, 전부</strong> 비워질 때까지 처리</td>
</tr>
<tr>
<td><strong>Macrotask Queue</strong></td>
<td><code>setTimeout</code>, <code>setInterval</code>, UI 렌더링</td>
<td>마이크로태스크 큐가 비어있을 때 <strong>한 번에 하나씩</strong> 처리</td>
</tr>
</tbody></table>
<hr>
<h2 id="3-왜-동기-함수-대신-비동기와-await을-쓰는가">3. 왜 동기 함수 대신 비동기와 <code>await</code>을 쓰는가?</h2>
<blockquote>
<p>&quot;결국 기다려야 한다면, 그냥 동기 함수(Sync)로 처리하면 되지 않을까?&quot;라는 의문이 생긴다. 하지만 동기 처리는 웹 환경에서 치명적인 결함을 만든다.</p>
</blockquote>
<h3 id="블로킹blocking-현상">블로킹(Blocking) 현상</h3>
<blockquote>
<p>동기 함수는 결과가 나올 때까지 메인 스레드를 점유한다. 예를 들어 네트워크 호출을 동기식으로 처리하면, 데이터를 받아오는 몇 초 동안 브라우저는 모든 동작을 멈춘다. 사용자는 버튼을 클릭할 수도, 화면을 스크롤할 수도 없는 &#39;프리징(Freezing)&#39; 현상을 겪게 된다.</p>
</blockquote>
<h3 id="await의-본질-비차단non-blocking-대기"><code>await</code>의 본질: 비차단(Non-blocking) 대기</h3>
<blockquote>
<p><code>await</code>은 코드를 동기적으로 작성할 수 있게 해주지만, 동작 방식은 철저히 비동기적이다.</p>
</blockquote>
<ul>
<li><code>await</code>을 만나면 해당 함수의 실행은 일시 중단된다.</li>
<li>하지만 <strong>메인 스레드(Call Stack)는 해제</strong>되어 다른 UI 인터랙션이나 스크립트를 처리할 수 있게 된다.</li>
<li>비동기 작업이 완료되면 이벤트 루프에 의해 다시 스택으로 돌아와 중단되었던 지점부터 실행을 재개한다.</li>
</ul>
<blockquote>
<p>즉, <code>await</code>은 <strong>&quot;메인 스레드를 쉬게 하면서 효율적으로 기다리는 방법&quot;</strong>이지, 단순히 실행 순서를 맞추기 위한 도구가 아니다.</p>
</blockquote>
<hr>
<h2 id="결론-효율적인-싱글-스레드-활용">결론: 효율적인 싱글 스레드 활용</h2>
<blockquote>
<p>자바스크립트는 싱글 스레드라는 제약을 역설적으로 비동기 처리를 통해 강점으로 승화시켰다. <strong>복잡한 스레드 관리 없이도 이벤트 루프를 통해 고성능의 논블로킹 I/O를 실현한 것이다.</strong></p>
</blockquote>
<blockquote>
<p>프론트엔드 개발자에게 비동기 처리 이해는 필수적이다. <strong>마이크로태스크의 높은 우선순위를 활용해 시급한 데이터를 먼저 처리</strong>하고, 무거운 작업은 적절히 분산하여 사용자 경험(UX)을 극대화하는 설계 능력이 곧 실력이다. </p>
</blockquote>
<hr>
<p><em>다음글은 마이크로태스크 큐를 활용해 실제 서비스의 렌더링 성능을 화하는 구체적인 사례를 다뤄 볼 것이다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[더 좋아진 타입스크립트]]></title>
            <link>https://velog.io/@live_in_truth/%EB%8D%94-%EC%A2%8B%EC%95%84%EC%A7%84-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</link>
            <guid>https://velog.io/@live_in_truth/%EB%8D%94-%EC%A2%8B%EC%95%84%EC%A7%84-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</guid>
            <pubDate>Fri, 27 Jun 2025 02:09:34 GMT</pubDate>
            <description><![CDATA[<h1 id="typescript-native-previews-발표-10배-빠른-typescript-컴파일러">TypeScript Native Previews 발표: 10배 빠른 TypeScript 컴파일러</h1>
<blockquote>
<p>원문: <a href="https://devblogs.microsoft.com/typescript/announcing-typescript-native-previews/">Announcing TypeScript Native Previews</a> - Microsoft Dev Blogs</p>
</blockquote>
<h2 id="개요">개요</h2>
<p>Microsoft TypeScript 팀이 2025년 5월 22일, <strong>TypeScript Native Previews</strong>의 광범위한 가용성을 발표했습니다. 이는 지난 3월에 공개된 네이티브 코드로 포팅된 TypeScript 컴파일러의 첫 번째 공개 프리뷰입니다.</p>
<h2 id="핵심-성능-개선">핵심 성능 개선</h2>
<h3 id="10배-빠른-컴파일-속도">10배 빠른 컴파일 속도</h3>
<ul>
<li><strong>기존 TypeScript</strong>: JavaScript 기반 (Strada)</li>
<li><strong>새로운 TypeScript</strong>: Go 언어로 작성된 네이티브 코드 (Corsa)</li>
<li><strong>성능 향상</strong>: 대부분의 프로젝트에서 <strong>10배 빠른 속도</strong> 달성</li>
<li><strong>개선 요소</strong>: <ul>
<li>네이티브 컴파일 언어 사용 (Go)</li>
<li>공유 메모리 병렬 처리</li>
<li>동시성 최적화</li>
</ul>
</li>
</ul>
<h2 id="설치-및-사용법">설치 및 사용법</h2>
<h3 id="1-npm을-통한-설치">1. npm을 통한 설치</h3>
<pre><code class="language-bash">npm install -D @typescript/native-preview</code></pre>
<h3 id="2-명령줄-사용">2. 명령줄 사용</h3>
<pre><code class="language-bash"># 기존 tsc 대신 tsgo 사용
npx tsgo --project ./src/tsconfig.json

# 진단 정보와 함께 실행
npx tsgo -p . --noEmit --extendedDiagnostics</code></pre>
<h3 id="3-vs-code-확장-프로그램">3. VS Code 확장 프로그램</h3>
<ul>
<li><strong>확장 프로그램명</strong>: &quot;TypeScript (Native Preview)&quot;</li>
<li><strong>설치 방법</strong>: VS Code Extension Marketplace에서 설치</li>
<li><strong>활성화 방법</strong>: <ul>
<li>명령 팔레트에서 &quot;TypeScript Native Preview: Enable (Experimental)&quot; 실행</li>
<li>또는 설정에서 <code>&quot;typescript.experimental.useTsgo&quot;: true</code> 추가</li>
</ul>
</li>
</ul>
<h2 id="실제-성능-비교">실제 성능 비교</h2>
<h3 id="sentry-프로젝트-기준-성능-테스트">Sentry 프로젝트 기준 성능 테스트</h3>
<p><strong>기존 TypeScript 5.8 (Strada)</strong>:</p>
<pre><code>Files:                         9306
Lines of TypeScript:        1113969
Memory used:               3356832K
Total time:                  72.81s  # 1분 이상 소요</code></pre><p><strong>새로운 TypeScript Native (Corsa)</strong>:</p>
<pre><code>Files:              9292
Lines:           1508361
Memory used:    3892267K
Total time:        ~7.3s   # 약 10배 빠름</code></pre><h2 id="주요-기능-지원-현황">주요 기능 지원 현황</h2>
<h3 id="✅-완전-지원">✅ 완전 지원</h3>
<ul>
<li><strong>타입 체킹</strong>: 대부분의 타입 체킹 기능 완전 지원</li>
<li><strong>JSX</strong>: JSX 타입 체킹 지원 추가됨</li>
<li><strong>JavaScript + JSDoc</strong>: JSDoc 기반 타입 체킹 지원</li>
<li><strong>기본 완성 기능</strong>: 코드 완성 기능 구현</li>
</ul>
<h3 id="🚧-개발-중인-기능">🚧 개발 중인 기능</h3>
<ul>
<li><strong>자동 임포트</strong>: 아직 구현되지 않음</li>
<li><strong>찾기/참조</strong>: find-all-references 기능 개발 중</li>
<li><strong>이름 변경</strong>: rename 기능 개발 중</li>
<li><strong>시그니처 도움말</strong>: signature help 개발 중</li>
</ul>
<h3 id="❌-아직-미지원">❌ 아직 미지원</h3>
<ul>
<li><strong>빌드 모드</strong>: <code>--build</code> 플래그 미지원</li>
<li><strong>선언 파일 생성</strong>: <code>--declaration</code> 미지원</li>
<li><strong>다운레벨 컴파일</strong>: 일부 구버전 타겟 미지원</li>
<li><strong>프로젝트 참조</strong>: 언어 서비스에서 프로젝트 참조 미지원</li>
</ul>
<h2 id="알려진-차이점-및-주의사항">알려진 차이점 및 주의사항</h2>
<h3 id="1-모듈-해석-방식-변경">1. 모듈 해석 방식 변경</h3>
<p>기존 설정에서 오류가 발생할 수 있습니다:</p>
<pre><code class="language-json">// ❌ 더 이상 권장되지 않음
{
  &quot;compilerOptions&quot;: {
    &quot;moduleResolution&quot;: &quot;node&quot;,
    &quot;module&quot;: &quot;commonjs&quot;
  }
}</code></pre>
<pre><code class="language-json">// ✅ 권장 설정
{
  &quot;compilerOptions&quot;: {
    &quot;module&quot;: &quot;preserve&quot;,
    &quot;moduleResolution&quot;: &quot;bundler&quot;
  }
}</code></pre>
<h3 id="2-typescript-60-호환성">2. TypeScript 6.0 호환성</h3>
<ul>
<li><code>node</code>/<code>node10</code> 해석 방식은 TypeScript 6.0에서 제거될 예정</li>
<li><code>node16</code>, <code>nodenext</code>, <code>bundler</code> 해석 방식 사용 권장</li>
</ul>
<h2 id="로드맵-및-업데이트">로드맵 및 업데이트</h2>
<h3 id="단기-계획-2025년-말까지">단기 계획 (2025년 말까지)</h3>
<ul>
<li><strong>완전한 컴파일러</strong>: <code>--build</code> 등 주요 기능 완성</li>
<li><strong>언어 서비스</strong>: 대부분의 편집기 기능 구현</li>
<li><strong>API 안정화</strong>: API 레이어 완성</li>
</ul>
<h3 id="업데이트-정책">업데이트 정책</h3>
<ul>
<li><strong>야간 빌드</strong>: 매일 새로운 개발 버전 배포</li>
<li><strong>자동 업데이트</strong>: VS Code 확장 프로그램 자동 업데이트</li>
<li><strong>문제 발생 시</strong>: &quot;TypeScript Native Preview: Disable&quot; 명령으로 비활성화 가능</li>
</ul>
<h2 id="개발자-권장사항">개발자 권장사항</h2>
<h3 id="1-시도해보기">1. 시도해보기</h3>
<ul>
<li>새로운 프로젝트나 테스트 환경에서 먼저 시도</li>
<li>기존 프로젝트는 백업 후 테스트</li>
</ul>
<h3 id="2-문제-보고">2. 문제 보고</h3>
<ul>
<li>예상과 다른 동작 발견 시 GitHub 이슈 트래커에 보고</li>
<li>구체적인 재현 단계와 함께 보고</li>
</ul>
<h3 id="3-점진적-도입">3. 점진적 도입</h3>
<ul>
<li>현재는 프리뷰 단계이므로 프로덕션 환경에서는 주의</li>
<li>안정화 후 TypeScript 7로 정식 출시 예정</li>
</ul>
<h2 id="결론">결론</h2>
<p>TypeScript Native Previews는 TypeScript 생태계의 중요한 발전입니다. 10배 빠른 컴파일 속도는 대규모 프로젝트에서 개발자 경험을 크게 향상시킬 것으로 예상됩니다. </p>
<p>현재는 프리뷰 단계이지만, 지속적인 개발과 커뮤니티 피드백을 통해 안정적인 TypeScript 7로 발전할 예정입니다. 개발자들은 이 기회에 새로운 네이티브 TypeScript를 미리 경험해보고 피드백을 제공하는 것이 좋겠습니다.</p>
<hr>
<p><strong>참고 자료</strong>:</p>
<ul>
<li><a href="https://devblogs.microsoft.com/typescript/announcing-typescript-native-previews/">원문: Announcing TypeScript Native Previews</a></li>
<li><a href="https://www.npmjs.com/package/@typescript/native-preview">TypeScript Native Preview npm 패키지</a></li>
<li><a href="https://github.com/microsoft/TypeScript">TypeScript GitHub 저장소</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[부수효과(Side Effect)란?         -javascript-]]></title>
            <link>https://velog.io/@live_in_truth/%EB%B6%80%EC%88%98%ED%9A%A8%EA%B3%BCSide-Effect%EB%9E%80-javascript-</link>
            <guid>https://velog.io/@live_in_truth/%EB%B6%80%EC%88%98%ED%9A%A8%EA%B3%BCSide-Effect%EB%9E%80-javascript-</guid>
            <pubDate>Mon, 09 Jun 2025 14:30:18 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>예측가능한 코드, 상태관리와 밀접한 개념인 부수효과(Side Effect)에 대해 알아보자.</p>
</blockquote>
<h2 id="부수효과side-effect란">부수효과(Side Effect)란?</h2>
<blockquote>
<p>부수효과는 함수가 실행될 때 _<strong>함수 외부의 상태를 변경</strong>_하거나, 외부 상태에 의존하는 모든 행위를 말한다.</p>
</blockquote>
<blockquote>
<p>부수효과에서 언급하는 &#39;외부&#39;는 함수의 스코프 밖에 있는 모든 것을 의미한다. <a href="https://velog.io/@live_in_truth/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%A0%89%EC%8B%9C%EC%BB%AC-%EC%8A%A4%EC%BD%94%ED%94%84lexical-scope-%EB%B9%A0%EB%A5%B4%EA%B2%8C-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0">하.. 스코프는 또 뭐지? =&gt; 클릭</a></p>
</blockquote>
<h3 id="1-예시로-이해해보자">1. 예시로 이해해보자</h3>
<pre><code class="language-typescript">// 🚨 부수효과가 있는 함수들

// 1. 외부 변수 변경
let total = 0;
const addToTotal = (num: number) =&gt; {
  total += num;  // 외부 변수 total을 변경
};

// 2. 콘솔 출력
const logUser = (user: User) =&gt; {
  console.log(user);  // 외부 환경(콘솔)에 출력
};

// 3. API 호출
const saveUser = async (user: User) =&gt; {
  await fetch(&#39;/api/users&#39;, {  // 외부 서버와 통신
    method: &#39;POST&#39;,
    body: JSON.stringify(user)
  });
};

// 4. DOM 조작
const updateUI = (element: HTMLElement) =&gt; {
  element.textContent = &#39;Updated!&#39;;  // DOM 상태 변경
};</code></pre>
<h3 id="2-순수-함수pure-function의-예시">2. 순수 함수(Pure Function)의 예시</h3>
<pre><code class="language-typescript">// ✅ 부수효과가 없는 순수 함수들

// 1. 입력값에 따른 출력값만 반환
const double = (num: number): number =&gt; {
  return num * 2;
};

// 2. 객체 변환
const formatUser = (user: User): FormattedUser =&gt; {
  return {
    fullName: `${user.firstName} ${user.lastName}`,
    age: calculateAge(user.birthDate)
  };
};

// 3. 배열 변환
const filterActiveUsers = (users: User[]): User[] =&gt; {
  return users.filter(user =&gt; user.isActive);
};</code></pre>
<h3 id="3-부수효과의-특징">3. 부수효과의 특징</h3>
<blockquote>
<ol>
<li><strong>예측 불가능성</strong></li>
</ol>
</blockquote>
<ul>
<li>외부 상태에 의존하므로 결과를 예측하기 어려움</li>
<li>테스트가 복잡해짐</li>
</ul>
<pre><code class="language-javascript">// 🚨 예측 불가능성 예시
let globalCount = 0;

const increment = () =&gt; {
  globalCount++;
  return globalCount;
};

console.log(increment()); // 1
console.log(increment()); // 2
// 다른 개발자가 globalCount를 100으로 변경했다면?
console.log(increment()); // 101 (예측 불가능!)

// ✅ 예측 가능한 코드
const increment = (count: number) =&gt; {
  return count + 1;
};

console.log(increment(0)); // 1
console.log(increment(1)); // 2
console.log(increment(2)); // 3 (항상 예측 가능!)</code></pre>
<blockquote>
<ol start="2">
<li><strong>디버깅의 어려움</strong></li>
</ol>
</blockquote>
<ul>
<li><p>문제 발생 시 원인 파악이 어려움</p>
</li>
<li><p>상태 변경의 흐름을 추적하기 어려움</p>
<pre><code class="language-typescript">// 🚨 디버깅이 어려운 코드예시
</code></pre>
</li>
</ul>
<p>// 1. 첫 번째 코드 (부수효과 있음)
let user = { name: &#39;김지성&#39; };</p>
<p>const updateUser = () =&gt; {
  user.name = &#39;박지성&#39;;  // 🚨 외부 변수 직접 수정
  console.log(&#39;User updated&#39;);
};</p>
<p>updateUser();
console.log(user); // { name: &#39;박지성&#39; }</p>
<p>// 2. 두 번째 코드 (순수 함수)
const user = { name: &#39;김지성&#39; };</p>
<p>const updateUser = (user: User) =&gt; {
  return { ...user, name: &#39;박지성&#39; };  // ✅ 새로운 객체 반환
};</p>
<p>const newUser = updateUser(user);
console.log(user);     // { name: &#39;김지성&#39; } (원본 유지)
console.log(newUser);  // { name: &#39;박지성&#39; } (새로운 객체)</p>
<p>주요 차이점:</p>
<ol>
<li><p>원본 데이터 변경 여부</p>
<ul>
<li>첫 번째: 원본 <code>user</code> 객체를 직접 수정</li>
<li>두 번째: 원본은 그대로 두고 새로운 객체를 반환</li>
</ul>
</li>
<li><p>함수의 예측 가능성</p>
<ul>
<li>첫 번째: 함수 호출 시 외부 변수 <code>user</code>의 상태에 따라 결과가 달라짐</li>
<li>두 번째: 입력값이 같으면 항상 같은 결과를 반환</li>
</ul>
</li>
<li><p>디버깅 용이성</p>
<ul>
<li>첫 번째: <code>user.name</code>이 어디서 변경되었는지 추적이 어려움</li>
<li>두 번째: 상태 변경이 명확하게 함수의 반환값으로 표현됨</li>
</ul>
</li>
<li><p>사용 예시
// 첫 번째 방식
let user = { name: &#39;김지성&#39; };
updateUser();
// user가 변경되었는지 확인하려면 user를 직접 확인해야 함</p>
</li>
</ol>
<p>// 두 번째 방식
const user = { name: &#39;박지성&#39; };
const updatedUser = updateUser(user);
// 변경된 내용이 명확하게 updatedUser에 담겨있음</p>
<p>두번째 방식 특히 React의 불변성(Immutability) 원칙에 맞다. 
불변성(Immutability): 데이터가 한번 생성되면 그 값을 변경할 수 없고, 대신 새로운 데이터를 생성하여 사용해야 한다는 원칙.
React에서 불변성을 지키면 상태 변경의 추적이 용이해짐.
예측 가능한 애플리케이션을 만들 수 있다.</p>
<pre><code>
&gt;3. **코드 재사용성 저하**
   - 외부 상태에 의존하므로 다른 환경에서 재사용이 어려움

### 4. 부수효과를 최소화하는 방법

```typescript
// 🚨 부수효과가 많은 코드
class UserManager {
  private users: User[] = [];

  addUser(user: User) {
    this.users.push(user);
    console.log(`User added: ${user.name}`);
    this.saveToDatabase(user);
    this.updateUI();
  }
}

// ✅ 부수효과를 분리한 코드
class UserManager {
  private users: User[] = [];

  // 순수 함수: 데이터 변환만 담당
  addUser(user: User): User[] {
    return [...this.users, user];
  }

  // 부수효과를 명시적으로 분리
  async handleUserAddition(user: User) {
    const newUsers = this.addUser(user);
    await this.saveToDatabase(user);
    this.notifyUserAdded(user);
    this.updateUI(newUsers);
  }
}</code></pre><h3 id="5-react에서의-부수효과-관리">5. React에서의 부수효과 관리</h3>
<h4 id="무한-렌더링-가능성">무한 렌더링 가능성</h4>
<pre><code class="language-typescript">const UserProfile: React.FC = () =&gt; {
  const [user, setUser] = useState&lt;User | null&gt;(null);

  // 이 함수는 컴포넌트가 렌더링될 때마다 새로 생성됨
  const fetchUser = async () =&gt; {
    const response = await fetch(&#39;/api/user&#39;);
    const data = await response.json();
    setUser(data);  // setUser 호출 → 상태 변경 → 컴포넌트 재렌더링
  };

  return &lt;div&gt;{user?.name}&lt;/div&gt;;
};</code></pre>
<blockquote>
<p>문제점:</p>
</blockquote>
<ul>
<li><code>fetchUser</code> 함수가 컴포넌트 내부에 있어서, 컴포넌트가 렌더링될 때마다 새로운 함수가 생성됨</li>
<li>이 함수가 <code>setUser</code>를 호출하면 상태가 변경되어 컴포넌트가 다시 렌더링됨</li>
<li>다시 렌더링되면 <code>fetchUser</code>가 다시 생성되고... 이렇게 무한 루프가 발생할 수 있음</li>
</ul>
<h4 id="데이터-페칭-시점-불명확">데이터 페칭 시점 불명확</h4>
<pre><code class="language-typescript">const UserProfile: React.FC = () =&gt; {
  const [user, setUser] = useState&lt;User | null&gt;(null);

  const fetchUser = async () =&gt; {
    const response = await fetch(&#39;/api/user&#39;);
    const data = await response.json();
    setUser(data);
  };

  // fetchUser를 어디서 호출해야 할지 명확하지 않음
  return &lt;div&gt;{user?.name}&lt;/div&gt;;
};</code></pre>
<blockquote>
<p>문제점:</p>
</blockquote>
<ul>
<li><code>fetchUser</code> 함수는 정의만 되어있고, 어디서 호출해야 할지가 명확하지 않음</li>
<li>컴포넌트가 처음 마운트될 때 자동으로 데이터를 가져오지 않음</li>
<li>사용자가 직접 호출해야 하는지, 자동으로 호출되어야 하는지 불명확</li>
</ul>
<h4 id="부수효과와-렌더링-로직이-섞여있음">부수효과와 렌더링 로직이 섞여있음</h4>
<pre><code class="language-typescript">const UserProfile: React.FC = () =&gt; {
  const [user, setUser] = useState&lt;User | null&gt;(null);

  // 데이터 가져오기 (부수효과)
  const fetchUser = async () =&gt; {
    const response = await fetch(&#39;/api/user&#39;);
    const data = await response.json();
    setUser(data);
  };

  // UI 그리기 (렌더링 로직)
  return &lt;div&gt;{user?.name}&lt;/div&gt;;
};</code></pre>
<blockquote>
<p>문제점:</p>
</blockquote>
<ul>
<li>데이터를 가져오는 로직(<code>fetchUser</code>)과 UI를 그리는 로직(<code>return</code>)이 한 컴포넌트에 섞여있음</li>
<li>이렇게 되면 코드가 복잡해지고 유지보수가 어려워짐</li>
</ul>
<h3 id="개선된-버전">개선된 버전</h3>
<pre><code class="language-typescript">const UserProfile: React.FC = () =&gt; {
  const [user, setUser] = useState&lt;User | null&gt;(null);

  // useEffect로 데이터 가져오기 로직을 분리
  useEffect(() =&gt; {
    const fetchUser = async () =&gt; {
      const response = await fetch(&#39;/api/user&#39;);
      const data = await response.json();
      setUser(data);
    };

    fetchUser();  // 컴포넌트 마운트 시 한 번만 실행
  }, []);  // 빈 배열: 의존성이 없으므로 마운트 시 한 번만 실행

  // UI 그리기 로직만 남음
  return &lt;div&gt;{user?.name}&lt;/div&gt;;
};</code></pre>
<blockquote>
<p>장점:</p>
</blockquote>
<ol>
<li><code>useEffect</code>를 사용해 데이터 가져오기 로직을 분리</li>
<li>컴포넌트 마운트 시 한 번만 실행되도록 명확하게 지정</li>
<li>UI 그리기 로직만 남아서 코드가 깔끔해짐</li>
</ol>
<p>이렇게 하면 코드가 더 예측 가능하고 유지보수하기 쉬워짐</p>
<h2 id="결론">결론</h2>
<blockquote>
<p>이 글을 여기까지 훑고 <strong>부수효과가 무엇</strong>이고, 프로그램에 어떤 영향을 미칠 수 있는지 정도 이해했다면 성공적이라고 생각한다.
부수효과는 코드의 예측 가능성과 유지보수성을 저하시키는 주요 원인이다. 하지만 현실적인 프로그래밍에서 부수효과를 완전히 제거하기는 불가능에 가깝다. </p>
</blockquote>
<blockquote>
<p>따라서 <strong>이 글의 핵심은 부수효과의 제거가 아닌 _&#39;이 함수를 호출하면 외부에 어떤 영향을 줄지 코드만 봐도 알 수 있게 하자&#39;_이다.</strong></p>
</blockquote>
<pre><code class="language-typescript">// ❌ 숨겨진 부수효과
const addToCart = (item) =&gt; {
  const newItem = { ...item, id: Date.now() };
  cart.push(newItem); // 🚨 전역 배열 변경 (숨겨진 부수효과)
  return newItem;
};

// ✅ 명시적 부수효과
const createCartItem = (item) =&gt; {
  return { ...item, id: Date.now() }; // 순수 함수
};

const addToCart = (item) =&gt; {
  const newItem = createCartItem(item);
  cart.push(newItem); // 명시적으로 전역 상태 변경
  return newItem;
};</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[3계층 구조(3-Tier Architecture)의 이해와 실제 적용]]></title>
            <link>https://velog.io/@live_in_truth/3%EA%B3%84%EC%B8%B5-%EA%B5%AC%EC%A1%B03-Tier-Architecture%EC%9D%98-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%8B%A4%EC%A0%9C-%EC%A0%81%EC%9A%A9</link>
            <guid>https://velog.io/@live_in_truth/3%EA%B3%84%EC%B8%B5-%EA%B5%AC%EC%A1%B03-Tier-Architecture%EC%9D%98-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%8B%A4%EC%A0%9C-%EC%A0%81%EC%9A%A9</guid>
            <pubDate>Thu, 17 Apr 2025 07:07:58 GMT</pubDate>
            <description><![CDATA[<h2 id="3계층-구조가-생긴-배경">3계층 구조가 생긴 배경</h2>
<p>웹 애플리케이션 개발이 점점 복잡해지면서, 초기의 단일 구조(Monolithic) 애플리케이션은 여러 문제점을 드러냈습니다. 이런 문제를 해결하기 위해 등장한 것이 <strong>3계층 구조(3-Tier Architecture)</strong> 입니다. IBM, Oracle, Microsoft 등의 기업들은 엔터프라이즈 애플리케이션 개발 가이드에서 단일 구조의 한계를 극복하기 위한 다계층 아키텍처의 중요성을 강조해왔습니다.</p>
<h3 id="단일-구조의-문제점">단일 구조의 문제점</h3>
<p><strong>모든 것이 한 곳에 섞임:</strong></p>
<blockquote>
<ul>
<li>한 파일에 HTML, CSS, JavaScript, 데이터베이스 쿼리가 모두 섞여 있어 변경이 어려웠습니다.</li>
</ul>
</blockquote>
<ul>
<li>화면 디자인만 바꾸고 싶어도 데이터 처리 코드까지 건드려야 했습니다.</li>
<li>TV 채널만 바꾸려고 할 때마다 전체 설정을 들어가서 바꿔야 하는 느낌.</li>
</ul>
<p><strong>코드 재활용이 어려움:</strong></p>
<blockquote>
<ul>
<li>모듈화가 되지 않으니 같은 기능이 필요할 때마다 처음부터 다시 코드를 작성해야 했습니다.</li>
</ul>
</blockquote>
<p><strong>테스트가 복잡:</strong></p>
<blockquote>
<ul>
<li>특정 기능만 테스트하고 싶어도 전체를 실행해야 했습니다.</li>
</ul>
</blockquote>
<p>이러한 문제를 해결하기 위해 애플리케이션을 기능별로 분리하는 계층화된 접근 방식이 필요!</p>
<svg viewBox="0 0 800 400" xmlns="http://www.w3.org/2000/svg">
  <!-- 배경 -->
  <rect width="800" height="400" fill="#f8f9fa" rx="10" ry="10"/>

  <!-- 3계층 박스 -->
  <rect x="150" y="30" width="500" height="100" fill="#4285f4" rx="5" ry="5" opacity="0.8"/>
  <rect x="150" y="150" width="500" height="100" fill="#34a853" rx="5" ry="5" opacity="0.8"/>
  <rect x="150" y="270" width="500" height="100" fill="#fbbc05" rx="5" ry="5" opacity="0.8"/>

  <!-- 계층 이름 -->
<p>  <text x="400" y="80" font-family="Arial" font-size="24" fill="white" text-anchor="middle">프레젠테이션 계층 (Presentation Tier)</text>
  <text x="400" y="110" font-family="Arial" font-size="18" fill="white" text-anchor="middle">React, Redux, 컴포넌트, UI</text></p>
<p>  <text x="400" y="200" font-family="Arial" font-size="24" fill="white" text-anchor="middle">비즈니스 계층 (Business Tier)</text>
  <text x="400" y="230" font-family="Arial" font-size="18" fill="white" text-anchor="middle">UseCase, 비즈니스 로직, 인터페이스</text></p>
<p>  <text x="400" y="320" font-family="Arial" font-size="24" fill="white" text-anchor="middle">데이터 계층 (Data Tier)</text>
  <text x="400" y="350" font-family="Arial" font-size="18" fill="white" text-anchor="middle">Repository 구현체, API 호출, DB 접근</text></p>
  <!-- 화살표 -->
  <path d="M400 130 L400 150" stroke="#333" stroke-width="3" fill="none" marker-end="url(#arrowhead)"/>
  <path d="M400 250 L400 270" stroke="#333" stroke-width="3" fill="none" marker-end="url(#arrowhead)"/>

  <!-- 화살표 마커 정의 -->
  <defs>
    <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
      <polygon points="0 0, 10 3.5, 0 7" fill="#333"/>
    </marker>
  </defs>
</svg>

<h2 id="3계층-구조란">3계층 구조란?</h2>
<blockquote>
</blockquote>
<p>3계층 구조는 애플리케이션을 논리적/물리적으로 세 개의 독립된 계층으로 나누어 구성하는 아키텍처 패턴입니다. 각 계층은 특정 책임을 담당하며, 서로 간의 의존성을 최소화합니다.</p>
<h3 id="1-프레젠테이션-계층-presentation-tier">1. 프레젠테이션 계층 (Presentation Tier)</h3>
<blockquote>
<ul>
<li><strong>역할</strong>: 사용자와 직접 상호작용하는 인터페이스 담당</li>
</ul>
</blockquote>
<ul>
<li><strong>포함 요소</strong>: UI 컴포넌트, 사용자 입력 처리, 데이터 표시</li>
<li><strong>프론트엔드 영역</strong>: 사용자가 직접 마주하는 부분</li>
</ul>
<h3 id="2-비즈니스-계층-businessapplication-tier">2. 비즈니스 계층 (Business/Application Tier)</h3>
<blockquote>
<ul>
<li><strong>역할</strong>: 비즈니스 로직과 규칙 처리</li>
</ul>
</blockquote>
<ul>
<li><strong>포함 요소</strong>: 데이터 검증, 비즈니스 규칙 적용, UseCase 구현</li>
<li><strong>미들웨어 영역</strong>: 프레젠테이션과 데이터 계층 사이의 중개자</li>
</ul>
<h3 id="3-데이터-계층-data-tier">3. 데이터 계층 (Data Tier)</h3>
<blockquote>
<ul>
<li><strong>역할</strong>: 데이터 저장 및 접근</li>
</ul>
</blockquote>
<ul>
<li><strong>포함 요소</strong>: 데이터베이스, 데이터 접근 로직</li>
<li><strong>백엔드 영역</strong>: 실제 데이터 관리를 담당</li>
</ul>
<h2 id="코드로-보는-3계층-구조">코드로 보는 3계층 구조</h2>
<p>실제 진행중인 프로젝트 코드를 통해 각 계층의 구현을 살펴보겠습니다.</p>
<h3 id="1-데이터-계층-repository-구현체">1. 데이터 계층: Repository 구현체</h3>
<pre><code class="language-typescript">// 데이터 계층: UserRepositoryImpl.ts
export class UserRepositoryImpl implements UserRepository {
  async getUser(): Promise&lt;User&gt; {
    const response = await fetch(&#39;https://XXXXXX.co.kr/product/user&#39;, {
      method: &#39;GET&#39;,
      headers: {
        &#39;Content-Type&#39;: &#39;application/json&#39;,
        Authorization: `Bearer ${localStorage.getItem(&#39;XXXX-accessToken&#39;)}`,
      },
    });

    if (!response.ok) {
      throw new Error(&#39;존재하지 않는 id입니다. 관리자에게 문의해주세요.&#39;);
    }

    const data = await response.json();
    return {
      userId: data.userId,
      name: data.name,
      // 기타 필드...
    };
  }
}</code></pre>
<blockquote>
<p>데이터 계층은 <code>UserRepositoryImpl</code> 클래스로 구현되며, <strong>API 호출을 통해 실제 데이터를 가져오는 역할</strong>을 합니다.</p>
</blockquote>
<h3 id="2-비즈니스-계층-usecase-구현">2. 비즈니스 계층: UseCase 구현</h3>
<pre><code class="language-typescript">// 비즈니스 계층: GetUserUseCase.ts
export class GetUserUseCase {
  constructor(private repository: UserRepository) {}

  async execute(): Promise&lt;User&gt; {
    return this.repository.getUser();
  }
}</code></pre>
<blockquote>
<p>비즈니스 계층은 <code>GetUserUseCase</code> 클래스로 구현되며, 데이터 계층에 의존하지만 <strong>구체적인 구현체가 아닌 인터페이스에 의존</strong>합니다. 개인적으로 이 부분이 아키텍처의 핵심이라고 생각합니다. 이유는 DIP와 SOLID와 연관되어있는데 밑에서 더 자세히 설명드리겠습니다.</p>
</blockquote>
<h3 id="3-프레젠테이션-계층">3. 프레젠테이션 계층</h3>
<pre><code class="language-typescript">// 프레젠테이션 계층: actions.ts
export const getUserAction = createAsyncThunk&lt;User, void, { rejectValue: string }&gt;(
  &#39;user/getUser&#39;,
  async (_, { rejectWithValue }) =&gt; {
    const useCase = new GetUserUseCase(repository);
    try {
      const user = await useCase.execute();
      return user;
    } catch (error) {
      return rejectWithValue((error as Error).message);
    }
  },
);</code></pre>
<blockquote>
<p>이 예시에서는 Redux를 사용하여 프레젠테이션 계층을 구현했습니다. 이것은 3계층 구조에서 필수적인 기술이 아니라, 제가 진행중인 프로젝트의 요구사항에 맞게 선택된 구현 방식입니다.</p>
</blockquote>
<h2 id="사용자-정보-가져오기-과정-요약">사용자 정보 가져오기 과정 요약</h2>
<blockquote>
<ol>
<li><strong>사용자 요청</strong> → <strong>프레젠테이션 계층</strong> 접근</li>
</ol>
</blockquote>
<ul>
<li>사용자가 프로필 페이지를 열거나 &quot;정보 가져오기&quot; 버튼 클릭</li>
</ul>
<blockquote>
<ol start="2">
<li><strong>Redux 액션</strong> → <strong>비즈니스 계층</strong> 호출</li>
</ol>
</blockquote>
<ul>
<li><code>getUserAction</code>이 <code>GetUserUseCase</code> 호출</li>
</ul>
<blockquote>
<ol start="3">
<li><strong>UseCase</strong> → <strong>데이터 계층 인터페이스</strong> 접근</li>
</ol>
</blockquote>
<ul>
<li><code>GetUserUseCase</code>가 <code>UserRepository</code> 인터페이스의 메서드 호출</li>
</ul>
<blockquote>
<ol start="4">
<li><strong>Repository 구현체</strong> → <strong>외부 API</strong> 요청</li>
</ol>
</blockquote>
<ul>
<li><code>UserRepositoryImpl</code>이 실제 서버 API에 HTTP 요청</li>
</ul>
<blockquote>
<ol start="5">
<li><strong>API 응답</strong> → <strong>역순으로 데이터 전달</strong> → <strong>화면 표시</strong></li>
</ol>
</blockquote>
<ul>
<li>서버 응답 → Repository → UseCase → Redux → UI 컴포넌트</li>
</ul>
<h2 id="각-계층을-연결하는-인터페이스의-중요성">각 계층을 연결하는 인터페이스의 중요성</h2>
<blockquote>
<p>3계층 구조에서 핵심은 각 계층 간의 <strong>인터페이스</strong>입니다. 3계층 구조와 SOLID/DIP는 필수적인 상관관계를 갖는 것은 아니지만, 함께 사용될 때 코드 품질과 유지보수성을 크게 향상시킵니다.</p>
</blockquote>
<h3 id="soliddip를-적용한-3계층-구조-vs-적용하지-않은-구조">SOLID/DIP를 적용한 3계층 구조 vs. 적용하지 않은 구조</h3>
<h4 id="dip-적용-현재-프로젝트">DIP 적용 (현재 프로젝트)</h4>
<pre><code class="language-typescript">// 인터페이스 (추상화)
interface UserRepository {
  getUser(): Promise&lt;User&gt;;
}

// 비즈니스 계층: 인터페이스에 의존
class GetUserUseCase {
  constructor(private repository: UserRepository) {}

  async execute(): Promise&lt;User&gt; {
    return this.repository.getUser();
  }
}</code></pre>
<h4 id="dip-미적용">DIP 미적용</h4>
<pre><code class="language-typescript">// 비즈니스 계층: 구체적인 구현체에 직접 의존
class GetUserUseCase {
  private repository = new UserRepository(); // 직접 의존!

  async execute(): Promise&lt;User&gt; {
    return this.repository.getUser();
  }
}</code></pre>
<h3 id="핵심-차이점">핵심 차이점</h3>
<blockquote>
<ol>
<li><strong>인터페이스 사용</strong></li>
</ol>
</blockquote>
<ul>
<li>DIP 적용: 인터페이스를 통한 추상화로 유연성 확보</li>
<li>DIP 미적용: 구체적인 구현체에 직접 의존으로 유연성 감소</li>
</ul>
<blockquote>
<ol start="2">
<li><strong>의존성 주입</strong></li>
</ol>
</blockquote>
<ul>
<li>DIP 적용: 생성자를 통해 외부에서 의존성 주입</li>
<li>DIP 미적용: 내부에서 직접 의존성 생성</li>
</ul>
<blockquote>
<ol start="3">
<li><strong>결합도</strong></li>
</ol>
</blockquote>
<ul>
<li>DIP 적용: 느슨한 결합으로 변경에 유연하게 대응</li>
<li>DIP 미적용: 강한 결합으로 변경 시 여러 부분 수정 필요</li>
</ul>
<blockquote>
<ol start="4">
<li><strong>테스트 용이성</strong></li>
</ol>
</blockquote>
<ul>
<li>DIP 적용: Mock 객체로 쉽게 대체 가능</li>
<li>DIP 미적용: 테스트 시 실제 API 호출 필요</li>
</ul>
<h2 id="3계층-구조의-장점">3계층 구조의 장점</h2>
<blockquote>
<ol>
<li><strong>관심사의 분리</strong></li>
</ol>
</blockquote>
<ul>
<li><strong>각 계층은 명확한 책임(이것이 3계층의 핵심)</strong>을 가져 코드 이해도가 향상됩니다.</li>
</ul>
<blockquote>
<ol start="2">
<li><strong>재사용성 증가</strong></li>
</ol>
</blockquote>
<ul>
<li>비즈니스 로직과 데이터 접근 로직을 여러 상황에서 재사용할 수 있습니다.</li>
</ul>
<blockquote>
<ol start="3">
<li><strong>테스트 용이성</strong></li>
</ol>
</blockquote>
<ul>
<li>각 계층을 독립적으로 테스트할 수 있어 품질 보증이 쉬워집니다.</li>
</ul>
<blockquote>
<ol start="4">
<li><strong>유지보수성 향상</strong></li>
</ol>
</blockquote>
<ul>
<li>특정 계층의 변경이 다른 계층에 미치는 영향을 최소화합니다.</li>
</ul>
<blockquote>
<ol start="5">
<li><strong>확장성 개선</strong></li>
</ol>
</blockquote>
<ul>
<li>각 계층을 독립적으로 확장할 수 있어 성장하는 애플리케이션에 적합합니다.</li>
</ul>
<h2 id="결론">결론</h2>
<p>3계층 구조는 복잡한 애플리케이션의 유지보수성, 확장성, 테스트 용이성을 높이는 효과적인 아키텍처 패턴입니다. 모든 상황에 적합한 것은 아니지만, 프로젝트가 성장함에 따라 그 가치가 더욱 분명해질 것 같은 느낌입니다.</p>
<p>핵심은 각 계층 간의 <strong>인터페이스</strong>를 통한 의존성 관리입니다. 이는 SOLID 원칙 중 DIP(의존성 역전 원칙)와 직접적으로 연관되며, 코드의 유연성과 테스트 용이성을 크게 향상시킵니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[클로저 실전편(feat: React, Redux)]]></title>
            <link>https://velog.io/@live_in_truth/%ED%81%B4%EB%A1%9C%EC%A0%80-%EC%8B%A4%EC%A0%84%ED%8E%B8feat-React-Redux</link>
            <guid>https://velog.io/@live_in_truth/%ED%81%B4%EB%A1%9C%EC%A0%80-%EC%8B%A4%EC%A0%84%ED%8E%B8feat-React-Redux</guid>
            <pubDate>Thu, 20 Mar 2025 07:14:31 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/live_in_truth/post/5fc65269-23df-4c04-9e70-453eab8c9860/image.png" alt=""></p>
<h1 id="문제-상황-상태는-변했는데-콘솔에는-예전-값이">문제 상황: 상태는 변했는데 콘솔에는 예전 값이?</h1>
<p>리액트와 리덕스로 개발하다 보니 이런 상황을 자주 마주쳤습니다.</p>
<pre><code class="language-javascript">// Redux 상태를 가져옴
const userDataState = useAppSelector(selectUserState);

useEffect(() =&gt; {
  // Redux 액션 디스패치
  dispatch(getUserAction())
    .unwrap()
    .then(() =&gt; {
      // 데이터가 바뀌었을 거라 기대하지만...
      console.log(&#39;userDataState:&#39;, userDataState); // 여전히 초기값(null)이 출력됨 😱
    });
}, []);</code></pre>
<blockquote>
<p>위 코드에서 저는 <code>getUserAction</code>이 성공적으로 완료된 후 업데이트된 <code>userDataState</code>를 콘솔에서 보길 기대했습니다. 하지만 실제로는 변경 전의 값(보통 초기값인 null)이 출력됩니다. (더 정확히는 리듀서에서 loading 값이 false로 나옵니다. 일단 값이 안들어갔다고 생각하시면 됩니다.)</p>
</blockquote>
<h2 id="왜-이런-일이-발생할까">왜 이런 일이 발생할까?</h2>
<blockquote>
<p>&quot;클로저&quot; 때문입니다 <a href="https://velog.io/@live_in_truth/%ED%81%B4%EB%A1%9C%EC%A0%80%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-">클로저가 뭐지? 클릭</a></p>
</blockquote>
<blockquote>
<p>자바스크립트의 클로저(Closure)란 _<strong>함수가 자신이 생성된 환경의 변수를 기억하는 특성</strong>_입니다. </p>
</blockquote>
<blockquote>
<p>이 코드에서:</p>
</blockquote>
<ol>
<li><code>.then(() =&gt; { ... })</code> 콜백 함수가 생성되는 시점에 <code>userDataState</code>는 초기값(null)입니다.</li>
<li>이 콜백은 해당 시점의 <code>userDataState</code> 값을 &quot;기억&quot;합니다.</li>
<li>비동기 작업이 완료되어 Redux 상태가 업데이트되더라도, 이미 생성된 콜백 내부의 <code>userDataState</code> 참조는 여전히 초기값을 가리킵니다.</li>
</ol>
<h2 id="실제-사례와-문제점">실제 사례와 문제점</h2>
<p>제가 개발 중인 로그인 프로세스에서 이러한 문제가 발생했습니다:</p>
<pre><code class="language-javascript">dispatch(getUserAction())
  .unwrap()
  .then(() =&gt; {
    console.log(&#39;userDataState from getUserAction&#39;, userDataState); // null이 출력됨

    dispatch(initUserAction())
      .unwrap()
      .then(() =&gt; {
        console.log(&#39;userDataState from initUserAction&#39;, userDataState); // 여전히 null 출력됨

        // 이후 로직...
      });
  });</code></pre>
<blockquote>
<p>이 문제로 인해:</p>
</blockquote>
<ol>
<li>상태 업데이트 여부를 콘솔로 확인하기 어려웠습니다.</li>
<li>업데이트된 상태에 의존하는 후속 로직이 올바르게 동작하지 않았습니다.</li>
<li>디버깅이 복잡해졌습니다.</li>
</ol>
<h2 id="해결-방법-클로저-함정-피하기">해결 방법: 클로저 함정 피하기</h2>
<h3 id="1-액션-결과-직접-사용하기">1. 액션 결과 직접 사용하기</h3>
<blockquote>
<p>방법 중 하나는 Redux 상태를 참조하지 않고, 액션의 결과를 직접 사용하는 것입니다:</p>
</blockquote>
<pre><code class="language-javascript">dispatch(getUserAction())
  .unwrap()
  .then((userResult) =&gt; {
    console.log(&#39;User data from action result:&#39;, userResult); // 여기서는 최신 데이터 접근 가능

    // 다음 액션으로 필요한 값 전달
    return dispatch(initUserAction()).unwrap().then(() =&gt; userResult.userId);
  })
  .then((userId) =&gt; {
    // 전달받은 값으로 작업
    dispatch(fetchProducts({ userId: Number(userId) }));
  });</code></pre>
<h3 id="2-promise-체인-활용하기">2. Promise 체인 활용하기</h3>
<blockquote>
<p>Promise 체인을 사용하여 각 단계의 결과를 다음 단계로 전달합니다:</p>
</blockquote>
<pre><code class="language-javascript">dispatch(getUserAction())
  .unwrap()
  .then(() =&gt; {
    const userId = localStorage.getItem(&#39;userId&#39;);
    if (!userId) throw new Error(&#39;사용자 ID를 찾을 수 없습니다.&#39;);

    // 이 값을 다음 단계로 전달
    return dispatch(initUserAction()).unwrap().then(() =&gt; userId);
  })
  .then((userId) =&gt; {
    // 전달받은 userId 사용
    return dispatch(fetchProducts({ userId: Number(userId) }));
  })
  .then(() =&gt; {
    // 최종 성공 처리
    message.success(&#39;로그인에 성공했습니다.&#39;);
    navigate(&#39;/admin&#39;);
  });</code></pre>
<h3 id="3-필요한-시점에-상태-다시-가져오기">3. 필요한 시점에 상태 다시 가져오기</h3>
<blockquote>
<p>리덕스 스토어에 직접 접근하여 최신 상태를 가져올 수도 있습니다:</p>
</blockquote>
<pre><code class="language-javascript">import { store } from &#39;../path/to/store&#39;;

dispatch(getUserAction())
  .unwrap()
  .then(() =&gt; {
    // 스토어에서 최신 상태 직접 가져오기
    const currentState = store.getState();
    console.log(&#39;Current user state:&#39;, currentState.user);

    // 이후 로직...
  });</code></pre>
<h2 id="교훈">교훈</h2>
<ol>
<li><p><strong>클로저의 작동 방식 이해하기</strong>: 비동기 콜백에서 외부 변수를 참조할 때 클로저 함정에 주의하자.</p>
</li>
<li><p><strong>상태 의존성 최소화하기</strong>: 비동기 액션 체인에서는 이전 단계의 결과를 직접 다음 단계로 전달하자.</p>
</li>
<li><p><strong>필요시 최신 상태 직접 접근하기</strong>: 꼭 필요하다면 스토어에서 최신 상태를 직접 가져오는 방법을 사용하자</p>
</li>
<li><p><strong>디버깅 전략 세우기</strong>: 상태 변화를 디버깅할 때는 컴포넌트 리렌더링이나 useEffect가 실행되는 시점에 로그를 확인하자.</p>
</li>
</ol>
<h2 id="정리">정리</h2>
<blockquote>
<ul>
<li>클로저 좋다. </li>
</ul>
</blockquote>
<ul>
<li>하지만 비동기 환경에서 명심하자. </li>
<li>특히 상태 관리에서.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[useState를 조건문 안에서 사용하면 안 되는 이유]]></title>
            <link>https://velog.io/@live_in_truth/useState%EB%A5%BC-%EC%A1%B0%EA%B1%B4%EB%AC%B8-%EC%95%88%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%A9%B4-%EC%95%88-%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@live_in_truth/useState%EB%A5%BC-%EC%A1%B0%EA%B1%B4%EB%AC%B8-%EC%95%88%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%A9%B4-%EC%95%88-%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Wed, 05 Mar 2025 07:12:12 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/live_in_truth/post/e617b87a-a451-4080-ae07-9c70d4b874ff/image.png" alt=""></p>
<blockquote>
<p>&quot;<strong>Hook은 컴포넌트의 최상위 레벨에서만 호출해야 한다&quot;</strong></p>
</blockquote>
<blockquote>
<p>리액트를 사용하다 보면 마주치는 규칙 중 하나는 &quot;Hook은 컴포넌트의 최상위 레벨에서만 호출해야 한다&quot;는 것이다. 특히 <code>useState</code>를 조건문이나 반복문, 중첩된 함수 내부에서 사용하면 안 된다. 이 규칙을 어기면 어떤 문제가 발생하는지, 그리고 왜 이런 규칙이 존재하는지 자세히 알아보자.</p>
</blockquote>
<h2 id="리액트-hooks의-동작-원리">리액트 Hooks의 동작 원리</h2>
<h3 id="hook과-순서-의존성">Hook과 순서 의존성</h3>
<blockquote>
<p>리액트는 내부적으로 컴포넌트의 상태(state)를 관리하기 위해 <strong>&#39;순서&#39;</strong>에 의존한다. 컴포넌트가 렌더링될 때마다 Hook이 호출되는 순서를 기억하여 각 Hook과 해당 상태를 연결한다.</p>
</blockquote>
<p>예를 들어, 다음과 같은 컴포넌트가 있다고 가정해 보자.</p>
<pre><code class="language-jsx">function ProfileCard() {
  const [name, setName] = useState(&#39;홍길동&#39;);       // 첫 번째 Hook
  const [age, setAge] = useState(30);             // 두 번째 Hook
  const [isAdmin, setIsAdmin] = useState(false);  // 세 번째 Hook

  // ...
}</code></pre>
<p>리액트는 내부적으로 이 Hook들을 배열 형태로 저장하고 관리한다. 첫 번째 렌더링에서는:</p>
<blockquote>
<ol>
<li>첫 번째 <code>useState</code>: &#39;name&#39; 상태를 &#39;홍길동&#39;으로 초기화</li>
<li>두 번째 <code>useState</code>: &#39;age&#39; 상태를 30으로 초기화</li>
<li>세 번째 <code>useState</code>: &#39;isAdmin&#39; 상태를 false로 초기화</li>
</ol>
</blockquote>
<p>다음 렌더링에서도 같은 순서로 Hook이 호출되기 때문에, 리액트는 각 Hook 호출이 어떤 상태와 연결되어 있는지 정확히 알 수 있다.</p>
<h2 id="조건부-hook-사용-시-발생하는-문제">조건부 Hook 사용 시 발생하는 문제</h2>
<p>이제 <code>useState</code>를 조건문 안에서 사용하면 어떤 일이 발생하는지 살펴보자.</p>
<pre><code class="language-jsx">function ProfileCard({ isAdmin }) {
  const [name, setName] = useState(&#39;홍길동&#39;);       // 항상 첫 번째 Hook

  if (isAdmin) {
    const [adminSince, setAdminSince] = useState(&#39;2023-01-01&#39;);  // 조건부 두 번째 Hook
  }

  const [age, setAge] = useState(30);             // 조건에 따라 두 번째 또는 세 번째 Hook

  // ...
}</code></pre>
<p>첫 렌더링에서 <code>isAdmin</code>이 <code>true</code>인 경우:</p>
<blockquote>
<ol>
<li>첫 번째 <code>useState</code>: &#39;name&#39; 상태 초기화</li>
<li>두 번째 <code>useState</code>: &#39;adminSince&#39; 상태 초기화</li>
<li>세 번째 <code>useState</code>: &#39;age&#39; 상태 초기화</li>
</ol>
</blockquote>
<p>하지만 다음 렌더링에서 <code>isAdmin</code>이 <code>false</code>로 바뀌면:</p>
<blockquote>
<ol>
<li>첫 번째 <code>useState</code>: &#39;name&#39; 상태 (유지)</li>
<li><strong>두 번째 <code>useState</code>가 호출되지 않음</strong></li>
<li>두 번째(원래는 세 번째) <code>useState</code>: 이제 이 Hook은 이전 렌더링의 &#39;adminSince&#39; 상태를 참조하게 된다.</li>
</ol>
</blockquote>
<p>이렇게 되면 리액트는 &#39;age&#39; 상태를 &#39;adminSince&#39; 상태로 오인하게 되며, 이는 버그를 발생시킬 수 있다.</p>
<h2 id="실제-예시로-살펴보기">실제 예시로 살펴보기</h2>
<p>더 구체적인 예시로 문제를 살펴보자.</p>
<pre><code class="language-jsx">function Counter({ showSpecialCounter }) {
  const [count, setCount] = useState(0);

  if (showSpecialCounter) {
    const [specialCount, setSpecialCount] = useState(10);
  }

  const [step, setStep] = useState(1);

  return (
    &lt;div&gt;
      &lt;p&gt;일반 카운터: {count}&lt;/p&gt;
      &lt;button onClick={() =&gt; setCount(count + step)}&gt;증가&lt;/button&gt;
      &lt;p&gt;스텝: {step}&lt;/p&gt;
      &lt;button onClick={() =&gt; setStep(step + 1)}&gt;스텝 증가&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>이 컴포넌트는 다음과 같은 시나리오에서 문제가 발생한다:</p>
<blockquote>
<ol>
<li>처음에 <code>showSpecialCounter</code>가 <code>true</code>인 경우:</li>
</ol>
</blockquote>
<ul>
<li>첫 번째 Hook: <code>count</code> = 0</li>
<li>두 번째 Hook: <code>specialCount</code> = 10</li>
<li>세 번째 Hook: <code>step</code> = 1</li>
</ul>
<blockquote>
<ol start="2">
<li>사용자가 &quot;스텝 증가&quot; 버튼을 클릭하여 <code>step</code>을 2로 변경한다.</li>
</ol>
</blockquote>
<blockquote>
<ol start="3">
<li>부모 컴포넌트에서 <code>showSpecialCounter</code>를 <code>false</code>로 변경한다.</li>
</ol>
</blockquote>
<blockquote>
<ol start="4">
<li>다음 렌더링에서:</li>
</ol>
</blockquote>
<ul>
<li>첫 번째 Hook: <code>count</code> = 0 (유지)</li>
<li>두 번째 Hook: 이제 <code>specialCount</code>의 Hook이 사라지고, 원래 세 번째였던 Hook이 두 번째가 된다.</li>
<li>리액트는 두 번째 Hook에 저장된 값(원래는 <code>specialCount</code>의 10)을 <code>step</code>의 값으로 사용한다.</li>
</ul>
<blockquote>
<p>결과적으로 <code>step</code>은 사용자가 설정한 2가 아닌 10으로 표시되며, &quot;증가&quot; 버튼을 클릭하면 <code>count</code>가 1씩 증가하는 것이 아니라 10씩 증가하게 된다.</p>
</blockquote>
<h2 id="리액트-개발자-도구-경고">리액트 개발자 도구 경고</h2>
<blockquote>
<p>리액트는 이러한 문제를 방지하기 위해 개발 모드에서 Hook 규칙 위반을 감지하고 경고를 표시한다.</p>
</blockquote>
<pre><code>React Hook &quot;useState&quot; is called conditionally. React Hooks must be called in the exact same order in every component render.</code></pre><p>이 경고는 우리가 앞서 살펴본 문제를 방지하기 위한 것이다.</p>
<h2 id="조건부-상태를-관리하는-올바른-방법">조건부 상태를 관리하는 올바른 방법</h2>
<blockquote>
<p>조건부로 상태를 사용해야 하는 경우, Hook을 컴포넌트 최상위 레벨에 배치하고 조건을 내부 로직에 적용하는 것이 올바른 방법이다.</p>
</blockquote>
<pre><code class="language-jsx">function ProfileCard({ isAdmin }) {
  const [name, setName] = useState(&#39;홍길동&#39;);
  const [adminSince, setAdminSince] = useState(isAdmin ? &#39;2023-01-01&#39; : null);
  const [age, setAge] = useState(30);

  // adminSince를 조건부로 사용
  const adminSection = isAdmin &amp;&amp; (
    &lt;div&gt;
      &lt;h3&gt;관리자 정보&lt;/h3&gt;
      &lt;p&gt;관리자 등록일: {adminSince}&lt;/p&gt;
    &lt;/div&gt;
  );

  return (
    &lt;div&gt;
      &lt;h2&gt;{name}, {age}세&lt;/h2&gt;
      {adminSection}
    &lt;/div&gt;
  );
}</code></pre>
<p>또는 조건에 따라 다른 컴포넌트를 렌더링하는 방법도 있다:</p>
<pre><code class="language-jsx">function AdminProfile() {
  const [adminSince, setAdminSince] = useState(&#39;2023-01-01&#39;);
  // ...
  return &lt;div&gt;관리자 프로필...&lt;/div&gt;;
}

function UserProfile() {
  // 관리자 상태 없음
  // ...
  return &lt;div&gt;일반 사용자 프로필...&lt;/div&gt;;
}

function ProfileContainer({ isAdmin }) {
  return isAdmin ? &lt;AdminProfile /&gt; : &lt;UserProfile /&gt;;
}</code></pre>
<h2 id="결론">결론</h2>
<blockquote>
<p>리액트의 Hook은 호출 순서에 의존하여 상태를 관리하는 특성을 가지고 있다. 따라서 <code>useState</code>와 같은 Hook은 항상 컴포넌트의 최상위 레벨에서, 그리고 렌더링마다 동일한 순서로 호출되어야 한다. </p>
</blockquote>
<blockquote>
<p>조건문 안에서 Hook을 사용하면 렌더링마다 Hook의 호출 순서가 바뀔 수 있어 의도치 않은 상태 불일치와 버그가 발생할 수 있다. 이를 방지하기 위해서는 Hook을 최상위에 배치하고, 조건부 로직은 Hook 호출 이후에 처리하는 것이 중요하다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[트렁크(Trunk) 기반 개발: 현대 소프트웨어 개발의 핵심 전략]]></title>
            <link>https://velog.io/@live_in_truth/Trunk-%EB%B9%A4%EC%8A%A4%EC%9D%B8%EA%B0%80-%ED%8A%B8%EB%A0%81%ED%81%ACTrunk-%EA%B8%B0%EB%B0%98-%EA%B0%9C%EB%B0%9C-%ED%98%84%EB%8C%80-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EA%B0%9C%EB%B0%9C%EC%9D%98-%ED%95%B5%EC%8B%AC-%EC%A0%84%EB%9E%B5</link>
            <guid>https://velog.io/@live_in_truth/Trunk-%EB%B9%A4%EC%8A%A4%EC%9D%B8%EA%B0%80-%ED%8A%B8%EB%A0%81%ED%81%ACTrunk-%EA%B8%B0%EB%B0%98-%EA%B0%9C%EB%B0%9C-%ED%98%84%EB%8C%80-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%EA%B0%9C%EB%B0%9C%EC%9D%98-%ED%95%B5%EC%8B%AC-%EC%A0%84%EB%9E%B5</guid>
            <pubDate>Mon, 17 Feb 2025 05:15:19 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.atlassian.com/continuous-delivery/continuous-integration/trunk-based-development">참고문서 </a>
<img src="https://velog.velcdn.com/images/live_in_truth/post/0b992da7-383e-4027-a964-b006bc7bf1d7/image.png" alt="">
<strong>핵심 키워드</strong></p>
<blockquote>
<ul>
<li>트렁크(Trunk) / 메인 브랜치(Main Branch)</li>
</ul>
</blockquote>
<ul>
<li>CI/CD (지속적 통합/배포)</li>
<li>소규모 빈번한 커밋</li>
<li>피처 플래그(Feature Flag)</li>
<li>자동화된 테스트</li>
<li>코드 리뷰</li>
</ul>
<h2 id="들어가며-왜-트렁크-기반-개발인가">들어가며: 왜 트렁크 기반 개발인가?</h2>
<blockquote>
<p>소프트웨어 개발에서 가장 중요한 것 중 하나는 &quot;얼마나 빠르고 안정적으로 새로운 기능을 사용자에게 전달할 수 있는가&quot; 이다. 트렁크 기반 개발은 이러한 목표를 달성하기 위한 현대적인 개발 방식이다.</p>
</blockquote>
<h2 id="트렁크-빤스인가">트렁크? 빤스인가?</h2>
<blockquote>
<p>트렁크 기반 개발은 개발자들이 작은 단위의 변경사항을 자주 메인 브랜치(트렁크)에 병합하는 버전 관리 방식이다. 이는 마치 나무의 줄기(trunk)처럼 하나의 중심 줄기에 모든 변경사항이 모이는 형태를 띈다.</p>
</blockquote>
<h3 id="실제-시나리오로-이해하기">실제 시나리오로 이해하기</h3>
<p>팀 프로젝트 상황을 가정해보겠다:</p>
<pre><code>상황: 온라인 쇼핑몰 개발 프로젝트
팀원: 프론트엔드 개발자 A, 백엔드 개발자 B, C

1일차 아침:
- A: 장바구니 UI 개선 작업 시작
- B: 결제 API 수정 작업 시작
- C: 상품 검색 기능 개선 작업 시작

1일차 오후:
- A: 장바구니 아이콘 변경사항 커밋 및 병합 (15줄 수정)
- B: 결제 API 유효성 검사 로직 추가 커밋 및 병합 (20줄 수정)
- C: 검색 알고리즘 최적화 부분 커밋 및 병합 (30줄 수정)

2일차:
- 각자 남은 작업을 작은 단위로 나누어 지속적으로 커밋 및 병합</code></pre><h2 id="기존-git-flow와의-차이점">기존 Git Flow와의 차이점</h2>
<h3 id="git-flow-방식">Git Flow 방식</h3>
<pre><code>Feature Branch 방식:
1. feature/cart-improvement 브랜치 생성
2. 2주간 작업
3. 100개 이상의 파일 변경
4. PR 생성
5. 코드 리뷰에 3일 소요
6. 충돌 해결에 2일 소요</code></pre><h3 id="트렁크-기반-개발-방식">트렁크 기반 개발 방식</h3>
<pre><code>1. 트렁크에서 직접 작업 또는 초단기 브랜치 생성
2. 하루 작업
3. 5-10개 파일 변경
4. PR 생성
5. 코드 리뷰 30분 소요
6. 충돌 최소화</code></pre><h2 id="트렁크-기반-개발의-장점">트렁크 기반 개발의 장점</h2>
<blockquote>
<ol>
<li><strong>지속적 통합의 실현</strong></li>
</ol>
</blockquote>
<ul>
<li>작은 변경사항의 빈번한 병합으로 통합 문제 최소화</li>
<li>실시간으로 문제 발견 및 해결 가능</li>
</ul>
<blockquote>
<ol start="2">
<li><strong>효율적인 코드 리뷰</strong></li>
</ol>
</blockquote>
<ul>
<li>작은 단위의 변경사항으로 리뷰어의 부담 감소</li>
<li>더 깊이 있는 코드 리뷰 가능</li>
</ul>
<blockquote>
<ol start="3">
<li><strong>빠른 배포 주기</strong></li>
</ol>
</blockquote>
<ul>
<li>언제든 배포 가능한 상태 유지</li>
<li>새로운 기능의 빠른 출시 가능</li>
</ul>
<h2 id="실전-적용을-위한-best-practice">실전 적용을 위한 Best Practice</h2>
<h3 id="1-작은-단위로-개발하기">1. 작은 단위로 개발하기</h3>
<pre><code>나쁜 예:
- 한 번에 전체 회원가입 기능 구현 (500줄 변경)

좋은 예:
- 회원가입 입력 폼 UI 구현 (50줄)
- 이메일 유효성 검사 추가 (30줄)
- 비밀번호 정책 구현 (40줄)
- API 연동 구현 (60줄)</code></pre><h3 id="2-피처-플래그-활용하기">2. 피처 플래그 활용하기</h3>
<blockquote>
<p>피처 플래그(Feature Flag): 코드 안에 &quot;스위치&quot;를 심어두는 개발 기법. 이 스위치를 통해 프로덕션 환경에서도 새로운 기능을 안전하게 켜고 끌 수 있다.</p>
</blockquote>
<pre><code class="language-javascript">// 피처 플래그 예시
if (featureFlags.isEnabled(&#39;new-payment-system&#39;)) {
    // 새로운 결제 시스템 코드(특정 사용자에게만 새 기능을 보여줄 수 있음)
    processNewPayment();
} else {
    // 기존 결제 시스템 코드
    processOldPayment();
}</code></pre>
<h3 id="3-자동화된-테스트-구축">3. 자동화된 테스트 구축</h3>
<pre><code>커밋 시 자동 실행되는 테스트:
1. 단위 테스트
2. 통합 테스트
3. 코드 커버리지 검사
4. 린트 검사</code></pre><h2 id="트렁크-기반-개발-도입-시-주의사항">트렁크 기반 개발 도입 시 주의사항</h2>
<blockquote>
<ol>
<li><strong>팀 문화의 변화</strong></li>
</ol>
</blockquote>
<ul>
<li>작은 단위 커밋에 대한 팀원 합의 필요</li>
<li>빠른 코드 리뷰 문화 정착 필요</li>
</ul>
<blockquote>
<ol start="2">
<li><strong>테스트 자동화 필수</strong></li>
</ol>
</blockquote>
<ul>
<li>지속적 통합을 위한 테스트 인프라 구축</li>
<li>테스트 작성을 일상화</li>
</ul>
<blockquote>
<ol start="3">
<li><strong>점진적 도입</strong></li>
</ol>
</blockquote>
<ul>
<li>소규모 프로젝트부터 시작</li>
<li>팀원들의 적응 기간 필요</li>
</ul>
<h2 id="마치며">마치며</h2>
<p>트렁크 기반 개발은 현대 소프트웨어 개발에서 CI/CD를 실현하는 핵심 방법론이다. 필자가 참고한 본문에 의하면 작은 변경사항의 빈번한 통합이라는 단순한 원칙이 가져오는 효과는 매우 크다고 한다. 처음에는 도전적으로 느껴질 수 있지만, 팀의 생산성과 코드 품질을 크게 향상시킬 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SEO 적용하기 (feat: nextjs, vercel, google search console)]]></title>
            <link>https://velog.io/@live_in_truth/SEO-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0-feat-nextjs-vercel</link>
            <guid>https://velog.io/@live_in_truth/SEO-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0-feat-nextjs-vercel</guid>
            <pubDate>Sun, 09 Feb 2025 14:45:51 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>글을 읽기 전에 SEO가 뭔지 빠르게 알고 가기 =&gt; <a href="https://velog.io/@live_in_truth/SEO%EB%9E%80">SEO가 뭐징?</a></p>
</blockquote>
<h2 id="필요성">필요성</h2>
<blockquote>
<p>고생해서 웹 서비스 하나 만들었다. ⇒ 사용자가 있어야 의미가 있다. ⇒ 사용자에게 노출시켜야한다. ⇒ 지인들에게 일일이 url을 나눠준다?ㄴㄴ ⇒ 구글에 검색하게 한다. =&gt; 서비스 이름, 관련 검색어를 구글에 검색했을때 우리 서비스가 상위에 노출되어야한다.</p>
</blockquote>
<blockquote>
<ul>
<li>구글 검색창에 내가 만든 서비스 명을 검색했을때 나오게 하려면 구글의 검색 인덱스에 등록되어야 한다. </li>
</ul>
</blockquote>
<ul>
<li>이를 위해 구글 서치 콘솔에 사이트를 등록하고 인덱싱을 요청해야한다.</li>
<li>그냥 자연 크롤링도 가능하지만 상대적으로 시간이 오래걸린다.  </li>
<li>그렇다고 구글 서치 콘솔 등록만으로 상위 노출이 보장되지는 않는다.</li>
<li>SEO 최적화, 양질의 컨텐츠, 사용자 경험 등이 모두 중요하다.</li>
<li>구글 서치 콘솔 등록은 이 과정의 첫 단계이다.</li>
</ul>
<p>정리하자면 </p>
<blockquote>
<p>구글검색창에 검색 시 나의 프로젝트가 빨리빨리 상위에 뜨기 위해서는 
<strong>구글 서치 콘솔등록 + 메타데이터 최적화(SEO)</strong>를 해야한다. </p>
</blockquote>
<h2 id="메타데이터-최적화seo-먼저-해보자">메타데이터 최적화(SEO) 먼저 해보자</h2>
<p><a href="https://nextjs.org/docs/app/api-reference/file-conventions/metadata">nextjs 공식문서 참조</a></p>
<h3 id="공식문서에-나오는-5가지-메타데이터-요소들의-필요성-요약">공식문서에 나오는 5가지 메타데이터 요소들의 필요성 요약</h3>
<blockquote>
<p><em><strong>favicon.ico (파비콘)</strong></em>
<img src="https://velog.velcdn.com/images/live_in_truth/post/9a54ee2c-405b-4079-bbc1-3fed0f465b9f/image.png" alt=""></p>
</blockquote>
<ul>
<li>웹브라우저 탭에 보이는 작은 아이콘</li>
<li>사용자가 여러 탭을 열었을 때 어떤 사이트인지 빠르게 구분 가능</li>
<li>네이버 -&gt; 녹색 N, 깃헙 -&gt; 고양이 모양</li>
</ul>
<blockquote>
<p><em><strong>icon (일반 아이콘)</strong></em>
<img src="https://velog.velcdn.com/images/live_in_truth/post/51d2bcdd-8146-4adc-996b-2160ec5baa95/image.png" alt=""></p>
</blockquote>
<ul>
<li>모바일 기기나 데스크톱에서 웹사이트 바로가기 아이콘</li>
<li>앱 아이콘처럼 보이는 큰 아이콘</li>
<li>사용자 기기의 홈 화면이나 바탕화면에 웹사이트 바로가기를 만들 때 사용</li>
</ul>
<blockquote>
<p><em><strong>manifest.json</strong></em></p>
</blockquote>
<ul>
<li>웹앱의 설치 및 표시 방식을 정의하는 설정 파일</li>
<li>PWA(Progressive Web App) 구현에 필요한 정보를 포함</li>
<li>사용자가 웹사이트를 마치 모바일 앱처럼 사용할 수 있게 해줌</li>
</ul>
<blockquote>
<p><em><strong>opengraph-image (오픈그래프 이미지)</strong></em>
    <img src="https://velog.velcdn.com/images/live_in_truth/post/b268c145-d953-4cd0-a596-759814f6dad8/image.png" alt=""> </p>
</blockquote>
<ul>
<li>링크 공유 시 보이는 대표 이미지</li>
<li>링크의 미리보기 이미지를 예쁘게 만들어줌</li>
<li>사용자의 클릭율에 영향</li>
</ul>
<blockquote>
<p><strong><em>robots.txt</em></strong></p>
</blockquote>
<ul>
<li>검색엔진 크롤러에게 웹사이트 탐색 규칙을 알려주는 파일</li>
<li>어떤 페이지를 검색 결과에 보여줄지, 숨길지 지정</li>
<li>웹사이트의 중요한 페이지는 노출하고, 민감한 페이지는 숨기는 역할</li>
<li>SEO(검색 엔진 최적화)에 매우 중요한 파일</li>
<li>예: 관리자 페이지는 숨기고, 검색 결과 페이지는 검색 노출</li>
</ul>
<p>예시 코드(필자의 프로젝트에 맞는 코드이기 때문에 참고용으로만 봐주세요..)</p>
<pre><code class="language-tsx">import { MetadataRoute } from &#39;next&#39;

export default function robots(): MetadataRoute.Robots {
  const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || &#39;https://npmhub.vercel.app&#39;

  return {
    // 크롤러 규칙
    rules: [
      {
        // 구글 크롤러에 대한 특별 규칙
        userAgent: &#39;Googlebot&#39;,
        allow: [
          &#39;/&#39;,             
          &#39;/search/*&#39;,        
          &#39;/detail/*&#39;,      
        ],
        disallow: [
          &#39;/api/*&#39;,         // API 엔드포인트 제외
          &#39;/_next/*&#39;,       // Next.js 내부 파일 제외
          &#39;/static/*&#39;,      // 정적 파일 제외
        ],
      },
      {
        // 다른 모든 크롤러에 대한 규칙
        userAgent: &#39;*&#39;,
        allow: [
          &#39;/&#39;,
          &#39;/search/*&#39;,
          &#39;/detail/*&#39;,     
        ],
        disallow: [
          &#39;/api/*&#39;,
          &#39;/_next/*&#39;,
          &#39;/static/*&#39;,
        ],
      }
    ],
    // 사이트맵 위치
    sitemap: `${baseUrl}/sitemap.xml`,
    // 표준 호스트 선언
    host: baseUrl,
  }
}</code></pre>
<blockquote>
<p><em><strong>sitemap.xml</strong></em> (필자는 ts 확장자로 함. Next.js 13 이상에서는 sitemap.ts 파일로 만들어도 자동으로 XML 형식으로 변환해줌.)</p>
</blockquote>
<ul>
<li>웹사이트의 페이지 구조를 검색엔진에 알려주는 지도 역할</li>
<li>각 페이지의 중요도(priority)와 업데이트 주기(changeFrequency) 정보 제공</li>
<li>검색엔진이 누락 없이 사이트의 모든 중요 페이지를 발견할 수 있도록 안내</li>
<li>효율적인 색인 생성으로 검색 노출 가능성 증가</li>
</ul>
<pre><code class="language-ts">import type { MetadataRoute } from &#39;next&#39;

export default async function sitemap(): Promise&lt;MetadataRoute.Sitemap&gt; {
  const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || &#39;https://npmhub.vercel.app&#39;

  const staticPages: MetadataRoute.Sitemap = [
    {
      url: `${baseUrl}`,
      lastModified: new Date(),
      changeFrequency: &#39;daily&#39;,
      priority: 1.0
    },
  ]

  return staticPages
}</code></pre>
<blockquote>
<p>여기까지 SEO 최적화가 되었다면!</p>
</blockquote>
<h2 id="google-search-console에-등록하기">Google Search Console에 등록하기</h2>
<blockquote>
<p><a href="https://search.google.com/search-console">Google Search Console</a> &lt;= 여기에 들어가서 </p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/live_in_truth/post/0e439dbd-2b24-4c16-a414-cd62b139ca56/image.png" alt=""></p>
<blockquote>
<p>선택을 하는데 지금은 DNS 관련 비용없이 해야하기 때문에 필자는 오른쪽의 url 접두어를 선택하여 vercel로 배포한 url을 넣었다.  </p>
</blockquote>
<blockquote>
<p>그럼 verfication 코드를 보여주는데 이걸 메타데이터 파일에 추가한다. </p>
</blockquote>
<pre><code class="language-tsx">// app/layout.tsx
... 생략
export const metadata: Metadata = {
  ... 생략
  verification: {
    google: &#39;KKAVIyXJmhqKL0jj2c6OT8mUawJAktjzV88OUMnCm_s&#39;, 
  }, // 여기여기
  category: &#39;Technology&#39;,
 };
... 생략
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    &lt;html lang=&quot;en&quot;&gt;
      &lt;body&gt;
        &lt;ClientRoot&gt;
          &lt;ClientLayout&gt;{children}&lt;/ClientLayout&gt;
        &lt;/ClientRoot&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  );
}
</code></pre>
<blockquote>
<p><em><strong>verfication 코드 넣어야하는 이유</strong></em></p>
</blockquote>
<ul>
<li>사이트 전체 소유권 확인</li>
<li>하위 페이지 메타데이터에 중복 추가할 필요 없음</li>
<li>Next.js에서는 루트 레이아웃의 메타데이터가 전체 사이트에 적용됨</li>
</ul>
<blockquote>
<p>이후 콘솔에 만든 사이트맵을 제출한다.
<img src="https://velog.velcdn.com/images/live_in_truth/post/719ddb92-a5d9-4dc1-9d00-9de53a7e78d4/image.png" alt="">
제출하는 이유는 </p>
</blockquote>
<ul>
<li>구글 검색 엔진이 웹사이트의 모든 중요 페이지를 더 빠르고 정확하게 발견</li>
<li>수동으로 모든 페이지를 크롤링하는 시간 단축</li>
</ul>
<blockquote>
<p>필자는 sitemap.ts로 만들었지만 여기에서의 등록은 sitemap.xml로 해야한다. 그러면 nextjs가 알아서 ts확장자를 xml로 변환해준다. </p>
</blockquote>
<p>이후 구글 서치 콘솔에 인덱싱이 될 때까지 기다린다. 며칠 ~ 몇 주 걸린다고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[양자 컴퓨터 쉽고 빠르게 이해하기]]></title>
            <link>https://velog.io/@live_in_truth/%EC%96%91%EC%9E%90-%EC%BB%B4%ED%93%A8%ED%84%B0%EA%B0%80-%EB%AD%94%EB%8D%B0-%EC%9B%B9-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%98%90-%EC%9D%B4%EC%A0%9C-%EB%A7%9D%ED%95%A8</link>
            <guid>https://velog.io/@live_in_truth/%EC%96%91%EC%9E%90-%EC%BB%B4%ED%93%A8%ED%84%B0%EA%B0%80-%EB%AD%94%EB%8D%B0-%EC%9B%B9-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%98%90-%EC%9D%B4%EC%A0%9C-%EB%A7%9D%ED%95%A8</guid>
            <pubDate>Mon, 03 Feb 2025 09:15:20 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>양자역학적인 현상을 쓴다? 0과 1이 동시에 존재한다..?
전자가 저기있을 수도 있고 여기 있을 수도 있다..? 
그러나 관측하는순간 여기에 나타난다..? </p>
</blockquote>
<p><em>이게 뭐고 뭐가 대단하길래 요즘 난리일까?
빠르게 알아보자.</em></p>
<h2 id="양자-컴퓨터의-기본-개념">양자 컴퓨터의 기본 개념</h2>
<blockquote>
<p>양자 컴퓨터는 양자역학적 현상을 활용하여 연산을 수행하는 새로운 패러다임의 컴퓨터이다. 일반 컴퓨터가 비트(0 또는 1)를 사용한다면, 양자 컴퓨터는 큐비트(quantum bit)를 사용하여 정보를 처리한다.</p>
</blockquote>
<h3 id="중첩-상태의-이해">중첩 상태의 이해</h3>
<blockquote>
<p>양자역학에서는 전자가 동시에 여러 위치에 존재할 수 있는 특이한 현상이 있다. 이를 중첩 상태라고 한다. </p>
</blockquote>
<p><em>&#39;무슨 소리인가 1이면 1이고 0이면 0이지..&#39; 싶을 때</em>   </p>
<blockquote>
<p>종이 앞면에 새와 뒷면에 새장이 그려진 종이를 빠르게 회전시켰을 때 새와 새장이 동시에 존재하는 것처럼 보이는 상태와 비슷하다.
<img src="https://velog.velcdn.com/images/live_in_truth/post/19ef7610-1063-43fc-a954-13d823fcfd2f/image.png" alt="">
이걸 파바박 돌리면 밑에 그림처럼 보이는 상태
<img src="https://velog.velcdn.com/images/live_in_truth/post/b9ba7dff-3f6b-48a5-8a94-37cec636a7a5/image.png" alt=""></p>
</blockquote>
<h3 id="관측의-역설">관측의 역설</h3>
<blockquote>
<p>중첩 상태의 특징은 관측하는 순간 하나의 상태로 &quot;붕괴&quot;한다는 것이다. 양자역학에서 관측이란 단순히 눈으로 보는 것이 아니라 물리적으로 부딪히는 것에 가까운 개념이다. 이는 회전하는 동전을 잡는 순간 반드시 한 면만 보이는 것과 같은 원리이다.</p>
</blockquote>
<h2 id="양자-컴퓨터의-연산-능력">양자 컴퓨터의 연산 능력</h2>
<blockquote>
<p>양자 컴퓨터의 강력한 점은 동시 연산 능력이다. 
예를 들어 10개의 비트로는 2¹⁰ = 1024가지 경우의 수가 가능한데, 일반 컴퓨터는 이를 하나씩 계산해야 한다. <strong>반면 양자 컴퓨터는 10개의 큐비트로 1024가지 상태를 동시에 다룰 수 있다. 0과 1의 상태를 동시에 갖기 때문이다.</strong></p>
</blockquote>
<blockquote>
<p>0과 1의 상태를 동시에 갖는데 왜 10개의 큐비트로 1024가지 상태를 동시에 다룰 수 있는 것인가 이해가 되지않는다면 =&gt;<strong>큐비트는 단순히 0 또는 1을 담는 그릇이 아니라, &#39;가능성&#39;을 담는 그릇</strong>이라고 생각하면 쉬울 것 같다.
  <strong>큐비트 N개를 모으면 2^N개의 모든 가능성을 동시에 담고</strong> 연산을 수행할 수 있는, 지수적으로 강력한 &#39;가능성의 덩어리&#39; 라고 생각해보자.</p>
</blockquote>
<h3 id="현실적-제약">현실적 제약</h3>
<blockquote>
<p>당연히 현재 인프라로는 제약이 있다. 
중첩 상태는 극도로 민감해서 먼지 하나라도 묻으면 안 되며, 관측하는(부딪히는) 순간 상태가 깨진다. 따라서 계산만 하고 그 안에서 최적의 결론을 찾아야 하며, 이 상태를 유지하기 위한 인프라 비용이 매우 크다. 온도도 낮아야하고 진공이어야 하고 등등.. <strong>양자역학을 전공하시는 분들의 팟캐스트나 강연을 참고한 결과 현재의 인프라로 상용화되기에는 수지타산이 안맞는다고 한다.</strong></p>
</blockquote>
<h2 id="현재-웹-보안에-대한-위협">현재 웹 보안에 대한 위협</h2>
<p><em><strong>요즘 양자컴퓨터 양자컴퓨터 말이 많은 이유가 바로 &#39;이제 암호화 어떡하징?&#39;에 대한 걱정 때문이다.</strong></em> </p>
<blockquote>
<p>현재 웹 보안의 근간인 RSA 암호화를 예로 들어보자. 서버는 두 개의 소수를 선택한다. 53(비밀키)과 59(공개키)라고 가정하자. 이 두 수를 곱하면 3127이 된다. 서버는 59라는 공개키만 클라이언트에게 제공하고 53이라는 비밀키는 안전하게 보관한다.</p>
</blockquote>
<blockquote>
<p>이제 클라이언트가 중요한 정보를 서버로 전송하고 싶다면:</p>
</blockquote>
<ol>
<li>공개키(59)와 n값(3127)을 사용해 데이터를 암호화한다</li>
<li>암호화된 데이터를 서버로 전송한다</li>
<li>서버는 자신만 알고 있는 비밀키(53)를 사용해 이 데이터를 복호화한다</li>
</ol>
<blockquote>
<p>실제로는 훨씬 더 큰 소수를 사용하기 때문에, 일반 컴퓨터로는 공개키만으로 비밀키를 찾아내는 것이 거의 불가능하다. n값을 소인수분해하여 비밀키를 찾으려면 수백 년이 걸리기 때문이다.</p>
</blockquote>
<p><em>*<em>하지만 양자 컴퓨터는 이야기가 다르다. 양자 컴퓨터는 모든 가능한 소인수를 동시에 계산할 수 있다. *</em></em></p>
<blockquote>
<p>예를 들어 3127이라는 숫자의 소인수를 찾기 위해:</p>
</blockquote>
<pre><code>일반 컴퓨터: 2로 나눠보고, 3으로 나눠보고... 하나씩 시도
양자 컴퓨터: 모든 수로 동시에 나눗셈 시도 가능</code></pre><p><strong><em>즉, 양자 컴퓨터는 서버의 비밀키를 매우 빠른 시간 내에 찾아낼 수 있다는 것이다. 이는 현재 웹 보안의 기반을 흔들 수 있는 심각한 위협이 된다.</em></strong></p>
<pre><code>일반 컴퓨터: 가능한 모든 열쇠 조합을 하나씩 시도 → 수백 년 소요
양자 컴퓨터: 모든 조합을 동시에 시도 → 매우 빠른 시간 내 해결 가능</code></pre><blockquote>
<p>이것이 바로 새로운 암호화 방식, 특히 양자 내성 암호화(Post-Quantum Cryptography)가 필요한 이유이다. 양자 컴퓨터로도 풀 수 없는 새로운 수학적 문제를 기반으로 한 암호화 방식을 개발해야 한다. 
무언가가 상용화 되기 위해서는 그에 대응할 수 있는 울타리가 만들어져야하는데 아마 비용과 이 문제가 양자컴퓨터의 상용화의 발목을 잡고 있지 않을까 싶다. _(개인적인 생각입니다.) _</p>
</blockquote>
<h2 id="웹-개발에-미치는-영향">웹 개발에 미치는 영향</h2>
<p>필자는 웹 개발자를 꿈꾸는 새싹이기 때문에 이 글이 결론적으로 이러한 파도속에서 어떤 웹 개발자로 준비해야하는가로 끝나야 그림이 예쁠 것 같아 정리해본다.</p>
<blockquote>
<p>웹 개발에서 렌더링은 CPU, GPU, RAM이 협력하여 웹 페이지를 화면에 그리는 과정이다. </p>
</blockquote>
<h3 id="하드웨어별-역할">하드웨어별 역할</h3>
<blockquote>
<ul>
<li>CPU: JavaScript 실행, DOM 조작</li>
</ul>
</blockquote>
<ul>
<li>GPU: 그래픽 처리, 애니메이션</li>
<li>RAM: 임시 데이터 저장</li>
</ul>
<p><strong>_계산이 빠르게 되면 렌더링이 엄청 빨라지려나? 싶었지만 현재로서는 양자 컴퓨터가 웹 렌더링에 직접적인 영향을 미치지는 않는다고한다. _</strong></p>
<p><strong><em>왜?</em></strong> </p>
<p>렌더링과 양자컴퓨팅의 관계를 보면 알 수 있다.</p>
<blockquote>
<ul>
<li>렌더링의 특성:</li>
</ul>
</blockquote>
<pre><code>- 순차적 처리가 필요한 작업이 많음
- 실시간 처리가 필요함
- 결과를 즉시 관찰해야 함</code></pre><ul>
<li>양자컴퓨터의 특성:
```</li>
<li>특정 종류의 병렬 계산에 강점</li>
<li>중간 관찰이 불가능</li>
<li>결과 관찰 시 상태가 무너짐</li>
<li>매우 불안정한 환경<pre><code>
</code></pre></li>
</ul>
<blockquote>
<p>웹 렌더링 과정:</p>
</blockquote>
<pre><code>1. HTML 파싱 → 2. CSS 계산 → 3. 레이아웃 계산 → 4. 페인팅
(각 단계가 이전 단계의 결과에 의존적)</code></pre><blockquote>
<p>양자컴퓨팅이 잘 하는 것:</p>
</blockquote>
<pre><code>독립적인 많은 계산을 동시에 처리
예) 1024개의 숫자를 동시에 더하기</code></pre><p><em><strong>여기서 집중!!</strong></em></p>
<blockquote>
<p>왜 렌더링에 적합하지 않은가: </p>
</blockquote>
<blockquote>
<ol>
<li>순차성</li>
</ol>
</blockquote>
<ul>
<li>렌더링은 이전 단계의 결과를 보고 다음 작업을 결정해야 함</li>
<li>양자컴퓨터는 중간 결과 확인이 불가능</li>
</ul>
<blockquote>
<ol start="2">
<li>실시간성</li>
</ol>
</blockquote>
<ul>
<li>웹은 실시간 상호작용이 필요</li>
<li>양자컴퓨터는 결과 관찰에 제약이 있음</li>
</ul>
<blockquote>
<ol start="3">
<li>안정성</li>
</ol>
</blockquote>
<ul>
<li>렌더링은 지속적이고 안정적인 처리 필요</li>
<li>양자컴퓨터는 극도로 통제된 환경 필요</li>
</ul>
<p><em><strong>따라서 현재의 CPU, GPU가 렌더링에 더 적합한 구조를 가지고 있다. 
양자컴퓨터는 암호화 해독이나 대규모 데이터 분석 같은 특수한 계산에 더 적합하다.</strong></em></p>
<h2 id="그렇다면-웹-개발자가-준비해야-할-역량">그렇다면 웹 개발자가 준비해야 할 역량</h2>
<blockquote>
<p>보안 관련 역량</p>
</blockquote>
<ul>
<li>양자 내성 암호화에 대한 이해</li>
<li>새로운 보안 프로토콜 학습</li>
<li>암호화 관련 최신 동향 파악(현실적으로는 이 방법이 양자시대 속 작은 무기를 갖추는데 도움이 될 것 같다.)</li>
</ul>
<p><em>양자 컴퓨터 시대가 도래하더라도 계산하는 하드웨어가 바뀌는것이기때문에 웹 개발의 기본 원칙은 변하지 않을 것이라고 한다. 다만 보안과 암호화 분야에서 큰 변화가 예상되므로, 이에 대한 준비가 필요할 것 같다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[클로저에 대해서 설명해주세요 -자바스크립트-]]></title>
            <link>https://velog.io/@live_in_truth/%ED%81%B4%EB%A1%9C%EC%A0%80%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-</link>
            <guid>https://velog.io/@live_in_truth/%ED%81%B4%EB%A1%9C%EC%A0%80%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-</guid>
            <pubDate>Mon, 23 Dec 2024 13:06:27 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/live_in_truth/post/b6e83a8c-c5e9-4ced-af4f-d692a01a2827/image.png" alt="">
<em>모던 자바스크립트 Deep Dive 서적을 참고했습니다.</em></p>
<blockquote>
<p>사실 클로저는 자바스크립트 고유의 개념이 아니다. 
클로저의 정의가 ECMAScript사양에 등장하지 않는다.</p>
</blockquote>
<blockquote>
<p>MDN(신뢰할 수 있는 개발자 문서. 공식문서는 아님) 曰: “<strong>클로저</strong>는 함수와 그 함수가 선언된 <strong>렉시컬</strong> 환경과의 조합이다.”</p>
</blockquote>
<blockquote>
<p>하... 렉시컬은 또 무엇일까? 이왕 하는 김에 쉽고 빠르게 보고 오자. ⇒ <a href="https://velog.io/@live_in_truth/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%A0%89%EC%8B%9C%EC%BB%AC-%EC%8A%A4%EC%BD%94%ED%94%84lexical-scope-%EB%B9%A0%EB%A5%B4%EA%B2%8C-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0%5Dhttps://velog.io/@live_in_truth/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%A0%89%EC%8B%9C%EC%BB%AC-%EC%8A%A4%EC%BD%94%ED%94%84lexical-scope-%EB%B9%A0%EB%A5%B4%EA%B2%8C-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0">렉시컬 빠르게 집어넣기 클릭</a></p>
</blockquote>
<h2 id="클로저-이해를-돕기-위한-개념부터-슥">클로저 이해를 돕기 위한 개념부터 슥</h2>
<p><em>렉시컬 스코프 개념을 이해했다면 술술 읽힐겁니다.</em></p>
<blockquote>
<p>함수는 &#39;태어난 곳&#39;과 &#39;일하는 곳&#39;이 다를 수 있다. 그래서 함수는 &#39;일하는 곳&#39;과 관계없이 자신이 &#39;태어난 곳&#39;의 환경을 기억해야 하는데, 이때 <strong>&#39;태어난 곳&#39;(정의 된 위치, 환경)이 바로 상위 스코프</strong>이다. =&gt; 기억해야 한다.</p>
</blockquote>
<blockquote>
<p>다시! 상위 스코프란?: 함수의 <strong>정의</strong>가 위치하는 스코프</p>
</blockquote>
<blockquote>
<p>이를 위해 함수는 자신의 내부슬롯[[Environment]]에 자신이 정의된 환경, 즉 상위 스코프의 참조를 저장한다.</p>
<blockquote>
<p>함수의 [[Environment]]가 어떻게 상위 스코프를 결정하는지 보면:</p>
</blockquote>
</blockquote>
<ul>
<li><strong>상위 스코프 결정 시점</strong><ul>
<li>함수 정의가 평가될 때(코드가 실행되기 전) 상위 스코프가 결정된다.<ul>
<li>이것이 바로 <strong>&#39;렉시컬 스코프&#39;</strong>.</li>
<li><strong>[[Environment]]의 역할</strong></li>
<li>함수가 자신이 태어난(정의된) 환경을 기억하게 해준다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="예제-코드로-이해하기">예제 코드로 이해하기</h3>
<p><em>자바스크립트 deep dive 24-04</em></p>
<pre><code class="language-javascript">const x = 1;

function foo() {
    const x = 10;
    bar();
}

function bar() {
    console.log(x);
}
</code></pre>
<blockquote>
<ul>
<li><code>bar</code> 함수는 전역에서 정의되었으므로 전역 스코프를 기억한다.</li>
</ul>
</blockquote>
<ul>
<li>그래서 <code>bar</code> 함수가 어디서 호출되든 상관없이 전역의 <code>x</code>값인 1을 참조한다.</li>
<li><code>foo</code> 안에서 호출되어도 마찬가지이다.</li>
</ul>
<blockquote>
<p>즉, 함수의 상위 스코프는 <strong>함수를 어디서 호출하는지가 아니라</strong>, <em><strong>함수를 어디서 정의했는지에 따라 결정된다.</strong></em> 이것이 바로 렉시컬 스코프의 핵심이다.</p>
</blockquote>
<hr>
<h2 id="본격적으로-클로저하게-클로저-보기">본격적으로 클로저하게 클로저 보기</h2>
<blockquote>
<p><strong>이 코드하나 머리에 박아놓고 클로저하면 떠올리기</strong></p>
</blockquote>
<pre><code class="language-jsx">    function foo() {
        const x = 1;
        const y = 2;

        function bar() {
            console.log(x); // bar는 foo의 x에 접근 가능
        }
        return bar;
    }

    const bar = foo();  // foo를 실행하고 bar 함수를 반환받음
    bar();  // bar 실행
</code></pre>
<blockquote>
<p><strong>생명 주기 관점에서 보기</strong></p>
</blockquote>
<pre><code class="language-jsx">    function outer() {
        const name = &quot;철수&quot;;  // 원래는 outer 함수 종료시 사라져야 할 변수

        function inner() {
            console.log(name);  // 하지만 inner가 name을 기억함
        }
        return inner;  // inner 함수 반환
    }

    const savedFunc = outer();  // outer는 실행 종료됨
    savedFunc();  // 여전히 &quot;철수&quot; 출력 가능!
</code></pre>
<blockquote>
<ul>
<li>보통의 경우: outer 함수가 끝나면 그 안의 변수들(name)은 사라져야 함</li>
</ul>
</blockquote>
<ul>
<li>클로저의 경우: inner 함수가 name을 참조하고 있어서 사라지지 않고 유지됨</li>
</ul>
<blockquote>
<p>여기에서 의문이 들 수도 있다! (의문 없다면 pass)</p>
</blockquote>
<blockquote>
<blockquote>
<p>“엥? <code>outer()</code> 함수는 일급객체로써 변수 <code>savedFunc</code>에 넣었기때문에 <code>savedFunc();</code> 를 실행하면  <code>outer();</code> 가 실행되니까 애초에 이 결과가 당연한거 아니야?” 라고 생각이 들었다면</p>
</blockquote>
</blockquote>
<blockquote>
<p>그렇게 오해할 수 있지만 실제로는 다르게 작동한다.</p>
</blockquote>
<pre><code class="language-jsx">        function outer() {
            const name = &quot;박지성&quot;;

            function inner() {
                console.log(name);
            }
            return inner;  // inner 함수를 &#39;반환&#39;
        }

        // 여기서 잘 보면
        const savedFunc = outer();  // (1) outer 함수가 실행되고 inner 함수를 반환
        savedFunc();  // (2) 저장된 inner 함수를 실행
</code></pre>
<blockquote>
<p><code>const savedFunc = outer()</code>에서 일어나는 일:</p>
</blockquote>
<ol>
<li>outer 함수가 실행됨</li>
<li>inner 함수가 생성됨</li>
<li><strong>inner 함수가 반환</strong>되어 savedFunc에 저장됨</li>
<li><strong>outer 함수의 실행은 여기서 완전히 종료됨</strong></li>
</ol>
<blockquote>
<p><code>savedFunc()</code>에서 일어나는 일:</p>
</blockquote>
<ul>
<li>저장된 inner 함수가 실행됨</li>
<li><strong>outer 함수가 다시 실행되는 것이 아님!</strong></li>
<li>이전에 저장된 inner 함수가 실행되는 것</li>
</ul>
<blockquote>
<p>다시 보자면</p>
</blockquote>
<pre><code class="language-jsx">    // 이렇게 생각이 들 수 있는데
    const savedFunc = outer;  // outer 함수 자체를 저장
    savedFunc();  // outer 함수를 실행

    // 실제로는 이렇게 동작함
    const savedFunc = outer();  // outer()의 반환값(inner 함수)을 저장
    savedFunc();  // 저장된 inner 함수를 실행
</code></pre>
<blockquote>
<p>비유하자면</p>
</blockquote>
<ul>
<li><code>outer()</code>는 &quot;조리법&quot;을 주는 게 아니라</li>
<li>&quot;이미 완성된 요리(inner 함수)&quot;를 주는 것이다.</li>
<li>그래서 나중에 savedFunc를 실행할 때는 처음부터 다시 요리하는 게 아니라</li>
<li>이미 만들어진 요리(inner)를 사용한다.</li>
</ul>
<blockquote>
<p><strong>&quot;일찍 소멸된다&quot;는 의미</strong></p>
</blockquote>
<pre><code class="language-jsx">    function foo() {
        const x = 1;
        const y = 2;

        // 케이스 1: 클로저가 모든 변수 유지
        function bar() {
            console.log(x, y);  // x와 y 모두 필요
        }

        // 케이스 2: 최적화된 클로저
        function optimizedBar() {
            console.log(x);  // x만 필요
            // y는 사용하지 않아서 메모리에서 일찍 제거됨
        }
    }
</code></pre>
<blockquote>
<p>이게이게 자바스크립트 엔진의 최적화를 도와준다.</p>
</blockquote>
<ul>
<li>optimizedBar는 x만 사용하므로 y는 메모리에서 제거</li>
<li><ul>
<li>불필요한 메모리 점유를 줄임</li>
</ul>
</li>
</ul>
<h3 id="클로저-때문에-가능한-것들많이-쓰이는-방법"><strong>클로저 때문에 가능한 것들(많이 쓰이는 방법)</strong></h3>
<pre><code class="language-jsx">function counter() {
    let count = 0;  // 외부에서 직접 접근 불가능한 변수

    return {
        increase() { count++; },
        decrease() { count--; },
        getCount() { return count; }
    };
}

const myCounter = counter();
myCounter.increase();  // count는 private하게 보호됨
console.log(myCounter.getCount());  // 1
</code></pre>
<h3 id="메모리-관점에서의-이해"><strong>메모리 관점에서의 이해</strong></h3>
<pre><code class="language-jsx">function bigFunction() {
    const bigData = new Array(10000);  // 큰 데이터
    const smallData = &quot;hello&quot;;         // 작은 데이터

    return function() {
        console.log(smallData);  // smallData만 사용
        // bigData는 사용하지 않으므로 메모리에서 제거됨
    };
}
</code></pre>
<blockquote>
<ul>
<li>최적화 전: bigData와 smallData 모두 메모리 유지</li>
</ul>
</blockquote>
<ul>
<li>최적화 후: smallData만 메모리에 유지, bigData는 일찍 소멸</li>
</ul>
<blockquote>
<ul>
<li>이렇게 클로저는 함수가 자신이 생성된 환경의 변수를 기억하되, 실제로 사용하는 변수만을 메모리에 유지하는 최적화된 방식으로 동작한다.<ul>
<li>메모리 효율성 &amp; 코드의 캡슐화를 동시 달성!</li>
</ul>
</li>
</ul>
</blockquote>
<h3 id="결론">결론</h3>
<blockquote>
<p>그래서 자바스크립트에서 클로저가 뭐냐고 물어보면 뭐라고 답해야하지..?! </p>
</blockquote>
<ul>
<li><strong>함수와 그 함수가 선언될 당시의 lexical environment의 상호관계에 따른 현상.</strong></li>
<li><strong>내부함수가 외부함수의 생명 주기가 종료된 후에도 외부함수의 변수를 참조(이게 핵심)</strong>할 수 있는데, 이때 해당 변수들 중 내부함수가 실제로 사용하는 변수만을 선택적으로 기억하여 메모리 효율을 높임.</li>
</ul>
<h3 id="아니-그럼-렉시컬-스코프와-클로저가-뭐가-다른거지">아니 그럼 렉시컬 스코프와 클로저가 뭐가 다른거지?</h3>
<blockquote>
<p><strong>렉시껄 스코프</strong>는 &quot;함수를 어디에 선언했는지&quot;에 따라 상위 스코프를 결정하는 <code>규칙</code>이다.</p>
</blockquote>
<pre><code class="language-jsx">    const x = 1;

    function foo() {
        const x = 10;
        bar();
    }
    function bar() {
        console.log(x); // 1
    }
    foo();
</code></pre>
<ul>
<li>bar가 전역에서 선언되었으므로 전역 스코프의 x를 참조</li>
</ul>
<blockquote>
<p><strong>클로저</strong>는 이 렉시컬 스코프의 규칙을 기반으로, &quot;이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 <code>현상</code>&quot;이다.</p>
</blockquote>
<pre><code class="language-jsx">    function foo() {
        const x = 1;
        return function bar() {
            console.log(x); // 1
        }
    }

    const savedBar = foo(); // foo는 실행 종료
    savedBar(); // 하지만 여전히 x에 접근 가능
</code></pre>
<ul>
<li>foo 함수는 종료됐지만 반환된 bar가 x를 여전히 참조 가능</li>
</ul>
<blockquote>
<p>즉:</p>
</blockquote>
<ul>
<li>렉시컬 스코프: 상위 스코프를 결정하는 규칙</li>
<li>클로저: 이 규칙을 활용해 이미 종료된 함수의 변수를 참조하는 현상</li>
<li>클로저는 렉시컬 스코프라는 규칙이 있기에 가능한 현상이라고 볼 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트 - 렉시컬 스코프(lexical scope) 빠르게 알아보기]]></title>
            <link>https://velog.io/@live_in_truth/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%A0%89%EC%8B%9C%EC%BB%AC-%EC%8A%A4%EC%BD%94%ED%94%84lexical-scope-%EB%B9%A0%EB%A5%B4%EA%B2%8C-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@live_in_truth/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%A0%89%EC%8B%9C%EC%BB%AC-%EC%8A%A4%EC%BD%94%ED%94%84lexical-scope-%EB%B9%A0%EB%A5%B4%EA%B2%8C-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Thu, 19 Dec 2024 11:33:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/live_in_truth/post/11dfd68c-3e55-4e3c-aeb1-edf90eb3b8f4/image.png" alt=""></p>
<p><em>모던 자바스크립트 Deep Dive 예시코드 참고</em></p>
<blockquote>
<p>자바스크립트에서 렉시컬 스코프는 &quot;함수가 어디서 호출되는지&quot;가 아니라 _<strong>&quot;함수가 어디서 정의되었는지&quot;</strong>_에 따라 상위 스코프가 결정되는 것을 말한다.</p>
</blockquote>
<h2 id="1-함수의-위치에-따른-스코프-차이">1. 함수의 위치에 따른 스코프 차이</h2>
<blockquote>
<p>먼저 첫 번째 코드를 보면:</p>
</blockquote>
<pre><code class="language-javascript">const x = 1;

function outerFunc() {
  const x = 10;
  innerFunc();
}

function innerFunc() {
  console.log(x);
}

outerFunc(); // 출력결과: 1</code></pre>
<blockquote>
<p>이 코드에서 함수 <code>innerFunc</code>는 전역에서 정의되었다. 따라서 <code>innerFunc</code>의 <strong><em>상위 스코프는 전역</em></strong>이다. 
<code>innerFunc</code>가 <code>outerFunc</code> 내부에서 _<strong>호출</strong>_되더라도, <code>innerFunc</code>는 전역 변수 <code>x</code>의 값인 1을 출력한다.</p>
</blockquote>
<h2 id="2-중첩-함수의-렉시컬-스코프">2. 중첩 함수의 렉시컬 스코프</h2>
<p>두 번째 코드를 살펴보면:</p>
<pre><code class="language-javascript">const x = 1;

function outerFunc() {
  const x = 10;
  const innerFunc = () =&gt; {
    console.log(x);
  }
  innerFunc();
}

outerFunc(); // 출력결과: 10</code></pre>
<blockquote>
<p>이번에는 <code>innerFunc</code>가 <code>outerFunc</code> 내부에서 정의되었다. 렉시컬 스코프의 규칙에 따라, <code>innerFunc</code>의 상위 스코프는 <em><strong>자신이 정의된 위치인</strong></em> <code>outerFunc</code>의 스코프가 된다. 따라서 <code>innerFunc</code>는 <code>outerFunc</code>의 지역 변수 <code>x</code>값인 10을 참조한다.</p>
</blockquote>
<h2 id="3-함수의-호출-위치와-렉시컬-스코프">3. 함수의 호출 위치와 렉시컬 스코프</h2>
<p>마지막 예제를 보면:</p>
<pre><code class="language-javascript">const x = 1;

function foo() {
  const x = 10;
  bar();
}

function bar() {
  console.log(x);
}

foo(); // 출력: 1
bar(); // 출력: 1</code></pre>
<blockquote>
<p>이 예제에서 <code>bar</code> 함수는 <em><strong>전역에서 정의</strong>_되었다. <code>bar</code>가 <code>foo</code> 내부에서 호출되든, 전역에서 직접 호출되든 상관없이, <code>bar</code>의 _<strong>상위 스코프는 항상 전역 스코프이다</strong></em>. 따라서 두 경우 모두 전역 변수 <code>x</code>의 값인 1을 출력한다.</p>
</blockquote>
<h2 id="핵심-정리">핵심 정리</h2>
<blockquote>
<p>렉시컬 스코프는 함수를 어디서 호출하는지가 아니라, <em><strong>어디에 선언하는지에 따라 결정됨.</strong></em></p>
</blockquote>
<blockquote>
<p>중첩 함수의 경우, 상위 스코프는 함수가 정의된 위치의 스코프가 됨.</p>
</blockquote>
<blockquote>
<p>전역에서 정의된 함수의 상위 스코프는 항상 전역 스코프.</p>
</blockquote>
<h2 id="결론">결론</h2>
<blockquote>
<p><em><strong>렉시컬 스코프란?</strong> 이라고 물어본다면</em>
<strong>함수가 선언된 위치에 따라 상위 스코프가 결정되는 것!
이는 함수가 호출된 위치와는 무관하게 함수가 정의된 위치에서 상위 스코프가 고정적으로 결정됨!</strong></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트 - 일급객체 
빠르게 알아보기]]></title>
            <link>https://velog.io/@live_in_truth/%EC%9D%BC%EA%B8%89%EA%B0%9D%EC%B2%B4-%EC%A7%A7%EA%B3%A0-%EB%B9%A0%EB%A5%B4%EA%B2%8C-%EC%91%A4%EC%85%94%EB%84%A3%EA%B8%B0</link>
            <guid>https://velog.io/@live_in_truth/%EC%9D%BC%EA%B8%89%EA%B0%9D%EC%B2%B4-%EC%A7%A7%EA%B3%A0-%EB%B9%A0%EB%A5%B4%EA%B2%8C-%EC%91%A4%EC%85%94%EB%84%A3%EA%B8%B0</guid>
            <pubDate>Sat, 14 Dec 2024 08:25:49 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/live_in_truth/post/99386757-83eb-4f5d-85d4-c7c5198762a6/image.png" alt=""></p>
<p><em>JavaScript에서 &quot;함수는 일급 객체이다&quot;라는 개념을 설명하기 위해 작성.</em></p>
<h3 id="javascript에서-다음과-같은-조건을-만족하는-객체를-일급-객체라-한다">javascript에서 다음과 같은 조건을 만족하는 객체를 일급 객체라 한다.</h3>
<blockquote>
<ol>
<li>무명의 리터럴로 생성할 수 있다. 즉, 런타임에 생성이 가능하다.</li>
<li>변수나 자료구조(객체, 배열 등)에 저장할 수 있다.</li>
<li>함수의 매개변수에 전달할 수 있다.</li>
<li>함수의 반환값으로 사용할 수 있다.</li>
</ol>
</blockquote>
<h3 id="뭔말인지-모르겠다면-여기를-먼저-보고-가기">뭔말인지 모르겠다면 여기를 먼저 보고 가기</h3>
<h4 id="무명의-리터럴이란">무명의 리터럴이란?</h4>
<blockquote>
<p>이름이 없는 값을 직접 코드에 작성하는 것을 말한다.
예를 들어 let num = 5;에서 5가 무명의 리터럴이다.
리터럴을 딱 이렇게 생각해보자 </p>
</blockquote>
<pre><code class="language-javascript">const x = &quot;이곳에 위치할 수 있다.&quot;;</code></pre>
<pre><code class="language-javascript">const z = function() {};    // 함수 이름이 없기 때문에 무명의 리터럴이라고 하는것이다. </code></pre>
<h4 id="여기서-또-잠깐">여기서 또 잠깐.</h4>
<h4 id="런타임에-생성이란">런타임에 생성이란?</h4>
<blockquote>
<p>프로그램이 실제로 실행되는 시점에 만들어진다는 의미이다.
코드가 작성된 시점이 아니라, 실제로 그 코드가 실행되는 순간에 메모리에 생성된다.
아래 예시 코드에서 makeCounter 함수가 호출될 때마다 새로운 함수가 그 순간(런타임)에 생성되는 것을 말한다.</p>
</blockquote>
<blockquote>
<p>즉, 이름 없이 값을 직접 쓰고(무명의 리터럴), 그 값이 프로그램이 실행되는 순간에 만들어진다(런타임에 생성)는 의미이다.</p>
</blockquote>
<h4 id="이참에-다른-개념도-알아보기">이참에 다른 개념도 알아보기</h4>
<h4 id="컴파일-타임compile-time">컴파일 타임(Compile time)</h4>
<blockquote>
<p>컴파일 타임은 프로그램이 실행되기 전, 소스 코드가 기계어로 변환되는 시점을 말한다. 이때 생성되거나 결정되는 것들을 &#39;컴파일 타임에 생성된다&#39; 또는 &#39;정적(static)으로 생성된다&#39;고 표현한다.</p>
</blockquote>
<blockquote>
<p>컴파일 타임: 소스코드에 직접 작성된 상수, 클래스 정의 등
런타임: 사용자 입력에 따른 값, 함수 실행 결과 등</p>
</blockquote>
<h3 id="다시-일급객체로-돌아와서">다시 &#39;일급객체&#39;로 돌아와서.</h3>
<h4 id="모던-자바스크립트-deep-dive-18-01-예제-코드">모던 자바스크립트 Deep Dive 18-01 예제 코드</h4>
<pre><code class="language-javascript">// 1. 무명의 리터럴로 생성: 함수를 이름 없이 변수에 직접 할당
const increase = function (num) {
  return ++num;
}

const decrease = function (num) {
  return --num;
}

// 2. 자료구조(객체)에 저장: 함수를 객체의 프로퍼티로 저장
const auxs = { increase, decrease };

// 3. 함수의 매개변수로 전달: aux 매개변수로 함수를 전달받음
function makeCounter(aux) {
  let num = 0;

  // 4. 함수의 반환값으로 함수를 사용: 새로운 함수를 생성하여 반환
  return function () {
    num = aux(num); // 전달받은 함수(aux)를 실행
    return num;
  };
}

// makeCounter 함수에 increase 함수를 전달하여 새로운 함수 생성
const increaser = makeCounter(auxs.increase);
console.log(increaser()); // 1
console.log(increaser()); // 2

// makeCounter 함수에 decrease 함수를 전달하여 새로운 함수 생성
const decreaser = makeCounter(auxs.decrease);
console.log(decreaser()); // -1
console.log(decreaser()); // -2</code></pre>
<h3 id="결론">결론</h3>
<blockquote>
<p><em><strong>일급객체란?</strong> 이라고 물어본다면?</em>
<strong>함수를 일반 객체처럼 변수에 할당할 수 있고, 다른 함수의 매개변수로 전달하거나 반환값으로 사용할 수 있으며, 객체의 프로퍼티로도 할당할 수 있는 성질!</strong></p>
</blockquote>
<blockquote>
<p>JavaScript에서 &quot;함수는 일급 객체이다&quot; =&gt; <strong>함수를 객체</strong>처럼 사용가능하다. 
왜? 유연성과 재사용성을 위해!</p>
</blockquote>
<p>개념 및 코드 참고: <em>모던 자바스크립트 Deep Dive</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Mixed Content 에러 해결하기 (feat: Vercel Serverless Function)]]></title>
            <link>https://velog.io/@live_in_truth/Mixed-Content-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0-feat-Vercel-Serverless-Function</link>
            <guid>https://velog.io/@live_in_truth/Mixed-Content-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0-feat-Vercel-Serverless-Function</guid>
            <pubDate>Tue, 03 Dec 2024 13:08:02 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/live_in_truth/post/39c7d6cf-c014-45a6-b62d-c4452fe6bff3/image.png" alt=""></p>
<h1 id="vercel-serverless-function으로-mixed-content-에러-해결하기">Vercel Serverless Function으로 Mixed Content 에러 해결하기</h1>
<h2 id="문제-상황">문제 상황</h2>
<p>HTTPS로 배포된 React 애플리케이션에서 HTTP API(서울시 문화행사 정보)를 호출하려고 할 때 Mixed Content 에러가 발생한다.
하필 서울시 open api는 https 프로토콜을 제공하지 않기 때문에 </p>
<pre><code class="language-html">&lt;meta http-equiv=&quot;Content-Security-Policy&quot; content=&quot;upgrade-insecure-requests</code></pre>
<p><em>(https로 변환하는 방법) 위 방법도 안먹힌다.</em></p>
<pre><code class="language-javascript">// ❌ 직접 HTTP API를 호출하는 경우
fetch(&#39;http://openapi.seoul.go.kr:8088/API_KEY/json/culturalEventInfo/1/5/&#39;);
// Mixed Content 에러 발생!</code></pre>
<h2 id="원인">원인</h2>
<ul>
<li>보안상의 이유로 브라우저는 HTTPS 페이지에서 HTTP 리소스를 직접 불러오는 것을 차단한다</li>
<li>사용자의 데이터를 보호하기 위한 보안 정책때문..</li>
</ul>
<h2 id="해결-방법">해결 방법</h2>
<p>Vercel의 Serverless Function을 프록시로 사용하여 HTTP API 호출을 우회한다.</p>
<h3 id="1-api-라우트-설정-apieventsjs">1. API 라우트 설정 (/api/events.js)</h3>
<pre><code class="language-javascript">const axios = require(&#39;axios&#39;);

module.exports = async (req, res) =&gt; {
  try {
    // 서버 사이드에서 HTTP API 호출
    const API_KEY = process.env.REACT_APP_API_KEY;
    const response = await axios.get(
      `http://openapi.seoul.go.kr:8088/${API_KEY}/json/culturalEventInfo/1/5/`
    );

    // 응답 데이터 확인 및 반환
    if (!response.data.culturalEventInfo) {
      throw new Error(response.data.RESULT?.MESSAGE || &#39;API 호출 실패&#39;);
    }

    res.status(200).json(response.data);
  } catch (error) {
    console.error(&#39;Server Error:&#39;, error);
    res.status(500).json({
      error: true,
      message: error.message || &#39;Internal Server Error&#39;
    });
  }
};</code></pre>
<h3 id="2-vercel-설정-verceljson-netlify도-당연히-가능함-경로나-파일명만-살짝-달리해야함">2. Vercel 설정 (vercel.json) (netlify도 당연히 가능함. 경로나 파일명만 살짝 달리해야함.)</h3>
<pre><code class="language-json">{
  &quot;version&quot;: 2,
  &quot;rewrites&quot;: [
    {
      &quot;source&quot;: &quot;/api/:path*&quot;,
      &quot;destination&quot;: &quot;/api/:path*&quot;
    }
  ]
}</code></pre>
<h3 id="3-react-컴포넌트에서-api-호출appjs-일부">3. React 컴포넌트에서 API 호출(App.js 일부)</h3>
<pre><code class="language-javascript">const fetchEvents = async () =&gt; {
  try {
    // ✅ HTTPS로 제공되는 Vercel Function 호출
    const response = await fetch(&#39;/api/events&#39;);
    const data = await response.json();

    if (data.error) {
      throw new Error(data.message);
    }

    setEvents(data.culturalEventInfo.row || []);
  } catch (err) {
    console.error(&#39;Error details:&#39;, err);
    setError(err.message);
  }
};</code></pre>
<h4 id="전체-appjs-코드">전체 App.js 코드</h4>
<pre><code class="language-jsx">import { useState, useEffect } from &#39;react&#39;;
import &#39;./App.css&#39;;

function App() {
  const [events, setEvents] = useState([]);
  const [error, setError] = useState(null);

  useEffect(() =&gt; {
    const fetchEvents = async () =&gt; {
      try {
        const response = await fetch(&#39;/api/events&#39;);
        console.log(&#39;Response status:&#39;, response.status);

        const data = await response.json();
        console.log(&#39;Response data:&#39;, data);

        if (data.error) {
          throw new Error(data.message);
        }

        setEvents(data.culturalEventInfo.row || []);
      } catch (err) {
        console.error(&#39;Error details:&#39;, err);
        setError(err.message);
      }
    };

    fetchEvents();
  }, []);

  if (error) {
    return &lt;div&gt;에러 발생: {error}&lt;/div&gt;;
  }

  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;h1&gt;서울시 문화행사 정보&lt;/h1&gt;
      {events.length === 0 ? (
        &lt;p&gt;로딩중...&lt;/p&gt;
      ) : (
        &lt;ul&gt;
          {events.map((event, index) =&gt; (
            &lt;li key={index} style={{marginBottom: &#39;20px&#39;, textAlign: &#39;left&#39;}}&gt;
              &lt;h3&gt;{event.TITLE}&lt;/h3&gt;
              &lt;p&gt;분류: {event.CODENAME}&lt;/p&gt;
              &lt;p&gt;장소: {event.PLACE}&lt;/p&gt;
              &lt;p&gt;날짜: {event.DATE}&lt;/p&gt;
              &lt;p&gt;요금: {event.USE_FEE}&lt;/p&gt;
              {event.MAIN_IMG &amp;&amp; (
                &lt;img 
                  src={event.MAIN_IMG}
                  alt={event.TITLE}
                  style={{maxWidth: &#39;200px&#39;}}
                /&gt;
              )}
            &lt;/li&gt;
          ))}
        &lt;/ul&gt;
      )}
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<h2 id="작동-원리">작동 원리</h2>
<ol>
<li>브라우저가 안전한 HTTPS 연결을 통해 Vercel Serverless Function을 호출한다.</li>
<li>Serverless Function이 서버 사이드에서 HTTP API를 호출한다.</li>
<li>받아온 데이터를 다시 HTTPS를 통해 브라우저로 전달한다.</li>
</ol>
<pre><code>[브라우저] → HTTPS → [Vercel Function] → HTTP → [서울시 API]</code></pre><p><em>브라우저: &quot;물건이 왔는데 가져오기 무서워요.. Vercel Function님 대신 가져와주세요ㅎ&quot; (브라우저가 Vercel Function에 HTTPS로 요청)</em></p>
<p><em>Vercel Function: 응 알겠어. 나는 브라우저가 아니라 서버라서 http/https 모두 가져올 수 있어. (Vercel이 서버에서 HTTP API 호출)</em></p>
<p><em>Vercel Function: 자 받아. 가져왔어. (Vercel이 데이터를 HTTPS로 브라우저에 전달)</em></p>
<h2 id="구현-순서">구현 순서</h2>
<ol>
<li><code>/api/events.js</code> 파일 생성 및 서버리스 함수 구현</li>
<li><code>vercel.json</code> 설정으로 API 라우트 경로 매핑</li>
<li>React 컴포넌트에서 API 호출 코드 수정</li>
<li>Vercel 환경변수 설정 (REACT_APP_API_KEY)</li>
<li>배포 및 테스트</li>
</ol>
<h2 id="주의사항">주의사항</h2>
<ul>
<li>환경변수는 반드시 Vercel 대시보드에서도 설정해야 함.</li>
<li>로컬 개발 환경에서는 <code>.env.local</code> 파일에 환경변수를 설정.</li>
<li>API 응답의 에러 처리를 반드시 구현해야 디버깅 편함</li>
</ul>
<blockquote>
<p>이렇게 Vercel Serverless Function을 활용하면 Mixed Content 에러를 해결하면서도 보안을 유지할 수 있다! 이것이 바로 <strong>서버리스 아키텍처</strong>라고 한다. 엥? vercel 서버를 사용하는데 왜 서버less 지? =&gt; 내가 서버 관리안하고 vercel서비스가 서버 관리를 해주므로 <strong>서버리스</strong>라고 하는 것이다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[미들웨어 프록시란?(CORS(Cross-Origin Resource Sharing), React)]]></title>
            <link>https://velog.io/@live_in_truth/%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4-%ED%94%84%EB%A1%9D%EC%8B%9C%EB%9E%80CORSCross-Origin-Resource-Sharing-React</link>
            <guid>https://velog.io/@live_in_truth/%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4-%ED%94%84%EB%A1%9D%EC%8B%9C%EB%9E%80CORSCross-Origin-Resource-Sharing-React</guid>
            <pubDate>Mon, 07 Oct 2024 14:30:39 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/live_in_truth/post/69d43bd6-432d-48e7-9a57-8e3c9d392c38/image.png" alt=""></p>
<h3 id="미들웨어-프록시란">미들웨어 프록시란?</h3>
<p>프록시는 클라이언트(브라우저)와 서버 사이에 중계 역할을 하는 서버입니다. 클라이언트가 특정 서버에 직접 요청을 보내지 않고, 중간에 위치한 프록시 서버가 요청을 대신 전달하고 그 응답을 다시 클라이언트로 보내는 방식입니다.</p>
<p><strong>미들웨어 프록시</strong>는 개발 환경에서 자주 사용되며, 개발 중 클라이언트와 외부 API 간의 요청을 중계하여 발생할 수 있는 <strong>CORS(Cross-Origin Resource Sharing)</strong> 문제를 우회할 수 있도록 도와줍니다.</p>
<h3 id="왜-미들웨어-프록시가-필요한가">왜 미들웨어 프록시가 필요한가?</h3>
<p>React 같은 싱글 페이지 애플리케이션(SPA)을 개발할 때, 클라이언트 측에서 외부 API로 요청을 보낼 때 CORS 정책에 의해 브라우저에서 차단될 수 있습니다. 브라우저는 동일 출처 정책(Same-Origin Policy)을 따르기 때문에, 클라이언트가 다른 도메인에 직접적으로 요청을 보내는 것을 허용하지 않습니다. 이 문제를 해결하기 위해 개발 환경에서는 <strong>프록시 미들웨어</strong>를 사용합니다.</p>
<blockquote>
<p>개발 환경 <a href="http://localhost:3000">http://localhost:3000</a> 브라우저<strong>&#39;에서&#39;</strong> 외부 API 요청<strong>&#39;을&#39;</strong>차단하는 겁니다.</p>
</blockquote>
<h3 id="미들웨어-프록시-사용법-react와-http-proxy-middleware">미들웨어 프록시 사용법 (React와 <code>http-proxy-middleware</code>)</h3>
<p>React에서 개발 환경에서만 동작하는 미들웨어 프록시는 <code>http-proxy-middleware</code> 라이브러리를 사용해 설정할 수 있습니다. 이 미들웨어는 주로 <strong><code>create-react-app</code></strong> 환경에서 사용되며, 로컬 개발 서버(<code>webpack-dev-server</code>)에서 동작합니다.</p>
<h3 id="http-proxy-middleware-설정-방법"><code>http-proxy-middleware</code> 설정 방법</h3>
<h4 id="1-설치">1. 설치</h4>
<p>먼저 <code>http-proxy-middleware</code> 라이브러리를 프로젝트에 설치합니다:</p>
<pre><code class="language-bash">npm install http-proxy-middleware --save</code></pre>
<h4 id="2-setupproxyjs-파일-생성">2. <code>setupProxy.js</code> 파일 생성</h4>
<p><code>src/</code> 디렉토리에 <code>setupProxy.js</code> 파일을 생성합니다. 이 파일에 프록시 설정을 추가합니다. 예를 들어, 클라이언트에서 <code>/api</code>로 시작하는 모든 요청을 외부 API 서버로 프록시하려면 다음과 같은 설정을 사용할 수 있습니다:</p>
<pre><code class="language-javascript">const { createProxyMiddleware } = require(&#39;http-proxy-middleware&#39;);

module.exports = function(app) {
  app.use(
    &#39;/api&#39;,
    createProxyMiddleware({
      target: &#39;https://api.example.com&#39;, // 외부 API 서버의 주소
      changeOrigin: true, // 서버의 origin을 변경
      pathRewrite: {
        &#39;^/api&#39;: &#39;&#39;, // /api로 시작하는 경로를 빈 문자열로 바꿈
      },
    })
  );
};</code></pre>
<p>이 설정은 다음과 같은 역할을 합니다:</p>
<ul>
<li><strong><code>/api</code> 경로</strong>로 들어오는 모든 요청을 <code>https://api.example.com</code>으로 프록시합니다.</li>
<li><code>pathRewrite</code> 설정을 통해 <code>/api</code> 부분을 제거하고 실제 API 서버로 요청을 보냅니다.</li>
</ul>
<h4 id="3-프록시-동작-과정">3. 프록시 동작 과정</h4>
<p>클라이언트가 <code>http://localhost:3000/api/some-endpoint</code>로 요청을 보낼 경우, 이 요청은 미들웨어 프록시에 의해 <code>https://api.example.com/some-endpoint</code>로 전달됩니다. 클라이언트는 이 과정을 인식하지 못하고, 응답만 받게 됩니다.</p>
<h3 id="주의사항-배포-환경에서의-프록시">주의사항: 배포 환경에서의 프록시</h3>
<p><strong>중요한 점은 이 미들웨어 프록시는 개발 환경에서만 동작</strong>한다는 것입니다. <code>create-react-app</code>으로 시작한 개발 서버(<code>webpack-dev-server</code>)가 실행될 때만 프록시가 활성화됩니다. 하지만 배포된 환경에서는 이 미들웨어가 동작하지 않습니다.</p>
<h4 id="왜-배포-환경에서는-동작하지-않는가">왜 배포 환경에서는 동작하지 않는가?</h4>
<ul>
<li><strong>정적 파일로 배포</strong>: React 애플리케이션이 배포되면, 일반적으로 Vercel, Netlify, GitHub Pages와 같은 플랫폼에서 <strong>정적 파일</strong>로 제공됩니다. 이때 프론트엔드 애플리케이션은 <code>webpack-dev-server</code> 같은 Node.js 서버를 사용하지 않으며, 단지 정적 파일(HTML, CSS, JavaScript)로만 제공됩니다. 따라서 <code>setupProxy.js</code>에 설정된 프록시 미들웨어는 더 이상 작동하지 않습니다.</li>
<li><strong>CORS 문제</strong>: 배포 환경에서는 클라이언트에서 API 서버로 직접 요청을 보내기 때문에 다시 <strong>CORS 문제</strong>가 발생할 수 있습니다. 이 문제를 해결하려면 배포 환경에서도 CORS를 허용할 수 있는 백엔드 서버가 필요하거나, 외부 API가 CORS 요청을 허용해야 합니다.</li>
</ul>
<h3 id="배포-환경에서의-해결-방법">배포 환경에서의 해결 방법</h3>
<ol>
<li><p><strong>API 요청을 직접 HTTPS로 보내기</strong>:
배포된 애플리케이션은 보안(HTTPS)으로 제공되므로, API 요청도 HTTPS로 보내야 합니다. 만약 API 서버가 HTTPS를 지원하면, 클라이언트에서 직접 HTTPS로 요청을 보내어 CORS 문제를 피할 수 있습니다.</p>
<blockquote>
<p>엥간~한 openAPI서버들은 HTTPS를 지원하기때문에 기존 http로 보냈던 API를 https로 바꿔주면 됩니다.</p>
</blockquote>
</li>
<li><p><strong>백엔드 서버 설정</strong>:
백엔드 서버가 있다면, 클라이언트가 외부 API로 직접 요청을 보내는 대신 백엔드 서버로 요청을 보내게 하고, 백엔드가 외부 API에 요청한 결과를 클라이언트로 전달하도록 설정할 수 있습니다. 이 방식은 클라이언트와 외부 API 간의 CORS 문제를 우회할 수 있는 좋은 방법입니다.</p>
</li>
<li><p><strong>서버리스 함수(Serverless Function) 사용</strong>:
Vercel이나 Netlify와 같은 호스팅 플랫폼에서는 서버리스 함수(예: AWS Lambda)로 API 요청을 중계할 수 있습니다. 클라이언트가 서버리스 함수로 요청을 보내면, 이 함수가 외부 API로 요청을 보내고, 응답을 다시 클라이언트로 전달합니다. 이를 통해 CORS 문제를 해결할 수 있습니다.</p>
</li>
</ol>
<h3 id="예시-서버리스-함수-사용">예시: 서버리스 함수 사용</h3>
<p>Vercel에서는 서버리스 함수를 쉽게 설정할 수 있습니다. 예를 들어, Vercel에서 API 요청을 처리하는 서버리스 함수는 다음과 같습니다:</p>
<pre><code class="language-javascript">// api/proxy.js

export default async function handler(req, res) {
  const response = await fetch(&#39;https://api.example.com/some-endpoint&#39;);
  const data = await response.json();
  res.status(200).json(data);
}</code></pre>
<p>클라이언트는 <code>/api/proxy</code> 경로로 요청을 보내면, Vercel 서버리스 함수가 외부 API에 요청을 보내고, 응답을 전달합니다. 이 방법은 배포 환경에서도 CORS 문제를 해결할 수 있습니다.</p>
<h3 id="결론">결론</h3>
<ul>
<li><strong>미들웨어 프록시</strong>는 개발 환경에서 CORS 문제를 해결하고, 클라이언트와 외부 API 간의 요청을 중계하는 역할을 합니다. 하지만 이는 <strong>배포 환경에서는 동작하지 않기 때문에</strong> 클라이언트에서 직접 HTTPS로 API 요청을 보내거나 백엔드 서버를 이용해 요청을 중계해야 합니다.</li>
<li>배포 환경에서는 백엔드 서버 또는 서버리스 함수가 이러한 역할을 대신하여 CORS 문제를 해결하고, 클라이언트가 안정적으로 API와 통신할 수 있도록 도와줍니다.</li>
</ul>
<blockquote>
<p>요약</p>
</blockquote>
<ul>
<li>미들웨어를 통해 프록시 역할을 수행하도록 코드를 작성한다!</li>
<li>http-proxy-middleware 같은 라이브러리는 미들웨어 코드로서 프록시 기능을 구현한다! </li>
<li>이 경우 미들웨어가 프록시 서버 역할을 간접적으로 수행한다!</li>
<li>클라이언트가 서버에 요청을 보내면, 미들웨어가 그 요청을 가로챈다!</li>
<li>미들웨어는 요청을 처리하고, 다른 서버로 전달하는 역할(프록시 역할)을 한다!</li>
<li>해당 서버의 응답을 다시 받아서 클라이언트에게 반환한다!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[.eslintrc.json 모르면 기술면접 떨어짐]]></title>
            <link>https://velog.io/@live_in_truth/.eslintrc.json-%EB%AA%A8%EB%A5%B4%EB%A9%B4-%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EB%96%A8%EC%96%B4%EC%A7%90</link>
            <guid>https://velog.io/@live_in_truth/.eslintrc.json-%EB%AA%A8%EB%A5%B4%EB%A9%B4-%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EB%96%A8%EC%96%B4%EC%A7%90</guid>
            <pubDate>Wed, 02 Oct 2024 16:58:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/live_in_truth/post/2b612a36-9081-4e43-a615-55d2bec06c39/image.png" alt=""></p>
<blockquote>
<p>프론트엔드 개발자에게 있어 <strong>코드의 품질</strong>과 <strong>일관성</strong>을 유지하는 것은 매우 중요합니다. 특히, 현업에서는 혼자 프로젝트를 진행하는 경우가 거의 없다는 것은 학부생도 알고 있는 사실이죠. 
<strong>팀 단위</strong>로 프로젝트를 진행할 때, 모든 팀원이 <strong>동일한 코드 스타일</strong>을 따르는 것은 <strong>유지보수성과 가독성</strong>을 높이는 핵심 요소이자 배려이자 개념이자 기본 소양입니다. </p>
</blockquote>
<blockquote>
<p>이러한 상황에서 강력한 도구가 바로 <strong>ESLint</strong>이며, 그 중심에는 프로젝트의 <strong>.eslintrc.json</strong> 설정 파일이 있습니다.</p>
</blockquote>
<hr>
<h2 id="왜-eslintrcjson을-사용해야-하는가"><strong>왜 <code>.eslintrc.json</code>을 사용해야 하는가?</strong></h2>
<h3 id="1-코드-품질-유지">1. <strong>코드 품질 유지</strong></h3>
<p><code>.eslintrc.json</code> 파일은 프로젝트의 <strong>ESLint 설정을 정의</strong>하는 파일입니다. ESLint는 코드 품질을 자동으로 검사해주고, 일관되지 않은 코드 스타일이나 잠재적인 에러를 발견할 수 있습니다. 이 파일은 팀 내에서 <strong>일관된 코드 스타일을 유지</strong>하는 데 매우 중요한 역할을 합니다. 이를 통해 개발자는 팀원들 간에 서로 다른 코드 스타일로 인해 발생하는 불필요한 충돌을 줄일 수 있습니다.</p>
<hr>
<h3 id="2-버그-예방">2. <strong>버그 예방</strong></h3>
<p>규칙 기반의 ESLint 설정은 잠재적인 버그를 미리 찾아낼 수 있도록 돕습니다. 예를 들어, 변수 선언 후 사용하지 않았거나, 올바르지 않은 비교 연산자를 사용한 경우 경고 메시지를 통해 버그 발생을 예방할 수 있습니다. 이는 사소해 보이지만, 시간이 지남에 따라 큰 문제로 발전할 수 있는 버그들을 조기에 잡아내는 데 매우 유용합니다.</p>
<hr>
<h3 id="3-일관된-코드-스타일">3. <strong>일관된 코드 스타일</strong></h3>
<p>팀이 커질수록 코드 스타일의 통일성은 점점 더 중요해집니다. 프로젝트 초기부터 ESLint 설정을 확립해놓으면, 팀원들이 동일한 코드 스타일 규칙을 따르게 되어 리뷰 시간도 단축되고, 코드 가독성도 높아집니다. ESLint는 코딩 컨벤션을 강제할 수 있는 다양한 플러그인과 규칙을 제공합니다. 예를 들어, 세미콜론 사용 여부, 들여쓰기 스타일, 함수의 선언 방식 등 일관된 스타일을 유지하는 데 도움을 줍니다.</p>
<blockquote>
<p>좀 더 직관적이게 예시로 보여드리겠습니다.</p>
</blockquote>
<h4 id="eslint-설정-eslintrcjson">ESLint 설정 (<code>.eslintrc.json</code>)</h4>
<pre><code class="language-json">{
  &quot;env&quot;: {
    &quot;browser&quot;: true,
    &quot;es2021&quot;: true
  },
  &quot;extends&quot;: [
    &quot;eslint:recommended&quot;,
    &quot;plugin:react/recommended&quot;,
    &quot;airbnb&quot;,
    &quot;prettier&quot;
  ],
  &quot;parserOptions&quot;: {
    &quot;ecmaFeatures&quot;: {
      &quot;jsx&quot;: true
    },
    &quot;ecmaVersion&quot;: 12,
    &quot;sourceType&quot;: &quot;module&quot;
  },
  &quot;rules&quot;: {
    &quot;semi&quot;: [&quot;error&quot;, &quot;always&quot;],        // 세미콜론을 항상 사용
    &quot;quotes&quot;: [&quot;error&quot;, &quot;single&quot;],      // 문자열을 항상 single quote로 사용
    &quot;indent&quot;: [&quot;error&quot;, 2],             // 들여쓰기를 2칸으로 강제
    &quot;react/jsx-indent&quot;: [&quot;error&quot;, 2],   // JSX 들여쓰기를 2칸으로 강제
    &quot;react/prop-types&quot;: &quot;off&quot;           // PropTypes 사용을 끔 (TypeScript 대체)
  }
}</code></pre>
<h4 id="eslint-규칙-설명">ESLint 규칙 설명</h4>
<ul>
<li><strong><code>semi: [&quot;error&quot;, &quot;always&quot;]</code></strong>: <strong>세미콜론</strong>을 항상 붙이도록 강제.</li>
<li><strong><code>quotes: [&quot;error&quot;, &quot;single&quot;]</code></strong>: <strong>문자열</strong>은 항상 <code>&#39;</code>(single quote)로 작성하도록 강제.</li>
<li><strong><code>indent: [&quot;error&quot;, 2]</code></strong>: <strong>들여쓰기</strong>를 <strong>2칸</strong>으로 고정.</li>
<li><strong><code>react/jsx-indent: [&quot;error&quot;, 2]</code></strong>: <strong>JSX</strong>에서도 들여쓰기를 <strong>2칸</strong>으로 고정.</li>
<li><strong><code>react/prop-types: &quot;off&quot;</code></strong>: <strong>PropTypes</strong>를 사용하지 않도록 하고, 대신 TypeScript를 사용하는 경우를 대비.</li>
</ul>
<h3 id="코드-예시">코드 예시</h3>
<h4 id="1-잘못된-코드-eslint-규칙-위반">1. <strong>잘못된 코드 (ESLint 규칙 위반)</strong></h4>
<pre><code class="language-jsx">import React from &quot;react&quot;

function MyComponent(props) {
 return (
  &lt;div&gt;
    &lt;h1&gt;Hello, {props.name}&lt;/h1&gt;
    &lt;p&gt;This is my component&lt;/p&gt;
  &lt;/div&gt;
 )
}</code></pre>
<ul>
<li><strong>문제점</strong>:<ul>
<li>세미콜론이 누락됨 (<code>semi</code> 규칙 위반).</li>
<li>들여쓰기가 4칸으로 되어 있음 (<code>indent</code> 규칙 위반).</li>
<li>문자열이 더블 쿼트로 되어 있음 (<code>quotes</code> 규칙 위반).</li>
</ul>
</li>
</ul>
<h4 id="2-eslint가-자동으로-수정한-코드-규칙-적용">2. <strong>ESLint가 자동으로 수정한 코드 (규칙 적용)</strong></h4>
<pre><code class="language-jsx">import React from &#39;react&#39;;  // single quotes and semicolon

function MyComponent(props) {  // indent fixed
  return (
    &lt;div&gt;
      &lt;h1&gt;Hello, {props.name}&lt;/h1&gt;
      &lt;p&gt;This is my component&lt;/p&gt;
    &lt;/div&gt;
  );  // semicolon added
}</code></pre>
<ul>
<li><strong>수정 사항</strong>:<ul>
<li><strong>세미콜론</strong>이 추가됨.</li>
<li><strong>들여쓰기</strong>가 4칸에서 2칸으로 변경됨.</li>
<li><strong>문자열</strong>이 더블 쿼트에서 싱글 쿼트로 변경됨.</li>
</ul>
</li>
</ul>
<blockquote>
<p>이제 뭔가 느낌이 오시죠? 많이 쓰이는 플러그인 <strong>Prettier</strong>와 비슷한 느낌이 있습니다.</p>
</blockquote>
<h3 id="4-협업에-준비된-개발자로서의-필수-요소">4. <strong>협업에 준비된 개발자로서의 필수 요소</strong></h3>
<p>함께 개발할 준비가된 개발자라면 <code>.eslintrc.json</code> 파일의 중요성을 이해하고 프로젝트에서 이를 적극적으로 사용해야 합니다! <em>내가 만든 음식이 아무리 맛있어도 플레이팅이 개판이면 내 정성을 몰라주는건 당연합니다.</em> </p>
<hr>
<h2 id="기술-면접에서-나올-수-있는-질문들"><strong>기술 면접에서 나올 수 있는 질문들</strong></h2>
<p>기술 면접에서 ESLint와 <code>.eslintrc.json</code> 설정 파일에 대해 질문이 자주 나온다고 합니다(제가 이 글을 쓰게된 이유입니다). 면접관은 당신이 얼마나 협업을 고려한 개발을 하고 있는지, 코드 품질 관리에 신경을 쓰고 있는지를 확인하려 할 것입니다. =&gt; <strong>실력만큼 협업할 준비가 되었는지에 대한 역량도 당연히 중요하겠죠?</strong></p>
<h3 id="1-eslint란-무엇인가요">1. <strong>ESLint란 무엇인가요?</strong></h3>
<ul>
<li>ESLint는 JavaScript 코드의 품질을 분석하고 오류를 찾아내는 도구입니다. 코드 스타일을 통일하고 잠재적인 오류를 사전에 방지하기 위해 사용됩니다.
<em>(여기서 만약 &quot;ESLint는 ES(Ecma Script)와 Lint를 합친 것으로, (Ecma라는 기구에서 만든 Script가 표준 Javascript이기 때문에) 자바스크립트 코드의 에러를 표시해 줍니다. 아, Lint는 Linter의 약자로 에러가 있는 코드에 표시를 달아주는것을 뜻합니다.&quot; 까지 말한다면 바라보는 눈빛이 달라지겠네요.)</em></li>
</ul>
<h3 id="2-프로젝트에서-eslintrcjson-파일을-사용하는-이유는-무엇인가요">2. <strong>프로젝트에서 <code>.eslintrc.json</code> 파일을 사용하는 이유는 무엇인가요?</strong></h3>
<ul>
<li><code>.eslintrc.json</code> 파일은 프로젝트의 코드 스타일 규칙과 오류 탐지 규칙을 설정하는 곳입니다. 이를 통해 팀원들이 일관된 코드 스타일을 유지하고, 코드에서 발생할 수 있는 잠재적 오류를 미리 잡아낼 수 있습니다.</li>
</ul>
<h3 id="3-eslint와-prettier의-차이점은-무엇인가요">3. <strong>ESLint와 Prettier의 차이점은 무엇인가요?</strong></h3>
<ul>
<li>ESLint는 주로 코드의 <strong>품질과 오류를 검사</strong>하는 도구이며, Prettier는 코드의 <strong>포매팅(형식화)</strong>을 위한 도구입니다. 두 도구는 서로 보완적으로 사용될 수 있습니다. ESLint는 예를 들어 변수를 사용하지 않는 것 같은 논리적 오류를 찾아내고, Prettier는 코드의 들여쓰기나 세미콜론 위치 같은 포매팅을 자동화합니다.</li>
</ul>
<h3 id="4-eslint-설정을-어떻게-관리하나요">4. <strong>ESLint 설정을 어떻게 관리하나요?</strong></h3>
<ul>
<li>일반적으로 <code>.eslintrc.json</code> 파일을 루트 디렉토리에 두고, 프로젝트 전반에 걸친 코드 스타일과 규칙을 정의합니다. 추가로 프로젝트의 상황에 따라 <code>eslint-plugin-react</code>, <code>eslint-plugin-import</code>와 같은 플러그인들을 사용하여 더 구체적인 규칙을 설정할 수 있습니다.</li>
</ul>
<h3 id="5-eslint를-cicd-파이프라인에-통합할-수-있나요">5. <strong>ESLint를 CI/CD 파이프라인에 통합할 수 있나요?</strong></h3>
<ul>
<li>네, ESLint를 CI/CD 파이프라인에 통합하면 자동으로 코드 품질을 체크할 수 있습니다. 코드를 푸시하거나 풀 리퀘스트를 생성할 때 자동으로 ESLint 규칙이 적용되어 코드 품질을 보장할 수 있습니다.</li>
</ul>
<h2 id="결론"><strong>결론</strong></h2>
<blockquote>
<p>협업할 준비가 되어있는 프론트엔드 개발자라면 <strong>ESLint와 <code>.eslintrc.json</code> 파일</strong>은 필수 도구! </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[mockapi 사용법 with React-CSR(2024-2 OpenSourceStudio 수업 참고 자료)]]></title>
            <link>https://velog.io/@live_in_truth/mockapi-%EC%82%AC%EC%9A%A9%EB%B2%95-with-React-CSR2024-2-OpenSourceStudio-%EC%88%98%EC%97%85-%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C</link>
            <guid>https://velog.io/@live_in_truth/mockapi-%EC%82%AC%EC%9A%A9%EB%B2%95-with-React-CSR2024-2-OpenSourceStudio-%EC%88%98%EC%97%85-%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C</guid>
            <pubDate>Tue, 01 Oct 2024 20:07:27 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>_mockapi를 사용법에 포커스를 맞춘 오픈소스 스튜디오(Open Source Studio) 02분반 실습용 참고자료입니다. _</p>
</blockquote>
<h2 id="시작하기">시작하기</h2>
<blockquote>
</blockquote>
<p>무료버전 사용하시면 됩니다. 
<a href="https://mockapi.io/projects">클릭! =&gt; mockapi 사이트 접속</a>
<img src="https://velog.velcdn.com/images/live_in_truth/post/8e9666c9-52d3-4a8f-9fc6-a2e2b4d2538e/image.png" alt="">
&#39;Get started&#39; 버튼 눌러주세요.</p>
<blockquote>
</blockquote>
<p><strong>회원가입(저는 깃허브 sign in 했습니다.)</strong>
<img src="https://velog.velcdn.com/images/live_in_truth/post/ebfcc726-2e8c-4bec-a585-c2408dbeb7fb/image.png" alt=""></p>
<blockquote>
</blockquote>
<ul>
<li>로그인 후 프로젝트 폴더로 이동됩니다. 
<em>무료버전은 계정 당 프로젝트 1개까지 생성가능합니다.</em></li>
<li>알맞은 프로젝트 이름으로 하나 생성해주세요.
<em>(사진을 보시면 저는 OSS_Example로 미리 
만들었습니다.)</em></li>
<li>프로젝트 생성 후 클릭하여 이동해주세요
<img src="https://velog.velcdn.com/images/live_in_truth/post/09a5d839-1db5-4811-86a1-5d12dade9655/image.png" alt=""></li>
</ul>
<blockquote>
</blockquote>
<ul>
<li><p>보시면 자동으로 API 앤드포인트가 생성됩니다. </p>
</li>
<li><p>무료버전은 이 API 앤드포인트하나로 간단한 CRUD가 가능합니다.
<img src="https://velog.velcdn.com/images/live_in_truth/post/b6d8f095-e157-454c-87ef-cb3c35a35ce3/image.png" alt=""></p>
<h3 id="짚고-넘어가기미리-알아두면-좋습니다-귀찮으시면-넘어가셔도-문제는-없습니다">짚고 넘어가기(미리 알아두면 좋습니다. 귀찮으시면 넘어가셔도 문제는 없습니다.)</h3>
</li>
<li><p>저는 앤드포인트에서 &#39;api&#39;(보라색부분)을 prefix로 추가했습니다.</p>
</li>
<li><ul>
<li>엔드포인트에 <code>api</code>를 붙이는 이유는 <strong>사용자가 보는 웹페이지</strong>와 <strong>서버에 데이터를 요청하는 API</strong>를 쉽게 구분하려고 하기 위함입니다. 이렇게 하면 코드가 더 명확해지고, 어떤 주소가 API 요청인지 알기 쉬워집니다. </li>
</ul>
</li>
<li><ul>
<li><ul>
<li>예를 들어보겠습니다: 사용자가 글 목록을 보는 페이지 주소는 <code>handong.com/posts</code>라고 가정해봅시다.
그럼 당연히 서버에서 글 목록 데이터를 가져오는 API 주소도 필요합니다. 이때 <code>handong.com/api/posts</code>처럼 <code>api</code>를 붙이면 <strong>이 주소는 데이터를 가져오는 API</strong>임을 명확히 알 수 있습니다.
이렇게 하면:</li>
<li><em><code>example.com/posts</code>*</em>: 사용자에게 보여주는 웹페이지.</li>
<li><em><code>example.com/api/posts</code>*</em>: 서버에서 데이터를 받아오는 API.
이런 식으로 두 가지를 쉽게 구분할 수 있습니다.    </li>
</ul>
</li>
</ul>
<hr>
<h2 id="아주-간단하게-resourceentity-만들기">아주 간단하게 Resource(Entity) 만들기</h2>
<blockquote>
</blockquote>
<p>여기에서 resource는 Entity를 의미합니다.</p>
</li>
<li><p>엥? <code>Entity</code>가 뭐징?</p>
</li>
<li><ul>
<li><code>Entity</code>는 데이터베이스에서 객체지향적으로 <code>테이블</code>을 표현한 용어입니다.</li>
</ul>
</li>
<li><ul>
<li>자바에서 <code>Object</code>느낌입니다.</li>
</ul>
</li>
<li><ul>
<li>저는 게시판을 만들었기때문에 <code>Board</code>라는 이름으로 게시판 Entity를 생성했고, 그 안에는 <code>제목</code>, <code>내용</code>, <code>작성자</code>, <code>생성날짜</code>, <code>수정날짜</code> 등이 속성으로 들어갑니다.</li>
</ul>
</li>
</ul>
<blockquote>
</blockquote>
<ul>
<li>일단 new resouce 클릭
<img src="https://velog.velcdn.com/images/live_in_truth/post/b7558563-b9cd-4417-9471-f25c49c8f821/image.png" alt="">
<img src="https://velog.velcdn.com/images/live_in_truth/post/268ce9fb-e89b-491f-8c8d-00fbf4e3437b/image.png" alt=""></li>
<li><strong>Resource name 입력</strong>: 만들고자 하시는 <strong>직관적인</strong> 테이블 이름으로 지어주세요. <em>(영어로만 입력가능합니다.)</em></li>
<li><strong>Schema 생성:</strong>: 저는 게시판 엔티티를 만들고자 했기 때문에 사진과 같이 생성날짜, 수정날짜, 제목, 내용 등을 추가했습니다.</li>
<li><ul>
<li>여기에서 자동으로 있는 id는 pk로 사용되기 때문에 냅두시고 따로 pk추가 안하셔도 됩니다.</li>
</ul>
</li>
<li><ul>
<li>데이터 타입은 맨 오른쪽(날짜 =&gt; date.recent) 타입에서 만드시고자하는 속성에 맞는 타입 찾아서 선택하시면 됩니다.</li>
</ul>
</li>
<li><ul>
<li>이 이상 건들게 없습니다. 바로 Create 눌러주세요. </li>
</ul>
</li>
</ul>
<blockquote>
</blockquote>
<p><strong>이렇게 resource 생성되면 다 끝난겁니다.</strong>
<em>resource는 무료버전에서 최대 2개까지 생성가능합니다. 삭제하고 다시만들기 가능합니다.</em></p>
<ul>
<li>파란색 progress 바를 보시면 저는 28입니다. 이건 이 resource안에 데이터가 28개 들어있다는 의미입니다.</li>
<li>progress 바에 커서 올리시고 원하는 수치를 클릭하면 자동랜덤으로 데이터 생성됩니다. 만들어보시고 삭제도 해보세요.
<img src="https://velog.velcdn.com/images/live_in_truth/post/6d220280-360b-4969-bb81-66a0ac2c150a/image.png" alt="">
이제 이 api만 어디에 복사하시거나 창 열어두시고 개발준비 하시면 됩니다.
<img src="https://velog.velcdn.com/images/live_in_truth/post/701cfeb5-ddac-4eed-9cb2-ab0c22b33cb4/image.png" alt=""></li>
</ul>
<hr>
<h2 id="api사용해서-crud-테스트-해보기">api사용해서 crud 테스트 해보기</h2>
<blockquote>
<p>지금부터 아까만든 api사용법을 코드안에 주석으로 설명하겠습니다.
_이 글에서는 mockapi에서 생성한 api를 어떻게 쓰는지만 다루겠습니다. _</p>
</blockquote>
<h3 id="get">GET</h3>
<pre><code class="language-jsx">const Home = () =&gt; {
  const [posts, setPosts] = useState([]);
  const [openUpdateModal, setOpenUpdateModal] = useState(false);
  const [openCreateModal, setOpenCreateModal] = useState(false);
  const [selectedPost, setSelectedPost] = useState(null);

  const fetchData = async () =&gt; {
    // 일단 이 부분만 보시면 됩니다.
    const response = await axios.get(
      // http method로 GET을 사용하고 
      // 아까 복사하신 &#39;api + 만드신 resource 이름&#39; 넣으시면 됩니다.
      &quot;https://66fa7fb3afc569e13a9bfcce.mockapi.io/api/BoardEntity&quot;
    );
    setPosts(response.data);
  };
  ...</code></pre>
<blockquote>
<p><img src="https://velog.velcdn.com/images/live_in_truth/post/1b3acc40-1921-42d0-9272-efaf61ea2452/image.png" alt=""></p>
</blockquote>
<ul>
<li>여기에서 <code>:endpoint</code> 를 <code>만드신 리소스 명</code>으로 넣어주시면 됩니다. </li>
<li>코드보시면 저는 리소스이름이 <code>BoardEntity</code>라서 <code>https://66fa7fb3afc569e13a9bfcce.mockapi.io/api/BoardEntity</code>입니다.</li>
</ul>
<hr>
<h3 id="postcreate">POST(Create)</h3>
<pre><code class="language-jsx">  const handleCreate = async (values) =&gt; {
    try {
      // 여기를 보시면 됩니다.
      await axios.post(
        &quot;https://66fa7fb3afc569e13a9bfcce.mockapi.io/api/BoardEntity&quot;,
        {
          ...values,
          createdAt: new Date().toISOString(),
          modifiedAt: new Date().toISOString(),
        }
      );
      form.resetFields();
      onClose();
    } catch (error) {
      console.error(&quot;글 작성 중 오류 발생:&quot;, error);
    }
  };</code></pre>
<blockquote>
<ul>
<li>post는 api url이 get과 동일하고 http method를 get -&gt; post로 바꾸고 body만 추가하면 됩니다.</li>
</ul>
</blockquote>
<hr>
<h3 id="updatemockapi-사용시-patch말고-put을-사용하셔야합니다">UPDATE(mockapi 사용시 patch말고 put을 사용하셔야합니다.)</h3>
<pre><code class="language-jsx">  const handleUpdate = async () =&gt; {
    try {
      const values = await form.validateFields();
      // 여기를 보시면 됩니다.
      await axios.put(
        `https://66fa7fb3afc569e13a9bfcce.mockapi.io/api/BoardEntity/${board.id}`,
        {
          ...values,
          modifiedAt: new Date().toISOString(),
        }
      );
      form.resetFields();
      onClose();
    } catch (error) {
      console.error(&quot;글 수정 중 오류 발생:&quot;, error);
    }
  };</code></pre>
<blockquote>
<ul>
<li>다를거 없습니다. 아까 pk로 자동생성된다던 id를 앤드포인트 끝에 넣어주시면 해당 아이디의 글이 수정요청됩니다.</li>
</ul>
</blockquote>
<hr>
<h3 id="delete">DELETE</h3>
<pre><code class="language-jsx">  const handleDeletePost = async (postId) =&gt; {
    try {
      // 여기를 보시면 됩니다.
      await axios.delete(
        `https://66fa7fb3afc569e13a9bfcce.mockapi.io/api/BoardEntity/${postId}`
      );
      fetchData();
    } catch (error) {
      console.error(&quot;글 삭제 중 오류 발생:&quot;, error);
    }
  };</code></pre>
<blockquote>
<ul>
<li>http method를 delete로 하시고 update처럼 id를 앤드포인트 끝에 넣어주시면 해당 아이디의 글이 삭제요청됩니다.</li>
</ul>
</blockquote>
<hr>
<p><a href="https://github.com/parkkr-js/oss-crud-example">깃허브 repo 이동</a>
<a href="https://oss-crud-example.vercel.app/">demo사이트 이동</a></p>
<p>배포된 사이트와 GitHub 저장소를 꼭 참고해주시기 바랍니다. 이 프로젝트는 <strong>MockAPI 생성 및 간단한 사용법</strong>을 시연하는 데 목적이 있기 때문에, 컴포넌트를 세부적으로 나누지 않고 단순하게 작성했습니다. 따라서, 이 코드 자체는 최적화된 예제는 아니며, <strong>API 사용법</strong>을 중심으로 참고해 주시면 감사하겠습니다.</p>
<p>GitHub보시고 <strong>React</strong> 관련 세부 사항이나 궁금한 점이 있으시면, 언제든지 질문해 주세요. 수업 시간이나 <strong>TA 세션</strong>외에도 메일주시면 답변드리겠습니다.</p>
<p><em>글 좋아요 및 팔로우 해주시면 복 받으실겁니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2.2 The Web and HTTP]]></title>
            <link>https://velog.io/@live_in_truth/2.2-The-Web-and-HTTP</link>
            <guid>https://velog.io/@live_in_truth/2.2-The-Web-and-HTTP</guid>
            <pubDate>Sun, 22 Sep 2024 09:37:51 GMT</pubDate>
            <description><![CDATA[<p><strong><em>&gt; (James F. Kurose, Keith Ross - Computer Networking- A Top Down Approach-Pearson (2020) 교과서 참고)</em></strong></p>
<h2 id="221-overview-of-http">2.2.1 Overview of HTTP</h2>
<p>HTTP(HyperText Transfer Protocol)은 웹의 핵심이 되는 애플리케이션 계층 프로토콜이다. </p>
<hr>
<h4 id="왜-hypertext일까">왜 HyperText일까?</h4>
<p>HyperText: HTTP는 HyperText를 전송하기 위해 만들어진 프로토콜이이다.</p>
<blockquote>
<p>HyperText는 단순한 텍스트가 아니라, 링크를 통해 다른 문서나 리소스로 쉽게 이동할 수 있는 텍스트를 말한다. </p>
</blockquote>
<hr>
<p>클라이언트 프로그램과 서버 프로그램은 HTTP 메시지를 서로 교환하는 방식으로 동작한다. 여기서 클라이언트는 웹 브라우저(예: 크롬, 인터넷 익스플로러)이고, 서버는 웹 서버(예: 아파치, 마이크로소프트 IIS)이다.</p>
<blockquote>
<p>웹 페이지는 여러 개의 객체들로 구성된다. </p>
</blockquote>
<p>객체는 HTML 파일, 이미지 파일(JPEG), 자바스크립트 파일, CSS 파일 등과 같이 하나의 URL로 접근할 수 있는 모든 파일이다.
일반적으로 웹 페이지는 하나의 기본 HTML 파일과 그 안에 참조된 여러 객체들로 이뤄져 있다. 예를 들어, 하나의 웹 페이지에 HTML 텍스트와 5개의 JPEG 이미지가 있다면, 총 6개의 객체를 가진 것이다.</p>
<p>HTTP는 웹 클라이언트가 서버에 웹 페이지를 요청하고 서버가 그 요청에 응답하는 방식을 정해준다.
<img src="https://velog.velcdn.com/images/live_in_truth/post/f87ae4d6-6ff3-4749-a127-7f72e12a5eed/image.png" alt="">
Figure 2.6을 보면, 클라이언트(PC나 스마트폰)가 서버에 HTTP 요청을 보내고, 서버는 이에 대해 HTTP 응답을 보내는 과정이 나타나 있다. </p>
<blockquote>
<p>이때, HTTP는 전송 계층 프로토콜로 TCP를 사용한다.</p>
</blockquote>
<p><strong>클라이언트와 서버 간에 TCP 연결이 먼저 이루어지고</strong>, 그 위에서 HTTP 요청과 응답이 오간다.</p>
<blockquote>
<p>중요한 점은 HTTP는 &#39;무상태 프로토콜(stateless)&#39;이라는 것이다.</p>
</blockquote>
<p>서버는 클라이언트에 대한 정보를 저장하지 않는다. 
예를 들어, 클라이언트가 같은 객체를 몇 초 간격으로 두 번 요청하더라도, 서버는 이전 요청을 기억하지 않고 동일한 객체를 다시 전송한다. </p>
<p>HTTP에는 여러 버전이 있는데, 초기 버전인 HTTP/1.0은 1990년대에 도입되었다. 현재는 HTTP/1.1이 주로 사용되지만, 최근에는 HTTP/2도 많이 도입되고 있다.</p>
<hr>
<h2 id="222-non-persistent-and-persistent-connections">2.2.2 Non-Persistent and Persistent Connections</h2>
<p>많은 인터넷 애플리케이션에서 클라이언트와 서버는 오랜 기간 동안 통신하며, 클라이언트가 일련의 요청을 보내고 서버가 각 요청에 응답하는 경우가 많다. 애플리케이션과 그 사용 방식에 따라, 이 일련의 요청들은 연달아, 주기적으로, 또는 간헐적으로 이루어질 수 있다. 이러한 클라이언트-서버 상호 작용이 TCP를 통해 이루어질 때, 애플리케이션 개발자는 중요한 결정을 내려야 한다. </p>
<blockquote>
<p>각 요청/응답 쌍을 별도의 TCP 연결로 보낼 것인가, 아니면 모든 요청과 해당 응답들을 동일한 TCP 연결로 보낼 것인가?</p>
</blockquote>
<p>전자의 경우, 애플리케이션은 비지속 연결을 사용한다고 하며, 후자의 경우는 지속 연결을 사용한다고 한다. 이 설계 문제를 깊이 이해하기 위해, 비지속 연결과 지속 연결의 장단점을 HTTP라는 특정 애플리케이션을 통해 살펴보자. HTTP는 비지속 연결과 지속 연결 모두를 사용할 수 있다. 기본 모드에서는 지속 연결을 사용하지만, HTTP 클라이언트와 서버는 비지속 연결을 사용하도록 구성될 수 있다.</p>
<h3 id="비지속-연결을-사용하는-http"><strong>비지속 연결을 사용하는 HTTP</strong></h3>
<p>비지속 연결을 사용하는 경우 서버에서 클라이언트로 웹 페이지를 전송하는 과정을 단계별로 살펴보자. 여기서는 페이지가 기본 HTML 파일과 10개의 JPEG 이미지로 구성되어 있으며, 이 11개의 객체가 모두 동일한 서버에 있다고 가정한다. 또한, 기본 HTML 파일의 URL은 </p>
<p><a href="http://www.someSchool.edu/someDepartment/home.index">http://www.someSchool.edu/someDepartment/home.index</a></p>
<p>라고 가정해보자. 이때 일어나는 과정은 다음과 같다.</p>
<ol>
<li><p>HTTP 클라이언트 프로세스는 서버 <code>www.someSchool.edu</code>의 80번 포트로 TCP 연결을 시작한다. 이 TCP 연결과 관련된 소켓이 클라이언트와 서버에 각각 생성된다.</p>
</li>
<li><p>HTTP 클라이언트는 이 소켓을 통해 서버로 HTTP 요청 메시지를 보낸다. 요청 메시지에는 경로 이름 <code>/someDepartment/home.index</code>가 포함된다. </p>
</li>
<li><p>HTTP 서버 프로세스는 이 소켓을 통해 요청 메시지를 수신하고, 스토리지(RAM 또는 디스크)에서 <code>/someDepartment/home.index</code> 객체를 가져와 HTTP 응답 메시지에 캡슐화한다. 그런 다음 이 응답 메시지를 소켓을 통해 클라이언트로 전송한다.</p>
</li>
<li><p>HTTP 서버 프로세스는 TCP에 연결을 닫으라고 알린다.</p>
<blockquote>
<p>하지만 TCP는 클라이언트가 응답 메시지를 정확히 수신했는지 확신할 때까지 실제로 연결을 종료하지 않는다.</p>
</blockquote>
</li>
<li><p>HTTP 클라이언트는 응답 메시지를 수신한다. <strong>이때 TCP 연결이 종료된다.</strong> 메시지에는 캡슐화된 객체가 HTML 파일이라는 내용이 포함되어 있다. 클라이언트는 응답 메시지에서 파일을 추출하고, HTML 파일을 분석하여 10개의 JPEG 객체에 대한 참조를 찾는다.</p>
</li>
<li><p>앞의 1~4단계를 참조된 각 JPEG 객체에 대해 반복한다.</p>
</li>
</ol>
<p>위의 과정에서 브라우저는 웹 페이지를 수신하면서 이를 사용자에게 보여준다.</p>
<p>위 단계들은 비지속 연결을 사용한 예를 보여준다. </p>
<blockquote>
<p>여기서 각 TCP 연결은 서버가 객체를 전송한 후에는 다른 객체를 위해 유지되지 않는다.</p>
</blockquote>
<p>HTTP/1.0은 비지속 TCP 연결을 사용한다. 각 비지속 TCP 연결은 정확히 하나의 요청 메시지와 하나의 응답 메시지를 전송한다. 따라서 이 예에서 사용자가 웹 페이지를 요청할 때 총 11개의 TCP 연결이 생성된다.</p>
<h4 id="소요-시간-계산"><strong>소요 시간 계산</strong></h4>
<p>이제 간단한 계산을 통해 클라이언트가 기본 HTML 파일을 요청하고 전체 파일을 수신하기까지 걸리는 시간을 추정해보자. 이를 위해 우리는 <strong>RTT(Round-Trip Time)</strong>를 정의한다. </p>
<blockquote>
<p>RTT는 작은 패킷이 클라이언트에서 서버로 이동한 다음 다시 클라이언트로 돌아오는 데 걸리는 시간이다. </p>
</blockquote>
<p>RTT에는 패킷 전파 지연, 중간 라우터와 스위치에서의 패킷 대기 지연, 그리고 패킷 처리 지연이 포함된다. (이러한 지연에 대해서는 이전 글을 참고하자.)</p>
<p><img src="https://velog.velcdn.com/images/live_in_truth/post/fe6a05fa-1805-4cfd-8d8d-461e31a060ef/image.png" alt=""></p>
<p>사용자가 하이퍼링크를 클릭하면 그림 2.7과 같이 브라우저가 브라우저와 웹 서버 간에 TCP 연결을 시작한다. 이때 &quot;three-way handshake&quot;가 필요하다. 먼저 클라이언트가 작은 TCP 세그먼트를 서버로 보내고, 서버는 이를 확인하여 작은 TCP 세그먼트로 응답하며, 마지막으로 클라이언트가 서버에 다시 확인 응답을 보낸다.</p>
<blockquote>
<p>이 three-way handshake의 처음 두 부분은 한 번의 RTT를 소요한다.</p>
</blockquote>
<hr>
<blockquote>
<p>왜 three-way handshake라고 명명했을까: 
three-way handshake는 클라이언트와 서버가 <strong>TCP 연결을 설정하는 과정</strong>에서 <strong>3번의 메시지 교환</strong>이 이루어지기 때문에 이런 이름이 붙었다.
간단히 이 3단계 과정을 살펴보면 다음과 같다.</p>
</blockquote>
<blockquote>
<blockquote>
<ol>
<li><strong>SYN (Synchronize) - 첫 번째 메시지:</strong> 클라이언트가 서버에 연결을 요청하는 메시지(SYN 패킷)를 보냄.</li>
<li><strong>SYN-ACK (Synchronize-Acknowledge) - 두 번째 메시지:</strong> 서버가 요청을 수락하고, 연결을 설정할 준비가 되었음을 알리는 메시지(SYN-ACK 패킷)를 클라이언트에게 응답함.</li>
<li><strong>ACK (Acknowledge) - 세 번째 메시지:</strong> 클라이언트가 서버의 응답을 확인하고, 연결이 설정되었음을 알리는 메시지(ACK 패킷)를 서버에 다시 보냄.</li>
</ol>
</blockquote>
</blockquote>
<p>이처럼 연결을 설정하는 데 <strong>3번의 단계</strong>를 거치므로 <strong>3-방향 핸드셰이크(three-way handshake)</strong>라고 부르는 것이다. 이 과정을 통해 클라이언트와 서버는 서로의 존재를 확인하고 데이터 전송을 위한 안정적인 경로를 만들 수 있다.</p>
<hr>
<p>three-way handshake의 처음 두 부분이 완료된 후, 클라이언트는 TCP 연결에 HTTP 요청 메시지와 three-way handshake의 세 번째 부분(확인 응답)을 함께 보낸다. 요청 메시지가 서버에 도착하면, 서버는 HTML 파일을 TCP 연결로 보낸다. 이 HTTP 요청/응답 과정은 또 다른 RTT를 소요한다.</p>
<blockquote>
<p>따라서 대략적인 총 응답 시간은 <strong>2 RTT + 서버의 HTML 파일 전송 시간</strong>이 된다.</p>
</blockquote>
<h3 id="지속-연결을-사용하는-http"><strong>지속 연결을 사용하는 HTTP</strong></h3>
<p>비지속 연결에는 몇 가지 단점이 있다. </p>
<blockquote>
<p>첫째, 각 요청된 객체마다 새로운 연결이 생성되고 유지되어야 한다. </p>
</blockquote>
<p>이러한 각 연결에 대해 TCP 버퍼를 할당하고, 클라이언트와 서버 모두에서 TCP 변수를 유지해야 한다. 이는 동시에 수백 개의 다른 클라이언트로부터 요청을 처리할 수 있는 웹 서버에 상당한 부담을 줄 수 있다. </p>
<blockquote>
<p>둘째, 앞에서 설명한 것처럼 각 객체는 두 번의 RTT 지연을 겪게 된다. </p>
</blockquote>
<p>첫 번째 RTT는 TCP 연결을 설정하는 데, 두 번째 RTT는 객체를 요청하고 수신하는 데 사용된다.</p>
<p><strong>HTTP/1.1의 지속 연결</strong>에서는 서버가 응답을 보낸 후에도 TCP 연결을 열어 둔다. 이후의 요청과 응답은 동일한 연결을 통해 이루어질 수 있다. 특히, 전체 웹 페이지(위 예에서는 기본 HTML 파일과 10개의 이미지)는 하나의 지속 TCP 연결을 통해 전송될 수 있다. 또한 동일한 서버에 있는 여러 웹 페이지도 동일한 클라이언트와의 하나의 지속 연결을 통해 전송될 수 있다. 이러한 객체에 대한 요청은 응답을 기다리지 않고 연속적으로(파이프라이닝) 이루어질 수 있다. 일반적으로 HTTP 서버는 일정 시간 동안 사용되지 않을 때(구성 가능한 타임아웃 간격) 연결을 닫는다. 서버가 연속적인 요청을 받으면 객체를 연속적으로 전송한다. HTTP의 기본 모드는 파이프라이닝을 사용하는 지속 연결이다.</p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript의 Branded Types으로 런타임 유형 안전성 개선하기]]></title>
            <link>https://velog.io/@live_in_truth/TypeScript%EC%9D%98-Branded-Types%EC%9C%BC%EB%A1%9C-%EB%9F%B0%ED%83%80%EC%9E%84-%EC%9C%A0%ED%98%95-%EC%95%88%EC%A0%84%EC%84%B1-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@live_in_truth/TypeScript%EC%9D%98-Branded-Types%EC%9C%BC%EB%A1%9C-%EB%9F%B0%ED%83%80%EC%9E%84-%EC%9C%A0%ED%98%95-%EC%95%88%EC%A0%84%EC%84%B1-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 17 Sep 2024 09:27:54 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/live_in_truth/post/6d2c6e7c-fa44-45bf-a6c6-164be1137fff/image.png" alt=""></p>
<blockquote>
<p><em>원문 작성자: Matías Hernández, 참고 링크: <a href="https://egghead.io/blog/using-branded-types-in-typescript">Improve Runtime Type Safety with Branded Types in TypeScript</a></em></p>
</blockquote>
<blockquote>
<p>코드의 안전성과 신뢰성을 높이기 위해 타입스크립트를 사용한다는 것은 이미 잘 알려진 사실이다. 하지만 인생이 다 그렇듯 만능과 완벽은 존재하지 않는다. 
특히 런타임 에러를 막기 위해서는 더 정교한 타입 시스템이 필요할 수 있다. 이때 <strong>브랜디드 타입(Branded Types)</strong>이 도움을 줄 수 있다. </p>
</blockquote>
<blockquote>
<p>이번 글에서는 브랜디드 타입(Branded Types)이 무엇인지, 어떻게 사용하는지, 그리고 어떤 장점이 있는지 살펴보겠다.</p>
</blockquote>
<hr>
<h2 id="런타임과-빌드타임-타입스크립트의-한계-이해하기">런타임과 빌드타임: 타입스크립트의 한계 이해하기</h2>
<blockquote>
<p><em>이 부분 알면 넘어가시고 모르시면 꼭 보시고 기본으로 깔고 가셔야합니다.</em></p>
</blockquote>
<blockquote>
<ul>
<li><strong>런타임(Runtime)</strong>: 코드가 실제로 실행되는 시점. 런타임에 발생하는 에러는 코드가 실행되는 도중에 감지되므로, 문제 해결이 까다롭고 실행 중에 예기치 않은 동작을 유발할 수 있다.</li>
</ul>
</blockquote>
<ul>
<li><strong>빌드타임(Build Time)</strong>: 코드를 작성하고 컴파일하는 시점으로,** 타입스크립트는 이 단계에서 타입 검사를 수행한다.** 
잘못된 타입 사용이나 타입 불일치를 컴파일 타임에 미리 감지해줌으로써 런타임 에러를 줄일 수 있다.</li>
</ul>
<blockquote>
<p>타입스크립트는 주로 빌드타임에 타입 검사를 통해 코드를 검증하고, 안전성을 높인다. </p>
</blockquote>
<blockquote>
<p>그러나!!!!!! 타입스크립트의 기본 타입만으로는 런타임에 발생할 수 있는 모든 오류를 방지하기에는 부족할 때가 있다. 
<strong>여기서 우리는 브랜디드 타입이 등장하게 된 배경을 알 수 있다.</strong></p>
</blockquote>
<hr>
<h2 id="타입스크립트에서-브랜디드-타입이-필요한-이유">타입스크립트에서 브랜디드 타입이 필요한 이유</h2>
<blockquote>
<p>타입스크립트는 빌드타임에 타입 검사를 통해 데이터가 올바르게 전달되는지 검증한다. 
그러나 데이터의 <strong>구체성</strong>이나 <strong>특수성</strong>이 충분히 표현되지 않는 경우가 종종 발생한다. 
예를 들어, 사용자, 게시물, 댓글을 다루는 애플리케이션을 만든다고 가정해보자.</p>
</blockquote>
<pre><code class="language-typescript">type User = {
  id: string;
  name: string;
}

type Post = {
  id: string;
  ownerId: string;
  comments: Comment[];
}

type Comment = {
  id: string;
  timestamp: string;
  body: string;
  authorId: string;
}</code></pre>
<blockquote>
<p>위 코드를 보면 <code>User</code>, <code>Post</code>, <code>Comment</code>는 모두 <code>id</code> 속성을 가지고 있다. 
그러나 이 속성들은 모두 단순히 <code>string</code> 타입이기 때문에, 타입스크립트 입장에서는 이 <code>id</code>들이 서로 구분되지 않는다.</p>
</blockquote>
<blockquote>
<p>즉, 아래와 같은 코드에서도 에러를 감지하지 못한다.</p>
</blockquote>
<pre><code class="language-typescript">async function getCommentsForPost(postId: string, authorId: string) {
  const response = await api.get(`/author/${authorId}/posts/${postId}/comments`);
  return response.data;
}

const comments = await getCommentsForPost(user.id, post.id);  // 타입스크립트는 에러를 인식하지 못함</code></pre>
<blockquote>
<p>위 코드에서는 <code>getCommentsForPost</code> 함수를 호출할 때 매개변수의 순서가 잘못되었다. 
그러나 타입스크립트는 <code>user.id</code>와 <code>post.id</code>가 모두 <code>string</code> 타입이므로 문제를 인식하지 못한다. 
이 때문에 <strong>런타임</strong>에 잘못된 응답을 받게 되고, 디버깅이 어려워진다.</p>
</blockquote>
<blockquote>
<p><strong>타입스크립트가 더욱 정교한 타입 안전성을 제공하기 위해 탄생한 것이 바로 &quot;브랜디드 타입&quot;이다.</strong></p>
</blockquote>
<hr>
<h2 id="브랜디드-타입branded-types이란">브랜디드 타입(Branded Types)이란?</h2>
<blockquote>
<p>브랜디드 타입은 기존 타입에 <strong>특정한 태그(brand)를 부여하여</strong> 더 구체적이고 유일한 타입을 만드는 방법이다. 
이렇게 하면 단순한 기본 타입보다 더 명확하고 안전하게 데이터를 모델링할 수 있다. </p>
</blockquote>
<h3 id="간단한-브랜디드-타입-구현-예시">간단한 브랜디드 타입 구현 예시</h3>
<pre><code class="language-typescript">type Brand&lt;K, T&gt; = K &amp; { __brand: T };
type UserID = Brand&lt;string, &quot;UserId&quot;&gt;;
type PostID = Brand&lt;string, &quot;PostId&quot;&gt;;</code></pre>
<blockquote>
<p>위 코드는 <code>UserID</code>와 <code>PostID</code>라는 두 개의 새로운 타입을 만들어낸다. <code>__brand</code> 속성으로 고유성을 부여하여 타입을 더욱 세밀하게 구분할 수 있다. </p>
</blockquote>
<blockquote>
<p>이제 <code>UserID</code>와 <code>PostID</code>는 단순한 <code>string</code>이 아닌 고유한 타입이 된다. 이를 활용하면 잘못된 데이터가 전달될 가능성을 줄일 수 있다.</p>
</blockquote>
<hr>
<h3 id="개선된-예시">개선된 예시</h3>
<pre><code class="language-typescript">type UserID = Brand&lt;string, &quot;UserId&quot;&gt;;
type PostID = Brand&lt;string, &quot;PostId&quot;&gt;;

type User = {
  id: UserID;
  name: string;
}

type Post = {
  id: PostID;
  ownerId: UserID;
  comments: Comment[];
}

async function getCommentsForPost(postId: PostID, authorId: UserID) {
  const response = await api.get(`/author/${authorId}/posts/${postId}/comments`);
  return response.data;
}

const comments = await getCommentsForPost(user.id, post.id);  // ❌ 타입 오류 발생</code></pre>
<blockquote>
<p>이제 <code>user.id</code>와 <code>post.id</code>가 각각 <code>UserID</code>와 <code>PostID</code> 타입을 가지므로, 잘못된 인자를 전달할 경우 타입스크립트가 이를 감지할 수 있다. 
이로써 컴파일 타임에 잘못된 타입 사용을 미리 방지할 수 있다.</p>
</blockquote>
<hr>
<h2 id="브랜디드-타입의-한계와-개선된-구현중요">브랜디드 타입의 한계와 개선된 구현(중요)</h2>
<blockquote>
<p>위 방법은 간단하고 유용하지만 몇 가지 문제점이 있다:</p>
</blockquote>
<ol>
<li><code>__brand</code> 속성은 빌드타임에만 존재하며, 런타임에는 사라진다.</li>
<li><code>__brand</code> 속성이 코드 자동 완성(IntelliSense)에 노출되어, 개발자가 오용할 수 있다.</li>
<li>단순한 문자열 기반 태깅은 안전하지 않으며, 중복된 타입을 만들 수 있다.</li>
</ol>
<h3 id="뭐라는거지-이게-왜-문제라는거지-싶으신-저같은-분들을-위한-쉬운-설명">뭐라는거지? 이게 왜 문제라는거지? 싶으신 저같은 분들을 위한 쉬운 설명</h3>
<blockquote>
<h3 id="1-__brand-속성은-빌드타임에만-존재하며-런타임에는-사라진다">1. <code>__brand</code> 속성은 빌드타임에만 존재하며, 런타임에는 사라진다.</h3>
<blockquote>
<ul>
<li>타입스크립트는 <strong>컴파일 타임</strong>에만 타입을 체크하고, 그 결과물을 <strong>런타임</strong>에 사용할 자바스크립트 코드로 변환한다. </li>
</ul>
</blockquote>
</blockquote>
<ul>
<li><code>type Brand&lt;K, T&gt; = K &amp; { __brand: T }</code> 같은 브랜디드 타입은 <strong>타입스크립트가 컴파일 중에만 확인</strong>하고, <strong>실제로 자바스크립트 코드로 변환된 후에는 사라진다</strong>. 즉, <strong>런타임에는 <code>__brand</code> 속성이 존재하지 않게 된다.</strong></li>
</ul>
<blockquote>
<blockquote>
<h4 id="왜-문제가-될까">왜 문제가 될까?</h4>
</blockquote>
</blockquote>
<ul>
<li>브랜디드 타입은 런타임에 타입의 고유성을 보장하는 것이 아니라, <strong>컴파일 시점에만 타입 검사를 위해 존재</strong>한다. 따라서 컴파일을 거친 이후 실제 실행 중에는 <code>__brand</code>가 사라지기 때문에, 런타임에 이 타입을 검사할 수 없다.</li>
<li>즉, 타입 안정성을 보장하기 위해 브랜디드 타입을 사용하지만, 런타임에는 사라져버리기 때문에 컴파일 타임에서만 안전성을 확보할 수 있다는 한계가 있다.</li>
</ul>
<blockquote>
<h3 id="2-__brand-속성이-코드-자동-완성intellisense에-노출되어-개발자가-오용할-수-있다">2. <code>__brand</code> 속성이 코드 자동 완성(IntelliSense)에 노출되어, 개발자가 오용할 수 있다.</h3>
<blockquote>
<ul>
<li><strong>IntelliSense</strong>는 개발자가 코드 작성 시 자동 완성 기능을 제공하는 툴. </li>
</ul>
</blockquote>
</blockquote>
<ul>
<li><code>__brand</code>라는 속성은 브랜디드 타입을 만들기 위해 우리가 <strong>태그</strong>로 사용한 속성이다. 
하지만 이 속성은 개발자가 직접 조작할 의도로 만든 것이 아니다. </li>
<li>문제는 <code>__brand</code>가 자동 완성 기능(IntelliSense)에 노출된다는 것이다. 
개발자가 코드 작성 중에 이 속성을 볼 수 있고, 오용할 가능성이 생긴다.</li>
</ul>
<blockquote>
<blockquote>
<h4 id="예를-들어">예를 들어:</h4>
</blockquote>
</blockquote>
<pre><code class="language-typescript">type UserId = Brand&lt;string, &quot;UserId&quot;&gt;;

const userId: UserId = &quot;12345&quot; as UserId;

// IntelliSense 자동 완성 기능에서 `userId.__brand`를 볼 수 있게 된다.</code></pre>
<blockquote>
<blockquote>
<ul>
<li>자동 완성 기능에서 <code>__brand</code> 속성이 노출되면, 개발자가 의도치 않게 <code>__brand</code> 속성을 참조하거나 조작할 수 있다. 이는 타입 안전성을 깨뜨릴 수 있는 잠재적인 문제이다.</li>
</ul>
</blockquote>
</blockquote>
<blockquote>
<h3 id="3-단순한-문자열-기반-태깅은-안전하지-않으며-중복된-타입을-만들-수-있다">3. 단순한 문자열 기반 태깅은 안전하지 않으며, 중복된 타입을 만들 수 있다.</h3>
<blockquote>
<ul>
<li><code>type Brand&lt;K, T&gt; = K &amp; { __brand: T }</code>에서 <code>T</code>는 보통 <code>&quot;UserId&quot;</code>나 <code>&quot;Email&quot;</code> 같은 <strong>문자열</strong>로 사용된다. 
그러나 문자열 기반으로 태그를 붙이는 것은 안전하지 않을 수 있다. </li>
</ul>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<h4 id="왜-문제가-될까-1">왜 문제가 될까?</h4>
</blockquote>
</blockquote>
<ul>
<li>동일한 문자열 값을 사용하여 다른 브랜디드 타입을 만들게 되면 타입의 고유성이 사라지게 된다. 즉, 중복된 브랜디드 타입을 생성할 위험이 있다.</li>
</ul>
<blockquote>
<blockquote>
<h4 id="예시">예시:</h4>
</blockquote>
</blockquote>
<pre><code class="language-typescript">type UserId = Brand&lt;string, &quot;Id&quot;&gt;;
type ProductId = Brand&lt;number, &quot;Id&quot;&gt;;

const userId: UserId = &quot;12345&quot; as UserId;
const productId: ProductId = 67890 as ProductId;</code></pre>
<blockquote>
<blockquote>
<ul>
<li>위 예시에서 <code>&quot;Id&quot;</code>라는 동일한 문자열을 <strong>다른 두 타입</strong> (<code>UserId</code>, <code>ProductId</code>)에 태그로 사용했다. 이 경우, 타입스크립트는 <code>UserId</code>와 <code>ProductId</code>를 서로 구분하지 못할 수 있고, 의도치 않게 두 타입이 혼동될 수 있다.</li>
</ul>
</blockquote>
</blockquote>
<ul>
<li>따라서 단순히 문자열로 태깅하는 것만으로는 완벽한 안전성을 보장할 수 없다는 한계가 있다.</li>
</ul>
<blockquote>
<p>이 문제를 해결하기 위해 <strong><code>unique symbol</code></strong>을 사용한 개선된 브랜디드 타입 구현이 필요하다.</p>
</blockquote>
<hr>
<h3 id="개선된-브랜디드-타입-구현">개선된 브랜디드 타입 구현</h3>
<pre><code class="language-typescript">declare const __brand: unique symbol;

type Brand&lt;B&gt; = { [__brand]: B };
export type Branded&lt;T, B&gt; = T &amp; Brand&lt;B&gt;;</code></pre>
<blockquote>
<p>이제 <code>__brand</code>를 <strong><code>unique symbol</code></strong>로 선언함으로써 고유성을 보장한다. 이를 통해 더 이상 <code>__brand</code> 속성이 외부에 노출되지 않고, 같은 이름의 브랜드라도 고유한 심볼을 가지기 때문에 중복될 가능성이 없다.</p>
</blockquote>
<hr>
<h2 id="브랜디드-타입이-가져다주는-이점">브랜디드 타입이 가져다주는 이점</h2>
<blockquote>
<h3 id="1-명확성">1. 명확성</h3>
<p>브랜디드 타입을 사용하면 변수의 의도를 더 명확하게 표현할 수 있다. 예를 들어, <code>UserID</code>와 <code>PostID</code>가 단순한 문자열이 아닌 고유한 타입으로 정의되어 각 용도의 혼동을 방지할 수 있다.</p>
</blockquote>
<blockquote>
<h3 id="2-안전성과-정확성">2. 안전성과 정확성</h3>
<p>타입 간의 불일치를 더 쉽게 감지하고 런타임 오류를 줄일 수 있다. 잘못된 데이터가 전달될 경우 컴파일 타임에 에러를 발생시킨다.</p>
</blockquote>
<blockquote>
<h3 id="3-유지보수성">3. 유지보수성</h3>
<p>팀원들이 코드의 <strong>의도</strong>를 쉽게 이해할 수 있다. =&gt; 이게 정말 중요한 것 같다.</p>
</blockquote>
<hr>
<h2 id="브랜디드-타입의-활용-예시">브랜디드 타입의 활용 예시</h2>
<blockquote>
<h3 id="1-커스텀-유효성-검사">1. 커스텀 유효성 검사</h3>
<p>브랜디드 타입을 사용해 이메일 주소와 같은 사용자 입력을 검증할 수 있다.</p>
</blockquote>
<pre><code class="language-typescript">type EmailAddress = Brand&lt;string, &quot;EmailAddress&quot;&gt;;

function validEmail(email: string): EmailAddress {
  // 이메일 유효성 검사 로직
  return email as EmailAddress;
}</code></pre>
<hr>
<blockquote>
<h3 id="2-도메인-모델링">2. 도메인 모델링</h3>
<p>특정 도메인을 구체적으로 표현할 때 유용하다.
예를 들어, 자동차 제조 라인에서 다양한 속성을 안전하게 관리할 수 있다.</p>
</blockquote>
<pre><code class="language-typescript">type CarBrand = Brand&lt;string, &quot;CarBrand&quot;&gt;;
type EngineType = Brand&lt;string, &quot;EngineType&quot;&gt;;</code></pre>
<hr>
<blockquote>
<h3 id="3-api-응답-및-요청">3. API 응답 및 요청</h3>
<p>API 호출에서 성공 및 실패 응답을 구분하여 타입 안정성을 높일 수 있다.</p>
</blockquote>
<pre><code class="language-typescript">type ApiSuccess&lt;T&gt; = T &amp; { __apiSuccessBrand: true };
type ApiFailure = {
  code: number;
  message: string;
  error: Error;
} &amp; { __apiFailureBrand: true };</code></pre>
<h2 id="결론">결론</h2>
<blockquote>
<p>브랜디드 타입은 타입스크립트의 타입 시스템을 한층 강화하여 코드의 안전성과 명확성을 높여주는 강력한 도구. </p>
</blockquote>
<blockquote>
<ul>
<li>데이터의 형태와 의도를 더욱 구체적으로 표현</li>
</ul>
</blockquote>
<ul>
<li>컴파일 타임에 잘못된 사용을 감지</li>
</ul>
<hr>
<h2 id="실습해보기">실습해보기</h2>
<p><a href="https://www.typescriptlang.org/ko/play/?#code/PQKhAIDEHsCdwC4AsCWBncBjJBDANngKYB2A5oeAJ7QCu4xhhAJotFrITghchQEKwcxJs3A0EKPCgSVElAA4VwIYACh1MxeACC5cAF5wAoSKYAeYjQC2AI0KwANOABEuws4B8AbnDBg4ACVCeTwcTB4kCgYAN3twAHdpJERIrDgONHloYRQycHlYFCtpFFi5RXVQEFVlcEAeDcBp-cB4P8BYAkABMiaoSTwUigAzGmJMCWz2Tm43J2lwNCRaPBYw8PkEcBx6azt4HAxc+XE14XAOBBpYYjXwG0FhUTdwGrA1AaGRi8wOLkI3AAorSjcAC4NrZ7ABKcDA+4Abxqx0Ip3O4H+9x2OnIXlUAF9KmBHvVmu1OgAVVAYF7DFCjWbzRaYZardbXEx3PSaCgmeGIi7rSyg2CPZ6DSmjcgIPgoWDIACanFgfwB5Ch5AhwL5W3AsPA2pOZwuKL0aPV9kxONUVXAAFU0Dg9E91JhsmhVgaKIYPuNvuQfgBmABsYJ8fnAAGU5jQFlcKNAANaqR3EZ1XSUyuUGcBiiVSpCynDy10Q3z+MO0qPgWMOp2rGwpnNygBM6cztdz8v9heDpPQM3DkZp8UO4HssDg6nNYHAxIUFGJhGdGBUqiKWSl5Qo0PAAFEAI40fBOTcAD0Uw3AWPAfRHVnAAHIAALsgC02HwRDIc+A4kkaBvGmnWB2Od0wAbThbUjxPBAzB3Pc8DMdloD6ZFFUIJw3A8DwHDArdj0IYZoN3fB4OnRDk2zVsnGNWAMKw7VwNw-CYKIgAFPMcCsBF7DQYjFFIj0vnQpxgKogBdcAaOwiC8Kgpi4NYwQOO4WBuIQpDm3IuVMPAYC3DEjDVBEoA">실습링크</a>
<a href="https://www.typescriptlang.org/play/?#code/CYUwxgNghgTiAEYD2A7AzgF3gfWwIxihWAC54BXFASwEdyE0BPAWzyQgCgNGAHBAIULEAPPwB88ALzwA3vADauAkWABdMv3gBfDiAAePJDCzc+8QSpDBhAFQA05idJvwAZOaHXxHDgHoAVP4c8P4elsDwpggAZkbwUPB8MGioAORo8QDmIA5oABZI5BAReCAQqJmRSJF5CFQoGCAwAG5QEAoADA4AjABMAKyq8AAU9ZDkaFTNIACUwYG+XLwIAILZUmHEVsIo5KxNDgBEayCHYgDcPgFBIfAAam1UwFCNGRi18PU85Fi7+zDxDIJVoQJ5ZHI1GBIADuQJQ8CaUIBVGinywVAyKCQGAAdPN-ItopQwBgqKhEHAXiATqMUN8MGQ-qUYDMyCdZMFPqjafT4MJ4B14AAfIWfOk-eASPr9GYc+DyyEw+AoEDQ+AAURgSOGhwAkuKsCD6PBYgD2Rjldj4NCqO96jUECCwUJsoc5vKdJy4BhyDB4V8JVAMidLp6iSgSWT4dkMPwqMY8gBNECwYZQbJs7KymSc+Xe33w4YqtUAESpwxmMxxMYAYkUIMnU7KALTgjie67wACqaHTCAWPg4yHQWGYjBOmYQ0jAlMaNIAzAA2GbneC+XyRGD0IeoTDwPDx96NgHSGNxhPH4Zjk6ynzDvcHi8pmC9DZnw9J5-DJeytcbmx5Ba+SFMU8DAWqRAIlqRiDp2NjLPANggJgGQEhwVDMIYxiRAhcjqnQbQOOqBjgFgWgmlCzDwKkAACUTNmAeRtBAIAoNkaC+D8VAQGgqQ+FEiBBshGzyLmGokSSwj4eQbTCFESCote2QOCcYhiHYYnEXwknSbJ8moo+R7Pg4TJNGpGkKuJ2kYFJBEQMIAAKsBQMwICNMkcnLApFIpnO2TqQopkwEM5maRJNm6fZTmEK57loJ5fDee+T6wAF8gnCFYgcKoQA">솔루션링크</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript에서 인터페이스와 타입의 차이, 장단점, 탄생배경]]></title>
            <link>https://velog.io/@live_in_truth/TypeScript%EC%97%90%EC%84%9C-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%ED%83%80%EC%9E%85%EC%9D%98-%EC%B0%A8%EC%9D%B4-%EC%9E%A5%EB%8B%A8%EC%A0%90-%ED%83%84%EC%83%9D%EB%B0%B0%EA%B2%BD</link>
            <guid>https://velog.io/@live_in_truth/TypeScript%EC%97%90%EC%84%9C-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%ED%83%80%EC%9E%85%EC%9D%98-%EC%B0%A8%EC%9D%B4-%EC%9E%A5%EB%8B%A8%EC%A0%90-%ED%83%84%EC%83%9D%EB%B0%B0%EA%B2%BD</guid>
            <pubDate>Wed, 11 Sep 2024 13:34:10 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/live_in_truth/post/13d62f45-8a43-4cd6-a6cf-5048ce449c4b/image.png" alt=""></p>
<blockquote>
<p>TypeScript에서 <strong>인터페이스(interface)</strong>와 <strong>타입(type)</strong>은 모두 객체의 형태와 구조를 정의하는 데 사용됨. </p>
</blockquote>
<h3 id="1-인터페이스와-타입의-탄생-배경">1. 인터페이스와 타입의 탄생 배경</h3>
<blockquote>
<p><strong>인터페이스</strong>는 TypeScript가 처음 설계될 때부터 있던 기능임. Java와 같은 객체 지향 언어의 영향을 받아 클래스와 연동되는 구조적인 정의가 필요했기 때문에 인터페이스가 도입되었음.</p>
</blockquote>
<blockquote>
<p><strong>타입</strong>은 이후 TypeScript에 추가된 기능으로, 더 유연하고 함수형 프로그래밍 스타일을 지원하는 방식으로 설계되었음. 다양한 데이터 구조를 유연하게 정의할 수 있는 도구로 발전했음.</p>
</blockquote>
<h3 id="2-인터페이스와-타입의-핵심-차이점">2. 인터페이스와 타입의 핵심 차이점</h3>
<h4 id="21-선언적-확장"><strong>2.1 선언적 확장</strong></h4>
<blockquote>
<p><strong>인터페이스</strong>는 선언적 확장이 가능
즉, 동일한 이름의 인터페이스를 여러 번 선언할 수 있으며, TypeScript는 이를 하나의 인터페이스로 병합함. 이는 코드 확장성과 유지보수 측면에서 큰 장점을 가짐. 
하지만 이미 선언된 interface를 모르고 중복 사용할 경우 오류가 나는 경우가 있어 이는 단점이 될 수도 있음.  </p>
</blockquote>
<pre><code class="language-typescript">  interface User {
    name: string;
  }

  interface User {
    age: number;
  }

  const user: User = {
    name: &quot;박지성&quot;,
    age: 25, // 병합된 인터페이스를 통해 이름과 나이 모두 사용 가능
  };</code></pre>
<blockquote>
<p><strong>타입</strong>은 확장될 수 없고, 한 번 선언된 타입은 재선언할 수 없음.</p>
</blockquote>
<pre><code class="language-typescript">  type User = {
    name: string;
  };

  // Error: Duplicate identifier &#39;User&#39;. 발생
  type User = {
    age: number;
  };</code></pre>
<h4 id="22-유니온union과-인터섹션intersection"><strong>2.2 유니온(Union)과 인터섹션(Intersection)</strong></h4>
<blockquote>
<p><strong>타입</strong>은 유니온과 인터섹션 타입을 지원함. 
즉, 여러 타입을 조합하거나(유니온), 합칠 수(인터섹션) 있음.</p>
</blockquote>
<pre><code class="language-typescript">  type Pet = { name: string };
  type Dog = Pet &amp; { breed: string }; // 인터섹션

  const dog: Dog = { name: &quot;Buddy&quot;, breed: &quot;Labrador&quot; };</code></pre>
<blockquote>
<p>유니온 타입도 가능</p>
</blockquote>
<pre><code class="language-typescript">  type StringOrNumber = string | number;</code></pre>
<blockquote>
<p>반면, <strong>인터페이스</strong>는 유니온 타입을 지원하지 않음.</p>
</blockquote>
<h4 id="23-클래스와의-호환성"><strong>2.3 클래스와의 호환성</strong></h4>
<blockquote>
<p><strong>인터페이스</strong>는 주로 클래스와 연동해서 사용됨. 
TypeScript에서 인터페이스는 클래스의 형태를 정의하고 클래스가 특정한 구조를 따르게 강제할 수 있음.</p>
</blockquote>
<pre><code class="language-typescript">  interface Animal {
    name: string;
    speak(): void;
  }

  class Dog implements Animal {
    name = &quot;Buddy&quot;;
    speak() {
      console.log(&quot;Woof!&quot;);
    }
  }</code></pre>
<blockquote>
<p><strong>타입</strong>은 클래스에 직접적으로 사용되기보다는 <strong>객체의 구조</strong>를 정의하거나 함수의 반환 타입 등을 정의하는 데 자주 사용됨.</p>
</blockquote>
<h3 id="3-장단점">3. 장단점</h3>
<h4 id="31-인터페이스의-장점"><strong>3.1 인터페이스의 장점</strong></h4>
<blockquote>
<ul>
<li><strong>확장성</strong>: 여러 번 선언이 가능하고 병합되므로 코드 확장이 용이함.</li>
</ul>
</blockquote>
<ul>
<li><strong>클래스와의 자연스러운 연동</strong>: 클래스가 특정 구조를 따르게 할 때 유용함.</li>
</ul>
<h4 id="32-인터페이스의-단점"><strong>3.2 인터페이스의 단점</strong></h4>
<blockquote>
<ul>
<li><strong>유연성 부족</strong>: 유니온 타입이나 인터섹션 타입을 지원하지 않음.</li>
</ul>
</blockquote>
<ul>
<li><strong>구조적 제한</strong>: 더 복잡한 구조나 동적 타입을 선언하는 데 제약이 있음.</li>
</ul>
<h4 id="33-타입의-장점"><strong>3.3 타입의 장점</strong></h4>
<blockquote>
<ul>
<li><strong>유연성</strong>: 유니온과 인터섹션 타입 지원으로 복잡한 타입을 표현할 수 있음.</li>
</ul>
</blockquote>
<ul>
<li><strong>복합 타입 지원</strong>: 객체, 유니온, 인터섹션 등 다양한 형태의 타입 선언이 가능.</li>
</ul>
<h4 id="34-타입의-단점"><strong>3.4 타입의 단점</strong></h4>
<blockquote>
<ul>
<li><strong>확장성 부족</strong>: 한 번 선언된 타입은 재선언할 수 없으므로 확장성 면에서 인터페이스보다 제한적임.</li>
</ul>
</blockquote>
<h3 id="4-예시-코드">4. 예시 코드</h3>
<h4 id="41-인터페이스-사용-예시"><strong>4.1 인터페이스 사용 예시</strong></h4>
<pre><code class="language-typescript">interface User {
  name: string;
  age: number;
}

const user: User = {
  name: &quot;박지성&quot;,
  age: 25,
};</code></pre>
<h4 id="42-타입-사용-예시"><strong>4.2 타입 사용 예시</strong></h4>
<pre><code class="language-typescript">type User = {
  name: string;
  age: number;
};

const user: User = {
  name: &quot;박지성&quot;,
  age: 25,
};</code></pre>
<h4 id="43-유니온-타입-예시"><strong>4.3 유니온 타입 예시</strong></h4>
<pre><code class="language-typescript">type StringOrNumber = string | number;

let value: StringOrNumber;

value = &quot;하잉&quot;;
value = 123;</code></pre>
<h4 id="44-인터섹션-타입-예시"><strong>4.4 인터섹션 타입 예시</strong></h4>
<pre><code class="language-typescript">type Person = { name: string };
type Employee = { employeeId: number };

type Staff = Person &amp; Employee;

const staff: Staff = {
  name: &quot;박지성&quot;,
  employeeId: 217,
};</code></pre>
<h3 id="5-공식-문서-권장-사항">5. 공식 문서 권장 사항</h3>
<blockquote>
<p>TypeScript 공식 문서에서는 <strong>인터페이스</strong>와 <strong>타입</strong>을 사용하는 상황에 대해 다음과 같은 가이드를 제시함:</p>
</blockquote>
<h4 id="51-인터페이스를-사용할-때"><strong>5.1 인터페이스를 사용할 때</strong></h4>
<blockquote>
<ul>
<li><strong>객체 지향적인 구조가 필요한 경우</strong>: 클래스와 연동하여 사용할 때는 인터페이스를 사용하는 것이 좋음.</li>
<li><strong>확장과 병합이 필요할 때</strong>: 여러 선언을 병합하여 하나의 인터페이스로 만들 수 있으므로, 확장이 예상되는 경우 인터페이스를 권장함.</li>
</ul>
</blockquote>
<pre><code class="language-typescript">  interface Animal {
    name: string;
  }

  interface Animal {
    age: number;
  }

  const animal: Animal = { name: &quot;강아지&quot;, age: 3 };</code></pre>
<h4 id="52-타입을-사용할-때"><strong>5.2 타입을 사용할 때</strong></h4>
<blockquote>
<ul>
<li><strong>유연한 타입 조합이 필요한 경우</strong>: 유니온 타입이나 인터섹션 타입을 사용할 때는 타입을 사용하는 것이 적합함.</li>
</ul>
</blockquote>
<ul>
<li><p><strong>동적이고 복합적인 타입을 다룰 때</strong>: 함수형 프로그래밍 스타일을 따르거나, 다양한 데이터 구조를 유연하게 정의할 때는 타입을 사용하는 것이 더 적합함.</p>
<pre><code class="language-typescript">type ID = string | number;</code></pre>
</li>
</ul>
<h3 id="6-결론">6. 결론</h3>
<p><strong>인터페이스</strong>와 <strong>타입</strong>은 TypeScript에서 각각의 강점과 용도를 가지고 있음. 객체지향적인 구조를 정의하고 확장이 필요한 경우에는 인터페이스가 적합하며, 유연하고 복잡한 데이터 구조를 정의할 때는 타입을 사용하는 것이 좋음.</p>
<p><strong>권장사항 요약:</strong></p>
<ul>
<li>클래스와 연동, 확장성: <strong>인터페이스</strong> 사용</li>
<li>유니온, 인터섹션, 복합 타입: <strong>타입</strong> 사용</li>
</ul>
<h3 id="7-보충내용">7. 보충내용</h3>
<h4 id="extends와-의-차이점"><code>extends</code>와 <code>&amp;</code>의 차이점</h4>
<blockquote>
<ul>
<li>위 내용에서 타입에서 인터섹션을 사용하여 속성 확장이 가능하다고 언급하였음. interface도 객체지향적으로 <code>extends</code> 상속이 가능함.</li>
<li><em><code>extends</code>*</em>: 상속을 의미. 타입의 인터섹션과 기능은 같지만 개념이 다름.</li>
</ul>
</blockquote>
<ul>
<li><p><code>extends</code>는 상속 개념으로, <strong>인터페이스 확장</strong>을 위해 사용됨.</p>
</li>
<li><p><code>&amp;</code>는 여러 <strong>타입을 결합</strong>하는 방식으로, 모든 속성을 합쳐 새로운 타입을 만듬.</p>
</li>
<li><p><strong>extends 예시</strong>:</p>
<pre><code class="language-typescript">interface Person {
  name: string;
  age: number;
}

interface Employee extends Person {
  salary: number;
}</code></pre>
</li>
</ul>
<h4 id="omit-사용-방법"><code>Omit</code> 사용 방법</h4>
<blockquote>
<p><code>Omit</code>은 타입이나 인터페이스에서 특정 속성을 <strong>제외</strong>하고 싶을 때 사용됨.</p>
</blockquote>
<ul>
<li><p><strong>타입에서 <code>Omit</code> 사용</strong>:</p>
<pre><code class="language-typescript">type Person = { name: string; age: number; address: string; }
type PersonWithoutAddress = Omit&lt;Person, &quot;address&quot;&gt;;</code></pre>
</li>
<li><p><strong>인터페이스에서 <code>Omit</code> 사용</strong>:</p>
<pre><code class="language-typescript">interface Person {
  name: string;
  age: number;
  address: string;
}

interface PersonWithoutAddress extends Omit&lt;Person, &quot;address&quot;&gt; {}</code></pre>
</li>
</ul>
<h3 id="요약">요약</h3>
<ul>
<li><strong><code>extends</code></strong>: 상속 개념으로, 인터페이스를 확장할 때 사용.</li>
<li><strong><code>&amp;</code></strong>: 여러 타입을 합쳐 새로운 타입을 만들 때 사용.</li>
<li><strong><code>Omit</code></strong>: 특정 속성을 제외한 타입이나 인터페이스를 정의할 때 사용.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Protocol Layers and Their Service Models (James F. Kurose, Keith Ross - Computer Networking- A Top Down Approach-Pearson (2020) 교과서 참고)]]></title>
            <link>https://velog.io/@live_in_truth/Protocol-Layers-and-Their-Service-Models-James-F.-Kurose-Keith-Ross-Computer-Networking-A-Top-Down-Approach-Pearson-2020-%EA%B5%90%EA%B3%BC%EC%84%9C-%EC%B0%B8%EA%B3%A0</link>
            <guid>https://velog.io/@live_in_truth/Protocol-Layers-and-Their-Service-Models-James-F.-Kurose-Keith-Ross-Computer-Networking-A-Top-Down-Approach-Pearson-2020-%EA%B5%90%EA%B3%BC%EC%84%9C-%EC%B0%B8%EA%B3%A0</guid>
            <pubDate>Sun, 08 Sep 2024 15:22:58 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>모든 내용과 이미지는 Computer Networking- A Top Down Approach-Pearson을 참고하였습니다.</p>
</blockquote>
<h2 id="chapter-15">Chapter 1.5</h2>
<hr>
<p>이번 글에서는 네트워크의 프로토콜 계층 구조와 서비스 모델을 다루며, 인터넷 프로토콜 스택과 OSI 모델에 대해 설명할 것임. 
또한, 네트워크 통신에서의 <strong>캡슐화(encapsulation)</strong>와 <strong>역캡슐화(de-encapsulation)</strong> 과정도 포함하여 정리할 것임.</p>
<h3 id="1-네트워크-계층-구조의-필요성">1. 네트워크 계층 구조의 필요성</h3>
<blockquote>
<p>인터넷은 매우 복잡한 시스템임. 
수많은 애플리케이션과 프로토콜, 다양한 종단 시스템, 패킷 스위치 및 다양한 링크 레벨 매체들이 존재함. 
이 복잡한 시스템을 어떻게 체계적으로 정리할 수 있을까? 
다행히 네트워크 아키텍처를 설명하는 계층적 구조가 존재함. 계층적 구조는 복잡한 시스템을 명확하게 설명하고 유지보수할 수 있는 유용한 도구임.</p>
</blockquote>
<h3 id="2-osi-7계층-모델과-인터넷-프로토콜-스택">2. OSI 7계층 모델과 인터넷 프로토콜 스택</h3>
<h4 id="osi-모델">OSI 모델</h4>
<p>OSI 모델은 7계층으로 이루어진 네트워크 통신 모델임:</p>
<blockquote>
<p><img src="https://velog.velcdn.com/images/live_in_truth/post/fcc491cb-e1ea-4541-83ab-7ab78d2f7dc5/image.png" alt=""></p>
<ol>
<li><strong>Application (응용)</strong></li>
<li><strong>Presentation (표현)</strong></li>
<li><strong>Session (세션)</strong></li>
<li><strong>Transport (전송)</strong></li>
<li><strong>Network (네트워크)</strong></li>
<li><strong>Data Link (데이터 링크)</strong></li>
<li><strong>Physical (물리)</strong></li>
</ol>
</blockquote>
<blockquote>
<p>이 중에서 <strong>Presentation</strong>과 <strong>Session</strong> 계층은 인터넷 프로토콜 스택에서 생략됨. 이 두 계층의 기능은 필요에 따라 응용 프로그램에서 구현됨.</p>
</blockquote>
<blockquote>
<ul>
<li><strong>Presentation 계층</strong>은 데이터를 암호화하거나, 압축하고, 기계 특유의 형식으로 변환하는 역할을 함. 예를 들어, HTTPS 프로토콜에서 암호화와 복호화가 이 계층에서 이루어짐.</li>
</ul>
</blockquote>
<ul>
<li><strong>Session 계층</strong>은 통신 중 동기화와 체크포인트, 데이터 교환 복구 등을 담당함. 하지만, 이 기능도 애플리케이션에서 구현될 수 있음.</li>
</ul>
<h4 id="인터넷-프로토콜-스택중요">인터넷 프로토콜 스택(중요!!!!)</h4>
<p>인터넷 프로토콜 스택은 OSI 모델보다 간소화된 5계층 모델로 이루어짐:</p>
<blockquote>
<ol>
<li><strong>Application (응용)</strong></li>
<li><strong>Transport (전송)</strong></li>
<li><strong>Network (네트워크)</strong></li>
<li><strong>Link (데이터 링크)</strong></li>
<li><strong>Physical (물리)</strong>
<img src="https://velog.velcdn.com/images/live_in_truth/post/01fe7291-70a2-47fa-9401-9d8bab1de767/image.png" alt=""></li>
</ol>
</blockquote>
<blockquote>
<ul>
<li><strong>Application Layer (응용 계층)</strong>: 사용자가 사용하는 애플리케이션과 해당 프로토콜을 포함함. 예를 들어 HTTP, FTP, SMTP 등이 있음.</li>
</ul>
</blockquote>
<ul>
<li><strong>Transport Layer (전송 계층)</strong>: 애플리케이션 간 데이터 전송을 담당하며, <strong>TCP</strong>와 <strong>UDP</strong> 프로토콜이 사용됨. <strong>TCP</strong>는 신뢰성 있는 데이터 전송을 보장하는 반면, <strong>UDP</strong>는 신뢰성 없이 빠르게 데이터를 전송함.</li>
<li><strong>Network Layer (네트워크 계층)</strong>: 데이터를 송수신할 경로를 찾아주며, <strong>IP</strong> 주소와 라우팅을 담당함.</li>
<li><strong>Link Layer (데이터 링크 계층)</strong>: 인접한 네트워크 장치 간의 데이터 전송을 담당하며, <strong>이더넷</strong>이나 <strong>Wi-Fi</strong> 등이 속함.</li>
<li><strong>Physical Layer (물리 계층)</strong>: 물리적인 매체를 통해 데이터를 전송함. 케이블이나 무선 신호를 통해 데이터를 비트 단위로 주고받음.</li>
</ul>
<h3 id="3-캡슐화encapsulation와-역캡슐화de-encapsulation">3. 캡슐화(Encapsulation)와 역캡슐화(De-encapsulation)</h3>
<blockquote>
<p>네트워크에서 데이터가 전송될 때, 각 계층은 데이터를 처리하면서 자신만의 헤더를 추가하는 <strong>캡슐화</strong> 과정을 거침. 그리고 수신 측에서 이 헤더들을 제거하는 <strong>역캡슐화</strong> 과정을 거쳐 데이터가 상위 계층으로 전달됨.
<img src="https://velog.velcdn.com/images/live_in_truth/post/a92dde1b-18df-4e30-b259-9e33581c3411/image.png" alt=""></p>
</blockquote>
<h4 id="캡슐화">캡슐화</h4>
<blockquote>
<ol>
<li><strong>Application Layer</strong>: 사용자가 입력한 데이터가 메시지로 전송됨.</li>
<li><strong>Transport Layer</strong>: 메시지에 <strong>세그먼트</strong>가 추가됨.</li>
<li><strong>Network Layer</strong>: <strong>세그먼트</strong>에 <strong>IP 헤더</strong>를 추가하여 <strong>데이터그램</strong>이 됨.</li>
<li><strong>Link Layer</strong>: <strong>프레임 헤더</strong>와 <strong>프레임 트레일러</strong>가 추가됨.</li>
<li><strong>Physical Layer</strong>: 비트로 변환되어 물리적 매체를 통해 전송됨.</li>
</ol>
</blockquote>
<h4 id="역캡슐화">역캡슐화</h4>
<blockquote>
<p>수신 측에서는 이 과정을 역순으로 수행함. 물리 계층에서 받은 비트 데이터를 링크 계층에서 <strong>프레임</strong>으로 처리하고, 네트워크 계층에서 <strong>데이터그램</strong>으로 변환하여 목적지까지 도달함.</p>
</blockquote>
<h3 id="4-why-layering">4. Why Layering?</h3>
<p>계층 구조의 주요 이점은 다음과 같음:</p>
<blockquote>
<ol>
<li><strong>복잡한 시스템 처리</strong>:<ul>
<li>복잡한 네트워크 시스템을 계층으로 나눠서 각 계층의 기능을 명확하게 정의할 수 있음.</li>
</ul>
</li>
<li><strong>모듈화의 장점</strong>:<ul>
<li>계층 구조 덕분에 한 계층의 구현을 변경하더라도 다른 계층에 영향을 미치지 않음. 이를 통해 시스템 유지보수 및 업데이트가 용이해짐.</li>
</ul>
</li>
<li><strong>계층화의 단점</strong>:<ul>
<li>계층 구조는 중복된 기능을 초래할 수 있음. 예를 들어, 오류 검출 기능이 여러 계층에서 중복되어 있을 수 있음. 또한, 각 계층에서 추가되는 오버헤드로 인해 성능 저하가 발생할 수 있음.</li>
</ul>
</li>
</ol>
</blockquote>
<h3 id="결론">결론</h3>
<p>네트워크 통신의 계층적 구조는 복잡한 시스템을 이해하고 관리하는 데 유용한 도구임. OSI 모델과 인터넷 프로토콜 스택은 계층적 구조의 대표적인 예로, 네트워크 통신의 각 단계에서 어떤 일이 일어나는지 명확하게 설명함. <strong>캡슐화</strong>와 <strong>역캡슐화</strong> 과정은 데이터를 안전하고 효율적으로 전달하기 위한 핵심 개념임. </p>
<hr>
]]></description>
        </item>
    </channel>
</rss>