<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Chan</title>
    <description>The latest articles on Forem by Chan (@algoorgoal).</description>
    <link>https://forem.com/algoorgoal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F517681%2F66e6161f-728b-4704-a50e-10d53f60bc52.jpg</url>
      <title>Forem: Chan</title>
      <link>https://forem.com/algoorgoal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/algoorgoal"/>
    <language>en</language>
    <item>
      <title>Frontend Fundamentals 모의고사 2 후기</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Thu, 26 Mar 2026 13:59:37 +0000</pubDate>
      <link>https://forem.com/algoorgoal/frontend-fundamentals-moyigosa-hugi-4i3k</link>
      <guid>https://forem.com/algoorgoal/frontend-fundamentals-moyigosa-hugi-4i3k</guid>
      <description>&lt;p&gt;간략하게 Lessons Learned만 일단 정리하여 공유합니다.&lt;/p&gt;

&lt;h1&gt;
  
  
  Lessons Learned
&lt;/h1&gt;

&lt;h2&gt;
  
  
  도메인으로 포함되는 로직 감싸기
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q. query 관련 로직을 컴포넌트 내부에 배치할까, 외부에 배치할까?
&lt;/h3&gt;

&lt;p&gt;다음은 예약 현황 페이지에서 내 현황 영역 컴포넌트를 렌더링하는 부분만 짧게 가져온 code snippet이다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;funciton&lt;/span&gt; &lt;span class="nc"&gt;ReservationStatusPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;myReservationList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMyReservations&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyReservationSection&lt;/span&gt; &lt;span class="nx"&gt;myReservationList&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;myReservationList&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;getRoomName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;getRoomName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onCancel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleCancel&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;useMyReservations&lt;/code&gt;(query 관련 로직)을 부모에 정의할까, 아니면 컴포넌트 내부에 정의할까 고민을 많이했는데 중요한 고민이 아닌 거 같아 컴포넌트 밖에서 정의했다.&lt;/p&gt;

&lt;h3&gt;
  
  
  A. 도메인을 이름에 나타냈으면 안에서 도메인 로직을 책임지게 만들자.
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;MyReservationSection&lt;/code&gt;이라는 이름이 붙은 순간 이 컴포넌트는 특정 도메인의 로직을 처리하는 컴포넌트라는 맥락을 가지므로, query data를 굳이 외부에서 줄 필요 없이 내부에서 정의하는 게 추상화 레벨에 맞는 거 같다.&lt;/p&gt;

&lt;h2&gt;
  
  
  네임스페이스 패턴 과다사용 경계하기
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;같은 name에 묶여서 내부 구현을 숨겨버리는 효과가 발생한다. 따라서 개발자가 구현이 알고 싶으면 직접 구현을 찾아들어가게 만들텐데, 이럴 필요가 있는지 다시 한번 생각해 볼 필요가 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;예)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimeSelect&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimeSelect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;선택 가능 시간&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimeSelect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimeSelect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;10:00&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimeSelect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimeSelect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;10:30&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimeSelect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimeSelect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;10:30&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TimeSelect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TimeSelect&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;문제점: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML Native element 'select'의 컨벤션을 따르고 있지 않아 예측하기가 어렵다.&lt;/li&gt;
&lt;li&gt;TimeSelect namespace에 어떤 컴폰넌트가 있는지 알고 싶다면 AI던 개발자던 결국 소스코드를 탐색해서 들어가야 한다. Title 컴포넌트가 숨겨져 있어서 존재 자체를 알기 어려워 다른 개발자들은 &lt;code&gt;TimeSelect.Title&lt;/code&gt;을 사용하지 않고 직접 구현하게 되는 일까지 벌어질 수 있다. 이러면 유지보수하기 더욱 힘들어질 것이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  여전히 의문인 점
&lt;/h2&gt;

&lt;h3&gt;
  
  
  리팩토링 단계 설계하기
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;재엽님이 코드를 고치신 방식: 인터페이스를 먼저 설계하신 다음에 LLM에게 인터페이스대로 리팩토링해달라고 지시함.&lt;/li&gt;
&lt;li&gt;문제점: 프로덕션 코드 같은 경우 그렇게 수정하면 그렇게 변경점이 많아져 리뷰어가 리뷰하기가 힘들 거다. 따라서 레거시 코드의 리팩토링을 단계별로 진행해야 할텐데 어떤 식으로 단계별로 쪼개야 할까?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  P.999 onChange 대신에 onValueChange는 어떠한가?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Native HTML의 인터페이스를 그대로 웬만해서 가져오는 게 예측하기 쉽다고 말씀하셨고, 이에는 전반적으로 동의한다.&lt;/li&gt;
&lt;li&gt;그런데 onChange 같은 경우에는 event를 인자로 전달해주는 함수라는 느낌이 든다. 따라서 value를 전달하는 함수라는 것을 명확히 해주기 위해 onValueChange라는 이름으로 핸들러 인터페이스를 구성하는 것은 어떤가?&lt;/li&gt;
&lt;li&gt;레퍼런스: Radix-Primitive의 `onValueChange' 함수 인터페이스(&lt;a href="https://www.radix-ui.com/primitives/docs/components/tabs" rel="noopener noreferrer"&gt;https://www.radix-ui.com/primitives/docs/components/tabs&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>frontend</category>
      <category>learning</category>
      <category>react</category>
    </item>
    <item>
      <title>알쓸신네(알아두면 쓸데없는 신비한 네트워크 사전)</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Sun, 22 Mar 2026 04:41:02 +0000</pubDate>
      <link>https://forem.com/algoorgoal/alsseulsinnealadumyeon-sseuldeeobsneun-sinbihan-neteuweokeu-sajeon-4ai5</link>
      <guid>https://forem.com/algoorgoal/alsseulsinnealadumyeon-sseuldeeobsneun-sinbihan-neteuweokeu-sajeon-4ai5</guid>
      <description>&lt;h2&gt;
  
  
  포트
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;포트의 용도&lt;/strong&gt;: 호스트 내부에서 어떤 프로세스에 전송해야되는 패킷인지 표시하는 용도로 사용한다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;예: 카카오톡, 디스코드 모두 실행중일 때 메시지를 카톡 답장이 오면 디스코드 프로세스가 아닌 카카오톡 프로세스로 전송이 되어야 한다. 이를 포트로 구분한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;고정 포트와 임시 포트(ephemeral port)&lt;/strong&gt;: 프로토콜의 종류에 따라 서버의 포트는 well-known port(잘 알려진 고정 포트)를 사용한다. 반면 클라이언트는 임시 포트를 발급 받아서 사용한다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;프로토콜 별로 사용되는 서버의 고정 포트는 application protocol(http, https, websocket 등)에서 정의한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;클라이언트의 운영체제는 전송 계층 connection이 open될 때 임시 포트를 할당해주고, connection이 close될 때 할당된 포트를 회수한다.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  MAC 주소와 IP 주소
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IP 주소&lt;/strong&gt;: 인터넷에서 특정 호스트를 식별하기 위한 주소&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MAC 주소&lt;/strong&gt;: 물리적인 데이터 전송을 위해서 기기가 가지는 고유한 식별자. 기기의 NIC(네트워크 인터페이스 카드) 부품에 MAC 주소가 할당된다.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MAC 주소의 용도&lt;/strong&gt;: 네트워크에서 물리적으로 연결된 인접 노드(adjacent nodes)끼리 데이터를 전송하는데 사용되는 식별자이다.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MAC 주소를 인터넷의 라우팅에 사용하지 않는 이유&lt;/strong&gt;: 규칙성이 없기 때문이다. IP 주소의 경우, 지역에 따라 사용하는 IP 주소가 달라지는 규칙이 있다. 따라서 이 규칙을 통해 중간 라우터 어떤 인접 노드로 어디로 보내야되는지 decision making이 가능하다. 다만 MAC 주소는 그런 규칙이 없다. 따라서 MAC 주소를 인터넷의 라우팅에서는 활용하는 게 비실용적이다.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;라우터의 데이터 전송 과정&lt;/strong&gt;: 패킷의 목적지 (destination)을 입력으로 받으면, 가지고 있는 라우팅 테이블을 확인하여 패킷을 넘겨야하는 인접 라우터의 ip address로 변환 =&amp;gt; ARP table을 통해 ip address를 mac 주소로 변환 =&amp;gt; 해당 mac 주소를 가진 인접 라우터에 패킷 전송&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;일상 속에서 IPv6 주소는 볼 수 없고, IPv4주소만 보이는 이유?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IPv4의 잔여 주소가 거의 바닥나는 중이나, 아직 남은 주소가 있긴 함&lt;/li&gt;
&lt;li&gt;네트워크 장비에서 IPv6를 지원하도록 전환하는데 비용이 들어 관련자(대표적으로 ISP)들은 최대한 IPv4를 유지하려고 노력 중. 따라서 IPv6 실사용은 계속 늦춰지고 있다.&lt;/li&gt;
&lt;li&gt;공인 IP의 사용으로 인해 문제가 일시적으로 해소되었다. 어차피 인터넷에서 통신하는 경우 기기에 연결된 공유기의 외부 IP(공인 IP)로 통신하기 때문에, 주소 부족 문제가 극적으로 나타나지 않는다.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  내부 IP, 내부 포트 / 공인 IP, 외부 포트
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;내부 IP&lt;/strong&gt;: 공유기에 연결된 호스트끼리 서로를 구분하는데 사용하는 식별자&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;내부 포트&lt;/strong&gt;: 호스트에서 실행되는 프로세스끼리 서로의 패킷을 구분하는데 쓰는 식별자&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;공인 IP&lt;/strong&gt;: 패킷이 인터넷으로 전송되기 위해 공유기 바깥으로 나갈 때 쓰는 공식 IP 주소. ISP(LG, SKT, KT)가 구매하여 소유하고 있고, 사용자의 공유기에 외부 IP를 할당하는 방식으로 운영된다.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;외부 포트&lt;/strong&gt;: 패킷이 인터넷으로 전송되기 위해 공유기 바깥으로 나갈 때 쓰는 포트 번호.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;공유기는 내부 IP로 사용될 IP address의 풀을 들고 있고, 새로운 기기가 연결될 때 ip address 풀에서 하나의 ip address를 해당 기기의 내부 포트로 지정한다.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;공유기는 내부 IP/포트 &amp;lt;-&amp;gt; 공인 IP/포트 매핑을 저장하는 테이블이 있는데, 이를 NAT(Network Address Translation) 테이블이라고 부른다. 이를 통해, 수신한 패킷을 LAN의 어떤 호스트에게 전달해야 하는지 정확히 알 수 있다.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  공유기, 라우터 그리고 모뎀
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;라우터&lt;/strong&gt;: IP 기반 라우팅과 패킷 전달 기능만 있으면 라우터라고 부를 수 있다.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;공유기&lt;/strong&gt;: 라우터 + 스위치(LAN 네트워크 안의 호스트끼리 mac 주소로 통신) + 무선 AP(access point, wifi 기능) + NAT(내부 IP =&amp;gt; 공인 IP 변환) + DHCP(연결된 호스트에 내부 IP 자동 할당) + 방화벽 기능을 탑재한 장비&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;모뎀&lt;/strong&gt;: 인터넷 회선으로 데이터를 보낼 수 있게, 디지털 신호를 아날로그 신호로 변환해줄 수 있는 장비&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>network</category>
    </item>
    <item>
      <title>실패 인정하기</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Sun, 08 Mar 2026 12:43:32 +0000</pubDate>
      <link>https://forem.com/algoorgoal/silpae-injeonghagi-2a33</link>
      <guid>https://forem.com/algoorgoal/silpae-injeonghagi-2a33</guid>
      <description>&lt;p&gt;기술 얘기만 꺼내다가 요즘 인생을 대하는 태도가 서서히 바뀌는 것을 느껴서 작성한다. 19년부터 최근까지 기억에 남는 실패들에 대해서 서술해보고, 그로 인해 바뀐 태도나 행동거지를 서술하였다. 그리고 앞으로 겪을 실패에 대응하기 위한 마인드셋 및 미래 계획도 포함하였다.&lt;/p&gt;

&lt;h2&gt;
  
  
  처음 초보자로서 실패한 경험 (2019-2020)
&lt;/h2&gt;

&lt;p&gt;대학교 2학년 때 연합동아리 및 네이버 부스트캠프를 지원하여 탈락하였다. 서류 지원시 3000자 분량의 자기소개서 제출이 필요하였는데 LLM이 발달하지 않았던 시절이라 정성을 들여서 한땀한땀 작성하였다. 당시 전공 기초 과목들 위주로 수업을 들었던지라 프로젝트 경험이 하나밖에 없었는데 어떻게던 쥐어짜서 3000자를 채워냈었다. 그렇게 에너지를 쏟아서 서류를 제출했으나 탈락이라는 결과를 받았다. 탈락이 트라우마로 작용하여 이외의 연합동아리 및 우아한테크코스에 지원하지 않았던 것으로 기억한다.&lt;/p&gt;

&lt;p&gt;해당 실패의 원인을 생각해보면 수행했던 프로젝트의 기간과 완성도의 문제였던 거 같다. 3개월 동안 진행한 프로젝트인데, 당시 인증/인가를 처음 다뤄보는데 깃헙의 OAuth까지 활용이 필요했던터라 인증 개발만 수행하는데 시간을 거의 할애했다. 다른 핵심 기능들의 완성도가 낮다보니 서류 평가자들에게 매력적으로 보이지 않았을 것으로 생각한다.&lt;/p&gt;

&lt;h2&gt;
  
  
  알고리즘 문제를 풀 때의 좌절(2020-2021)
&lt;/h2&gt;

&lt;p&gt;코로나19가 한창 유행하던 시절에 프로젝트를 같이 진행했던 친구들과 알고리즘 문제를 풀려고 노력했다. 친구들과 나를 비교하면서 나는 하루종일 고민해도 풀지 못했던 문제들을 친구들은 대부분 1~2시간 이내에 푸는 것을 보면서 많이 좌절했던 기억이 있다. 알고리즘 문제를 풀 때 느끼는 성취감보다는 좌절감이 감정을 지배해서 결국에는 동기부여가 크게 되지 않아서 열정적으로 공부하지 않았었다. 다음 두가지 패인이 결정적으로 작동했던 것 같다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;죽어도 답을 보지 않겠다는 태도: 당시에는 기본적인 다이나믹 프로그래밍, 분할정복, 그래프, 그리디 알고리즘에 익숙해져있지 않았는데 답지를 보는 게 패배를 인정하는 것이라고 생각하여 일주일, 이주일이고 한 문제를 고민하려고 했었다. 지금 와서 생각해보면 상대성이론이나 만류인력의 법칙을 바로 떠올리려고 한 것이나 다름 없다고 생각한다. 기본이 되는 이론이므로 일종의 수학 공식이라 볼 수 있는 코드 템플릿과 아이디어를 스스로 떠올리기 힘든 것들이 상당히 많았다고 생각한다.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;수학적 엄밀함에 대한 집착: 다른 블로그 문제 해설을 봐도 살짝 엄밀한 수학적 증명을 하지 않는 모호한 부분들이 있었는데 이를 전부 내 나름대로 명확히 하려는 시도를 하는데 시간을 쏟았다. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;학자적인 접근에 취해있다보면 돈을 벌지 못한다. 역사적으로 특정한 이론을 발견해낸 사람들보다 그것을 배워서 문제 해결에 사용한 사람들이 돈을 벌었다. 영화 이미테이션 게임의 주인공 엘런 튜링은 컴퓨테이션 이론의 창시자지만 살아생전에 부유하게 지내지는 못했다. 반면 IT 기술을 대중화에게 보급한 빌게이츠, 마크 주커버그, 제프 베조스 등은 돈을 쓸어담고 있다. 이렇듯이 실제로 현실적으로 코딩테스트를 통과하는 사람들이 돈을 더 잘 버니까, 요즘에는 납득 가능한 범위에서 수학적 설명을 생략하려고 시도하는 경우도 많아졌다.&lt;/p&gt;

&lt;h2&gt;
  
  
  초보자가 힘든 시기, 더욱더 실패 인정하기
&lt;/h2&gt;

&lt;p&gt;2024년부터 현재까지 인턴 및 정규직 지원을 꾸준히 하였는데, 채용 전형의 난도가 날이 갈수록 올라간다고 느낀다. 우수한 지원자들이 많다보니 조금이라도 회사의 문화에 맞지 않거나 기술적 역량이 부족해 보일 경우 탈락 당한다. 따라서 서류나 면접이 떨어질 때마다 일희일비하기보다는 부족한 부분을 성찰하는 학습의 과정으로 보고 마음의 짐을 좀 덜어놨으면 좋겠다. 이 글을 읽는 독자와 나 모두 말이다. 나는 10번이 넘는 인턴/정규직 면접에 탈락했지만, 올해까지는 프론트엔드로 취업을 시도해볼 예정이다. 면접 경험을 통해 지식의 공백과 언어적 능력이 개선되는 것이 체감되지만, 아직 결과로는 증명을 하지 못했다.&lt;/p&gt;

&lt;h2&gt;
  
  
  앞으로 어떻게 할래?
&lt;/h2&gt;

&lt;p&gt;전통적인 알고리즘 코딩테스트도 같이 준비를 하고 있다. 여기에는 세가지 이유가 있다. 첫번째, 신입 개발자로서 코딩테스트가 없는 전형의 경우 면접을 통해 걸러지기가 너무 쉽다고 생각한다. 두번째, 문제에서 주어지는 가능한 상태를 사전에 탐색하고 데이터를 모델링하는 설계 능력이 부족하다고 생각했기 때문이다. 이는 토스 프론트엔드 과제를 보고 피드백을 받으면서 체감했는데, 알고리즘 문제의 경우 설계가 중요해서 문제를 풀다 보면 개선이 되지 않을까 생각한다. 세번째, 프론트엔드 취업에 계속 실패하여 백엔드, 또는 다른 IT 직종의 일을 하더라도 기본 능력에 가까운 알고리즘 문제 해결 능력이 취업에 도움이 될 수 있다고 생각한다.&lt;/p&gt;

&lt;p&gt;점점 사회가 초보자를 경멸하는 시대로 전락하고 있다고 생각한다. 그에 따라 독자분들도 작은 실패와 큰 실패를 경험하고 더 많은 실패가 두려워질 거라고 생각한다. 나도 그랬기 때문이다. 하지만 실패했을 때 일어날 일들을 생각해보면 좋겠다. 나만 쪽팔리고 주변 사람들은 별로 신경도 안 쓴다. 인생 망하지 않고 알바라도 해서 먹고살 수는 있다. 요즘 나는 면접에 들어갈 때마다 이런 생각을 하면서 최대한 부담을 덜어보는데 효과가 좋은 거 같다. 혹시 도움이 될 거 같다면 시도해보시면 좋겠다.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>미친 react key</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Sun, 15 Feb 2026 14:42:24 +0000</pubDate>
      <link>https://forem.com/algoorgoal/micin-react-key-4ogo</link>
      <guid>https://forem.com/algoorgoal/micin-react-key-4ogo</guid>
      <description>&lt;p&gt;map을 통한 렌더링&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Child&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;실험 결과: 1 2 3 4 5&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Child&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;실험 결과: 6, 7, 8, 9, 10, 1, 2, 3, 4, 5&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Child&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;실험 결과: 10&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Child&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;실험 결과: 10&lt;/p&gt;

&lt;p&gt;실험 1&lt;br&gt;
상태: [1, 2, 3, 4, 5] =&amp;gt; [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]&lt;br&gt;
결과:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;react.memo로 감싸지 않았을 경우: 

&lt;ul&gt;
&lt;li&gt;key가 item인 경우: 리렌더링시 6, 7, 8, 9, 10, 1, 2, 3, 4, 5 출력&lt;/li&gt;
&lt;li&gt;key가 index인 경우: 리렌더링시 6, 7, 8, 9, 10, 1, 2, 3, 4, 5 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;react.memo로 감쌌을 경우:

&lt;ul&gt;
&lt;li&gt;key가 item인 경우: 리렌더링시 6, 7, 8, 9, 10 출력&lt;/li&gt;
&lt;li&gt;key가 index인 경우: 6, 7, 8, 9, 10, 1, 2, 3, 4, 5 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;실험 2&lt;br&gt;
상태: [1, 2, 3, 4, 5] =&amp;gt; [1, 2, 10, 4, 5]&lt;br&gt;
결과:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;react.memo로 감싸지 않았을 경우: 

&lt;ul&gt;
&lt;li&gt;key가 item인 경우: 리렌더링시 1, 2, 10, 4, 5 출력&lt;/li&gt;
&lt;li&gt;key가 index인 경우: 리렌더링시 1, 2, 10, 4, 5 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;react.memo로 감쌌을 경우:

&lt;ul&gt;
&lt;li&gt;key가 item인 경우: 리렌더링시 10 출력&lt;/li&gt;
&lt;li&gt;key가 index인 경우: 1, 2, 10, 4, 5 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;결론:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;react memo를 사용하면 부모 리렌더링시, 동일한 key에 대해 prop이 변경되지 않는다면 자식의 리렌더링이 발생하지 않는다. 다만 prop이 변경되면 리렌더링이 발생한다.&lt;/li&gt;
&lt;li&gt;react memo를 사용하지 않는다면 부모 리렌더링시 항상 자식의 리렌더링이 발생한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;실험 2&lt;br&gt;
부모 컴포넌트 상태: [1, 2, 3] =&amp;gt; [3, 2, 1]&lt;br&gt;
자식 컴포넌트 상태: text&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toReversed&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Child&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;th textfield: 
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;결과:&lt;/p&gt;

&lt;p&gt;실험 2&lt;br&gt;
부모 컴포넌트 상태: [1, 2, 3] =&amp;gt; [3, 2, 1]&lt;br&gt;
자식 컴포넌트 상태: text&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toReversed&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Child&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;th textfield: 
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setArray&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toReversed&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Child&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;th textfield: 
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;결과:&lt;/p&gt;

&lt;p&gt;원인: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;이전렌더 key의 컴포넌트 종류 === 이후 렌더 컴포넌트 종류일 경우 unmount/mount하지 않는다. 실험 같은 경우 Child로 이전 렌더와 이후 렌더의 컴포넌트 종류 같아서 unmount/mount가 발생하지 않는다.&lt;/li&gt;
&lt;li&gt;이전 렌더 컴포넌트와 이후 렌더 컴포넌트에서 같은 종류의 컴포넌트 instance에 대해서는, state가 유지된다. 즉, key와 state가 매핑된다. 따라서 index를 key로 사용하였을 경우, array 순서 변경이 일어날 때 index와 자식 상태(text)가 매핑되어서 순서 변경이 제대로 일어나지 않는다. 반면 item을 key로 사용하였을 경우에는 array 순서 변경이 일어날 때 item와 자식 상태(text)가 매핑되어서 순서 변경이 정상적으로 같이 일어난다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  결론
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;index를 key로 사용해도 괜찮다. 다만 요소 순서의 변경이 일어날 때는 index를 key로 사용하면 안 된다.&lt;/li&gt;
&lt;li&gt;자식 컴포넌트의 상태가 key와 매핑되는데, index와 매핑되는 경우 요소 순서 변경이 일어나도 상태 순서 변경이 일어나지 않기 때문이다.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>전역 상태 관리에 대한 고찰</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Thu, 05 Feb 2026 15:16:02 +0000</pubDate>
      <link>https://forem.com/algoorgoal/jeonyeog-sangtae-gwanrie-daehan-gocal-34pn</link>
      <guid>https://forem.com/algoorgoal/jeonyeog-sangtae-gwanrie-daehan-gocal-34pn</guid>
      <description>&lt;h2&gt;
  
  
  전역 상태 관리가 필요한 상황
&lt;/h2&gt;

&lt;p&gt;props drilling이 과도하게 일어나서, 중간 컴포넌트가 자신과 상관 없는 props를 들고 있어야하는 경우에 전역 상태 관리가 필요해진다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    A
   / \
  B   C
 / \ / \
D  E F  G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;컴포넌트 트리가 다음과 같이 구성되어 있다고 하자. D, E에서 데이터에 대한 접근이 필요하고, F, G에서 데이터를 변경하는 action에 대한 접근이 필요하다고 해보자. 그러면 B와 C에서는 자기 책임이 아닌 action들까지 자식 컴포넌트에 내려줘야하는 문제가 발생하여, 유지보수가 힘들어진다.&lt;/p&gt;

&lt;p&gt;전역&lt;/p&gt;

&lt;h2&gt;
  
  
  전역 상태 관리를 위한 두가지 요소
&lt;/h2&gt;

&lt;p&gt;전역 상태 관리를 수행하기 위해 필요한 요소를 두가지로 분해해볼 수 있다.&lt;/p&gt;

&lt;h3&gt;
  
  
  상태 관리
&lt;/h3&gt;

&lt;h3&gt;
  
  
  데이터 주입
&lt;/h3&gt;

&lt;h2&gt;
  
  
  context를
&lt;/h2&gt;

&lt;p&gt;전역 상태 관리의 두 부분&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;상태 관리: 상태에 대한 getter와 setter&lt;/li&gt;
&lt;li&gt;데이터 주입: 정의된 상태를 컴포넌트들이 쓸 수 있게 넘겨주는 과정&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;context는 데이터를 특정 컴포넌트 트리에 주입시킬 수 있는 '데이터 주입' 툴에 해당한다. 따라서 context를 통해 전역 상태 관리를 하겠다면 상태를 선언하고 이를 같이 주입해줄 수 있어야한다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ThemeProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useTheme&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buildContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ThemeContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;funtion&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ThemeProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ThemeProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  접근 제어성
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;부스 생성 상태의 경우 생성 페이지, 수정 상태의 경우 &lt;/li&gt;
&lt;li&gt;useFormContext()&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  리렌더링
&lt;/h2&gt;

&lt;h2&gt;
  
  
  contex
&lt;/h2&gt;

&lt;p&gt;전역 상태로 빼는 기준&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;deeply nested object&lt;/li&gt;
&lt;li&gt;접근 제어 목적인지, 모든 애플리케이션에서 공유 목적인지&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;전역 상태 관리를 수행하기 위해 두가지 요소가 필요&lt;/strong&gt;하다.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;상태 관리&lt;/li&gt;
&lt;li&gt;데이터 주입&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;는 데이터를 특정 컴포넌트 트리에서 접근할 수 있게 만드는 접근 제어자. 전역 상태관리에 쓴다면 (2)만 수행.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;전역 상태 관리 라이브러리&lt;/strong&gt;는  (1)과 (2)를 전부 수행하는데, 기본적으로 전역으로 데이터가 접근 가능하다.(global store)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;언제, 무엇을 사용할까?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;전달해야되는 데이터가 간단하고, 특정 컴포넌트 트리로 한정 =&amp;gt; context로 주입만 해도 문제 해결&lt;/li&gt;
&lt;li&gt;전달해야되는 데이터가 간단하고, 전역에서 쓰고 싶음 =&amp;gt; context도 ok, jotai도 써볼만함&lt;/li&gt;
&lt;li&gt;전달해야되는 데이터가 복잡하다 =&amp;gt; 전역상태관리를 통해 devtools 디버깅, 리렌더링 최적화 같은 기능 사용 가능

&lt;ul&gt;
&lt;li&gt;예) deeply nested object 이거나, 상태 바꾸는 action 여러개 정의해야 함.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;전달해야되는 데이터가 복잡하고, 특정 컴포넌트 트리에 가두고 싶다 =&amp;gt; 전역 상태 관리 도구로 상태 정의하고, context로 접근 제어하는 방향으로 두개를 혼용해서 사용 가능하다.&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>frontend</category>
      <category>react</category>
      <category>typescript</category>
    </item>
    <item>
      <title>javascript의 함수 파라미터 퀴즈(call by value and call by reference)</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Thu, 05 Feb 2026 14:18:41 +0000</pubDate>
      <link>https://forem.com/algoorgoal/javascriptyi-hamsu-paramiteoe-daehayeo-5h08</link>
      <guid>https://forem.com/algoorgoal/javascriptyi-hamsu-paramiteoe-daehayeo-5h08</guid>
      <description>&lt;h2&gt;
  
  
  퀴즈
&lt;/h2&gt;

&lt;p&gt;다음 코드의 출력 결과를 맞춰보세요.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;changed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;changed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unchanged&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unchagned&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  기본 원리
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;함수 파라미터는 mutable하다.&lt;/li&gt;
&lt;li&gt;함수 파라미터는 block scope를 지닌다. lexical environment의 environment  record에 기록되고 관리되기 때문이다.&lt;/li&gt;
&lt;li&gt;함수 호출시, creation phase에 함수 파라미터의 값이 초기화된다. primitive value 인자는 값을 복사하고, reference value 인자는 참조(메모리 주소)를 가진다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  해석
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;a: primitive value이므로 전달시 값을 복사한다. a의 값을 변경했을 때 lexical environment의 environment record의 값이 변경되기 때문에 block scope만 값 변경의 영향을 받는다.&lt;/li&gt;
&lt;li&gt;b: reference value이므로 메모리 주소를 전달한다. b의 레퍼런스를 변경했을 때 lexical environment의 environment record의 값이 변경되기 때문에 block scope만 값 변경의 영향을 받는다.&lt;/li&gt;
&lt;li&gt;c: reference value이므로 메모리 주소를 전달한다. c의 내부 프로퍼티를 변경했을 때 객체 자체가 수정되는 것이기 때문에 block scope가 아닌 외부에서도 값 변경의 영향을 받는다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;따라서&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;unchanged&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unchanged&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;changed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;가 출력된다.&lt;/p&gt;

&lt;h2&gt;
  
  
  요약
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;함수 파라미터는 lexical environment의 environment record에 초기화되므로 block scope를 지닌다. 또한 mutable하다.&lt;/li&gt;
&lt;li&gt;함수 파라미터로 primitive value를 전달하면 복사본이 들어가고, refernce value를 전달하면 reference(메모리 참조값)이 들어간다.&lt;/li&gt;
&lt;li&gt;reference를 전달했을 때 내부 프로퍼티 값을 변경하면, 객체 자체의 값이 변경되어 동일한 객체를 가르키는 다른 스코프 식별자도 영향을 받는다.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>beginners</category>
      <category>computerscience</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>TCP와 UDP</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Fri, 30 Jan 2026 09:44:30 +0000</pubDate>
      <link>https://forem.com/algoorgoal/tcpwa-udp-oh</link>
      <guid>https://forem.com/algoorgoal/tcpwa-udp-oh</guid>
      <description>&lt;h2&gt;
  
  
  TCP
&lt;/h2&gt;

&lt;p&gt;Transmission Control Protocol의 약자이다. OSI Model 기준으로 L4에 해당하는 프로토콜이다.&lt;/p&gt;

&lt;h2&gt;
  
  
  UDP
&lt;/h2&gt;

&lt;p&gt;User Datagram Protocol의 약자이다. OSI Model 기준으로 L4에 해당하는 프로토콜이다.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Control &amp;amp; Retransmission
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;tcp: error detection과 error correction을 모두 수행한다. checksum이 올바르지 않다면 세그먼트를 재전송한다 지정된 시간 내 ack가 오지 않는다면 timeout이 되어 재전송이 발생한다.&lt;/li&gt;
&lt;li&gt;udp: error detection만 수행한다. checksum이 올바르지 않다면 전송된 세그먼트를 버린다. timeout은 없다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Handshake
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;tcp: connection open/close시 handshake를 한다.&lt;/li&gt;
&lt;li&gt;udp: connection open/close시 handshake를 하지 않는다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Congestion Control and Flow Control
&lt;/h3&gt;

&lt;p&gt;Tcp는 sliding window를 통해 여러개의 세그먼트를 한번에 보낸다. congestion control과 flow control은 얼마나 많은 세그먼트를 한번에 보낼지 조절해주는 역할을 한다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Congestion Control: 네트워크가 감당 가능한 만큼의 세그먼트만 보내는 방법이다. Congestion window를 보고 확인한다.&lt;/li&gt;
&lt;li&gt;Flow Control: 수신자의 버퍼가 넘쳐 데이터 유실이 나지 않게 보내는 방법이다. Recevier window를 보고 확인한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  tcp connection open이 3 way handshake인 이유
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;tcp는 full duplex이다. A-&amp;gt;B 채널, B-&amp;gt;A 별도로 존재하고, 송수신이 동시에 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;안정적인 데이터 전송을 보장하기 위해서는 A-&amp;gt;B 채널이 정상적으로 동작하는지, 그리고, B-&amp;gt;A 채널이 정상적으로 동작하는지 확인이 필요하다. 그래서 SYN / SYN + ACK / ACK의 3 way handshake가 필요하다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  tcp connection close가 4 way handshake인 이유
&lt;/h2&gt;

&lt;p&gt;A가 더이상 보낼 데이터가 없더라도, B는 보낼 데이터가 있을 때까지 기다려줘야 하기 때문에 4 way handshake를 한다. A는 송신 종료하고, B는 계속 송신을 하고 있는 이 상태를 half-close라고 한다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A: B에게 자신은 더이상 전송할 데이터가 없다는 사실을 알려야 한다.(FIN)&lt;/li&gt;
&lt;li&gt;B: A의 FIN을 제대로 받았다는 사실을 알려야 한다.(ACK)&lt;/li&gt;
&lt;li&gt;B: A에게 자신은 더이상 전송할 데이터가 없다는 사실을 알려야 한다. (FIN)&lt;/li&gt;
&lt;li&gt;A: B의 FIN을 제대로 받았다는 사실을 알려야 한다.(ACK)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  B의 FIN과 ACK를 한번에 보낼 수 없는 이유
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;B가 자신의 데이터를 전부 보낸 뒤에 FIN과 ACK를 동시에 보낸다고 하자. 그러면 A는 그동안 B가 FIN 세그먼트를 제대로 받았는지 알 수 없기 때문에 timeout이 계속 걸려 FIN 요청을 보내버리는 등 사이드 이펙트가 발생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>react query를 잘 쓰는 방법</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Sun, 25 Jan 2026 14:57:26 +0000</pubDate>
      <link>https://forem.com/algoorgoal/react-queryreul-jal-sseuneun-bangbeob-19ch</link>
      <guid>https://forem.com/algoorgoal/react-queryreul-jal-sseuneun-bangbeob-19ch</guid>
      <description>&lt;h2&gt;
  
  
  react query
&lt;/h2&gt;

&lt;p&gt;작게 보면 서버 상태 도구, 넓게 보면 비동기 상태 도구이다. 서버를 대상으로하는 data fetching뿐만 아니라 비동기적으로 이루어지는 외부 시스템과의 통신 및 처리를 관리하는데 사용할 수 있다.&lt;/p&gt;

&lt;h2&gt;
  
  
  react query를 사용하는 이유
&lt;/h2&gt;

&lt;p&gt;서버와 통신할 때 endpoint마다 반복적으로 이루어지는 loading, error 등 상태 관리를 하기가 귀찮을 때 사용할 수 있다. 게시물 리스트를 서버로부터 받아오는 상황을 예로 들어 보자.&lt;/p&gt;

&lt;h3&gt;
  
  
  AS-IS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/posts`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;usePosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPosts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;isLoading, error 와 같은 상태는 스켈레톤 UI와 에러 UI를 보여주기 위해서 대부분의 data fetching 로직에서 반복적으로 관리해주어야하는 상태이다. useQuery를 사용하면 다음과 같이 상태를 반복적으로 정의하지 않고 재사용할 수 있다.&lt;/p&gt;

&lt;h3&gt;
  
  
  TO-BE-1
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/posts`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;usePosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PostListSection&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt; 
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePosts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ListSection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Skeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ListSection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;loading ui는 어디서 비동기 작업이 트리거되는지 알 필요없다.&lt;/li&gt;
&lt;li&gt;비동기 작업은 어떤 loading ui가 비동기 작업을 캐치했는지 알 필요가 없다.&lt;/li&gt;
&lt;li&gt;component tree의 어딘가에 있는 다른 컴포넌트들도 비동기 작업을 수행할 때, 하나의 Suspense로 잡아서 Loader UI를 보여줄 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cache Invalidation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;data stale하다 &amp;amp;&amp;amp; 새로운 query instance가 mount되었다&lt;/li&gt;
&lt;li&gt;data가 stale하다 &amp;amp;&amp;amp; 네트워크 재연결이 발생하다. 네트워크 연결이 불안정안 환경에 있는 유저에게 best effort로 data fetching 결과를 제공해주어야 할 때 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;data가 stale하다 &amp;amp;&amp;amp; window가 refocus되었다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;queryClient.invalidateQueries()&lt;/code&gt;를 통해 query invalidation이 발생하였다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Background Refetching
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;background에서 refethcin&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  react query의 active / inactive
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;더이상 mount된 컴포넌트 중에 react query hook을 사용하고 있지 않은 경우 inactive 상태로 전환된다.&lt;/li&gt;
&lt;li&gt;inactice된지 gcTime이 지났을 때 캐시는 제거된다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  새로운 query instance가 mount되었다
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;새로운 query key를 가지는 react query hook (useQuery, useSuspenseQuery) 가 mount되었다&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  useSuspenseQueries를 사용하는 이유
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Suspense Boundary로 인하여 request waterfall이 발생할 때 사용한다.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;&amp;gt;
  &amp;lt;Suspense clientOnly&amp;gt;
  &amp;lt;/Suspense&amp;gt;
&amp;lt;/&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Structural Sharing and Referential Stability
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;레퍼런스를 유지하여 virtual dom에서 리렌더링이 필요한 부분만 리랜더링(재실행) 할 수 있게 만들어준다.&lt;/li&gt;
&lt;li&gt;deeply nested object의 depth별로, 데이터가 변하지 않았다면 동일한 레퍼런스를 유지한다.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function usePosts() {
  return useSuspenseQuery({
    queryKey: ['posts'],
    queryFn: getPosts,
  });
}

async function usePostCount() {
  return useSuspenseQuery({
    queryKey: ['posts'],
    queryFn: getPosts,
    select: ({ data: posts }) =&amp;gt; posts.count
  });
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  throwing Error on &lt;code&gt;onSuccess&lt;/code&gt; callback
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;onSuccess&lt;/code&gt;와 &lt;code&gt;onError&lt;/code&gt;는 모두
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  useSuspenseQueries
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Suspensive를 사용해야 하는 이유
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;&amp;lt;SuspenseQuery /&amp;gt;&lt;/code&gt;를 이용한
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Suspense를 사용하면 subtree에서 
&lt;code&gt;Suspense&lt;/code&gt;와 &lt;code&gt;useSuspenseQuery&lt;/code&gt;를 같이 사용하기 위해서는, data fetching만을 위해서 &lt;code&gt;&amp;lt;PostList /&amp;gt;&lt;/code&gt;와 같이 컴포넌트를 추가로 만들어야 한다.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  AS-IS
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PostsPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      ...
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Skeleton&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PostList&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ErrorBounbary&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      ...
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PostList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePosts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  TO-BE
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;data fetching
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PostPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Skeleton&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SuspenseQuery&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;postsQueryOptions&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;SuspenseQuery&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Client-only suspense
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;useSuspenseQuery&lt;/code&gt;를 사용하게 되면 Next.js 서버에서도 실행된다. 이를 막기 위해서 특정 컴포넌트 트리를 client서만 실행할 수 있게 설정해야 하는데, 이 때 &lt;code&gt;Suspensive&lt;/code&gt;의 &lt;/p&gt;

&lt;h3&gt;
  
  
  Loader UI의 깜빡거림을  컴포넌트로 방지
&lt;/h3&gt;

&lt;p&gt;data fetching시에 응답이 빠르게 온다면, Loader UI에서 데이터 UI로 전환될 때  깜빡인다는 느낌을 사용자에게 줄 수 있다. ` 컴포넌트를 사용하여 Loader UI 렌더링을 의도적으로 지연시켜서, 깜빡거린다는 느낌을 줄일 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;tsx&lt;br&gt;
function PostPage() {&lt;br&gt;
  return (&lt;br&gt;
    &amp;lt;Suspense fallback={&amp;lt;Delay ms={200}&amp;gt;&amp;lt;Skeleton/&amp;gt;&amp;lt;/Suspense&amp;gt;}&lt;br&gt;
      &amp;lt;PostListSection /&amp;gt;&lt;br&gt;
    &amp;lt;/Suspense&amp;gt;&lt;br&gt;
  )&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Loader UI가 Delay 250ms 후에 렌더렝되고, data fetching이 300ms에 이루어진다면 유저는 여전히 깜빡이는 느낌을 받을 것이다. 이를 해결하기 위해서 Loader UI에 최소 렌더링 시간을 부여할 수도 있을 것이다. 다만 그렇게하면 데이터를 보여주기까지의 시간도 같이 길어질 수 있다는 문제가 있다. 다음의 시나리오를 확인하라.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Loader UI의 렌더링을 200ms만큼 지연시키고, 최소 렌더링 시간을 보장하지 않는 경우 발생하는 시나리오
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;0ms~200ms: data fetching을 시작하고, 빈 화면을 보여준다.&lt;/li&gt;
&lt;li&gt;200ms~300ms: Loader UI를 보여준다.&lt;/li&gt;
&lt;li&gt;300ms~: data fetching이 완료되어 데이터 UI를 보여준다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Loader UI의 렌더링을 200ms만큼 지연시키고, 최소 렌더링 시간을 300ms만큼 보장하는 경우 발생하는 시나리오
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;0ms~200ms: data fetching을 시작하고, 빈 화면을 보여준다.&lt;/li&gt;
&lt;li&gt;200ms~300ms: Loader UI를 보여준다.&lt;/li&gt;
&lt;li&gt;300ms~400ms: data fetching이 완료되었지만, Loader UI의 최소 렌더링 시간 200ms를 채우기 위해서 계속 Loader UI를 보여준다.&lt;/li&gt;
&lt;li&gt;400ms~: data fetching이 완료되어 데이터 UI를 보여준다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;최소 렌더링 시간을 보장하게 되면 UI의 깜빡거림은 막을 수 있겠지만, 데이터 UI를 보여주는데 걸리는 시간이 지연된다. 유저가 원하는 정보를 가장 빠르게 보여주고 싶다면 Loader UI의 최소 렌더링 시간은 설정하지 않고, Delay 컴포넌트로 지연만 주는 것이 최선의 선택이다. 최소 렌더링 시간의 트레이드오프를 고려해서 선택하라.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;작게 보면 비동기, 크게 보면 서버 상태를 관리하기 위해서 react query를 사용한다.
2.&lt;/li&gt;
&lt;li&gt;Client-only suspense, Loader UI 렌더링 지연을 통한 깜빡거림 방지, SuspensiveQuery/SuspenseQueries를 위하여 Suspensive를 사용한다.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>react</category>
    </item>
    <item>
      <title>connection pool과 세마포어, 그 응용들에 대하여</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Tue, 13 Jan 2026 17:08:45 +0000</pubDate>
      <link>https://forem.com/algoorgoal/javascriptro-connection-pool-mandeulgi-hkd</link>
      <guid>https://forem.com/algoorgoal/javascriptro-connection-pool-mandeulgi-hkd</guid>
      <description>&lt;h2&gt;
  
  
  connection pool을 사용하는 이유
&lt;/h2&gt;

&lt;p&gt;DB connection을 맺을 때는 tcp handshake, 메모리, 세션, 실행 컨텍스트 등의 서버 자원 할당이 필요하다. 데이터베이스와 통신이 connection setup을 하면 시간이 오래 걸린다. 따라서 connection 리스트를 만들어두고, DB 리소스를 재사용할 수 있는 저장소가 connection pool이다.&lt;/p&gt;

&lt;h2&gt;
  
  
  connection pool의 역할
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;사용 중인 connection과 사용 중이지 않은 connection을 구분한다.&lt;/li&gt;
&lt;li&gt;idle(사용중 X) connection이 있을 때 connection을 활용하여 DB query를 실행한다. connection이 모두 in-use(사용중)인 경우, idle로 전환된 connection을 이용하여 DB query를 실행한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;호출해야 하는 DB query는 애플리케이션(또는 DB driver)에서 대기열로 관리된다.&lt;/p&gt;

&lt;p&gt;일반적인 경우 브라우저와 서버는 웹 상에서 통신하기 때문에 http 통신을 하고, 서버와 DB는 tcp 통신을 한다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  connection pool의 구현
&lt;/h2&gt;

&lt;p&gt;semaphore를 통해 connection pool을 구현할 수 있다. connection를 일종의 임계구역(critical section)으로 보고, 동시에 실행될 수 있는 DB query의 개수를 lock의 개수로 볼 수 있다. lock이 모두 사용 중인 경우에는 DB query가 queue에서 대기했다가, 빠져나갈 때는 lock을 acquire한다는 관점으로도 해석이 가능하다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Semaphore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;connections&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalConnections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;connections&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;idleConnections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;connections&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inUseConnectionsMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;InUseConnections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;totalConnections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toBeInUseConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;idleConnections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inUseConnectionsMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toBeInUseConnection&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toBeIdleConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inUseConnectionsMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inUseConnectionsMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;idleConnections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toBeIdleConnection&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;idleConnections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DB&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;semaphore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Semaphore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;findUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;semaphore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Semaphore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  HTTP/1.1 상 브라우저의 동시 요청 개수 제한과 connection pool 사이의 연관성
&lt;/h2&gt;

&lt;p&gt;HTTP/1.1 상에서 대부분의 브라우저는 동일한 origin에 대한 요청을 한번에 6개까지만 처리가 가능하도록 설정되어 있다. 이를 구현하기 위해서는 다음 스펙을 만족시키는 코드를 작성하면 된다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;현재 진행 중인 요청의 개수를 기록한다.&lt;/li&gt;
&lt;li&gt;호출해야하는 HTTP 요청을 순서대로 기억한다.&lt;/li&gt;
&lt;li&gt;현재 진행 중인 요청의 개수 &amp;lt; 6인 경우, 요청을 실행한다. 현재 진행 중인 요청의 개수 &amp;gt;= 6인 경우, 가장 먼저 끝나는 HTTP 요청을 완료한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;위의 스펙과 connection pool 사이의 공통점이 많다. DB query를 HTTP 요청으로 대체하고, connection의 상태를 in use(사용중) / idle(사용중 X)으로 구분하는 대신에 현재 진행 중인 요청의 개수를 기록하면 된다.&lt;/p&gt;

&lt;h3&gt;
  
  
  구현
&lt;/h3&gt;

&lt;h4&gt;
  
  
  첫번째 시도(오답)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;it has waited&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exampleTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;결과: 8번의 "it has waited"가 즉시 실행되었다.&lt;/li&gt;
&lt;li&gt;원인:

&lt;ol&gt;
&lt;li&gt;첫번째 promise가 lock을 실행하고 resolve(), await을 만나 그 다음 태스크 microtask에 적재&lt;/li&gt;
&lt;li&gt;두번째 promise가 lock을 실행하고 resolve(), await을 만나 그 다음 테스크 microtask에 적재&lt;/li&gt;
&lt;li&gt;... 8번째 promise가 lock을 실행하고 resolve(), await을 만나 그 다음 테스크 microtask에 적재&lt;/li&gt;
&lt;li&gt;첫번째 task 실행, await을 만나 그 다음 테스크 microtask에 적재&lt;/li&gt;
&lt;li&gt;두번째 task 실행, await을 만나 그 다음 테스크 microtask에 적재&lt;/li&gt;
&lt;li&gt;... 8번째 task 실행, await을 만나 그 다음 테스크 microtask에 적재&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;내가 원했던 것은 1,4,2,5,3,6 실행인데 promise의 동작구조로 인해 모든 data fetching이 동시에 lock을 얻어버린다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;정리:

&lt;ul&gt;
&lt;li&gt;then chaining 또는 await을 만나는 순간 메인 스레드는 해당 비동기 코드 실행을 중단하고 동기 코드 실행으로 전환한다.&lt;/li&gt;
&lt;li&gt;resolve되면 then chaining callback 또는 await 후속 코드 태스크를 microtask queue에 적재한다.&lt;/li&gt;
&lt;li&gt;따라서 Promise.any()를 호출하는 순간에, 어떤 태스크도 tasks에 추가되지 않아 모든 요청이 한번에 실행된다.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  두번째 시도(해답)
&lt;/h3&gt;

&lt;p&gt;connection pool과 유사하게 semaphore를 통해 을 구현할 수 있다. http connection을 일종의 임계구역(critical section)으로 보고, 동시에 실행될 수 있는 요청의 개수를 lock의 개수로 볼 수 있다. lock이 모두 사용 중인 경우에는 요청이 queue에서 대기했다가, 빠져나갈 때는 lock을 acquire하여 실행된다는 관점으로 해석이 가능하다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exampleTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Semaphore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="p"&gt;}){&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;semaphore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Semaphore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;semaphore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;exampleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  html element &lt;code&gt;&amp;lt;link rel="preconnect"&amp;gt;&lt;/code&gt; 태그와의 연관성: ahead-of-time connection setup
&lt;/h2&gt;

&lt;p&gt;html link tag에 &lt;code&gt;rel=preconnect&lt;/code&gt; 속성을 지정하면, 리소스 다운로드 요청이 실제로 이루어지기 전에 미리 connection을 열어서 추후 리소스 다운로드 시간을 단축시킨다. &lt;/p&gt;

&lt;h3&gt;
  
  
  공통점
&lt;/h3&gt;

&lt;p&gt;connection을 맺기 위해 필요한 setup(initiation)을 미리 완료하여, 실제로 통신이 수행되는데 걸리는 시간을 단축시킨다는 점이 동일하다.&lt;/p&gt;

&lt;h3&gt;
  
  
  차이점
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;link rel="preconnect"&amp;gt;&lt;/code&gt;은 http connection을 미리 setup하고, connection pool은 DB connection을 setup한다. 따라서 &lt;code&gt;&amp;lt;link rel="preconnect"&amp;gt;&lt;/code&gt;은 DNS lookup, tcp 3 way handshake, tls handshake을 미리 수행하기 위해 사용하지만, connection pool의 경우 connection에 저장된 DB 상태를 재사용하기 위해 사용한다는 차이가 있다.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL; DR
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;DB Query를 처리할 때마다 서버 자원 할당을 하지 않기 위해 위해 connection pool을 유지하고 여기 저장된 connection을 재사용한다.&lt;/li&gt;
&lt;li&gt;connection pool은 한번에 진행되는 태스크의 개수를 제한할 수 있다는 특징이 있어 semaphore를 통해 구현할 수 있다.&lt;/li&gt;
&lt;li&gt;connection pool은 미리 connection을 setup한다는 점에서 html의 &lt;code&gt;&amp;lt;link rel="preconnect"&amp;gt;&lt;/code&gt;와 유사성이 있고, 한번에 진행되는 태스크의 개수를 제한한다는 점에서 http/1.1의 브라우저 요청 개수 제한과 유사성이 있다.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>performance</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>yarn pnp 세팅하기</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Tue, 06 Jan 2026 16:36:06 +0000</pubDate>
      <link>https://forem.com/algoorgoal/yarn-pnp-setinghagi-2dgg</link>
      <guid>https://forem.com/algoorgoal/yarn-pnp-setinghagi-2dgg</guid>
      <description>&lt;h2&gt;
  
  
  yarn pnp를 사용하는 이유
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ghost dependencies의 방지
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;yarn v1 및 npm은 패키지의 중복 다운로드를 방지하기 위해서, 중복되는 패키지는 node_modules에서 끌어올리는 hoisting을 진행합니다.&lt;/li&gt;
&lt;li&gt;intellisense에서 프로젝트 자체의 package.json에 존재하지 않는 package까지 import할 수 있게 되면서, 의존성 관리에 실패하게 됩니다.&lt;/li&gt;
&lt;li&gt;yarn pnp에서는 각 모듈의 경로를 lookup table에서 찾도록 설정해서 package.json에 존재하는 모듈만 import될 수 있도록 만듭니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  module resolution시 무수한 I/O 발생
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;build 또는 dev 과정에서, import를 호출하는 파일의 디렉토리부터 루트 디렉토리까지 &lt;code&gt;/node_modules/[package]&lt;/code&gt; 디렉토리 스캐닝을 진행합니다.&lt;/li&gt;
&lt;li&gt;무수한 I/O 스캐닝으로 개발 서버 시작 및 빌드가 느려집니다.&lt;/li&gt;
&lt;li&gt;yarn pnp에서는 node.js의 module resolution 알고리즘을 덮어씌우고 .pnp.cjs lookup table을 참고하여 개발 서버 시작 및 빌드 속도가 향상됩니다.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise ls-remote yarn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;stable version은 &lt;a href="https://yarnpkg.com/" rel="noopener noreferrer"&gt;https://yarnpkg.com/&lt;/a&gt; 에서 확인 가능합니다.&lt;/p&gt;

&lt;p&gt;글 작성 시점 기준으로 yarn stable version이 4.12.0이므로 해당 버전으로 설치합니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mise use yarn@4.12.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;yarn pnp 모드가 적용되어 있는지 확인합니다. yarn berry(yarn v2+)에서는 자동으로 설치되어 있습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn config get nodeLinker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;만약 현재 설정이 'pnp'가 아니라 'node-modules'로 되어 있다면, 다음을 입력해서 nodeLinker로 바꿔줍시다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn config &lt;span class="nb"&gt;set &lt;/span&gt;nodeLinker pnp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;다시 nodeLinker 세팅값을 확인해서 yarn pnp가 제대로 적용되어 있는지 확인합니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn config get nodeLinker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;.yarnrc.yml 파일에서 값이 잘 적용된 것도 볼 수 있습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nodeLinker: pnp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  마이그레이션
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;프로젝트에서 node_modules 폴더 완전히 제거하기&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.bin&lt;/code&gt; 폴더의 바이너리 실행 파일을 제거하기&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;node&lt;/code&gt; 명령어 호출을 &lt;code&gt;yarn node&lt;/code&gt;로 모두 대체하기&lt;/li&gt;
&lt;li&gt;명령어가 실행되기 전에 자동으로 끼워 넣는 훅은 모두 직접 호출하도록 바꾸기(&lt;code&gt;yarn prestart&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  code editor와 연동하기
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;ZipFS extension을 설치하면, zip으로 압축된 패키지 소스코드 내부를 확인할 수 있다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;yarn dlx @yarnpkg/sdks vscode&lt;/code&gt;를 사용하면, 프로젝트의 typescript를 사용하도록 만들어줄 수 있다.&lt;/li&gt;
&lt;li&gt;타입스크립트 파일이 포커스된 상태에서 &lt;code&gt;Typescript: Select Typescript Version...&lt;/code&gt;을 클릭 &amp;gt; &lt;code&gt;Use Workspace Version&lt;/code&gt;을 클릭한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  vite project에서 &lt;code&gt;yarn dev&lt;/code&gt; 실행시 node_modules가 생기는 원인
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;yarn dev&lt;/code&gt;와 같이 개발 서버를 실행할 때는 tree shaking이 진행되지 않아, 사용되지 않는 export가 제거되지 않는다. &lt;/li&gt;
&lt;li&gt;그 결과 개발 서버 url로 접속했을 때 브라우저는 import되는 모듈 파일을 하나씩 다운로드 받는다.&lt;/li&gt;
&lt;li&gt;http 1.1에서 브라우저가 동일 오리진에 보낼 수 있는 요청의 개수는 보통 6개로 정해져있어, 네트워크 병목이 발생한다.&lt;/li&gt;
&lt;li&gt;vite는 개발 서버 실행 단계에서 패키지의 파일을 하나로 묶어서 node_modules/.vite 디렉토리에 캐싱한다. 이를 pre bundling이라고 부른다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;사실상 node_modules라는 이름으로 의존성이 되고 있는 것이 아니라, 개발 서버 실행 과정에서 재사용되는 캐시 파일이 저장되고 있는 것이다. node_modules 디렉토리의 본래 용도는 의존성 저장 용도이기에, yarn pnp에서 node_modules 디렉토리가 존재한다는 것이 어색하다고 판단하여 캐싱되는 디렉토리를 옮겼다.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;vite.config.ts&lt;/code&gt;에 cacheDir 디렉토리를 &lt;code&gt;.vite&lt;/code&gt;로 설정하고 &lt;code&gt;.gitignore&lt;/code&gt;에 추가하였다.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default defineConfig({
  plugins: [react()],
  cacheDir: ".vite",
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;.gitignore&lt;/code&gt;에 해당 디렉토리를 추가하여, git history에 등록되지 않도록 한다.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# vite
.vite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  실험
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;lodash-es&lt;/code&gt;를 설치하고 pre bundling 과정이 없다면 실제로 네트워크 요청이 무수히 날아가는지 확인해보았다.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;lodash-es&lt;/code&gt;를 의존성에 추가한다.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add lodash-es
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;vite.config.ts에서 최적화 대상에 &lt;code&gt;lodash-es&lt;/code&gt;를 제외한다.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default defineConfig({
  plugins: [react()],
  cacheDir: ".vite",
  optimizeDeps: {
    exclude: ["lodash-es"],
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;개발 서버를 실행하고 url로 접속한다. 브라우저 개발자 도구의 네트워크 탭을 확인한다.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;결과&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqj8l3onogovdsy87y2hk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqj8l3onogovdsy87y2hk.png" alt="네트워크 탭1" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;600개가 넘는 요청이 보내졌다. 요청을 전부 처리하는데 800ms~1000ms가 걸렸다. 타임라인을 확인해보라.&lt;/p&gt;

&lt;p&gt;이제 pre-bundling 옵션을 적용한 뒤에 결과를 확인하겠다. pre-bundling은 최적화를 꺼놓지 않는 이상 자동으로 실행되기에, (2)에서 진행한 과정을 모두 제거하고 결과를 확인하였다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpo55wbnssl017sjqmfbv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpo55wbnssl017sjqmfbv.png" alt="네트워크 탭2" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4ms가 걸렸다. 모듈 다운로드 속도가 1000ms =&amp;gt; 4ms로 250배가 빨라진 샘이다.&lt;/p&gt;

&lt;h3&gt;
  
  
  nodeLinker: node-modules로 실행할 경우 결과
&lt;/h3&gt;

&lt;h4&gt;
  
  
  pre-bundling을 껐을 경우 결과
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32ixm7bgtfag59es2g32.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32ixm7bgtfag59es2g32.png" alt="Pre bundling을 껐을 경우 결과" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;timeline에서 확인했을 때 다운로드하는데 800ms~1000ms가 걸렸다.&lt;/p&gt;

&lt;h4&gt;
  
  
  pre-bundling을 켰을 경우 결과
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkn9d2xxm5orx2x3u6d8f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkn9d2xxm5orx2x3u6d8f.png" alt="pre bundling을 껐을 경우 결과" width="800" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;다운로드에서 20ms가 걸렸다. 40배~50배 다운로드 속도가 빨라졌다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vite.dev/guide/dep-pre-bundling" rel="noopener noreferrer"&gt;https://vite.dev/guide/dep-pre-bundling&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vite.dev/guide/dep-pre-bundling#caching" rel="noopener noreferrer"&gt;https://vite.dev/guide/dep-pre-bundling#caching&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://yarnpkg.com/migration/pnp" rel="noopener noreferrer"&gt;https://yarnpkg.com/migration/pnp&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>performance</category>
      <category>tooling</category>
    </item>
    <item>
      <title>개발 툴 버전 관리, mise 하나면 충분합니다</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Thu, 01 Jan 2026 15:46:25 +0000</pubDate>
      <link>https://forem.com/algoorgoal/gaebal-tul-beojeon-gwanri-mise-hanamyeon-cungbunhabnida-5f00</link>
      <guid>https://forem.com/algoorgoal/gaebal-tul-beojeon-gwanri-mise-hanamyeon-cungbunhabnida-5f00</guid>
      <description>&lt;h2&gt;
  
  
  기존 javascirpt 개발 도구들의 문제점
&lt;/h2&gt;

&lt;h3&gt;
  
  
  node version management
&lt;/h3&gt;

&lt;p&gt;프로젝트별로 사용하는 node.js의 버전을 따로 설치해서 관리하고 싶기에 nvm을 설치할 겁니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install nvm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;그리고 프로젝트 루트 디렉토리에 &lt;code&gt;.nvmrc&lt;/code&gt; 파일을 생성해서 현재 프로젝트에서 어떤 node version을 사용해야하는지 알려줍니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;22.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;그리고 현재 열려있는 쉘 세션에서 해당 노드 버전을 사용하도록 매번 쉘을 열 때마다 다음 커맨드를 입력해줍니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nvm use
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;아니면, 쉘을 열 때마다 &lt;code&gt;nvm use&lt;/code&gt; 명령어를 입력하기가 귀찮기 때문에 프로젝트의 node 버전을 시스템 기본 값을 설정해줍니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nvm alias default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;하지만 여전히 다른 프로젝트로 스위칭할 때마다 &lt;code&gt;nvm alias default&lt;/code&gt; 명령어를 입력해야돼서 귀찮습니다.&lt;/p&gt;

&lt;h3&gt;
  
  
  package manager version management
&lt;/h3&gt;

&lt;p&gt;프로젝트별로 사용하는 package manager의 버전을 따로 설치해서 관리하고 싶기에 corepack을 사용할 겁니다. node를 설치할 때 같이 설치되기 때문에, disabled 상태인 corepack을 활성화시키면 됩니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;corepack enable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;위의 명령어를 실행하면, corepack은 프로젝트 루트 디렉토리의 package.json의 &lt;code&gt;packageManager&lt;/code&gt; 필드를 기준으로 버전을 결정합니다. 그리고 package manager의 설치까지 해줍니다.&lt;/p&gt;

&lt;p&gt;nvm에다가 corepack까지 관리해줘야 하니 귀찮습니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  문제점
&lt;/h2&gt;

&lt;p&gt;노드 버전 관리와 패키저 매니저 버전 관리를 할 때 다음과 같은 문제점이 발생합니다.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;프로젝트를 한번 세팅할 때마다 nvm과 corepack이라는 두개의 도구를 사용해야 합니다. 세팅할 때만 사용하니 사용법을 자꾸 잊어버리게 되고 귀찮습니다.&lt;/li&gt;
&lt;li&gt;프로젝트를 스위칭할 때마다 &lt;code&gt;nvm alias default&lt;/code&gt;를 입력해서 쉘의 node 버전을 변경해야 하는 번거로움이 있습니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  올인원 mise로 구원 받읍시다
&lt;/h2&gt;

&lt;p&gt;보편적인 개발 도구들의 버전관리 도구입니다. javascript, python, ruby 등 다양한 언어에서 사용되는 개발 도구들의 버전 관리를 모두 지원합니다. 이를 사용해서 문제를 해결할 수 있습니다.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;nvm과 corepack을 사용하지 않고 &lt;code&gt;mise.toml&lt;/code&gt;에 패키지 관리자 버전, 노드 버전을 명시하면 &lt;code&gt;mise install&lt;/code&gt; 실행시 알아서 설치해줍니다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mise activate&lt;/code&gt; 명령어를 환경변수에 추가하면, 프로젝트별로 node 버전을 수동으로 전환할 필요 없이 쉘 실행시 자동으로 프로젝트에 맞는 버전을 선택해줍니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;지원하는 툴의 리스트는 &lt;a href="https://mise.jdx.dev/registry.html#tools" rel="noopener noreferrer"&gt;https://mise.jdx.dev/registry.html#tools&lt;/a&gt; 에서 확인하실 수 있습니다.&lt;/p&gt;

&lt;h3&gt;
  
  
  설치 방법
&lt;/h3&gt;

&lt;p&gt;macOS 사용자는 homebrew로 mise를 설치할 수 있습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install mise
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;mise가 제대로 설치되었는지 확인합니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mise --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;새로운 쉘을 열 때마다 mise를 활성화하고 싶다면 다음 명령어를 입력해서, zsh config file에 반영되도록 다음 명령어를 실행하세요.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 'eval "$(mise activate zsh)"' &amp;gt;&amp;gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;vscode 또는 cursor 사용자라면 다음 명령어를 통해 &lt;code&gt;eval "$(mise activate zsh)"&lt;/code&gt;가 .zshrc에 제대로 반영되었는지 확인할 수 있습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;mise로 설치 가능한 개발 도구의 버전을 확인하고 싶으면 다음 명령어를 입력하세요.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mise ls-remote [tool@version]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;mise로 현재 프로젝트에 개발 도구를 설치하고, config file에 추가하고 싶다면 다음 명령어를 입력하세요.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mise use [tool@version]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;현재 프로젝트 버전에 설치된 개발 도구의 버전을 확인하고 싶으면 다음 명령어를 입력하세요.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mise ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  참고
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.daleseo.com/mise/" rel="noopener noreferrer"&gt;https://www.daleseo.com/mise/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>tooling</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>2025 결산</title>
      <dc:creator>Chan</dc:creator>
      <pubDate>Sun, 28 Dec 2025 13:00:28 +0000</pubDate>
      <link>https://forem.com/algoorgoal/2025-gyeolsan-16gp</link>
      <guid>https://forem.com/algoorgoal/2025-gyeolsan-16gp</guid>
      <description>&lt;h2&gt;
  
  
  가장 잘했던 것: 번아웃 방지
&lt;/h2&gt;

&lt;p&gt;일주일에 하루는 항상 쉬었다. 아무리 많은 할일이 있어도 미루고 놀았다. 꾸준히 지치지 않고 더 일을 많이 할 수 있게된 거 같다.&lt;/p&gt;

&lt;h2&gt;
  
  
  내가 쌓은 역량
&lt;/h2&gt;

&lt;p&gt;코드를 작성할 때 무엇이 중요한지 구별하는 능력이 향상되었다. 리팩토링을 진행할 때 구현보다는 인터페이스 변경에 집중하여야 한다. 이름을 통해 모듈(또는 컴포넌트)가 어떤 기능을 수행하는지 내부 코드를 보지 않고도 예측이 가능할 때 적절한 추상화이고, 이를 실패하면 안 하느니만 못하다. 과거의 나는 코드가 길어지면 훅으로 분리하거나 컴포넌트로 분리하는 것에만 집중을 했었는데, 지금 돌이켜보니 가치가 떨어졌던 거 같다. 지금은 전체 코드를 한 모듈/컴포넌트에 작성한 뒤에 재사용이 자주 되거나, 이름을 통해 코드 예측이 가능한 경우만 컴포넌트로 분리하는 편이다.&lt;/p&gt;

&lt;h2&gt;
  
  
  내가 사용하는 기술을 저수준에서 설명할 수 있을 정도로 만들기
&lt;/h2&gt;

&lt;p&gt;서류 합격률은 높아졌지만 기본 역량 테스트에서 모두 탈락하였다. &lt;/p&gt;

&lt;p&gt;내가 사용하는 기술을 표현적으로, 현상 수준에서 알고 있어도 문제 해결이 되는 경우가 많아서 거기서 멈춘 경우가 많았던 거 같다. 하지만 테크 기업일 수록 자신이 사용한 기술을 내부 동작 원리 수준에서 설명할 수 있기를 기대하였다. 그렇게 하지 못했기 때문에 기술면접을 탈락하였다.&lt;/p&gt;

&lt;p&gt;7월부터 1월까지 6개월동안 어시스턴트를 한 이후 서류 합격률은 높아졌으나, 그 다음 과정에서 모두 탈락하였다. 유형별로 나눠본다면 다음과 같다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;알고리즘 코딩테스트&lt;/li&gt;
&lt;li&gt;웹 기본기 평가: html, css, javascript 사용 능력 측정&lt;/li&gt;
&lt;li&gt;리액트를 통한 과제 구현: 기본 구현 능력, 추상화 및 코드 퀄리티를 확인한다.&lt;/li&gt;
&lt;li&gt;전공 지식 질문&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;알고리즘, 자료구조, 네트워크, 운영체제, 데이터베이스, 웹의 기초 지식이 부족하다. 하지만 모든 것을 다 준비할 수 없기에 운영체제와 데이터베이스는 기본 개념 수준만 정리해놓는 것으로 일단락 짓고, 나머지 시간을 다른 곳에 투자하겠다.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;이력서에서 사용되는 키워드와 관련된 웹 기초 지식(Next.js, 이미지 최적화(사이즈/CLS 방지/레이지 로딩)&lt;/li&gt;
&lt;li&gt;네트워크&lt;/li&gt;
&lt;li&gt;웹 기초&lt;/li&gt;
&lt;li&gt;코딩테스트 문제를 풀 수 있을 정도의 알고리즘 및 자료구조 역량&lt;/li&gt;
&lt;li&gt;표면적인 개념 차이 수준의 운영체제 및 데이터베이스&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>devjournal</category>
      <category>interview</category>
      <category>programming</category>
      <category>career</category>
    </item>
  </channel>
</rss>
