<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>gosuminjun</title>
        <link>https://velog.io/</link>
        <description>ChatGPT-Driven Development를 지양합니다.</description>
        <lastBuildDate>Thu, 27 Feb 2025 09:07:41 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>gosuminjun</title>
            <url>https://velog.velcdn.com/images/mingjuu_u/profile/37868676-a8fa-4f03-b227-cfa5522f63ea/image.gif</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. gosuminjun. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mingjuu_u" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[3]]></title>
            <link>https://velog.io/@mingjuu_u/3</link>
            <guid>https://velog.io/@mingjuu_u/3</guid>
            <pubDate>Thu, 27 Feb 2025 09:07:41 GMT</pubDate>
            <description><![CDATA[<h2 id="chapter-3-intro">Chapter 3 Intro</h2>
<ul>
<li>리팩토링을 언제 시작하고 언제 그만할지 명확하게 정립된 규칙이 없다.</li>
<li>리팩토링할 시점을 &#39;냄새&#39;라는 표현을 사용하는데 그러한 &#39;냄새&#39;가 나는 코드들에 일정한 패턴이 있다.</li>
<li>그러나 언제 리팩토링을 멈춰야 하는지에 대해서는 숙련된 사람의 직관만큼 정확한 기준이 없기에 명확한 기준을 제시하지 않을 것이다.</li>
</ul>
<h4 id="기이한-이름">기이한 이름</h4>
<ul>
<li>함수, 모듈, 변수, 클래스의 이름은 명확해야 한다.</li>
</ul>
<h4 id="중복-코드">중복 코드</h4>
<ul>
<li>반복되는 중복 코드는 하나로 통합해야 한다.</li>
<li><strong>함수 추출하기, 문장 슬라이스하기, 메서드 올리기</strong>등을 활용한다.</li>
</ul>
<h4 id="긴-함수">긴 함수</h4>
<ul>
<li>코드를 이해하고, 공유하고, 선택하기 쉬워지는 장점은 함수를 짧게 구성할 때 나온다.</li>
<li>함수의 이름을 잘 지어두면 본문코드를 볼 이유가 사라진다.</li>
<li><strong>함수 추출하기</strong>를 활용한다.</li>
</ul>
<h4 id="긴-매개변수-목록">긴 매개변수 목록</h4>
<ul>
<li>매개변수 목록이 길어지면 그 자체로 이해하기 어려워진다.</li>
<li><strong>매개변수를 질의 함수로 바꾸기</strong>를 활용한다.</li>
</ul>
<h4 id="전역-데이터">전역 데이터</h4>
<ul>
<li><strong>변수 캡슐화하기</strong>를 활용한다.</li>
</ul>
<h4 id="가변-데이터">가변 데이터</h4>
<ul>
<li><strong>변수 캡슐화하기</strong>를 활용한다.</li>
</ul>
<h4 id="뒤엉킨-변경">뒤엉킨 변경</h4>
<ul>
<li>하나의 모듈이 서로 다른 이유로 인해 여러가지 방식으로 변경되는 일이 많을 때 발생한다.</li>
<li>이는 단일 책임 원칙이 제대로 지켜지지 않아서 발생하는 것이다.</li>
</ul>
<h4 id="산탄총-수술">산탄총 수술</h4>
<ul>
<li>코드를 변경할 때마다 변경해야 하는 부분이 코드 전반에 퍼져 있을 때 발생한다.</li>
</ul>
<h4 id="기능-편애">기능 편애</h4>
<ul>
<li>모듈화 시, 나뉜 영역간의 상호작용은 최소로 줄여야 하지만 그렇지 못했을 때 주로 발생한다.</li>
</ul>
<h4 id="데이터-뭉치">데이터 뭉치</h4>
<ul>
<li><strong>클래스 추출하기, 매개변수 객체 만들기, 객체 통째로 넘기기</strong>를 활용한다.</li>
</ul>
<h4 id="기본형-집착">기본형 집착</h4>
<ul>
<li>자료형을 문자형으로만 표현할 때 발생한다.</li>
</ul>
<h4 id="반복되는-switch문">반복되는 switch문</h4>
<ul>
<li><h4 id="반복문">반복문</h4>
</li>
<li></li>
</ul>
<h4 id="성의-없는-요소">성의 없는 요소</h4>
<ul>
<li><strong>함수 인라인하기, 클래스 인라인하기, 계층 합치기</strong>를 활용한다.</li>
</ul>
<h4 id="추측성-일반화">추측성 일반화</h4>
<ul>
<li>나중에 필요할거라는 생각으로 작성한 코드가 이해하거나 관리하기 어려워진 경우에 발생한다.</li>
<li><strong>계층 합치기, 함수 인라인하기, 클래스 인라인하기</strong>로 삭제하거나 본문에서 사용되지 않는 매개변수는 <strong>함수 선언 바꾸기</strong>로 없앤다.</li>
<li>테스트 코드 외에 사용한 적이 없는 코드는 <strong>죽은 코드 제거하기</strong>를 활용한다.</li>
</ul>
<h4 id="임시-필드">임시 필드</h4>
<ul>
<li>특정 상황에만 값이 생선되는 클래스가 이해하기 어려운 경우게 발생한다.</li>
<li><strong>클래스 추출하기, 함수 옮기기, 특이 케이스 추가하기</strong>를 활용한다.</li>
</ul>
<h4 id="메시지-체인">메시지 체인</h4>
<p>-</p>
<h4 id="중개자">중개자</h4>
<ul>
<li>클래스가 제공하는 메서드의 상당 부분이 다른 클래스에 구현을 위임하고 있는 경우 발생한다.</li>
</ul>
<h4 id="내부자-거래">내부자 거래</h4>
<ul>
<li><h4 id="거대한-클래스">거대한 클래스</h4>
</li>
<li>클래스에 필드가 너무 많으면 중복 코드가 생기기 쉽다.</li>
<li><strong>클래스 추출하기</strong>로 일부 필드를 묶어 해결한다.</li>
</ul>
<h4 id="서로-다른-인터페이스의-대안-클래스들">서로 다른 인터페이스의 대안 클래스들</h4>
<ul>
<li><h4 id="데이터-클래스">데이터 클래스</h4>
</li>
<li></li>
</ul>
<h4 id="상속-포기">상속 포기</h4>
<ul>
<li><strong>서브클래스를 위임으로 바꾸기, 슈퍼클래스를 위임으로 바꾸기</strong>를 활용한다.</li>
</ul>
<h4 id="주석">주석</h4>
<ul>
<li>주석을 남기기 전에 주석이 필요없는 코드를 짤 수 있는지 리팩토링 해보자</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 2]]></title>
            <link>https://velog.io/@mingjuu_u/Chapter-2</link>
            <guid>https://velog.io/@mingjuu_u/Chapter-2</guid>
            <pubDate>Thu, 13 Feb 2025 02:55:41 GMT</pubDate>
            <description><![CDATA[<h2 id="chapter-2">Chapter 2</h2>
<h3 id="21-리팩토링-정의">2.1 리팩토링 정의</h3>
<p>특정한 방식에 따라 코드를 정리하는 것이 리팩토링이지 단순히 코드를 정리하는 작업은 리팩토링이 아니다.
리팩토링은 성능 최적화와 비슷하며 둘 다 코드를 변경하지만 프로그램의 전반적인 기능은 그대로 유지한다.
단, 성능 최적화는 속도 개선을 리팩토링은 코드를 이해하고 수정하기 쉽게 만드는데 그 목적이 있다.</p>
<h3 id="22-두개의-모자">2.2 두개의 모자</h3>
<p>기능을 추가 할 때는 기존 코드는 건드리지 않고 새 기능을 추가한다. 이때의 진척도는 테스트를 추가해 통과하는지 확인한다.
리팩토링할 때는 기능 추가는 하지 않고 오로지 코드 재구성에만 전념한다.</p>
<h3 id="23-리팩토링-하는-이유">2.3 리팩토링 하는 이유</h3>
<h4 id="소프트웨어-설계가-좋아진다">소프트웨어 설계가 좋아진다.</h4>
<p>같은 일을 하더라도 설계가 나쁘면 코드가 길어지며 아키텍쳐가 무너진다.
코드량이 줄어든다고 시스템이 빨라지는 것은 아니나, 사람이 수정하는데 들여야하는 노력은 줄어든다.
이해햐야 할 코드가 짧을 수록 실수 없이 수정할 수 있다.</p>
<h4 id="리팩토링하면-소프트웨어를-이해하기-쉬워진다">리팩토링하면 소프트웨어를 이해하기 쉬워진다.</h4>
<p>프로그램을 동작하는데에만 신경쓰면 다른 개발자는 그 코드를 제대로 이해하기 어려워진다. (보통 &#39;나&#39;의 기억용량을 초과해 내가 그 수혜를 입게 된다.)</p>
<h4 id="리팩토링하면-버그를-쉽게-찾을-수-있다">리팩토링하면 버그를 쉽게 찾을 수 있다.</h4>
<p>코드를 이해하기 쉽다는 말은 버그를 찾기 쉽다는 말과 일맥상통한다.</p>
<h4 id="리팩토링하면-프로그래밍-속도를-높일-수-있다">리팩토링하면 프로그래밍 속도를 높일 수 있다.</h4>
<p>좋은 설계는 기능 누적에 따라 그 진가가 드러난다.</p>
<h3 id="24-언제-리팩토링-해야-할까">2.4 언제 리팩토링 해야 할까?</h3>
<p>준비를 위한 리팩토링 : 기능을 새로 추가하기 직전에 리팩토링한다.</p>
<p>이해를 위한 리팩토링 : 코드를 분석하며 리팩토링한다.</p>
<p>쓰레기 줍기 리팩토링 : 간단히 수정할 수 있는 것은 즉시 고치고, 시간이 좀 걸리는 일은 하던 일을 끝내고 나서 리팩토링한다.</p>
<p>수시로 하는 리팩토링</p>
<p>오래 걸리는 리팩토링 : 주어진 문제를 몇 주에 걸쳐 조금씩 해결해 가는게 효과적이다.</p>
<p>코드 리뷰에 리팩토링 활용하기</p>
<p>리팩토링하지 말아야 할 때</p>
<ul>
<li>외부 API 다루듯 호출해서 쓰는 코드라면 내부 동작을 이해해야 할 시점에 리팩토링해야 효과를 볼 수 있다.</li>
<li>처음부터 새로 작성하는게 쉬울 때에도 리팩토링 하지 않는다.</li>
</ul>
<h3 id="25-리팩토링시-고려할-문제">2.5 리팩토링시 고려할 문제</h3>
<p>리팩토링은 개발 기간을 단축하고, 기능 추가 시간을 줄이고, 버그 수정 시간을 줄이기 위한 경제적인 이유로 하는 것이다.
좋은 설계는 지향해야 하지만 클린코드에 집착하지 말자, 클린코드가 리팩터링의 궁극적인 목적이 되어서는 안된다</p>
<h4 id="새-기능-개발-속도-저하">새 기능 개발 속도 저하</h4>
<p>리팩토링이 당장의 속도 저하를 일으키는 것처럼 보일 수 있고 이것이 실전에서 적용하는데 가장 큰 걸림돌이다.
지속적인 코드베이스 개선을 통해 생산성을 키우도록 해야 한다.</p>
<h4 id="코드-소유권">코드 소유권</h4>
<p>코드 소유권이 나뉘어 있거나 API 자체일 경우 리팩토링에 제약이 있지만 리팩토링이 가능하다.</p>
<h4 id="브랜치">브랜치</h4>
<p>독립 브랜치로 작업하는 기간이 길어질수록 마스터로 통합하기가 어려워진다.
브랜치 통합 주기를 짧게해 머지 시 복잡도를 줄이는 것은 리팩토링에도 도움이 된다.</p>
<h4 id="테스팅">테스팅</h4>
<h4 id="레거시-코드">레거시 코드</h4>
<h4 id="데이터베이스">데이터베이스</h4>
<h3 id="26-리팩토링-아키텍쳐-애그니yagni">2.6 리팩토링, 아키텍쳐, 애그니(YAGNI)</h3>
<p>리팩토링이 아키텍처에 미치는 실질적인 효과는 요구사항 변화에 자연스럽게 대응하도록 코드베이스를 잘 설계해준다는 것이다.
현재까지 파악한 요구사항만을 해결하는 소프트웨어를 구축하고, 진행하면서 아키텍처도 그에 맞게 리팩토링해서 바꾼다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1]]></title>
            <link>https://velog.io/@mingjuu_u/1-q0ri0hlr</link>
            <guid>https://velog.io/@mingjuu_u/1-q0ri0hlr</guid>
            <pubDate>Wed, 22 Jan 2025 02:49:41 GMT</pubDate>
            <description><![CDATA[<h2 id="chapter-1-intro">Chapter 1 Intro</h2>
<ul>
<li>챕터1에서는 리팩토링 원칙을 이해하기 이전에 실제로 리팩토링을 수행한다.</li>
<li>원칙은 일반화되기 쉬워 실제 적용방법을 파악하기 어렵지만 예시가 있다면 명확해지기 때문이다.</li>
</ul>
<h3 id="11">1.1</h3>
<p>다양한 연극을 외주로 받아 공연하는 극단이 있다.
공연요청이 들어오면 연극의 장르와 관객 규모를 기초로 비용을 책정한다.
공연료와 별개로 포인트를 지급해 다음번 의뢰 시 공연료를 할인받을 수도 있다.</p>
<h4 id="공연할-연극-정보">공연할 연극 정보</h4>
<pre><code class="language-json">plays.json
{
  &quot;hamlet&quot;: {&quot;name&quot;: &quot;Hamlet&quot;, &quot;type&quot;: &quot;tragedy&quot;}
  &quot;as-like&quot;: {&quot;name&quot;: &quot;As You Like It&quot;, &quot;type&quot;: &quot;comedy&quot;}
  &quot;othello&quot;: {&quot;name&quot;: &quot;Othello&quot;, &quot;type&quot;: &quot;tragedy&quot;}
}
</code></pre>
<h4 id="공연료-청구서에-들어갈-데이터">공연료 청구서에 들어갈 데이터</h4>
<pre><code class="language-json">invoices.json
[
  {
    &quot;customer&quot;: &quot;BigCo&quot;,
    &quot;performances&quot;: [
      {
        &quot;playID&quot;: &quot;hamlet&quot;,
        &quot;audience&quot;: 55
      },
      {
        &quot;playID&quot;: &quot;as-like&quot;,
        &quot;audience&quot;: 35
      },
      {
        &quot;playID&quot;: &quot;othello&quot;,
        &quot;audience&quot;: 40
      },
    ]
  } 
]</code></pre>
<h4 id="공연료-청구서를-출력하는-코드">공연료 청구서를 출력하는 코드</h4>
<pre><code class="language-typescript">export function statement(invoice, plays) {
  let totalAmount = 0;
  let volumeCredits = 0;
  let result = `청구내역 (고객명: ${invoice.customer})\n`;
  const format = new Intl.NumberFormat(&#39;en-US&#39;, { style: &#39;currency&#39;, currency: &#39;USD&#39;, maximumFractionDigits: 2 })
    .format;

  for (let perf of invoice.performances) {
    const play = plays[perf.playID];
    let thisAmount = 0;

    switch (play.type) {
      case &#39;tragedy&#39;:
        thisAmount = 40_000;

        if (perf.audience &gt; 30) {
          thisAmount += 1_000 * (perf.audience - 30);
        }
        break;
      case &#39;comedy&#39;:
        thisAmount = 30_000;

        if (perf.audience &gt; 20) {
          thisAmount += 10_000 + 500 * (perf.audience - 20);
        }
        thisAmount += 300 * perf.audience;
        break;

      default:
        throw new Error(`알 수 없는 장르: ${play.type}`);
    }

    // 포인트를 적립한다.
    volumeCredits += Math.max(perf.audience - 30, 0);

    // 희극 관객 5명마다 추가 포인트를 제공한다.
    if (&#39;comedy&#39; === play.type) {
      volumeCredits += Math.floor(perf.audience / 5);
    }

    // 청구 내역을 출력한다.
    result += `${play.name}: ${format(thisAmount / 100)} ${perf.audience}석\n`;
    totalAmount += thisAmount;
  }
  result += `총액 ${format(totalAmount / 100)}\n`;
  result += `적립 포인트 ${volumeCredits}점\n`;

  return result;
}
</code></pre>
<h3 id="12">1.2</h3>
<ul>
<li>짧은 프로그램이 잘 작동하는 상황에서 그저 코드가 &#39;지저분하다&#39;라는 이유로 수정하는 것은 좋지 않다.</li>
<li>설계가 나빠 수정하기 어려운 프로그램이 있다면 구조부터 바로잡은 뒤에 기능을 수정하는 편이 수월하다.</li>
<li>위 프로그램에 수정할 부분<ul>
<li>청구 내역을 HTML로 출력하는 기능이 필요하다.</li>
<li>연극 장르와 공연료 정책이 변경될 수 있지만 그에 맞지 않는 구조를 갖고 있다.</li>
</ul>
</li>
</ul>
<h3 id="13">1.3</h3>
<ul>
<li>리팩토링하기 전에 자가진단이 가능한 테스트코드부터 마련해야한다.</li>
</ul>
<h3 id="14-staetement-함수-쪼개기">1.4 staetement() 함수 쪼개기</h3>
<ul>
<li>전체 동작을 각각의 작은 부분으로 나눌 수 있는 지점을 찾다보면 중간 지점의 switch문이 눈에 띈다.</li>
<li>switch문은 한 번의 공연에 대한 요금을 계산하고 있는데 이는 코드를 분석해서 얻은 정보이며, 이런식으로 분석을 통해 파악한 정보는 휘발되므로 다시 분석하지 않아도 되는 코드를 작성해야 한다.</li>
</ul>
<ul>
<li>프로그램 수정을 작은 단계로 나눠 진행해야 버그를 쉽게 잡을 수 있다.</li>
</ul>
<p>volumeCredits 변수를 제거하는 작업 단계</p>
<ol>
<li><strong>반복문 쪼개기</strong>로 변수 값을 누적시키는 부분을 분리한다.</li>
<li><strong>문장 슬라이드하기</strong>로 변수 초기화 문장을 변수 값 누적 코드 바로 앞으로 옮기고</li>
<li><strong>함수 추출하기</strong>로 적립 포인트 계산 부분을 별도 함수로 추출한다.</li>
<li><strong>변수 인라인하기</strong>로 volumeCredits 변수를 제거한다.</li>
</ol>
<h3 id="15">1.5</h3>
<ul>
<li>그 결과 계산 로직은 모두 여러개의 보조함수로 빠져 최상위 statement() 함수는 짧아지고 출력한 문장을 생성하기만 한다.</li>
</ul>
<h3 id="16-계산-단계와-포맷팅-단계-분리하기">1.6 계산 단계와 포맷팅 단계 분리하기</h3>
<ul>
<li>앞서 말한대로 지금까지는 코드의 구조를 보강하는 데에 주안점을 두었다면 이제는 기능 변경, statement()의 HTML 버전을 만드는 작업을 하려고 한다.</li>
</ul>
<pre><code class="language-typescript">export function createStatementData(invoice, plays) {
  const statementData = {};

  statementData.customer = invoice.customer;
  statementData.performances = invoice.performances.map(enrichPerformance);
  statementData.totalAmount = totalAmount(statementData);
  statementData.totalVolumeCredits = totalVolumeCredits(statementData);

  return statementData;

  function enrichPerformance(aPerformance) {
    const result = Object.assign({}, aPerformance);

    result.play = playFor(result);
    result.amount = amountFor(result);
    result.volumeCredits = volumeCreditsFor(result);

    return result;
  }

  function playFor(aPerformance) {
    return plays[aPerformance.playID];
  }

  function amountFor(aPerformance) {
    let result = 0;

    switch (aPerformance.play.type) {
      case &#39;tragedy&#39;:
        result = 40_000;

        if (aPerformance.audience &gt; 30) {
          result += 1_000 * (aPerformance.audience - 30);
        }
        break;
      case &#39;comedy&#39;:
        result = 30_000;

        if (aPerformance.audience &gt; 20) {
          result += 10_000 + 500 * (aPerformance.audience - 20);
        }
        result += 300 * aPerformance.audience;
        break;

      default:
        throw new Error(`알 수 없는 장르: ${aPerformance.play.type}`);
    }
    return result;
  }

  function volumeCreditsFor(aPerformance) {
    let result = 0;

    result += Math.max(aPerformance.audience - 30, 0);

    if (&#39;comedy&#39; === aPerformance.play.type) {
      result += Math.floor(aPerformance.audience / 5);
    }

    return result;
  }

  function totalAmount(data) {
    return data.performances.reduce((acc, cur) =&gt; acc + cur.amount, 0);
  }

  function totalVolumeCredits(data) {
    return data.performances.reduce((acc, cur) =&gt; acc + cur.volumeCredits, 0);
  }
}
</code></pre>
<pre><code class="language-typescript">import { createStatementData } from &#39;./createStatementData.js&#39;;

export function statement(invoice, plays) {
  return renderPlainText(createStatementData(invoice, plays));
}

function renderPlainText(data) {
  let result = `청구내역 (고객명: ${data.customer})\n`;

  for (let perf of data.performances) {
    result += `${perf.play.name}: ${usd(perf.amount)} ${perf.audience}석\n`;
  }

  result += `총액 ${usd(data.totalAmount)}\n`;
  result += `적립 포인트 ${data.totalVolumeCredits}점\n`;

  return result;
}

function htmlStatement(invoice, plays) {
  return renderHtml(createStatementData(invoice, plays));
}

function renderHtml(data) {
  let result = `&lt;h1&gt;청구 내역 ${data.customer}&lt;/h1&gt;\n`;

  result += &#39;&lt;table&gt;\n&#39;;
  result += &#39;&lt;tr&gt;&lt;th&gt;연극&lt;/th&gt;&lt;th&gt;좌석 수&lt;/th&gt;&lt;th&gt;금액&lt;/th&gt;&lt;/tr&gt;&#39;;

  for (let perf of data.performances) {
    result += `  &lt;tr&gt;&lt;td&gt;${perf.play.name}&lt;/td&gt;&lt;td&gt;${perf.audience}석&lt;/td&gt;`;
    result += `&lt;td&gt;${usd(perf.amount)}&lt;/td&gt;&lt;/tr&gt;\n`;
  }
  result += &#39;&lt;/table&gt;\n&#39;;
  result += `&lt;p&gt;총액: &lt;em&gt;${usd(data.totalAmount)}&lt;/em&gt;&lt;/p&gt;\n`;
  result += `&lt;p&gt;적립포인트: &lt;em&gt;${data.totalVolumeCredits}&lt;/em&gt;점&lt;/p&gt;\n`;

  return result;
}

function usd(aNumber) {
  return new Intl.NumberFormat(&#39;en-US&#39;, { style: &#39;currency&#39;, currency: &#39;USD&#39;, maximumFractionDigits: 2 }).format(
    aNumber / 100
  );
}

</code></pre>
<h3 id="18-다형성을-활용해-계산-코드-재구성하기">1.8 다형성을 활용해 계산 코드 재구성하기</h3>
<ul>
<li>연극 장르를 추가하고 장르마다 공연료와 적립 포인트 곗나법을 다르게 지정하도록 기능을 수정한다.</li>
<li>amountFor()와 같은 조건부 로직은 코드 수정횟수가 늘어날수록 골치거리이므로 구조적인 요소로 적절히 보완해야한다.</li>
<li>공연료와 적립 포인트 계산 함수를 담을 클래스를 만든다.</li>
</ul>
<p>dumplicate code</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[5. 타입 활용하기]]></title>
            <link>https://velog.io/@mingjuu_u/5.-%ED%83%80%EC%9E%85-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mingjuu_u/5.-%ED%83%80%EC%9E%85-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 08 Apr 2024 07:48:56 GMT</pubDate>
            <description><![CDATA[<h1 id="📘-조건부-타입">📘 조건부 타입</h1>
<blockquote>
<p>조건에 따라 다른 타입을 반환해야 할 때, 타입스크립트에서는 조건부 타입을 사용해 조건에 따라 출력 타입을 다르게 도출할 수 있다.
extends, infer, never 등을 활용해 원하는 타입을 만들고 어떤 상황에서 조건부 타입이 필요한지 알아본다.</p>
</blockquote>
<h3 id="💬-extends와-제네릭을-이용한-조건부-타입">💬 extends와 제네릭을 이용한 조건부 타입</h3>
<ul>
<li>T extends U ? X : Y 의 형태로 사용한다.</li>
<li>T를 U에 할당할 수 있으면 X타입, 그렇지 않다면 Y타입으로 결정된다.</li>
</ul>
<h3 id="💬-조건부-타입을-사용하지-않았을-때의-문제점">💬 조건부 타입을 사용하지 않았을 때의 문제점</h3>
<ul>
<li>사용자의 의도와는 다르게 정확한 타입을 반환하지 못한다.</li>
<li>인자에 따라 반환되는 타입을 다르게 설정하고 싶다면 extends를 사용한 조건부 타입을 활용하면 된다.</li>
</ul>
<h3 id="💬-extends-조건부-타입을-활용하여-개선하기">💬 extends 조건부 타입을 활용하여 개선하기</h3>
<ul>
<li>제네릭과 extned를 함께 사용해 제네릭으로 받는 타입을 제한해 휴먼에러를 방지할 수 있다.</li>
<li>불필요한 타입가드, 타입 단언을 방지할 수 있다.</li>
</ul>
<h3 id="💬-infer를-활용해서-타입-추론하기">💬 infer를 활용해서 타입 추론하기</h3>
<ul>
<li>extends로 조건을 서술하고 infer로 타입을 추론하는 방식을 취한다.</li>
</ul>
<h1 id="📗-템플릿-리터럴-타입-활용하기">📗 템플릿 리터럴 타입 활용하기</h1>
<h3 id="💬">💬</h3>
<ul>
<li>템플릿 리터럴 타입을 사용하면 컴파일타임의 변수에 할당되는 타입을 특정 문자열로 정확하게 검사하여 휴먼 에러를 방지할 수 있고, 자동 완성 기능을 통해 생산성을 높일 수 있다.</li>
</ul>
<h1 id="📙-커스텀-유틸리티-타입-활용하기">📙 커스텀 유틸리티 타입 활용하기</h1>
<h3 id="💬-유틸리티-함수를-활용해-styled-components의-중복-타입-선언-피하기">💬 유틸리티 함수를 활용해 styled-components의 중복 타입 선언 피하기</h3>
<ul>
<li></li>
<li><h3 id="💬-pickone-유틸리티-함수">💬 PickOne 유틸리티 함수</h3>
</li>
<li></li>
<li></li>
</ul>
<h3 id="💬-nonnullable-타입-검사-함수를-사용하게-간편하게-타입-가드하기">💬 NonNullable 타입 검사 함수를 사용하게 간편하게 타입 가드하기</h3>
<h2 id="-">-</h2>
<h1 id="📔-불변-객체-타입으로-활용하기">📔 불변 객체 타입으로 활용하기</h1>
<h3 id="💬-atom-컴포넌트에서-theme-style-활용하기">💬 Atom 컴포넌트에서 theme style 활용하기</h3>
<ul>
<li></li>
<li><h3 id="💬-sub-index-2">💬 Sub-Index 2</h3>
</li>
<li></li>
<li></li>
</ul>
<h1 id="📕-record-원시-타입-키-개선하기">📕 Record 원시 타입 키 개선하기</h1>
<h3 id="💬-무한한-키를-집합으로-가지는-record">💬 무한한 키를 집합으로 가지는 Record</h3>
<ul>
<li></li>
<li><h3 id="💬-유닛-타입으로-변경하기">💬 유닛 타입으로 변경하기</h3>
</li>
<li></li>
<li></li>
</ul>
<h3 id="💬-partial을-활용하여-정확한-타입-표현하기">💬 Partial을 활용하여 정확한 타입 표현하기</h3>
<h2 id="--1">-</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[4. 타입 확장하기/좁히기]]></title>
            <link>https://velog.io/@mingjuu_u/4.-%ED%83%80%EC%9E%85-%ED%99%95%EC%9E%A5%ED%95%98%EA%B8%B0%EC%A2%81%ED%9E%88%EA%B8%B0</link>
            <guid>https://velog.io/@mingjuu_u/4.-%ED%83%80%EC%9E%85-%ED%99%95%EC%9E%A5%ED%95%98%EA%B8%B0%EC%A2%81%ED%9E%88%EA%B8%B0</guid>
            <pubDate>Wed, 06 Mar 2024 20:07:37 GMT</pubDate>
            <description><![CDATA[<h1 id="📘-타입-확장하기">📘 타입 확장하기</h1>
<blockquote>
<p>타입 확장은 기존 타입을 사용해서 새로운 타입을 정의하는 것을 말한다.
기본적으로 interface와 type 키워드를 사용해 타입을 정의하고 extends, 교차 타입, 유니온 타입을 사용하여 타입을 확장한다.
여기서는 타입 확장의 장점과 extends, 교차 타입, 유니온 타입간의 차이를 파악하고자 한다.</p>
</blockquote>
<h3 id="💬-타입-확장의-장점">💬 타입 확장의 장점</h3>
<ul>
<li>기존에 작성한 타입을 바탕으로 타입 확장을 하므로 코드 중복을 줄일 수 있다.</li>
<li>유니온 타입과 교차 타입을 사용한 새로운 타입은 오로지 type 키워드로만 선언할 수 있다.</li>
</ul>
<h3 id="💬-유니온-타입">💬 유니온 타입</h3>
<pre><code class="language-typescript">type MyUnion = A | B</code></pre>
<ul>
<li>유니온 타입은 2개 이상의 타입을 조합하여 사용하는 방법이다.</li>
<li>집합의 관점에서 유니온 타입은 합집합이므로 A 타입과 B 타입의 모든 값이 MyUnion 타입의 값이 된다.</li>
<li>유니온 타입으로 선언된 값은 유니온 타입에 포함된 모든 타입이 공통으로 갖고 있는 속성에만 접근 가능하다.</li>
</ul>
<pre><code class="language-typescript">interface CookingStep {
  orderId: string;
  price: number;
}

interface DeliveryStep {
  orderId: string;
  time: number;
  distance: string;
}

function getDeliveryDistance(step: CookingStep | DeliveryStep) {
  return step.distance;
  // Property ‘distance’ does not exist on type ‘CookingStep | DeliveryStep’
  // Property ‘distance’ does not exist on type ‘CookingStep’
}</code></pre>
<ul>
<li>getDeliveryDistance 함수는 CookingStep과 DeliveryStep의 유니온 타입 값을 step이라는 인자로 받는다.</li>
<li>함수에서는 step.disatnce를 호출하지만 distance는 DeliveryStep에만 존재하므로 인자로 받는 step의 타입이 CookingStep일 때는 disatnce 속성을 찾을 수 없어 에러가 발생한다.</li>
<li>즉, step이라는 유니온 타입은 CookingStep 혹은 DeliveryStep 타입에 해당할 뿐이지 CookingStep이면서 DeliveryStep인 것은 아니다.</li>
</ul>
<h3 id="💬-교차-타입">💬 교차 타입</h3>
<pre><code class="language-typescript">type MyIntersection = A &amp; B</code></pre>
<ul>
<li>마찬가지로 교차 타입 또한 기존 타입을 합쳐 하나의 타입을 만든다.</li>
<li>그러나 유니온 타입과 달리 A 타입과 B 타입을 합쳐 모든 속성을 가진 단일 타입이 된다.</li>
<li>집합의 관점에서 교차 타입은 교집합이므로 MyIntersection의 모든 원소는 집합 A의 원소이자 집합 B의 원소이다.</li>
</ul>
<pre><code class="language-typescript">interface CookingStep {
  orderId: string;
  time: number;
  price: number;
}

interface DeliveryStep {
  orderId: string;
  time: number;
  distance: string;
}

type BaedalProgress = CookingStep &amp; DeliveryStep;</code></pre>
<p>function logBaedalInfo(progress: BaedalProgress) {
  console.log(<code>주문 금액: ${progress.price}</code>);
  console.log(<code>배달 거리: ${progress.distance}</code>);
}</p>
<ul>
<li>BaedalProgress 타입의 progress 값은 CookingStep이 가진 price 속성과 DeliveryStep이 가진 distance 속성을 모두 포함하고 있다.</li>
</ul>
<h3 id="💬-extends와-교차-타입">💬 extends와 교차 타입</h3>
<pre><code class="language-typescript">// extends 키워드를 사용해 교차 타입을 작성하였다.
interface B extends A {
  // 새로운 속성을 작성한다.
}</code></pre>
<ul>
<li>B는 A를 확장함으로써 A의 속성을 모두 포함하고 있다.</li>
<li>따라서, B는 A의 모든 속성을 포함하는 사우이 집합이 되고 A는 B의 부분집합이 된다.</li>
<li>이를 교차 타입의 관점에서 작성하면 아래와 같다.</li>
</ul>
<pre><code class="language-typescript">// 유니온 타입과 교차 타입을 사용한 새로운 타입은 type 키워드로만 선언 가능하다.
type B = {
  // 새로운 속성을 작성한다.
} &amp; A</code></pre>
<ul>
<li>여기서 주의할 점은 extends 키워드를 사용한 타입은 교차 타입과 100% 상응하지는 않는다.</li>
</ul>
<pre><code class="language-typescript">interface DeliveryTip {
  tip: number;
  }

interface Filter extends DeliveryTip {
  tip: string;
  // Interface ‘Filter’ incorrectly extends interface ‘DeliveryTip’
  // Types of property ‘tip’ are incompatible
  // Type ‘string’ is not assignable to type ‘number’
}

type DeliveryTip = {
  tip: number;
  };

type Filter = DeliveryTip &amp; {
  tip: string;
};</code></pre>
<ul>
<li>DeliveryTip을 extends로 확장한 Filter 타입에 string타입의 속성 tip을 선언하면 tip의 타입이 호환되지 않는 에러가 발생한다.</li>
<li>그러나 extends를 교차 타입으로 바꾸면 에러가 발생하지 않는다.</li>
<li>이 때 tip 속성의 타입은 never로 교차 타입으로 선언될 때 새롭게 추가되는 속성을 미리 알 수 없으므로 선언시 에러가 발생하지는 않는다.</li>
<li>그러나 tip이라는 같은 속성에 대해 서로 호환되지 않는 타입이 선언되어 never 타입이 된 것이다.</li>
</ul>
<h1 id="📗-타입-가드로-타입-좁히기">📗 타입 가드로 타입 좁히기</h1>
<blockquote>
<p>타입스크립트에서 타입 좁히기는 변수나 표현식의 타입 범위를 더 작은 범위로 좁혀나가는 과정을 말한다.
타입 좁히기를 통해 더 정확하고 명시적인 타입 추론을 할 수 있게 되고, 복잡한 타입을 작은 범위로 축소하여 타입 안정성을 높일 수 있다.</p>
</blockquote>
<h3 id="💬-타입-가드에-따라-분기-처리하기">💬 타입 가드에 따라 분기 처리하기</h3>
<ul>
<li>타입스크립트에의 분기 처리는 조건문과 타입 가드를 활용하여 변수나 표현식의 타입 범위를 좁혀 다양한 상황에 따라 다른 동작을 처리하는 것을 말한다.</li>
<li>타입 가드는 런타임에 조건문을 사용하여 타입을 검사하고 타입 기능을 좁혀주는 기능을 말한다.</li>
<li>컴파일 시에 타입 정보는 모두 제거되어 런타임에 존재하지 않으므로 if문 등을 사용해 로직을 처리할 수 없다</li>
<li>따라서 특정 문맥 안에서 타입스크립트가 해당 변수를 원하는 타입으로 추론하도록 유도하면서도 런타임에서도 유효한 방법이 필요한데 이 때 타입 가드를 사용한다.</li>
<li>typeof, instanceof, in과 같은 자바스크립트 연산자를 사용하여 제어문으로 특정 타입 값을 가질수밖에 없도록 유도하여 자연스럽게 타입을 좁힌다.</li>
<li>여기서 런타임에 유효하다는 말은 타입스크립트뿐만 아니라 자바스크립트에서도 사용 가능한 문법이어야 한다는 의미이다.</li>
</ul>
<h3 id="💬-typeof를-활용하여-원시-타입을-추론">💬 typeof를 활용하여 원시 타입을 추론</h3>
<ul>
<li>typeof A === B를 조건으로 분기 처리하면 해당 분기 내에서는 A의 타입이 B로 추론된다.</li>
<li>다만 typeof는 자바스크립트 타입 시스템만 대응 가능하므로 null이나 object 타입과 같은 복잡한 타입을 검증할 수는 없다.</li>
<li>typeof 연산자를 사용하여 검사할 수 있는 타입에는 string, number, boolean, undefined, object, function, bigint, symbol이 있다.</li>
</ul>
<pre><code class="language-typescript">const replaceHyphen: (date: string | Date) =&gt; string | Date = (date) =&gt; {
  if (typeof date === “string”) {
  // 이 분기에서는 date의 타입이 string으로 추론된다
  return date.replace(/-/g, “/”);
  }

  return date;
};</code></pre>
<h3 id="💬-instanceof를-활용하여-인스턴스화-된-객체-타입-판별">💬 instanceof를 활용하여 인스턴스화 된 객체 타입 판별</h3>
<ul>
<li>A instanceof B 형태로 사용하여 A는 타입을 검사할 대상 변수, B는 특정 객체의 생성자가 들어간다.</li>
<li>A의 프로토타입 체인에 생성자 B가 존재한다면 true를, 그렇지 않다면 false를 반환한다.</li>
</ul>
<h3 id="💬-in을-활용하여-객체의-속성-유무를-구분">💬 in을 활용하여 객체의 속성 유무를 구분</h3>
<ul>
<li>A in B 형태로 사용하여 A라는 속성이 B에 존재하는 지를 검사한다.</li>
<li>프로토타입 체인으로 접근할 수 있다면 전부 true를 반환한다.</li>
</ul>
<h3 id="💬-is로-사용자-정의-타입가드-만들기">💬 is로 사용자 정의 타입가드 만들기</h3>
<ul>
<li>A is B 형태로 사용하며 A는 매개변수 이름이고 B는 타입이다.</li>
<li>참/거짓의 진릿값을 반환하면서 반환 타입을 타입 명제로 지정하게 되면 반환 값이 참 일때 A의 매개변수의 타입을 B 타입으로 취급한다.</li>
</ul>
<h1 id="📙-식별할-수-있는-유니온으로-타입-좁히기">📙 식별할 수 있는 유니온으로 타입 좁히기</h1>
<blockquote>
<p>종종 Tagged Union으로도 불리는 식별할 수 있는 유니온은 타입 좁히기에 널리 사용되는 방식이다.</p>
</blockquote>
<h3 id="💬-에러-정의하기">💬 에러 정의하기</h3>
<ul>
<li></li>
<li><h3 id="💬-식별할-수-있는-유니온">💬 식별할 수 있는 유니온</h3>
</li>
<li></li>
<li></li>
</ul>
<h3 id="💬-식별할-수-있는-유니온의-판별자-선정">💬 식별할 수 있는 유니온의 판별자 선정</h3>
<h2 id="-">-</h2>
<h1 id="📔-exhaustiveness-checking으로-정확한-타입-분기-유지하기">📔 Exhaustiveness Checking으로 정확한 타입 분기 유지하기</h1>
<h3 id="💬-예시">💬 예시</h3>
<pre><code class="language-typescript">type ProductPrice = “10000” | “20000” | “5000”;

const getProductName = (productPrice: ProductPrice): string =&gt; {
  if (productPrice === “10000”) return “배민상품권 1만 원”;
  if (productPrice === “20000”) return “배민상품권 2만 원”;
  if (productPrice === “5000”) return “배민상품권 5천 원”; // 조건 추가 필요
  else {
    return “배민상품권”;
  }
};</code></pre>
<ul>
<li>새로운 상품권이 생겨 ProductPrice 타입이 업데이트되면 getProductName 함수도 함께 업데이트 되어야 한다.</li>
<li>이 때 productPrice가 &quot;5000&quot;일 경우의 조건도 검사하여 반환해야 한다.</li>
<li>이와 같이 모든 타입에 대한 타입 검사를 강제하려면 아래와 같이 코드를 작성하면 된다.</li>
</ul>
<pre><code class="language-typescript">type ProductPrice = “10000” | “20000” | “5000”;

const getProductName = (productPrice: ProductPrice): string =&gt; {
  if (productPrice === “10000”) return “배민상품권 1만 원”;
  if (productPrice === “20000”) return “배민상품권 2만 원”;
  // if (productPrice === “5000”) return “배민상품권 5천 원”;
  else {
    exhaustiveCheck(productPrice); // Error: Argument of type ‘string’ is not assignable to parameter of type ‘never’
    return “배민상품권”;
  }
};

const exhaustiveCheck = (param: never) =&gt; {
  throw new Error(“type error!”);
};</code></pre>
<ul>
<li>exhaustiveCheck(productPrice)에서 에러가 발생하는데 이는 ProductPrice 타입 중 500에 대한 분기 처리를 하지 않아서 발생한 것이다.</li>
<li>이렇게 모든 케이스에 대한 타입 분기 처리를 해주지 않았을 때, 컴파일타임 에러가 발생하게 하는 것을 Exhaustiveness Checking이라고 한다.</li>
<li>Exhaustiveness Checking 함수는 매개변수를 never 타입으로 선언하고 있다.</li>
<li>이는 매개변수로 그 어떤 값도 받을 수 없으며 만일 값이 들어온다면 에러를 뱉는다.</li>
<li>이 함수를 타입 처리 조건문의 마지막 else문에 사용한다면 앞의 조건문에서 모든 타입에 대한 분기 처리를 강제할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[3장 고급 타입]]></title>
            <link>https://velog.io/@mingjuu_u/3%EC%9E%A5-%EA%B3%A0%EA%B8%89-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@mingjuu_u/3%EC%9E%A5-%EA%B3%A0%EA%B8%89-%ED%83%80%EC%9E%85</guid>
            <pubDate>Tue, 13 Feb 2024 01:02:18 GMT</pubDate>
            <description><![CDATA[<h1 id="📘-타입스크립트만의-독자적-타입-시스템">📘 타입스크립트만의 독자적 타입 시스템</h1>
<blockquote>
<p>타입스크립트는 자바스크립트 자료형에서 제시되지 않은 독자적인 타입시스템을 가지고 있으나 엄밀히 말하면 타입스크립트의 타입 시스템의 개념은 모두 자바스크립트에서 기인한 것이다.
다음은 앞으로 다룰 타입의 계층 구조를 그림으로 나타낸 것이다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/mingjuu_u/post/8bbe7551-1341-4b1c-8c90-edca881f28d4/image.png" alt=""></p>
<h3 id="💬-any-타입">💬 any 타입</h3>
<ul>
<li><p>any 타입은 자바스크립트의 기본적인 사용방식과 같으므로 자바스크립트에 존재하는 모든 값을 오류 없이 받을 수 있다.</p>
</li>
<li><p>타입스크립트는 동적 타이핑 특징을 가진 자바스크립트에 정적 타이핑을 적용하는 것이 목적이나 any는 이를 무시하므로 any타입의 효용성에 대해 의문이 생긴다</p>
</li>
<li><p>따라서, 타입스크립트의 사용 목적에 맞게 any 타입을 지양하는 것은 옳지만 개발 단계에서 어쩔 수 없이 any 타입을 사용해야 할 때가 있다.</p>
<ul>
<li>개발 단계에서 추후에 값이 변경될 가능성이 있거나 아직 세부적인 타입이 확정되지 않아 임시로 값을 지정할 때</li>
<li>어떤 값을 받아올지 혹은 넘겨줄지 정할 수 없을 때</li>
<li>값을 예측할 수 없을 때</li>
</ul>
</li>
<li><p>any 타입이 개발자에게 편의성과 확장성을 제공하기도 하지만 남발한다면 실제 런타임에서 오류가 발생한다.</p>
</li>
</ul>
<h3 id="💬-unknown-타입">💬 unknown 타입</h3>
<ul>
<li>이름처럼 아직 무엇이 할당될지 모르는 상태의 타입으로 any 타입과 유사하게 모든 타입의 값이 할당될 수 있다.</li>
<li>함수를 unknown 타입 변수에 할당할 때는 컴파일러가 경고를 주지 않지만 실행하면 에러가 발생한다.</li>
<li>any 타입을 사용해 임시로 문제를 회피한 후 차후에 수정 사항을 누락한다면 런타임에 예상치 못한 오류가 발생하므로 unknown 타입은 이러한 상황에서 any 타입을 보완하기 위해 등장하였다.</li>
</ul>
<h3 id="💬-void-타입">💬 void 타입</h3>
<ul>
<li>일반적으로 함수의 타입을 지정할 때, 함수에 전달되는 매개변수의 타입과 반환하는 타입을 지정해야 한다.</li>
<li>이 때 매개변수를 전달하지 않는 경우에는 괄호를 비워두면 되지만 콘솔에 로그를 출력하거나 다른 함수를 실행하는 역할만 하는 함수의 경우 아무런 값을 반환하지 않는다.</li>
</ul>
<pre><code class="language-typescript">function showModal(type: ModalType): void {
  feedbackSlice.actions.createModal(type);</code></pre>
<ul>
<li>예시 코드와 같은 상황에서 함수 반환 타입을 void로 지정할 수 있다.</li>
<li>함수 자체를 다른 함수의 인자로 전달하는 경우가 아니면 void 타입을 잘 명시하지 않는 경향이 있는데, 이는 함수 내부에 별도의 반환문이 없다면 컴파일러가 함수 타입을 void로 추론해주기 때문이다. </li>
</ul>
<h3 id="💬-never-타입">💬 never 타입</h3>
<ul>
<li>never 타입은 값을 반환할 수 없는 타입을 말한다. 이 때, 값을 반환하지 않는 것과 값을 반환할 수 없는것을 명확히 구분해야 한다.</li>
<li>값을 반환할 수 없는 예에는 크게 두가지가 있다.<ul>
<li>throw 키워드를 사용해 에러를 던지는 경우</li>
<li>무한히 함수가 실행되는 경우</li>
</ul>
</li>
</ul>
<h3 id="💬-array-타입">💬 Array 타입</h3>
<ul>
<li>typeof를 사용하여 타입을 알 수 있지만 Object.prototype.toString.call() 함수를 사용하면 객체의 인스턴스까지 알려준다.</li>
<li>대괄호([ ])를 사용하여 직접 타입을 명시할 수 있는데 이 때의 타입은 배열보다 좁은 범위인 tuple을 가리킨다.</li>
<li>배열은 사전에 허용하지 않은 타입이 서로 섞이는 것을 방지하여 타입 안정성을 제공하고 튜플은 길이까지 제한하여 원소 갯수와 타입을 보장한다.</li>
<li>어떤 값이던 배열의 원소로 허용하지만 이는 타입스크립트의 정적 타이핑과 부합하지 않으므로 배열의 원소로 하나의 타입만 사용해야한다.</li>
</ul>
<pre><code class="language-typescript">const array: number[] = [1, 2, 3]; // 숫자에 해당하는 원소만 허용한다.
const array: Array&lt;number&gt; = [1, 2, 3] // 표기만 다른 동일한 선언 방식이다.</code></pre>
<ul>
<li>여러 타입을 관리해야 하는 배열을 선언하려면 유니온 타입을 활용할 수 있다.</li>
</ul>
<pre><code class="language-typescript">const array1: Array&lt;number | string&gt; = [1, &quot;string&quot;];
const array2: number [] | string[] = [1, &quot;string&quot;];
const array3: (number | string)[] = [1, &quot;string&quot;];</code></pre>
<ul>
<li>tuple은 배열의 특정 인덱스에 정해진 타입을 선언하는 것이다.</li>
<li>또한 옵셔널 프로퍼티를 명시하고 싶다면 물음표 기호와 함께 해당 속성을 선언하면 된다.</li>
</ul>
<pre><code class="language-typescript">let tuple: [number] = [1];
tuple = [1, 2]; // 불가능
tuple = [1, &quot;string&quot;]; // 불가능
let tuple: [number, string, boolean] = [1, &quot;string&quot;, true]; // 여러 타입과 혼합 가능

let optionlaTuple1: [number, number?] = [1]
let optionlaTuple1: [number, number?] = [1, 2]
</code></pre>
<ul>
<li>대표적인 tuple의 유용한 쓰임새는 리액트의 useState이다.</li>
<li>useState API는 배열 원소의 자리마다 명확한 의미를 부여하므로 컴포넌트에서 사용하지 않은 값에 접근하는 오류를 방지할 수 있다.</li>
<li>또한 구조분해 할당을 이용하여 사용자가 자유롭게 이름을 지정할 수 있다.</li>
</ul>
<pre><code class="language-typescript">import { useState } from &quot;react&quot;

const [value, setValue] = useState(false)
const [username, setUsername] = useState(&quot;&quot;)
</code></pre>
<h3 id="💬-enum-타입">💬 enum 타입</h3>
<ul>
<li>enum 타입은 열거형으로 기본적인 추론 방식은 숫자 0부터 1씩 늘려가며 값을 할당하는 것이다.</li>
<li>enum 타입은 주로 문자열 상수를 생성하는데 사용한다.</li>
<li>그러나 할당된 값을 넘어 역방향으로 접근하는 경우 타입스크립트는 막지 않으므로 안전하지 않다. 이러한 동작을 막기 위해 const enum으로 열거형을 선언하는 방법이 있다.</li>
<li>const enum은 역방향으로의 접근을 허용하지 않으므로 자바스크립트에서 객체에 접근하는 것과 유사한 동작을 보장한다.</li>
</ul>
<pre><code class="language-typescript">enum ProgrammingLanguage {
  Typescript = &quot;Typescript&quot;, // 각 멤버에 명시적으로 값을 할당할 수 있다.
  Javascript = &quot;300&quot;,
  Java,
  Python,
  Kotlin,
  Rust,
  Go,
}

ProgrammingLanguage[2] // Java
ProgrammingLanguage[200] // undefined를 출력하나 에러는 발생하지 않는다.

// 이와 같이 선언하면 위의 문제를 방지할 수 있다.
const enum ProgrammingLanguage {
  ...
}
</code></pre>
<ul>
<li>그러나 숫자 상수로 관리되는 열거형은 const enum으로 열거형을 선언하더라도 선언한 값 이외의 값을 할당하거나 접근할 때 이를 방지하지 못한다.</li>
<li>따라서 의도하지 않은 값의 할당이나 접근을 방지하는 문자열 상수 방식이 숫자 상수 방식보다 더 안전하다.</li>
<li>열거형은 타입스크립트 코드가 자바스크립트로 변환될 때 즉시실행 함수 형식으로 변환되는데, 일부 번들러에서 트리쉐이킹 과정 중 즉시 실행 함수로 변환된 값을 사용하지 않는 경우가 발생한다.</li>
<li>이러한 문제를 해결하려면 const enum 또는 as const assertion을 사용해 유니온 타입으로 열거형과 동일한 효과를 얻는 방법이 있다.</li>
</ul>
<h1 id="📗-타입-조합">📗 타입 조합</h1>
<blockquote>
<p>앞에서 다룬 개념을 응용하거나 약간의 내용을 덧붙여 좀 더 심화한 타입 검사를 수행하는데 필요한 지식을 살펴본다.</p>
</blockquote>
<h3 id="💬-교차-타입">💬 교차 타입</h3>
<ul>
<li>교차 타입을 사용하여 여러가지 타입을 결합, 하나의 단일 타입으로 만들 수 있다.</li>
<li>&amp; 를 사용하여 표기하며 type C = A &amp; B 라면 타입 C는 타입 A와 타입 B의 모든 멤버를 가진 타입이다.</li>
</ul>
<pre><code class="language-typescript">type ProductItem = {
  id: number
  name: string
  type: string
  price: number
  imageUrl: string
  quantity: number
}

type ProductItemwithDiscount = Product &amp; {discountAmount: number }</code></pre>
<h3 id="💬-유니온-타입">💬 유니온 타입</h3>
<ul>
<li>유니온 타입은 타입 A 또는 타입 B 둘 중 하나가 될 수 있는 타입을 말한다.</li>
<li>A | B 로 표기한다.</li>
</ul>
<pre><code class="language-typescript">type CardItem = {
  id: number
  name: string
  type: string
  imageUrl: string
}

// PromotionEventItem이 ProductItem 일 수도 CardItem일 수도 있다.
type PromotionEventItem = ProductItem | CardItem

const printPromotionItem = (item: PromotionEvenItem) =&gt; {
  console.log(item.name) // 0
  console.log(item.quantity) // 컴파일 에러 발생</code></pre>
<h3 id="💬-인덱스-시그니처">💬 인덱스 시그니처</h3>
<ul>
<li>인덱스 시그니쳐는 특정 타입의 속성 이름은 알 수 없지만 속성의 타입을 알고 있을 때 사용한다.</li>
<li>[key: K]: T 꼴로 타입을 명시하는데 해당 타입의 속성 키는 모두 K 타입이고 속성 값은 모두 T 타입을 가져야 한다는 의미이다.</li>
</ul>
<pre><code class="language-typescript">interface IndexSignatureEx {
  [key: string]: number</code></pre>
<ul>
<li>인덱스 시그니쳐를 선언할 때 다른속성을 추가로 명시해줄 수 있는데 이 때 추가로 명시된 속성은 인덱스 시그니처에 포험되는 타입이여야 한다.</li>
</ul>
<pre><code class="language-typescript">interface IndexSignatureEx2 {
  [key: string]: number | boolean
  length: number
  isValid: boolean
  name: string // 에러 발생</code></pre>
<h3 id="💬-인덱스드-엑세스-타입">💬 인덱스드 엑세스 타입</h3>
<ul>
<li>다른 타입의 특정 속성이 가지는 타입을 조회하기 위해 사용하거나 배열의 요소 타입을 조회하기 위해 사용한다.</li>
</ul>
<h3 id="💬-맵드-타입">💬 맵드 타입</h3>
<ul>
<li>인덱스 시그니처 문법을 사용해 반복적인 타입 선언을 줄일 수 있다.</li>
</ul>
<h3 id="💬-템플릿-리터럴-타입">💬 템플릿 리터럴 타입</h3>
<ul>
<li>자바스크립트의 템플릿 리터럴 문자열을 사용하여 문자열 리터럴 타입을 선언할 수 있는 문법이다.</li>
</ul>
<pre><code class="language-typescript">type Stage = | &quot;init&quot; | &quot;select-image&quot; | &quot;edit-image&quot;
type StageName = `${Stage}-stage` // &#39;init-stage&#39; | &#39;select-image-stage&#39; | &#39;edit-image-stage&#39;</code></pre>
<h3 id="💬-제네릭">💬 제네릭</h3>
<ul>
<li>함수, 타입, 클래스 등에서 내부적으로 사용할 타입을 미리 정해두지 않고 타입 변수를 사용해서 해당 위치를 비워둔 다음, 실제고 그 값을 사용할 때 외부에서 타입 변수 자리에 타입을 지정하여 사용하는 방식이다.</li>
<li>해당 방식을 사용하면 함수, 타입, 클래스 등 여러 타입에 대해 따로 정의하지 않아도 되기 때문에 재사용성이 크게 향상된다.</li>
<li>타입 변수는 꺽쇠괄호 내부에 정의되며 T(Type), E(Element), K(Key), V(Value)등이 사용된다.<pre><code class="language-typescript">type ExampleArrayType&lt;T&gt; = T[]
</code></pre>
</li>
</ul>
<p>const array1: ExampleArrayType<string> = [&quot;치킨&quot;, &quot;피자&quot;, &quot;우동&quot;]</p>
<pre><code>
# 📙 제네릭 사용법

### 💬 함수의 제네릭
- 어떤 함수의 매개변수나 반환값에 다양한 타입을 넣고 싶을 때 제네릭을 사용할 수 있다. 
```typescript
function ReadOnlyRepository&lt;T&gt;(target: ObjectType&lt;T&gt; | EntitySchema&lt;T&gt; | string):
Repository&lt;T&gt; {
  return getConnection(&quot;ro&quot;).getRepository(target)
}</code></pre><h3 id="💬-호출-시그니처의-제네릭">💬 호출 시그니처의 제네릭</h3>
<ul>
<li>호출 시그니처는 타입스크립트의 함수 문으로 매개변수와 반환타입을 미리 선언하여 함수 호출시 필요한 타입을 별도로 지정하는 것을 말한다.</li>
<li>제네릭 타입을 어디에 위치시키는지에 따라 타입의 범위와 제네릭 타입을 언제 구체 타입으로 한정할지를 결정할 수 있다.</li>
</ul>
<h3 id="💬-제네릭-클래스">💬 제네릭 클래스</h3>
<ul>
<li>외부에서 입력된 타입을 클래스 내부에 적용할 수 있는 클래스이다.</li>
<li>클래스 이름 뒤에 타입 매개변수인 &lt; T &gt;를 선언해준다.</li>
<li>제네릭 클래스를 사용하면 클래스 전체에 걸쳐 타입 매개변수가 적용되므로 특정 메소드를 대상으로 제네릭을 적용하려면 해당 메소드를 제네릭 메소드로 선언하면 된다.</li>
</ul>
<h3 id="💬-제한된-제네릭">💬 제한된 제네릭</h3>
<h2 id="-">-</h2>
<h3 id="💬-확장된-제네릭">💬 확장된 제네릭</h3>
<h2 id="--1">-</h2>
<h3 id="💬-제네릭-예시">💬 제네릭 예시</h3>
<ul>
<li>제네릭의 장점은 다양한 타입을 받게 함으로써 코드를 효율적으로 재사용할 수 있는 것이다.</li>
<li>실제 현업에서는 API 응답값의 타입을 지정할 때이다.</li>
</ul>
<pre><code class="language-typescript">// API 응답값에 따라 달라지는 data를 제네릭 타입 Data로 선언하고 있다.
export interface MobileApiResponse&lt;Data&gt; {
  data: Data
  statusCode: string
  statusMessage? : string
} 

// 이렇게 만든 MobileAPiResponse는 실제 API 응답 값의 타입을 지정할 때 아래와 같이 사용된다.

export const fetchPriceInfo = (): Promise&lt;MobileApiResponse&lt;PriceInfo&gt;&gt; =&gt; {
  const priceUrl = &quot;https://....&quot; // url 주소

  return request({
    method: &quot;GET&quot;,
    url: priceUrl,
  })
}

export const fetchOrderInfo = (): Promise&lt;MobileApiResponse&lt;PriceInfo&gt;&gt; =&gt; {
  const orderUrl = &quot;https://....&quot; // url 주소

  return request({
    method: &quot;GET&quot;,
    url: orderUrl,
  })
}

</code></pre>
<ul>
<li>제네릭은 코드의 재사용성을 높이고 타입 추론을 하는데 사용되므로 any를 사용하면 그 이점을 누릴 수 없게 된다.</li>
<li>무분별한 제네릭 사용한 가독성을 해치므로 부득이한 상황을 제외하고 의미 단위로 분할해서 사용하는게 좋다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[타입스크립트]]></title>
            <link>https://velog.io/@mingjuu_u/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</link>
            <guid>https://velog.io/@mingjuu_u/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</guid>
            <pubDate>Thu, 25 Jan 2024 06:03:02 GMT</pubDate>
            <description><![CDATA[<h2 id="1-타입이란">1. 타입이란</h2>
<p>타입을 지정해 코드에서 사용하는 유효한 값의 범위를 제한해 런타임에서 발생할 수 있는 유효하지 않은 값에 대한 에러를 방지한다.</p>
<pre><code class="language-javascript">function double(n) {
  return n * 2
}

double(2) //4
double(&quot;z&quot;) // NaN</code></pre>
<p>double()의 내부 동작은 숫자를 인자로 받을 것으로 기대하나 그 외의 타입에 해당하는 값을 전달하면 의도하지 않은 작업을 수행해 원하는 값을 얻지 못한다.</p>
<pre><code class="language-typescript">function double(n : number) {
  return n * 2;
}

double(2) //4
double(&quot;z&quot;) // NaN</code></pre>
<p>타입을 제한하면 타입스크립트 컴파일러는 함수를 호출할 때 호환되는 인자로 호출했는지를 판단한다. 따라서 string 타입인 &quot;z&quot;를 호출한 경우 number에 할당이 불가능해 에러가 발생한다.</p>
<p>이 때, 타입스크립트의 컴파일 결과물은 여전히 사람이 이해 가능한 자바스크립트 파일이다.
타입스크립트의 탄생 이유는 고수준-저수준의 코드 변환을 위해서가 아닌 자바스크립트의 런타임 에러를 잡아내기 위한 것으로 타입스크립트를 컴파일 하면 타입이 모두 제거된 자바스크립트 소스코드만이 남게 된다.</p>
<h2 id="2-타입-시스템">2. 타입 시스템</h2>
<ul>
<li><p>타입 에너테이션 방식</p>
<ul>
<li>우리가 흔히 아는 방식으로 변수/상수/인자/반환 값 등에 타입을 명시적으로 선언하여 컴파일러에 직접 알려주는 문법이다.</li>
</ul>
</li>
<li><p>구조적 타이핑</p>
<ul>
<li>이름으로 타입을 구분하는 명목적인 타입 언어의 특징과 달리 타입스크립트는 구조로 타입을 구분한다.</li>
<li>이러한 구조적 타이핑의 특징 때문에 예기치 못한 결과가 발생할 수도 있다.</li>
<li>interface에 추가 속성 타입이 정의되는 경우 기존 필드의 타입으로 예측하여 판단하나 추가 속성은 다른 타입을 가질 수 있으므로 에러가 발생한다.</li>
</ul>
</li>
<li><p>구조적 서브타이핑</p>
<ul>
<li>타입 시스템을 집합으로 이해하여 객체가 가지고 있는 속성을 바탕으로 타입을 구분한다.</li>
<li>이름이 다르더라도, 가진 속성이 동일하다면 서로 호환이 가능한 동일한 타입으로 여긴다.<pre><code class="language-typescript">interface Pet {
name: string;
}
</code></pre>
</li>
</ul>
</li>
</ul>
<p>interface Cat
  name: string;
  age: number;
}</p>
<p>let pet: Pet;
let cat: Cat = {name: &quot;Zag&quot;, age: 2}</p>
<p>// OK
pet = cat</p>
<pre><code>Cat과 Pet이 다른 타입으로 선언되었으나, Pet이 갖고 있는 name 속성을 가지고 있으므로 Cat타입으로 설정한 cat을 Pet타입으로 설정한 pet에 할당할 수 있다.

- 값과 타입
    - 값 : value 은 프로그램이 처리하기 위해 메모리에 저장하는 모든 데이터이다. 따라서, 숫자와 같은 데이터는 물론이고 반환하는 결괏값, 문자열, 매개변수 등도 값에 해당된다.
    - ```typescript
    11; // 숫자 값
    &quot;hello typescript&quot; // 문자열 값
    let foo = &quot;bar&quot; //  변수값

    // 함수 역시 변수에 할당할 수 있는 값임을 알 수 있다.
    function goWork(developer) {
        console.log(`tired ${developer}`)
    }

    // 이 예시는 developer라는 변수에 &quot;zig&quot;라는 문자열 값을 할당했다
    const developer = &quot;zig&quot;
    ```

    - 입스크립트 문법인 type으로 선언한 내용은 자바스크립트 런타임에서 제거되기 때문에 값 공간과 타입 공간의 이름은 서로 충돌하지 않기 때문에 타입과 변수를 같은 이름으로 정의할 수 있다. 
    - 타입은 주로 타입 선언(:) 또는 단언 문(as)으로 작성하고 값은 할당 연산자(=)로 작성한다.
    - 타입스크립트에서 값과 타입의 구분은 맥락에 따라 달라지기 때문에 혼동할 때도 있다.
    - ```typescript
    function email(option: { person: Person; subject: string; body: string}) {
        //..
    }

    // 위의 코드를 구조 분해 할당하면 아래와 같다.
    function email({ person, subject, body}) {
        //..
    }
    ```
    - 자바스크립트의 구조 분해 할당을 사용하면 email 함수의 매개변수로 넘기는 options 객체를 아래와 같이 풀어 쓸 수 있다. 그러나 같은 코드를 타입스크립트에서 구조 분해 할당 하면 오류가 발생한다.
    - 이는 값의 관점에서 Person과 string이 해석되었기 때문이다. 개발자의 의도와 달리 Person과 string이 값 공간에 있는 것으로 해석해 person과 Person이 각 함수의 매개변수 객체 내부 속성의 키-값 쌍에 해당되는 것으로 해석했기 때문이다.
    - 이와 같은 값-타입 공간을 혼동하는 문제를 해결하기 위해 아래와 같이 값과 타입을 구분해서 작성한다.
    - ```typescript
    function email({person, subject, body} : { person: Person; subject: string; body: string; }) {
    //...
    }
    - 이와 다르게 클래스와 enum은 값과 타입 공간에 동시에 존재할 수도 있다.
    - 클래스의 실제 동작은 함수와 같으며 동시에 타입으로도 사용 가능하다
    - enum의 경우 클래스처럼 타입공간에서 타입을 제한하는 역할을 하지만 런타임에 객체로 변환되어 실제 객체로 존재하며 함수로도 표현 가능하고 실제 값으로도 사용될 수 있다.


💥 enum과 union
다른 타입을 하나의 그룹으로 묶는 데 사용될 수 있으나, 그 용도와 작동 방식에 차이가 있다.

- Enum
    - Enum은 한정된 몇 가지 선택지 중 하나를 나타내는 데 사용됩니다.
    - 일반적으로 상수 값의 집합을 정의하는 데 사용됩니다.
    - enum은 값이기 때문에 순회가 가능하다.
    - 자바스크립트로 컴파일될 때 성능에 영향을 준다는 우려가 있다.

- union
    - Union은 여러 다른 타입 중 하나를 가질 수 있는 타입을 나타낸다.
    - 서로 다른 타입들을 하나의 그룹으로 묶을 때 사용된다.
    - 각 타입은 각각의 구성원을 가질 수 있다.
    - union 타입은 어떤 타입을 가졌는지 전부 기억해야 해 리팩토링에 번거로움이 있다.
    - union 타입은 말 그대로 타입이므로 순회가 불가능하다.


💥 type과 interface
- type
    - type을 사용해야만 하는 경우는 union이나 intersection을 활용할 때
    - 타입 별칭을 정할 때 
    - computed value를 사용할 때
    - generic type이나 literal types을 사용할 때 등이 있다.
    - scope의 제한을 두고 한정적으로 사용할 때 쓰는게 좋다.

- interface
    - interface를 사용해야만 하는 경우는 클래스나 객체를 구조화해 명세할 때 
    - 상속을 통한 타입 확장을 할 때 등이 있다.
    - 전역으로 사용할 때 사용하는게 좋다.
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[면접 질문 정리하기]]></title>
            <link>https://velog.io/@mingjuu_u/%EB%A9%B4%EC%A0%91-%EC%A7%88%EB%AC%B8-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mingjuu_u/%EB%A9%B4%EC%A0%91-%EC%A7%88%EB%AC%B8-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 18 Dec 2023 15:16:59 GMT</pubDate>
            <description><![CDATA[<h2 id="🟥-javascript">🟥 JavaScript</h2>
<h3 id="1-동기와-비동기">1. 동기와 비동기</h3>
<ul>
<li><strong>동기적인 코드는 순차적으로 실행</strong>되며 한 작업이 끝나야만 실행된다.</li>
<li><strong>비동기적인 코드는 작업이 백그라운드에서도 실행</strong>되며 다른 작업이 진행 중 일 때 코드 실행이 멈추지 않고 계속된다.<ul>
<li>이때 비동기적인 코드에서는 콜백함수, Promise, async/await 등을 사용하여 코드를 효율적으로 작성하고 유지보수 하기 쉽게 만들 수 있다.</li>
</ul>
</li>
</ul>
<h3 id="2-콜백-함수">2. 콜백 함수</h3>
<ul>
<li><strong>다른 함수의 인자로서 이용</strong>되거나 <strong>어떤 이벤트에 의해 호출되는 함수</strong>를 말한다.</li>
<li>콜백함수를 중첩하여 사용할 때 코드의 가독성과 유지보수성이 떨어지는 상황이 생기는데 이를 <strong>콜백지옥</strong>(callback hell)이라 한다.<ul>
<li><strong>콜백 지옥을 해결하기 위해서는 Promise나 async/await를 사용하여 코드를 구성</strong>한다.   </li>
</ul>
</li>
</ul>
<h3 id="3-promise">3. Promise</h3>
<ul>
<li><strong>Promise는 비동기 작업의 성공 또는 실패를 나타내는 객체</strong>로, 비동기 코드를 더 효과적으로 다룰 수 있게 도와준다.</li>
<li>Promise 체이닝을 통해 .then() 메서드를 사용하여 연속된 비동기 작업을 간결하게 표현해 가독성을 향상 시키고 콜백 지옥을 방지한다.</li>
</ul>
<h3 id="4-aysncawait">4. aysnc/await</h3>
<ul>
<li><strong>async/await은 비동기 코드를 동기적으로 작성할 수 있게 해주는 문법</strong>이다. </li>
<li>async 함수 내에서 await 키워드를 사용하여 Promise가 처리될 때까지 대기할 수 있다.</li>
</ul>
<h2 id="🟧-front-end">🟧 Front-End</h2>
<h3 id="http">HTTP</h3>
<ul>
<li>HyperText Transfer Protocol로 클라이언트와 서버 간의 통신 규칙이다.</li>
<li>요청-응답의 구조를 띄며 응답에 상태 코드를 포함하여 요청의 성공, 실패등의 상태를 알린다.</li>
</ul>
<table>
<thead>
<tr>
<th align="center">상태 코드</th>
<th align="center">상태 텍스트</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">200</td>
<td align="center">OK</td>
<td>요청을 성공적으로 처리했음을 나타낸다.<br>일반적으로 GET 요청에 대한 성공적인 응답을 의미한다.</td>
</tr>
<tr>
<td align="center">201</td>
<td align="center">Created</td>
<td>새로운 리소스가 성공적으로 생성되었음을 나타낸다.<br>주로 POST나 PUT 요청에 대한 응답으로 사용된다.</td>
</tr>
<tr>
<td align="center">400</td>
<td align="center">Bad Request</td>
<td>클라이언트의 요청이 잘못되었음을 나타낸다.<br>서버가 요청을 이해할 수 없거나 유효하지 않은 구문으로 작성되었을 때 발생한다.</td>
</tr>
<tr>
<td align="center">401</td>
<td align="center">Unauthorized</td>
<td>요청한 리소스에 대한 인증이 필요함을 나타낸다.<br>클라이언트가 인증되지 않았거나, 유효하지 않은 인증 정보를 제공했을 때 발생한다.</td>
</tr>
<tr>
<td align="center">403</td>
<td align="center">Forbidden</td>
<td>클라이언트가 특정 리소스에 접근할 권한이 없음을 나타낸다.<br> 서버가 요청을 이해했으나 거부할 때 발생한다.</td>
</tr>
<tr>
<td align="center">404</td>
<td align="center">Not Found</td>
<td>요청한 리소스를 찾을 수 없음을 나타낸다.<br>서버가 요청한 URI에 해당하는 리소스를 찾을 수 없을 때 발생한다.</td>
</tr>
<tr>
<td align="center">500</td>
<td align="center">Internal Server Error</td>
<td>서버가 요청을 처리하는 동안 내부 오류가 발생했음을 나타낸다.<br>서버 측에서 처리 중에 오류가 발생했을 때 사용한다.</td>
</tr>
<tr>
<td align="center">503</td>
<td align="center">Service Unavailable</td>
<td>서버가 현재 요청을 처리할 수 없음을 나타낸다.<br>일반적으로 서버가 과부하되었거나 유지 보수 중일 때 사용한다.</td>
</tr>
</tbody></table>
<ul>
<li>주요한 특징으로 비연결지향과 상태없음이 있다.<ul>
<li>비연결지향 :</li>
<li>상태없음 :</li>
</ul>
</li>
</ul>
<h3 id="쿠키--캐시--세션">쿠키 / 캐시 / 세션</h3>
<ul>
<li><table>
<thead>
<tr>
<th>분류</th>
<th>쿠키</th>
<th>캐시</th>
<th>세션</th>
</tr>
</thead>
<tbody><tr>
<td>정의</td>
<td>주로 사용자의 상태를 유지하고 추적하기 위해 활용한다. <br> 로그인 상태, 사용자 설정 등을 저장하는 데 사용</td>
<td>리소스 파일을 임시로 저장하여 다시 계산하지 않도록 하기 위해 사용한다. <br> 웹 페이지 로딩 속도를 향상시키고 네트워크 트래픽을 감소시킵니다.</td>
<td>사용자의 상태를 유지하고 관리하는 메커니즘이다.<br>사용자의 로그인 상태나 웹 애플리케이션에서의 상태를 저장한다.</td>
</tr>
<tr>
<td>저장 위치</td>
<td>로컬 브라우저</td>
<td>로컬 브라우저</td>
<td>서버</td>
</tr>
<tr>
<td>보안성</td>
<td>취약</td>
<td>-</td>
<td>높음</td>
</tr>
</tbody></table>
</li>
</ul>
<h3 id="2-웹-스토리지">2. 웹 스토리지</h3>
<ul>
<li>웹 스토리지는 </li>
</ul>
<h2 id="🟨-project">🟨 Project</h2>
<h3 id="프로젝트에서-nextjs를-선택한-이유">프로젝트에서 next.js를 선택한 이유</h3>
<ul>
<li>SEO를 위한 SSR을 가능하게 하므로 선택하였다.</li>
<li>직관적인 page 기반 라우팅이 가능하므로</li>
<li>code splitting</li>
<li>image optimization</li>
</ul>
<p>🟩🟦🟪🟫⬛⬜</p>
<h4 id="pwa">PWA</h4>
<p>-</p>
<h4 id="lazy-loading">LAZY LOADING</h4>
<p>-</p>
<h4 id="jwt">JWT</h4>
<ul>
<li>Json Web Token</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[All in One] Next.js]]></title>
            <link>https://velog.io/@mingjuu_u/All-in-One-Next.js</link>
            <guid>https://velog.io/@mingjuu_u/All-in-One-Next.js</guid>
            <pubDate>Fri, 17 Nov 2023 17:23:44 GMT</pubDate>
            <description><![CDATA[<p>asdf</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Button_Component]]></title>
            <link>https://velog.io/@mingjuu_u/ButtonComponent</link>
            <guid>https://velog.io/@mingjuu_u/ButtonComponent</guid>
            <pubDate>Fri, 22 Sep 2023 09:03:48 GMT</pubDate>
            <description><![CDATA[<h3 id="props">Props</h3>
<h4 id="1-onclick">1. onClick</h4>
<ol start="2">
<li>theme</li>
</ol>
<h3 id="button--props들">Button  Props들</h3>
<ul>
<li>자주 사용하는 것들만 선별하여 입력하도록 하였습니다.</li>
</ul>
<ol>
<li>height</li>
<li></li>
</ol>
<h3 id="buttontheme를-구성하는-필수요소들">ButtonTheme를 구성하는 필수요소들</h3>
<ol>
<li>color</li>
<li>backgroundColor</li>
<li>radius</li>
</ol>
<h3 id="button의-구성">Button의 구성</h3>
<ol>
<li>Index.tsx</li>
<li>Button.tsx</li>
<li>ButtonTheme.tsx</li>
<li>ButtonTypes.ts</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[컴포넌트 모듈화]]></title>
            <link>https://velog.io/@mingjuu_u/%EB%8B%A4%EC%96%91%ED%95%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B5%AC%EC%A1%B0%ED%99%94%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mingjuu_u/%EB%8B%A4%EC%96%91%ED%95%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B5%AC%EC%A1%B0%ED%99%94%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 19 Sep 2023 06:35:37 GMT</pubDate>
            <description><![CDATA[<h2 id="서론">서론</h2>
<h3 id="컴포넌트-모듈화의-장점">컴포넌트 모듈화의 장점</h3>
<ul>
<li>다양한 공용 컴포넌트를 사전에 제작하면 초기 개발 단계 비용을 절약해 주요 기능 개발에 더 많은 노력을 쏟을 수 있다.</li>
<li>코드의 일관성을 유지하여 사용자 경험을 향상시킨다.</li>
<li>사전에 테스트된 코드이므로 발생 가능한 버그를 줄인다.</li>
<li>이후에, 안정화 된 버전을 npm 라이브러리에 등록한다. </li>
</ul>
<h3 id="지향점">지향점</h3>
<ul>
<li>이후에 사용 가능하게 만든다.</li>
</ul>
<h3 id="지양점">지양점</h3>
<ul>
<li>anyscript를 지양한다.</li>
</ul>
<h2 id="1-button">1. Button</h2>
<p>(버튼 움짤)
왜 이렇게 개발했는가?
장점
개선점</p>
<h2 id="2-input">2. Input</h2>
<h2 id="3-hamburger-bar">3. Hamburger Bar</h2>
<h2 id="4">4.</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[webpack 최적화]]></title>
            <link>https://velog.io/@mingjuu_u/webpack-%EC%B5%9C%EC%A0%81%ED%99%94</link>
            <guid>https://velog.io/@mingjuu_u/webpack-%EC%B5%9C%EC%A0%81%ED%99%94</guid>
            <pubDate>Mon, 08 May 2023 19:17:23 GMT</pubDate>
            <description><![CDATA[<h1 id="webpack의-기본-옵션">webpack의 기본 옵션</h1>
<ul>
<li>entry: 앱이 번들처리를 시작할 지점을 뜻하며 index.js부터 시작해 import문을 따라 빌드를 진행한다.</li>
<li>output: 번들링된 결과물의 위치 및 파일 이름을 지정해줍니다. path나 filename이라는 옵션으로 위치 및 파일이름을 지정할 수 있다.
이미지나 파일 같은 외부 리소스를 로드할때는 publicPath가 필요한데 이는 prefix의 개념으로 사용자가 webpack.config.js에 설정한 주소가 실제 배포되는 주소 앞에 설정이 된다.<pre><code class="language-javascript">// putblicPath: /assets/
</code></pre>
</li>
</ul>
<p>src=&quot;picture.jpg&quot; -&gt; /assets/picture.jpg</p>
<pre><code>
- resolve: 모듈을 해석하는 방식을 변경할 수 있다. 예를 들어 alias 옵션을 이용할때 특정 모듈의 별칭을 만들 수 있으며 일반적으로는 사용되는 src 폴더의 별칭을 지정할 수 있다.

- loader: 기본적으로 webpack은 javascript 및 json파일만 해석 가능한데 로더를 사용하면 webpack이 다른 포맷의 파일을 처리하고 앱에서 사용 가능한 모듈로 변환이 가능하다.

- plugin: 로더가 파일 단위로 처리한다면 플러그인은 주로 번들된 결과물을 처리한다.

- externals: 우리도 코드가 의존하고 있지만 빌드 과정에서 포함하지 않아도 되는 axios, jQuery같은 써드파티 라이브러리들을 여기에 명시하면 빌드 프로세스에 포함되지 않는다.

- performance: 성능과 관련된 옵션으로 파일 크기가 250kb를 넘어갈 경우 경고를 띄워주는 옵션 등이 있다.

# webpack의 최적화
![](https://velog.velcdn.com/images/mingjuu_u/post/f4e6434f-4be1-4aea-b646-d1b782860636/image.png)
- 번들 사이즈 줄이기
    - webpack mode
    - source-map
    - 코드 스플리팅
    - 트리 쉐이킹
- 빌드 속도 올리기
    - caching


# webpack mode
### webpack 모드의 종류
- Development: 강력한 소스 매핑, localhost 서버에서는 라이브러리 로딩이나 hot module replacement 기능을 목적으로 사용한다.
- production: 로드 시간을 줄이기 위해 번들 최소화 가벼운 소스맵 및 에셋 최적화에 초점을 맞춘다.
기본적으로 tersurPlugin을 이용하여 코드를 압축, 난독화를 한다.

# Source-map
- production으로 빌드한 파일과 원본 파일을 서로 연결시켜주는 기능이다.
- 소스맵은 원본 코드를 특정 알고리즘으로 인코딩하여 특정 키워드로 매핑을 시켜 놓으면 나중에 브라우저에서
난독화된 코드를 그대로 디코딩하여 복원시킬 수 있다.
- ```javascript
{
    version : 3,
    file: &quot;bundle.js&quot;
    sourceRoot: &quot;&quot;,
    sources: [&quot;a.js&quot;, &quot;b.js&quot;]
    names: [&quot;src&quot;, &quot;maps&quot;, &quot;are&quot;, &quot;fun&quot;],
    mapping: &quot;AAgBC, SAAQ, CAAEA&quot;
}
- 소스맵의 구성
    - file : 연결된 파일의 이름
    - sources : bundle.js를 만드는데 활용되는 소스 코드 파일 목록
    - names : 소스코드의 모든 변수와 함수 이름이 기록된다.
    - mappings : 실제 코드와 매핑할 수 있도록 하는 데이터이며 Base64 VLQ로 인코딩되어 기록된다.


#### 소스 레벨 종류
- None
    - 소스맵을 생성하지 않는다.
    - 최대 성능의 Production build시 추천하는 방식
- Source-map:
    - 고품질 소스맵을 포함한 Production build시 추천하는 옵션

- 기본적으로 none과 source-map이 있고 대부분의 소스맵은 (option)- source-map 형식으로 진행된다.

#### option의 종류
- eval
    - eval이 붙는 소스맵 옵션은 자바스크립트 함수인 eval을 사용해서 소스맵을 만듭니다
    - eval은 mode: development에서devtool 옵션을 주지 않으면 기본적으로 들어가는 소스맵이므로 실제로 소스맵을 생성하지 않으려면 devtool: false를 준 상태로 빌드를 진행해야한다.
    - eval 함수는 각 모듈을 따로 실행시켜 수정된 모듈만 재빌드하여 빠르지만 정확한 소스 코드 위치를 맵핑  하지 못한 경우가 종종 있습니다

- inline
    - inline 옵션은 map 파일을 만들지 않고 주석에 파일을 data URL로 작성한다.
    - 따라서, source map이 독립된 파일로 존재하지 않고 bundle.js 파일 내에 포함되게 됩니다

![](https://velog.velcdn.com/images/mingjuu_u/post/3d11c441-ca41-4a8f-9018-daf568c37164/image.png)

- hidden
    - 소스맵 옵션과 거의 동일하지만 소스맵에 대한 참조가 추가 되지 않는다.
    - 주로 사용자에게 개발자 도구에서 소스맵을 보여주고 싶지 않을 때 사용하는 옵션이다.

![](https://velog.velcdn.com/images/mingjuu_u/post/cbed90cd-86c0-4625-8eaa-f2523b0733e0/image.png)

- nosource
    - 주로 사용자에게 내부 소스 코드를 보여 주고 싶지 않을 때 사용하는 옵션이다.

![](https://velog.velcdn.com/images/mingjuu_u/post/6c9855e7-f6a5-4529-8239-a429985de778/image.png)
![](https://velog.velcdn.com/images/mingjuu_u/post/842c5292-7df7-4954-8ac2-320051206402/image.png)

- cheap
    - 라인 넘버만 매핑하고 라인에서 몇 번째 글자인지는 매핑하지 않는 옵션입니다
    - 그래서 에러가 발생하면 몇 번째 라인에서 발생했는지 알 수 있지만 실제로 몇 번째 글자에서 발생했는지 알 수 없습니다.
    - 빌드 속도와 리빌드 속도가 약간 향상된다.

요약
![](https://velog.velcdn.com/images/mingjuu_u/post/250acbbc-9ede-4d67-a886-3e1b2a49a849/image.png)

#### 모드별로 추천하는 소스맵
- Development
    기본적으로 리빌드가 빠른 eval을 추천한다.
    - eval : eval은 매우 빠른 리빌드와 빠른 빌드를 제공하지만 개발자가 작성한 코드가 아니기 때문에 babel이나 webpack으로 변환된 코드를 보게 된다.
    - eval-cheap-module-source-map : 빠른 리빌드와 함께 소스맵을 제공하지만 정확한 글자에 대한 매핑은 불가능
    - eval-source-map : 앞의 두 소스맵에 비해 리빌드가 약간 느려지지만 더 성능 좋은 소스맵을 제공한다.

- Production
    - none : 매우 빠른 리빌드와 매우 빠른 빌드를 제공하고 소스맵을 제공하지 않으므로 디버깅이 불가능하다.
    - source-map : 성능 좋은 소스맵을 Production 환경에서 사용하려면 이용한다.
    - inline으로 생성되는 eval과 inline같은 소스맵은 번들 사이즈가 커져서 프로덕션 빌드에는 적합하지 않다.

# Code Splitting
- 자바스크립트로 애플리케이션을 개발하게 되면 기본적으로 하나의 파일에 모든 로직이 들어가게 된다.
- 따라서, 프로젝트의 규모가 커질수록 자바스크립트 파일 용량도 커지는데 용량이 커지면 로딩 속도가 저하된다.
- 코드 스플리팅은 지금 당장 필요한 코드가 아니라면 따로 분리시켜 필요할 때 불러와 사용한다.

#### SPA로 구현된 react project에서 코드 스플리팅 하는법

- React에서는 컴포넌트들을 동적으로 불러오기 위해서
React.lazy를 사용하는데 이를 위해선 React.Suspense를 함께 이용해야 한다.
- 예시 코드를 보면 Suspense가 Routes를 감싼 걸 볼 수 있는데 이렇게 감싼 상태이면 컴포넌트를 동적으로 불러올 때 로딩 상태를 React.Suspense가 처리하게 된다.
```javascript
const Home = lazy(() =&gt; import(&quot;@/pages/Home&quot;));

//router Code
&lt;Suspense fallback={&lt;div&gt;로딩중..&lt;/div&gt;}/&gt;
    &lt;Routes&gt;
        &lt;Routes path=&quot;|&quot; element={&lt;Home /&gt;} /&gt;
          ...
    &lt;/Routes&gt;
&lt;/Suspense&gt;</code></pre><ul>
<li>다음은 React.lazy를 사용해서 코드 스플리팅한 번들 결과물로 큰 하나의 파일을 여러 개의 작은 모듈로 나눠진 걸 볼수 있다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mingjuu_u/post/77927af5-a4e2-477d-98d0-111d658882fe/image.png" alt=""></p>
<ul>
<li>여기서 추가적으로 최적화할 수 있는 옵션으로 중복된 모듈을 처리하는 optimization.splitChunks 옵션이다.</li>
<li>splitChunks옵션을 주면 중복된 모듈을 공통 모듈로 분리한다.</li>
<li>default 설정으로 chunks가 node_modules에 존재하고 20kb보다 크고 로드할 때 최대 병렬의 요청 수가 30개 이하여야지만 splitChunks를 진행한다.</li>
</ul>
<h1 id="tree-shaking">Tree Shaking</h1>
<ul>
<li>일반적으로 사용하지 않는 코드를 번들링 결과에 포함하지 않는 일이다.</li>
<li>함수 단위가 아닌 모듈 단위에서 필요하지 않거나 사용하지 않는 코드를 번들링 결과에 포함하지 않는 것을 의미한다.
<img src="https://velog.velcdn.com/images/mingjuu_u/post/a513d52b-a1cf-452a-bbc3-93e4393b7386/image.png" alt=""></li>
<li>이런 경우 tree shaking 이루어지면 c는 번들 결과에 포함되지 않게 된다.</li>
</ul>
<h3 id="💡-안-쓰는-코드는-그냥-지워버리면-되는거-아닌가요">💡 안 쓰는 코드는 그냥 지워버리면 되는거 아닌가요?</h3>
<p>우리가 작성한 코드라면 폴더에서 파일을 삭제하면 되지만 </p>
<ul>
<li>node처럼 서로간의 의존성이 높고 </li>
<li>대규모 프로젝트라 코드를 지웠을 때 서로에게 어떤 영향이 있을지 모를 때는 함부로 코드를 지우는 것은 지양해야 한다. </li>
</ul>
<ol>
<li>Library
라이브러리를 만드는 경우에는 tree shaking 개념을 알고 있어야 소비자들의 자원을 낭비하지 않게 만들 수 있습니다.
또 소비자들은 webpack을 쓸지 rollup을 쓸지, 또 사용하더라도 webpack의 최신 버전을 안쓸지도 모르는 일이기 때문입니다</li>
<li>CommonJS
두 번째로는 CommonJs 방식으로 개발된 lodash같은 라이브러리를 사용할 때 더 조심할 수 있습니다
tree shaking 개념을 모르고 이런 옛날에 만들어진 라이브러리를 사용한다면 사용하지 않는 코드들도 다 같이 불러와질 수 있기 때문입니다</li>
</ol>
<h4 id="그래서-tree-shaking은-어떻게-하는데">그래서 tree shaking은 어떻게 하는데..?</h4>
<ul>
<li>tree shaking은 그냥 production mode를 켜면 알아서 잘 이루어진다.</li>
</ul>
<h1 id="persistent-cache">persistent cache</h1>
<ul>
<li>webpack 5에서 persistent cache라는 기능이 추가 되었는데 말 그대로 하드디스크에 빌드된 결과물을 저장해 놓는다는 것입니다</li>
<li>그리고 다시 re-build가 일어났을 때 파일이 변경되지 않았다면 하드디스크에 저장돼 있는 캐시 데이터를 재활용하고 만약에 변경이 되었다면 하드디스크에 있는 캐시 데이터를 무효화하는 일을 한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mingjuu_u/post/ee27cdff-6191-45f4-b4cf-7eb19a36e4ff/image.png" alt=""></p>
<h4 id="persistent-cache-적용법">persistent cache 적용법</h4>
<pre><code class="language-javascript">moduel.exports = merge(common, {
  mode: &quot;production&quot;
  devtools: &quot;source-map&quot;,
  plugins: [],
  optimization: {},
  cache: {
    type: &quot;filesystem&quot;,
      buildDependencies: {
        config: [__filename],
    },
  },
}),</code></pre>
<ul>
<li>cache 옵션에 type을 &quot;filesystem&quot;으로 지정해주면 하드디스크를 사용한다는 의미이다.</li>
</ul>
<h3 id="💡-근데-이-좋은걸-왜-default로-안-씀">💡 <del>근데 이 좋은걸 왜 default로 안 씀?</del></h3>
<p><del>캐시의 무효화 정책이 상황에 따라 다르게 적용돼야 하기 때문이다.</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[📖 Webpack 공부하기]]></title>
            <link>https://velog.io/@mingjuu_u/Webpack-%EA%B3%B5%EB%B6%80%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mingjuu_u/Webpack-%EA%B3%B5%EB%B6%80%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 27 Apr 2023 20:45:38 GMT</pubDate>
            <description><![CDATA[<h1 id="📘-서론">📘 서론</h1>
<blockquote>
<h3 id="💬-module이란">💬 Module이란?</h3>
<p>분리된 코드의 조각, 시스템을 이루는 논리적인 일부분</p>
</blockquote>
<ul>
<li>Javascript는 웹 페이지에 보조적인 기능을 부여하기 위한 용도로 만들어졌다.</li>
<li>웹페이지에서 Javascript를 사용하려면 아래와 같이 script 태그를 통해 Javascript 파일을 가져오면 된다.</li>
</ul>
<pre><code class="language-javascript">&lt;script type=&quot;text/javascript&quot; src=&quot;index.js&gt;&lt;/script&gt;</code></pre>
<ul>
<li>만약 필요한 자바스크립트 파일이 2개이고 두 파일에 각각 같은 이름의 변수가 선언되어 있다면?</li>
</ul>
<pre><code class="language-javascript">&lt;script type=&quot;text/javascript&quot; src=&quot;index.js&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;todo.js&gt;&lt;/script&gt;

// index.js
var todo = &quot;세션 준비하기&quot;

// todo.js
var todo = &quot;꿀잠자기&quot;</code></pre>
<ul>
<li><p>지금과 같은 방식으로 javascript 파일을 불러온다면 하나의 파일에 코드를 작성하는 것과 다를게 없다.</p>
</li>
<li><p>또한 todo는 전역 변수이므로 전역 스코프를 오염시키고 예측하기 어렵고 오류를 만들어내기 쉬운 코드를 만든다.</p>
</li>
<li><p>이러한 문제는 아래와 같이 Closure의 원리를 이용하여 즉시실행 함수 등을 통해 구현한 모듈 패턴으로 외부로부터 독립적인 스코프를 만들어 사용하며 어느 정도 극복 가능했다.</p>
</li>
</ul>
<pre><code class="language-javascript">var todoApp = (function () {
    var todo = &quot;꿀잠자기&quot;

    return {
        getTodo: function() {
        return todo;
        }
    }
})();

console.log(todoApp.getTodo()); // &quot;꿀잠자기&quot;
console.log(todo); // ReferenceError: todo is not defined</code></pre>
<h1 id="📗-modularization">📗 Modularization</h1>
<h3 id="💬-모듈화의-필요성">💬 모듈화의 필요성</h3>
<ul>
<li>자바스크립트를 브라우저에서만 사용할게 아니라 범용적인 서버사이드 언어로 사용하려는 움직임</li>
<li>이를 위해 모듈화를 하고 서로 호환되는 표준 라이브러리나 다른 모듈을 가져오는 방법이 필요했다.</li>
<li>모듈화의 구성요소에는 스코프, 정의, 사용이 있다.</li>
</ul>
<blockquote>
<p>각각의 모듈은 독립적인 <strong>스코프</strong>를 갖고, 
모듈을 <strong>정의</strong>하여 만들 수 있어야 하고, 
정의된 모듈을 <strong>사용</strong>할 수 있어야 한다.</p>
</blockquote>
<h3 id="💬-commonjs">💬 commonJS</h3>
<ul>
<li>module.exports를 통해 모듈을 정의하고, require문법을 통해 정의된 모듈을 가져다 사용할 수 있다.</li>
<li>```javascript
  module.exports
   require(&#39;./files.js&#39;)</li>
<li>모든 파일이 로컬에 존재하고 바로 불러올 수 있으며 동기적으로 동작함을 전제로 사용한다.</li>
<li>우리가 현재 사용하는 node.js가 commonJS를 사용한다.</li>
</ul>
<p>여담으로, </p>
<ul>
<li>비동기로도 모듈을 사용하고 싶은 움직임으로 등장한 AMD(Asynchronous Module Definition)과 </li>
<li>AMD기반으로 CommonJS 방식까지 지원하는 통합 형태인 UMD(Universal Module Definition)가 존재한다.</li>
</ul>
<h1 id="📙-webpack">📙 Webpack</h1>
<ul>
<li>commonJS의 등장으로 모듈을 사용할 수 있게 되었으나 모든 파일을 네트워크 통신을 통해 하나씩 가져오는 문제점이 발생하였다.</li>
<li>이러한 문제점을 해결하기 위해 Module Bundler가 등장하였다.</li>
</ul>
<h3 id="💬-module-bundler">💬 Module Bundler</h3>
<ul>
<li>모듈 번들러는 말 그대로 여러 개의 모듈을 하나의 파일로 묶어서 처리하는 도구를 말한다.</li>
</ul>
<h3 id="💬-webpack">💬 Webpack</h3>
<p><img src="https://velog.velcdn.com/images/mingjuu_u/post/8b00fac7-c251-4cdb-b9a5-c956dbf5f812/image.png" alt=""></p>
<ul>
<li>가장 대표적인 모듈 번들러인 웹팩에서는 모든 파일(HTML, CSS, 이미지, 폰트 등)을 모듈로 보고 이를 처리할 수 있는 번들(bundle)로 변환해 줍니다.</li>
</ul>
<h3 id="💬-webpack의-동작-방식">💬 Webpack의 동작 방식</h3>
<ul>
<li>Webpack은 entry를 통해 프로젝트의 모든 의존성을 분석한다.</li>
<li>entry에서 정의한 파일을 시작으로 의존하는 다른 모듈을 순차적으로 분석하고, 이를 하나의 모듈로 묶어 번들링한다.</li>
<li>이때, 로더(loader)와 플러그인(plugin)을 이용하여 다양한 파일 형식(CSS, 이미지 등)을 모듈로 인식하고, 처리할 수 있습니다.</li>
</ul>
<h3 id="💬-webpack의-주요-구성-요소">💬 Webpack의 주요 구성 요소</h3>
<ul>
<li>entry : 앱이 번들처리를 시작할 지점으로 일반적으로 index.js에서 시작해 import문을 따라 빌드가 진행된다.</li>
<li>output : 번들링된 결과물의 위치 및 파일이름을 지정한다. 일반적으로 dist나 build라는 이름의 폴더를 사용한다.</li>
<li>module: 웹팩이 모듈을 처리할 때 사용하는 규칙(rule)을 정의합니다.</li>
<li>loader <ul>
<li>기본적으로 javascript 및 JSON 파일만 해석이 가능한 Webpack을 다른 포멧의 파일을 처리하고 모듈로 변환하게 해준다.</li>
<li>자주 사용하는 loader에는 css-loader, style-loader, file-loader등이 있다.</li>
</ul>
</li>
<li>plugin<ul>
<li>플러그인은 번들된 결과물의 형태를 바꾸는 후처리를 하는 역할이다.</li>
<li>난독화나 특정 문자열 치환등의 처리가 가능하다.</li>
<li>대표적인 플러그인으로 개발용 api와 배포용 api주소를 서로 다르게 설정하는 것과 같이 환경 의존적인 정보를 관리하는데 사용하는 definePlugin이 있다.</li>
</ul>
</li>
<li>mode : production, development, none등 웹팩의 모드를 설정한다.</li>
</ul>
<h1 id="📕-webpack-최적화">📕 Webpack 최적화</h1>
<h3 id="💬-번들-사이즈-줄이기">💬 번들 사이즈 줄이기</h3>
<p>번들 사이즈를 줄여야 하는 이유</p>
<ul>
<li>네트워크 비용 : 파일이 무거울수록 네트워크 통신이 오래 걸린다.</li>
<li>파싱 및 컴파일 비용 줄이기</li>
<li>메모리 비용 : 코드가 실행되지 않아도 RAM에 코드가 올라가 메모리를 낭비한다.</li>
</ul>
<p>번들 사이즈를 줄이는 방법</p>
<ul>
<li>Webpack mode</li>
<li>source map</li>
<li>code splitting</li>
<li>tree shaking</li>
<li>html, css 최적화</li>
</ul>
<h3 id="💬-빌드-속도-줄이기">💬 빌드 속도 줄이기</h3>
<ul>
<li>persistant cache 사용하기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[소프트웨어 개발 방법론 공부하기]]></title>
            <link>https://velog.io/@mingjuu_u/SDM</link>
            <guid>https://velog.io/@mingjuu_u/SDM</guid>
            <pubDate>Sun, 16 Apr 2023 18:16:13 GMT</pubDate>
            <description><![CDATA[<h1 id="소프트웨어-개발-방법론이란">소프트웨어 개발 방법론이란?</h1>
<blockquote>
<p>소프트웨어 개발 방법론은 소프트웨어를 개발하는 과정에서 필요한 절차, 도구, 활동, 산출물 등을 체계적으로 <strong>정의</strong>하고 <strong>표준화</strong>한 것이다.
이를 통해 효율적이고 품질 높은 소프트웨어를 개발할 수 있다.</p>
</blockquote>
<ul>
<li>왜 소프트웨어 개발 방법론이 필요한가?<ul>
<li>소프트웨어 개발은 복잡하고 다양한 요소들이 병행적으로 진행되어야 하기 때문에 표준화된 방법이 필요하다.</li>
<li>또한, 소프트웨어 개발 과정에서 발생하는 문제점을 미리 파악하고 예방하기 위해 개발 방법론을 사용한다.</li>
</ul>
</li>
</ul>
<h1 id="📘-소프트웨어-개발-방식의-변화">📘 소프트웨어 개발 방식의 변화</h1>
<h3 id="💬-소프트웨어-개발-방식의-등장">💬 소프트웨어 개발 방식의 등장</h3>
<ul>
<li>초기에 소프트웨어가 개발되는 과정에서는 별도의 방법론이 없어, 개발자들이 자신만의 방법으로 개발을 진행했다.</li>
<li>그러나 소프트웨어 개발의 증가와 대규모의 복잡한 시스템을 개발하는 과정에서 많은 문제가 발생하였다. </li>
<li>이에 따라, 소프트웨어 개발 방식의 체계화와 표준화를 원하는 목소리가 커졌고 이에 따라 대두된 최초의 소프트웨어 개발 방식이 폭포수 모델이다.</li>
</ul>
<h3 id="💬-시대에-따라-변하는-개발-방식">💬 시대에 따라 변하는 개발 방식</h3>
<ul>
<li>앞서 언급했던 폭포수 모델 이외에도 객체지향 프로그래밍이 대두되면서 객체지향 분석 및 방법론이 등장했다.</li>
<li>이후 선형적인 구조의 폭포수 모델을 보완하면서도 유연하고 적응성 있는 개발 방법인 애자일 방법론이 등장하여 현재까지 발전해오고 있다.</li>
</ul>
<h1 id="📗-폭포수-모델">📗 폭포수 모델</h1>
<h3 id="💬-폭포수-모델이란">💬 폭포수 모델이란?</h3>
<blockquote>
<h5 id="다음-그림은-폭포수-모델의-초기-모습이다">다음 그림은 폭포수 모델의 초기 모습이다.</h5>
</blockquote>
<h5 id="요구사항-기술-→-설계-→-구현-→-시험과-디버깅-→-설치-→-유지보수">요구사항 기술 → 설계 → 구현 → 시험과 디버깅 → 설치 → 유지보수</h5>
<h5 id=""></h5>
<p><img src="https://velog.velcdn.com/images/mingjuu_u/post/43fcf224-080c-4cb0-8a6a-96fbfd90c1f1/image.png" alt=""></p>
<ul>
<li>폭포수 모델은 개발 과정을 단계별로 구분하여 개발하는 방식으로 개발 흐름이 마치 폭포수처럼 이뤄진다는 점에서 이러한 이름이 붙었다.</li>
</ul>
<h3 id="💬-폭포수-모델의-장단점">💬 폭포수 모델의 장단점</h3>
<ul>
<li><p>장점</p>
<ul>
<li>프로젝트 초기 단계에서 요구사항을 분석하고, 설계할 때 사용하기 적합하다.</li>
<li>각 단계가 일련의 과정으로 이루어지므로 전체적인 개발 과정을 파악하고 계획하기 용이하다.</li>
<li>각 단계가 완료되면 다음 단계로 진행하기 전 반드시 검증을 거치므로 오류를 최소화할 수 있다.</li>
</ul>
</li>
<li><p>단점</p>
<ul>
<li>각 단계가 선형적으로 이루어지므로 client의 요구사항이나 피드백을 수용하기 어렵고 개발 중간에 문제가 발생하면 이를 수정하기가 어렵다.</li>
<li>결과에 대한 test는 단계의 가장 마지막에 이뤄지므로 test는 오류나 결함을 수정하기 어렵고 고객의 요구사항과 개발 결과물에 괴리가 있을 수 있다. </li>
</ul>
</li>
</ul>
<h1 id="📙-애자일-방법론">📙 애자일 방법론</h1>
<h3 id="💬-애자일-방법론이란">💬 애자일 방법론이란?</h3>
<blockquote>
<h5 id="agile--날렵한-민첩한-기민한">Agile : 날렵한, 민첩한, 기민한</h5>
</blockquote>
<h5 id="소프트웨어를-더-빠르게-유연하게-효율적으로-개발하기-위한-방법론">소프트웨어를 더 빠르게, 유연하게, 효율적으로 개발하기 위한 방법론</h5>
<p><img src="https://velog.velcdn.com/images/mingjuu_u/post/816cd064-7700-4b31-a322-9d0b5761d083/image.png" alt=""></p>
<ul>
<li>애자일 방법론은 폭포수 모델에서의 문제점, 즉 요구사항 변경이나 추가에 대응하기 어렵다는 점을 극복하고자 한 것이다. </li>
<li>애자일 방법론은 소프트웨어 개발 과정에서 변경에 유연하게 대처할 수 있도록 하는 것을 목적으로 한다. </li>
<li>애자일 방법론은 포괄적인 문서보다 실행 가능한 소프트웨어를 우선한다.<h3 id="💬-애자일-방법론의-장단점">💬 애자일 방법론의 장단점</h3>
</li>
<li>장점<ul>
<li><strong>짧은 개발 주기</strong>와 <strong>반복(iteration)</strong> 개발으로 빠른 개발과 출시 가능하다.</li>
<li>client 요구사항이나 <strong>계획 변경에 대한 대응력</strong>이 높아 변경이 용이하고 client 만족도를 높일 수 있다.</li>
<li>테스트를 통해 <strong>위험을 미리 파악</strong>하고 관리 가능하다.</li>
</ul>
</li>
<li>단점<ul>
<li>확정되지 않은 계획 및 요구사항으로 <strong>반복적인 유지보수 작업</strong>이 많고 개발 진행 시 이해하지 못하고 진행하는 부분이 생긴다.</li>
<li>이 때문에 높은 의사소통 능력과 적극적인 참여를 하는 팀원이 필요하다.</li>
<li>계획이 확정되지 않아 <strong>예산 및 일정 관리에 어려움</strong>을 겪는다.</li>
</ul>
</li>
</ul>
<blockquote>
<h3 id="📌-scrum은-뭐지">📌 SCRUM은 뭐지?</h3>
</blockquote>
<ul>
<li><h5 id="프로젝트를-애자일-방식으로-진행할-때-프로젝트를-스프린트-단위로-나누어-팀-내에서-회의를-통해-문제를-해결하는-방식이다">프로젝트를 애자일 방식으로 진행할 때 프로젝트를 스프린트 단위로 나누어 팀 내에서 회의를 통해 문제를 해결하는 방식이다.</h5>
</li>
<li><h5 id="scrum과-밑에-설명할-3가지-개발-방법론-모두-애자일-방법론의-하위-개념으로서-개발-프로세스의-일부를-담당하고-있지만-병렬적인-구조는-아니다">SCRUM과 밑에 설명할 3가지 개발 방법론 모두 애자일 방법론의 하위 개념으로서 개발 프로세스의 일부를 담당하고 있지만 병렬적인 구조는 아니다.</h5>
</li>
<li><h5 id="스크럼은-프로젝트-관리-방법론-중-하나이며-tdd-bdd-ddd-등은-소프트웨어-개발-방법론이다">스크럼은 프로젝트 관리 방법론 중 하나이며 TDD, BDD, DDD 등은 소프트웨어 개발 방법론이다.</h5>
</li>
</ul>
<h3 id="💬-tdd">💬 TDD</h3>
<blockquote>
<h5 id="test-driven-development-테스트-주도-개발">Test Driven Development, 테스트 주도 개발</h5>
</blockquote>
<h5 id="테스트가-개발의-중심이-되는-개발-방법론으로-테스트를-먼저-작성하고-그에-해당하는-코드를-작성하는-개발-방법이다">테스트가 개발의 중심이 되는 개발 방법론으로 테스트를 먼저 작성하고 그에 해당하는 코드를 작성하는 개발 방법이다.</h5>
<h5 id="작성된-코드는-테스트를-통해-검증되고-검증을-통과한-코드만이-실제로-사용된다">작성된 코드는 테스트를 통해 검증되고, 검증을 통과한 코드만이 실제로 사용된다.</h5>
<p><img src="https://velog.velcdn.com/images/mingjuu_u/post/8ec93746-3d7b-40cc-bc80-980d737e82bb/image.png" alt=""></p>
<ul>
<li><p>TDD 개발주기</p>
<ul>
<li><span style="color:red">{ Red } </span>단계에서는 실패하는 테스트 코드를 먼저 작성한다.</li>
<li><span style="color:green">{ Green } </span>단계에서는 테스트 코드를 성공시키기 위한 실제 코드를 작성한다.</li>
<li><span style="color:blue">{ Blue } </span>단계에서는 중복 코드 제거, 일반화 등의 리팩토링을 수행한다.</li>
</ul>
</li>
<li><p>TDD의 장점</p>
<ul>
<li>TDD를 통해 작성된 코드는 테스트를 통해 검증되므로 오류가 줄고 유지보수가 쉬워진다.</li>
<li>오류가 발생할 경우 디버깅 시간을 단축할 수 있다.</li>
<li>테스트 케이스를 작성하며 요구사항을 좀 더 명확하게 이해하고 구현 방식을 결정하므로 코드의 구조와 설계에 대한 고민이 더욱 깊어질 수 있습니다.</li>
</ul>
</li>
<li><p>TDD의 단점</p>
<ul>
<li>코드 작성 전에 테스트 코드를 작성해야 하므로 개발자의 추가적인 노력이 필요합니다.</li>
<li>TDD를 처음 사용하는 개발자들은 테스트 작성 시 어려움을 느낄 수 있습니다.</li>
</ul>
</li>
</ul>
<h3 id="💬-bdd">💬 BDD</h3>
<blockquote>
<h5 id="behavior-driven-development-행위-주도-개발">Behavior-Driven Development, 행위 주도 개발</h5>
</blockquote>
<h5 id="요구사항을-분석하고-검증하는-것에-중점을-둔-개발-방법론이다">요구사항을 분석하고 검증하는 것에 중점을 둔 개발 방법론이다</h5>
<p><img src="https://velog.velcdn.com/images/mingjuu_u/post/cbbc9e73-1080-41fb-b7a5-9916e84956fa/image.JPG" alt=""></p>
<ul>
<li>BDD란?
  TDD에서 비롯된 개발 방법론으로, TDD와 상호 보완적인 관계로 비슷한 개발 주기를 따르면서도 BDD는 비지니스의 요구사항에 초점을 맞추어 테스트를 작성한다.</li>
<li>BDD의 장점<ul>
<li>개발 결과물이 실제 비지니스 요구사항을 만족하는지 쉽게 확인 가능하다.</li>
<li>테스트 자동화 구현이 쉽고, 개발자와 비즈니스 팀과의 소통이 원활해진다.</li>
</ul>
</li>
<li>BDD의 단점<ul>
<li>요구사항 분석이 길어지며 명세화 비용과 시나리오 작성 비용이 증가한다.</li>
<li>또한, 개발시간이 증가한다.</li>
</ul>
</li>
</ul>
<h3 id="💬-ddd">💬 DDD</h3>
<blockquote>
<h5 id="domain-driven-design-도메인-주도-개발">Domain Driven Design, 도메인 주도 개발</h5>
</blockquote>
<ul>
<li>DDD란?
비즈니스 도메인을 모델링하여 이를 기반으로 소프트웨어를 설계한다. 
이를 위해 도메인 전문가와 소프트웨어 개발자가 함께 일하며, 비즈니스 도메인 지식을 소프트웨어 설계에 반영한다.</li>
<li>DDD의 장점<ul>
<li>비즈니스 도메인에 초점을 맞춰 설계하므로 유지보수성이 높다.</li>
<li>비즈니스 도메인의 복잡성을 다룰 수 있다</li>
</ul>
</li>
<li>DDD의 단점<ul>
<li>도메인 모델링에 시간과 비용이 많이 들어간다.</li>
<li>도메인 전문가의 참여가 필요하므로 도메인 전문가의 시간과 노력이 많이 필요하다.</li>
</ul>
</li>
</ul>
<h1 id="📕-종합-비교-및-결론">📕 종합 비교 및 결론</h1>
<ul>
<li>어떤 방법이 낫다기보단 프로젝트의 상황을 고려하여 더 적합한 것을 사용해야 한다.</li>
<li>최근에는 xp방법론이나 애자일 방법론을 보완하는 형태로 린(Lean) 방법론이나 DevOps 방법론이 등장하고 있습니다. </li>
<li>이러한 방법론들은 더욱 빠르고 유연한 개발을 위해 지속적인 개선과 협업을 강조합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[media query 사용을 위한 custom hook ]]></title>
            <link>https://velog.io/@mingjuu_u/media-query-%EC%82%AC%EC%9A%A9%EC%9D%84-%EC%9C%84%ED%95%9C-custom-hook</link>
            <guid>https://velog.io/@mingjuu_u/media-query-%EC%82%AC%EC%9A%A9%EC%9D%84-%EC%9C%84%ED%95%9C-custom-hook</guid>
            <pubDate>Thu, 13 Apr 2023 11:35:00 GMT</pubDate>
            <description><![CDATA[<p>d</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL Template]]></title>
            <link>https://velog.io/@mingjuu_u/TIL-Template</link>
            <guid>https://velog.io/@mingjuu_u/TIL-Template</guid>
            <pubDate>Wed, 12 Apr 2023 00:36:13 GMT</pubDate>
            <description><![CDATA[<h1 id="til-작성-template-모음">TIL 작성 Template 모음</h1>
<h1 id="1-공부-예시">1. 공부 예시</h1>
<h3 id="글-제목--📖-title-공부하기">글 제목 : 📖 (Title) 공부하기</h3>
<h1 id="title">(Title)</h1>
<blockquote>
<p>(Title) Description</p>
</blockquote>
<ul>
<li></li>
<li></li>
</ul>
<h1 id="📘-index-1">📘 Index 1</h1>
<h3 id="💬-sub-index-1">💬 Sub-Index 1</h3>
<ul>
<li></li>
<li><h3 id="💬-sub-index-2">💬 Sub-Index 2</h3>
</li>
<li></li>
<li></li>
</ul>
<h1 id="📗-index-2">📗 Index 2</h1>
<h3 id="💬-sub-index-1-1">💬 Sub-Index 1</h3>
<ul>
<li></li>
<li><h3 id="💬-sub-index-2-1">💬 Sub-Index 2</h3>
</li>
<li></li>
<li></li>
</ul>
<h1 id="📙-index-3">📙 Index 3</h1>
<h3 id="💬-sub-index-1-2">💬 Sub-Index 1</h3>
<ul>
<li></li>
<li><h3 id="💬-sub-index-2-2">💬 Sub-Index 2</h3>
</li>
<li></li>
<li></li>
</ul>
<h1 id="📔-index-4">📔 Index 4</h1>
<h3 id="💬-sub-index-1-3">💬 Sub-Index 1</h3>
<ul>
<li></li>
<li><h3 id="💬-sub-index-2-3">💬 Sub-Index 2</h3>
</li>
<li></li>
<li></li>
</ul>
<h1 id="📕-index-5">📕 Index 5</h1>
<h3 id="💬-sub-index-1-4">💬 Sub-Index 1</h3>
<ul>
<li></li>
<li><h3 id="💬-sub-index-2-4">💬 Sub-Index 2</h3>
</li>
<li></li>
<li></li>
</ul>
<h1 id="2-구현">2. 구현</h1>
<h3 id="글-제목--📐-title-구현하기">글 제목 : 📐 (Title) 구현하기</h3>
<h1 id="3-알고리즘">3. 알고리즘</h1>
<h3 id="글-제목--알고리즘-문제">글 제목 : 알고리즘 문제</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 에서 FCM을 통한 알림 수신]]></title>
            <link>https://velog.io/@mingjuu_u/Next.js-%EC%97%90%EC%84%9C-FCM%EC%9D%84-%ED%86%B5%ED%95%9C-%EC%95%8C%EB%A6%BC-%EC%88%98%EC%8B%A0</link>
            <guid>https://velog.io/@mingjuu_u/Next.js-%EC%97%90%EC%84%9C-FCM%EC%9D%84-%ED%86%B5%ED%95%9C-%EC%95%8C%EB%A6%BC-%EC%88%98%EC%8B%A0</guid>
            <pubDate>Tue, 28 Mar 2023 08:14:36 GMT</pubDate>
            <description><![CDATA[<h3 id="1-외-안되는건데">1. 외 안되는건데</h3>
<h3 id="2">2.</h3>
<h3 id="3">3.</h3>
<h3 id="4">4.</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js에서 무한스크롤 & Masonry Layout 구현]]></title>
            <link>https://velog.io/@mingjuu_u/Next.js%EC%97%90%EC%84%9C-egjs-infinitegrid-%EC%82%AC%EC%9A%A9%ED%95%B4%EC%84%9C-%EB%AC%B4%ED%95%9C%EC%8A%A4%ED%81%AC%EB%A1%A4-Marsonry-Layout-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@mingjuu_u/Next.js%EC%97%90%EC%84%9C-egjs-infinitegrid-%EC%82%AC%EC%9A%A9%ED%95%B4%EC%84%9C-%EB%AC%B4%ED%95%9C%EC%8A%A4%ED%81%AC%EB%A1%A4-Marsonry-Layout-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Wed, 22 Mar 2023 00:26:28 GMT</pubDate>
            <description><![CDATA[<h3 id="1-egjs-infinitegrid-사용-이유">1. egjs-infinitegrid 사용 이유</h3>
<ul>
<li>우리 프로젝트에 필요한 무한 스크롤을 기본적으로 제공해준다.</li>
<li>프로젝트에 사용하려 한 Masonry Layout과 같은 다양한 Layout을 제공한다.</li>
</ul>
<h3 id="2-사용한-라이브러리">2. 사용한 라이브러리</h3>
<pre><code class="language-node.js">// 이번 task에서 사용한 라이브러리
npm i @egjs/infinitegrid

// class 형태로 개발한 react code의 오류를 없애준다.
npm i prop-types

// width크기를 고정하고 height를 불러오기 위해 사용
npm i styled-components</code></pre>
<h3 id="3-겪었던-어려움">3. 겪었던 어려움</h3>
<ul>
<li>Next.js의 Image가 흉악하다는 이야기는 들었지만 생각보다 더 흉악했다.<ul>
<li>첫 번째로 Next.js Image는 명시적으로 width와 height를 제공해야 렌더링이 된다.</li>
<li>나의 경우 width를 기준으로 height를 auto 값으로 사용하기를 원했으나 auto는 명시적이지 않은 크기이므로 사용이 불가능 했다.</li>
<li>그래서, AutoHeightImage.tsx 라는 컴포넌트를 분리해 가로 길이를 화면 크기에 비례한 크기로 유지하고 세로 길이를 가로에 비례한 크기로 만들었다.</li>
<li>이 과정에서 styled component를 쓰는 방법 또한 공부하였다.</li>
</ul>
</li>
</ul>
<pre><code class="language-javascript">// AutoHeightImage.tsx

import React from &quot;react&quot;;
import Image, { ImageProps } from &quot;next/legacy/image&quot;;

import { AutoHeightImageWrapper } from &quot;./AutoHeightImage.styles&quot;;

const AutoHeightImage = ({ ...props }: ImageProps): React.ReactElement =&gt; (
  &lt;AutoHeightImageWrapper&gt;
    &lt;Image priority layout=&quot;fill&quot; className=&quot;autoImage&quot; {...props} /&gt;
  &lt;/AutoHeightImageWrapper&gt;
);

export default AutoHeightImage;</code></pre>
<pre><code class="language-javascript">// AutoHeightImage.styles.tsx

import styled from &quot;styled-components&quot;;

export const AutoHeightImageWrapper = styled.div`
  width: 100%;
  &amp; &gt; span {
    position: unset !important;
    &amp; .autoImage {
      object-fit: contain !important;
      position: relative !important;
      height: auto !important;
    }
  }
`;</code></pre>
<ul>
<li><p>반응형으로 만들기로 기획했으므로 화면 크기에 따라 column의 갯수를 조절하기 위해 custom hook을 공부했다.</p>
<ul>
<li>style hook 관련해서 링크 추가 예정</li>
</ul>
</li>
<li><p>ㅁㄴㅇㄹ</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[PWA 공부하기]]></title>
            <link>https://velog.io/@mingjuu_u/PWA</link>
            <guid>https://velog.io/@mingjuu_u/PWA</guid>
            <pubDate>Sun, 12 Mar 2023 10:30:28 GMT</pubDate>
            <description><![CDATA[<h1 id="pwa란">PWA란?</h1>
<blockquote>
<ul>
<li>Progressive Web Apps의 줄임말로 모바일 사이트에서 Native App과 같은 사용자 경험을 제공하는 기술이다.</li>
</ul>
</blockquote>
<ul>
<li>WEB을 Native App처럼 만들어 주는 기술이므로 모든 Native 기능을 사용할 순 없으나 읽기 속도, 표시 속도, 오프라인에서의 실행 등의 이점이 있다.</li>
<li>웹과 앱 모두의 장점을 가져 App처럼 설치할 필요는 없으나 홈 화면에 아이콘 추가 및 푸시 알림 전송이 가능해 UX에 이점이 있다.</li>
</ul>
<h1 id="📘-react에서-pwa-적용하기">📘 React에서 PWA 적용하기</h1>
<h3 id="💬-1-pwa-template-생성하기">💬 1. PWA template 생성하기</h3>
<ul>
<li>다음의 명령어를 실행한다.<pre><code>npx create-react-app my-app --template cra-template</code></pre></li>
<li>my-app 내부에 &quot;service-worker.js&quot;와 &quot;serviceWorkerRegistrations.js&quot;가 생성되는데 이것을 기존 프로젝트로 가져온다.</li>
</ul>
<h3 id="💬-2-service-worker-register">💬 2. service worker Register</h3>
<ul>
<li>root파일(index.js)에 아래 두 줄을 추가시켜준다.<pre><code>import * as serviceWorkerRegistration from &#39;./serviceWorkerRegistration&#39;;
</code></pre></li>
</ul>
<p>serviceWorkerRegistration.register();</p>
<pre><code>### 💬 3. icon 설정
- 편리한 icon 설정을 위한 site
    - https://favicomatic.com/
    - meta tag도 제공한다.
- 다운 받은 파일은 publi/icons 폴더에 저장하여 관리한다.
- public/index.html로 가서 제공해준 meta tag를 모두 head태그 안에 붙여넣는다.
- public/manifest.json에서 아래와 같이 아이콘들을 모두 추가해줘야 한다.
- ```
{
  &quot;short_name&quot;: &quot;project name&quot;,
  &quot;name&quot;: &quot;project name&quot;,
  &quot;icons&quot;: [
    {
      &quot;src&quot;: &quot;./icons/apple-touch-icon-57x57.png&quot;,
      &quot;sizes&quot;: &quot;57x57&quot;,
      &quot;type&quot;: &quot;image/png&quot;
    },
    {
      &quot;src&quot;: &quot;./icons/apple-touch-icon-60x60.png&quot;,
      &quot;sizes&quot;: &quot;60x60&quot;,
      &quot;type&quot;: &quot;image/png&quot;
    },
    {
      &quot;src&quot;: &quot;./icons/apple-touch-icon-72x72.png&quot;,
      &quot;sizes&quot;: &quot;72x72&quot;,
      &quot;type&quot;: &quot;image/png&quot;
    },
    {
      &quot;src&quot;: &quot;./icons/apple-touch-icon-76x76.png&quot;,
      &quot;sizes&quot;: &quot;76x76&quot;,
      &quot;type&quot;: &quot;image/png&quot;
    },
    {
      &quot;src&quot;: &quot;./icons/apple-touch-icon-114x114.png&quot;,
      &quot;sizes&quot;: &quot;114x114&quot;,
      &quot;type&quot;: &quot;image/png&quot;
    },
    {
      &quot;src&quot;: &quot;./icons/apple-touch-icon-120x120.png&quot;,
      &quot;sizes&quot;: &quot;120x120&quot;,
      &quot;type&quot;: &quot;image/png&quot;
    },

    {
      &quot;src&quot;: &quot;./icons/apple-touch-icon-144x144.png&quot;,
      &quot;sizes&quot;: &quot;144x144&quot;,
      &quot;type&quot;: &quot;image/png&quot;
    },
    {
      &quot;src&quot;: &quot;./icons/apple-touch-icon-152x152.png&quot;,
      &quot;sizes&quot;: &quot;152x152&quot;,
      &quot;type&quot;: &quot;image/png&quot;
    },
    {
      &quot;src&quot;: &quot;./icons/favicon-512x512.png&quot;,
      &quot;sizes&quot;: &quot;512x512&quot;,
      &quot;type&quot;: &quot;image/png&quot;
    }
  ],
  &quot;start_url&quot;: &quot;/&quot;,
  &quot;display&quot;: &quot;standalone&quot;,
  &quot;theme_color&quot;: &quot;#031230&quot;,
  &quot;background_color&quot;: &quot;#031230&quot;
}
}
- display: standalone은 브라우저의 주소칸과 버튼을 숨겨준다.
- theme_color는 PWA의 바 색상이 되고 background_color은 splash화면의 색상이다.

### 💬 4. PWA 설정 마무리
- 기존 프로젝트에서 service worker는 가져왔지만 여기에 필요한 npm은 가져오지 않았다.
- 아래 모듈을 package.json에 저장하고 npm install해준다.</code></pre><p>&quot;dependencies&quot;: {
    &quot;workbox-background-sync&quot;: &quot;^5.1.4&quot;,
    &quot;workbox-broadcast-update&quot;: &quot;^5.1.4&quot;,
    &quot;workbox-cacheable-response&quot;: &quot;^5.1.4&quot;,
    &quot;workbox-core&quot;: &quot;^5.1.4&quot;,
    &quot;workbox-expiration&quot;: &quot;^5.1.4&quot;,
    &quot;workbox-google-analytics&quot;: &quot;^5.1.4&quot;,
    &quot;workbox-navigation-preload&quot;: &quot;^5.1.4&quot;,
    &quot;workbox-precaching&quot;: &quot;^5.1.4&quot;,
    &quot;workbox-range-requests&quot;: &quot;^5.1.4&quot;,
    &quot;workbox-routing&quot;: &quot;^5.1.4&quot;,
    &quot;workbox-strategies&quot;: &quot;^5.1.4&quot;,
    &quot;workbox-streams&quot;: &quot;^5.1.4&quot;
}</p>
<p>```</p>
<ul>
<li><p>앱을 product로 실행시키고 chrome 개발자 도구 에서 아래 옵션을 선택해준다.
<img src="https://velog.velcdn.com/images/mingjuu_u/post/8f9db3b1-79a0-410e-be51-79f2bdf3f6fb/image.png" alt=""></p>
</li>
<li><p>installable이 가능해지면, 모바일 브라우저를 통해 다운받고 설치할 수 있다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Query 공부하기]]></title>
            <link>https://velog.io/@mingjuu_u/React-Query</link>
            <guid>https://velog.io/@mingjuu_u/React-Query</guid>
            <pubDate>Wed, 08 Mar 2023 08:29:39 GMT</pubDate>
            <description><![CDATA[<h1 id="react-query란">React Query란?</h1>
<blockquote>
<p>React Query는 React 애플리케이션에서 데이터를 관리하기 위한 라이브러리로 API 호출, 캐싱, 데이터 갱신 등 다양한 기능을 제공합니다. 이를 통해 React 개발을 보다 쉽고 효율적으로 할 수 있습니다. 
React Query는 React 개발자들이 많이 사용하는 라이브러리 중 하나입니다.</p>
</blockquote>
<ul>
<li>API 호출 관리: React Query는 API 호출을 관리하기 위한 여러 가지 유용한 함수들을 제공합니다. 이를 통해 API 호출을 처리하고, 데이터를 가져오거나 업데이트할 수 있습니다.</li>
<li>캐싱: React Query는 API 호출 결과를 캐싱하여 성능을 향상시킵니다. 이를 통해, 동일한 데이터에 대한 반복적인 API 호출을 줄일 수 있으며, 불필요한 네트워크 트래픽을 줄일 수 있습니다.</li>
<li>데이터 갱신: React Query는 자동으로 데이터를 갱신하고, 필요한 경우 화면을 다시 렌더링합니다. 이를 통해 데이터의 일관성을 유지하며, 사용자 경험을 개선할 수 있습니다.</li>
<li>비동기 작업 관리: React Query는 비동기 작업을 관리하는 데 유용한 함수들을 제공합니다. 이를 통해, 복잡한 비동기 작업을 보다 쉽고 간편하게 처리할 수 있습니다.</li>
</ul>
<h1 id="📘-query-key">📘 Query Key</h1>
<h3 id="💬-react-query-devtools">💬 React Query Devtools</h3>
<ul>
<li>Query key로 Query를 표시해주고 활성, 비활성 만료 등에 해당하는 모든 쿼리의 상태를 알려준다.</li>
<li>마지막으로 업데이트된 timestamp를 알려준다.</li>
<li>Data explorer</li>
<li>Query explorer</li>
<li>Stale Data<ul>
<li>React Query에서 refetcing은 만료된 data에서만 실행된다.</li>
<li>staleTime은 데이터의 유지 시간이다.</li>
<li>useQuery(쿼리키, 쿼리함수, staleTime)</li>
<li>Data가 만료됬을때만 refetching이 실행된다.</li>
</ul>
</li>
<li>Cache Time<ul>
<li>Query instance가 unmounted 되면 데이터가 inactive되며 cache는 cache time 동안 유지된다.</li>
<li>cache time이 지나면 garbage로 수집된다.</li>
</ul>
</li>
</ul>
<h3 id="💬-query-key">💬 Query Key</h3>
<ul>
<li>모든 Query가 동일한 Query key를 사용하고 있으면 데이터가 만료된 상태임에도 refetching 하지 않는다.</li>
<li>이런 경우에는 어떠한 트리거가 있어야만 데이터를 다시 가져온다.<ul>
<li>예를 들어, 컴포넌트를 다시 마운트하거나</li>
<li>윈도우를 다시 focus할 때</li>
<li>useQuery에서 반환되어 수동으로 refetching을 실행할 때</li>
<li>지정된 간격으로 refetching을 자동으로 실행할 때</li>
<li>혹은 mutation을 생성한 뒤 Query를 무효화할 때 client data와 server data가 불일치 하면 refetching이 트리거 된다. </li>
</ul>
</li>
<li>따라서 Query key에 문자열 대신 배열을 전달하여 이러한 문제를 해결한다.</li>
<li>배열의 첫 번재 요소로 문자열을 갖고 두번째 요소로 post.id를 갖게 한다.</li>
<li>Query key가 변경되면, 다시 말해 post.id가 업데이트 되면 React Query가 새 Query를 생성하므로 모든 Query가 동일하지 않은 Query key를 갖는다고 간주한다.</li>
</ul>
<h3 id="💬-pagination">💬 Pagination</h3>
<ul>
<li>페이지마다 다른 Query key를 사용해서 페이지를 유지한다.</li>
</ul>
<h1 id="📗-data--cache">📗 Data &amp; Cache</h1>
<h3 id="💬--pre-fetching">💬  Pre-fetching</h3>
<ul>
<li>데이터를 미리 가져와 cache에 넣어 사용자가 기다릴 필요가 없도록 만든다.</li>
<li>다시 말해 Pre-fetching은 데이터를 cache에 추가하여 구성할 수 있지만 stale 상태로 불러오는 것이다.</li>
</ul>
<h3 id="💬-isfetching-vs-isloading">💬 isFetching vs isLoading</h3>
<ul>
<li>isFetching의 경우 async query 함수가 해결되지 않았을때 true이다.</li>
<li>isLoading은 isFetching이 true이면서 Query에 대해 cache된 data가 없는 상태를 뜻합니다.<ul>
<li>즉, isLoading 상태이거나 isLoading이 참인 경우 isFetching 또한 참입니다.</li>
</ul>
</li>
<li>isLoading을 isFatching으로 변경하게 되면 cache된 data의 존재 여부와 관계 없이 실행된다.<ul>
<li>우리가 원하는 방식은 대개 isLoading이다.</li>
</ul>
</li>
</ul>
<h3 id="💬-mutations">💬 Mutations</h3>
<ul>
<li>mutation은 서버에 데이터를 업데이트 하도록 서버에 네트워크 호출을 실시한다.</li>
<li>useMutation은 일부 예외를 제외하고 useQuery와 상당히 유사하다.</li>
<li>mutate 함수를 반환하는데 사용하는 mutate 함수는 데이터를 저장하지 않으므로 Query key는 필요하지 않다.</li>
<li>또한, 캐시된 항목이 없으므로 isLoading은 존재하지만 isFetching은 존재하지 않는다.</li>
<li>useQuery의 경우 default 값으로 3회 재시도하나 useMutation은 default값은 없고 설정 가능하다.</li>
</ul>
<h1 id="📙-infinite-scroll">📙 Infinite scroll</h1>
<ul>
<li>사용자가 scroll할 때마다 새로운 데이터를 가져온다.</li>
<li>모든 데이터를 한 번에 가져오는 거보다 효율적이다.</li>
<li>사용자가 버튼을 클릭해서 새로운 데이터를 요청하거나 페이지의 특정 지점을 스크롤 했을 때 새 데이터를 가져오게 한다.</li>
<li>useInfiniteQuery를 사용한다.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>