<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ilikezzi</title>
    <link>https://ilikezzi.tistory.com/</link>
    <description>Nope, 말하는 감자입니다만.</description>
    <language>ko</language>
    <pubDate>Wed, 1 Jul 2026 22:35:34 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>대파양파애비</managingEditor>
    <image>
      <title>ilikezzi</title>
      <url>https://tistory1.daumcdn.net/tistory/5645003/attach/1c8a4ea263f940e3998c4759d810c681</url>
      <link>https://ilikezzi.tistory.com</link>
    </image>
    <item>
      <title>[NestJS] 비동기의 핵심, 이벤트 루프 + libuv 파헤치기 (2편)</title>
      <link>https://ilikezzi.tistory.com/80</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예전 포스팅에서 Node.js의 &lt;b&gt;이벤트 루프(event loop)&lt;/b&gt;의 개념과 동작 원리에 대해 자세히 알아보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/68&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ilikezzi.tistory.com/68&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748185339461&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Javascript] 비동기의 핵심, 이벤트 루프(Event loop) 파헤치기&quot; data-og-description=&quot;메리 크리스마스   크리스마스인데도 포스팅을 하는 이유는 백엔드파트 리더님과 대화중에 JS 이벤트루프를 설명해보라고 하셨는데 어버버대다가 제대로 설명을 못해서 당황했었다.. 리더님&quot; data-og-host=&quot;ilikezzi.tistory.com&quot; data-og-source-url=&quot;https://ilikezzi.tistory.com/68&quot; data-og-url=&quot;https://ilikezzi.tistory.com/68&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cAymNT/hyYYvGWUXd/Nkp6oGcLgv2NGkinGeGz50/img.png?width=800&amp;amp;height=803&amp;amp;face=0_0_800_803,https://scrap.kakaocdn.net/dn/q62qQ/hyYYvAbUPy/5yXW9joOkzBZ1cJnwjOj90/img.png?width=800&amp;amp;height=803&amp;amp;face=0_0_800_803,https://scrap.kakaocdn.net/dn/c0htIs/hyYYEYd4Be/a0mGIzWp0aKiO7Bswkiuv0/img.png?width=1814&amp;amp;height=1444&amp;amp;face=0_0_1814_1444&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/68&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ilikezzi.tistory.com/68&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cAymNT/hyYYvGWUXd/Nkp6oGcLgv2NGkinGeGz50/img.png?width=800&amp;amp;height=803&amp;amp;face=0_0_800_803,https://scrap.kakaocdn.net/dn/q62qQ/hyYYvAbUPy/5yXW9joOkzBZ1cJnwjOj90/img.png?width=800&amp;amp;height=803&amp;amp;face=0_0_800_803,https://scrap.kakaocdn.net/dn/c0htIs/hyYYEYd4Be/a0mGIzWp0aKiO7Bswkiuv0/img.png?width=1814&amp;amp;height=1444&amp;amp;face=0_0_1814_1444');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Javascript] 비동기의 핵심, 이벤트 루프(Event loop) 파헤치기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;메리 크리스마스   크리스마스인데도 포스팅을 하는 이유는 백엔드파트 리더님과 대화중에 JS 이벤트루프를 설명해보라고 하셨는데 어버버대다가 제대로 설명을 못해서 당황했었다.. 리더님&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 포스팅에서는 그 이벤트 루프를 포함하고 있는 Node.js의 핵심 &lt;b&gt;비동기 처리 라이브러리인 libuv&lt;/b&gt;를 중심으로, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS를 사용하면서 반드시 이해해야 할&lt;b&gt;&amp;nbsp;장단점&lt;/b&gt;과 &lt;b&gt;부하에 대한 내구성 관리&lt;/b&gt;에 대해서 깊이 있게 다뤄보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 개발자들이 Node.js에 대해&lt;b&gt; &quot;싱글 스레드라서 I/O에는 강하지만 CPU 집약적 작업에는 약하다&quot;&lt;/b&gt;라고 알고 있는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확히 왜 그런지, 그리고 그 한계를 어떻게 극복할 수 있을지 하나씩 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;왜 CPU 집약 작업에 약할까?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; 먼저 &lt;b&gt;Node.js의 단점&lt;/b&gt;부터 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js는 기본적으로 &lt;b&gt;싱글 스레드 + 이벤트 루프&lt;/b&gt; 구조로 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Java/Spring처럼 멀티 스레드&lt;/b&gt;가 아닌 싱글 스레드에서 JavaScript를 실행하기 때문에,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU 집약적인 작업이 들어오면 &lt;b&gt;이벤트 루프가 블로킹&lt;/b&gt;되어 버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748186021590&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (let i = 0; i &amp;lt; 1e9; i++) {
  Math.sqrt(i);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 이런 코드가 있다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 연산은 무조건&lt;b&gt; 메인 스레드&lt;/b&gt;에서 실행되고, &lt;b&gt;이벤트 루프를 막아&lt;/b&gt;버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과 API 응답이 지연되고 전체 애플리케이션이&lt;b&gt; 멈춘 것처럼 동작&lt;/b&gt;하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 문제도 해결 방법이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Node.js에서 이러한 CPU 집약적 작업을 처리할 때는 크게 &lt;b&gt;두 가지 방법으로 해결&lt;/b&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span&gt;1. Worker Threads 활용&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748186236734&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Worker } from 'worker_threads';
new Worker('./heavy-task.js'); // 별도의 쓰레드에서 연산&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Worker Threads&lt;/b&gt;는 각각 &lt;b&gt;독립적인 V8 엔진&lt;/b&gt; 인스턴스를 워커마다 띄워서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;순수 CPU 연산&lt;/b&gt;(암호화, 영상 처리, 대규모 계산 등)을 진정한 &lt;b&gt;병렬&lt;/b&gt;로 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 처리(이미지 리사이징), 복잡한 수식 계산, 텍스트 파싱 등의 작업에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 1 [&amp;quot;ordered_list&amp;quot;,{&amp;quot;spread&amp;quot;:true,&amp;quot;startingNumber&amp;quot;:1,&amp;quot;start&amp;quot;:620,&amp;quot;end&amp;quot;:1097},&amp;quot;regular_list_item&amp;quot;,{&amp;quot;start&amp;quot;:905,&amp;quot;end&amp;quot;:1097}]&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;&lt;b&gt;2. 클러스터 모드 (PM2)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;b&gt;활용&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748186464672&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pm2 start app.js -i max&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;클러스터 모드&lt;/b&gt;는 멀티코어를 활용하여 &lt;b&gt;CPU 코어 수만큼 &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Node.js 인스턴스를 띄워&lt;b&gt; 병렬 처리&lt;/b&gt;를 가능하게 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 멀티코어를 활용해서 &lt;b&gt;부하를 분산&lt;/b&gt;시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 방법들을 통해&amp;nbsp;NestJS의 싱글 스레드 구조로 인한&lt;b&gt; 블로킹 문제를 상당 부분 해소&lt;/b&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;그럼 왜 I/O 작업은 장점일까?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; 이제 핵심 질문이다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;왜 Node.js는 I/O 작업에 강할까? &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;단순히 이벤트 루프&lt;/b&gt;가 있어서일까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;아니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그 비밀은 바로 &lt;b&gt;libuv&lt;/b&gt;라는 라이브러리에 숨어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 루프는 사실 &lt;b&gt;libuv 안에 포함된 개념&lt;/b&gt;이고, &lt;b&gt;libuv가 실제 I/O를 처리하는 핵심 엔진&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 바로 &lt;b&gt;싱글 스레드이면서도 논블로킹 구조&lt;/b&gt;를 가질 수 있는 핵심이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;libuv란 무엇인가?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRoS43/btsObUjAA5X/IqvWSNZa4qEGtDUBJxPivk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRoS43/btsObUjAA5X/IqvWSNZa4qEGtDUBJxPivk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRoS43/btsObUjAA5X/IqvWSNZa4qEGtDUBJxPivk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRoS43%2FbtsObUjAA5X%2FIqvWSNZa4qEGtDUBJxPivk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;188&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;384&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;libuv&lt;/b&gt;는 Node.js의 비동기/논블로킹 처리를 가능하게 해주는 &lt;b&gt;C 기반 라이브러리&lt;/b&gt;다. (C++ 아님)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js는 내부적으로 이런 구조로 되어 있다:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dTS8SK/btsOdgzf1md/btdhJtODMwv1jK8NkZ3tx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dTS8SK/btsOdgzf1md/btdhJtODMwv1jK8NkZ3tx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dTS8SK/btsOdgzf1md/btdhJtODMwv1jK8NkZ3tx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdTS8SK%2FbtsOdgzf1md%2FbtdhJtODMwv1jK8NkZ3tx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;234&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이전 Node.js 버전&lt;/b&gt;에서는&lt;b&gt; libeio, libev를 나눠서&lt;/b&gt; 사용했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 우리가 사용하는 Node.js에서는 &lt;b&gt;통합된 libuv&lt;/b&gt;로 변경되었다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 80.2316%; height: 55px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.2155%; height: 17px;&quot;&gt;컴포넌트&lt;/td&gt;
&lt;td style=&quot;width: 9.26514%; height: 17px;&quot;&gt;언어&lt;/td&gt;
&lt;td style=&quot;width: 61.0645%; height: 17px;&quot;&gt;역할&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 18.2155%; height: 18px;&quot;&gt;V8&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 9.26514%; height: 18px;&quot;&gt;C++&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 61.0645%; height: 18px;&quot;&gt;자바스크립트 실행 엔진&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 18.2155%; height: 10px;&quot;&gt;&lt;b&gt;libuv&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.26514%; height: 10px;&quot;&gt;&lt;b&gt;C&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 61.0645%; height: 10px;&quot;&gt;&lt;b&gt;비동기 I/O 처리 (이벤트 루프, Thread Pool 포함)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 18.2155%; height: 10px;&quot;&gt;Node.js 바인딩 코드&lt;/td&gt;
&lt;td style=&quot;width: 9.26514%; height: 10px;&quot;&gt;C++&lt;/td&gt;
&lt;td style=&quot;width: 61.0645%; height: 10px;&quot;&gt;JS &amp;rarr; C/C++ 연결 코드 (fs, crypto 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;libuv&lt;/b&gt;의 특징에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 특징:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;네트워크 요청, 파일 읽기, 타이머, DNS, 비동기 I/O&lt;/b&gt; 전부 libuv가 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- OS에 작업을 위임하고 결과를 기다림&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시스템마다 제공하는 최적화된 API를 활용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;libuv가 정말 똑똑한 점은&lt;b&gt; 각 운영체제가 제공하는 최적화된 API&lt;/b&gt;를 활용한다는 것이다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;b&gt; Windows&lt;/b&gt;: IOCP (I/O Completion Ports)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;b&gt; Linux&lt;/b&gt;: epoll&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;b&gt; macOS&lt;/b&gt;: kqueue&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 Spring의 경우 Linux 환경에서 select를 사용하는데, libuv는 더 효율적인 epoll을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;libuv의 내부 동작 원리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pbpaP/btsOaOLtuno/CDJ5LgS5Hoq4J8HrPidgK1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pbpaP/btsOaOLtuno/CDJ5LgS5Hoq4J8HrPidgK1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pbpaP/btsOaOLtuno/CDJ5LgS5Hoq4J8HrPidgK1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpbpaP%2FbtsOaOLtuno%2FCDJ5LgS5Hoq4J8HrPidgK1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;294&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;357&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Node.js 내부적으로 비동기 작업이 발생하면 다음과 같은 흐름으로 처리된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;JavaScript 코드 실행: &lt;b&gt;스택&lt;/b&gt;에 코드가 쌓임&amp;nbsp;&lt;/li&gt;
&lt;li&gt;libuv 호출: 스택에 쌓인 코드를 실행하면서 &lt;b&gt;libuv를 호출&amp;nbsp;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;작업 분류: libuv가 비동기 처리할지, 동기 처리할지 검사&amp;nbsp;&lt;/li&gt;
&lt;li&gt;작업 위임: (비동기 작업) &lt;b&gt;시스템 API&lt;/b&gt;를 이용하거나 &lt;b&gt;Thread Pool&lt;/b&gt;에게 작업 위임&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;- 시스템 API: 소켓 네트워크, 파이프, 파일 디스크립터 감시, 타이머 등&lt;br /&gt;&amp;nbsp; &amp;nbsp;- ThreadPool: 파일 시스템 read/write, DNS getaddrinfo, xrypto, zlib 등&lt;/li&gt;
&lt;li&gt;콜백 등록: 작업이 완료되면 &lt;b&gt;콜백 함수를 태스크 큐&lt;/b&gt;에 전달&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이벤트 루프: 콜스택이 비었을 때 태스크 큐의 콜백을 &lt;b&gt;콜스택으로 이동&amp;nbsp;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;콜백 실행: 콜스택에서 콜백 함수 실행 후 제거&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, &lt;b&gt;libuv가 내부적으로 작업을&lt;/b&gt; 처리하여 JS 실행 스레드는 &lt;b&gt;블로킹되지 않고&lt;/b&gt; 다음 작업을 계속 수행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 Node.js &lt;b&gt;공식 소스코드&lt;/b&gt;를 보면 이런 식으로 되어 있다:&lt;/p&gt;
&lt;pre id=&quot;code_1748188994868&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int NodeMainInstance::Run() {
  // ... 초기화 코드 ...
  
  do {
    uv_run(env-&amp;gt;event_loop(), UV_RUN_DEFAULT);
    
    per_process::v8_platform.DrainVMTasks(isolate_);
    
    more = uv_loop_alive(env-&amp;gt;event_loop());
    if (more &amp;amp;&amp;amp; !env-&amp;gt;is_stopping()) continue;
    
    // ... 기타 처리 ...
  } while (more == true &amp;amp;&amp;amp; !env-&amp;gt;is_stopping());
  
  // ... 정리 코드 ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서&lt;b&gt;&amp;nbsp;uv_run()&lt;/b&gt;이&amp;nbsp;이벤트&amp;nbsp;루프를&amp;nbsp;실행하는&amp;nbsp;핵심&amp;nbsp;함수다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Node.js&amp;nbsp;인스턴스가&amp;nbsp;생성될&amp;nbsp;때&amp;nbsp;이&amp;nbsp;함수가&amp;nbsp;&lt;b&gt;do-while문으로&amp;nbsp;계속&amp;nbsp;호출되면서&lt;/b&gt;&amp;nbsp;&lt;b&gt;이벤트&amp;nbsp;루프&lt;/b&gt;가&amp;nbsp;동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;중요한 점은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Node.js에서 동작하는 이벤트 루프는 libuv의 구현체&lt;/b&gt;&lt;span&gt;라는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;libuv는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JavaScript 엔진이 아니기&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;때문에,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;파라미터로 넘겨받은&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;v8::Isolate, v8::Context&lt;/b&gt;를 이용해서 JavaScript 로직을 처리한다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Thread Pool의 이해&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Node.js는 싱글 스레드라고 하지만, 이는 &lt;b&gt;JavaScript를 실행하는 스레드가 하나&lt;/b&gt;라는 의미다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제로는 libuv 내부에 &lt;b&gt;Thread Pool&lt;/b&gt;이 존재한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 &lt;b&gt;4개의 워커 스레드&lt;/b&gt;를 사용하며, 이렇게 조절할 수 있다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748189311432&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;process.env.UV_THREADPOOL_SIZE = 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Thread Pool은 &lt;b&gt;라운드 로빈&lt;/b&gt;이 아니라 &lt;b&gt;단순 FIFO 큐 기반&lt;/b&gt;으로 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 10개의 요청이 들어오면:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 처음 4개는 각 스레드에서 즉시 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 나머지 6개는 대기 큐에서 순서대로 대기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 스레드가 &lt;b&gt;완료되는 순서대로&lt;/b&gt; 대기 중인 작업을 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 동시에 기본 4개까지만 처리되고, 나머지는 풀 안에서 &lt;b&gt;FIFO 순서로 대기&lt;/b&gt;하는 구조다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;libuv Thread Pool은 &lt;b&gt;일부 CPU 작업도 처리&lt;/b&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;처리&amp;nbsp;가능한&amp;nbsp;작업:&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- crypto.pbkdf2와 같은 내장 비동기 API &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 파일 시스템 I/O(fs), zlib 압축, DNS 조회 등&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;처리 불가능한 작업:&amp;nbsp; &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- (메인 스레드에서 처리됨): 순수 JavaScript로 구현한 반복문이나 수학 연산 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 이미지 처리, 머신러닝과 같은 복잡한 연산&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결론적으로 NestJS에서 &lt;b&gt;성능을 최적화하기 위한 전략&lt;/b&gt;은 다음과 같이 정리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-&lt;b&gt; 순수 CPU 연산이 필요한 경우:&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Worker Threads&lt;/b&gt; 또는 &lt;b&gt;PM2 클러스터 모드&lt;/b&gt;를 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-&lt;b&gt; I/O 기반 작업(fs, crypto 등)인 경우:&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;UV_THREADPOOL_SIZE&lt;/b&gt;를 늘려서 효율적으로 처리&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 두 가지 전략을 활용하면 &lt;b&gt;Node.js의 단점인 CPU 집약적 작업&lt;/b&gt;에 대한 블로킹 문제를 효과적으로 해결할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;아래 링크는 &lt;b&gt;이벤트 루프와 libuv&lt;/b&gt;에 대해 더 깊이 이해하는 데 큰&amp;nbsp;&lt;/span&gt;도움을&lt;span&gt; &lt;/span&gt;받았어서&lt;span&gt; &lt;/span&gt;강추한다&lt;span&gt;!&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c&quot;&gt;https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748189722338&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;What you should know to really understand the Node.js Event Loop&quot; data-og-description=&quot;Node.js is an event-based platform. This means that everything that happens in Node is the reaction to an event. A transaction passing&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c&quot; data-og-url=&quot;https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/yQBrk/hyYWYJra7s/lBJI9lHuCmnpF4dkKxjfc1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/yQBrk/hyYWYJra7s/lBJI9lHuCmnpF4dkKxjfc1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;What you should know to really understand the Node.js Event Loop&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Node.js is an event-based platform. This means that everything that happens in Node is the reaction to an event. A transaction passing&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js와 NestJS의&lt;b&gt; 비동기 처리 메커니즘&lt;/b&gt;을 이해하는 것은 단순히 이론적 지식이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 애플리케이션의 &lt;b&gt;성능을 최적화&lt;/b&gt;하고, &lt;b&gt;병목 지점을 파악&lt;/b&gt;하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;적절한 아키텍처를 설계&lt;/b&gt;하는 데 필수적인 지식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bravochos.medium.com/the-internals-of-node-js-b57bab6dc90&quot;&gt;https://bravochos.medium.com/the-internals-of-node-js-b57bab6dc90&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/nodejs/node&quot;&gt;https://github.com/nodejs/node&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://nodejs.org/ko/docs/guides/event-loop-timers-and-nexttick/&quot;&gt;https://nodejs.org/ko/docs/guides/event-loop-timers-and-nexttick/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.naver.com/pjt3591oo/221976414901&quot;&gt;https://blog.naver.com/pjt3591oo/221976414901&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sjh836.tistory.com/149&quot;&gt;https://sjh836.tistory.com/149&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/NestJS</category>
      <category>libuv</category>
      <category>nestJS</category>
      <category>Node.js</category>
      <category>이벤트루프</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/80</guid>
      <comments>https://ilikezzi.tistory.com/80#entry80comment</comments>
      <pubDate>Mon, 26 May 2025 02:04:21 +0900</pubDate>
    </item>
    <item>
      <title>[Frontend] React SPA에서 Next.js SSR로 동적 OG 메타태그 적용기</title>
      <link>https://ilikezzi.tistory.com/79</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;갑자기 프론트엔드 포스팅을 쓰게 되었다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 날 문득 개발로 부수입을 벌어보고 싶다는 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마침 주변에&lt;b&gt; 웹&amp;middot;앱에 애드센스&lt;/b&gt;를 붙여 매달 용돈을 벌고 있는 개발자가 적지 않게 보이더라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 &lt;span&gt;&lt;b&gt;프론트엔드 경험이 전무&lt;/b&gt;&lt;/span&gt;하다는 사실이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 최근 &lt;b&gt;Cursor AI&amp;middot;GPT&lt;/b&gt; 같은 &amp;lsquo;바이브 코딩&amp;rsquo; 도구들이 꽤 쓸 만해 보여 직접 React로 도전해 보기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인 일정상 오래 매달릴 수 없었기에, &lt;span&gt;&lt;b&gt;주말 이틀동안&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;b&gt;밤새서 &amp;lsquo;자체 1인 해커톤&amp;rsquo;&lt;/b&gt;으로 삼아 기획부터 배포까지 끝내기로 결심했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;광고 수익을 노리려면 트래픽이 필수이니, &lt;span&gt;&lt;b&gt;공유 기능이 있는 단순 모바일 웹&lt;/b&gt;&lt;/span&gt;을 목표로 삼았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LuckStargram&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;LuckStargram&lt;/b&gt;이라는 AI 운세 서비스를 만들기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_3384.PNG&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;2532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d6chxF/btsOcjv6Vub/IvBpciWwKfpNyIF3qDVtC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d6chxF/btsOcjv6Vub/IvBpciWwKfpNyIF3qDVtC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d6chxF/btsOcjv6Vub/IvBpciWwKfpNyIF3qDVtC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd6chxF%2FbtsOcjv6Vub%2FIvBpciWwKfpNyIF3qDVtC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;866&quot; data-filename=&quot;IMG_3384.PNG&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;2532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;- &lt;/span&gt;&lt;span&gt;&lt;b&gt;이름&amp;middot;생년월일&amp;middot;운세 날짜&lt;/b&gt;&lt;/span&gt;를 입력하면 GPT AI가 오늘의 운세를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 결과는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;카드형 UI&lt;/b&gt;&lt;/span&gt;로 표시되며, 메시지와 행동 팁을 함께 제공한다.&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;caret-color: transparent; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/b2Q1OZ/btsOa3heA43/XEru3IB5f4pYfNkkSyXk50/img.png&quot; width=&quot;400&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;2532&quot; data-is-animation=&quot;false&quot; data-filename=&quot;IMG_3383.PNG&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 인스타그램이나 카카오톡에 &lt;b&gt;쉽게 공유를 유도&lt;/b&gt;하기 위해&lt;b&gt; '티켓'&lt;/b&gt;이라는 &lt;b&gt;게이미피케이션 요소&lt;/b&gt;도 넣었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 운세 결과를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;공유&lt;/b&gt;&lt;/span&gt;하면 티켓 1장 추가 획득&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 공유 링크로 들어온 사용자도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;1회 티켓&lt;/b&gt;&lt;/span&gt;을 받을 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주말 동안 기획 &amp;rarr; 개발 &amp;rarr; 배포까지 일사천리로 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;- 백엔드&lt;/span&gt;&amp;nbsp;: NestJS &amp;rarr; AWS API Gateway + AWS Lambda&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;- 프론트엔드 &lt;/span&gt;: React &amp;rarr; Vercel&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_3385.jpg&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;915&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfPLRc/btsObHjW2Lc/B4djFccu6K5slgDzxgYKq0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfPLRc/btsObHjW2Lc/B4djFccu6K5slgDzxgYKq0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfPLRc/btsObHjW2Lc/B4djFccu6K5slgDzxgYKq0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfPLRc%2FbtsObHjW2Lc%2FB4djFccu6K5slgDzxgYKq0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;313&quot; data-filename=&quot;IMG_3385.jpg&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;915&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;카카오톡으로 공유해 보니&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;메타태그가 항상 같은 이미지&amp;middot;텍스트&lt;/b&gt;&lt;/span&gt;로 노출되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;React 공유페이지&lt;/b&gt;에서 메타태그를 아래처럼 넣고 공유해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748027803290&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const dateObj = new Date(json.fortune_date);
const mm  = dateObj.getMonth() + 1;
const dd  = dateObj.getDate();
const nameOnly = json.name.length &amp;gt; 1 ? json.name.slice(1) : json.name;
const title = `${nameOnly}님의 ${mm}월 ${dd}일 운세  `;
const firstSentence = json.message.split('. ')[0] + '.';
const description  = firstSentence;

document.title = title;

const setMeta = (sel: string, attr: string, val: string) =&amp;gt; {
  const el = document.querySelector(sel);
  if (el) el.setAttribute(attr, val);
};

setMeta('meta[property=&quot;og:title&quot;]',        'content', title);
setMeta('meta[name=&quot;twitter:title&quot;]',        'content', title);
setMeta('meta[property=&quot;og:description&quot;]',   'content', description);
setMeta('meta[name=&quot;description&quot;]',          'content', description);&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 결과는 변하지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾아보니&lt;b&gt; React는 SPA&lt;/b&gt;라서 클라이언트 사이드에서 동적으로 메타태그를 변경해도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오톡, 페이스북 같은&lt;b&gt; 소셜 크롤러들이 &lt;/b&gt;이를 제대로&lt;b&gt; 인식하지 못한다&lt;/b&gt;고 하더라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPA는 처음에 &lt;b&gt;비어있는 HTML&lt;/b&gt;을 받고, JavaScript가 &lt;b&gt;실행되면서 동적&lt;/b&gt;으로 내용을 채우는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 소셜 크롤러들은 &lt;b&gt;초기 HTML&lt;/b&gt;만 읽고 JavaScript 실행을 기다리지 않기 때문에 &lt;b&gt;빈 메타태그&lt;/b&gt;만 보게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 아무리 JavaScript로 메타태그를 수정해도 소용없는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 다른 방법을 찾아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다이나믹 링크, Prerender.io 시도&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 다른 프로젝트에서 공유 기능을 넣을 때 &lt;b&gt;Firebase의 다이나믹 링크&lt;/b&gt;를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 적용했었던 기억이 있어서 바로 적용하려고 홈페이지에 들어가보니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-24 오전 4.21.31.png&quot; data-origin-width=&quot;1448&quot; data-origin-height=&quot;518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s9wyh/btsOanG4ibb/KMEzXSdZCIa2NABbThXMp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s9wyh/btsOanG4ibb/KMEzXSdZCIa2NABbThXMp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s9wyh/btsOanG4ibb/KMEzXSdZCIa2NABbThXMp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs9wyh%2FbtsOanG4ibb%2FKMEzXSdZCIa2NABbThXMp0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;215&quot; data-filename=&quot;스크린샷 2025-05-24 오전 4.21.31.png&quot; data-origin-width=&quot;1448&quot; data-origin-height=&quot;518&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;... 그렇다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 어쩔 수 없이 다른 대안을 찾아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프리렌더링&lt;b&gt; Prerender.io&lt;/b&gt;를 알게 되었는데, 이것도 물론 편하고 좋지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초반 일부만 무료고 유료라길래 다른 방법을 알아보기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.linode.com/ko/blog/devops/improve-seo-with-prerender-io/&quot;&gt;https://www.linode.com/ko/blog/devops/improve-seo-with-prerender-io/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748028172007&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Prerender.io로 SEO 개선&quot; data-og-description=&quot;이 글에서는 Prerender.io의 프리렌더링 서비스가 SEO 장애물을 극복하는 데 어떻게 도움이 되는지 살펴보겠습니다.&quot; data-og-host=&quot;www.linode.com&quot; data-og-source-url=&quot;https://www.linode.com/ko/blog/devops/improve-seo-with-prerender-io/&quot; data-og-url=&quot;https://www.linode.com/ko/blog/devops/improve-seo-with-prerender-io/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/f9smg/hyYW16Yixf/Xm3FGT6UalbRkKdSedkAuK/img.jpg?width=1920&amp;amp;height=1008&amp;amp;face=0_0_1920_1008,https://scrap.kakaocdn.net/dn/FqheC/hyYYt2SFRS/yPwbAQdkbIpNRFdepwHnMk/img.jpg?width=1920&amp;amp;height=1008&amp;amp;face=0_0_1920_1008,https://scrap.kakaocdn.net/dn/mKNw8/hyYYwyw5yK/Taz4WdBxUUuQnb0meaJGh0/img.jpg?width=632&amp;amp;height=332&amp;amp;face=0_0_632_332&quot;&gt;&lt;a href=&quot;https://www.linode.com/ko/blog/devops/improve-seo-with-prerender-io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.linode.com/ko/blog/devops/improve-seo-with-prerender-io/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/f9smg/hyYW16Yixf/Xm3FGT6UalbRkKdSedkAuK/img.jpg?width=1920&amp;amp;height=1008&amp;amp;face=0_0_1920_1008,https://scrap.kakaocdn.net/dn/FqheC/hyYYt2SFRS/yPwbAQdkbIpNRFdepwHnMk/img.jpg?width=1920&amp;amp;height=1008&amp;amp;face=0_0_1920_1008,https://scrap.kakaocdn.net/dn/mKNw8/hyYYwyw5yK/Taz4WdBxUUuQnb0meaJGh0/img.jpg?width=632&amp;amp;height=332&amp;amp;face=0_0_632_332');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Prerender.io로 SEO 개선&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이 글에서는 Prerender.io의 프리렌더링 서비스가 SEO 장애물을 극복하는 데 어떻게 도움이 되는지 살펴보겠습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.linode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;React-Helmet-Async + Puppeteer 시도&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;- react-helmet-async&lt;/b&gt;&lt;/span&gt; : 렌더 시점에 &lt;span&gt;&amp;lt;head&amp;gt;&lt;/span&gt;를 동적으로 조작해 주는 라이브러리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;- Puppeteer&lt;/b&gt;&lt;/span&gt; : Headless Chrome을 제어해 실제 브라우저에서 페이지를 렌더링, 정적 HTML을 생성할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 라이브러리 조합이 내 상황에 적절해 보였기에 바로 도입했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. &amp;lt;Helmet&amp;gt;&lt;/span&gt;으로 SPA 내부에서 &lt;span&gt;&lt;b&gt;동적 OG 메타태그&lt;/b&gt;&lt;/span&gt;를 설정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;2. Puppeteer&lt;/b&gt;&lt;/span&gt;로 &lt;span&gt;&lt;b&gt;크롤러 User-Agent&lt;/b&gt;&lt;/span&gt;일 때만 HTML 스냅샷을 생성하도록 프리렌더링 플로우를 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만&amp;hellip;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748028395324&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// vite.config.ts
function generatePerformanceRoutes() {
  const staticRoutes  = ['/', '/main']; // 정적 경로
  const dynamicRoutes = [];             // 동적 경로 저장 배열
  dynamicRoutes.push('/share/123');
  return staticRoutes.concat(dynamicRoutes);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;dynamicRoutes&lt;/span&gt;에 &lt;span&gt;&lt;b&gt;직접 경로를 써야만&lt;/b&gt;&lt;/span&gt; HTML이 생성됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운세 페이지는 &lt;span&gt;&lt;b&gt;/share/:uuid&lt;/b&gt;&lt;/span&gt; 형태로 동적 생성되는데, &lt;b&gt;SSG 시점에는 UUID를 알 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 후에 &lt;b&gt;메시지 큐&lt;/b&gt;로 vite 설정을 다시 만지려 하니, 구조가 지나치게 복잡해져 다른 방법을 모색했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Next.js SSR 도입&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 &lt;b&gt;하이브리드 구조&lt;/b&gt;로 결정했다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;메인 앱&lt;/b&gt;: React SPA로 유지 (빠른 사용자 경험)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공유 페이지&lt;/b&gt;: Next.js SSR로 분리 (완벽한 OG 메타태그)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;share.&lt;/span&gt; 서브도메인을 만들어 &lt;span&gt;&lt;b&gt;도메인 레벨&lt;/b&gt;&lt;/span&gt;로 기능을 구분&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 &lt;b&gt;Short Link&lt;/b&gt;까지 도입해서 share/luckstargram.com/abc123 같은&lt;b&gt; 깔끔한 공유 주소&lt;/b&gt;를 만들기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;//&amp;nbsp;pages/share/[uuid].tsx&lt;/p&gt;
&lt;pre id=&quot;code_1748028750975&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// pages/share/[uuid].tsx
import { GetStaticProps } from 'next';
import Head from 'next/head';

export const getStaticProps: GetStaticProps = async ({ params }) =&amp;gt; {
  const uuid = params?.uuid as string;
  
  // 백엔드에서 운세 데이터 가져오기
  const res = await fetch(`${process.env.API_BASE_URL}/share/${uuid}`);
  const data = await res.json();
  
  // 동적 OG 메타 생성
  const nameOnly = data.name.length &amp;gt; 1 ? data.name.slice(1) : data.name;
  const title = `${nameOnly}님의 ${mm}월 ${dd}일 운세  `;
  const description = data.message.split('. ')[0] + '.';
  
  return {
    props: { meta: { title, description, image: '/logo.webp' } },
    revalidate: 60, // ISR로 60초마다 캐시 갱신
  };
};

export default function SharePage({ meta }) {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Head&amp;gt;
        &amp;lt;title&amp;gt;{meta.title}&amp;lt;/title&amp;gt;
        &amp;lt;meta property=&quot;og:title&quot; content={meta.title} /&amp;gt;
        &amp;lt;meta property=&quot;og:description&quot; content={meta.description} /&amp;gt;
        &amp;lt;meta property=&quot;og:image&quot; content={meta.image} /&amp;gt;
        {/* 일반 사용자는 메인 앱으로 리다이렉트 */}
        &amp;lt;meta httpEquiv=&quot;refresh&quot; content=&quot;0; URL=https://luckstargram.com&quot; /&amp;gt;
      &amp;lt;/Head&amp;gt;
      &amp;lt;div /&amp;gt;
    &amp;lt;/&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;// middleware.ts&lt;/p&gt;
&lt;pre id=&quot;code_1748028819840&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// middleware.ts
import { NextRequest, NextResponse } from 'next/server';

const SOCIAL_BOTS = ['facebookexternalhit', 'twitterbot', 'kakaotalk'];

export async function middleware(req: NextRequest) {
  const userAgent = req.headers.get('user-agent')?.toLowerCase() || '';
  const isSocialBot = SOCIAL_BOTS.some(bot =&amp;gt; userAgent.includes(bot));
  
  if (isSocialBot) {
    // 소셜 크롤러 &amp;rarr; SSR 페이지로 내부 라우팅
    return NextResponse.rewrite(new URL(`/share/${uuid}`, req.url));
  } else {
    // 일반 사용자 &amp;rarr; 메인 앱으로 리다이렉트  
    return NextResponse.redirect('https://luckstargram.com/share/...', 302);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/share/[uuid]&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;페이지에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;ISR + Edge Runtime&lt;/b&gt;&lt;/span&gt;으로 &lt;b&gt;OG 메타를 동적&lt;/b&gt;으로 공급하도록 구성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;여기서 &lt;b&gt;ISR&lt;/b&gt;(Incremental Static Regeneration)이란?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Next.js의 하이브리드 렌더링 방식으로, 빌드 시에는 정적 페이지를 만들고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;런타임에는 필요에 따라 페이지를 재생성&lt;/b&gt;한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;revalidate: 60로 설정하면 60초마다 백그라운드에서 페이지를 새로 만들어서 최신 데이터를 유지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_3386.jpg&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;968&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rwj4B/btsOaqw1f9n/f0Z0mX1n3rgSPeztPKJtKK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rwj4B/btsOaqw1f9n/f0Z0mX1n3rgSPeztPKJtKK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rwj4B/btsOaqw1f9n/f0Z0mX1n3rgSPeztPKJtKK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frwj4B%2FbtsOaqw1f9n%2Ff0Z0mX1n3rgSPeztPKJtKK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;372&quot; data-filename=&quot;IMG_3386.jpg&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;968&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게&lt;b&gt; SPA의 빠른 로딩 성능&lt;/b&gt;을 유지하면서도,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유 페이지는 &lt;b&gt;SSR로 완벽히 OG 메타&lt;/b&gt;를 제공하는 &lt;span&gt;&lt;b&gt;하이브리드 구조&lt;/b&gt;&lt;/span&gt;를 완성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로 아키텍쳐는 아래처럼 간단하게 구성을 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1314&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4wXCX/btsOaMzxcKb/t1zcK6CZSK0h1y1svPI761/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4wXCX/btsOaMzxcKb/t1zcK6CZSK0h1y1svPI761/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4wXCX/btsOaMzxcKb/t1zcK6CZSK0h1y1svPI761/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4wXCX%2FbtsOaMzxcKb%2Ft1zcK6CZSK0h1y1svPI761%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;342&quot; data-origin-width=&quot;1314&quot; data-origin-height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명이 길었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 서비스가 제대로 작동하는지 궁금하다면, 직접 한 번 체험해 보는 편이 가장 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;a href=&quot;https://share.luckstargram.com/mCrr1R&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://share.luckstargram.com/mCrr1R&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748029281334&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;승모님의 5월 25일 운세  &quot; data-og-description=&quot;오늘은 명확함이 길을 열어요.&quot; data-og-host=&quot;share.luckstargram.com&quot; data-og-source-url=&quot;https://share.luckstargram.com/mCrr1R&quot; data-og-url=&quot;https://luckstargram.com/share/60a1ef1466ee50309414551e16dd0f9a&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/stSsA/hyYYGgPB1C/XLn4tYfKXekqGlkuDuN240/img.png?width=1120&amp;amp;height=628&amp;amp;face=0_0_1120_628,https://scrap.kakaocdn.net/dn/0Vo7S/hyYYBNmQgi/rZr3cO1pqSMycd80qVc6KK/img.png?width=1120&amp;amp;height=628&amp;amp;face=0_0_1120_628&quot;&gt;&lt;a href=&quot;https://share.luckstargram.com/mCrr1R&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://share.luckstargram.com/mCrr1R&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/stSsA/hyYYGgPB1C/XLn4tYfKXekqGlkuDuN240/img.png?width=1120&amp;amp;height=628&amp;amp;face=0_0_1120_628,https://scrap.kakaocdn.net/dn/0Vo7S/hyYYBNmQgi/rZr3cO1pqSMycd80qVc6KK/img.png?width=1120&amp;amp;height=628&amp;amp;face=0_0_1120_628');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;승모님의 5월 25일 운세  &lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 명확함이 길을 열어요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;share.luckstargram.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름이랑 생년월일 입력해 AI가 오늘의 운세를 만들어준 결과를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오톡에 공유해보면 이 글에서 설명한 동적 OG 메타태그가 어떻게 작동하는지 직접 확인할 수 있을 것이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;참조 :&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&lt;a href=&quot;https://techblog.woowahan.com/15469/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://techblog.woowahan.com/15469/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://team-beat.tistory.com/32&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://team-beat.tistory.com/32&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&lt;a href=&quot;https://firebase.google.com/support/dynamic-links-faq?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://firebase.google.com/support/dynamic-links-faq?hl=ko&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-helmet-async&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.npmjs.com/package/react-helmet-async&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.chrome.com/docs/puppeteer?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.chrome.com/docs/puppeteer?hl=ko&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/app/getting-started/metadata-and-og-images&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nextjs.org/docs/app/getting-started/metadata-and-og-images&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;++ 해당 포스팅은 vibeaz에도 함께 게재되었습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #66666e; text-align: left;&quot;&gt;&lt;a href=&quot;https://www.vibeaz.co.kr/share/RTEq&quot;&gt;https://www.vibeaz.co.kr/share/RTEq&lt;/a&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>Web/Frontend</category>
      <category>Next</category>
      <category>OG</category>
      <category>React</category>
      <category>SSR</category>
      <category>메타태그</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/79</guid>
      <comments>https://ilikezzi.tistory.com/79#entry79comment</comments>
      <pubDate>Sat, 24 May 2025 04:58:11 +0900</pubDate>
    </item>
    <item>
      <title>[NestJS] Winston 기반 로깅 라이브러리 'blanc-logger' npm 배포하기</title>
      <link>https://ilikezzi.tistory.com/78</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;658&quot; data-origin-height=&quot;658&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cks7jW/btsMB8b5Hhu/mCJ7fpP3HN2H8dTTKhIzH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cks7jW/btsMB8b5Hhu/mCJ7fpP3HN2H8dTTKhIzH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cks7jW/btsMB8b5Hhu/mCJ7fpP3HN2H8dTTKhIzH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcks7jW%2FbtsMB8b5Hhu%2FmCJ7fpP3HN2H8dTTKhIzH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;300&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;658&quot; data-origin-height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS 기반 프로젝트를 개발 중에 곧 배포를 앞두고 &lt;/span&gt;있어서 &lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;로깅 시스템이 필요&lt;/b&gt;&lt;/span&gt;&lt;span&gt;했다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처음에는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Winston&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 그대로 사용하려 했지만, 생각보다 부족한 기능이 많았다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1.&lt;b&gt; Winston 기본 설정이 부족&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &amp;rarr; NestJS와 TypeORM에서 바로 사용하기 어려움&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2.&lt;b&gt; SQL 쿼리 로깅이 비효율적&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &amp;rarr; 중요한 정보를 가독성 좋게 보기 어려움&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3.&lt;b&gt; 모듈 기반 로깅 미지원&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &amp;rarr; 특정 모듈에서 발생한 로그를 명확하게 구분하기 어려움&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;4.&lt;b&gt; 파일 로그 관리 부족&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &amp;rarr; 로그 파일이 커지면 관리가 어려워지고, 파일 회전 기능이 필요함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이러한 문제를 해결하기 위해 일일히&lt;b&gt; Winston을 커스텀&lt;/b&gt;하기 시작했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히&lt;b&gt; NestJS 및 TypeORM&lt;/b&gt; 환경에 최적화하여 &lt;b&gt;HTTP 요청 로깅&lt;/b&gt;, &lt;b&gt;SQL 쿼리 하이라이팅&lt;/b&gt;, &lt;b&gt;에러 스택 추적&lt;/b&gt; 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 기능을 사용할 수 있도록 개발하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만들다 보니 생각보다 &lt;b&gt;NestJS와 TypeORM에 최적화된 기능&lt;/b&gt;을 추가하게 된 것 같아서&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처음으로 &lt;b&gt;npm에 배포&lt;/b&gt;를 해보기로 했다 !&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Blanc-Logger&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Winston 기반 로깅 라이브러리 &lt;b&gt;&quot;Blanc-Logger&quot;&lt;/b&gt; 를 만들게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 전반적인 파일 구성에 대해 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741103324471&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;├─ src
│  ├─ helper
│  │  ├─ sql-formatter.ts           // SQL 구문 하이라이팅, 포맷팅, 및 쿼리 분석 기능을 제공
│  │  └─ uuid.ts                    // UUIDv5를 사용하여 고유한 로그 식별자를 생성하는 기능을 제공
│  ├─ index.ts                      // 라이브러리의 주요 모듈들을 한 곳에서 통합하여 내보내는 엔트리 포인트 역할
│  ├─ logger                         
│  │  ├─ blanc-logger.ts            // Winston 기반 로거의 메인 설정 및 콘솔/파일 로그 전송을 구성
│  │  ├─ custom-blanc.logger.ts     // NestJS의 LoggerService를 구현해서 기본 로거 대체 제공
│  │  ├─ logger.config.ts           // 사용자 커스터마이징 로깅 설정을 로드하고 관리하는 구성 파일
│  │  └─ typeorm-blanc-logger.ts    // TypeORM 전용 로거로, SQL 쿼리와 데이터베이스 관련 로그를 상세하게 기록
│  └─ middleware
│     └─ blanc-logger.middleware.ts // HTTP 요청에서 모듈명을 추출하여 로그 컨텍스트에 추가하는 미들웨어를 제공&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상세 코드는 포스팅 하단의&amp;nbsp;&lt;b&gt;GitHub 링크&lt;/b&gt;에서 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1192&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1ypFr/btsMBjS1mjR/7rRDvhBK6NgS1kHlzj7dH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1ypFr/btsMBjS1mjR/7rRDvhBK6NgS1kHlzj7dH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1ypFr/btsMBjS1mjR/7rRDvhBK6NgS1kHlzj7dH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1ypFr%2FbtsMBjS1mjR%2F7rRDvhBK6NgS1kHlzj7dH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;216&quot; data-origin-width=&quot;1192&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 로그 출력 콘솔부터 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디버깅할 때 추적이 편해지게, 각 로그에&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;UUIDv5&lt;/b&gt;로 생성된&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;고유&lt;span&gt;&amp;nbsp;&lt;/span&gt;LogID&lt;/b&gt;를 부여하고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;{timestamp, level, message}&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;구조의&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;JSON 포맷으로 출력&lt;/b&gt;되어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;외부 로그 분석 도구와&lt;span&gt;&amp;nbsp;&lt;/span&gt;연동&lt;/b&gt;하기 용이하도록 하였다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;커스텀 콘솔 포맷에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;로그 레벨에 따라 이모지와 색상&lt;/b&gt;을 적용하여 가독성을 높였다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이어서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SQL 쿼리&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;내의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;주요 키워드를 식별&lt;/b&gt;하고, 해당 토큰에 서식을 적용하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;쿼리&lt;/b&gt;의 가독성을 높였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리 하이라이팅은 &lt;b&gt;키워드,&amp;nbsp;값,&amp;nbsp;테이블명&lt;/b&gt;을 &lt;b&gt;색상 강조 및 들여 쓰기로&lt;/b&gt; 구분하며, &lt;b&gt;파라미터&lt;/b&gt; 값도 별도로 강조했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 콘솔에 출력되는 로그와 SQL 쿼리의 하이라이팅을 통해 &lt;b&gt;사용성과 가독성&lt;/b&gt;을 개선했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1458&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkkGaF/btsMAEXFqGE/GuL7aQjUeKpiXFi5CZ3mLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkkGaF/btsMAEXFqGE/GuL7aQjUeKpiXFi5CZ3mLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkkGaF/btsMAEXFqGE/GuL7aQjUeKpiXFi5CZ3mLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkkGaF%2FbtsMAEXFqGE%2FGuL7aQjUeKpiXFi5CZ3mLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;121&quot; data-origin-width=&quot;1458&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 &lt;b&gt;에러 발생 시&lt;/b&gt; &lt;b&gt;다중 스택 레이어&lt;/b&gt;와&lt;b&gt; 추가 메타데이터&lt;/b&gt;를 포함하여 상세한 에러 로그를 기록했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;BlancLoggerMiddleware를&lt;/b&gt; 활용하여&lt;b&gt; HTTP 요청의 URL에서 모듈명을 자동 추출&lt;/b&gt;해서 메시지에 활용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미들웨어 적용으로 &lt;b&gt;모듈별 컨텍스트 추적&lt;/b&gt;이 가능해져,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[UserService &amp;rarr; AuthModule &amp;rarr; Subsystem] 과 같이 &lt;b&gt;계층 구조&lt;/b&gt;로 로깅할 수 있게 되어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 로그 메시지의 &lt;b&gt;출처를 명확하게 파악&lt;/b&gt;할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741104202876&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;╔═ SQL Query ═════════════════════════════════
    SELECT
        &quot;user&quot;.&quot;id&quot; AS &quot;userId&quot;,
        &quot;user&quot;.&quot;email&quot; AS &quot;userEmail&quot;
    FROM &quot;user&quot; &quot;user&quot;
    WHERE &quot;user&quot;.&quot;age&quot; &amp;gt; $1
╠═ Parameters ═══════════════════════════════
    [18]
╠═ Analysis ═════════════════════════════════
    ⚠️ Avoid SELECT * - specify columns explicitly
╚═════════════════════════════════════════════&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 SQL 쿼리 출력 시 간단한 &lt;b&gt;성능 모니터링&lt;/b&gt;과 &lt;b&gt;실행 계획(Explain Plan) 리포트&lt;/b&gt;를 구축했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;b&gt;SELECT * 및 JOIN 조건 누락&lt;/b&gt;과 같은 &lt;b&gt;SQL 성능 저하 패턴&lt;/b&gt;을 자동 감지하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Slow Query &lt;/b&gt;(예: 100ms 이상)를&amp;nbsp;&lt;b&gt;자동 감지&lt;/b&gt;를 해 경고 로그로 기록하도록 구성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;쿼리 최적화&lt;/b&gt;가 필요한 부분을 사전에 식별 가능하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741104913234&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;combined-YYYY-MM-DD.log    // 모든 레벨의 로그 메시지가 기록되는 파일
error-YYYY-MM-DD.log       // 에러 레벨의 로그 메시지만 기록되는 파일
exceptions-YYYY-MM-DD.log  // 처리되지 않은 예외(Unhandled Exception) 로그가 기록되는 파일
rejections-YYYY-MM-DD.log  // 미처리된 Promise 거부(Unhandled Rejection) 로그가 기록되는 파일&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1741107877839&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// error-2025-03-05.log 
{&quot;level&quot;:&quot;error&quot;,&quot;message&quot;:&quot;HTTP Exception: DUPLICATION&quot;,&quot;stack&quot;:[{&quot;moduleName&quot;:&quot;user&quot;,&quot;path&quot;:&quot;/api/user/profile&quot;,&quot;stack&quot;:&quot;ConflictException: DUPLICATION\n    at UserService.getProfile (/path/to/src/user/user.service.ts:60:13)\n    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)&quot;}],&quot;timestamp&quot;:&quot;2025-03-05 02:29:51&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 중요한 &lt;b&gt;로그 파일&lt;/b&gt;에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 살펴본 &lt;b&gt;콘솔 출력&lt;/b&gt;과 &lt;b&gt;파일 저장&lt;/b&gt;을 동시에 지원하게끔 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 로그&amp;nbsp;파일이&amp;nbsp;무작정&amp;nbsp;쌓이지&amp;nbsp;않도록 &lt;b&gt;일정 크기(예: 20MB)&lt;/b&gt; 또는 &lt;b&gt;일정 주기(예: 15일)&lt;/b&gt;에 따라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동으로 &lt;b&gt;파일 회전(Rotation)&lt;/b&gt; 되고 &lt;b&gt;날짜별&lt;/b&gt;로 파일이 &lt;b&gt;분리&lt;/b&gt;되어 생성되도록 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 필요한 정보만 선별 기록하여 &lt;b&gt;로그의 가독성과 관리 효율성&lt;/b&gt;을 증가시키기 위해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 및 운영 환경에 따라 &lt;b&gt;[debug, verbose, info, warn, error]&lt;/b&gt; 로그 레벨을 &lt;b&gt;실시간&lt;/b&gt;으로 조절할 수 있도록 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 &lt;b&gt;FILE_LOG_LEVEL&lt;/b&gt; 변수를 &lt;b&gt;info로 세팅 시&lt;/b&gt; 해당 값보다 높은 로그 레벨인,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[info, warn, error] &lt;/b&gt;세 가지의 로그 레벨이 로그 파일에 적재되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FILE_LOG_LEVEL&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;변수를&lt;b&gt;&lt;span&gt; error&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;로 세팅 시&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 가장 높은 레벨이므로 &lt;b&gt;error 로그만 파일&lt;/b&gt;에 적재된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이렇게 &lt;/span&gt;&lt;/span&gt;&lt;b&gt;실시간으로 레벨을 조절&lt;/b&gt;하여 필요한 정보만 효과적으로 기록 가능하게 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741105760691&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LOG_DIR: logs            # 로그 파일 저장 경로 (기본: 프로젝트 루트/logs)
CONSOLE_LOG_LEVEL: info  # 콘솔 출력 로그 레벨 (debug, verbose, info, warn, error)
FILE_LOG_LEVEL: error    # 파일 출력 로그 레벨 (debug, verbose, info, warn, error)
ROTATION_DAYS: 30d       # 로그 파일 보관 기간 (예: 30일)
MAX_FILE_SIZE: 20m       # 단일 파일 최대 크기 (예: 20MB)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 얘기한 변숫값들을 기본 설정을 제공하지만, 필요에 따라 &lt;b&gt;사용자 환경에 맞게 커스터마이징&lt;/b&gt; 할 수 있게 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정을&amp;nbsp;변경하려면&amp;nbsp;프로젝트&amp;nbsp;루트에&amp;nbsp;&lt;b&gt;logger-config.yaml&amp;nbsp;파일&lt;/b&gt;을 생성하고 원하는 값을 세팅하고,&lt;br /&gt;&lt;br /&gt;실행 시 자동으로 &lt;b&gt;Override&lt;/b&gt; 되어서 사용자가 원하는 환경설정을 할 수 있게끔 구성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설정 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;blanc-logger는 &lt;b&gt;NestJS 프로젝트&lt;/b&gt;에 아주 간단하게 통합할 수 있도록 설계되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741107159243&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install blanc-logger&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 &lt;b&gt;install&lt;/b&gt;을 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.&amp;nbsp;NestJS&amp;nbsp;전역&amp;nbsp;Logger&amp;nbsp;적용&amp;nbsp;(main.ts)&amp;nbsp;&lt;/h4&gt;
&lt;pre id=&quot;code_1741107228320&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { blancLogger, BlancLoggerMiddleware } from 'blanc-logger';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: blancLogger, // 전역 Logger 적용
  });

  // 미들웨어를 적용하여 요청 시 모듈명 등 컨텍스트 정보를 추가
  app.use(new BlancLoggerMiddleware().use); 

  await app.listen(3000);
}
bootstrap();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Blanc Logger를 &lt;b&gt;전역 로거로 적용&lt;/b&gt;하면, 애플리케이션 전체에서 &lt;b&gt;동일한 로깅 설정&lt;/b&gt;을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 미들웨어는 AppModule에서 &lt;b&gt;DI(Dependency Injection) 방식&lt;/b&gt;으로 등록해도 무방하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.&amp;nbsp;TypeORM&amp;nbsp;Logger&amp;nbsp;적용&amp;nbsp;(AppModule)&lt;/h4&gt;
&lt;pre id=&quot;code_1741107328589&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TypeOrmBlancLogger } from 'blanc-logger';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      // ... DB 설정
      logging: true,
      logger: new TypeOrmBlancLogger(), // TypeORM용 로거 사용
    }),
    // 다른 모듈들...
  ],
})
export class AppModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TypeORM&amp;nbsp;설정&lt;/b&gt;에서&amp;nbsp;Blanc&amp;nbsp;Logger의&amp;nbsp;전용&amp;nbsp;로거를&amp;nbsp;사용하여,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL 쿼리 및 데이터베이스 관련 로그를 효과적으로 기록할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 사용을 위한 설정은 모두 끝났다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기존 Logger 대체 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 사용법을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법도 정말 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Blanc Logger를 사용하여 &lt;b&gt;기존의 NestJS 내장 로거&lt;/b&gt;를 대체할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.&amp;nbsp;기존&amp;nbsp;코드&lt;/h4&gt;
&lt;pre id=&quot;code_1741107738844&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 기존 NestJS 내장 로거 사용:
this.logger.error('Error message', error.stack);
this.logger.log('Log message');&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.&amp;nbsp;Blanc&amp;nbsp;Logger&amp;nbsp;사용&lt;/h4&gt;
&lt;pre id=&quot;code_1741107748059&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 에러 발생 시, 스택 정보와 함께 기록
blancLogger.error('Error message', { moduleName: 'ModuleName', stack: error.stack });
blancLogger.log('Log message', { moduleName: 'ModuleName' });
blancLogger.warn('Warn message', { moduleName: 'ModuleName' });
blancLogger.verbose('Verbose message', { moduleName: 'ModuleName' });
blancLogger.debug('Debug message', { moduleName: 'ModuleName' });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 기존 Logger를 대체하여 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용 예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 적용한 Logger에 적용 예시를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. Logging&amp;nbsp;Interceptor&amp;nbsp;구현&lt;/h4&gt;
&lt;pre id=&quot;code_1741108087347&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { blancLogger } from 'blanc-logger';
import * as chalk from 'chalk';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable&amp;lt;any&amp;gt; {
    const startTime = Date.now();
    const req = context.switchToHttp().getRequest();
    const decodedUrl = decodeURIComponent(req.url);
    const moduleName = (req as any).moduleName || 'UnknownModule';

    return next.handle().pipe(
      tap(() =&amp;gt; {
        const delay = Date.now() - startTime;
        const delayStr =
          delay &amp;gt; 100 ? chalk.bold.red(`${delay}ms  `) : chalk.magenta(`${delay}ms`);
        const message = `Request processed: ${chalk.yellow(req.method)} ${chalk.green(
          decodedUrl,
        )} ${delayStr}`;
        blancLogger.log(message, moduleName);
      }),
    );
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전역 인터셉터로 적용&lt;/b&gt;하려면 AppModule에 아래와 같이 등록하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741108128273&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggingInterceptor } from './commons/interceptors/logging.interceptor';

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: LoggingInterceptor, // 전역 인터셉터로 등록
    },
  ],
})
export class AppModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HTTP 요청 처리 시간을 측정&lt;/b&gt;하여 로그로 기록하는 인터셉터 예시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;아까 적용한 &lt;b&gt;BlancLoggerMiddleware&lt;/b&gt;를 통해 설정된 모듈명 정보가 자동으로 포함된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKV54T/btsMAWjrpou/yH0YkjDhTFaqKTi0r9W43K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKV54T/btsMAWjrpou/yH0YkjDhTFaqKTi0r9W43K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKV54T/btsMAWjrpou/yH0YkjDhTFaqKTi0r9W43K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKV54T%2FbtsMAWjrpou%2FyH0YkjDhTFaqKTi0r9W43K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;34&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 로그가 출력된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(응답 시간 초과 시 (예: 100ms)강조)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. Global&amp;nbsp;Exception&amp;nbsp;Filter&amp;nbsp;구현&lt;/h4&gt;
&lt;pre id=&quot;code_1741108320841&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {
  ArgumentsHost,
  Catch,
  ExceptionFilter,
  HttpException,
  InternalServerErrorException,
} from '@nestjs/common';
import { blancLogger } from 'blanc-logger';
import { Request, Response } from 'express';

interface ExceptionResponse {
  status: number;
  message: string;
  stack?: string;
}

/** 예외 객체를 처리하여 상태, 메시지, 스택을 반환하는 함수 */
const handleException = (exception: unknown, _request: Request): ExceptionResponse =&amp;gt; {
  if (exception instanceof HttpException) {
    const status = exception.getStatus();
    const res = exception.getResponse();
    const message =
      typeof res === 'object' &amp;amp;&amp;amp; res !== null
        ? (res as any).message ?? exception.message
        : exception.message;
    return {
      status,
      message: `HTTP Exception: ${message}`,
      stack: exception instanceof Error ? exception.stack : '',
    };
  }
  if (exception instanceof Error) {
    const status = new InternalServerErrorException().getStatus();
    return {
      status,
      message: `Unhandled exception: ${exception.message}`,
      stack: exception.stack,
    };
  }
  return { status: 500, message: 'Unknown error' };
};

@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost): void {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse&amp;lt;Response&amp;gt;();
    const request = ctx.getRequest&amp;lt;Request&amp;gt;();

    const moduleName = (request as any)?.moduleName ?? 'Global';
    const { status, message, stack } = handleException(exception, request);

    blancLogger.error(message, {
      moduleName,
      path: request.url,
      stack,
    });

    response.status(status).json({
      statusCode: status,
      status: message,
      timestamp: new Date().toISOString(),
      path: request.url,
    });
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전역&amp;nbsp;필터로&amp;nbsp;적용&lt;/b&gt;하려면 AppModule에 아래와 같이 등록하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741108374548&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { GlobalExceptionFilter } from './commons/filters/global-exception.filter';

@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: GlobalExceptionFilter, // 전역 필터로 등록
    },
  ],
})
export class AppModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 다 적용을 했으면 &lt;b&gt;예외&lt;/b&gt;를 던져보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741108404193&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;throw new ConflictException('DUPLICATION');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be3q8M/btsMCvY5KUk/KrrRVKuHLgYOyMGKHG0Md0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be3q8M/btsMCvY5KUk/KrrRVKuHLgYOyMGKHG0Md0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be3q8M/btsMCvY5KUk/KrrRVKuHLgYOyMGKHG0Md0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe3q8M%2FbtsMCvY5KUk%2FKrrRVKuHLgYOyMGKHG0Md0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;139&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1741108470273&quot; class=&quot;json&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;// error-2025-03-05.log 
{&quot;level&quot;:&quot;error&quot;,&quot;message&quot;:&quot;HTTP Exception: DUPLICATION&quot;,&quot;stack&quot;:[{&quot;moduleName&quot;:&quot;user&quot;,&quot;path&quot;:&quot;/api/user/profile&quot;,&quot;stack&quot;:&quot;ConflictException: DUPLICATION\n    at UserService.getProfile (/path/to/src/user/user.service.ts:60:13)\n    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)&quot;}],&quot;timestamp&quot;:&quot;2025-03-05 02:29:51&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 &lt;b&gt;에러 로그 출력&lt;/b&gt;과 함께 &lt;b&gt;로그 파일&lt;/b&gt;에 정상적으로 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;npm 배포&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 &lt;b&gt;npm배포 후 GitHub 패키지&lt;/b&gt;까지 둘 다 배포를 하였으나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 &lt;b&gt;package.json&lt;/b&gt; 파일에 아래 설정을 적용하여 동시에 배포하려 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741108725410&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;publishConfig&quot;: {
  &quot;registry&quot;: &quot;https://npm.pkg.github.com/&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 적용하였을 때, &lt;b&gt;두 레지스트리 간의 설정 충돌&lt;/b&gt;과 배포 관련 이슈가 발생하였으며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동시에 관리하는 것이 비효율적&lt;/b&gt;인 것으로 확인되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GitHub 패키지&lt;/b&gt;는 주로 프라이빗 패키지 관리 용도로 활용하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CI/CD 환경&lt;/b&gt;에서 npm 패키지가 더 쉽게 배포 및 설치 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 최종적으로 불필요한 복잡성을 줄이기 위해&lt;b&gt;&amp;nbsp;npm 배포에 집중&lt;/b&gt;하기로 결정하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 &lt;b&gt;package.json&lt;/b&gt;에 다음과 같은 설정이 필요하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;b&gt;빌드 결과물만 포함&lt;/b&gt;하도록&amp;nbsp;하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1741111344785&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;files&quot;: [&quot;dist&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. ES 모듈, CommonJS, 타입스크립트 타입 파일을 각각 지원하도록 구성하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1741111287494&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;exports&quot;: { 
    &quot;import&quot;: &quot;./dist/index.js&quot;, 
    &quot;require&quot;: &quot;./dist/index.cjs&quot;, 
    &quot;types&quot;: &quot;./dist/index.d.ts&quot; 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 검색&amp;nbsp;최적화를&amp;nbsp;위한&amp;nbsp;&lt;b&gt;키워드&amp;nbsp;추가&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741111421367&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  &quot;keywords&quot;: [
    &quot;winston&quot;,
    &quot;nestjs&quot;,
    &quot;logger&quot;,
    &quot;typeorm&quot;,
  ],&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고&lt;b&gt; tsconfig.json&lt;/b&gt;&amp;nbsp;파일을&amp;nbsp;통해&amp;nbsp;&lt;b&gt;엄격한 컴파일 환경&amp;nbsp;&lt;/b&gt;(예:&amp;nbsp;CommonJS&amp;nbsp;모듈,&amp;nbsp;ES6&amp;nbsp;타겟,&amp;nbsp;데코레이터&amp;nbsp;지원&amp;nbsp;등)을&amp;nbsp;설정하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm에 배포된 &lt;b&gt;blanc-logger&lt;/b&gt;는 아래 링크에서 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS를 사용하시는 분들이라면 한번 사용해 보시길 ! &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/blanc-logger&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.npmjs.com/package/blanc-logger&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741109361548&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;blanc-logger&quot; data-og-description=&quot;Advanced Winston logger for NestJS &amp;amp; TypeORM with structured logging (npm package).. Latest version: 1.0.9, last published: a day ago. Start using blanc-logger in your project by running &amp;#96;npm i blanc-logger&amp;#96;. There are no other projects in the npm registry&quot; data-og-host=&quot;www.npmjs.com&quot; data-og-source-url=&quot;https://www.npmjs.com/package/blanc-logger&quot; data-og-url=&quot;https://www.npmjs.com/package/blanc-logger&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/VTQ6o/hyYmZgZ0le/g50Whu0QGnPoCDnCWizSJ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/blanc-logger&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.npmjs.com/package/blanc-logger&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/VTQ6o/hyYmZgZ0le/g50Whu0QGnPoCDnCWizSJ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;blanc-logger&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Advanced Winston logger for NestJS &amp;amp; TypeORM with structured logging (npm package).. Latest version: 1.0.9, last published: a day ago. Start using blanc-logger in your project by running `npm i blanc-logger`. There are no other projects in the npm registry&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.npmjs.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/yooseungmo/blanc-logger&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/yooseungmo/blanc-logger&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741109631035&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - yooseungmo/blanc-logger: Advanced Winston logger for NestJS &amp;amp; TypeORM with structured logging (npm package).&quot; data-og-description=&quot;Advanced Winston logger for NestJS &amp;amp; TypeORM with structured logging (npm package). - yooseungmo/blanc-logger&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/yooseungmo/blanc-logger&quot; data-og-url=&quot;https://github.com/yooseungmo/blanc-logger&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cbcsve/hyYmI0JIb3/KMjOtu1Zj8MgUmJsUtkfk1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/imdqy/hyYmTnCfvx/QnzN60zFglE1H6B5CIMV00/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/yooseungmo/blanc-logger&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/yooseungmo/blanc-logger&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cbcsve/hyYmI0JIb3/KMjOtu1Zj8MgUmJsUtkfk1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/imdqy/hyYmTnCfvx/QnzN60zFglE1H6B5CIMV00/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - yooseungmo/blanc-logger: Advanced Winston logger for NestJS &amp;amp; TypeORM with structured logging (npm package).&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Advanced Winston logger for NestJS &amp;amp; TypeORM with structured logging (npm package). - yooseungmo/blanc-logger&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/NestJS</category>
      <category>logging</category>
      <category>nestJS</category>
      <category>npm</category>
      <category>TypeORM</category>
      <category>Winston</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/78</guid>
      <comments>https://ilikezzi.tistory.com/78#entry78comment</comments>
      <pubDate>Wed, 5 Mar 2025 03:08:35 +0900</pubDate>
    </item>
    <item>
      <title>[NestJS] @automock/jest로 번거로운 Unit Test Mocking 자동화하기</title>
      <link>https://ilikezzi.tistory.com/77</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;1132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA5si6/btsL3nWC7Xv/Ww02XT5aw0tXOFjMUUDYD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA5si6/btsL3nWC7Xv/Ww02XT5aw0tXOFjMUUDYD0/img.png&quot; data-alt=&quot;Jest&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA5si6/btsL3nWC7Xv/Ww02XT5aw0tXOFjMUUDYD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA5si6%2FbtsL3nWC7Xv%2FWw02XT5aw0tXOFjMUUDYD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;250&quot; height=&quot;303&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;1132&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Jest&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS에서 &lt;b&gt;유닛 테스트&lt;/b&gt;를 작성할 때, 많은 &lt;b&gt;의존성을 모킹(Mock)&lt;/b&gt;해야 하는 상황이 자주 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Repository, Service, ConfigService, Cache 등 다양한 Provider를 직접 등록하고&lt;b&gt; &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;jest.fn()&lt;/b&gt;을 이용해 일일이 모킹하면 &lt;b&gt;코드가 복잡&lt;/b&gt;해지고 관리가 어려워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하기 위해 &lt;b&gt;AutoMock&lt;/b&gt;을 활용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 @automock/jest를 사용해 번거로운 Provider 등록 과정을 자동화하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NestJS의 DI 흐름&lt;/b&gt;을 그대로 모사하여 테스트하는 방법을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;기존의 Mocking 방식과 문제점&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS에서 유닛 테스트를 작성할 때, 종속된 서비스나 레포지토리를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 `&lt;b&gt;jest.fn()&lt;/b&gt;`을 사용하여 &lt;b&gt;일일이 Mocking&lt;/b&gt;해야 했다. &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 `@nestjs/testing`의 `Test.createTestingModule`을 사용하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`providers` 배열에 `useValue` 또는 `useFactory`를 통해 Mock 객체를 &lt;b&gt;수동으로 주입&lt;/b&gt;해야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일일이 주입해야 하므로, Provider가 많을수록 복잡해지는 문제가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1738386991625&quot; class=&quot;typescript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;const mockUserRepository = {
  findOne: jest.fn(),
};

const mockConfigService = {
  get: jest.fn(),
};

const mockJwtService = {
  signAsync: jest.fn(),
  verifyAsync: jest.fn(),
};

const mockUserService = {
  create: jest.fn(),
};

const mockCacheManager = {
  set: jest.fn(),
};

describe('AuthService', () =&amp;gt; {
  let authService: AuthService;
  let userRepository: Repository&amp;lt;User&amp;gt;;
  let configService: ConfigService;
  let jwtService: JwtService;

  beforeEach(async () =&amp;gt; {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        AuthService,
        {
          provide: getRepositoryToken(User),
          useValue: mockUserRepository,
        },
        {
          provide: ConfigService,
          useValue: mockConfigService,
        },
        {
          provide: JwtService,
          useValue: mockJwtService,
        },
        // ...
      ],
    }).compile();

    authService = module.get&amp;lt;AuthService&amp;gt;(AuthService);
    userRepository = module.get&amp;lt;Repository&amp;lt;User&amp;gt;&amp;gt;(getRepositoryToken(User));
    configService = module.get&amp;lt;ConfigService&amp;gt;(ConfigService);
    jwtService = module.get&amp;lt;JwtService&amp;gt;(JwtService);
  });

  // ... 테스트 코드 ...
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 방식의 단점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;providers: [...]&lt;/span&gt;&lt;span&gt; 배열에 &lt;/span&gt;&lt;b&gt;Mock 객체를 매번 수동으로 등록&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;의존하는 객체가 많아질수록 테스트 코드가 &lt;b&gt;복잡&lt;/b&gt;해진다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;b&gt;&lt;span&gt; &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;Mock 객체를 직접 관리해야&lt;/b&gt; 해서 유지보수에 부담이 크다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;새로운 Provider가 추가될 때마다 &lt;b&gt;일일이 변경&lt;/b&gt;해야 하는 번거롭다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하기 위해 &lt;span&gt;@automock/jest&lt;/span&gt;를 적용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;span&gt;AutoMock(@automock/jest)&amp;nbsp;&lt;/span&gt;적용&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;@automock/jest는 이러한 번거로운 과정을 &lt;b&gt;자동화&lt;/b&gt;해주는 라이브러리다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;NestJS에서 필요한 Provider를 알아서 찾아 &lt;b&gt;Mock 버전&lt;/b&gt;으로 주입해주므로,&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기존 대비 훨씬 &lt;b&gt;코드가 간결&lt;/b&gt;해진다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;패키지 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;npm i -D @automock/jest @automock/adapters.nestjs&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;@automock/jest&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;적용 방식&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738387115088&quot; class=&quot;typescript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;import { TestBed } from '@automock/jest';

describe('MovieService', () =&amp;gt; {
  let movieService: MovieService;
  let movieRepository: jest.Mocked&amp;lt;Repository&amp;lt;Movie&amp;gt;&amp;gt;;

  beforeEach(async () =&amp;gt; {
    // TestBed.create(MovieService) 호출 시, 의존성이 자동으로 Mock 처리된다.
    const { unit, unitRef } = TestBed.create(MovieService).compile();
     
    /**
     * unit: 실제 테스트 대상인 MovieService의 인스턴스 (Mock 아님)
     * unitRef: Nest DI 컨테이너처럼 작동하는 레퍼런스 (Mock을 get(token)으로 조회)
     */
    movieService = unit;
    movieRepository = unitRef.get(getRepositoryToken(Movie) as string);
  });

  // ... 테스트 코드 ...
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 기존 방식&lt;/b&gt;: beforeEach에서 Mock 객체를 만들고, providers에 수동 등록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- AutoMock 방식&lt;/b&gt;: TestBed.create(MyService).compile()만 하면, NestJS에서 주입받는 의존성을 &lt;b&gt;자동으로&lt;/b&gt; Mock 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동작 원리를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. TestBed.create(MyService).compile()를 호출하면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MyService가 의존하는 모든 Provider를 NestJS 컨테이너처럼 자동 스캔하여 &lt;b&gt;Mock 버전&lt;/b&gt;을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;b&gt;unit&lt;/b&gt;은 실제 서비스의 인스턴스(테스트 대상)이고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;unitRef&lt;/b&gt;는 Nest 컨테이너처럼 get(token)을 통해 Mock 객체를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 리포지토리나 ConfigService 같은 객체는 jest.Mocked&amp;lt;Type&amp;gt; 형태로 제공되어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mockResolvedValue(), mockImplementation() 등의&lt;b&gt; Jest 함수를 바로 사용&lt;/b&gt;할 수 있어 편리하다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;color: #000000; text-align: start; border-collapse: collapse; width: 100%; height: 95px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 16.0465%; height: 19px;&quot;&gt;&lt;span&gt;항목&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.1861%; height: 19px;&quot;&gt;&lt;span&gt;기존 방식&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.6511%; height: 19px;&quot;&gt;&lt;span&gt;@automock/jest&amp;nbsp;적용 후&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 16.0465%; height: 19px;&quot;&gt;&lt;span&gt;의존성 주입&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.1861%; height: 19px;&quot;&gt;&lt;span&gt;providers: [...]&lt;span&gt;에 직접 Mock 객체 등록&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.6511%; height: 19px;&quot;&gt;&lt;span&gt;TestBed.create()&lt;span&gt; 호출만으로 자동 처리&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 16.0465%; height: 19px;&quot;&gt;&lt;span&gt;의존성 접근&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.1861%; height: 19px;&quot;&gt;&lt;span&gt;module.get(토큰)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.6511%; height: 19px;&quot;&gt;&lt;span&gt;unitRef.get(토큰)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 16.0465%; height: 19px;&quot;&gt;&lt;span&gt;유지보수&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.1861%; height: 19px;&quot;&gt;&lt;span&gt;의존성이 많아질수록 복잡해짐&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.6511%; height: 19px;&quot;&gt;&lt;span&gt;간결하고 확장 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 16.0465%; height: 19px;&quot;&gt;&lt;span&gt;Mock 생성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.1861%; height: 19px;&quot;&gt;&lt;span&gt;&lt;span&gt;jest.fn()&lt;/span&gt;을 이용해 직접 생성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.6511%; height: 19px;&quot;&gt;&lt;span&gt;자동 생성된 Mock 사용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적용 후 장점을 살펴보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 코드 간소화&lt;/b&gt;: 테스트를 위한 모킹 로직이 줄어듦으로써, 테스트 파일이 한결 가독성 있어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- NestJS 친화적인 DI&lt;/b&gt;: NestJS의 Provider/DI 매커니즘을 그대로 사용하므로, 실제 애플리케이션 구조와 유사한 테스트가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 유지보수성 향상&lt;/b&gt;: Provider가 늘어나도 자동으로 Mock가 생성되므로, 설정해야 하는 부분이 최소화된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 커버리지 상승&lt;/b&gt;: 모킹 작업 부담이 줄어드니, 로직 테스트에 집중할 수 있어 자연스럽게 커버리지를 높일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Automock&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;적용 후 간결해진 코드 예시&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp;&lt;/h3&gt;
&lt;pre id=&quot;code_1738387118124&quot; class=&quot;typescript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { TestBed } from '@automock/jest';

describe('MovieService', () =&amp;gt; {
  let movieService: MovieService;
  let movieRepository: jest.Mocked&amp;lt;Repository&amp;lt;Movie&amp;gt;&amp;gt;;
  let directorRepository: jest.Mocked&amp;lt;Repository&amp;lt;Director&amp;gt;&amp;gt;;
  let genreRepository: jest.Mocked&amp;lt;Repository&amp;lt;Genre&amp;gt;&amp;gt;;
  let userRepository: jest.Mocked&amp;lt;Repository&amp;lt;User&amp;gt;&amp;gt;;
  let dataSource: jest.Mocked&amp;lt;DataSource&amp;gt;;
  let commonService: jest.Mocked&amp;lt;CommonService&amp;gt;;
  let cacheManager: jest.Mocked&amp;lt;Cache&amp;gt;;

  beforeEach(async () =&amp;gt; { 
    // 오토목 TestBed 사용
    const { unit, unitRef } = TestBed.create(MovieService).compile();

    movieService = unit;
    movieRepository = unitRef.get(getRepositoryToken(Movie) as string);
    directorRepository = unitRef.get(getRepositoryToken(Director) as string);
    genreRepository = unitRef.get(getRepositoryToken(Genre) as string);
    userRepository = unitRef.get(getRepositoryToken(User) as string);
    dataSource = unitRef.get(DataSource);
    commonService = unitRef.get(CommonService);
    cacheManager = unitRef.get(CACHE_MANAGER);
  });

  // ... 테스트 코드 ...
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;providers: [...] 배열에 useValue로 Mock 객체를 일일이 등록하거나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jest.fn()을 통해 중복 설정하지 않아도 되므로 테스트 코드가 상당히 간결해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;JEST 커버리지 100% + E2E 테스트&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;@automock/jest&lt;/span&gt;를 적용하여 기존보다 훨씬 빠르고 쉽게 테스트를 작성할 수 있었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로 &lt;b&gt;Jest 커버리지 100%&lt;/b&gt;를 달성하였으며, &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;유닛(Unit), 통합(Integration), E2E(End-to-End)&lt;/b&gt; 테스트까지 완료했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YRPEC/btsL3xx7AYa/1IkT2a700P5IzpFquCAsK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YRPEC/btsL3xx7AYa/1IkT2a700P5IzpFquCAsK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YRPEC/btsL3xx7AYa/1IkT2a700P5IzpFquCAsK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYRPEC%2FbtsL3xx7AYa%2F1IkT2a700P5IzpFquCAsK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;351&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AutoMock&lt;/b&gt;을 활용하면 NestJS 테스트에서 필요한 의존성을 자동으로 &lt;b&gt;Mocking&lt;/b&gt;하여,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 코드의 &lt;b&gt;복잡도를 줄이고&lt;/b&gt; 유지보수성을 극대화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 의존성으로 인해 테스트 작성을 미뤘다면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;AutoMock을 도입하여 안정적이고 &lt;b&gt;효율적인 테스트 환경&lt;/b&gt;을 구축해보길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #171717; text-align: start;&quot;&gt;Happy Testing !!! &lt;span style=&quot;background-color: #ffffff; color: #171717; text-align: start;&quot;&gt; &lt;/span&gt; &amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조 :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.nestjs.com/fundamentals/testing&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.nestjs.com/fundamentals/testing&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.nestjs.com/recipes/suites#suites-formerly-automock&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.nestjs.com/recipes/suites#suites-formerly-automock&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jestjs.io/docs/es6-class-mocks#automatic-mock&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jestjs.io/docs/es6-class-mocks#automatic-mock&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.to/omermorad/unit-test-like-a-pro-automock-my-open-source-answer-to-mocking-frustration-31p4&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.to/omermorad/unit-test-like-a-pro-automock-my-open-source-answer-to-mocking-frustration-31p4&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/NestJS</category>
      <category>automock</category>
      <category>jest</category>
      <category>nestJS</category>
      <category>Unit Test</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/77</guid>
      <comments>https://ilikezzi.tistory.com/77#entry77comment</comments>
      <pubDate>Sun, 2 Feb 2025 08:44:16 +0900</pubDate>
    </item>
    <item>
      <title>[Postman] 환경변수와 Script를 활용한 랜덤 데이터 생성부터 관계형 데이터 Seeding까지</title>
      <link>https://ilikezzi.tistory.com/76</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1qZBz/btsLUnOTnli/E6fxVLaaB2k39qUenM6JY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1qZBz/btsLUnOTnli/E6fxVLaaB2k39qUenM6JY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1qZBz/btsLUnOTnli/E6fxVLaaB2k39qUenM6JY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1qZBz%2FbtsLUnOTnli%2FE6fxVLaaB2k39qUenM6JY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;270&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;570&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발을 하다&lt;b&gt;&amp;nbsp;페이지네이션 관련 테스트&lt;/b&gt;를 진행해야 하는 상황이 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관계형 데이터를 하나하나 매핑해서 &lt;b&gt;적재하는 작업이 번거로워,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보다 간편한 방법을 찾던 중 이 방식을 활용해봤는데, 매우 유용해서 포스팅하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Postman 환경변수와 Script&lt;/b&gt;를 활용해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;랜덤 데이터&lt;/b&gt;부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;관계형 데이터(FK)&lt;/b&gt;까지 한 번에 생성해보고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이후에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Collection Runner&lt;/b&gt;로 대량 데이터를 만들어 보는 과정을 정리해보려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 TypeORM 관계 설정&lt;b&gt;(@ManyToOne, @ManyToMany 등)&lt;/b&gt;을 해둔 DB에 손쉽게 데이터를 넣을 수 있는 방법이라, &lt;br /&gt;&lt;br /&gt;대규모 테스트에도 편리하게 활용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일일히 넣기 귀찮은 &lt;b&gt;Token 자동화&lt;/b&gt;부터, &lt;b&gt;랜덤한 데이터 생성&lt;/b&gt;, &lt;b&gt;Runner로 대규모 데이터&lt;/b&gt; 만들기 까지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금부터 하나씩 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;환경변수(Environments) 설정&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-21 오전 5.05.00.png&quot; data-origin-width=&quot;1866&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnNSff/btsLStpp67L/bSXKjIYDPNYMPxyPnNRFf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnNSff/btsLStpp67L/bSXKjIYDPNYMPxyPnNRFf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnNSff/btsLStpp67L/bSXKjIYDPNYMPxyPnNRFf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnNSff%2FbtsLStpp67L%2FbSXKjIYDPNYMPxyPnNRFf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;223&quot; data-filename=&quot;스크린샷 2025-01-21 오전 5.05.00.png&quot; data-origin-width=&quot;1866&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Postman에서 새 &lt;b&gt;Environment&lt;/b&gt;를 하나 생성하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;환경변수를 사용해 &lt;b&gt;API URL&lt;/b&gt;이나 &lt;b&gt;동적인 데이터&lt;/b&gt;를 간단히 관리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이제 다음과 같이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;host&lt;/b&gt;를 추가해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;host: ex) http://localhost:3000&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 만들어두면, &lt;span&gt;API 호출 시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;{{host}}&lt;/span&gt;&lt;span&gt;가 자동으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;http://localhost:3000&lt;/span&gt;&lt;span&gt;으로 대체된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737403817676&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;- Path 사용법:
{{host}}/movie&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 &lt;b&gt;Environment&lt;/b&gt;에 다양한 변수들을 추가시킬 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;로그인 및 Token 자동화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 &lt;b&gt;POST {{host}}/auth/login&lt;/b&gt;을 호출했다고 가정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 API가 &lt;b&gt;accessToken, refreshToken&lt;/b&gt;을 JSON으로 리턴한다고 할 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Script&lt;/b&gt;에서 아래처럼 코드를 작성해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-21 오전 5.16.22.png&quot; data-origin-width=&quot;1308&quot; data-origin-height=&quot;606&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cILn2B/btsLSRRuwHv/TId8PGVU9Qj5RejSUwfU01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cILn2B/btsLSRRuwHv/TId8PGVU9Qj5RejSUwfU01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cILn2B/btsLSRRuwHv/TId8PGVU9Qj5RejSUwfU01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcILn2B%2FbtsLSRRuwHv%2FTId8PGVU9Qj5RejSUwfU01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;278&quot; data-filename=&quot;스크린샷 2025-01-21 오전 5.16.22.png&quot; data-origin-width=&quot;1308&quot; data-origin-height=&quot;606&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌측에 &lt;b&gt;Pre-request&lt;/b&gt;랑 &lt;b&gt;Post-reponse&lt;/b&gt;가 있는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 작업은 return값을 활용해야 하므로 &lt;b&gt;Post-reponse&amp;nbsp;&lt;/b&gt;를 선택하고 스크립트를 작성하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737404307433&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pm.test(&quot;Status code is 201&quot;, function (){
    pm.response.to.have.status(201)

    const body = pm.response.json()

    pm.environment.set(&quot;accessToken&quot;, body.accessToken);
    pm.environment.set(&quot;refreshToken&quot;, body.refreshToken);
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 코드는 &lt;b&gt;로그인 성공 시&lt;/b&gt; 응답으로 받은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span&gt;accessToken&lt;/span&gt;&lt;span&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;refreshToken&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 Postman &lt;b&gt;환경변수에 저장&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-21 오전 5.19.56.png&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpSeHw/btsLTGn6rTi/ta4Kh3uI1vjqsinV9AgM11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpSeHw/btsLTGn6rTi/ta4Kh3uI1vjqsinV9AgM11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpSeHw/btsLTGn6rTi/ta4Kh3uI1vjqsinV9AgM11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpSeHw%2FbtsLTGn6rTi%2Fta4Kh3uI1vjqsinV9AgM11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;278&quot; data-filename=&quot;스크린샷 2025-01-21 오전 5.19.56.png&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행시키고 &lt;b&gt;Environment&lt;/b&gt;에 가보면 Token이 정상적으로 추가되었을것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;Environment&lt;/b&gt;에 있는 Token을 사용해서 &lt;b&gt;Authorization 재사용&lt;/b&gt; 설정을 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. 다른 API에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span&gt;Authorization&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;타입&lt;/b&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span&gt;Inherit auth from parent&lt;/span&gt;&lt;/b&gt;&lt;span&gt;로 설정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;2. &lt;b&gt;프로젝트 상단의 폴더&lt;/b&gt;에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Authorization&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;타입을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span&gt;Bearer Token&lt;/span&gt;&lt;/b&gt;&lt;span&gt;으로 변경한 뒤, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Token 값에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span&gt;{{accessToken}}&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 입력한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이후 한 번만 로그인하면, 모든 요청에서 &lt;b&gt;환경변수에 저장된 토큰 값&lt;/b&gt;을 사용하여 편리하게 인증할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 귀찮게 매번 헤더에 토큰을 추가해서 디버깅하지 않아도 된다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;랜덤 데이터 생성&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Postman에서는 일부 &lt;b&gt;빌트인 랜덤 변수&lt;/b&gt;를 제공한다. 예를 들어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737404857229&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;{{$randomFullName}}&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 작성하면, &lt;span&gt;Body 데이터 생성할&amp;nbsp;&lt;/span&gt;때마다 새로운 이름으로 데이터를 생성할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 외에도 &lt;b&gt;{{$randomCountry}}, {{$randomLoremSentence}},&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;{{$randomNoun}}, {{$randomAdjective}} 등&lt;/b&gt; 다양한 랜덤 변수가 있으니 참고하면 편리하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;관계형 데이터 Seeding 설정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 TypeORM 예시를 들어서, &lt;b&gt;Director&lt;/b&gt;와 &lt;b&gt;Movie&lt;/b&gt;, 그리고 &lt;b&gt;Genre&lt;/b&gt; 간의 관계를 다뤄봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737405105653&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Movie Entity
@ManyToMany(() =&amp;gt; Genre, (genre) =&amp;gt; genre.movies)
@JoinTable()
genres: Genre[];

@ManyToOne(() =&amp;gt; Director, (director) =&amp;gt; director.id, {
  cascade: true,
  nullable: false,
})
director: Director;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;영화(Movie)&lt;/b&gt;에 &lt;b&gt;장르(Genre)&lt;/b&gt;가 여러 개 매핑될 수 있으므로 &lt;b&gt;@ManyToMany&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;감독(Director)&lt;/b&gt;은 &lt;b&gt;@ManyToOne&lt;/b&gt;으로 지정해두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;FK인 Director와 Genre 먼저 생성해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Director POST API&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Director&lt;/b&gt;를 생성하는 API를 예시로 보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737405292089&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;name&quot;: &quot;{{$randomFullName}}&quot;,
    &quot;dob&quot;: &quot;1963-05-02T00:00:00.000Z&quot;,
    &quot;nationality&quot;: &quot;{{$randomCountry}}&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Body에 &lt;b&gt;랜덤 변수&lt;/b&gt;들을 넣어서, 다양한 감독 정보가 쌓이도록 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답에서 받은 &lt;b&gt;director의 id&lt;/b&gt;를 &lt;b&gt;환경변수에 계속 누적&lt;/b&gt;하기 위해, &lt;b&gt;Script&lt;/b&gt;에서 아래처럼 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737405364073&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pm.test(&quot;Status code is 201&quot;, function () {
    pm.response.to.have.status(201);

    const body = pm.response.json();

    let directorIds = pm.environment.get(&quot;directorIds&quot;);
    if(!directorIds){
        directorIds = body.id;
    } else {
        directorIds = directorIds + ',' + body.id;
    }

    pm.environment.set(&quot;directorIds&quot;, directorIds);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;아까와 마찬가지로 return값을 활용해야 하므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Post-reponse&amp;nbsp;&lt;/b&gt;를 선택하고 스크립트를 작성하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 스크립트는 &lt;b&gt;Director&lt;/b&gt;를 하나 만들 때마다 &lt;b&gt;directorIds 문자열에 ,로 ID를 이어붙여서 저장&lt;/b&gt;했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Genre POST API&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Genre&lt;/b&gt;도 마찬가지로, 아래처럼 Body를 작성하고 응답의 id를 모아서 genreIds에 저장했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737405595776&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;{{$randomNoun}}&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1737405603906&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pm.test(&quot;Status code is 201&quot;, function () {
    pm.response.to.have.status(201);

    const body = pm.response.json();

    let genres = pm.environment.get(&quot;genreIds&quot;);
    if(!genres){
        genres = body.id;
    } else {
        genres = genres + ',' + body.id;
    }

    pm.environment.set(&quot;genreIds&quot;, genres);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;아까와 마찬가지로 return값을 활용해야 하므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Post-reponse&amp;nbsp;&lt;/b&gt;를 선택하고 스크립트를 작성하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-21 오전 5.41.47.png&quot; data-origin-width=&quot;1586&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zv2Dz/btsLSNH3KZA/MomZqk0gSSAZttuzCqkTU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zv2Dz/btsLSNH3KZA/MomZqk0gSSAZttuzCqkTU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zv2Dz/btsLSNH3KZA/MomZqk0gSSAZttuzCqkTU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzv2Dz%2FbtsLSNH3KZA%2FMomZqk0gSSAZttuzCqkTU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;165&quot; data-filename=&quot;스크린샷 2025-01-21 오전 5.41.47.png&quot; data-origin-width=&quot;1586&quot; data-origin-height=&quot;436&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이렇게 하면, &lt;b&gt;Director IDs와 Genre IDs&lt;/b&gt;가 각각&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;환경변수에 누적&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;되므로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Movie&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터를 만들 때 이를 참조하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Movie (PK) POST API&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737405802835&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;title&quot;: &quot;{{$randomNoun}} {{$randomAdjective}} {{$randomAlphaNumeric}}&quot;,
    &quot;detail&quot;: &quot;{{$randomLoremSentence}}&quot;,
    &quot;directorId&quot;: {{director}},
    &quot;genreIds&quot;: [{{genres}}]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{{$randomNoun}}, {{$randomAdjective}}, {{$randomAlphaNumeric}} 등을 조합해 &lt;b&gt;영화 제목&lt;/b&gt;을 랜덤하게 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;directorId와 genreIds&lt;/b&gt;에 아까 쌓은 Postman 환경변수를 사용하도록 설정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737405947042&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const _ = require('lodash');

const directorIds = pm.environment.get('directorIds').split(&quot;,&quot;);
const randomDirectorId = _.sample(directorIds);
pm.environment.set(&quot;director&quot;, randomDirectorId);

const genreIds = pm.environment.get('genreIds').split(&quot;,&quot;);
const pickedGenreIds = [];
let failCount = 0;

while(pickedGenreIds.length &amp;lt; 3 &amp;amp;&amp;amp; failCount &amp;lt; 20) {
    const randomGenreId = _.sample(genreIds);

    if(pickedGenreIds.includes(randomGenreId)) {
        failCount++;
        continue;
    }

    pickedGenreIds.push(randomGenreId);
}

pm.environment.set(&quot;genres&quot;, pickedGenreIds);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 Body에서 &lt;b&gt;{{director}}, {{genres}}&lt;/b&gt;라는 변수를 썼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 값들은 request 전에 필요하므로&amp;nbsp;&lt;b&gt;Pre-request Script&lt;/b&gt;에서 작성하고, 무작위로 뽑아내준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lodash의 .sample() 함수를 사용해서 &lt;b&gt;directorIds 중 하나를 무작위&lt;/b&gt;로 뽑았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;genreIds 중 &lt;b&gt;3개까지만 골라&lt;/b&gt;서 genres 변수에 할당했다. (&lt;b&gt;중복 방지&lt;/b&gt;를 위해 &lt;b&gt;failCount&lt;/b&gt;도 추가)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737406099552&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;id&quot;: 917,
    &quot;title&quot;: &quot;program cross-platform t&quot;,
    &quot;detail&quot;: {
        &quot;id&quot;: 917,
        &quot;detail&quot;: &quot;Rerum voluptas omnis.&quot;
    },
    &quot;director&quot;: {
        &quot;id&quot;: 229,
        &quot;name&quot;: &quot;Kathy Cummings&quot;,
        &quot;dob&quot;: &quot;1963-05-02T00:00:00.000Z&quot;,
        &quot;nationality&quot;: &quot;Poland&quot;
    },
    &quot;genres&quot;: [
        {
            &quot;id&quot;: 14,
            &quot;name&quot;: &quot;driver&quot;
        },
        {
            &quot;id&quot;: 21,
            &quot;name&quot;: &quot;capacitor&quot;
        },
        {
            &quot;id&quot;: 24,
            &quot;name&quot;: &quot;sensor&quot;
        }
    ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;FK 테이블(Director, Genre)을 먼저 여러 번 생성&lt;/b&gt;해두고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Movie 생성 시점에 &lt;b&gt;랜덤 FK&lt;/b&gt;를 골라 넣어주면, DB에 &lt;b&gt;다양한 조합의 데이터&lt;/b&gt;가 쌓이게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Collection Runner로 대규모 데이터 만들기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로, Postman의 &lt;b&gt;Collection Runner&lt;/b&gt; 기능을 사용하면 수백~수천 번 반복 호출도 간단하게 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Runner 설정 방법&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. Postman에서 Collection 선택&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2. Runner 실행 후, Iterations 값을 원하는 만큼 설정 (예: 10번, 50번, 100번 등)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3. Start Run 클릭하여 대량 데이터 생성.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-21 오전 5.59.39.png&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;940&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boy6NO/btsLVdSjc8d/NxFLUYnAvVwzbVVCKd0Kjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boy6NO/btsLVdSjc8d/NxFLUYnAvVwzbVVCKd0Kjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boy6NO/btsLVdSjc8d/NxFLUYnAvVwzbVVCKd0Kjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fboy6NO%2FbtsLVdSjc8d%2FNxFLUYnAvVwzbVVCKd0Kjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;422&quot; data-filename=&quot;스크린샷 2025-01-21 오전 5.59.39.png&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;940&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;Director와 Genre API&lt;/b&gt;가 반복적으로 호출되어 &lt;b&gt;환경변수에 ID&lt;/b&gt;를 계속 쌓아두고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Movie API&lt;/b&gt; 호출 시 &lt;b&gt;FK를 랜덤으로 할당&lt;/b&gt;해, DB에 방대한 테스트 데이터를 자동으로 넣을 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 생성된 영화 데이터들을 토대로 &lt;b&gt;페이지네이션&lt;/b&gt; 기능을 테스트할 수도 있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;다양한 시나리오별로 데이터를 쉽게 구성할 수 있어서 아주 편리했다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;b&gt;Environment&lt;/b&gt;에 host부터 미리 셋팅을 해둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&lt;b&gt; 로그인 API&lt;/b&gt;로 accessToken을 받아 환경변수에 저장해두고, &lt;b&gt;Bearer Token&lt;/b&gt; 설정을 &lt;b&gt;Inherit&lt;/b&gt;해서 편리하게 인증한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;b&gt;랜덤 변수&lt;/b&gt;({{$randomFullName}}, {{$randomNoun}}, {{$randomCountry}} 등)를 이용해 다양하게 &lt;b&gt;테스트 데이터&lt;/b&gt;를 만든다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. FK가 필요한 경우, &lt;b&gt;Post-response &lt;/b&gt;&lt;b&gt;Script&lt;/b&gt;에서 응답의 id를 환경변수에 저장하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; PK 쪽(예: Movie) API에서 &lt;b&gt;Pre-request Script&lt;/b&gt;로 무작위 샘플을 뽑아 Body에 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. &lt;b&gt;Collection Runner&lt;/b&gt;를 통해 대규모 반복 호출을 수행하면서 DB에 한꺼번에 많은 데이터를 쌓는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/etc</category>
      <category>Postman</category>
      <category>관계형 데이터</category>
      <category>랜덤 데이터</category>
      <category>스크립트</category>
      <category>환경변수</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/76</guid>
      <comments>https://ilikezzi.tistory.com/76#entry76comment</comments>
      <pubDate>Tue, 21 Jan 2025 06:15:01 +0900</pubDate>
    </item>
    <item>
      <title>[Typescript] Reflect Metadata를 활용한 Custom Decorator</title>
      <link>https://ilikezzi.tistory.com/75</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-06 오후 10.30.59.png&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;692&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXQPcs/btr2sWIjDQW/sCDutKuttmTiiPfGlSj9Q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXQPcs/btr2sWIjDQW/sCDutKuttmTiiPfGlSj9Q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXQPcs/btr2sWIjDQW/sCDutKuttmTiiPfGlSj9Q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXQPcs%2Fbtr2sWIjDQW%2FsCDutKuttmTiiPfGlSj9Q1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;302&quot; data-filename=&quot;스크린샷 2023-03-06 오후 10.30.59.png&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;692&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그동안&lt;b&gt; NestJS&lt;/b&gt;로 개발을 하면서, &lt;b&gt;&lt;span&gt;class-validator&lt;/span&gt;&lt;/b&gt; 같은 라이브러리를 사용하는 건 너무나 당연한 일이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별다른 고민 없이 &lt;b&gt;데이터 유효성 검사&lt;/b&gt;를 자동으로 처리하는 데 &lt;span&gt;class-validator&lt;/span&gt;를 사용해 왔지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 내부에서 &lt;b&gt;어떻게 작동&lt;/b&gt;하는지에 대한 깊은 이해 없이 그저 편리함에 의존해왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이제는 &lt;b&gt;그 원리&lt;/b&gt;를 제대로 이해하고, 더 창의적으로 &lt;b&gt;Custom Decorator&lt;/b&gt;를 생성해서 활용해 보고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 &lt;b&gt;Reflect Metadata&lt;/b&gt;를 활용하여 &lt;b&gt;런타임에도 타입 정보를 유지하고 검증&lt;/b&gt;하는 방법과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Custom Decorator를 만드는 법을 알아보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Reflect Metadata란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TypeScript는 컴파일 시점에 타입 정보를 가지고 있지만, &lt;b&gt;컴파일 후 JavaScript로 변환되면 그 정보가 사라진다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 Reflect Metadata를 사용하면&lt;b&gt; 런타임에도 타입 정보를 유지&lt;/b&gt;하고 활용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 주로 데코레이터를 사용할 때 추가적인 메타데이터를 주고받기 위해 사용되며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스, 메서드, 파라미터 등의 메타정보를 코드에 삽입하거나 수정할 수 있게 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Reflect Metadata의 주요 요소&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reflect Metadata를 사용하기 위해서는 다음과 같은 요소들이 필요하다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;메타데이터의 키&lt;/b&gt;: 메타데이터를 식별하기 위한 고유한 키.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;메타데이터 키에 저장할 값&lt;/b&gt;: 메타데이터 키에 매핑되어 저장될 값.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;메타데이터를 저장할 객체&lt;/b&gt;: 메타데이터를 저장할 대상 객체.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;4.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;(선택 사항) 메타데이터를 저장할 객체의 프로퍼티&lt;/b&gt;: 메타데이터를 저장할 객체의 특정 프로퍼티.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Method Decorator&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729702728099&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function TestMethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. &lt;b&gt;target&lt;/b&gt;&lt;/span&gt;: 데코레이터가 적용된 메서드가 속한 클래스의 &lt;b&gt;프로토타입 또는 생성자 함수.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp; 스태틱 메서드인 경우 &lt;b&gt;생성자 함수.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-&amp;nbsp; &lt;/span&gt;인스턴스 메서드인 경우 &lt;b&gt;프로토타입.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2. &lt;b&gt;propertyKey&lt;/b&gt;&lt;/span&gt;: 데코레이터가 적용된 메서드의 이름.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;b&gt;descriptor&lt;/b&gt;&lt;span&gt;: 메서드의 속성 디스크립터로, &lt;/span&gt;{ value, writable, enumerable, configurable }&lt;span&gt; 등의 속성을 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Descriptor &lt;/b&gt;&lt;/span&gt;&lt;b&gt;attributes&lt;/b&gt;&lt;span&gt;&lt;b&gt;&lt;/b&gt;의 역할에 대해서도 간략하게 집고 넘어가자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. value&lt;span&gt;:&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 메서드 자체를 나타내는 값이다. 즉, 해당 메서드의 &lt;b&gt;실제 구현&lt;/b&gt;이 저장된 속성이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;b&gt;2.&lt;span&gt; &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;writable&lt;span&gt;:&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- &lt;/span&gt;이 속성이 &lt;span&gt;true&lt;/span&gt;일 경우, &lt;b&gt;메서드의 &lt;span&gt;value&lt;/span&gt;를 수정&lt;/b&gt;할 수 있다. &lt;span&gt;false&lt;/span&gt;일 경우 메서드를 덮어쓸 수 없게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(값 변경시 에러는 안뜨지만 절때&lt;span&gt; &lt;/span&gt;안바뀐다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;3.&lt;span&gt; &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;enumerable&lt;span&gt;:&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- &lt;/span&gt;이 속성이 &lt;span&gt;true&lt;/span&gt;일 경우, 객체의 속성을 열거할 때(예: &lt;span&gt;for...in&lt;/span&gt; 루프) 이 메서드가 포함된다.&lt;b&gt; &lt;span&gt;false&lt;/span&gt;일 경우 열거되지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(false로 설정해두고 값 변경시 값이 안보이지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;그&lt;span&gt; &lt;/span&gt;값이&lt;span&gt; &lt;/span&gt;없어진건&lt;span&gt; &lt;/span&gt;아님&lt;span&gt; &lt;/span&gt;호출하면&lt;span&gt; &lt;/span&gt;나온다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;4.&lt;span&gt; &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;configurable&lt;span&gt;:&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- &lt;/span&gt;이 속성이 &lt;span&gt;true&lt;/span&gt;일 경우, 나중에 메서드의 속성(예: &lt;span&gt;writable&lt;/span&gt; 등)을 수정하거나, 메서드 자체를 삭제할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;false&lt;/span&gt;일 경우, 속성을 &lt;b&gt;변경하거나 삭제할 수 없게 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&lt;span&gt;writable&lt;/span&gt; 속성은 &lt;b&gt;한 번만&lt;/b&gt; &lt;span&gt;true&lt;/span&gt;에서 &lt;span&gt;false&lt;/span&gt;로 변경할 수 있다. &lt;span&gt;false&lt;/span&gt;로 설정한 후에는 다시 &lt;span&gt;true&lt;/span&gt;로 되돌릴 수 없다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데코레이터와 Reflect Metadata 예제 code&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 예제 코드를 통해 &lt;b&gt;Reflect Metadata와 Custom Decorator&lt;/b&gt;를 어떻게 활용하는지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729703723152&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Idol {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  sing(style: 'hiphop' | 'rock') {
    return `${this.name}이 ${style} 노래를 부릅니다.`;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;sing&lt;/span&gt; 메서드&lt;/b&gt;는 &lt;span&gt;style&lt;/span&gt; 매개변수로 &lt;b&gt;&lt;span&gt;'hiphop'&lt;/span&gt;&lt;/b&gt; 또는 &lt;b&gt;&lt;span&gt;'rock'&lt;/span&gt;&lt;/b&gt;만을 허용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b&gt;컴파일 후 JS에서는 타입 정보가 사라지기 때문에,&lt;/b&gt; 다른 값이 들어와도 런타임에서는 오류가 발생하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 문제점이자, &lt;b&gt;Reflect Metadata&amp;nbsp;&lt;/b&gt;를 사용하는 가장 큰 이유이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 메서드 내부에서 조건문으로 검증하는 것은 번거롭고 매개변수가 많아질수록 코드가 아주 지저분해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 Reflect Metadata와 데코레이터를 사용하여 &lt;b&gt;런타임에서도 매개변수 값을 제한&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 적용한 코드를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729703972075&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install --save reflect-metadata

import 'reflect-metadata';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reflect Metadata 설치하고 import 시켜준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729704053355&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const restrictParamValueKey = Symbol('restrictParamValue');

interface RestrictionInfo&amp;lt;T&amp;gt; {
  index: number;
  restrictedValues: T[];
}

function RestrictParamValue&amp;lt;T&amp;gt;(restrictedValues: T[]) {
  return (target: any, propertyKey: string, index: number) =&amp;gt; {
    const prevMeta = Reflect.getOwnMetadata(restrictParamValueKey, target, propertyKey) ?? [];

    const info = {
      index,
      restrictedValues,
    };

    Reflect.defineMetadata(restrictParamValueKey, [...prevMeta, info], target, propertyKey);
  };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;매개변수 데코레이터 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;span&gt;&lt;b&gt;Symbol&lt;/b&gt;('restrictParamValue')&lt;/span&gt;는 &lt;b&gt;고유한 메타데이터 키&lt;/b&gt;를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 키를 통해 메타데이터에 접근할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RestrictParamValue&lt;/span&gt;는 &lt;b&gt;허용할 값들의 배열을 인자&lt;/b&gt;로 받아 매개변수 데코레이터를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 함수는 데코레이터의 표준 형태로, &lt;b&gt;&lt;span&gt;target&lt;/span&gt;, &lt;span&gt;propertyKey&lt;/span&gt;, &lt;span&gt;index&lt;/span&gt;&lt;/b&gt;를 인자로 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;target&lt;/b&gt;: 데코레이터가 적용된 메서드가 속한 객체.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- &lt;/span&gt;&lt;b&gt;&lt;span&gt;propertyKey&lt;/span&gt;&lt;/b&gt;: 메서드의 이름.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- &lt;/span&gt;&lt;b&gt;&lt;span&gt;index&lt;/span&gt;&lt;/b&gt;: 매개변수의 인덱스.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Reflect.getOwnMetadata&lt;/span&gt;를 통해 &lt;b&gt;기존에 저장된 메타데이터&lt;/b&gt;를 가져온다. &lt;b&gt;??로 없으면 빈 배열&lt;/b&gt;을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;info&lt;/span&gt; 객체에 현재 &lt;b&gt;매개변수의 인덱스와 허용할 값들을 저장&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reflect.defineMetadata&lt;span&gt;를 통해 &lt;b&gt;메타데이터를 갱신&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729704134608&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function ValidateMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const metas = Reflect.getOwnMetadata(restrictParamValueKey, target, propertyKey) ?? [];
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    for (const meta of metas) {
      const argValue = args[meta.index];
      if (!meta.restrictedValues.includes(argValue)) {
        throw new Error(`매개변수 ${meta.index}의 값 &quot;${argValue}&quot;는 허용되지 않습니다.`);
      }
    }
    return originalMethod.apply(this, args);
  };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메서드 데코레이터 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ValidateMethod&lt;/span&gt;는 메서드 데코레이터로, &lt;b&gt;메서드 실행 전에 매개변수 검증&lt;/b&gt;을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Reflect.getOwnMetadata&lt;/span&gt;를 통해 해당 메서드에&lt;b&gt; 저장된 매개변수 제한 정보&lt;/b&gt;를 가져온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;originalMethod&lt;/span&gt;에 &lt;b&gt;원래의 메서드&lt;/b&gt; 구현을 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;descriptor.value&lt;/span&gt;를 &lt;b&gt;재정의&lt;/b&gt;하여 매개변수 &lt;b&gt;검증 로직을 추가&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 매개변수에 대해 &lt;b&gt;허용된 값인지 검사&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 허용되지 않은 값이 있으면 &lt;b&gt;에러를 throw&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 검증이 &lt;b&gt;통과하면 원래의 메서드&lt;/b&gt;를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729704162154&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Idol {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  @ValidateMethod
  sing(@RestrictParamValue(['hiphop', 'rock']) style: string) {
    return `${this.name}이 ${style} 노래를 부릅니다.`;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데코레이터 적용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@RestrictParamValue(['hiphop', 'rock'])&lt;span&gt; 데코레이터로 &lt;/span&gt;sing&lt;span&gt; 메서드의 &lt;/span&gt;&lt;b&gt;style&lt;/b&gt;&lt;span&gt;&lt;b&gt; 매개변수에 허용할 값들을 지정&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;@ValidateMethod&lt;/span&gt; &lt;b&gt;데코레이터&lt;/b&gt;로 메서드 실행 전에 &lt;b&gt;매개변수 검증&lt;/b&gt;을 수행하도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729704227250&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const idol = new Idol('Newjeans', 20);

console.log(idol.sing('hiphop')); // 정상 동작
console.log(idol.sing('ballad')); // 오류 발생: 매개변수 0의 값 &quot;ballad&quot;는 허용되지 않습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;허용되지 않은 &lt;b&gt;'ballad'&lt;/b&gt;&lt;/span&gt;&lt;b&gt;를 전달&lt;/b&gt;하면, 에러가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한번 더 전체적인 흐름을 정리해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;1. 메타데이터 키 생성&lt;/b&gt;: 메타데이터를 저장하고 읽을 때 사용할 &lt;b&gt;고유한 키를 생성&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 매개변수 데코레이터&lt;/b&gt;: 매개변수에 허용할 값들을 지정하고, 해당 정보를 &lt;b&gt;메타데이터에 저장&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 메서드 데코레이터&lt;/b&gt;: 메서드 실행 전에 &lt;b&gt;메타데이터를 참고하여 매개변수를 검증&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 데코레이터 적용&lt;/b&gt;: 클래스의 메서드와 매개변수에 데코레이터를 &lt;b&gt;적용하여 검증 로직을 추가&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메서드 실행 시간을 측정하는 Custom Decorator 만들기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 전반적인 흐름에 대해 이해를 했으니 &lt;b&gt;간단한 Custom Decorator&lt;/b&gt;를 만들어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션을 개발하다 보면 &lt;b&gt;성능 최적화가 필요한 부분을 식별&lt;/b&gt;해야 할 때가 많다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;어떤 메서드가 오래&lt;/b&gt; 걸리는지, &lt;b&gt;병목 현상이 어디서 발생&lt;/b&gt;하는지 알기 위해서는 &lt;b&gt;메서드의 실행 시간을 측정&lt;/b&gt;하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 &lt;b&gt;CloudWatch&lt;/b&gt;로 메서드의 실행 시간을 비교해서 모니터링 하는것을 만들어 보기도 했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ilikezzi.tistory.com/71&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1729705844288&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[AWS] 서버 상태 실시간 모니터링: CloudWatch를 이용한 Nginx 액세스 로그 분석 및 대시보드 구축하기&quot; data-og-description=&quot;AWS에서 서비스를 운영하다 보면, 서버의 상태를 실시간으로 파악하는 것이 얼마나 중요한지 잘 알게 될 것이다. 특히 웹 서버인 NGINX에서 발생하는 액세스 로그를 분석하고 모니터링하는 것은, &quot; data-og-host=&quot;ilikezzi.tistory.com&quot; data-og-source-url=&quot;https://ilikezzi.tistory.com/71&quot; data-og-url=&quot;https://ilikezzi.tistory.com/71&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bRZDkG/hyXlNvDgka/tOYGPoGrvl5ZzwGfMluZD0/img.png?width=800&amp;amp;height=353&amp;amp;face=0_0_800_353,https://scrap.kakaocdn.net/dn/AszDq/hyXlQ0bLyM/IPHh3gPZk8YPjjUXlVWxX1/img.png?width=800&amp;amp;height=353&amp;amp;face=0_0_800_353,https://scrap.kakaocdn.net/dn/QAPfF/hyXlKlol13/Lh6ti2PvEOUxqXkeHKMWk1/img.png?width=1050&amp;amp;height=779&amp;amp;face=0_0_1050_779&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ilikezzi.tistory.com/71&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bRZDkG/hyXlNvDgka/tOYGPoGrvl5ZzwGfMluZD0/img.png?width=800&amp;amp;height=353&amp;amp;face=0_0_800_353,https://scrap.kakaocdn.net/dn/AszDq/hyXlQ0bLyM/IPHh3gPZk8YPjjUXlVWxX1/img.png?width=800&amp;amp;height=353&amp;amp;face=0_0_800_353,https://scrap.kakaocdn.net/dn/QAPfF/hyXlKlol13/Lh6ti2PvEOUxqXkeHKMWk1/img.png?width=1050&amp;amp;height=779&amp;amp;face=0_0_1050_779');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[AWS] 서버 상태 실시간 모니터링: CloudWatch를 이용한 Nginx 액세스 로그 분석 및 대시보드 구축하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;AWS에서 서비스를 운영하다 보면, 서버의 상태를 실시간으로 파악하는 것이 얼마나 중요한지 잘 알게 될 것이다. 특히 웹 서버인 NGINX에서 발생하는 액세스 로그를 분석하고 모니터링하는 것은,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 간단하게 실행 시간이 &lt;b&gt;특정 임계값(threshold)을 초과&lt;/b&gt;할 때만 &lt;b&gt;로그를 출력&lt;/b&gt;하는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;LogExecutionTime&lt;/span&gt; 데코레이터의 코드&lt;/b&gt;를 짜보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729706378368&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function LogExecutionTime(threshold: number = 0) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function (...args: any[]) {
      const start = Date.now();
      const result = originalMethod.apply(this, args);
      const finish = Date.now();
      const time = finish - start;

      if (time &amp;gt;= threshold) {
        console.log(`${propertyKey} 실행 시간: ${time}ms`);
      }

      return result;
    };
  };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데코레이터 팩토리: &lt;b&gt;&lt;span&gt;LogExecutionTime&lt;/span&gt;은 데코레이터 팩토리 함수로&lt;/b&gt;, &lt;span&gt;threshold&lt;/span&gt;라는 매개변수를 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 매개변수는 실행 시간이 이 값 이상일 때만 로그를 출력하도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데코레이터 함수 반환&lt;/b&gt;: 데코레이터 팩토리는 실제 데코레이터 함수를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 함수는 &lt;b&gt;&lt;span&gt;target&lt;/span&gt;, &lt;span&gt;propertyKey&lt;/span&gt;, &lt;span&gt;descriptor&lt;/span&gt;&lt;/b&gt;를 매개변수로 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(해당 매개변수에 대한 설명은 위에서 작성했어서 생략한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 메서드 저장: &lt;span&gt;const originalMethod = descriptor.value;&lt;/span&gt;를 통해 원래의 &lt;b&gt;메서드 구현을 저장&lt;/b&gt;해둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 이 메서드를 호출해야 하므로 따로 보관한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드 재정의: &lt;span&gt;descriptor.value&lt;/span&gt;에 새로운 함수를 할당하여 &lt;b&gt;메서드를 재정의&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 새로운 함수는 실행 시간 측정 로직을 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;실행 시간 측정: 메서드 실행전 &lt;b&gt;(start)&lt;/b&gt;, 메서드 실행 후&lt;b&gt;(finish)&lt;/b&gt;로 실행 시간을 계산한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건부 로그 출력: &lt;span&gt;if (time &amp;gt;= threshold) { ... }&lt;/span&gt;를 통해 실행 시간이 &lt;b&gt;임계값 이상인 경우에만 로그를 출력&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 반환: &lt;span&gt;return result;&lt;/span&gt;를 통해 원래&lt;b&gt; 메서드의 실행 결과를 반환&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729706795715&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Calculator {
  @LogExecutionTime(10) // 실행 시간이 10ms 이상인 경우에만 로그 출력
  fibonacci(n: number): number {
    if (n &amp;lt;= 1) return n;
    return this.fibonacci(n - 1) + this.fibonacci(n - 2);
  }
}

const calc = new Calculator();
calc.fibonacci(10);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729706828012&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fibonacci 실행 시간: 55ms&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;@LogExecutionTime(10)&lt;/span&gt;&lt;/b&gt; 데코레이터를 &lt;span&gt;fibonacci&lt;/span&gt; 메서드에 적용해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 데코레이터는 실행 시간이 &lt;b&gt;10ms 이상인 경우에만 실행 시간을 로그로 출력&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;calc.fibonacci(10);&lt;/span&gt;을 호출하면 피보나치 수를 계산하면서 실행 시간이 측정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;n&lt;/span&gt;의 값이 커질수록 재귀 호출이 많아져 실행 시간이 길어지므로, &lt;b&gt;임계값을 적절히 조정&lt;/b&gt;하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 방금 데코레이터에 기능을 좀 더 추가한 데코레이터를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729707082051&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function LogExecutionTime(threshold: number = 0) {
  let maxTime = 0;
  let maxMethod = '';

  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function (...args: any[]) {
      const start = Date.now();
      const result = originalMethod.apply(this, args);
      const finish = Date.now();
      const time = finish - start;

      if (time &amp;gt;= threshold) {
        console.log(`${propertyKey} 실행 시간: ${time}ms`);
      }

      if (time &amp;gt; maxTime) {
        maxTime = time;
        maxMethod = propertyKey;
      }

      return result;
    };

    // 클래스가 로드될 때 실행되는 코드
    process.on('exit', () =&amp;gt; {
      console.log(`가장 오래 걸린 메서드: ${maxMethod} (${maxTime}ms)`);
    });
  };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 &lt;span&gt;LogExecutionTime&lt;/span&gt; 데코레이터를 정의하여 메서드의 실행 시간을 측정하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임계값을 초과하면 로그를 출력하며, &lt;b&gt;가장 오래 걸린 메서드를 추적&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(전반적인 프로세스는 다 똑같아서 설명은 생략하겠다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마치며&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;첫번째 예시&lt;/b&gt;를 잘 이해했다면 따라오기 쉬웠을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 데코레이터를 사용하면 &lt;b&gt;중복 코드 제거, 관심사의 분리, 깔끔한 코드&lt;/b&gt; 등 장점이 있으나, 물론 단점도 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;디버깅 어려움&lt;/b&gt;: 데코레이터를 통해 메서드가 &lt;b&gt;재정의&lt;/b&gt;되므로 디버깅 시 &lt;b&gt;호출 스택이 복잡해&lt;/b&gt;질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;성능 영향&lt;/b&gt;: 데코레이터 자체가 추가 연산을 수행하므로 &lt;b&gt;성능에 민감한 부분에서는 주의&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가독성 저하&lt;/b&gt;: 데코레이터가 너무 많으면 코드가 복잡해져 &lt;b&gt;가독성이 떨어질 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 &lt;b&gt;Reflect Metadata&lt;/b&gt;와 &lt;b&gt;Custom Decorator&lt;/b&gt;를 활용하여 런타임에서도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 정보를 유지하고 검증하는 방법을 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 &lt;b&gt;NestJS&lt;/b&gt;와 같은 프레임워크에서 이미 편리하게 사용하고 있던 &lt;b&gt;class-validator&lt;/b&gt; 등의 라이브러리가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부적으로 어떻게 동작하는지 이해하게 되면서, 그 원리를 직접 적용해 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Reflect Metadata&lt;/b&gt;를 사용하면 &lt;b&gt;런타임에도 타입 정보&lt;/b&gt;를 유지하며, 메서드와 매개변수에 대한 &lt;b&gt;검증을 더욱 쉽게&lt;/b&gt; 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 메서드의 실행 시간을 측정하거나, 메서드의 동작을 제한하는 등 다양한 커스텀 데코레이터를 통해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드의 중복&lt;/b&gt;을 줄이고 &lt;b&gt;가독성&lt;/b&gt;을 높일 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, 데코레이터의 남용은 코드의 복잡성을 높이고 디버깅을 어렵게 할 수 있기 때문에 &lt;b&gt;적절히&lt;/b&gt; 사용하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로도&lt;b&gt; TypeScript&lt;/b&gt;의 강력한 기능들을 깊이 있게 이해하고 활용하여 더욱 효율적이고 안정적인 코드를 작성하도록 해야겠다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조 :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/reflect-metadata&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.npmjs.com/package/reflect-metadata&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.typescriptlang.org/ko/docs/handbook/decorators.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.typescriptlang.org/ko/docs/handbook/decorators.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://toss.tech/article/nestjs-custom-decorator&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://toss.tech/article/nestjs-custom-decorator&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EC%BD%94%EB%93%9C%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%92%80%EC%BD%94%EC%8A%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.inflearn.com/course/%EC%BD%94%EB%93%9C%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%92%80%EC%BD%94%EC%8A%A4&lt;/a&gt;&lt;/p&gt;</description>
      <category>Programming Language/Typescript</category>
      <category>custom decorator</category>
      <category>nestJS</category>
      <category>reflect metadata</category>
      <category>TypeScript</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/75</guid>
      <comments>https://ilikezzi.tistory.com/75#entry75comment</comments>
      <pubDate>Thu, 24 Oct 2024 03:28:08 +0900</pubDate>
    </item>
    <item>
      <title>[책 리뷰] 객체지향의 사실과 오해</title>
      <link>https://ilikezzi.tistory.com/74</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼마 전, 약 2년간 다녔던 회사를 퇴사했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;퇴사 후 한두 달 정도는 아예 코드를 쳐다보지 않고 푹 쉬었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이직을 바로 할까 고민하다가, 실업급여를 받을 수 있는 기회도 생겨서 이번 기회에 부족한 부분을 채우기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무작정 코드를 작성하기보다는, &lt;b&gt;내 코드의 구조를 고민&lt;/b&gt;하다가 &lt;b&gt;객체지향&lt;/b&gt;에 대해 좀 더 깊이 있게 알고, 코드에 적용해보고 싶어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러던 중 &lt;b&gt;조영호 저자&lt;/b&gt;의&amp;nbsp;&lt;b&gt;&quot;객체지향의 사실과 오해&quot; &lt;/b&gt;와&lt;b&gt; &quot;오브젝트&quot; &lt;/b&gt;라는 책을 알게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾아보니 둘다 객체지향 관련 책이지만&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;오브젝트&quot;&lt;/b&gt;는 실질적인 구현에 관한 코드 위주의 책이고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;객체지향의 사실과 오해&quot;&lt;/b&gt;는 제목 그대로 객체지향의 개념과, 사람들이 오해하는 포인트를 잡아서 설명하는 설명해주는 책이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 CS지식이 탄탄하지 않아서 평소 코딩을 할 때에도 &lt;b&gt;&quot;왜??&quot; &lt;/b&gt;라는 의문을 품었던 적이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 나는 좀 더 개념을 다루는 &lt;b&gt;&quot;객체지향의 사실과 오해&quot;&lt;/b&gt;를 선택하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0762.JPG&quot; data-origin-width=&quot;2095&quot; data-origin-height=&quot;2095&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU5Kjh/btsJejJESvv/oWkkUAEo0t2q0yfVdRlnEK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU5Kjh/btsJejJESvv/oWkkUAEo0t2q0yfVdRlnEK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU5Kjh/btsJejJESvv/oWkkUAEo0t2q0yfVdRlnEK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU5Kjh%2FbtsJejJESvv%2FoWkkUAEo0t2q0yfVdRlnEK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;600&quot; data-filename=&quot;IMG_0762.JPG&quot; data-origin-width=&quot;2095&quot; data-origin-height=&quot;2095&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체지향 프로그래밍이란?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&amp;ldquo;커피 주문&amp;rdquo;&lt;/b&gt;이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&amp;ldquo;이상한 나라의 앨리스&amp;rdquo;&lt;/b&gt;와 같은 비유를 들어 객체지향 개념을 설명하고 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;복잡하다고 느꼈던 개념들이 비유를 통해 훨씬 쉽게 다가왔다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;시너지를 생각하라. 전체는 부분의 합보다 크다. - 스티븐 코비&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 프로그래밍은 현실 세계에 존재하는 사물을 최대한 유사하게 소프트웨어 내부로 옮겨오는 작업이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 과정은 &lt;b&gt;단순히 현실 세계를 모방하는 것이 아니다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 작업은 신세계를 &lt;b&gt;창조&lt;/b&gt;하는 것에 가깝다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 패러다임의 목적은 &lt;b&gt;현실 세계를 기반으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;새로운 세계를 창조&lt;/span&gt;&lt;/b&gt;하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0768.JPG&quot; data-origin-width=&quot;2266&quot; data-origin-height=&quot;1114&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cttHMu/btsJgeG3eiy/u1d1IAefc6VpFYRDcY46g1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cttHMu/btsJgeG3eiy/u1d1IAefc6VpFYRDcY46g1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cttHMu/btsJgeG3eiy/u1d1IAefc6VpFYRDcY46g1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcttHMu%2FbtsJgeG3eiy%2Fu1d1IAefc6VpFYRDcY46g1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;295&quot; data-filename=&quot;IMG_0768.JPG&quot; data-origin-width=&quot;2266&quot; data-origin-height=&quot;1114&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책에서는 &lt;b&gt;&amp;ldquo;커피 주문&amp;rdquo;&lt;/b&gt;을 예시로 들어 설명하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;손님, 캐시어, 바리스타는 각각의 &lt;b&gt;역할&lt;/b&gt;과 &lt;b&gt;책임&lt;/b&gt;을 갖고 있으며, 이들은 &lt;b&gt;협력&lt;/b&gt;을 통해 문제를 해결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 객체도 &lt;b&gt;단독으로 존재하지 않으며, 항상 협력&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;객체는 다른 객체가 무엇(what)을 수행하는지 알 수 있지만 어떻게(how) 수행하는지에 대해서는 알 수 없다&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;클래스가 아닌 객체 중심의 사고&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향의 중심은 클래스가 아니라 &lt;b&gt;객체&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메시지&lt;/b&gt;를 주고받는 &lt;b&gt;객체의 관점&lt;/b&gt;에서 사고의 중심을 전환해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스는 객체들의 협력 관계를 코드로 옮기는 &lt;b&gt;도구에 불과&lt;/b&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 세계와 현실 세계의 가장 &lt;b&gt;큰 차이점&lt;/b&gt;은 소프트웨어 세계의 객체들이 모두 &lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;ldquo;&lt;b&gt;스스로&lt;/b&gt;&amp;rdquo;&lt;/span&gt; 행동한다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 전등이 외부의 도움 없이 스스로 켜지고, 자동차가 스스로 시동을 거는 것처럼 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향의 세계에서 모든 객체는 자신의 상태를 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;스스로&lt;/b&gt;&lt;/span&gt; 관리하는 &lt;b&gt;자율적인 존재&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체의 상태와 행동&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;상태&lt;/b&gt;를 통해 과거의 행동을 기억하며, 상태 변경에 따라 유일하게 식별될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태가 중요한 이유는 &lt;b&gt;과거의 행동&lt;/b&gt;이 현재의 행동에 영향을 미치기 때문이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 객체지향에서 더 중요한 것은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;행동&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;행동&lt;/b&gt;이 상태를 결정하고, 객체를 결정하는 것도 &lt;b&gt;행동&lt;/b&gt;이다. 중요한 것은 상태가 아닌 &lt;b&gt;행동&lt;/b&gt;에 초점을 맞추는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 입문자들이 자주 하는 실수는 &lt;b&gt;상태&lt;/b&gt;를 중심으로 객체를 바라보는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;상태를 먼저&lt;/b&gt; 결정하고 &lt;b&gt;행동을 나중에&lt;/b&gt; 결정하면, 설계에 &lt;b&gt;부정적인&lt;/b&gt; 영향을 미칠 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구체적으로, 이런 접근 방식은 &lt;b&gt;캡슐화를 저해&lt;/b&gt;하고, 객체를 &lt;b&gt;고립된 섬&lt;/b&gt;처럼 만들며, 결과적으로 객체의 &lt;b&gt;재사용성을 떨어뜨린다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0765.JPG&quot; data-origin-width=&quot;3377&quot; data-origin-height=&quot;1900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/er8Jie/btsJgACXjtB/kVuIpiHVGYHVBWjx8aXNMK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/er8Jie/btsJgACXjtB/kVuIpiHVGYHVBWjx8aXNMK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/er8Jie/btsJgACXjtB/kVuIpiHVGYHVBWjx8aXNMK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fer8Jie%2FbtsJgACXjtB%2FkVuIpiHVGYHVBWjx8aXNMK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;338&quot; data-filename=&quot;IMG_0765.JPG&quot; data-origin-width=&quot;3377&quot; data-origin-height=&quot;1900&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽과 오른쪽에 차이점은 지도가 당연히 가져야한다고 생각되는 &lt;b&gt;&quot;정확성&quot;&lt;/b&gt;을 버리고 그&lt;b&gt; &quot;목적&quot;&lt;/b&gt;에 집중했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;상태가 아닌&lt;/span&gt; &lt;b&gt;행동에 초점&lt;/b&gt;&lt;/span&gt;을 둔 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로 객체의 타입을 결정하는것은 객체의 행동뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동일한 행동 === 동일한 책임 === 동일한 메시지 수신&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0767.JPG&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;1814&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/busXL8/btsJgK6p5IA/0fAYHD32r6YClsPpjcKzKK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/busXL8/btsJgK6p5IA/0fAYHD32r6YClsPpjcKzKK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/busXL8/btsJgK6p5IA/0fAYHD32r6YClsPpjcKzKK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbusXL8%2FbtsJgK6p5IA%2F0fAYHD32r6YClsPpjcKzKK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;423&quot; data-filename=&quot;IMG_0767.JPG&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;1814&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일반화/특수화 = 슈퍼 타입/서브 타입&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 개념 역시 &lt;b&gt;행동&lt;/b&gt;과 관련이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;슈퍼 타입과 서브 타입&lt;/b&gt;을 구분하는 기준은 다른 타입보다 더 &lt;b&gt;특수하게 행동&lt;/b&gt;하는지, 아니면 더 &lt;b&gt;일반적으로 행동&lt;/b&gt;하는지에 따라 결정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;다형성과 책임&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다형성이란 &lt;b&gt;서로 다른 유형의 객체&lt;/b&gt;가 &lt;b&gt;동일한 메시지에 대해 다르게 반응&lt;/b&gt;하는 것을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 다형성은 코드의 &lt;b&gt;유연성&lt;/b&gt;을 극대화하며, 객체지향 설계에서 역할과 책임의 명확한 분리를 가능하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드의 재사용성을 높이고, 새로운 객체를 추가할 때 기존 코드를 수정할 필요 없이 &lt;b&gt;확장&lt;/b&gt;할 수 있게 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 다형성은 객체들이 동일한 &lt;b&gt;인터페이스&lt;/b&gt;를 통해 다양한 방식으로 행동할 수 있도록 하여,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설계를 더욱 &lt;b&gt;유연하고 강력하게 만든다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체의 책임과 메시지&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체의 책임&lt;/b&gt;은 외부에 제공할 수 있는 정보와 서비스의 목록을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 객체의 인터페이스를 구성하며, 객체의 역할을 대체할 수 있는 다른 객체는 동일한 메시지를 이해할 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테스트 주도 개발(TDD)&lt;/b&gt;의 목표는 역할, 책임, 협력을 명확히 식별하고, 이를 코드로 구현한 후 피드백을 받는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테스트&lt;/b&gt;는 단지 TDD를 통해 얻을 수 있는 별도의 보너스 같은것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 객체가 자율적이기 위해서는 객체에게 부여되는 책임의 수준 또한 자율적이어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;&lt;b&gt;메시지는 어떻게(how)가 아니라 무엇(what)을 해야 하는지를 요청하는 것이다.&lt;/b&gt;&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지 중심의 설계에서 중요한 것은 메시지가 객체에 &lt;b&gt;무엇&lt;/b&gt;을 요청하는가이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설계의 품질을 높이기 위해서는 훌륭한 메시지를 선택해야 하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향의 강력함은 &lt;b&gt;클래스가 아니라 객체들이 주고받는 메시지&lt;/b&gt;에서 비롯된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;메시지 중심의 설계&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 설계의 핵심은 &lt;b&gt;객체 자체가 아닌 객체들이 주고받는 메시지&lt;/b&gt;에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지는 객체가 &lt;b&gt;무엇&lt;/b&gt;을 해야 하는지를 요청하며, 이는 객체의 &lt;b&gt;공용 인터페이스&lt;/b&gt;를 통해 외부로 노출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;책임 주도 설계(Responsibility-Driven Design)&lt;/b&gt; 방식에서는 &lt;b&gt;What/Who&lt;/b&gt; 사이클을 따른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;b&gt;어떤 행위(What)&lt;/b&gt;를 수행할지를 결정한 후, &lt;b&gt;누가(Who)&lt;/b&gt; 그 행위를 수행할지를 결정하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 어떤 행위가 바로 메시지에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 책임 주도 설계는 객체가 아닌 객체들이 주고받는 메시지에 초점을 맞추어, 객체지향의 장점을 극대화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지는 &lt;b&gt;어떻게&lt;/b&gt;가 아닌 &lt;b&gt;무엇&lt;/b&gt;을 해야 하는지를 요청하는 방식으로 설계를 단순화하고, 객체의 인터페이스 크기를 줄인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 &lt;b&gt;공용 인터페이스&lt;/b&gt;는 &lt;b&gt;외부에서 전송 가능한 메시지의 집합&lt;/b&gt;으로 정의되며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 객체가 외부와 어떻게 상호작용하는지를 명확하게 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 프로그래밍은 객체들의 &lt;b&gt;협력과 메시지&lt;/b&gt;에 초점을 맞춘다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;행동&lt;/b&gt;이 상태를 결정하며, 객체는 자율적인 존재로서 자신의 상태를 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설계의 중심은 객체가 아니라 객체들이 주고받는&lt;b&gt; 메시지&lt;/b&gt;에 있으며, 이를 통해 유연하고 확장 가능한 소프트웨어를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;역할, 책임, 협력&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등 객체지향의 핵심 개념들을 이해하고 적용함으로써, 더 유연하고 확장 가능한 설계를 할 수 있을 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책을 다 읽고 나니, 객체지향이 무엇인지에 대한 개념이 대략적으로 잡히는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향이라는 주제를 깊이 있게 다루면서도 &lt;b&gt;실생활의 예시&lt;/b&gt;를 통해 쉽게 이해할 수 있게 해준 덕분에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡하게만 느껴졌던 개념들이 점점 명확해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히, 객체지향의 본질과 설계 원칙에 대해 고민하게 되어, 앞으로의 코드 작성에 큰 도움이 될 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책에는 &quot;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;비개발자가 책을 읽더라도 이해하는 데는 큰 무리가 없을 정도로 일반적이고 평이한 난이도를 유지하기 위해 노력했습니다.&lt;/span&gt;&quot;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;라고 써 있지만 나는 아예 객체지향에 낯선 사람보다 객체지향 코드를 적어도 &lt;b&gt;1년&lt;/b&gt; 정도 다뤄본 사람에게 더 적합해 보인다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;객체지향의 구조를 고민해본 사람이라면 꼭 읽어보길 권한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0552.jpg&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;335&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/laM4G/btsJguvIYZ2/gaW0kNstkK7eo5QpjQKlkK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/laM4G/btsJguvIYZ2/gaW0kNstkK7eo5QpjQKlkK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/laM4G/btsJguvIYZ2/gaW0kNstkK7eo5QpjQKlkK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlaM4G%2FbtsJguvIYZ2%2FgaW0kNstkK7eo5QpjQKlkK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;172&quot; data-filename=&quot;IMG_0552.jpg&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;335&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a title=&quot;LinkedIn 조영호님&quot; href=&quot;https://www.linkedin.com/in/%EC%98%81%ED%98%B8-%EC%A1%B0-a4a363238/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LinkedIn 조영호님&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 어쩌다보니 이 책의 저자인 조영호님께 피드백을 받았다...!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Book</category>
      <category>객체지향의 사실과 오해</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/74</guid>
      <comments>https://ilikezzi.tistory.com/74#entry74comment</comments>
      <pubDate>Mon, 26 Aug 2024 15:30:41 +0900</pubDate>
    </item>
    <item>
      <title>[TypeORM] 밤 12시, 수만 명의 출석체크에 대응한 동시성 문제 해결기</title>
      <link>https://ilikezzi.tistory.com/73</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_7244.jpg&quot; data-origin-width=&quot;1169&quot; data-origin-height=&quot;943&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vqVx7/btsFVtA6ULd/kdiZ8kIqKNK5GxukYJ3wFK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vqVx7/btsFVtA6ULd/kdiZ8kIqKNK5GxukYJ3wFK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vqVx7/btsFVtA6ULd/kdiZ8kIqKNK5GxukYJ3wFK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvqVx7%2FbtsFVtA6ULd%2FkdiZ8kIqKNK5GxukYJ3wFK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;242&quot; data-filename=&quot;IMG_7244.jpg&quot; data-origin-width=&quot;1169&quot; data-origin-height=&quot;943&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영중인 앱에서 &lt;b&gt;출석체크 이벤트&lt;/b&gt;를 도입하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출석체크&amp;nbsp;이벤트는&amp;nbsp;사용자들에게&amp;nbsp;&lt;b&gt;매일&amp;nbsp;자정&lt;/b&gt;에&amp;nbsp;접속하여&amp;nbsp;&lt;b&gt;출석체크&lt;/b&gt;를&amp;nbsp;하면&amp;nbsp;&lt;b&gt;보상을 제공&lt;/b&gt;하는 간단한 메커니즘이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예상했던 것 이상으로 &lt;b&gt;수만 명의 사용자&lt;/b&gt;들로부터 &lt;b&gt;동시&lt;/b&gt;에 들어오는 출석체크 요청의 폭풍에 직면했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;동시성 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수만 명의 사용자&lt;/b&gt;들로부터 동시에 들어오는 요청을 처리하는 것은 결코 간단한 일이 아니었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버의&amp;nbsp;자원은&amp;nbsp;한정되어&amp;nbsp;있고,&amp;nbsp;&lt;b&gt;동시에&amp;nbsp;너무&amp;nbsp;많은&amp;nbsp;요청&lt;/b&gt;이&amp;nbsp;처리될&amp;nbsp;경우&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터베이스&lt;/b&gt;&amp;nbsp;&lt;b&gt;충돌,&lt;/b&gt; 성능 저하, 심지어는 서비스 다운에 이르기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 단순히 기술적인 도전을 넘어, 우리 서비스의 &lt;b&gt;안정성&lt;/b&gt;과 사용자의 &lt;b&gt;신뢰성&lt;/b&gt;에 대한 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;818&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/72Cnx/btsFVSN9SzS/HTnn0i3XPGjd1l9cmPlqAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/72Cnx/btsFVSN9SzS/HTnn0i3XPGjd1l9cmPlqAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/72Cnx/btsFVSN9SzS/HTnn0i3XPGjd1l9cmPlqAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F72Cnx%2FbtsFVSN9SzS%2FHTnn0i3XPGjd1l9cmPlqAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;340&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;818&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CloudWatch&lt;/b&gt;를 확인해보면 출석체크가 시작되는 &lt;b&gt;밤 12시&lt;/b&gt; (UTC 15:00)에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;API 요청&lt;/b&gt;이 &lt;b&gt;수만 건&lt;/b&gt;으로 확 치솟는 게 보일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동시성 문제&lt;/b&gt;를 해결하기 위해선 먼저 &lt;b&gt;문제의 본질&lt;/b&gt;을 이해해야 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시에&amp;nbsp;들어오는&amp;nbsp;수많은&amp;nbsp;요청이&amp;nbsp;데이터베이스에&amp;nbsp;&lt;b&gt;동일한&amp;nbsp;쓰기&amp;nbsp;작업&lt;/b&gt;을&amp;nbsp;요구할&amp;nbsp;때,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 데이터의 &lt;b&gt;무결성을 해치고&lt;/b&gt;, &lt;b&gt;충돌이나 데이터 손실&lt;/b&gt;로 이어질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출석체크 이벤트에 동시에 참여하려는 수만 명의 사용자들이 이 문제를 발생시키기엔 충분했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 우리 시스템이 &lt;b&gt;서버가 4대로 분리&lt;/b&gt;되어 있다는 특성도 큰 영향을 미쳤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버&amp;nbsp;4대가&amp;nbsp;분리되어&amp;nbsp;있다는&amp;nbsp;것은,&amp;nbsp;각&amp;nbsp;서버가&amp;nbsp;동시에&amp;nbsp;독립적으로&amp;nbsp;&lt;b&gt;같은&amp;nbsp;데이터에&amp;nbsp;접근&lt;/b&gt;하려&amp;nbsp;할&amp;nbsp;때&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 일관성&lt;/b&gt;을 유지하는 것이 더욱 어렵다는 것을 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는&amp;nbsp;각&amp;nbsp;서버&amp;nbsp;간에&amp;nbsp;상태를&amp;nbsp;동기화하는&amp;nbsp;복잡성을&amp;nbsp;증가시키며,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 한 대의 서버에서만 동시성을 관리하는 것보다 훨씬 더 많은 고려 사항을 필요로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 문제점들을 어떻게 해결했는지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Pessimistic&amp;nbsp;Locking&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시성 문제에 대응하기 위해 먼저 &lt;b&gt;TypeORM&lt;/b&gt;의 &lt;b&gt;Pessimistic Locking(비관적 잠금 기능)&lt;/b&gt;을 활용하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Pessimistic Locking&lt;/b&gt;은 특정 데이터에 대한 변경이나 조회를 시도할 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 데이터를 잠가 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;다른 &lt;/b&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;트&lt;/span&gt;랜잭션의 접근을 차단&lt;/b&gt;&lt;/span&gt;하는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &lt;b&gt;데이터의 일관성을 유지&lt;/b&gt;하고, 동시성 문제에서 발생할 수 있는 &lt;b&gt;데이터 무결성 위반을 방지&lt;/b&gt;하는 데 큰 도움이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 두 사용자가 동시에 같은 계정의 잔액을 수정한다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Pessimistic Lock&lt;/b&gt;을 사용하면, 첫 번째 사용자가 해당 데이터에 접근하여 잠금을 걸면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 사용자는 &lt;b&gt;첫 번째 사용자의 작업이 완료되고 잠금이 해제될 때&lt;/b&gt;까지 기다려야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 데이터의 동시 수정으로 인한 충돌이나 불일치를 방지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b22Y5X/btsFW9VU7Wr/uKwOuGkqwlgUvxNAAyzz1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b22Y5X/btsFW9VU7Wr/uKwOuGkqwlgUvxNAAyzz1k/img.png&quot; data-alt=&quot;Pessimistic Lock&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b22Y5X/btsFW9VU7Wr/uKwOuGkqwlgUvxNAAyzz1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb22Y5X%2FbtsFW9VU7Wr%2FuKwOuGkqwlgUvxNAAyzz1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;228&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;402&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Pessimistic Lock&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 &lt;b&gt;TypeORM&lt;/b&gt;에서 &lt;b&gt;Pessimistic Lock&lt;/b&gt;을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 &lt;b&gt;Optimistic Locking&lt;/b&gt;(낙관적 잠금 기능)도 존재 하지만 &lt;b&gt;Pessimistic Lock&lt;/b&gt;을&amp;nbsp;선택한&amp;nbsp;이유는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포인트&amp;nbsp;지급과&amp;nbsp;같은&amp;nbsp;중요한&amp;nbsp;작업의&amp;nbsp;&lt;b&gt;데이터&amp;nbsp;일관성과&amp;nbsp;무결성을&amp;nbsp;최우선&lt;/b&gt;으로 고려했기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Optimistic Locking&lt;/b&gt;으로는 충돌 해결 과정에서 발생할 수 있는 데이터 일관성 문제를 효과적으로 관리하기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Unique&amp;nbsp;제약&amp;nbsp;조건&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유니크 키는 특정 컬럼(또는 컬럼들의 조합)에 대해 각 행의 값이 전체 테이블에서&lt;b&gt; 유일함을 보장하는 제약 조건&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 사용자의 출석체크 데이터에서 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;같은 사용자가 같은 이벤트에 두 번 이상 참여하는 것을 방지&lt;/span&gt;&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 우발적인 중복 요청이나 네트워크 지연으로 인한 재시도 요청으로부터도 데이터의 무결성을 보호하는 역할을 했다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1710893008062&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ALTER TABLE user_attend_check
ADD UNIQUE UNIQ_user_attend_check_user (user_id, event_id, check_date);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 MySQL DB에 Unique 제약 조건을 걸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결 완료&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Pessimistic Lock&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Unique 제약 조건&lt;/b&gt;을 활용한 접근 방식은 우리 서비스의 동시성 문제를 해결하는 데 큰 도움이 되었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;특히,&amp;nbsp;&lt;b&gt;서버&amp;nbsp;4대&lt;/b&gt;에서&amp;nbsp;동시에&amp;nbsp;처리되는&amp;nbsp;요청들&amp;nbsp;사이에서&amp;nbsp;&lt;b&gt;데이터의&amp;nbsp;일관성과&amp;nbsp;정확성&lt;/b&gt;을 유지할 수 있게 되었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이로 인해 사용자 경험이 크게 개선되었고, 시스템의 안정성도 높아졌다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든 과정을 통해, 나는 단순히 동시성 문제를 해결하는 것을 넘어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;분산 시스템 환경&lt;/b&gt;에서도 데이터의 일관성과 무결성을 유지할 수 있는 방법을 찾아냈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로도 이러한 경험을 바탕으로 더 나은 서비스와 유저 경험을 제공하도록 노력해야겠다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/TypeOrm</category>
      <category>Pessimistic Lock</category>
      <category>TypeORM</category>
      <category>unique</category>
      <category>동시성문제</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/73</guid>
      <comments>https://ilikezzi.tistory.com/73#entry73comment</comments>
      <pubDate>Wed, 20 Mar 2024 09:19:39 +0900</pubDate>
    </item>
    <item>
      <title>[해커톤] 연대 X 숙대 ABC LIVING LAB 해커톤 멘토 참여 후기</title>
      <link>https://ilikezzi.tistory.com/72</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1300&quot; data-origin-height=&quot;1810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJ006M/btsFJJXFcbS/OgJepilz20jWDT1pTNHOG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJ006M/btsFJJXFcbS/OgJepilz20jWDT1pTNHOG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJ006M/btsFJJXFcbS/OgJepilz20jWDT1pTNHOG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJ006M%2FbtsFJJXFcbS%2FOgJepilz20jWDT1pTNHOG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;557&quot; data-origin-width=&quot;1300&quot; data-origin-height=&quot;1810&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간만에 &lt;b&gt;해커톤 멘토링&lt;/b&gt;을 다녀오게 되어서 포스팅을 해보려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;24.03.09 - 24.03.10 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;연대 X 숙대 ABC LIVING LAB &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;HACKATHON&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-03-12 오전 6.11.41.png&quot; data-origin-width=&quot;2632&quot; data-origin-height=&quot;1474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p7MJV/btsFGlRKkbK/isdhMk9FJ3FEHKZwkYvMa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p7MJV/btsFGlRKkbK/isdhMk9FJ3FEHKZwkYvMa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p7MJV/btsFGlRKkbK/isdhMk9FJ3FEHKZwkYvMa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp7MJV%2FbtsFGlRKkbK%2FisdhMk9FJ3FEHKZwkYvMa1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;280&quot; data-filename=&quot;스크린샷 2024-03-12 오전 6.11.41.png&quot; data-origin-width=&quot;2632&quot; data-origin-height=&quot;1474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-03-12 오전 6.11.21.png&quot; data-origin-width=&quot;2642&quot; data-origin-height=&quot;1490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B57FN/btsFFX4D2iK/PWmp4KZiyeiyTk9vSXoew0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B57FN/btsFFX4D2iK/PWmp4KZiyeiyTk9vSXoew0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B57FN/btsFFX4D2iK/PWmp4KZiyeiyTk9vSXoew0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB57FN%2FbtsFFX4D2iK%2FPWmp4KZiyeiyTk9vSXoew0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;282&quot; data-filename=&quot;스크린샷 2024-03-12 오전 6.11.21.png&quot; data-origin-width=&quot;2642&quot; data-origin-height=&quot;1490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 해커톤은 &lt;b&gt;리빙랩 해커톤&lt;/b&gt;이라서 메인 주제는 &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&lt;b&gt;AI/Cloud/Bigdata를 이용해 지역사회의 문제를 해결하는 서비스&lt;/b&gt;를 개발해보는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;참여한 학생들은&amp;nbsp;&lt;b&gt;AWS Cloud과정&lt;/b&gt;을 사전 교육으로 받았으며,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;특히 이전 해커톤과 다르게 &lt;b&gt;AWS Bedrock&lt;/b&gt; 이라는 서비스 활용을 권장했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;나도 이번 기회에 처음 접해보게 되었다..&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;간략하게 &lt;b&gt;AWS Bedrock&lt;/b&gt; 이란 ?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;다양한 고성능 파운데이션 모델을 단일 API를 통해 제공하는 &lt;b&gt;완전관리형 서비스&lt;/b&gt;이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;이 서비스를 활용하면, 사용자들은&amp;nbsp;&lt;b&gt;AI&amp;nbsp;기반의&amp;nbsp;생성형&amp;nbsp;AI&amp;nbsp;애플리케이션&lt;/b&gt;을&amp;nbsp;쉽게&amp;nbsp;&lt;b&gt;개발&lt;/b&gt;하고&amp;nbsp;&lt;b&gt;확장&lt;/b&gt;할&amp;nbsp;수&amp;nbsp;있으며,&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 서비스를 통해 생성형 AI 기능을 &lt;b&gt;인프라 관리 없이&lt;/b&gt; 애플리케이션에 통합하고 배포할 수 있는 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_7001.JPG&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XgEfn/btsFI5UqK2A/lLIsJRJEN3eWNjGTXZhoOk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XgEfn/btsFI5UqK2A/lLIsJRJEN3eWNjGTXZhoOk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XgEfn/btsFI5UqK2A/lLIsJRJEN3eWNjGTXZhoOk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXgEfn%2FbtsFI5UqK2A%2FlLIsJRJEN3eWNjGTXZhoOk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;711&quot; data-filename=&quot;IMG_7001.JPG&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_7021.JPG&quot; data-origin-width=&quot;2056&quot; data-origin-height=&quot;3656&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsFfrP/btsFGjM8tS5/pVfK6wurJh5HKxwzf37EA0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsFfrP/btsFGjM8tS5/pVfK6wurJh5HKxwzf37EA0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsFfrP/btsFGjM8tS5/pVfK6wurJh5HKxwzf37EA0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsFfrP%2FbtsFGjM8tS5%2FpVfK6wurJh5HKxwzf37EA0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;711&quot; data-filename=&quot;IMG_7021.JPG&quot; data-origin-width=&quot;2056&quot; data-origin-height=&quot;3656&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 해커톤은 &lt;b&gt;AWS 본사&lt;/b&gt;에서 진행되었으며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 3시쯤 도착했는데 &lt;b&gt;아이디어 브레인스토밍&lt;/b&gt;로 다들 머리를 싸매고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 시간이 해커톤에서 가장 중요한 순간 중 하나다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리빙랩&lt;/b&gt;이라는 주제에 부합하면서, &lt;b&gt;생성형 AI &lt;/b&gt;및 &lt;b&gt;Elastic Search&lt;/b&gt;도 접목하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제한된 시간&lt;/b&gt;안에 현실적으로 구현이 가능한 아이디어를 정하는것은 정말이지 어려운 일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해커톤 현장을 돌아다니며 다양한 팀들의 &lt;b&gt;아이디어 스피치&lt;/b&gt;하는 시간을 가졌다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각&amp;nbsp;팀의&amp;nbsp;프로젝트에&amp;nbsp;대한&amp;nbsp;소소한&amp;nbsp;피드백을&amp;nbsp;나누는&amp;nbsp;것은&amp;nbsp;생각보다&amp;nbsp;더&amp;nbsp;의미&amp;nbsp;있는&amp;nbsp;경험이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;이미 존재하는 서비스와의 작은 차별점을 찾아보는 것도 하나의 방법이 될 수 있어요&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;ChatGPT를 활용하는 건 좋지만, 가끔 데이터를 잘못 인식할 수도 있으니 이에 대비한 대책이 필요할 것 같다&quot;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;사용자 범위를 명확히 하여, 타겟 이용자의 필요와 문제점을 이해하고, 그들의 관점에서 실질적인 가치를 제공하는 것이 중요해요.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등등..&lt;b&gt; 다양한 피드백&lt;/b&gt;을 제시해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서, 조금이나마 방향을 잡아준것 같아서 만족스러웠다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2660&quot; data-origin-height=&quot;2660&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w1gXg/btsFJBZyYNZ/Yz2XdwKaU1Oa7RlLfksBv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w1gXg/btsFJBZyYNZ/Yz2XdwKaU1Oa7RlLfksBv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w1gXg/btsFJBZyYNZ/Yz2XdwKaU1Oa7RlLfksBv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw1gXg%2FbtsFJBZyYNZ%2FYz2XdwKaU1Oa7RlLfksBv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;500&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2660&quot; data-origin-height=&quot;2660&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OXlTN/btsFJmaunLr/2e9aG4oSpGuk0xYk4FFyt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OXlTN/btsFJmaunLr/2e9aG4oSpGuk0xYk4FFyt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OXlTN/btsFJmaunLr/2e9aG4oSpGuk0xYk4FFyt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOXlTN%2FbtsFJmaunLr%2F2e9aG4oSpGuk0xYk4FFyt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;500&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깨알 내사진...&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔가 열심히 알려주고 있는거 같은데 기억이 안난다 ㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;무박 2일&lt;/b&gt;로 하는 해커톤이다 보니깐 새벽엔 눈이 반토막 되어있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;DCB7DD0E-DDD8-4641-A227-CD6BD28731A4.JPG&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;2080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doHbWi/btsFJH6BWCj/ppVfsDAv8FIPW4jKwwAj81/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doHbWi/btsFJH6BWCj/ppVfsDAv8FIPW4jKwwAj81/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doHbWi/btsFJH6BWCj/ppVfsDAv8FIPW4jKwwAj81/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoHbWi%2FbtsFJH6BWCj%2FppVfsDAv8FIPW4jKwwAj81%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;711&quot; data-filename=&quot;DCB7DD0E-DDD8-4641-A227-CD6BD28731A4.JPG&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;2080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀별 아이디어 스피치를 했을 때 솔직히 조금은 걱정이 앞섰지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;걱정과 달리, 모든 학생들이 보여준 &lt;b&gt;열정&lt;/b&gt;과 &lt;b&gt;노력&lt;/b&gt;은 정말 놀라웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더욱&amp;nbsp;놀라운&amp;nbsp;것은,&amp;nbsp;&lt;b&gt;포기하는&amp;nbsp;팀이&amp;nbsp;단&amp;nbsp;한&amp;nbsp;팀도&amp;nbsp;없었다&lt;/b&gt;는&amp;nbsp;사실이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 팀이 제한된 시간 내에 실제로 &lt;b&gt;구현까지&lt;/b&gt; 마무리 지었다는 점에서 정말 대단했다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_IMG_7059.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1687&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwGI1s/btsFLqcBXM1/j3kat79UwxLte5vveK13K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwGI1s/btsFLqcBXM1/j3kat79UwxLte5vveK13K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwGI1s/btsFLqcBXM1/j3kat79UwxLte5vveK13K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwGI1s%2FbtsFLqcBXM1%2Fj3kat79UwxLte5vveK13K0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;281&quot; data-filename=&quot;edited_IMG_7059.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1687&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학생들이 밤새우며  &lt;b&gt;Slack&lt;/b&gt;으로 다양한 이슈들을 SOS 치면 달려가서 도움을 주었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Elastic Search&lt;/b&gt;를 사용해 본 적이 없어서 관련 질문들에 내가 도움을 전혀 주지 못했다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이참에 지금 진행&amp;nbsp;중인 &lt;b&gt;사이드 프로젝트&lt;/b&gt;에다가 &lt;b&gt;Elastic Search&lt;/b&gt;를 붙혀볼 생각이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음엔 좀 더 도움이 될 수 있도록 미리미리 준비를 해둬야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 해커톤도 배우고 얻어가는 점이 너무나 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다들 고생하셨습니다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_IMG_7094.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GTlYw/btsFIxqJ9iV/KxkutV8DNDH0TkWzHmneK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GTlYw/btsFIxqJ9iV/KxkutV8DNDH0TkWzHmneK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GTlYw/btsFIxqJ9iV/KxkutV8DNDH0TkWzHmneK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGTlYw%2FbtsFIxqJ9iV%2FKxkutV8DNDH0TkWzHmneK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;375&quot; data-filename=&quot;edited_edited_IMG_7094.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Participation</category>
      <category>AWS</category>
      <category>AWS Bedrock</category>
      <category>elastic search</category>
      <category>Hackathon</category>
      <category>숙대</category>
      <category>연대</category>
      <category>해커톤</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/72</guid>
      <comments>https://ilikezzi.tistory.com/72#entry72comment</comments>
      <pubDate>Tue, 12 Mar 2024 22:00:15 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] 서버 상태 실시간 모니터링: CloudWatch를 이용한 Nginx 액세스 로그 분석 및 대시보드 구축하기</title>
      <link>https://ilikezzi.tistory.com/71</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;840&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HZDhl/btsE6SgIdMl/tSwAmH76LIKCs6KYKTjBHK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HZDhl/btsE6SgIdMl/tSwAmH76LIKCs6KYKTjBHK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HZDhl/btsE6SgIdMl/tSwAmH76LIKCs6KYKTjBHK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHZDhl%2FbtsE6SgIdMl%2FtSwAmH76LIKCs6KYKTjBHK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;315&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;840&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AWS&lt;/b&gt;에서 서비스를 운영하다 보면, &lt;b&gt;서버의 상태를 실시간으로 파악&lt;/b&gt;하는 것이 얼마나 중요한지 잘 알게 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히&amp;nbsp;웹&amp;nbsp;서버인&lt;b&gt;&amp;nbsp;NGINX&lt;/b&gt;에서&amp;nbsp;발생하는&amp;nbsp;&lt;b&gt;액세스&amp;nbsp;로그&lt;/b&gt;를&amp;nbsp;분석하고&amp;nbsp;모니터링하는&amp;nbsp;것은,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서비스의&amp;nbsp;성능&lt;/b&gt;을&amp;nbsp;유지하고&amp;nbsp;&lt;b&gt;사용자&amp;nbsp;경험&lt;/b&gt;을 개선하는 데 필수적이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 많은 사람들이 이런 중요한 데이터를 어떻게 &lt;b&gt;효과적으로 수집하고 분석&lt;/b&gt;할 수 있는지에 대해 궁금해 하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 AWS의 &lt;b&gt;CloudWatch Logs&lt;/b&gt;가 빛을 발한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CloudWatch&amp;nbsp;Logs&lt;/b&gt;는&amp;nbsp;로그&amp;nbsp;데이터를&amp;nbsp;&lt;b&gt;실시간&lt;/b&gt;으로 수집하고, 저장하며, 접근할 수 있게 해주는 서비스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;내가 서비스중인 앱에 최근에 &lt;b&gt;유저가 &lt;span style=&quot;color: #ee2323;&quot;&gt;5배&lt;/span&gt; 가량&lt;/b&gt; 확&lt;b&gt; 증가&lt;/b&gt;하면서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;사용자 경험을 개선&lt;/b&gt;하고, &lt;b&gt;서비스를 더욱 최적화&lt;/b&gt;하기 위해서 구축하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;AWS의 NGINX 액세스 로그&lt;/b&gt;를 &lt;b&gt;CloudWatch Logs&lt;/b&gt;로 전송하는 과정을 단계별로 자세하게 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;IAM 역할 생성 및 EC2 인스턴스에 할당하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS에서&amp;nbsp;서비스&amp;nbsp;간&amp;nbsp;통신을&amp;nbsp;위해 &lt;b&gt;IAM&lt;/b&gt; 역할이 필수적이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CloudWatch&amp;nbsp;Logs에&amp;nbsp;로그를&amp;nbsp;보낼&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;&lt;b&gt;EC2&amp;nbsp;인스턴스에&amp;nbsp;권한&lt;/b&gt;을&amp;nbsp;부여하는&amp;nbsp;것부터&amp;nbsp;시작해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IAM 콘솔에 접속하여 &lt;b&gt;역할(Role)&lt;/b&gt; 섹션으로 이동하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &quot;&lt;b&gt;새 역할 생성(Create new role)&lt;/b&gt;&quot;을 선택한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AWS 서비스&lt;/b&gt;를 선택하고, 사용 사례로 &lt;b&gt;EC2&lt;/b&gt;를 선택한 다음, &lt;b&gt;&quot;권한(Next: Permissions)&quot;&lt;/b&gt;을 클릭한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-02-02 오후 3.08.35.png&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;53&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9gELO/btsE1FbGvdY/0ZxIKP0Beld3mEZx98PspK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9gELO/btsE1FbGvdY/0ZxIKP0Beld3mEZx98PspK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9gELO/btsE1FbGvdY/0ZxIKP0Beld3mEZx98PspK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9gELO%2FbtsE1FbGvdY%2F0ZxIKP0Beld3mEZx98PspK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;697&quot; height=&quot;53&quot; data-filename=&quot;스크린샷 2024-02-02 오후 3.08.35.png&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;53&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CloudWatchLogsFullAccess&lt;/b&gt; 정책을 검색해서 선택하고, 역할 이름을 지정한 후 역할을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 EC2 인스턴스가 &lt;b&gt;CloudWatch Logs에 로그를 보낼 권한&lt;/b&gt;을 갖게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 IAM 역할을 &lt;b&gt;EC2 인스턴스에 할당&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;View alarms -.png&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8p2jI/btsE6OyEvzw/CYOksoc1IZbkSZL2vIS0ok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8p2jI/btsE6OyEvzw/CYOksoc1IZbkSZL2vIS0ok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8p2jI/btsE6OyEvzw/CYOksoc1IZbkSZL2vIS0ok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8p2jI%2FbtsE6OyEvzw%2FCYOksoc1IZbkSZL2vIS0ok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;515&quot; height=&quot;345&quot; data-filename=&quot;View alarms -.png&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;345&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2 대시보드에서 인스턴스를 &lt;b&gt;선택&lt;/b&gt;하고 &lt;b&gt;작업 -&amp;gt; 보안 -&amp;gt; IAM&lt;/b&gt; &lt;b&gt;역할 수정&lt;/b&gt;으로 이동해서 새로 생성한 역할을 선택하면 된다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CloudWatch Logs Agent 설치 및 구성하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2 인스턴스에서 로그를 수집하고 CloudWatch로 전송하기 위해선 &lt;b&gt;CloudWatch Logs Agent&lt;/b&gt;가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ubuntu 기반&lt;/b&gt;의 시스템에서는 CloudWatch Unified Agent를 설치하고 구성하는 과정을 따라야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- AWS CLI 설치하기 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, EC2 인스턴스에 AWS &lt;b&gt;CLI가 설치되어 있는지&lt;/b&gt; &lt;b&gt;확인&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치되어 있지 않다면 다음 명령어로 설치할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708351397523&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install awscli -y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- CloudWatch Logs Agent 설치하기 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 CloudWatch Unified Agent를 &lt;b&gt;설치&lt;/b&gt;할 차례다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;홈 디렉토리로 이동한 후, 다음 명령어를 실행해서 &lt;b&gt;Agent를 다운로드하고 설치&lt;/b&gt;하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708351490573&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd ~

wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb

sudo dpkg -i amazon-cloudwatch-agent.deb&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- CloudWatch Agent 구성하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CloudWatch Agent를 설치한 후, &lt;b&gt;로그와 메트릭을 CloudWatch로&lt;/b&gt; 보낼 수 있도록 구성해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서&lt;b&gt; 로그 파일의 위치, 로그 그룹 및 스트림 이름&lt;/b&gt; 등을 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구성 파일을&lt;b&gt; 직접 수정&lt;/b&gt;하거나 &lt;b&gt;구성 마법사&lt;/b&gt;를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;구성 마법사&lt;/b&gt;를 사용하려면 다음 명령어를 실행하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708351798435&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는,&amp;nbsp;&lt;b&gt;구성&amp;nbsp;파일을&amp;nbsp;직접&amp;nbsp;편집&lt;/b&gt;하고 싶다면 다음 명령어를 실행하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708351828298&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo nano /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 &lt;b&gt;NGINX 액세스 로그 파일&lt;/b&gt;의 &lt;b&gt;경로, 로그 그룹 이름&lt;/b&gt; 등을 지정해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 예시를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708352003480&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;agent&quot;: {
        &quot;metrics_collection_interval&quot;: 60,
        &quot;run_as_user&quot;: &quot;cwagent&quot;
    },
    &quot;metrics&quot;: {
        &quot;metrics_collected&quot;: {
            &quot;disk&quot;: {
                &quot;measurement&quot;: [
                    &quot;used_percent&quot;
                ],
                &quot;metrics_collection_interval&quot;: 60,
                &quot;resources&quot;: [
                    &quot;*&quot;
                ]
            },
            &quot;mem&quot;: {
                &quot;measurement&quot;: [
                    &quot;mem_used_percent&quot;
                ],
                &quot;metrics_collection_interval&quot;: 60
            }
        }
    },
    &quot;logs&quot;: {
        &quot;logs_collected&quot;: {
            &quot;files&quot;: {
                &quot;collect_list&quot;: [
                    {
                        &quot;file_path&quot;: &quot;/var/log/nginx/**액세스 로그 파일**&quot;,
                        &quot;log_group_name&quot;: &quot;**원하는 로그 그룹 이름**&quot;,
                        &quot;log_stream_name&quot;: &quot;{instance_id}&quot;,
                        &quot;timezone&quot;: &quot;Local&quot;
                    }
                ]
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의&lt;b&gt; &quot;file_path&quot;&lt;/b&gt; 와 &lt;b&gt;&quot;log_group_name&quot;&lt;/b&gt;만 알아서 자신의 환경에 맞게 적절하게 입력 해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CloudWatch&amp;nbsp;Agent&amp;nbsp;실행&amp;nbsp;및&amp;nbsp;모니터링&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구성이 완료된 후, &lt;b&gt;CloudWatch Agent를 시작&lt;/b&gt;해야 로그가 CloudWatch로 전송된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Agent를 시작&lt;/b&gt;하기 위해 다음 명령어를 실행하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708352631092&quot; class=&quot;awk&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -s&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그를 확인하거나, Agent의 &lt;b&gt;상태를 확인&lt;/b&gt;하고 싶다면 다음 명령어를 실행하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708352653010&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo systemctl status amazon-cloudwatch-agent&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정을 변경해서 &lt;b&gt;재시작&lt;/b&gt;을 하고 싶다면 다음 명령어를 실행하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708352723265&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo systemctl restart amazon-cloudwatch-agent&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;로그 모니터링 및 분석&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 설정은 모두 끝나서 확인을 하러 가보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CloudWatch &amp;gt; 로그그룹 &amp;gt; &lt;b&gt;아까 설정하면서 만든 로그그룹 선택&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;833&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRVzUM/btsE6TUfy8H/GFyAGkGdGVZpS2H21cZkx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRVzUM/btsE6TUfy8H/GFyAGkGdGVZpS2H21cZkx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRVzUM/btsE6TUfy8H/GFyAGkGdGVZpS2H21cZkx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRVzUM%2FbtsE6TUfy8H%2FGFyAGkGdGVZpS2H21cZkx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;833&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;833&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 하단에 로그 스트림에 &lt;b&gt;자동으로 추가&lt;/b&gt;가 되어 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;눌러서 들어가보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;753&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DkdWm/btsE5DRVoOS/EhRCfg3jKgBnqfXezfYBJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DkdWm/btsE5DRVoOS/EhRCfg3jKgBnqfXezfYBJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DkdWm/btsE5DRVoOS/EhRCfg3jKgBnqfXezfYBJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDkdWm%2FbtsE5DRVoOS%2FEhRCfg3jKgBnqfXezfYBJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;753&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;753&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정상적으로 &lt;b&gt;Nginx 액세스 로그가 쌓이는 중&lt;/b&gt;이다!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 해당 &lt;b&gt;로그값&lt;/b&gt;들을 보기 쉽게 &lt;b&gt;대시보드&lt;/b&gt;에 구축을 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;다양한 지표 분석 및 대시보드 구축하기&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CloudWatch &amp;gt; 대시보드 생성 &amp;gt; &quot;&lt;b&gt;+&lt;/b&gt;&quot; 버튼 클릭&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-02-19 오후 11.40.36.png&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBlAhz/btsE3mJFRn7/fsfNqH2qjhJbfolOaWsCxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBlAhz/btsE3mJFRn7/fsfNqH2qjhJbfolOaWsCxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBlAhz/btsE3mJFRn7/fsfNqH2qjhJbfolOaWsCxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBlAhz%2FbtsE3mJFRn7%2FfsfNqH2qjhJbfolOaWsCxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;355&quot; data-filename=&quot;스크린샷 2024-02-19 오후 11.40.36.png&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;562&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그 유형에서 원하는 위젯을 골라주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음, &lt;b&gt;Logs Insights&lt;/b&gt;에 들어왔으면 내가 아까 만든 로그그룹을 선택한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 쿼리를 짜면 되는데 이전에 &lt;b&gt;로그 스트림에서 나왔던 로그 형식을 참고&lt;/b&gt;해서 쿼리를 작성하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지 예시를 보여주자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 &lt;b&gt;&quot;응답시간이 1초를 초과하는 요청 수&quot;&lt;/b&gt;를 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1708353958158&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;parse @message &quot;* - - [*] \&quot;*\&quot; * * \&quot;*\&quot; \&quot;*\&quot; *&quot; as ip_address, timestamp, request, status, body_bytes_sent, referer, user_agent, upstream_response_time
| filter user_agent != &quot;ELB-HealthChecker/2.0&quot;
| filter upstream_response_time &amp;gt; 1.0
| stats count() by bin(10m)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-02-19 오후 11.47.05.png&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;779&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G8E6n/btsE6VLhzZk/sZw9TAR2qw4u9iXbXtha2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G8E6n/btsE6VLhzZk/sZw9TAR2qw4u9iXbXtha2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G8E6n/btsE6VLhzZk/sZw9TAR2qw4u9iXbXtha2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG8E6n%2FbtsE6VLhzZk%2FsZw9TAR2qw4u9iXbXtha2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;594&quot; data-filename=&quot;스크린샷 2024-02-19 오후 11.47.05.png&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;779&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 &lt;b&gt;&quot;응답시간 1초를 초과하는 요청 수&quot;&lt;/b&gt; 의 합을 막대 그래프로 뽑아서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;어느시간에 요청이 전반적으로 느려졌는지&lt;/b&gt; 구했다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 그래프 우측 상단에 &lt;b&gt;&quot;대시보드에 추가&quot;&lt;/b&gt;를 하면 끝이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2024-02-19 오후 11.38.13.png&quot; data-origin-width=&quot;2479&quot; data-origin-height=&quot;1095&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJs4kN/btsE0GuTqCq/yaiqpHpq0AfaywmJO2R1S0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJs4kN/btsE0GuTqCq/yaiqpHpq0AfaywmJO2R1S0/img.png&quot; data-alt=&quot;CloudWatch Nginx access log&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJs4kN/btsE0GuTqCq/yaiqpHpq0AfaywmJO2R1S0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJs4kN%2FbtsE0GuTqCq%2FyaiqpHpq0AfaywmJO2R1S0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;860&quot; height=&quot;380&quot; data-filename=&quot;edited_스크린샷 2024-02-19 오후 11.38.13.png&quot; data-origin-width=&quot;2479&quot; data-origin-height=&quot;1095&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CloudWatch Nginx access log&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 나는 우선&amp;nbsp;&lt;b&gt;4가지&lt;/b&gt;를 더 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히들 &lt;b&gt;HTTP status&lt;/b&gt;를 가지고 대시보드로 많이 만들던데 지금 서비스에 status가 문제가 있어서... 다른걸 이용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;- 평균 응답 시간&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평균 응답 시간을 모니터링함으로써, 우리는 서버가 &lt;b&gt;얼마나 빠르게 사용자의 요청에 반응&lt;/b&gt;하는지를 파악할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 애플리케이션의 성능을 실시간으로 감시하고, 필요한 경우 즉시 개선 조치를 취할 수 있는 근거를 제공해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;- 요청 수&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전체 요청 수&lt;/b&gt;를 추적하는 것은 우리에게 웹 애플리케이션에 대한 사용자 &lt;b&gt;트래픽의 양과 패턴&lt;/b&gt;을 이해할 수 있는 통찰력을 준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 정보를 활용함으로써, 우리는 서버 용량을 적절히 계획하고 조정하여 사용자 경험을 최적화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;- 특정 IP 주소로부터의 요청 수&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 IP 주소로부터 오는 요청 수를 모니터링함으로써, 우리는 &lt;b&gt;비정상적인 트래픽 패턴이나 의심스러운 행동&lt;/b&gt;을 조기에 탐지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 서비스의 보안 위협에 대응하고, 안정성을 유지하는 데 큰 도움이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;- 응답시간이 1초를 초과하는 요청 수&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답 시간이 1초를 초과하는 요청의 수를 분석함으로써, 우리는 사용자 경험에 &lt;b&gt;부정적인 영향을 미치는 느린 요청&lt;/b&gt;을 식별할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 데이터를 기반으로 성능 최적화를 진행함으로써, 전반적인 서비스 품질을 개선할 수 있는 기회를 얻게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/AWS</category>
      <category>AWS</category>
      <category>cloudwatch</category>
      <category>log</category>
      <category>nginx</category>
      <category>모니터링</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/71</guid>
      <comments>https://ilikezzi.tistory.com/71#entry71comment</comments>
      <pubDate>Tue, 20 Feb 2024 00:08:37 +0900</pubDate>
    </item>
    <item>
      <title>[SeoulSync82] HTTPS와 SameSite로 해결한 서로 다른 도메인의 Cookie 전송 이슈</title>
      <link>https://ilikezzi.tistory.com/70</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJX3IK/btsEb9QOsps/z1AbsvB9ueaoqwcM1LEuu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJX3IK/btsEb9QOsps/z1AbsvB9ueaoqwcM1LEuu1/img.png&quot; data-alt=&quot;소셜로그인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJX3IK/btsEb9QOsps/z1AbsvB9ueaoqwcM1LEuu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJX3IK%2FbtsEb9QOsps%2Fz1AbsvB9ueaoqwcM1LEuu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;383&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;912&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;소셜로그인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 이전에 만들었던 &lt;b&gt;소셜로그인&lt;/b&gt;에 이슈가 생겼는데 2주정도 머리 쥐어뜯다가 해결을 해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 내용을 포스팅 해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/65&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ilikezzi.tistory.com/65&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706530575461&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Nest.JS] 구글, 네이버, 카카오 소셜로그인 구현 - 2&quot; data-og-description=&quot;소셜로그인 1편에 이어서 바로 2편을 포스팅하려 했는데 refresh_token과 JWT 전략에 대해서 이것저것 머리싸매면서 고민하느라 늦어졌다.. 정말 다양한 JWT 전략과 고민할 사항이 많았다. 한 계정으&quot; data-og-host=&quot;ilikezzi.tistory.com&quot; data-og-source-url=&quot;https://ilikezzi.tistory.com/65&quot; data-og-url=&quot;https://ilikezzi.tistory.com/65&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dnoeLU/hyVb8uKbuM/VfoYOjuwVkdu7fWhf7nDJK/img.png?width=800&amp;amp;height=766&amp;amp;face=0_0_800_766,https://scrap.kakaocdn.net/dn/COa4Y/hyVb13rOtS/KJUwm6YCllvN4ok67bTayk/img.png?width=800&amp;amp;height=766&amp;amp;face=0_0_800_766,https://scrap.kakaocdn.net/dn/cIxn6T/hyVccKFA5G/XnVV0GLjgx9iSjkPkNkrQk/img.png?width=1288&amp;amp;height=822&amp;amp;face=0_0_1288_822&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/65&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ilikezzi.tistory.com/65&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dnoeLU/hyVb8uKbuM/VfoYOjuwVkdu7fWhf7nDJK/img.png?width=800&amp;amp;height=766&amp;amp;face=0_0_800_766,https://scrap.kakaocdn.net/dn/COa4Y/hyVb13rOtS/KJUwm6YCllvN4ok67bTayk/img.png?width=800&amp;amp;height=766&amp;amp;face=0_0_800_766,https://scrap.kakaocdn.net/dn/cIxn6T/hyVccKFA5G/XnVV0GLjgx9iSjkPkNkrQk/img.png?width=1288&amp;amp;height=822&amp;amp;face=0_0_1288_822');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Nest.JS] 구글, 네이버, 카카오 소셜로그인 구현 - 2&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소셜로그인 1편에 이어서 바로 2편을 포스팅하려 했는데 refresh_token과 JWT 전략에 대해서 이것저것 머리싸매면서 고민하느라 늦어졌다.. 정말 다양한 JWT 전략과 고민할 사항이 많았다. 한 계정으&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;소셜로그인 전략&lt;/b&gt;을 어떻게 구성했는지는 위의 &lt;b&gt;포스팅&lt;/b&gt;을 참고하길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 소셜로그인 전략에 대해 간략하게 얘기해보자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;소셜로그인 전략&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 첫 로그인 시 &lt;b&gt;access_token / refresh_token 발급&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. access_token은 1시간 만료기간으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;로컬스토리지&lt;/b&gt;&lt;/span&gt;에 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. refresh_token은 2주 만료기간으로 &lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;Set-Cookie 헤더에&lt;span style=&quot;color: #ee2323;&quot;&gt; &lt;b&gt;httpOnly 쿠키&lt;/b&gt;&lt;/span&gt;로 저장 + &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DB&lt;/b&gt;&lt;/span&gt;에 저장&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;4. access_token이 만료되었으면 &lt;b&gt;쿠키&lt;/b&gt;에 저장된 refresh_token을 &lt;b&gt;검증&lt;/b&gt;해서 새로운 &lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;access_token&lt;/span&gt;&amp;nbsp;발급&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;ㄴ (&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;Silent Refresh API)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런&amp;nbsp;식으로&amp;nbsp;이루어져&amp;nbsp;있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;문제 이슈&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의&lt;b&gt; 4번째&amp;nbsp;&lt;/b&gt;전략에서&amp;nbsp;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;Silent Refresh API를 프론트에서 호출시 새로운 &lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;&lt;b&gt;access_token 발급이 안된다&lt;/b&gt;고 했다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하기 위해 코드를 디버깅하기 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-01-29 오후 9.32.59.png&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;177&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yNEng/btsEb8qPSqs/6ZF2h2h2cNjAb7lnqdxD2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yNEng/btsEb8qPSqs/6ZF2h2h2cNjAb7lnqdxD2k/img.png&quot; data-alt=&quot; silent refresh api&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yNEng/btsEb8qPSqs/6ZF2h2h2cNjAb7lnqdxD2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyNEng%2FbtsEb8qPSqs%2F6ZF2h2h2cNjAb7lnqdxD2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;154&quot; data-filename=&quot;스크린샷 2024-01-29 오후 9.32.59.png&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;177&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; silent refresh api&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;getRefreshToken&quot; 이 undefined로 출력 되더라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 return 값에 &lt;b&gt;access_token&lt;/b&gt;이 아닌 false만 출력되고 있었다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애초에 &lt;b&gt;헤더에 cookie&lt;/b&gt;가 저장되지 않았나? 하고 확인을 해보았다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-01-29 오후 9.41.13.png&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kQ1yL/btsD6yqRQVd/JsaTkWi2TPrXwe3bI5Hkdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kQ1yL/btsD6yqRQVd/JsaTkWi2TPrXwe3bI5Hkdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kQ1yL/btsD6yqRQVd/JsaTkWi2TPrXwe3bI5Hkdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkQ1yL%2FbtsD6yqRQVd%2FJsaTkWi2TPrXwe3bI5Hkdk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;272&quot; data-filename=&quot;스크린샷 2024-01-29 오후 9.41.13.png&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cookie는 정상적으로 헤더에 &lt;b&gt;저장&lt;/b&gt;되어 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, Cookie를 &lt;b&gt;헤더에서 꺼내오지 못하고&lt;/b&gt; 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글링을 해보니 &lt;b&gt;credentials:true&lt;/b&gt; 옵션을 찾았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 옵션을 프론트,백엔드 둘 다 설정하면 &lt;b&gt;동일 출처&lt;/b&gt; 또는 &lt;b&gt;다른 출처에 관계없이 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 HTTP 요청에 쿠키를 포함&lt;/b&gt;시킨다고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;크로스 오리진 요청&lt;/b&gt;에서도 쿠키를 보내고 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-01-29 오후 10.42.23.png&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5uolj/btsD3Lj86yP/IGHSviJpZl2EEwKmUk5Kt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5uolj/btsD3Lj86yP/IGHSviJpZl2EEwKmUk5Kt0/img.png&quot; data-alt=&quot; main.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5uolj/btsD3Lj86yP/IGHSviJpZl2EEwKmUk5Kt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5uolj%2FbtsD3Lj86yP%2FIGHSviJpZl2EEwKmUk5Kt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;169&quot; data-filename=&quot;스크린샷 2024-01-29 오후 10.42.23.png&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; main.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 바로 해당 옵션을 추가하고 테스트를 해봤는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여전히 안되더라...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 다양하게 테스트를 해보다가&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프론트(staging) - 백엔드(staging)&lt;/b&gt; 이렇게 &lt;b&gt;같은 환경&lt;/b&gt;에서는 정상적으로 쿠키를 꺼내오고 있는걸 확인했다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제서야 문제점을 제대로 파악했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쿠키는 기본적으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;동일한 도메인&lt;/span&gt; 및 서브 도메인으로만 전송되도록 설정되어 있어서,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;서로 다른 도메인 간에는 쿠키가 공유되지 않았던것&lt;span style=&quot;color: #000000;&quot;&gt;이&lt;/span&gt;&lt;/span&gt;였다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론트엔드 로컬 환경에서 테스트를 하다보니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;localhost:3457&lt;/b&gt; 에서 -&amp;gt; &lt;b&gt;http://staging.seoulsync82.com&lt;/b&gt;&amp;nbsp;으로요청을&amp;nbsp;보낼&amp;nbsp;때,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;다른 도메인 간에 쿠키가 전송되지 않는 상황&lt;/b&gt;이 발생했던 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;문제 해결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다른 도메인 간에 쿠키 전송을 가능하게끔 해줄 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-01-29 오후 11.10.00.png&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doxshz/btsD4H2QFna/5T2l6WKhZrddvlZmpbZebk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doxshz/btsD4H2QFna/5T2l6WKhZrddvlZmpbZebk/img.png&quot; data-alt=&quot;Cookie 설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doxshz/btsD4H2QFna/5T2l6WKhZrddvlZmpbZebk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdoxshz%2FbtsD4H2QFna%2F5T2l6WKhZrddvlZmpbZebk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;494&quot; height=&quot;234&quot; data-filename=&quot;스크린샷 2024-01-29 오후 11.10.00.png&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Cookie 설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키 설정을 할때 &lt;b&gt;&quot;&lt;span style=&quot;color: #ee2323;&quot;&gt;SameSite&lt;/span&gt;&quot;&lt;/b&gt;라는 옵션을 &lt;b&gt;&quot;&lt;span style=&quot;color: #ee2323;&quot;&gt;none&lt;/span&gt;&quot;&lt;/b&gt;으로 해줘야&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 도메인에서도 쿠키&lt;b&gt; 전달이 가능&lt;/b&gt;하다더라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b&gt;&quot;SameSite : none&quot;&lt;/b&gt; 옵션을 사용하려면 &lt;b&gt;중요한 포인트가 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &quot;&lt;/span&gt;Secure&lt;span style=&quot;color: #000000;&quot;&gt;&quot;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; 옵션이 &lt;b&gt;&quot;&lt;/b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;True&lt;span style=&quot;color: #666666;&quot;&gt;&quot;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;로 설정되어야 한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 쿠키가 &lt;b&gt;HTTPS&lt;/b&gt; 연결을 통해서만 전송되도록 보장해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 결국엔, 나는 사이트를 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;HTTPS&lt;/span&gt;&lt;/b&gt;로 바꿔야만 했다ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS에서&amp;nbsp;제공하는&amp;nbsp;&lt;b&gt;SSL/TLS&lt;/b&gt; 인증서를 받고 인증서를 웹서버에 연결해서 &lt;b&gt;HTTPS&lt;/b&gt;로 안전하게&lt;b&gt; 전환&lt;/b&gt;을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_스크린샷 2024-01-29 오후 11.14.06.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uLe9X/btsD4UOrMB9/B37lGZ14zukKMUigu8hSM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uLe9X/btsD4UOrMB9/B37lGZ14zukKMUigu8hSM0/img.png&quot; data-alt=&quot;SSH 터미널&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uLe9X/btsD4UOrMB9/B37lGZ14zukKMUigu8hSM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuLe9X%2FbtsD4UOrMB9%2FB37lGZ14zukKMUigu8hSM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;263&quot; data-filename=&quot;edited_edited_스크린샷 2024-01-29 오후 11.14.06.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SSH 터미널&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어 !!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 도메인 간에 쿠키 전송을 &lt;b&gt;성공&lt;/b&gt;했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;이로 인해,&amp;nbsp;&lt;b&gt;Silent Refresh API&lt;/b&gt;도 제대로 실행되어서 &lt;b&gt;새로운 access_token 발급&lt;/b&gt;까지 원활하게 이루어졌다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;이런 변경 덕분에 이제 &lt;b&gt;로컬 환경의 프론트엔드&lt;/b&gt;에서도 &lt;b&gt; Staging 서버의 도메인&lt;/b&gt;으로&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;&lt;b&gt;쿠키 전송&lt;/b&gt;을 원활하게 할 수 있게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: left;&quot;&gt;개발하는 동안에도 쿠키를 효과적으로 관리하며, &lt;b&gt;더 나은 테스트 환경을 구축&lt;/b&gt;할 수 있게 되었다&amp;nbsp;!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Project/SeoulSync82</category>
      <category>cookie</category>
      <category>https</category>
      <category>samesite</category>
      <category>소셜로그인</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/70</guid>
      <comments>https://ilikezzi.tistory.com/70#entry70comment</comments>
      <pubDate>Mon, 29 Jan 2024 23:34:03 +0900</pubDate>
    </item>
    <item>
      <title>[해커톤] AWS Rookie Championship 심사위원 참여 후기</title>
      <link>https://ilikezzi.tistory.com/69</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_5174.GIF&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cd9Cob/btsCVJzndeJ/jeHukjzFkYbDxy6LOIbexk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cd9Cob/btsCVJzndeJ/jeHukjzFkYbDxy6LOIbexk/img.gif&quot; data-alt=&quot; AWS Rookie Championship&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cd9Cob/btsCVJzndeJ/jeHukjzFkYbDxy6LOIbexk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cd9Cob/btsCVJzndeJ/jeHukjzFkYbDxy6LOIbexk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;500&quot; data-filename=&quot;IMG_5174.GIF&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; AWS Rookie Championship&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;올 한해 운 좋게 &lt;b&gt;AWS 멘토진&lt;/b&gt;에 들어가게 되면서&lt;b&gt; 다양한 해커톤 멘토&lt;/b&gt;로 참석을 했었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;열정&lt;/b&gt; 넘치는 학생들과의 만남은 정말 영광스러운 경험이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;어찌보면 지금 개발중인 &lt;b&gt;프로젝트&lt;/b&gt;를 하게 된 계기도 멘토링을 하면서 &lt;b&gt;부족한 부분&lt;/b&gt;을 느껴 시작한 것이다.&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2023년을 회고하며, 멘토링 활동은 &lt;b&gt;나&lt;/b&gt; &lt;b&gt;자신의 성장&lt;/b&gt;에도 크게 기여했다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_6212.JPG&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1926&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6bPqs/btsCN6puqyw/9KNknj3DCkISeE7gFEJe11/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6bPqs/btsCN6puqyw/9KNknj3DCkISeE7gFEJe11/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6bPqs/btsCN6puqyw/9KNknj3DCkISeE7gFEJe11/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6bPqs%2FbtsCN6puqyw%2F9KNknj3DCkISeE7gFEJe11%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;658&quot; data-filename=&quot;IMG_6212.JPG&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1926&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;너무나 감사하게도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;AWS 이사님&lt;/b&gt;께서 초대를 해주셔서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난주 금요일(29일)&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;AWS Rookie Championship&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;심사위원으로 참석하게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;2023년 해커톤에서 뛰어난 결과를 낸 학생들을 초대해&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;발표&lt;/b&gt;하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;시상&lt;/b&gt; 까지하는 자리였다 !&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_6178.JPG&quot; data-origin-width=&quot;2599&quot; data-origin-height=&quot;3466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6SyXB/btsCVIUK0f4/zHc9sYfPzvhSp8fCnSzF9K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6SyXB/btsCVIUK0f4/zHc9sYfPzvhSp8fCnSzF9K/img.jpg&quot; data-alt=&quot;AWS 본사&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6SyXB/btsCVIUK0f4/zHc9sYfPzvhSp8fCnSzF9K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6SyXB%2FbtsCVIUK0f4%2FzHc9sYfPzvhSp8fCnSzF9K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;533&quot; data-filename=&quot;IMG_6178.JPG&quot; data-origin-width=&quot;2599&quot; data-origin-height=&quot;3466&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AWS 본사&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_6177.JPG&quot; data-origin-width=&quot;2875&quot; data-origin-height=&quot;3833&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lZVU1/btsCMxOsLus/7ARrgy7A6O9le9T4ubtGv1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lZVU1/btsCMxOsLus/7ARrgy7A6O9le9T4ubtGv1/img.jpg&quot; data-alt=&quot; AWS Rookie Championship&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lZVU1/btsCMxOsLus/7ARrgy7A6O9le9T4ubtGv1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlZVU1%2FbtsCMxOsLus%2F7ARrgy7A6O9le9T4ubtGv1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;533&quot; data-filename=&quot;IMG_6177.JPG&quot; data-origin-width=&quot;2875&quot; data-origin-height=&quot;3833&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; AWS Rookie Championship&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_6200.jpg&quot; data-origin-width=&quot;2760&quot; data-origin-height=&quot;3680&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qeTGT/btsCSDfAgsd/SkW0m0JkQMnHHRbT8Ix8C0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qeTGT/btsCSDfAgsd/SkW0m0JkQMnHHRbT8Ix8C0/img.jpg&quot; data-alt=&quot; &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qeTGT/btsCSDfAgsd/SkW0m0JkQMnHHRbT8Ix8C0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqeTGT%2FbtsCSDfAgsd%2FSkW0m0JkQMnHHRbT8Ix8C0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;533&quot; data-filename=&quot;IMG_6200.jpg&quot; data-origin-width=&quot;2760&quot; data-origin-height=&quot;3680&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장소는&amp;nbsp;&lt;b&gt;AWS 본사&lt;/b&gt;라서 센터필드로 갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 본사는 역시나 멋있더라..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_6186.JPG&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Mv5DI/btsCRiJwpyy/n1tFlQNEyIWHpVl9qUakS1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Mv5DI/btsCRiJwpyy/n1tFlQNEyIWHpVl9qUakS1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Mv5DI/btsCRiJwpyy/n1tFlQNEyIWHpVl9qUakS1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMv5DI%2FbtsCRiJwpyy%2Fn1tFlQNEyIWHpVl9qUakS1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;711&quot; data-filename=&quot;IMG_6186.JPG&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;귀여운 스티커도 받았다..ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_IMG_6179.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BCR12/btsCTU85Oti/m5kWs9WvUFRoyuYjl85cXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BCR12/btsCTU85Oti/m5kWs9WvUFRoyuYjl85cXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BCR12/btsCTU85Oti/m5kWs9WvUFRoyuYjl85cXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBCR12%2FbtsCTU85Oti%2Fm5kWs9WvUFRoyuYjl85cXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;375&quot; data-filename=&quot;edited_IMG_6179.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_IMG_6188.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7Edbn/btsCWKLF2D3/4VLRNiKduE8QYGHwcKr5M1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7Edbn/btsCWKLF2D3/4VLRNiKduE8QYGHwcKr5M1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7Edbn/btsCWKLF2D3/4VLRNiKduE8QYGHwcKr5M1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7Edbn%2FbtsCWKLF2D3%2F4VLRNiKduE8QYGHwcKr5M1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;375&quot; data-filename=&quot;edited_IMG_6188.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 12개 팀이 참여해&lt;b&gt; 기능소개&lt;/b&gt; 및 &lt;b&gt;아키텍쳐&lt;/b&gt;에 대해 발표를 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수상 팀들의 프로젝트인 만큼 대학생이 구현한거 맞아??? 라는 생각이 들 정도로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 수준 높은 기술&lt;/b&gt;로 구현된 프로젝트들이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당장 &lt;b&gt;비즈니스 모델&lt;/b&gt;로 사용해도 손색이 없어 보였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 인상 깊었던건 해당 프로젝트가 &lt;b&gt;단순한 발표&lt;/b&gt;로 끝나는 것이 아니라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지속적인 관리와 발전을 통해 더욱 &lt;b&gt;개선&lt;/b&gt;되고&lt;b&gt; 성장&lt;/b&gt;할 것임을 시사했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_IMG_6195.JPG&quot; data-origin-width=&quot;2322&quot; data-origin-height=&quot;1741&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buAaTF/btsCVFKvA2y/pcyBKsjyv26A1WMkq6gYm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buAaTF/btsCVFKvA2y/pcyBKsjyv26A1WMkq6gYm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buAaTF/btsCVFKvA2y/pcyBKsjyv26A1WMkq6gYm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuAaTF%2FbtsCVFKvA2y%2FpcyBKsjyv26A1WMkq6gYm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;375&quot; data-filename=&quot;edited_IMG_6195.JPG&quot; data-origin-width=&quot;2322&quot; data-origin-height=&quot;1741&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_IMG_6199.JPG&quot; data-origin-width=&quot;2746&quot; data-origin-height=&quot;2060&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8kKmO/btsCOBCMJES/Cet005tq4x4KADQUSfUPR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8kKmO/btsCOBCMJES/Cet005tq4x4KADQUSfUPR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8kKmO/btsCOBCMJES/Cet005tq4x4KADQUSfUPR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8kKmO%2FbtsCOBCMJES%2FCet005tq4x4KADQUSfUPR0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;375&quot; data-filename=&quot;edited_IMG_6199.JPG&quot; data-origin-width=&quot;2746&quot; data-origin-height=&quot;2060&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시상은 &lt;b&gt;AWS 상, Slack 상, Elastic 상, 코드스테이츠 상&lt;/b&gt; 등 다양한 상이 주어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 AWS 상으로는 팀원 각자에게 &lt;b&gt;AWS 주식 1주&lt;/b&gt;가 수여되었다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2023년 한 해 동안&lt;b&gt; AWS 해커톤 멘토&lt;/b&gt;로 활동하면서 많은 것을 배우고 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열정적인 분위기 속에서 함께 문제를 해결해 나가는 과정은 매우 보람찼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 팀이 &lt;b&gt;특색 있는 프로젝트&lt;/b&gt;를 발표하는 모습을 보며, 기술의 무한한 가능성을 다시 한번 실감했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내년에도 이러한 멘토링 경험을 계속 이어나가며, 더 많은 지식을 나누고, 더 많은 영감을 받고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멘토링의&amp;nbsp;질을&amp;nbsp;향상시키기&amp;nbsp;위해,&amp;nbsp;&lt;b&gt;지속적인&amp;nbsp;학습&lt;/b&gt;과&amp;nbsp;&lt;b&gt;개인적&amp;nbsp;성장&lt;/b&gt;에 힘 써야겠다  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Participation</category>
      <category>AWS</category>
      <category>AWS Rookie Championship</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/69</guid>
      <comments>https://ilikezzi.tistory.com/69#entry69comment</comments>
      <pubDate>Mon, 1 Jan 2024 04:58:50 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 비동기의 핵심, 이벤트 루프(Event loop) 파헤치기</title>
      <link>https://ilikezzi.tistory.com/68</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csntkT/btsCG1Utkjx/doO3h7s984wyzYvZ1X5kNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csntkT/btsCG1Utkjx/doO3h7s984wyzYvZ1X5kNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csntkT/btsCG1Utkjx/doO3h7s984wyzYvZ1X5kNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsntkT%2FbtsCG1Utkjx%2FdoO3h7s984wyzYvZ1X5kNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;402&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메리 크리스마스  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크리스마스인데도 포스팅을 하는 이유는 &lt;b&gt;백엔드파트 리더님&lt;/b&gt;과 대화중에 &lt;b&gt;JS 이벤트루프&lt;/b&gt;를 설명해보라고 하셨는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어버버대다가 제대로 &lt;b&gt;설명을 못해서&lt;/b&gt; 당황했었다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리더님은 면접을 보러 들어가면 &lt;b&gt;주니어, 시니어&lt;/b&gt; 상관없이 &lt;b&gt;JS 이벤트 루프&lt;/b&gt;에 대해서 설명해보라고 질문을 던진다고 하셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그만큼 &lt;b&gt;JS에서 가장 기본적&lt;/b&gt;이고 &lt;b&gt;비동기 동작원리&lt;/b&gt;를 알려면 무조건 알아야하고 설명을 할 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서..! 내일 출근하기전에 &lt;b&gt;제대로&lt;/b&gt; 알고 가서 설명을 드리려 포스팅을 해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Event Loop&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작하기에 앞서 간단히 &lt;b&gt;JS&lt;/b&gt;에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript는 &lt;b&gt;싱글 스레드&lt;/b&gt; 프로그래밍 언어로서, &lt;b&gt;한 번에 하나&lt;/b&gt;의 작업만 처리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;싱글&amp;nbsp;스레드&lt;/b&gt;인&amp;nbsp;자바스크립트의&amp;nbsp;작업을&amp;nbsp;&lt;b&gt;멀티&amp;nbsp;스레드&lt;/b&gt;로 돌려 작업을 동시에 처리시키게 하던가,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;JavaScript가 웹 애플리케이션에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;비동기적인 작업&lt;/b&gt;을 수행할 수 있는 이유는 무엇일까 ?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;'이벤트 루프(Event Loop)'&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 표현하자면 &lt;b&gt;브라우저의 동작 타이밍을 제어하는 관리자&lt;/b&gt;라고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스팅에서는 JavaScript의 핵심인 이벤트 루프의 원리와 작동 방식을 한번 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이벤트 루프의 원리와 구성 요소&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-12-25 오후 9.22.01.png&quot; data-origin-width=&quot;1814&quot; data-origin-height=&quot;1444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hfi1D/btsCALdLXZM/f3RkIsHGyeNf9Fa2zIykG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hfi1D/btsCALdLXZM/f3RkIsHGyeNf9Fa2zIykG0/img.png&quot; data-alt=&quot;Event Loop&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hfi1D/btsCALdLXZM/f3RkIsHGyeNf9Fa2zIykG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHfi1D%2FbtsCALdLXZM%2Ff3RkIsHGyeNf9Fa2zIykG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;398&quot; data-filename=&quot;스크린샷 2023-12-25 오후 9.22.01.png&quot; data-origin-width=&quot;1814&quot; data-origin-height=&quot;1444&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Event Loop&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사진속 이벤트 루프의 &lt;b&gt;구성 요소&lt;/b&gt;를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Heap &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적으로 할당된 메모리를 관리하는 영역이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체와 같은 구조체는 이곳에 저장되며, 메모리 관리는 '가비지 컬렉션'에 의해 자동으로 수행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Call Stack&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수의 호출을 기록하는 자료구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript 코드가 실행되면, 함수 호출은 스택에 push 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 함수가 실행을 마치고 반환될 때, 해당 함수는 스택에서 pop 되어 나간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript는 싱글 스레드 언어이기 때문에, 한 번에 하나의 함수만 처리할 수 있으며 이 처리 과정이 Call Stack에서 일어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Web&amp;nbsp;APIs&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저가 제공하는 비동기적인 기능들을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 setTimeout, XMLHttpRequest, fetch, DOM 이벤트 등을 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript 엔진이 아니라 브라우저에서 제공되고 실행된다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 JavaScript는 싱글 스레드임에도 불구하고 비블로킹 방식으로 다양한 작업을 동시에 처리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Callback Queue&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 작업(Web API로부터의 콜백, 사용자 이벤트 등)의 결과를 받는 콜백 함수들이 대기하는 곳이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 루프가 이 큐를 모니터링하며, Call Stack이 비어있을 때 콜백을 Call Stack으로 이동시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Event Loop&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Call Stack, Web APIs, Callback Queue 간의 작업 흐름을 조정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 루프는 계속해서 Call Stack을 확인하며, Stack이 비어있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백이 Callback Queue에 있을 때, 해당 콜백을 Call Stack으로 옮겨 실행하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱글 스레드인 JavaScript가 비동기 작업을 수행할 수 있게 해주며, 프로그램이 멈추지 않고 계속해서 실행될 수 있도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Event Table&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발생한 이벤트와 그에 해당하는 콜백 함수를 임시로 저장하는 자료구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, addEventListener를 사용하여 이벤트 리스너를 등록하면, 해당 이벤트와 콜백 함수가 Event Table에 등록된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트가 발생하면, Event Table은 해당 콜백을 Callback Queue로 이동시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;두 가지의 Callback Queue&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QSJOC/btsCyw9DWnE/AA8MvVQhfldtaBrSr3QmZk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QSJOC/btsCyw9DWnE/AA8MvVQhfldtaBrSr3QmZk/img.gif&quot; data-alt=&quot; Microtask Queue&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QSJOC/btsCyw9DWnE/AA8MvVQhfldtaBrSr3QmZk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/QSJOC/btsCyw9DWnE/AA8MvVQhfldtaBrSr3QmZk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;338&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; Microtask Queue&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Callback Queue&lt;/b&gt;에는 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;(Task)Macrotask queue&lt;/span&gt;&lt;/b&gt;와 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;(Job)Microtask queue&lt;/span&gt;&lt;/b&gt; 두 가지 종류가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두가지&amp;nbsp;&lt;b&gt;큐&lt;/b&gt;는  비슷하지만 다양한 종류의 작업에 적합한 &lt;b&gt;우선 순위&lt;/b&gt;와 &lt;b&gt;실행 타이밍&lt;/b&gt;을 제공하기 위해서 나눠진것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Callback Queue&lt;/b&gt;는 해당 &lt;b&gt;두가지 큐를 묶어&lt;/b&gt; 총칭하는 개념이라고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 큐는 무슨 작업을 처리 하는지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;-&lt;/span&gt; (Task) Macrotask queue&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 루프가 관리하는 큐 중 하나로, 일련의 &lt;b&gt;macrotask&lt;/b&gt;를 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Macrotask는 큐에 들어온 &lt;b&gt;순서대로&lt;/b&gt; 처리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 Macrotask의 처리가 완료되면 다음 Macrotask로 넘어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Macrotask 예시&lt;/b&gt;: setTimeout, setInterval, setImmediate (Node.js의 경우), I/O 작업, UI 렌더링 요청 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;-&lt;/span&gt; (Job) Microtask queue&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ES6/ES2015&amp;nbsp;&lt;/b&gt;에서&amp;nbsp;소개된&amp;nbsp;&lt;b&gt;Job&amp;nbsp;Queue&lt;/b&gt;는 주로 &lt;b&gt;Promise&lt;/b&gt;를 사용할 경우&lt;b&gt; Job Queue&lt;/b&gt;를 사용하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;promise&lt;/b&gt;를 사용할 때 callback 함수 역할을 하는 &lt;b&gt;.then&lt;/b&gt; 을 사용하게 되며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 &lt;b&gt;thenable&lt;/b&gt;한 함수들은&lt;b&gt; Job Queue&lt;/b&gt;에 추가된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Macrotask가 처리된 후, 다음 Macrotask로 넘어가기 전에, 이벤트 루프는 Microtask Queue에 있는 &lt;b&gt;모든 작업을 처리&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 Microtask가 Macrotask 사이에 &lt;b&gt;빠르게 처리&lt;/b&gt;되도록 보장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Microtask Queue는 &lt;b&gt;비어있을 때까지 Microtask를 연속적으로 처리&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 하나의 Microtask 처리 중에 &lt;b&gt;새로운&lt;/b&gt; Microtask가 생성되면, 그것도 &lt;b&gt;즉시&lt;/b&gt; 처리됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Microtasks 예시&lt;/b&gt;: Promise 처리 (then, catch, finally 콜백), MutationObserver, process.nextTick (Node.js의 경우)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 두개의 큐에 대해서 알아봤는데 요약해보자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Job&lt;/span&gt;&lt;/b&gt;의&amp;nbsp;&lt;b&gt;우선순위&lt;/b&gt;가&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;task&lt;/b&gt;&lt;/span&gt;의&lt;b&gt;&amp;nbsp;우선순위보다&amp;nbsp;높다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Job&lt;/span&gt;&lt;/b&gt;의 높은 우선 순위는 &lt;b&gt;빠른 반응성을 필요로 하는 작업&lt;/b&gt;을 적시에 처리할 수 있게 도와줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;task&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;더 큰 작업&lt;/b&gt; 단위를 관리하여, 애플리케이션의 흐름을 조절하고 성능을 최적화합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;우선순위&lt;/b&gt;와&amp;nbsp;&lt;b&gt;처리&amp;nbsp;방식&lt;/b&gt;을&amp;nbsp;이해하는&amp;nbsp;것은&amp;nbsp;&lt;b&gt;비동기&lt;/b&gt; 프로그래밍&amp;nbsp;패턴을&amp;nbsp;효과적으로&amp;nbsp;설계하고&amp;nbsp;최적화하는데&amp;nbsp;중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;예제 코드와 작동 방식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1703621360265&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log('Start!');

setTimeout(() =&amp;gt; {
	console.log('Timeout!');
}, 0);

Promise.resolve('Promise!').then(res =&amp;gt; console.log(res));

console.log('End!');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 개념을 흝어봤으니 직접 코드를 통한 작동방식을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. console.log('Start!')가 &lt;b&gt;Call Stack&lt;/b&gt;에 쌓인 후&lt;b&gt; &quot;start!&quot;&lt;/b&gt; 출력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0MWQu/btsCLajz9Se/sfMrupXFg2rvCdV1XkHGhK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0MWQu/btsCLajz9Se/sfMrupXFg2rvCdV1XkHGhK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0MWQu/btsCLajz9Se/sfMrupXFg2rvCdV1XkHGhK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/b0MWQu/btsCLajz9Se/sfMrupXFg2rvCdV1XkHGhK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;338&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. &lt;b&gt;setTimeout&lt;/b&gt;이 &lt;b&gt;Call Stack&lt;/b&gt;에 적재되고 실행되면, 그 안의 콜백 함수가 &lt;b&gt;Web API&lt;/b&gt;로 옮겨지고 &lt;b&gt;타이머&lt;/b&gt;가 작동한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byB4zz/btsCKpVzp4Z/nYB478Ct0ZwjKd0KIKFAh1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byB4zz/btsCKpVzp4Z/nYB478Ct0ZwjKd0KIKFAh1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byB4zz/btsCKpVzp4Z/nYB478Ct0ZwjKd0KIKFAh1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/byB4zz/btsCKpVzp4Z/nYB478Ct0ZwjKd0KIKFAh1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;338&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 타이머가 &lt;b&gt;종료되면&lt;/b&gt; setTimeout의 &lt;b&gt;콜백 함수&lt;/b&gt;는 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;(Task)MacroTask Queue&lt;/span&gt;&lt;/b&gt;에 적재된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Promise 코드가 &lt;b&gt;Call Stack&lt;/b&gt;에 적재 되어 실행되고, &lt;b&gt;then 핸들러&lt;/b&gt;의 콜백 함수가 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;(Job)MicroTask Queue&lt;/b&gt;&lt;/span&gt;에 적재된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wgqIQ/btsCy7vGa34/M5CmkzQ9Hnv52UXuWeiHpK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wgqIQ/btsCy7vGa34/M5CmkzQ9Hnv52UXuWeiHpK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wgqIQ/btsCy7vGa34/M5CmkzQ9Hnv52UXuWeiHpK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/wgqIQ/btsCy7vGa34/M5CmkzQ9Hnv52UXuWeiHpK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;338&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. &lt;b&gt;console.log('End!')&lt;/b&gt; 코드가 실행되고 콘솔창에 &lt;b&gt;&quot;End!&quot;를 출력&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqbsmm/btsCzHDvTey/GKpk1GGtJufGdz7Cveeq60/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqbsmm/btsCzHDvTey/GKpk1GGtJufGdz7Cveeq60/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqbsmm/btsCzHDvTey/GKpk1GGtJufGdz7Cveeq60/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bqbsmm/btsCzHDvTey/GKpk1GGtJufGdz7Cveeq60/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;338&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 모든 &lt;b&gt;메인 스레드&lt;/b&gt;의 자바스크립트 코드가 실행이되어 더이상 &lt;b&gt;Call Stack&lt;/b&gt;엔 실행할 스택이 없어 비워지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 그러면 &lt;b&gt;이벤트 핸들러&lt;/b&gt;가 이를 감지하여, &lt;b&gt;Callback Queue&lt;/b&gt;에 남아있는 &lt;b&gt;콜백 함수&lt;/b&gt;들을 빼와 &lt;b&gt;Call Stack에 적재&lt;/b&gt;하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. 이때 2종류의 큐 중 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;(Job)MicroTask Queue&lt;/b&gt;&lt;/span&gt;에 남아있는 콜백이 &lt;b&gt;우선적&lt;/b&gt;으로 처리된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLaHpu/btsCzqBYv0u/GqleACDciACUKzVoYKyokK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLaHpu/btsCzqBYv0u/GqleACDciACUKzVoYKyokK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLaHpu/btsCzqBYv0u/GqleACDciACUKzVoYKyokK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bLaHpu/btsCzqBYv0u/GqleACDciACUKzVoYKyokK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;338&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;(Job)MicroTask Queue&lt;/b&gt;&lt;/span&gt;가 비어지면, 이제 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;(Task)MacroTask Queue&lt;/span&gt;&lt;/b&gt;에 있는 콜백 함수를 &lt;b&gt;Call Stack&lt;/b&gt;에 적재시켜 실행한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuhYmp/btsCzszOFKw/2Vyx2FW5bwlHeQS8RnOdQk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuhYmp/btsCzszOFKw/2Vyx2FW5bwlHeQS8RnOdQk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuhYmp/btsCzszOFKw/2Vyx2FW5bwlHeQS8RnOdQk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cuhYmp/btsCzszOFKw/2Vyx2FW5bwlHeQS8RnOdQk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;338&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 &lt;b&gt;이벤트 루프&lt;/b&gt;다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 이벤트 루프에 &lt;b&gt;중요한 특징&lt;/b&gt;을 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Non-blocking&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Event Loop는 I/O 작업이나 타이머 등을 &lt;b&gt;비동기적&lt;/b&gt;으로 처리할 수 있게 하여,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인 스레드가 그 동안 &lt;b&gt;다른 작업&lt;/b&gt;을 계속 수행할 수 있도록 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Concurrency &amp;amp; Threading &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript는 싱글 스레드 기반이지만, Event Loop와 Callback Queue를 통해 &lt;b&gt;동시성&lt;/b&gt;을 가질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 JavaScript가 &lt;b&gt;멀티 스레드&lt;/b&gt; 언어처럼 작동할 수 있게 하며, 특히 웹 애플리케이션에서 비동기적인 작업 처리에 매우 유용하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Event-Driven Programming &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript는 &lt;b&gt;이벤트 기반 프로그래밍&lt;/b&gt;을 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 인터랙션, I/O 작업 완료 등의 이벤트에 대응하여 비동기적으로 코드를 실행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JS 이벤트 루프 시각화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 알아본 이벤트 루프를 &lt;b&gt;직접&amp;nbsp;코드를&lt;/b&gt;&amp;nbsp;&lt;b&gt;쓰고&amp;nbsp;조작&lt;/b&gt;하여,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애니메이션으로&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;&lt;b&gt;시각화&amp;nbsp;사이트&lt;/b&gt;가&amp;nbsp;있어&amp;nbsp;소개해본다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것저것&amp;nbsp;실험해보며&amp;nbsp;브라우저&amp;nbsp;내부에서&amp;nbsp;&lt;b&gt;비동기&amp;nbsp;동작&lt;/b&gt;이&amp;nbsp;어떠한&amp;nbsp;순서로&amp;nbsp;일어나는지&amp;nbsp;알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1703506386667&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7%21%21%21PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D&quot; data-og-description=&quot;&quot; data-og-host=&quot;latentflip.com&quot; data-og-source-url=&quot;http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D&quot; data-og-url=&quot;http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7%21%21%21PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7%21%21%21PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;latentflip.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=8aGhZQkoFbQ&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=8aGhZQkoFbQ&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://engineering.linecorp.com/ko/blog/dont-block-the-event-loop&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://engineering.linecorp.com/ko/blog/dont-block-the-event-loop&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/sjk5766/javascript-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%95%B5%EC%8B%AC-event-loop-%EC%A0%95%EB%A6%AC-422eb29231a8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/sjk5766/javascript-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%95%B5%EC%8B%AC-event-loop-%EC%A0%95%EB%A6%AC-422eb29231a8&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/%F0%9F%94%84-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84-%EA%B5%AC%EC%A1%B0-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://inpa.tistory.com/entry/%F0%9F%94%84-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84-%EA%B5%AC%EC%A1%B0-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://wiki.yowu.dev/ko/dev/Nodejs/event-loop&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://wiki.yowu.dev/ko/dev/Nodejs/event-loop&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/Javascript</category>
      <category>eventloop</category>
      <category>js</category>
      <category>비동기</category>
      <category>이벤트루프</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/68</guid>
      <comments>https://ilikezzi.tistory.com/68#entry68comment</comments>
      <pubDate>Mon, 25 Dec 2023 22:07:55 +0900</pubDate>
    </item>
    <item>
      <title>[SeoulSync82] Mysql DB에 이모지 저장하기 - Nest.JS</title>
      <link>https://ilikezzi.tistory.com/67</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 오랜만에 하는 포스팅이다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에&lt;b&gt; 프로젝트,&lt;/b&gt;&amp;nbsp;&lt;b&gt;회사업무,&lt;/b&gt;&amp;nbsp;&lt;b&gt;코딩테스트 준비&lt;/b&gt;때매 너무 정신없이 바빴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트는 기획이 어느정도 나오고 &lt;b&gt;한달 넘게..?&lt;/b&gt;&amp;nbsp;걸려서 &lt;b&gt;모든 API 개발을 완료&lt;/b&gt;했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 간단하게 하려고 했는데 &lt;b&gt;점점 욕심이 생겨서 API도 50개&lt;/b&gt; 넘게 생겨버렸다...^^&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-12-20 오후 9.47.30.png&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfgH5k/btsCok1HmhE/ZIl9VbkPE4DLtv1pYY7NDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfgH5k/btsCok1HmhE/ZIl9VbkPE4DLtv1pYY7NDk/img.png&quot; data-alt=&quot;Git-hub&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfgH5k/btsCok1HmhE/ZIl9VbkPE4DLtv1pYY7NDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfgH5k%2FbtsCok1HmhE%2FZIl9VbkPE4DLtv1pYY7NDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;205&quot; data-filename=&quot;스크린샷 2023-12-20 오후 9.47.30.png&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;328&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Git-hub&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예비군 동미참 가느라&lt;b&gt; 3일&lt;/b&gt; 빼고 전부 달렸네.. 따흑&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 내꺼를 만드니깐 확실히 재밌긴하다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-12-20 오후 9.08.47.png&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;1612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TCR2h/btsClYLAkKU/QL5ZQD2VUANrJfmMNNkKok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TCR2h/btsClYLAkKU/QL5ZQD2VUANrJfmMNNkKok/img.png&quot; data-alt=&quot;SeoulSync82 - AI추천&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TCR2h/btsClYLAkKU/QL5ZQD2VUANrJfmMNNkKok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTCR2h%2FbtsClYLAkKU%2FQL5ZQD2VUANrJfmMNNkKok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;864&quot; data-filename=&quot;스크린샷 2023-12-20 오후 9.08.47.png&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;1612&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SeoulSync82 - AI추천&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트에서 &lt;b&gt;&quot;테마&quot; &lt;/b&gt;를 고르는 부분이있는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 테마에 &lt;b&gt;이모지&lt;/b&gt;가 붙어있어서 해당 이모지를 &lt;b&gt;&quot;코스이름&quot;&lt;/b&gt;을 만들어줄때 붙혀주기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blpZOr/btsCo6BWsbf/Zp2A6TKJYTusnjzjQVmcek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blpZOr/btsCo6BWsbf/Zp2A6TKJYTusnjzjQVmcek/img.png&quot; data-alt=&quot;SeoulSync82 - &amp;quot;코스 결과&amp;quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blpZOr/btsCo6BWsbf/Zp2A6TKJYTusnjzjQVmcek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblpZOr%2FbtsCo6BWsbf%2FZp2A6TKJYTusnjzjQVmcek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;201&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;186&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SeoulSync82 - &quot;코스 결과&quot;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 &lt;b&gt;코스이름&lt;/b&gt;에 이모지를 붙여 줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 API 로직을 짜고 실행을 시켰더니 &lt;b&gt;에러&lt;/b&gt;가 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-12-20 오후 10.54.32.png&quot; data-origin-width=&quot;1594&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4FlHG/btsComea2SS/Rq4ye9dPNPT3hWDSW2Z221/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4FlHG/btsComea2SS/Rq4ye9dPNPT3hWDSW2Z221/img.png&quot; data-alt=&quot;Error&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4FlHG/btsComea2SS/Rq4ye9dPNPT3hWDSW2Z221/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4FlHG%2FbtsComea2SS%2FRq4ye9dPNPT3hWDSW2Z221%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;213&quot; data-filename=&quot;edited_스크린샷 2023-12-20 오후 10.54.32.png&quot; data-origin-width=&quot;1594&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Error&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엥 이게 뭐지 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;ChatGPT&lt;/b&gt; 와 &lt;b&gt;구글링&lt;/b&gt;을 해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;이모지를 저장하려면 기존의 utf8 문자셋으로는 부족합니다. &lt;br /&gt;이유는 utf8 이 MySQL에서 3바이트까지만 지원하기 때문입니다.&lt;br /&gt;대부분의 이모지는 4바이트를 필요로 하기 때문에, utf8mb4 문자셋으로 전환해야 합니다. &lt;br /&gt;이 문자셋은 모든 유니코드 문자를 지원하며, 이모지도 문제없이 저장할 수 있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;utf8 &lt;/span&gt;문자셋&lt;/b&gt;이 문제였다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MySQL&lt;/b&gt;과 &lt;b&gt;TypeORM&lt;/b&gt; 두가지 설정을 바꿔줘야지 이모지를 저장할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MySQL&amp;nbsp;문자셋&amp;nbsp;변경하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;b&gt;MySQL&lt;/b&gt;을 바꿔보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1703080875257&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 명령어로 변경이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-12-20 오후 11.02.24.png&quot; data-origin-width=&quot;868&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sbel1/btsCqtpVePd/gBqGhOeEuSdpwKV11gceE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sbel1/btsCqtpVePd/gBqGhOeEuSdpwKV11gceE1/img.png&quot; data-alt=&quot;MySQL&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sbel1/btsCqtpVePd/gBqGhOeEuSdpwKV11gceE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsbel1%2FbtsCqtpVePd%2FgBqGhOeEuSdpwKV11gceE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;103&quot; data-filename=&quot;스크린샷 2023-12-20 오후 11.02.24.png&quot; data-origin-width=&quot;868&quot; data-origin-height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MySQL&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 DB는 다행히 이미 &lt;b&gt;utf8mb4_unicode_ci&lt;/b&gt; 로 되어있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TypeORM&amp;nbsp;연결&amp;nbsp;설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NestJS&lt;/b&gt;&amp;nbsp;프로젝트에서&amp;nbsp;&lt;b&gt;TypeORM&lt;/b&gt;을&amp;nbsp;사용한다면,&amp;nbsp;연결&amp;nbsp;설정에&amp;nbsp;&lt;b&gt;utf8mb4&lt;/b&gt; 문자셋을 명시해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;app.module.ts&amp;nbsp;&lt;/b&gt;파일에서 데이터베이스 연결 설정을 다음과 같이 수정하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1703081402964&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;TypeOrmModule.forRoot({
  // 다른 설정들...
  charset: 'utf8mb4',
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 해당 연결 설정이 &lt;b&gt;기존에 없었다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;이모지 저장&lt;/b&gt;이 안됬었나보다..!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정을 하고 &lt;b&gt;저장&lt;/b&gt;을 한 후 다시 코드를 실행 시켜 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-12-20 오후 11.18.45.png&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vhl1X/btsCjYscDWE/DpKivKwjWiKSEsPri6P82k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vhl1X/btsCjYscDWE/DpKivKwjWiKSEsPri6P82k/img.png&quot; data-alt=&quot;MySQL&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vhl1X/btsCjYscDWE/DpKivKwjWiKSEsPri6P82k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvhl1X%2FbtsCjYscDWE%2FDpKivKwjWiKSEsPri6P82k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;204&quot; data-filename=&quot;스크린샷 2023-12-20 오후 11.18.45.png&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;198&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MySQL&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;DB에 이모지&lt;/b&gt;가&amp;nbsp;정상적으로 쌓였다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Project/SeoulSync82</category>
      <category>MYSQL</category>
      <category>TypeORM</category>
      <category>utf8mb4</category>
      <category>이모지</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/67</guid>
      <comments>https://ilikezzi.tistory.com/67#entry67comment</comments>
      <pubDate>Wed, 20 Dec 2023 23:21:44 +0900</pubDate>
    </item>
    <item>
      <title>[TypeOrm] loadRelationCountAndMap() - 관계된 데이터의 갯수를 쉽게 세는 방법</title>
      <link>https://ilikezzi.tistory.com/66</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-18 오전 5.34.09.png&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;820&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUrcwK/btszMbst7jc/gKeun1ENKc7KwcWyTLRZLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUrcwK/btszMbst7jc/gKeun1ENKc7KwcWyTLRZLk/img.png&quot; data-alt=&quot;TypeOrm&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUrcwK/btszMbst7jc/gKeun1ENKc7KwcWyTLRZLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUrcwK%2FbtszMbst7jc%2FgKeun1ENKc7KwcWyTLRZLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;244&quot; data-filename=&quot;스크린샷 2023-03-18 오전 5.34.09.png&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;820&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TypeOrm&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사에 백엔드파트 리더로 &lt;b&gt;전 야놀자 리더&lt;/b&gt;분께서 오셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오셔서 &lt;b&gt;코드품질&lt;/b&gt;과&lt;b&gt; 성능개선&lt;/b&gt;에 대해서 설명해주시는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그동안 내가&lt;b&gt; 쓰레기&lt;/b&gt;같은 코드들만 빨리 짜고 있었구나 싶었다.. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 요새는 기존 코드들을 하나씩 &lt;b&gt;리팩토링&lt;/b&gt;에 들어가고있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TypeOrm&lt;/b&gt;을 좀 효율적으로 잘 쓰자고 강조하셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 오늘은 TypeOrm의 &lt;b&gt;loadRelationCountAndMap() &lt;/b&gt;메서드에 대해서 포스팅을 해보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 &lt;b&gt;기존 코드&lt;/b&gt;를 먼저 확인해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기존 Code&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-05 오후 6.35.42.png&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDqjye/btszKIdAmNq/XKfTCz4Zh8GNsKxyN4fhw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDqjye/btszKIdAmNq/XKfTCz4Zh8GNsKxyN4fhw0/img.png&quot; data-alt=&quot;comment.service.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDqjye/btszKIdAmNq/XKfTCz4Zh8GNsKxyN4fhw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDqjye%2FbtszKIdAmNq%2FXKfTCz4Zh8GNsKxyN4fhw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;251&quot; data-filename=&quot;스크린샷 2023-11-05 오후 6.35.42.png&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;comment.service.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사진속 코드에 대해서 설명을 하자면 &lt;b&gt;투표 댓글 작성 API&lt;/b&gt; 인데,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;존재하지 않는 투표&lt;/b&gt;거나, &lt;b&gt;종료된 투표가 내가 참여한 투표가 아니면&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;댓글을 &lt;b&gt;못달게&lt;/b&gt; 에러를 return하는 로직이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;vote &lt;b&gt;Repository &lt;/b&gt;/ voting Repository&lt;/b&gt;로 &lt;b&gt;두번 DB Connection&lt;/b&gt;이 이뤄지는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 &lt;b&gt;한번만 Connection&lt;/b&gt; 하도록 효율적으로 리팩토링을 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;loadRelationCountAndMap()&lt;/b&gt; 메서드를 사용한 리팩토링한 코드를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리팩토링한 code&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-05 오후 6.53.18.png&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUclBR/btszKJjiuvi/jGSFcVz0YgCap1lmM0ZWKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUclBR/btszKJjiuvi/jGSFcVz0YgCap1lmM0ZWKk/img.png&quot; data-alt=&quot;comment.service.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUclBR/btszKJjiuvi/jGSFcVz0YgCap1lmM0ZWKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUclBR%2FbtszKJjiuvi%2FjGSFcVz0YgCap1lmM0ZWKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;257&quot; data-filename=&quot;스크린샷 2023-11-05 오후 6.53.18.png&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;comment.service.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-05 오후 6.56.52.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wZNnY/btszK7dakaL/wOlQucsVyQSKpUxvdNkPek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wZNnY/btszK7dakaL/wOlQucsVyQSKpUxvdNkPek/img.png&quot; data-alt=&quot;vote.query.repository.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wZNnY/btszK7dakaL/wOlQucsVyQSKpUxvdNkPek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwZNnY%2FbtszK7dakaL%2FwOlQucsVyQSKpUxvdNkPek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;182&quot; data-filename=&quot;스크린샷 2023-11-05 오후 6.56.52.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;vote.query.repository.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 기존과 다르게 한개의&amp;nbsp;&lt;b&gt;repository &lt;/b&gt;로만 &lt;b&gt;connection&lt;/b&gt;이 이뤄진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 왜 될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;loadRelationCountAndMap()&amp;nbsp;&lt;/b&gt;를 사용해서 &lt;b&gt;가상의 속성을 매핑&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 들으면 무슨소리인지 모를테니 좀 더 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;loadRelationCountAndMap()&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특정&amp;nbsp;엔티티&lt;/b&gt;와&amp;nbsp;&lt;b&gt;연결된&amp;nbsp;관계의&amp;nbsp;수&lt;/b&gt;를 쉽게 계산하고, 그 결과를 엔티티의 속성에 매핑해주는 기능을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 복잡한 쿼리를 작성하지 않고도 관계의 수를 쉽게 얻을 수 있 다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-05 오후 7.11.10.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBQews/btszJ2wTFWI/USI9bS0Nt7NaFYEmHqlL70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBQews/btszJ2wTFWI/USI9bS0Nt7NaFYEmHqlL70/img.png&quot; data-alt=&quot;vote.entity&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBQews/btszJ2wTFWI/USI9bS0Nt7NaFYEmHqlL70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBQews%2FbtszJ2wTFWI%2FUSI9bS0Nt7NaFYEmHqlL70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;68&quot; data-filename=&quot;스크린샷 2023-11-05 오후 7.11.10.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;122&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;vote.entity&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-05 오후 7.11.44.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yo76T/btszK7RKMkD/69SKkxUUrxs4J7gckpgWJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yo76T/btszK7RKMkD/69SKkxUUrxs4J7gckpgWJK/img.png&quot; data-alt=&quot;voting.entity&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yo76T/btszK7RKMkD/69SKkxUUrxs4J7gckpgWJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fyo76T%2FbtszK7RKMkD%2F69SKkxUUrxs4J7gckpgWJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;90&quot; data-filename=&quot;스크린샷 2023-11-05 오후 7.11.44.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;154&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;voting.entity&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;loadRelationCountAndMap()&lt;/b&gt;를 사용하려면 &lt;b&gt;각각 엔티티&lt;/b&gt;에서 속성이 추가되어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@OneToMany&lt;/b&gt;와&amp;nbsp;&lt;b&gt;@ManyToOne&lt;/b&gt;은&amp;nbsp;TypeORM에서&amp;nbsp;제공하는&amp;nbsp;데코레이터로,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티 간의 &lt;b&gt;1:N(N:1) 관계&lt;/b&gt;를 정의해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;loadRelationCountAndMap()&lt;/b&gt; 은 이러한 &lt;b&gt;관계&lt;/b&gt;를 바탕으로 하여,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연관된 엔티티의 개수를 세어 그 결과를 &lt;b&gt;특정 엔티티의 속성으로 매핑&lt;/b&gt;하는 기능을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;엔티티 준비&lt;/b&gt;가 끝났으니 사용법을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699180146579&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// VoteEntity 내부에 voted 속성을 추가해야 한다.
@Entity()
export class VoteEntity {
  // ... 기타 필드들 ...

  // 가상 속성을 추가
  voted?: number;
}

// Service 또는 Repository 내부
async function findVoteAndVotingCount(voteId: string, userId: string) {
  return await this.repository
    .createQueryBuilder(&quot;vote&quot;)
    .loadRelationCountAndMap(
      &quot;vote.voted&quot;, // 매핑될 속성
      &quot;vote.votings&quot;, // 관계 경로
      &quot;voting&quot;, // 쿼리 빌더 내에서 사용될 별칭
      (qb) =&amp;gt; qb.andWhere(&quot;voting.userId = :userId&quot;, { userId }) // 조건을 적용하기 위한 콜백 함수
    )
    .getOne();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loadRelationCountAndMap()은 &lt;b&gt;세 가지 주요 인자&lt;/b&gt;를 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 매핑될 속성의 이름&amp;nbsp;&lt;/b&gt;- 결과가 매핑될 엔티티 내의 속성 이름.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;이름은&amp;nbsp;&quot;entityName.propertyName&quot;&amp;nbsp;형태로&amp;nbsp;지정돼야&amp;nbsp;하며,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;entityName은&amp;nbsp;TypeORM&amp;nbsp;쿼리&amp;nbsp;빌더에서&amp;nbsp;사용된&amp;nbsp;&lt;b&gt;별칭&lt;/b&gt;(alias)이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-05 오후 7.29.55.png&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;104&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/An0of/btszI158873/Wc6yABOGBbRzstkIMd8NF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/An0of/btszI158873/Wc6yABOGBbRzstkIMd8NF0/img.png&quot; data-alt=&quot;vote.entity&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/An0of/btszI158873/Wc6yABOGBbRzstkIMd8NF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAn0of%2FbtszI158873%2FWc6yABOGBbRzstkIMd8NF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;68&quot; data-filename=&quot;스크린샷 2023-11-05 오후 7.29.55.png&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;104&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;vote.entity&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식은 &lt;b&gt;voteEntity에 새 속성을 추가&lt;/b&gt;시켜준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 관계(relation)의 경로&lt;/b&gt; - 카운트될 관계의 경로. &quot;entity.relation&quot; 형태로 작성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-05 오후 7.11.10.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBQews/btszJ2wTFWI/USI9bS0Nt7NaFYEmHqlL70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBQews/btszJ2wTFWI/USI9bS0Nt7NaFYEmHqlL70/img.png&quot; data-alt=&quot;vote.entity&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBQews/btszJ2wTFWI/USI9bS0Nt7NaFYEmHqlL70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBQews%2FbtszJ2wTFWI%2FUSI9bS0Nt7NaFYEmHqlL70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;68&quot; data-filename=&quot;스크린샷 2023-11-05 오후 7.11.10.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;122&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;vote.entity&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;아까&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;@OnetoMany&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;votings &lt;/b&gt;라고 이름을 정해주었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 조건을 추가할 수 있는 콜백 함수&lt;/b&gt; &lt;b&gt;(선택적)&lt;/b&gt; (QueryBuilder를 인자로 받는 함수)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 필요한 경우 특정 조건을 적용하기 위해 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 가지 주요 인자에 대해서 알아봤으니 그 다음 &lt;b&gt;qb.andWhere&amp;nbsp;&lt;/b&gt;를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;andWhere 메소드&lt;/b&gt;를 사용해서&lt;b&gt; voting.userId&lt;/b&gt;가 파라미터로 받아온 &lt;b&gt;userId&lt;/b&gt;와 일치하는 조건을 쿼리에 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 특정 사용자가 투표한 것만 세겠다는 의미다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제&lt;b&gt; loadRelationCountAndMap()&lt;/b&gt;의 &lt;b&gt;장점&lt;/b&gt;을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;성능 향상&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별도의&amp;nbsp;카운트&amp;nbsp;쿼리를&amp;nbsp;실행하지&amp;nbsp;않고도&amp;nbsp;관련&amp;nbsp;데이터의&amp;nbsp;수를&amp;nbsp;가져올&amp;nbsp;수&amp;nbsp;있어서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에 대한 &lt;b&gt;요청 횟수가 줄어&lt;/b&gt;들고, 결과적으로 애플리케이션의 &lt;b&gt;성능이 향상된다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 코드 간결성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관계&amp;nbsp;수를&amp;nbsp;셀&amp;nbsp;때&amp;nbsp;필요한&amp;nbsp;&lt;b&gt;추가적인&amp;nbsp;쿼리&amp;nbsp;작성&amp;nbsp;없이&lt;/b&gt;&amp;nbsp;명확한&amp;nbsp;API를&amp;nbsp;통해&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직관적으로 카운트를 할 수 있어서 코드가 훨씬 간결해진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 유연성&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loadRelationCountAndMap는&amp;nbsp;콜백&amp;nbsp;함수를&amp;nbsp;통해&amp;nbsp;특정&amp;nbsp;조건에&amp;nbsp;맞는&amp;nbsp;카운트만을&amp;nbsp;셀&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;해서,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동적인 쿼리 생성&lt;/b&gt;이 가능해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로&lt;b&gt; loadRelationCountAndMap()&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;의&lt;b&gt;&lt;span&gt; 주의할 점&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 복잡한 쿼리 성능 저하&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약에 매우 &lt;b&gt;복잡한 조건이나 많은 양의 조인&lt;/b&gt;이 필요한 경우, loadRelationCountAndMap 메소드는 성능이 저하될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 땐 성능을 위해 별도의 최적화된 쿼리를 작성하는 것이 좋을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 인덱싱과 최적화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loadRelationCountAndMap를 사용할 때는 관련 테이블에 &lt;b&gt;적절한 인덱스&lt;/b&gt;가 설정되어 있는지 확인해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지 않으면 카운트를 계산할 때 성능 문제가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 오버페칭 문제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 쿼리로 많은 데이터와 그 관계를 가져올 경우, 실제로 &lt;b&gt;필요하지 않은 데이터까지&lt;/b&gt; 가져오는 오버페칭 문제가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 어떤 데이터가 실제로 필요한지 잘 파악하고 쿼리를 작성해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 엔티티 설계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loadRelationCountAndMap를 사용하기 위해서는 &lt;b&gt;엔티티 간의 관계가 올바르게 매핑&lt;/b&gt;되어 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때때로 이런 관계 설정이 복잡할 수 있는데, 이때 잘못 설계되면 예상치 못한 결과가 나올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;loadRelationCountAndMap() 메서드&lt;/b&gt;에 대해서 자세히 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로도 &lt;b&gt;엔티티 관계&lt;/b&gt;가 잡혀있고 &lt;b&gt;여러 Connection&lt;/b&gt;을 해야할 경우엔&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loadRelationCountAndMap() 를 사용하여 &lt;b&gt;효율성 높은 코드&lt;/b&gt;를 짜야겠다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/TypeOrm</category>
      <category>loadRelationCountAndMap()</category>
      <category>TypeORM</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/66</guid>
      <comments>https://ilikezzi.tistory.com/66#entry66comment</comments>
      <pubDate>Sun, 5 Nov 2023 19:53:37 +0900</pubDate>
    </item>
    <item>
      <title>[Nest.JS] 구글, 네이버, 카카오 소셜로그인 구현 - 2</title>
      <link>https://ilikezzi.tistory.com/65</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.15.54.png&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5mdqO/btszHHlTXoQ/wM2O7Q825REK1WWdaFydAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5mdqO/btszHHlTXoQ/wM2O7Q825REK1WWdaFydAK/img.png&quot; data-alt=&quot;Nest.JS&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5mdqO/btszHHlTXoQ/wM2O7Q825REK1WWdaFydAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5mdqO%2FbtszHHlTXoQ%2FwM2O7Q825REK1WWdaFydAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;257&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.15.54.png&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;860&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Nest.JS&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소셜로그인 1편에 이어서 바로 2편을 포스팅하려 했는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;refresh_token&lt;/b&gt;과 &lt;b&gt;JWT 전략&lt;/b&gt;에 대해서 이것저것 머리싸매면서 고민하느라 늦어졌다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 다양한 JWT 전략과&lt;b&gt; 고민할 사항&lt;/b&gt;이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;한 계정으로 여러 디바이스에서 로그인&lt;/b&gt;을 할 수도 있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;access_Token 만료시 refresh-API 실행 타이밍&lt;/b&gt;을 &lt;b&gt;백엔드&lt;/b&gt;에서 만료를 체크해서 할 지,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니면 &lt;b&gt;프론트엔드&lt;/b&gt;에서 access_Token&amp;nbsp;&lt;b&gt;&quot;exp&quot;&lt;/b&gt;로 만료 체크해서 API 요청할지 등등...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 본론으로 들어가기전에 &lt;b&gt;소설로그인 1편&lt;/b&gt;을 꼭 보고오시길 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/64&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ilikezzi.tistory.com/64&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1699042242750&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Nest.JS] 구글, 네이버, 카카오 소셜로그인 구현 - 1&quot; data-og-description=&quot;진행중인 사이드 프로젝트에서 기획이 끝나서 화면기획서가 나오고, 디자인쪽도 피그마로 UI/UX 디자인을 시작하고, 개발쪽도 DB ERD 설계, 서버설계, Stg서버 등등.. 기본적인 개발하기 위한 준비&quot; data-og-host=&quot;ilikezzi.tistory.com&quot; data-og-source-url=&quot;https://ilikezzi.tistory.com/64&quot; data-og-url=&quot;https://ilikezzi.tistory.com/64&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c3kSdu/hyUrFsn65C/KmfEQr2f2FkiuGkwbKvWZ1/img.png?width=800&amp;amp;height=446&amp;amp;face=0_0_800_446,https://scrap.kakaocdn.net/dn/sjKxT/hyUnNFBfED/MmARLEBryp4Ou1s3pshSpk/img.png?width=800&amp;amp;height=446&amp;amp;face=0_0_800_446,https://scrap.kakaocdn.net/dn/PlvEB/hyUrp39s6z/EehrOobXeZrmJq9VvOKpuK/img.png?width=1030&amp;amp;height=1344&amp;amp;face=0_0_1030_1344&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/64&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ilikezzi.tistory.com/64&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c3kSdu/hyUrFsn65C/KmfEQr2f2FkiuGkwbKvWZ1/img.png?width=800&amp;amp;height=446&amp;amp;face=0_0_800_446,https://scrap.kakaocdn.net/dn/sjKxT/hyUnNFBfED/MmARLEBryp4Ou1s3pshSpk/img.png?width=800&amp;amp;height=446&amp;amp;face=0_0_800_446,https://scrap.kakaocdn.net/dn/PlvEB/hyUrp39s6z/EehrOobXeZrmJq9VvOKpuK/img.png?width=1030&amp;amp;height=1344&amp;amp;face=0_0_1030_1344');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Nest.JS] 구글, 네이버, 카카오 소셜로그인 구현 - 1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;진행중인 사이드 프로젝트에서 기획이 끝나서 화면기획서가 나오고, 디자인쪽도 피그마로 UI/UX 디자인을 시작하고, 개발쪽도 DB ERD 설계, 서버설계, Stg서버 등등.. 기본적인 개발하기 위한 준비&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;refresh_token&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소셜로그인 1편을 보고왔으면 알겠지만, 나는&lt;b&gt; refresh_token&lt;/b&gt;을 쓰기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;b&gt;refresh_token&lt;/b&gt;은 뭐고 왜 쓰는것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;refresh_token&lt;/b&gt;은 단어 뜻 그대로 &lt;b&gt;새로고침 토큰&lt;/b&gt;이라고 보면 좋을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;access_token&lt;/b&gt;은 보호된 자원에 액세스 하는데 필요한 인증 수단이지만, 해당 토큰을 가지고 있는 사람이라면 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;누구든지&lt;/span&gt;&lt;/b&gt; 해당 자원에 접근할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 특성 때문에 악의적인 사용자가 시스템을 침해하고 &lt;b&gt;access_token&lt;/b&gt;을 훔쳐서 접근을 하지 못하도록 막기 위한 적절한 조치가 필요한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 &lt;b&gt;적절한 조치&lt;/b&gt;가 있지만 그 중 하나인 &lt;b&gt;access_token&lt;/b&gt;의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;만료시간을 짧게&lt;/b&gt;&lt;/span&gt; 설정하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 기존의 &lt;b&gt;access_token&lt;/b&gt;이 탈취 당하더라도 새로운 &lt;b&gt;access_token만이 자원에 액세스&lt;/b&gt;할 수 있게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b&gt;단점&lt;/b&gt;도 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만료시간을 짧게 설정하면 &lt;b&gt;보안적 측면에서는 좋겠지만&lt;/b&gt;,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;유저 경험&quot;&lt;/b&gt; 즉 ,&lt;b&gt;UX&lt;/b&gt; 측면에선 굉장히 &lt;b&gt;불편&lt;/b&gt;할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단점을 개선하기 위해 등장한 것이 바로 &lt;b&gt;&quot;refresh_token&quot;&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;JWT 전략&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;JWT 전략&lt;/b&gt;을 사용하면 서버가 세션 상태를 유지할 필요가 없기 때문에 확장성 있는 어플리케이션을 만드는 데 좋고,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 시스템 간에&lt;b&gt; 토큰을 전달하기 용이&lt;/b&gt;하다는 점을 강조할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 앞서 얘기한대로 한 번 발급된 토큰은 &lt;b&gt;그 자체로 인증 수단&lt;/b&gt;이 되기 때문에, &lt;b&gt;보안에 더 신경&lt;/b&gt;을 써야 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토큰이 탈취되면 &lt;b&gt;악용&lt;/b&gt;될 수 있다는 점도 주의해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 &lt;b&gt;refresh_token&lt;/b&gt;을 가지고 &lt;b&gt;JWT전략&lt;/b&gt;을 어떻게 짰는지 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 유저가 &lt;b&gt;첫 로그인시 access_token, refresh_token 발급&lt;/b&gt;해 줄 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&lt;b&gt; access_token은 클라이언트에서 저장&lt;/b&gt;을 하고 &lt;b&gt;refresh_token은 DB&lt;/b&gt;에 쌓는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 각각의 &lt;b&gt;토큰 만료&lt;/b&gt;는 access_token: &lt;b&gt;1시간&lt;/b&gt; , refresh_token: &lt;b&gt;14일&lt;/b&gt;로 정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4.&lt;b&gt; refresh_token은 쿠키에 저장&lt;/b&gt;을 하고 만료기간은 &lt;b&gt;동일하게 14일&lt;/b&gt;로 정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. Access token의 &lt;b&gt;payload안에 &amp;ldquo;exp&amp;rdquo;&lt;/b&gt;정보도 담아서 이 값으로 &lt;b&gt;프론트에서 만료체크&lt;/b&gt;를 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만료되었으면 &lt;b&gt;refresh-API&lt;/b&gt;로 access_token을 &lt;b&gt;재발급&lt;/b&gt;해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. &lt;b&gt;refresh-API &lt;/b&gt;실행시 &lt;b&gt;refresh_token도 만료&lt;/b&gt;되었으면 &lt;b&gt;재로그인&lt;/b&gt;을 하게끔 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. &lt;b&gt;refresh-API&lt;/b&gt;실행시 &lt;b&gt;refresh_token&lt;/b&gt;이 다르면 &lt;b&gt;재로그인&lt;/b&gt;을 하게끔 한다. (여러 디바이스 동시로그인 방지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. &lt;b&gt;로그아웃 API&lt;/b&gt;는 DB와 쿠키의 있는&amp;nbsp;&lt;b&gt;refresh_token&lt;/b&gt;을 지워버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지가 내가 세운 &lt;b&gt;JWT 전략&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Code&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 바로 코드로 확인해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699044834997&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// auth.controller.ts

@Get('/user/login/google')
  @ApiOperation({
    summary: '구글 로그인',
    description: '구글 로그인',
  })
  @UseGuards(AuthGuard('google'))
  async googleAuth(@Req() _req: Request) {}

  /* Get Google Auth Callback */
  @Get('/auth/google/callback')
  @UseGuards(AuthGuard('google'))
  async googleAuthCallback(
    @Req() req: GoogleRequest,
    @Res() res: Response, // : Promise&amp;lt;GoogleLoginAuthOutputDto&amp;gt;
  ) {
    const result = await this.authService.googleLogin(req, res);
    return res.json(result);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699044712406&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// auth.service.ts

async googleLogin(
    req: GoogleRequest,
    res: Response,
  ) {
    try {
      req.user.nickname = req.user.firstName + req.user.lastName;
      const { user } = req;
      delete user.lastName;
      delete user.firstName;
      user.type = 'google';

      // 유저 중복 검사
      let findUser = await this.userQueryRepository.findUser(user);

      // 없는 유저면 DB에 유저정보 저장
      if (!findUser) {
        const uuid = generateUUID();
        findUser = await this.userQueryRepository.createUser(user, uuid);
      }

      // 구글 가입이 되어 있는 경우 accessToken 및 refreshToken 발급
      const findUserPayload = {
        id: findUser.id,
        uuid: findUser.uuid,
        nickname: findUser.name,
        profile_image: findUser.profile_image,
      };
      const eid_access_token = jwt.sign(findUserPayload, this.configService.get('JWT_SECRET'), {
        expiresIn: this.configService.get('JWT_ACCESS_TOKEN_EXPIRATION_TIME'),
      });
      const eid_refresh_token = jwt.sign({}, this.configService.get('JWT_REFRESH_KEY'), {
        expiresIn: this.configService.get('JWT_REFRESH_TOKEN_EXPIRATION_TIME'),
        audience: String(findUser.id),
      });

      /* refreshToken 필드 업데이트 */
      findUser.eid_refresh_token = eid_refresh_token;
      await this.userQueryRepository.save(findUser);

      // 쿠키 설정
      const now = new Date();
      now.setDate(
        now.getDate() +
          parseInt(this.configService.get('JWT_REFRESH_TOKEN_EXPIRATION_DATE')) / 1000,
      );
      console.log(this.configService.get('JWT_REFRESH_TOKEN_EXPIRATION_DATE'));
      res.cookie('eid_refresh_token', eid_refresh_token, {
        expires: now,
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production' ? true : false,
        sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax',
      });
      return {
        ok: true,
        eid_access_token,
      };
    } catch (error) {
      return { ok: false, error: '구글 로그인 인증을 실패 하였습니다.' };
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;소셜로그인 1편 포스팅&lt;/b&gt;에서 &lt;b&gt;DB에 유저정보&lt;/b&gt; 쌓는거 까지 다뤘으니 그 다음부터 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-04 오전 5.58.27.png&quot; data-origin-width=&quot;1412&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3E4xK/btszGPdqJ9v/C1XkUSfk7CkNSubGfszkB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3E4xK/btszGPdqJ9v/C1XkUSfk7CkNSubGfszkB1/img.png&quot; data-alt=&quot;auth.service.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3E4xK/btszGPdqJ9v/C1XkUSfk7CkNSubGfszkB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3E4xK%2FbtszGPdqJ9v%2FC1XkUSfk7CkNSubGfszkB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;222&quot; data-filename=&quot;스크린샷 2023-11-04 오전 5.58.27.png&quot; data-origin-width=&quot;1412&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;auth.service.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;findUserPayload&lt;/b&gt;에는 &lt;b&gt;access_token&lt;/b&gt;에 담을 정보들을 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;refresh_token&lt;/b&gt;에는 굳이 &lt;b&gt;findUserPayload&amp;nbsp;&lt;/b&gt;이 정보를 다 담을 필요가 없어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;audience&lt;/b&gt;만 지정해줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게&amp;nbsp;설정하면&amp;nbsp;나중에&amp;nbsp;백엔드에서 이&amp;nbsp;&lt;b&gt;audience값&lt;/b&gt;을&amp;nbsp;검증해서,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요청을 보낸 사용자의 ID&lt;/b&gt;와 일치하는지를 확인해 해당 토큰이 &lt;b&gt;맞는 사용자에게 발급&lt;/b&gt;된 건지 &lt;b&gt;확인&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 6.03.37.png&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bw9hs9/btszMdi37p8/j3tYLFhDSZe57VdXkjYIvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bw9hs9/btszMdi37p8/j3tYLFhDSZe57VdXkjYIvk/img.png&quot; data-alt=&quot;.env.debug&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bw9hs9/btszMdi37p8/j3tYLFhDSZe57VdXkjYIvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbw9hs9%2FbtszMdi37p8%2Fj3tYLFhDSZe57VdXkjYIvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;161&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 6.03.37.png&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;.env.debug&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;만료기간&lt;/b&gt;은 env파일에서 &lt;b&gt;access_token 1시간&lt;/b&gt;, &lt;b&gt;refresh_token 14일&lt;/b&gt;로 지정해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-04 오전 6.06.07.png&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PM84U/btszJYnjGL4/dNKgDEN1Y5QLMu1olU6cZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PM84U/btszJYnjGL4/dNKgDEN1Y5QLMu1olU6cZ0/img.png&quot; data-alt=&quot;auth.service.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PM84U/btszJYnjGL4/dNKgDEN1Y5QLMu1olU6cZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPM84U%2FbtszJYnjGL4%2FdNKgDEN1Y5QLMu1olU6cZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;512&quot; data-filename=&quot;스크린샷 2023-11-04 오전 6.06.07.png&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;auth.service.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키설정의 만료기간도 &lt;b&gt;refresh_token에서 사용하던 14일&lt;/b&gt;을 동일하게 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;httpOnly&lt;/b&gt;: 이 옵션을 true로 설정하면, 쿠키에 &lt;b&gt;자바스크립트로 접근할 수 없다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XSS&amp;nbsp;공격을&amp;nbsp;방지하기&amp;nbsp;위한&amp;nbsp;&lt;b&gt;중요한 설정이다&lt;/b&gt;.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;secure&lt;/b&gt;: 이 속성이 true일 때, 쿠키는 &lt;b&gt;HTTPS&lt;/b&gt; 프로토콜을 통해서만 전송된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발&amp;nbsp;환경에서는&amp;nbsp;굳이&amp;nbsp;HTTPS가&amp;nbsp;아니어도&amp;nbsp;되니까,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;process.env.NODE_ENV&amp;nbsp;===&amp;nbsp;'production'&amp;nbsp;조건을&amp;nbsp;통해&amp;nbsp;&lt;b&gt;프로덕션&amp;nbsp;환경에서만&amp;nbsp;true&lt;/b&gt;로 설정되게 해놨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;sameSite&lt;/b&gt;: 이 옵션은 &lt;b&gt;CSRF&lt;/b&gt; 공격을 방지하는 데 도움을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게해서 &lt;b&gt;로그인&lt;/b&gt; 할 때는 끝이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 로그인 연장하는&lt;b&gt; refresh API&lt;/b&gt;를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699046077287&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  // auth.controller.ts
  
  @Post('/user/refresh')
  @ApiOperation({
    summary: '로그인 연장',
    description: '로그인 연장',
  })
  async silentRefresh(@Req() req: Request, @Res({ passthrough: true }) res: Response) {
    return await this.authService.silentRefresh(req, res);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699046126083&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// auth.service.ts

async silentRefresh(req: Request, res: Response): Promise&amp;lt;SilentRefreshAuthOutputDto&amp;gt; {
    try {
      // refreshToken 유효성 검사
      const getRefreshToken = req.cookies['eid_refresh_token'];
      if (isEmpty(getRefreshToken)) {
        return { ok: false };
      }
      let userId: string | string[] | null;
      jwt.verify(
        getRefreshToken,
        this.configService.get('JWT_REFRESH_KEY'),
        (err: jwt.VerifyErrors | null, decoded: jwt.JwtPayload | undefined) =&amp;gt; {
          if (err) {
            res.clearCookie('eid_refresh_token');
            return { ok: false, error: '토큰이 유효하지 않습니다. 로그인이 필요합니다' };
          }
          userId = decoded.aud;
        },
      );

      // 로그아웃 후에는 Silent Refresh를 무시
      const loginUser = await this.userQueryRepository.findId(+userId);
      if (loginUser.eid_refresh_token !== getRefreshToken) {
        return { ok: false, error: '토큰이 유효하지 않습니다. 로그인이 필요합니다' };
      }

      // accessToken 재발급
      const payload = {
        id: loginUser.id,
        uuid: loginUser.uuid,
        nickname: loginUser.name,
        profile_image: loginUser.profile_image,
      };
      const eid_access_token = jwt.sign(payload, this.configService.get('JWT_SECRET'), {
        expiresIn: this.configService.get('JWT_ACCESS_TOKEN_EXPIRATION_TIME'),
      });

      return {
        ok: true,
        eid_access_token,
      };
    } catch (error) {
      console.log(error);
      return { ok: false, error: '로그인 연장에 실패하였습니다.' };
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 하나씩 무슨코드인지 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-04 오전 6.18.14.png&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYttBG/btszM1JyY46/3rSKQS1haSqM453f0lttVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYttBG/btszM1JyY46/3rSKQS1haSqM453f0lttVk/img.png&quot; data-alt=&quot;auth.service.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYttBG/btszM1JyY46/3rSKQS1haSqM453f0lttVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYttBG%2FbtszM1JyY46%2F3rSKQS1haSqM453f0lttVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;337&quot; data-filename=&quot;스크린샷 2023-11-04 오전 6.18.14.png&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;632&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;auth.service.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 API는 &lt;b&gt;Req로 쿠키값&lt;/b&gt;만 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 &lt;b&gt;refresh_token&lt;/b&gt; 발급할 때&amp;nbsp;&lt;b&gt;audience&amp;nbsp;&lt;/b&gt;를 넣은 이유가 이제 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;JWT의 유효성을 검증&lt;/b&gt;을 하고 이상이 없으면&lt;b&gt; userId&lt;/b&gt;에 &lt;b&gt;audience&lt;/b&gt;를 담아준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-04 오전 6.27.18.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKliDA/btszLWIv7PM/eMG4Ky52Gwj5N2HqAR9BJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKliDA/btszLWIv7PM/eMG4Ky52Gwj5N2HqAR9BJk/img.png&quot; data-alt=&quot;auth.service.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKliDA/btszLWIv7PM/eMG4Ky52Gwj5N2HqAR9BJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKliDA%2FbtszLWIv7PM%2FeMG4Ky52Gwj5N2HqAR9BJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;383&quot; data-filename=&quot;스크린샷 2023-11-04 오전 6.27.18.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;822&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;auth.service.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;userId로&lt;b&gt; DB에서 유저정보&lt;/b&gt;를 찾고 &lt;b&gt;쿠키의 refresh_token&lt;/b&gt;이랑 &lt;b&gt;DB의 refresh_token&lt;/b&gt;이랑 비교를한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값이 다를 경우엔&amp;nbsp;&lt;b&gt;다른 디바이스로 로그인&lt;/b&gt; 한 것이므로 &lt;b&gt;로그인이 필요하다고 return&lt;/b&gt; 시켜준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;access_token 재발급&lt;/b&gt;을 해줄때는 기존과 동일하게 &lt;b&gt;payload와 만료시간&lt;/b&gt;을 설정하고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;새 토큰을 return &lt;/b&gt;해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;refresh API&lt;/b&gt;는 끝이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마지막으로 &lt;b&gt;로그아웃 API&lt;/b&gt;를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699047734699&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// auth.controller.ts

@UseGuards(JwtAuthGuard)
  @ApiBearerAuth('access-token')
  @Post('user/logout')
  @ApiOperation({
    summary: '로그아웃',
    description: '로그아웃',
  })
  async logout(
    @Res({ passthrough: true }) res: Response,
    @CurrentUser() user,
  ): Promise&amp;lt;LogoutAuthOutputDto&amp;gt; {
    return await this.authService.logout(user, res);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699047752365&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// auth.service.ts

async logout(user, res): Promise&amp;lt;LogoutAuthOutputDto&amp;gt; {
    try {
      if (isEmpty(user.id)) return { ok: false, error: '접근 권한을 가지고 있지 않습니다' };

      const loginUser = await this.userQueryRepository.findId(user.id);
      loginUser.eid_refresh_token = null;
      await this.userQueryRepository.save(loginUser);
      res.clearCookie('refreshToken');
      return { ok: true };
    } catch (error) {
      console.log(error);
      return { ok: false, error: '로그아웃을 실패하였습니다' };
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-04 오전 6.43.15.png&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FN4km/btszHsWUCKA/JRYuZoB4yBS9VNXZFbWyAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FN4km/btszHsWUCKA/JRYuZoB4yBS9VNXZFbWyAk/img.png&quot; data-alt=&quot;auth.service.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FN4km/btszHsWUCKA/JRYuZoB4yBS9VNXZFbWyAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFN4km%2FbtszHsWUCKA%2FJRYuZoB4yBS9VNXZFbWyAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;263&quot; data-filename=&quot;스크린샷 2023-11-04 오전 6.43.15.png&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;auth.service.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그아웃 API는 &lt;b&gt;@UseGuards(JwtAuthGuard)&lt;/b&gt;로 토큰이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정상적인 &lt;b&gt;access_token&lt;/b&gt; 인지 체크하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 유저&lt;b&gt;DB의 refresh_token&lt;/b&gt;과 &lt;b&gt;쿠키의 refresh_token&lt;/b&gt;을 초기화 시켜주면 끝이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;결과 확인&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 전부 끝났으니 정상 작동하는지 &lt;b&gt;결과&lt;/b&gt;를 확인해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 로그인&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X22Rq/btszHR3gBX8/V3DldDQEkQKatRQzu5gkwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X22Rq/btszHR3gBX8/V3DldDQEkQKatRQzu5gkwk/img.png&quot; data-alt=&quot;On-boarding 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X22Rq/btszHR3gBX8/V3DldDQEkQKatRQzu5gkwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX22Rq%2FbtszHR3gBX8%2FV3DldDQEkQKatRQzu5gkwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;383&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;912&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;On-boarding 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 6.47.46.png&quot; data-origin-width=&quot;1014&quot; data-origin-height=&quot;1352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ol1Hp/btszLYsMxND/0ia09DENxBVZJoS2g8RYlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ol1Hp/btszLYsMxND/0ia09DENxBVZJoS2g8RYlK/img.png&quot; data-alt=&quot;google-login&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ol1Hp/btszLYsMxND/0ia09DENxBVZJoS2g8RYlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fol1Hp%2FbtszLYsMxND%2F0ia09DENxBVZJoS2g8RYlK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;533&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 6.47.46.png&quot; data-origin-width=&quot;1014&quot; data-origin-height=&quot;1352&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;google-login&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 6.58.20.png&quot; data-origin-width=&quot;1718&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcLvBO/btszKd5szCe/QKpSwWRkN5PTZYmzNCCcL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcLvBO/btszKd5szCe/QKpSwWRkN5PTZYmzNCCcL1/img.png&quot; data-alt=&quot;클라이언트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcLvBO/btszKd5szCe/QKpSwWRkN5PTZYmzNCCcL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcLvBO%2FbtszKd5szCe%2FQKpSwWRkN5PTZYmzNCCcL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;61&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 6.58.20.png&quot; data-origin-width=&quot;1718&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;클라이언트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 6.59.35.png&quot; data-origin-width=&quot;1696&quot; data-origin-height=&quot;120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oOqaI/btszI1q39o4/X3yRXFrshOnspjuPQbpi1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oOqaI/btszI1q39o4/X3yRXFrshOnspjuPQbpi1K/img.png&quot; data-alt=&quot;user DB&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oOqaI/btszI1q39o4/X3yRXFrshOnspjuPQbpi1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoOqaI%2FbtszI1q39o4%2FX3yRXFrshOnspjuPQbpi1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;42&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 6.59.35.png&quot; data-origin-width=&quot;1696&quot; data-origin-height=&quot;120&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;user DB&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인시 &lt;b&gt;클라이언트엔 access_token&lt;/b&gt;, &lt;b&gt;DB엔 refresh_token&lt;/b&gt;이 정상적으로 쌓였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. refresh-API&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-04 오전 7.04.13.png&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxjYWs/btszHTUjj7W/xLbtudhXkfWByKYbK4h7fK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxjYWs/btszHTUjj7W/xLbtudhXkfWByKYbK4h7fK/img.png&quot; data-alt=&quot; access_token 재발급 &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxjYWs/btszHTUjj7W/xLbtudhXkfWByKYbK4h7fK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxjYWs%2FbtszHTUjj7W%2FxLbtudhXkfWByKYbK4h7fK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;610&quot; data-filename=&quot;스크린샷 2023-11-04 오전 7.04.13.png&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; access_token 재발급 &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-11-04 오전 7.06.01.png&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnF7Fb/btszK2vAf7T/qdp5QkQZE25UT9kAtN0pP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnF7Fb/btszK2vAf7T/qdp5QkQZE25UT9kAtN0pP0/img.png&quot; data-alt=&quot;만료된 refresh_token&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnF7Fb/btszK2vAf7T/qdp5QkQZE25UT9kAtN0pP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnF7Fb%2FbtszK2vAf7T%2Fqdp5QkQZE25UT9kAtN0pP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;175&quot; data-filename=&quot;스크린샷 2023-11-04 오전 7.06.01.png&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;만료된 refresh_token&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째는 정상적으로 &lt;b&gt;access_token이 정상적으로 재발급&lt;/b&gt; 된것이고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째는 &lt;b&gt;만료된 refresh_token&lt;/b&gt;을 넣었을 때 case인데 &lt;b&gt;&quot;로그인이 필요합니다&quot;&lt;/b&gt; 제대로&amp;nbsp;출력된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 로그아웃 API&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 7.10.31.png&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;1058&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KlP7v/btszHH7i4pr/GovaG0WppUjPhLP6hdxnxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KlP7v/btszHH7i4pr/GovaG0WppUjPhLP6hdxnxK/img.png&quot; data-alt=&quot;Swagger&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KlP7v/btszHH7i4pr/GovaG0WppUjPhLP6hdxnxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKlP7v%2FbtszHH7i4pr%2FGovaG0WppUjPhLP6hdxnxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;378&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 7.10.31.png&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;1058&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Swagger&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 7.11.38.png&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4YXkX/btszMZ54fpV/1VHsD4uoqfnCfeKW4syaAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4YXkX/btszMZ54fpV/1VHsD4uoqfnCfeKW4syaAk/img.png&quot; data-alt=&quot;user DB&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4YXkX/btszMZ54fpV/1VHsD4uoqfnCfeKW4syaAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4YXkX%2FbtszMZ54fpV%2F1VHsD4uoqfnCfeKW4syaAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;95&quot; data-filename=&quot;edited_스크린샷 2023-11-04 오전 7.11.38.png&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;user DB&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그아웃 API를 실행하면 정상적으로 &lt;b&gt;refresh_token이 초기화&lt;/b&gt;된 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어 &lt;b&gt;소셜 로그인을 전부 완료&lt;/b&gt;했다 ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음으로 제대로 JWT를 해보는거라 초반에 이해하는데 꽤나 머리를 쥐어뜯었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막상 이해를하고 코드를 보니 어려운건 없더라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅도 하면서 한번 더 정리를 하느라 &lt;b&gt;완벽히 이해&lt;/b&gt;를 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼른 프로젝트를 끝내고&lt;b&gt; 깃헙에 오픈소스&lt;/b&gt;로 올려야지...!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/NestJS</category>
      <category>JWT</category>
      <category>nestJS</category>
      <category>refresh_token</category>
      <category>소셜로그인</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/65</guid>
      <comments>https://ilikezzi.tistory.com/65#entry65comment</comments>
      <pubDate>Sat, 4 Nov 2023 07:21:19 +0900</pubDate>
    </item>
    <item>
      <title>[Nest.JS] 구글, 네이버, 카카오 소셜로그인 구현 - 1</title>
      <link>https://ilikezzi.tistory.com/64</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.15.54.png&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFhgoj/btsytQDIpyH/sURKsoqRc2N5KTmsXfnsyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFhgoj/btsytQDIpyH/sURKsoqRc2N5KTmsXfnsyK/img.png&quot; data-alt=&quot;Nest.JS&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFhgoj/btsytQDIpyH/sURKsoqRc2N5KTmsXfnsyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFhgoj%2FbtsytQDIpyH%2FsURKsoqRc2N5KTmsXfnsyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;257&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.15.54.png&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;860&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Nest.JS&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진행중인 사이드 프로젝트에서 기획이 끝나서&amp;nbsp;&lt;b&gt;화면기획서&lt;/b&gt;가 나오고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디자인쪽도 피그마로 &lt;b&gt;UI/UX 디자인&lt;/b&gt;을 시작하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발쪽도 &lt;b&gt;DB ERD 설계, 서버설계, Stg서버 &lt;/b&gt;등등.. 기본적인 개발하기 위한 준비를 마치고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;온보딩, 메인페이지 부터 드디어&lt;b&gt; Api 작업&lt;/b&gt;에 들어갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막상 개발은 큰 어려움이 없을텐데, 역시나 처음해보는 &lt;b&gt;기획&lt;/b&gt;이나 &lt;b&gt;DB/서버 설계&lt;/b&gt;에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간이 많이 걸리고, 제대로 처음 해보는거라서 어렵더라..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cduqiD/btsytgvQ7BD/mz4Hz3m22ZH7AC1AaVeQf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cduqiD/btsytgvQ7BD/mz4Hz3m22ZH7AC1AaVeQf1/img.png&quot; data-alt=&quot;On-boarding 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cduqiD/btsytgvQ7BD/mz4Hz3m22ZH7AC1AaVeQf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcduqiD%2FbtsytgvQ7BD%2Fmz4Hz3m22ZH7AC1AaVeQf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;575&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;912&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;On-boarding 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따로 &lt;b&gt;Local 이메일 로그인은 제외&lt;/b&gt;하고 &lt;b&gt;구글 / 카카오 / 네이버&lt;/b&gt; 로그인 세가지를 넣기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS에서 소셜 로그인을 붙히기 위해서는 &lt;b&gt;순서&lt;/b&gt;에 대한 이해가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나씩 차근차근 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;소셜 로그인 순서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2044&quot; data-origin-height=&quot;1140&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BAQ1w/btsytK4z7QV/iClhYYcKGl7LlT28Kb948k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BAQ1w/btsytK4z7QV/iClhYYcKGl7LlT28Kb948k/img.png&quot; data-alt=&quot;NestJS 소셜로그인 순서&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BAQ1w/btsytK4z7QV/iClhYYcKGl7LlT28Kb948k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBAQ1w%2FbtsytK4z7QV%2FiClhYYcKGl7LlT28Kb948k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;446&quot; data-origin-width=&quot;2044&quot; data-origin-height=&quot;1140&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;NestJS 소셜로그인 순서&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 이해한 순서를 이해하기 쉽게 &lt;b&gt;그림&lt;/b&gt;으로 만들어 보았다. (디자인 감각 Zero ㅠ)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 페이지&amp;nbsp;요청:&amp;nbsp;사용자가&amp;nbsp;소셜&amp;nbsp;로그인&amp;nbsp;페이지에&amp;nbsp;&lt;b&gt;접속&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 페이지&amp;nbsp;응답:&amp;nbsp;소셜&amp;nbsp;로그인&amp;nbsp;HTML&amp;nbsp;페이지를&amp;nbsp;웹/앱&amp;nbsp;브라우저에&amp;nbsp;&lt;b&gt;반환&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 구글&amp;nbsp;로그인&amp;nbsp;요청:&amp;nbsp;사용자가&amp;nbsp;구글&amp;nbsp;로그인&amp;nbsp;버튼을&amp;nbsp;클릭하면&amp;nbsp;http://localhost:3456/user/login/google 주소로&lt;b&gt; GET&lt;/b&gt; 요청을 보낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 구글 -&amp;gt; 웹/앱 브라우저: 구글 로그인 페이지에서 사용자가 인증을 하면, 구글은 &lt;b&gt;시크릿코드&lt;/b&gt;를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. controller -&amp;gt; 구글: &lt;b&gt;시크릿코드&lt;/b&gt;를 이용해서 구글에 access_token과 refresh_token을 요청한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 구글 -&amp;gt; controller: 구글은 &lt;b&gt;JWT와 user profile&lt;/b&gt;을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. controller&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;-&amp;gt; service:&lt;span&gt;&lt;b&gt; JWT와 user profile&lt;/b&gt;을 반환한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;8. service -&amp;gt; repository: 이미 &lt;b&gt;가입된 유저인지 체크&lt;/b&gt;하고, 미가입 유저면 &lt;b&gt;DB에 쌓는다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;9. repository -&amp;gt; service: 새로 만든 유저정보 or 기존 유저정보 &lt;b&gt;데이터를 반환&lt;/b&gt;한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;10. service: 넘겨받은 유저정보로 JWT access_token과 refresh_token을 &lt;b&gt;생성&lt;/b&gt;한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;11. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;service -&amp;gt; repository:&lt;span&gt; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;refresh_token을 user DB&lt;/b&gt;에 쌓는다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;12. service -&amp;gt; controller : JWT access_token과 refresh_token을 &lt;b&gt;반환&lt;/b&gt;한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;13. controller -&amp;gt; 웹/앱 브라우저: JWT access_token과 refresh_token을&lt;b&gt; 반환&lt;/b&gt;한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이후 토큰만료 체크해서&lt;b&gt; refresh_token&lt;/b&gt;으로 &lt;b&gt;토큰만료 체크&lt;/b&gt;해서&lt;b&gt; 새로운 access_token 발급&lt;/b&gt;받는데&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;해당 내용은 다음 포스팅에서 진행할 예정이다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;위 흐름을 제대로 이해하는데 좀 헤맸지만, 이것만 이해하면 끝이나 다름없다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Google, Naver, Kakao - secret key 발급&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이제 각각의 사이트에서 시크릿 키를 발급 받아야한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이때 &lt;b&gt;유저의 정보를 추가&lt;/b&gt;로 받아올지 정할 수 있는데&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;나는 &lt;b&gt;이메일, 프사, 닉네임 세가지&lt;/b&gt;를 공통으로 추가했다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://console.developers.google.com/apis&quot;&gt;https://console.developers.google.com/apis&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #373e48; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697389321860&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Google 클라우드 플랫폼&quot; data-og-description=&quot;로그인 Google 클라우드 플랫폼으로 이동&quot; data-og-host=&quot;accounts.google.com&quot; data-og-source-url=&quot;https://console.developers.google.com/apis&quot; data-og-url=&quot;https://accounts.google.com/v3/signin/identifier?continue=https%3A%2F%2Fconsole.cloud.google.com%2Fapis&amp;amp;followup=https%3A%2F%2Fconsole.cloud.google.com%2Fapis&amp;amp;ifkv=AVQVeyzC4_KgLsT1BtZd1Oxrwbz1LIwssKJlXyU3XEtE4U2_a5YuSs3d7R9fHS1hYMUOhC2YeXhE1A&amp;amp;osid=1&amp;amp;passive=1209600&amp;amp;service=cloudconsole&amp;amp;flowName=WebLiteSignIn&amp;amp;flowEntry=ServiceLogin&amp;amp;dsh=S1040756140%3A1697389320307592&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://console.developers.google.com/apis&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://console.developers.google.com/apis&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Google 클라우드 플랫폼&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;로그인 Google 클라우드 플랫폼으로 이동&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;accounts.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;a href=&quot;https://developers.naver.com/main/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developers.naver.com/main/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697389243010&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;NAVER Developers&quot; data-og-description=&quot;네이버 오픈 API들을 활용해 개발자들이 다양한 애플리케이션을 개발할 수 있도록 API 가이드와 SDK를 제공합니다. 제공중인 오픈 API에는 네이버 로그인, 검색, 단축URL, 캡차를 비롯 기계번역, 음&quot; data-og-host=&quot;developers.naver.com&quot; data-og-source-url=&quot;https://developers.naver.com/main/&quot; data-og-url=&quot;https://developers.naver.com/main&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/XSRIq/hyUdTyrg66/JKlt6JqL2Jq1QjHElOjLa1/img.jpg?width=940&amp;amp;height=492&amp;amp;face=0_0_940_492,https://scrap.kakaocdn.net/dn/qkoTG/hyUdTSKkpy/LbkkqD7cS6lpK1FkSrJkQ0/img.jpg?width=940&amp;amp;height=492&amp;amp;face=0_0_940_492&quot;&gt;&lt;a href=&quot;https://developers.naver.com/main/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers.naver.com/main/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/XSRIq/hyUdTyrg66/JKlt6JqL2Jq1QjHElOjLa1/img.jpg?width=940&amp;amp;height=492&amp;amp;face=0_0_940_492,https://scrap.kakaocdn.net/dn/qkoTG/hyUdTSKkpy/LbkkqD7cS6lpK1FkSrJkQ0/img.jpg?width=940&amp;amp;height=492&amp;amp;face=0_0_940_492');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;NAVER Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;네이버 오픈 API들을 활용해 개발자들이 다양한 애플리케이션을 개발할 수 있도록 API 가이드와 SDK를 제공합니다. 제공중인 오픈 API에는 네이버 로그인, 검색, 단축URL, 캡차를 비롯 기계번역, 음&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;a href=&quot;https://developers.kakao.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developers.kakao.com/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697389345236&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Kakao Developers&quot; data-og-description=&quot;카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.&quot; data-og-host=&quot;developers.kakao.com&quot; data-og-source-url=&quot;https://developers.kakao.com/&quot; data-og-url=&quot;https://developers.kakao.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bizBav/hyUdSM40KJ/jPzhBbFXbsWbVIKpC0L450/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/P1AAC/hyUdYNiiF2/Z3Pg7niJM7J1bt96N2tUJk/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000,https://scrap.kakaocdn.net/dn/bzsaZQ/hyUdQhqPbC/AHMxWVevlQpCfzKkXawjnk/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000&quot;&gt;&lt;a href=&quot;https://developers.kakao.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers.kakao.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bizBav/hyUdSM40KJ/jPzhBbFXbsWbVIKpC0L450/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/P1AAC/hyUdYNiiF2/Z3Pg7niJM7J1bt96N2tUJk/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000,https://scrap.kakaocdn.net/dn/bzsaZQ/hyUdQhqPbC/AHMxWVevlQpCfzKkXawjnk/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Kakao Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers.kakao.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;승인된 자바스크립트 원본&lt;/b&gt; : http://localhost:3456&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;승인된 리디렉션 URI&lt;/b&gt; : http://localhost:3456/auth/google/callback&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;나는 이런식으로 &lt;b&gt;콜백 url&lt;/b&gt;을 구성 했는데 각자 알아서 url을 추가해 주면된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;각각의 사이트에서 &lt;b&gt;Client ID&lt;/b&gt; 와 &lt;b&gt;Client Secret&lt;/b&gt; 를 생성을 한 후&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;.env 파일&lt;/b&gt;에 다음과 같이 넣어준다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by9IJw/btsyuHl3Pru/DLdKT98fGdN2slP6ng8LKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by9IJw/btsyuHl3Pru/DLdKT98fGdN2slP6ng8LKk/img.png&quot; data-alt=&quot;.env.debug&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by9IJw/btsyuHl3Pru/DLdKT98fGdN2slP6ng8LKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby9IJw%2FbtsyuHl3Pru%2FDLdKT98fGdN2slP6ng8LKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;243&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;.env.debug&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이제 준비는 끝났으니 로직을 짜러 가보자.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Code&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697390062140&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// JWT, passport 라이브러리 설치
npm install @nestjs/jwt
npm install @nestjs/passport;  

// 각각 스트래티지를 지원하는 의존성 패키지 설치
npm install passport-google-oauth20
npm install passport-kakao 
npm install passport-naver

// ts 버전 추가 설치
npm install --dev @types/passport-google-oauth20
npm install --dev @types/passport-kakao 
npm install --dev @types/passport-naver&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;해당 라이브러리를 모두 설치해준다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;yarn을 쓰면 &lt;b&gt;yarn add&lt;/b&gt; 로 설치해주면 된다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이제 각각의&lt;b&gt; strategy 파일&lt;/b&gt; 코드를 보자.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697390268863&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// jwt-social-google.strategy.ts

import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Profile, Strategy, VerifyCallback } from 'passport-google-oauth20';
import { ConfigService } from 'src/config/config.service';

@Injectable()
export class JwtGoogleStrategy extends PassportStrategy(Strategy, 'google') {
  //UseGuards의 이름과 동일해야함
  constructor(private readonly configService: ConfigService) {
    // console.log(configService)
    super({
      //자식의 constructor를 부모의 constructor에 넘기는 방법은 super를 사용하면 된다.
      clientID: configService.get('GOOGLE_ID'), //.env파일에 들어있음
      clientSecret: configService.get('GOOGLE_SECRET'), //.env파일에 들어있음
      callbackURL: 'http://localhost:3456/auth/google/callback', //.env파일에 들어있음
      scope: ['email', 'profile'],
    });
  }

  authorizationParams(): { [key: string]: string } {
    return {
      access_type: 'offline',
      prompt: 'consent',
    };
  }

  async validate(
    accessToken: string,
    refreshToken: string,
    profile: Profile,
    done: VerifyCallback,
  ) {
    console.log('success');
    console.log(accessToken);
    console.log(refreshToken);
    try {
      const { name, emails, photos } = profile;
      const user = {
        email: emails[0].value,
        firstName: name.familyName,
        lastName: name.givenName,
        photo: photos[0].value,
      };
      done(null, user);
    } catch (error) {
      done(error);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697390348838&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// jwt-social-kakao.strategy.ts

import { ConsoleLogger, Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Profile, Strategy } from 'passport-kakao';
import { ConfigService } from 'src/config/config.service';

@Injectable()
export class JwtKakaoStrategy extends PassportStrategy(Strategy, 'kakao') {
  constructor(private readonly configService: ConfigService) {
    super({
      clientID: configService.get('KAKAO_ID'), //.env파일에 들어있음
      clientSecret: configService.get('KAKAO_SECRET'), //.env파일에 들어있음
      callbackURL: 'http://localhost:3456/auth/kakao/callback', //.env파일에 들어있음
      // scope: [&quot;account_email&quot;, &quot;profile_nickname&quot;],
    });
  }

  async validate(
    accessToken: string,
    refreshToken: string,
    profile: Profile,
    done: (error: any, user?: any, info?: any) =&amp;gt; void,
  ) {
    try {
      console.log(profile);
      const { _json } = profile;
      const user = {
        email: _json.kakao_account.email,
        nickname: _json.properties.nickname,
        photo: _json.properties.profile_image,
      };
      done(null, user);
    } catch (error) {
      done(error);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697390411240&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// jwt-social-naver.strategy.ts

import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Profile, Strategy } from 'passport-naver';
import { ConfigService } from 'src/config/config.service';

@Injectable()
export class JwtNaverStrategy extends PassportStrategy(Strategy, 'naver') {
  constructor(private readonly configService: ConfigService) {
    super({
      clientID: configService.get('NAVER_ID'), //.env파일에 들어있음
      clientSecret: configService.get('NAVER_SECRET'), //.env파일에 들어있음
      callbackURL: 'http://localhost:3456/auth/naver/callback', //.env파일에 들어있음
    });
  }

  async validate(
    accessToken: string,
    refreshToken: string,
    profile: Profile,
    done: (error: any, user?: any, info?: any) =&amp;gt; void,
  ) {
    try {
      console.log(profile);
      const { _json } = profile;
      const user = {
        email: _json.email,
        nickname: _json.nickname,
        photo: _json.profile_image,
      };
      done(null, user);
    } catch (error) {
      done(error);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;구글, 카카오, 네이버&lt;/b&gt; strategy 파일을 추가해 주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 &lt;b&gt;ConfigModule 로컬 라이브러리&lt;/b&gt;를 사용하는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 라이브러리를 사용하게 될 경우 import 경로를 맞게 바꿔주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 각각에 strategy 파일마다 &lt;b&gt;validate()&lt;/b&gt; 부분이 다른게 보일텐데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 구글, 카카오, 네이버에서 넘겨주는&lt;b&gt; 데이터 폼이 약간씩 달라&lt;/b&gt;서 그렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697391049985&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// auth.controller.ts

//-----------------------구글 로그인-----------------------------//

  @Get('/user/login/google')
  @UseGuards(GoogleAuthGuard)
  async googleAuth(@Req() _req: Request) {
  }

  /* Get Google Auth Callback */
  @Get('/auth/google/callback')
  @UseGuards(AuthGuard('google'))
  async googleAuthCallback(
    @Req() req: GoogleRequest,
    @Res() res: Response, // : Promise&amp;lt;GoogleLoginAuthOutputDto&amp;gt;
  ) {
    // return res.send(user);
    return this.authService.googleLogin(req, res);
  }

  //-----------------------카카오 로그인-----------------------------//

  @Get('/user/login/kakao')
  @UseGuards(AuthGuard('kakao'))
  async kakaoAuth(@Req() _req: Request) {
  }

  /* Get kakao Auth Callback */
  @Get('/auth/kakao/callback')
  @UseGuards(AuthGuard('kakao'))
  async kakaoAuthCallback(
    @Req() req: KakaoRequest,
    // @Res({ passthrough: true }) res: Response,
    @Res() res: Response, // : Promise&amp;lt;KakaoLoginAuthOutputDto&amp;gt;
  ) {
    const { user } = req;
    console.log(user);
    return res.send(user);
    // return this.authService.kakaoLogin(req, res);
  }

  //-----------------------네이버 로그인-----------------------------//

  @Get('/user/login/naver')
  @UseGuards(AuthGuard('naver'))
  async naverAuth(@Req() _req: Request) {
  }

  /* Get naver Auth Callback */
  @Get('/auth/naver/callback')
  @UseGuards(AuthGuard('naver'))
  async naverAuthCallback(
    @Req() req: NaverRequest,
    @Res() res: Response, // : Promise&amp;lt;NaverLoginAuthOutputDto&amp;gt;
  ) {
    const { user } = req;
    console.log(user);
    return res.send(user);
    // return this.authService.naverLogin(req, res);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;구글&lt;/b&gt; 이랑 &lt;b&gt;카카오,네이버&lt;/b&gt;랑&lt;b&gt; return&lt;/b&gt; 값이 다를텐데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;카카오, 네이버&lt;/b&gt;는 &lt;b&gt;테스트&lt;/b&gt;를 위해서 return 값을 임시로 이렇게 해둔것이라 테스트가 끝나면 구글처럼 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-10-16 오전 2.32.48.png&quot; data-origin-width=&quot;1694&quot; data-origin-height=&quot;82&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNybVZ/btsyulwMz7C/KSv1ktZjm2N8eWMnalLon0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNybVZ/btsyulwMz7C/KSv1ktZjm2N8eWMnalLon0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNybVZ/btsyulwMz7C/KSv1ktZjm2N8eWMnalLon0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNybVZ%2FbtsyulwMz7C%2FKSv1ktZjm2N8eWMnalLon0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;750&quot; height=&quot;36&quot; data-filename=&quot;edited_스크린샷 2023-10-16 오전 2.32.48.png&quot; data-origin-width=&quot;1694&quot; data-origin-height=&quot;82&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;return res.send(user)&lt;/b&gt; 로 구성하면 service부 없이도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;http://localhost:3456/user/login/naver -&amp;gt; 네이버 로그인&lt;/b&gt;하면&lt;br /&gt;&lt;br /&gt;&lt;b&gt;콜백 url&lt;/b&gt;로 위 사진처럼 내가 정해놓은 &lt;b&gt;유저 데이터&lt;/b&gt;가 출력될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 혹시나 안되면 &lt;b&gt;env파일, config 설정, Auth module, 네이버 개발자센터 콜백 url&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 &lt;b&gt;4가지 항목&lt;/b&gt;을 잘 체크해보면 아마 해결될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4가지 체크하라는건 슬프게도 경험담... 따흑)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 여기까지 잘 따라왔다면 &lt;b&gt;DB에 데이터&lt;/b&gt;를 쌓아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697391761617&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// auth.service.ts

async googleLogin(
    req: GoogleRequest,
    res: Response,
    // googleLoginAuthInputDto, // : Promise&amp;lt;GoogleLoginAuthOutputDto&amp;gt;
  ) {
    try {
      req.user.nickname = req.user.firstName + req.user.lastName;
      const { user } = req;
      delete user.lastName;
      delete user.firstName;
      user.type = 'google';

      // 유저 중복 검사
      let findUser = await this.userQueryRepository.findUser(user);

      // 없는 유저면 DB에 유저정보 저장
      if (!findUser) {
        const uuid = generateUUID();
        findUser = await this.userQueryRepository.createUser(user, uuid);
      }
      console.log(findUser);

      // 구글 가입이 되어 있는 경우 accessToken 및 refreshToken 발급
      const findUserPayload = { id: findUser.id };
      const eid_access_token = jwt.sign(
        findUserPayload,
        this.configService.get('JWT_ACCESS_TOKEN_SECRET_KEY'),
        {
          expiresIn: this.configService.get('JWT_ACCESS_TOKEN_EXPIRATION_TIME'),
        },
      );
      const eid_refresh_token = jwt.sign(
        {},
        this.configService.get('JWT_REFRESH_TOKEN_SECRET_KEY'),
        {
          expiresIn: this.configService.get('JWT_REFRESH_TOKEN_EXPIRATION_TIME'),
          audience: String(findUser.id),
        },
      );

      /* refreshToken 필드 업데이트 */
      findUser.eid_refresh_token = eid_refresh_token;
      await this.userQueryRepository.save(findUser);

      // 쿠키 설정
      const now = new Date();
      now.setDate(now.getDate() + +this.configService.get('JWT_REFRESH_TOKEN_EXPIRATION_DATE'));
      res.cookie('eid_refresh_token', eid_refresh_token, {
        expires: now,
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production' ? true : false,
        sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax',
      });
      return {
        ok: true,
        eid_access_token,
      };
    } catch (error) {
      return { ok: false, error: '구글 로그인 인증을 실패 하였습니다.' };
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토큰 전까지만 우선 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;토큰, 쿠키는 다음 포스팅&lt;/b&gt;에서 다룰것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글은 &lt;b&gt;lastname&lt;/b&gt;, &lt;b&gt;firstname&lt;/b&gt;을 따로 넘겨줘서 네이버, 카카오처럼 &lt;b&gt;&quot;닉네임&quot;&lt;/b&gt;으로 합쳐주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Repository&lt;/b&gt;에서 이미 있는 유저인지 체크를 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가입된 유저가 아니면 &lt;b&gt;유저DB를 쌓아준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 &lt;b&gt;uuid 베이스&lt;/b&gt;로 DB를 설계해놔서 uuid도 추가해 주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697392085379&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// user.query.repository.ts

async findUser(user): Promise&amp;lt;UserEntity&amp;gt; {
    return await this.repository.findOne({
      where: { email: user.email, name: user.nickname, type: user.type },
    });
  }

  async createUser(user, uuid): Promise&amp;lt;UserEntity&amp;gt; {
    return await this.repository.save({
      uuid: uuid,
      email: user.email,
      name: user.nickname,
      profile_image: user.photo,
      type: user.type,
    });
  }

  async save(UserEntity): Promise&amp;lt;UserEntity&amp;gt; {
    return await this.repository.save(UserEntity);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user repository에는 별거없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 auth.service에서 넘긴 데이터 처리만 이뤄진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복 유저는&lt;b&gt; email, name, type&lt;/b&gt; 세가지로 비교한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 기본적인 코드는 끝이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 실행시키고 &lt;b&gt;http://localhost:3456/user/login/google &lt;/b&gt;에 접속하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-10-16 오전 2.50.58.png&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;1344&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUWxMp/btsyCi6MuRM/og6nss0ep9ZsHeDZsTgGtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUWxMp/btsyCi6MuRM/og6nss0ep9ZsHeDZsTgGtK/img.png&quot; data-alt=&quot;http://localhost:3456/user/login/google&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUWxMp/btsyCi6MuRM/og6nss0ep9ZsHeDZsTgGtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUWxMp%2FbtsyCi6MuRM%2Fog6nss0ep9ZsHeDZsTgGtK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;783&quot; data-filename=&quot;edited_스크린샷 2023-10-16 오전 2.50.58.png&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;1344&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;http://localhost:3456/user/login/google&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 계정을 누르면 &lt;b&gt;콜백url&lt;/b&gt;로 넘어가면서 &lt;b&gt;auth 코드&lt;/b&gt;로 넘어갈 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 로그인이니 제대로 DB에 쌓였나 확인을 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-10-16 오전 2.53.08.png&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GiC12/btsytfKw8P4/lKSSnjITgXDjlva2VM6Il0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GiC12/btsytfKw8P4/lKSSnjITgXDjlva2VM6Il0/img.png&quot; data-alt=&quot;user table&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GiC12/btsytfKw8P4/lKSSnjITgXDjlva2VM6Il0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGiC12%2FbtsytfKw8P4%2FlKSSnjITgXDjlva2VM6Il0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;65&quot; data-filename=&quot;edited_스크린샷 2023-10-16 오전 2.53.08.png&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;user table&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아주 잘 쌓였다 ㅎㅎ&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;네이버, 카카오&lt;/b&gt;도 동일한 방법으로 진행을 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;access_token과 fresh_token&lt;/b&gt;에 대해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[Nest.JS] 구글, 네이버, 카카오 소셜로그인 구현 - 2편&lt;/b&gt; 에서 포스팅 할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/NestJS</category>
      <category>nestJS</category>
      <category>OAuth</category>
      <category>구글</category>
      <category>네이버</category>
      <category>소셜로그인</category>
      <category>카카오</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/64</guid>
      <comments>https://ilikezzi.tistory.com/64#entry64comment</comments>
      <pubDate>Mon, 16 Oct 2023 03:01:04 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 클로저_코어 자바스크립트</title>
      <link>https://ilikezzi.tistory.com/63</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;1602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4GOR3/btsv9MQQEfr/7aUbTdk3XhWzf0rmnzXZ61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4GOR3/btsv9MQQEfr/7aUbTdk3XhWzf0rmnzXZ61/img.png&quot; data-alt=&quot;코어 자바스크립트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4GOR3/btsv9MQQEfr/7aUbTdk3XhWzf0rmnzXZ61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4GOR3%2Fbtsv9MQQEfr%2F7aUbTdk3XhWzf0rmnzXZ61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;617&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;1602&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코어 자바스크립트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 5단원인 &lt;b&gt;&quot;클로저&quot;&lt;/b&gt; 를 포스팅 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클로저(closure)&lt;/b&gt;는 자바스크립트에서 &lt;b&gt;중요한 개념&lt;/b&gt; 중 하나지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이번에 처음 제대로 파본다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실행 컨텍스트&lt;/b&gt;에 대한 사전지식이 없으면 분명 이해가 안 갈 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마침 &lt;b&gt;2단원에서 실행컨텍스트&lt;/b&gt;를 다뤘으니 &lt;b&gt;꼭! 꼭!&lt;/b&gt; 보고 오길 &lt;b&gt;권장&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/55&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ilikezzi.tistory.com/55&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1695921901503&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Javascript] 실행 컨텍스트_코어 자바스크립트&quot; data-og-description=&quot;저번에 포스팅한 &amp;quot;데이터 타입&amp;quot; 에 이어서 다음 챕터인 &amp;quot;실행 컨텍스트&amp;quot;를 포스팅 할 것이다. https://ilikezzi.tistory.com/52 [Javascript] 데이터 타입_코어 자바스크립트 계획했던대로 자격증 취득도 다 &quot; data-og-host=&quot;ilikezzi.tistory.com&quot; data-og-source-url=&quot;https://ilikezzi.tistory.com/55&quot; data-og-url=&quot;https://ilikezzi.tistory.com/55&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UilXk/hyT2sH1MIj/m832zAFt2GcEQUCwnBvngk/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/be67pt/hyT2rI6VXw/uFWp65ZPtmwDH8RpUKvSf0/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/i0tEG/hyT2BEYMqM/m0eFGP8WejZHwgsQjG9WK0/img.png?width=1038&amp;amp;height=1602&amp;amp;face=0_0_1038_1602&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/55&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ilikezzi.tistory.com/55&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UilXk/hyT2sH1MIj/m832zAFt2GcEQUCwnBvngk/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/be67pt/hyT2rI6VXw/uFWp65ZPtmwDH8RpUKvSf0/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/i0tEG/hyT2BEYMqM/m0eFGP8WejZHwgsQjG9WK0/img.png?width=1038&amp;amp;height=1602&amp;amp;face=0_0_1038_1602');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Javascript] 실행 컨텍스트_코어 자바스크립트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;저번에 포스팅한 &quot;데이터 타입&quot; 에 이어서 다음 챕터인 &quot;실행 컨텍스트&quot;를 포스팅 할 것이다. https://ilikezzi.tistory.com/52 [Javascript] 데이터 타입_코어 자바스크립트 계획했던대로 자격증 취득도 다&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;05. 클로저&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;클로저의 의미 및 원리 이해&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저는 여러 &lt;b&gt;함수형 프로그래밍&lt;/b&gt; 언어에서 등장하는 보편적인 특성이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저의 설명은 다양한 문헌에서 &lt;b&gt;제각각 다르게 정의 &lt;/b&gt;또는&lt;b&gt; 설명&lt;/b&gt;하고 있지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 문장을 접하면 &lt;b&gt;이해하기 어려울&lt;/b&gt; 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;클로저는 내부 함수가 외부 함수의 변수에 접근할 수 있게 해주는 자바스크립트의 특별한 기능&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 설명 중에 이 설명이 그나마 처음 접했을 때 제일 와닿았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MDN&lt;/b&gt;(Mozilla Developer Network)에서는 클로저에 대해 이렇게 설명했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;A Closure is the combination of a function and the lexical environment within which that function was declared.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직역해보면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&quot;클로저는 함수와 그 함수가 선언될 당시의 lexical environment의 상호관계에 따른 현상&quot;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;lexical environment&lt;/b&gt;는 실행 컨텍스트의 구성요소 중 하나인 &lt;b&gt;outerEnvironmentReference&lt;/b&gt;에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고&amp;nbsp;&lt;b&gt;상호관계&lt;/b&gt;란&amp;nbsp;&lt;b&gt;내부&amp;nbsp;함수에서&amp;nbsp;외부&amp;nbsp;변수를&amp;nbsp;참조하는&amp;nbsp;때&lt;/b&gt;에만&amp;nbsp;만을&amp;nbsp;뜻한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 파악한 내용에 따르면 클로저란&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;어떤 함수에서 &lt;b&gt;선언한 변수를 참조하는 내부함수&lt;/b&gt;에서만 발생하는 현상&quot; 이라고 볼 수 있겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;외부함수의 변수를 참조하는 내부함수&lt;/b&gt; 예제 코드를 보자.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1695926103925&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var outer = function(){
  var a = 1;
  var inner = function(){
    return ++a;
  };
  return inner();
};
var outer2 = outer();

console.log(outer2);     // 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6번째 라인을 보면 &lt;b&gt;함수를 실행한 결과를 &lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;return&lt;/b&gt; 하고있으므로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;outer함수의 실행 컨텐스트가 &lt;b&gt;종료된 시점&lt;/b&gt;에는 &lt;b&gt;a 변수를 참조하는 대상이 없어&lt;/b&gt;진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;a, inner변수 값들은 &lt;b&gt;가비지 컬렉터에 의해 소멸&lt;/b&gt;될 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이제 &lt;b&gt;outer의 실행 컨텍스트가 종료된 후에도 inner 함수를 호출&lt;/b&gt;하는 예제 코드를 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1695926504937&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var outer = function(){
  var a = 1;
  var inner = function(){
    return ++a;
  };
  return inner;
};
var outer2 = outer();

console.log(outer2());    // 2
console.log(outer2());    // 3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 6번째 라인에서 함수의 실행결과가 아닌 inner &lt;b&gt;함수 자체를 return&lt;/b&gt; 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 outer 함수의 실행 컨텍스트가 &lt;b&gt;종료&lt;/b&gt;될 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;outer2 변수는 outer의 실행 결과인&lt;b&gt; inner 함수를 참조&lt;/b&gt;하게 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;의문&lt;/b&gt;이 들 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;inner 함수의 실행 시점에는 outer 함수는 &lt;b&gt;이미 실행이 종료된 상태&lt;/b&gt;인데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;outer함수의 &lt;b&gt;LexicalEnvironment&lt;/b&gt;에 어떻게 &lt;b&gt;접근&lt;/b&gt;하는 걸까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;가비지 컬렉터의 동작 방식&lt;/b&gt;&lt;/span&gt; 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가비지 컬렉터는 &lt;b&gt;어떤값을 참조하는 변수가 하나라도&lt;/b&gt; 있다면 &lt;b&gt;그 값은 &lt;span style=&quot;color: #ee2323;&quot;&gt;수집 대상에 포함시키지 않는다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 덕에 inner 함수가 이 변수에 접근할 수 있었던 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제&amp;nbsp;다시&lt;b&gt; 클로저의 정의&lt;/b&gt;에 대해서 살펴보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;&lt;/b&gt;클로저란 어떤 함수 A에서 &lt;b&gt;선언한 변수 a를 참조&lt;/b&gt;하는 &lt;b&gt;내부함수 B를 외부로 전달&lt;/b&gt; 할 경우 A의 &lt;b&gt;실행 컨텍스트가 종료된 이후에도&lt;/b&gt; 변수 a가 &lt;b&gt;사라지지 않는&lt;/b&gt; 현상&lt;b&gt;&quot;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;이라고 정의할 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;메모리 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저를 사용할 때 &lt;b&gt;주의&lt;/b&gt;해야할 점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저는 &lt;b&gt;메모리를 차지&lt;/b&gt;하기 때문에 과도하게 사용하면 성능 문제가 생길 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히 &lt;b&gt;&quot;메모리 누수&quot;&lt;/b&gt; 라는 표현을 쓰기도 하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 값의 참조 카운트가 0이 되지 않아&lt;b&gt; 가비지 컬렉터의 수거 대상이 되지 않는 경우&lt;/b&gt;를 얘기하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 관리방법은 정말 &lt;b&gt;간단&lt;/b&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저는 어떤 필요에 의해 의도적으로 &lt;b&gt;함수의 지역변수를 메모리를 소모&lt;/b&gt;하도록 함으로써 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 그 &lt;b&gt;필요성이 사라진 시점&lt;/b&gt;에는 더는 메모리를 &lt;b&gt;소모하지 않게&lt;/b&gt; 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참조 카운트를 0&lt;/b&gt; 으로 만들어주면 언젠간 &lt;b&gt;가비지 컬렉터가 수거&lt;/b&gt;해갈 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;null&lt;/b&gt;&lt;/span&gt;이나&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; undefined&lt;/b&gt;&lt;/span&gt;를 할당하면 해결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저 메모리 관리 예제 코드로 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1695927831242&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var outer = function(){
  var a = 1;
  var inner = function(){
    return ++a;
  };
  return inner;
};
var outer2 = outer();

console.log(outer2());
console.log(outer2());
outer = null; 			// outer 식별자의 inner 함수 참조를 끊음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 라인을 보면 이렇게&lt;b&gt; null을 할당&lt;/b&gt;하면 끝이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;클로저 활용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정보은닉&lt;/b&gt;은 어떤 모듈의 내부 로직에 대해 &lt;b&gt;외부로의 노출을 최소화&lt;/b&gt;해서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈간의 &lt;b&gt;결합도를 낮추고 유연성을 높이고자&lt;/b&gt; 하는 현대 프로그래밍 언어의 중요한 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말해 외부에서는 &lt;b&gt;오직 return 한 정보에만 접근&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;return 값이 &lt;b&gt;외부에 정보를 제공하는 &lt;span style=&quot;color: #ee2323;&quot;&gt;유일한 수단&lt;/span&gt;&lt;/b&gt;인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;외부에 제공&lt;/b&gt;하고자 하는 정보들을 모아서 &lt;b&gt;return&lt;/b&gt;하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내부에서만 사용할 정보&lt;/b&gt;들은 &lt;b&gt;return하지 않는 것&lt;/b&gt;으로 &lt;b&gt;접근 권한 제어&lt;/b&gt;가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;return한 변수&lt;/b&gt;들은 &lt;b&gt;공개 멤버&lt;/b&gt;(public member)가 되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그렇지 않은 변수&lt;/b&gt;들은 &lt;b&gt;비공개 멤버&lt;/b&gt;(private member)가 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 게임으로 해당 예제를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1695928386391&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var car = {
  fuel: Math.ceil(Math.random() * 10 + 10),	 // 연료
  power: Math.ceil(Math.random() * 3 + 2),	 // 연비
  moved:0,									 // 총 이동거리
  run: function(){
    var km = Math.ceil(Math.random() * 6);
    var wasteFuel = km / this.power;
    if(this.fuel &amp;lt; wasteFuel){
      console.log('이동불가');
      return;
    }
    this.fuel -= wasteFuel;
    this.moved += km;
    console.log(km + 'km 이동 (총 ' + this.moved + 'km)');
  }
}

// 각 턴마다 주사위를 굴려 나온 숫자(km)만큼 이동한다.
// 차량별로 연료량과 연비는 랜덤으로 생성된다.
// 남은 연료가 이동할 거리에 필요한 연료보다 부족하면 이동하지 못한다.
// 모든 유저가 이동할 수 없는 턴에 게임이 종료된다.
// 게임 종료 시점에 가장 멀리 이동해 있는 사람이 승리한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 간단한 게임을 만들어 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 유저가 &lt;b&gt;run 메서드&lt;/b&gt;만 호출하면 해당 게임의 코드는 아무런 문제가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 일부 유저가 JS를 다룰줄 안다면 &lt;b&gt;조작&lt;/b&gt;을 해버릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1695928665210&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;car.fuel = 99999999;
car.power = 9999999;
car.moved = 9999999;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 해버리면 &lt;b&gt;치트키&lt;/b&gt;가 따로 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 케이스에서 &lt;b&gt;값을 바꾸지 못하도록 방어&lt;/b&gt;할 때 &lt;b&gt;클로저를 활용&lt;/b&gt;하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체가 아닌 함수&lt;/b&gt;로 만들고, &lt;b&gt;필요한 멤버만을 return&lt;/b&gt; 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1695929521233&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var createCar = function() {
  var fuel = Math.ceil(Math.random() * 10 + 10); // 연료
  var power = Math.ceil(Math.random() * 3 + 2);  // 연비
  var moved = 0;
  
  return {
    get moved() {
      return moved;
    },
    run: function() {
      var km = Math.ceil(Math.random() * 6);
      var wasteFuel = km / power;
      if (fuel &amp;lt; wasteFuel) {
        console.log('이동불가');
        return;
      }
      fuel -= wasteFuel;
      moved += km;
      console.log(km + 'km 이동 (총 ' + moved + 'km). 남은 연료: ' + fuel);
    }
  };
};

var car = createCar();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;fuel, power 변수&lt;/b&gt;는 &lt;b&gt;비공개 멤버&lt;/b&gt;로 지정해 외부에서 접근을 제한하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;moved 변수&lt;/b&gt;는 getter만을 부여함으로써 &lt;b&gt;읽기 전용 속성&lt;/b&gt;을 부여했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 외부에서는&lt;b&gt; run 메서드 실행&lt;/b&gt;과, 현재&lt;b&gt; moved 값을 확인&lt;/b&gt;하는 두가지 동작만 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;커링 함수&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 이제 &lt;b&gt;커링 함수&lt;/b&gt;에 대해 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커링 함수란 &lt;b&gt;여러개의 인자를 받는 함수를 하나의 인자만 받는 함수로 나눠서 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순차적으로 호출될 수 있게 &lt;b&gt;체인형태로 구성&lt;/b&gt;한 것을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수를 실행한 결과는 그 다음 인자를 받기 위해 &lt;b&gt;대기만 할 뿐&lt;/b&gt;,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 인자가 전달되기 전까지는 &lt;b&gt;원본 함수가 실행되지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것도 관련 코드를 먼저 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1695930354556&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var curry5 = function(func){
  return function(a){
    return function(b){
      return function(c){
        return function(d){
          return function(e){
            return func(a, b, c, d, e);
          };
        };
      };      
    };
  };
};
var getMax = curry5(Math.max);
console.log(getMax(1)(2)(3)(4)(5));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 이 코드는 5개의 숫자 중에서 가장 큰 숫자를 &lt;b&gt;한번에&lt;/b&gt; 찾아줄 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 한눈에 봐도 &lt;b&gt;코드가 길고 가독성이 떨어&lt;/b&gt;진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ES6&lt;/b&gt;에서 제공하는&lt;b&gt; 화살표 함수&lt;/b&gt;를 써서 한줄에 표기할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1695930644528&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const curry5 = func =&amp;gt; a =&amp;gt; b =&amp;gt; c =&amp;gt; d =&amp;gt; e =&amp;gt; func(a, b, c, d, e);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;화살표 함수&lt;/b&gt;로 변환하면 한줄에 표기할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 단계에서 받은 인자들을 모두&lt;b&gt; 마지막 단계에서 참조&lt;/b&gt;할 것이므로 &lt;b&gt;가비지 컬렉터되지 않고,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리에 차곡차곡 쌓였다가, 마지막 호출로 &lt;b&gt;실행 컨텍스트가 종료&lt;/b&gt;된 후에야&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;한꺼번에 가비지 컬렉터의 수거 대상&lt;/b&gt;이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 하면 결국 &lt;b&gt;마지막 인자&lt;/b&gt;가 넘어갈 때까지 &lt;b&gt;함수 실행을 미루는&lt;/b&gt; 셈이된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 커링 함수가 유용한 경우는 바로 &lt;b&gt;지연실행&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;원하는 시점까지 지연&lt;/b&gt;시켰다가 실행하는 것이 필요할때 커링을 쓰기 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내에서 자주 쓰이는 함수의 &lt;b&gt;매개변수가 항상 비슷하고 일부만 바뀌는 경우&lt;/b&gt;에도 적합할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;클로저&lt;/b&gt;에 대해서 제대로 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저는 확실히 &lt;b&gt;코드를 보고나서&lt;/b&gt; 다시 설명을 보니 이해가 잘 가는것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;클로저 메모리&lt;/b&gt;는 항상 주의를 해야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 챕터는 &lt;b&gt;&quot;프로토타입&quot;&lt;/b&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/Javascript</category>
      <category>js</category>
      <category>코어 자바스크립트</category>
      <category>클로저</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/63</guid>
      <comments>https://ilikezzi.tistory.com/63#entry63comment</comments>
      <pubDate>Fri, 29 Sep 2023 05:03:28 +0900</pubDate>
    </item>
    <item>
      <title>[해커톤] 숙명여대 Bigdata/AI Streamlit 해커톤 멘토 참여후기</title>
      <link>https://ilikezzi.tistory.com/62</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_스크린샷 2023-09-27 오후 9.00.28.png&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;1802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kn6Xc/btsv0pPXk9K/zKqr5KckQvKkUlfffoU6Ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kn6Xc/btsv0pPXk9K/zKqr5KckQvKkUlfffoU6Ak/img.png&quot; data-alt=&quot;숙명여대 Streamlit 해커톤 AWS 멘토&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kn6Xc/btsv0pPXk9K/zKqr5KckQvKkUlfffoU6Ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKn6Xc%2Fbtsv0pPXk9K%2FzKqr5KckQvKkUlfffoU6Ak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;599&quot; data-filename=&quot;edited_edited_스크린샷 2023-09-27 오후 9.00.28.png&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;1802&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;숙명여대 Streamlit 해커톤 AWS 멘토&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-09-27 오후 8.28.07.png&quot; data-origin-width=&quot;2176&quot; data-origin-height=&quot;1234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p0BNe/btsv5hD0uJi/4rzePi2KI8VVwhoQwK3Tak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p0BNe/btsv5hD0uJi/4rzePi2KI8VVwhoQwK3Tak/img.png&quot; data-alt=&quot;Streamlit 해커톤&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p0BNe/btsv5hD0uJi/4rzePi2KI8VVwhoQwK3Tak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp0BNe%2Fbtsv5hD0uJi%2F4rzePi2KI8VVwhoQwK3Tak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;340&quot; data-filename=&quot;스크린샷 2023-09-27 오후 8.28.07.png&quot; data-origin-width=&quot;2176&quot; data-origin-height=&quot;1234&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Streamlit 해커톤&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번주에 &lt;b&gt;숙&lt;/b&gt;&lt;b&gt;명여대&lt;/b&gt;에서 &lt;b&gt;Bigdata/AI Streamlit 해커톤&lt;/b&gt;을 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는&lt;b&gt; AWS 멘토&lt;/b&gt;로 참여하게 되어서 간략하게 후기를 써보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번 &lt;b&gt;인하대 해커톤 AWS 멘토&lt;/b&gt;로 참여했을때, 멘토진들이랑 거의 동일해서 반가웠다ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_IMG_5038.jpg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SAft7/btsxqtXJzdR/3714FoNQqvePfJ8GxPxZkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SAft7/btsxqtXJzdR/3714FoNQqvePfJ8GxPxZkk/img.png&quot; data-alt=&quot;AWS 멘토진&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SAft7/btsxqtXJzdR/3714FoNQqvePfJ8GxPxZkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSAft7%2FbtsxqtXJzdR%2F3714FoNQqvePfJ8GxPxZkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;600&quot; data-filename=&quot;edited_edited_IMG_5038.jpg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AWS 멘토진&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_R0000748.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgqrKk/btsvYTRf7KJ/oCVkgtTxKKqgzxkOJ6eYc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgqrKk/btsvYTRf7KJ/oCVkgtTxKKqgzxkOJ6eYc0/img.png&quot; data-alt=&quot;AWS 멘토진&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgqrKk/btsvYTRf7KJ/oCVkgtTxKKqgzxkOJ6eYc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgqrKk%2FbtsvYTRf7KJ%2FoCVkgtTxKKqgzxkOJ6eYc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;400&quot; data-filename=&quot;edited_R0000748.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AWS 멘토진&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 해커톤은 &lt;b&gt;오뚜기&lt;/b&gt;가 후원사여서 &lt;b&gt;오뚜기의&lt;/b&gt; &lt;b&gt;상품 판매 데이터와, 제품 리뷰 데이터&lt;/b&gt;를 받아서 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 데이터와 &lt;b&gt;생성형 AI&lt;/b&gt;를 활용하여 &lt;b&gt;Streamlit&lt;/b&gt; or &lt;b&gt;Cloud native app&lt;/b&gt;을 개발을 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-09-27 오후 8.54.40.png&quot; data-origin-width=&quot;1996&quot; data-origin-height=&quot;1154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m4YU2/btsv8RdpoZm/zKd4DxWKQMr5NzQiVTcQFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m4YU2/btsv8RdpoZm/zKd4DxWKQMr5NzQiVTcQFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m4YU2/btsv8RdpoZm/zKd4DxWKQMr5NzQiVTcQFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm4YU2%2Fbtsv8RdpoZm%2FzKd4DxWKQMr5NzQiVTcQFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;347&quot; data-filename=&quot;스크린샷 2023-09-27 오후 8.54.40.png&quot; data-origin-width=&quot;1996&quot; data-origin-height=&quot;1154&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Streamlit&lt;/b&gt;에 대해서 이번기회에 처음 접하게 되었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Streamlit&lt;/b&gt;은&amp;nbsp;&lt;b&gt;데이터&amp;nbsp;사이언티스트&lt;/b&gt;나&lt;b&gt;&amp;nbsp;백엔드&amp;nbsp;개발자&lt;/b&gt;처럼&amp;nbsp;프론트엔드에&amp;nbsp;익숙하지&amp;nbsp;않은&amp;nbsp;사람들도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게&lt;b&gt; 데이터 시각화&lt;/b&gt;나 &lt;b&gt;웹 앱&lt;/b&gt;을 만들 수 있도록 해주는 &lt;b&gt;파이썬 라이브러리&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드&amp;nbsp;몇&amp;nbsp;줄만으로도&amp;nbsp;인터랙티브한&lt;b&gt;&amp;nbsp;대시보드나&amp;nbsp;차트&lt;/b&gt;를&amp;nbsp;만들&amp;nbsp;수&amp;nbsp;있어서,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 &lt;b&gt;데이터 분석&lt;/b&gt;이나 &lt;b&gt;머신러닝 모델&lt;/b&gt;의 결과를 빠르게 &lt;b&gt;시각화&lt;/b&gt;하고 공유하는 데 엄청 유용한것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;Streamlit&lt;/b&gt;은 이번 해커톤 취지에 딱 맞는것 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-09-27 오후 9.06.32.png&quot; data-origin-width=&quot;1996&quot; data-origin-height=&quot;1206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEjVrD/btsv8bcajNr/mymndjgYTU1zhK0TsyliH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEjVrD/btsv8bcajNr/mymndjgYTU1zhK0TsyliH0/img.png&quot; data-alt=&quot;해커톤 스케쥴&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEjVrD/btsv8bcajNr/mymndjgYTU1zhK0TsyliH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEjVrD%2Fbtsv8bcajNr%2FmymndjgYTU1zhK0TsyliH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;363&quot; data-filename=&quot;스크린샷 2023-09-27 오후 9.06.32.png&quot; data-origin-width=&quot;1996&quot; data-origin-height=&quot;1206&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;해커톤 스케쥴&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시상내역은 다음과 같았다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 오뚜기상&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;100만원&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Snow (Streamlit)상&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;50만원&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- AWS상&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;AWS Stock 팀원당 1주&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Slack상&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;50만원&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 인기상&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;30만원&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 전략적으로&lt;b&gt; 어떤 시상에 초점&lt;/b&gt;을 두고 할지에 따라 주제도 다양하게 정해졌다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;내가 멘토링을 맡았던 조들에 대해 간략하게 얘기해보면,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;악성재고 처리, 반품데이터 분석, 우크라이나 식품지원 등등 너무나 좋은 아이디어가 많았다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_R0000879.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sbGk9/btsvY0bSpDF/G7FS4YUDy6zCLjC2iuEGc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sbGk9/btsvY0bSpDF/G7FS4YUDy6zCLjC2iuEGc1/img.png&quot; data-alt=&quot;열정! 열정! 열정!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sbGk9/btsvY0bSpDF/G7FS4YUDy6zCLjC2iuEGc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsbGk9%2FbtsvY0bSpDF%2FG7FS4YUDy6zCLjC2iuEGc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;400&quot; data-filename=&quot;edited_R0000879.JPG&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;열정! 열정! 열정!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;밤새고 진행하는 해커톤인 만큼 새벽에 출출하지 않게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;오뚜기&lt;/b&gt;에서 밥차(?)도 왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;R0000829.JPG&quot; data-origin-width=&quot;6000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beNyOk/btsv7tYuvHp/QozNHN0LaMM1kIFeYdBCwk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beNyOk/btsv7tYuvHp/QozNHN0LaMM1kIFeYdBCwk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beNyOk/btsv7tYuvHp/QozNHN0LaMM1kIFeYdBCwk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeNyOk%2Fbtsv7tYuvHp%2FQozNHN0LaMM1kIFeYdBCwk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;400&quot; data-filename=&quot;R0000829.JPG&quot; data-origin-width=&quot;6000&quot; data-origin-height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-09-27 오후 10.05.40.png&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;1718&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OEHby/btsv8ih3zbt/2s3v9aoeOsQ8IDwRWXVPPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OEHby/btsv8ih3zbt/2s3v9aoeOsQ8IDwRWXVPPK/img.png&quot; data-alt=&quot;오뚜기 만세&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OEHby/btsv8ih3zbt/2s3v9aoeOsQ8IDwRWXVPPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOEHby%2Fbtsv8ih3zbt%2F2s3v9aoeOsQ8IDwRWXVPPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;743&quot; data-filename=&quot;스크린샷 2023-09-27 오후 10.05.40.png&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;1718&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;오뚜기 만세&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 해커톤에서 느낀점은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에 프로젝트할 때 &lt;b&gt;한번쯤은 꼭 Streamlit&lt;/b&gt;을 써봐야겠다고 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 백엔드 개발자다보니 프론트엔드쪽을 잘 몰라서, 지금 사이드 프로젝트 진행하는건&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나(&lt;b&gt;백엔드&lt;/b&gt;), &lt;b&gt;프론트엔드&lt;/b&gt;, &lt;b&gt;디자이너&lt;/b&gt;, &lt;b&gt;AI&lt;/b&gt; 이렇게 넷이서 하고 있지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Streamlit&lt;/b&gt;을 쓰면 나 혼자서도 &lt;b&gt;간단한 사이드 프로젝트&lt;/b&gt;는 할 수 있지않을까..? 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 사이드 프로젝트는 Streamlit으로 도전 !!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Participation</category>
      <category>AWS</category>
      <category>streamlit</category>
      <category>숙명여대</category>
      <category>해커톤</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/62</guid>
      <comments>https://ilikezzi.tistory.com/62#entry62comment</comments>
      <pubDate>Wed, 27 Sep 2023 22:30:48 +0900</pubDate>
    </item>
    <item>
      <title>[Nest.JS] Nest.JS에서 cache-manager를 활용한 캐싱 방법</title>
      <link>https://ilikezzi.tistory.com/61</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.15.54.png&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IcSTD/btst85FD9nF/Y1kqZZJg3FUd6nGAnL6ZFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IcSTD/btst85FD9nF/Y1kqZZJg3FUd6nGAnL6ZFk/img.png&quot; data-alt=&quot;Nest.JS&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IcSTD/btst85FD9nF/Y1kqZZJg3FUd6nGAnL6ZFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIcSTD%2Fbtst85FD9nF%2FY1kqZZJg3FUd6nGAnL6ZFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;257&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.15.54.png&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;860&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Nest.JS&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영중인 서비스에서 &lt;b&gt;응답시간이 느려진 부분&lt;/b&gt;이 있어서, 이를 &lt;b&gt;개선&lt;/b&gt;하고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마침 &lt;b&gt;유저 구분이 필요 없고, 수정이 거의 없는 페이지&lt;/b&gt;라서 &lt;b&gt;캐싱 전략&lt;/b&gt;을 사용하기 적합해 보였다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 페이지에 대해 간략하게 설명하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;당일&lt;/b&gt; &lt;b&gt;새벽시간의 뉴스데이터&lt;/b&gt;를 전부 분석을 해서 &lt;b&gt;아침 8시&lt;/b&gt;에&lt;b&gt; 그날의 뉴스를 한눈에 정리&lt;/b&gt;해서 보여주는 페이지다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_IMG_4833.jpg&quot; data-origin-width=&quot;1169&quot; data-origin-height=&quot;2011&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nj10A/btst6mukX33/FhIevs3VipkkfLjJfC28Q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nj10A/btst6mukX33/FhIevs3VipkkfLjJfC28Q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nj10A/btst6mukX33/FhIevs3VipkkfLjJfC28Q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNj10A%2Fbtst6mukX33%2FFhIevs3VipkkfLjJfC28Q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;688&quot; data-filename=&quot;edited_IMG_4833.jpg&quot; data-origin-width=&quot;1169&quot; data-origin-height=&quot;2011&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;유저별로 개인화&lt;/b&gt;가 들어가는 페이지도 아니고, 웬만해서는 &lt;b&gt;수정이 이뤄지지 않는&lt;/b&gt; API 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 바로&lt;b&gt; 캐싱작업&lt;/b&gt;을 시작해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 프로젝트로 이동해서 필요한 패키지를 몇가지 설치해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694878070366&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install cache-manager&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;cache-manager:&lt;/b&gt; &lt;b&gt;캐싱&lt;/b&gt;을 담당할 라이브러리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694878104678&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install @nestjs/common&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;nestjs의 CACHE_MANAGER:&lt;/b&gt; NestJS에서 &lt;b&gt;캐싱을 쉽게 관리&lt;/b&gt;하기 위한 것이니까 이것도 설치해줘야된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(일반적으로 NestJS 프로젝트를 시작할 때 이미 @nestjs/common은 &lt;b&gt;설치되어 있을것이다.&lt;/b&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694878219930&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install @types/cache-manager&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;TypeScript&lt;/b&gt;: 만약 TypeScript를 사용하고 있다면, &lt;b&gt;@types 패키지&lt;/b&gt;도 설치해야 할 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이제 전부 설치를 했으니 코드로 가보자.&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;캐싱 처리 코드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 &lt;b&gt;@Get&lt;/b&gt; 요청을 하는 API의 &lt;b&gt;Service부&lt;/b&gt;로 이동하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-09-17 오전 2.43.38.png&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;527&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdiQ9s/btsuqzEQIAc/Mk4JK0C2ojvnnBU2IECrHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdiQ9s/btsuqzEQIAc/Mk4JK0C2ojvnnBU2IECrHk/img.png&quot; data-alt=&quot; service 부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdiQ9s/btsuqzEQIAc/Mk4JK0C2ojvnnBU2IECrHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdiQ9s%2FbtsuqzEQIAc%2FMk4JK0C2ojvnnBU2IECrHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;472&quot; data-filename=&quot;edited_스크린샷 2023-09-17 오전 2.43.38.png&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;527&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; service 부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;b&gt;캐싱 처리 코드&lt;/b&gt;는 이런식으로 구현을 했는데, 이제 하나씩 코드를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694886427076&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { CACHE_MANAGER, Inject, Injectable } from '@nestjs/common';
import { Cache } from 'cache-manager';

@Injectable()
export class TodayService {
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;b&gt;@Inject(CACHE_MANAGER)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS에서&amp;nbsp;&lt;b&gt;Dependency&amp;nbsp;Injection&lt;/b&gt;을 사용하면서 @Inject 데코레이터를 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서&amp;nbsp;&lt;b&gt;CACHE_MANAGER&lt;/b&gt;는&amp;nbsp;특정&amp;nbsp;서비스나&amp;nbsp;객체를&amp;nbsp;주입할&amp;nbsp;때&amp;nbsp;사용되는&amp;nbsp;&lt;b&gt;토큰&lt;/b&gt;이라고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 토큰으로 어떤 객체를 주입할지 NestJS가 알게 된다고 보면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;b&gt;private cacheManager Cache&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;cacheManager&lt;/b&gt;는 주입받은 객체를 사용할 수 있는 클래스 내부의 변수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 변수의 타입은 &lt;b&gt;Cache&lt;/b&gt; 이다 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드의 주 목적은&lt;b&gt; Cache 타입의 객체&lt;/b&gt;를 &lt;b&gt;cacheManager라는 이름으로 클래스에 주입&lt;/b&gt;하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해&lt;b&gt; CACHE_MANAGER&lt;/b&gt;라는 토큰을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;cache-manager&lt;/b&gt;에서 캐싱을 쉽게 관리할 수 있게 &lt;b&gt;몇가지 메서드를 제공&lt;/b&gt;하는데 간단히 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1 .get(key)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 주어진 &lt;b&gt;키에 해당하는 값을 가져온다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &quot;key&quot; : 찾을 값의 키&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694887408616&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const value = await this.cacheManager.get('key');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. .set(key, value, [options])&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;캐시&lt;/b&gt;에 키-값 쌍을 &lt;b&gt;저장&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &quot;key&quot; : 저장할 키&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &quot;value&quot; : 저장할 값&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &quot;options&quot; : 옵션 객체. 보통 { ttl: 시간(초) } 이런 식으로 시간을 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694887430269&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;await this.cacheManager.set('key', 'value', { ttl: 60 });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 두가지 메서드로 &lt;b&gt;캐싱처리&lt;/b&gt;를 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694887796423&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async getData(key: string): Promise&amp;lt;any&amp;gt; {
    // 캐시에서 데이터 확인
    const cachedData = await this.cacheManager.get('temp');

    if (cachedData) {
      // 캐시에 데이터가 있으면 반환
      return cachedData;
    } else {

    // 캐시에 데이터가 없으면 새로 데이터를 생성 (DB 조회 등)
    const newData = await this.~~~~

    // 새로 생성한 데이터를 캐시에 저장
    await this.cacheManager.set('temp', newData, 360000 });  // ttl : 1시간 설정

    return newData;
  	}
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게&lt;b&gt; IF - ELSE문&lt;/b&gt; 으로 구현이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저장한 캐시데이터가 있는지 찾고,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캐시 데이터가 있으면&lt;/b&gt; 그대로 바로&lt;b&gt; 값을 return&lt;/b&gt;하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캐시 데이터가 없으면&lt;/b&gt; ELSE 쪽 로직을 돌면서 return 하기 직전에&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cacheManager.set() 으로 &lt;b&gt;ttl시간과 함께 캐시데이터를 저장&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 캐싱 구현을 마치고 &lt;b&gt;성능 테스트&lt;/b&gt;를 해봤는데 결과가 놀라웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;처음 로딩할 때&lt;/b&gt;는 캐싱데이터 .set() 을 하느라&lt;b&gt; 400ms&lt;/b&gt; 가량 걸렸는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그 후&lt;/b&gt; &lt;b&gt;캐싱 적용이 된&lt;/b&gt; 같은 페이지를 로딩 했을때엔&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;10ms 미만&lt;/b&gt;&lt;/span&gt;으로 엄청난 성능을 보여줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_IMG_4835.jpg&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfmM8E/btsuek9TwSN/Bjvb6niM2j8AAKQvNFIdE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfmM8E/btsuek9TwSN/Bjvb6niM2j8AAKQvNFIdE1/img.png&quot; data-alt=&quot;대만족 !&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfmM8E/btsuek9TwSN/Bjvb6niM2j8AAKQvNFIdE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfmM8E%2Fbtsuek9TwSN%2FBjvb6niM2j8AAKQvNFIdE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;228&quot; data-filename=&quot;edited_IMG_4835.jpg&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대만족 !&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사 직원분들도 빨라진 서비스에 만족을 하셨다 ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;장점, 단점, 주의사항&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캐싱의&amp;nbsp;장점&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빠른&lt;/b&gt; 데이터 접근: 캐싱된 데이터는 빠르게 접근할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 &lt;b&gt;부하 감소&lt;/b&gt;: 데이터베이스나 다른 서비스에 덜 접근하므로 서버 부하가 감소한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캐싱의&amp;nbsp;단점&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 데이터 &lt;b&gt;지연&lt;/b&gt;: 캐싱된 데이터가 최신이 아닐 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캐시 무효화&lt;/b&gt; 전략 필요: 언제 캐시를 지울지, 언제 새로운 데이터로 갱신할지에 대한 전략이 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의&amp;nbsp;사항&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시&amp;nbsp;&lt;b&gt;사이즈&lt;/b&gt;: 캐시 사이즈가 너무 크면 메모리 이슈가 생길 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시&amp;nbsp;&lt;b&gt;유효&amp;nbsp;시간&lt;/b&gt; (TTL): 너무 짧으면 캐싱의 의미가 없고, 너무 길면 데이터가 최신이 아니게 될 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 장단점과 주의사항을 보면 &lt;b&gt;추후에 개선&lt;/b&gt;해줘야 할 게 바로 떠오를 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 캐싱 처리 쪽 API 의 내용을 혹시나 &lt;b&gt;수정하게되면,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수정한 내용이 &lt;b&gt;TTL 시간이 지날때 까지 반영이 되지 않을 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서&lt;span style=&quot;color: #ee2323;&quot;&gt; &lt;b&gt;@Update API쪽에 캐싱 초기화&lt;/b&gt;&lt;/span&gt;를 넣으면 좋을것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐싱 초기화는 &lt;b&gt;두가지 방법&lt;/b&gt;이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- del :&lt;/b&gt; 특정 키로 저장된 캐시 삭제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694885656235&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;this.cacheManager.del('키', (err) =&amp;gt; {
  if (err) {
    // 에러 처리
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- reset:&lt;/b&gt; 모든 캐시 삭제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694885684050&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;this.cacheManager.reset((err) =&amp;gt; {
  if (err) {
    // 에러 처리
  }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두가지중에 &lt;b&gt;Update&lt;/b&gt;&amp;nbsp;API에 넣기 적합한 건 &lt;b&gt;&quot;del&quot;&lt;/b&gt; 이므로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추후에 작업을 할 때, 해당 &lt;b&gt;Update 로직에 캐싱초기화를 추가&lt;/b&gt;해야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조 : &lt;a href=&quot;https://docs.nestjs.com/techniques/caching&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.nestjs.com/techniques/caching&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1694888249619&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Documentation | NestJS - A progressive Node.js framework&quot; data-og-description=&quot;Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea&quot; data-og-host=&quot;docs.nestjs.com&quot; data-og-source-url=&quot;https://docs.nestjs.com/techniques/caching&quot; data-og-url=&quot;https://docs.nestjs.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DnIX3/hyTVVDLGsR/fFtlGVllQjdHFFxagczjR1/img.png?width=820&amp;amp;height=429&amp;amp;face=0_0_820_429&quot;&gt;&lt;a href=&quot;https://docs.nestjs.com/techniques/caching&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.nestjs.com/techniques/caching&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DnIX3/hyTVVDLGsR/fFtlGVllQjdHFFxagczjR1/img.png?width=820&amp;amp;height=429&amp;amp;face=0_0_820_429');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Documentation | NestJS - A progressive Node.js framework&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.nestjs.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/NestJS</category>
      <category>Cache</category>
      <category>nestJS</category>
      <category>캐싱</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/61</guid>
      <comments>https://ilikezzi.tistory.com/61#entry61comment</comments>
      <pubDate>Sun, 17 Sep 2023 03:31:10 +0900</pubDate>
    </item>
    <item>
      <title>[Error] 504 Gateway Timeout Error 해결: Nginx와 로드밸런서 타임아웃</title>
      <link>https://ilikezzi.tistory.com/60</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-09-15 오후 7.18.19.png&quot; data-origin-width=&quot;1014&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7pEvp/btsuehrsBrZ/Uo12SPF81wKopuSA3UANck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7pEvp/btsuehrsBrZ/Uo12SPF81wKopuSA3UANck/img.png&quot; data-alt=&quot;504 Error&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7pEvp/btsuehrsBrZ/Uo12SPF81wKopuSA3UANck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7pEvp%2FbtsuehrsBrZ%2FUo12SPF81wKopuSA3UANck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;339&quot; data-filename=&quot;스크린샷 2023-09-15 오후 7.18.19.png&quot; data-origin-width=&quot;1014&quot; data-origin-height=&quot;688&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;504 Error&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼마 전 회사 프론트직원분께서 staging admin에서 &lt;b&gt;504에러&lt;/b&gt;가 뜬다고 찾으셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 바로 staging Swagger에서 관련 API를 날려보니 다음과 같이 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-09-15 오후 7.26.09.png&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;856&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o2gDV/btsufY59U9N/O38jSSV3LMl29EN6tciVIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o2gDV/btsufY59U9N/O38jSSV3LMl29EN6tciVIk/img.png&quot; data-alt=&quot;504 Gateway Time-out&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o2gDV/btsufY59U9N/O38jSSV3LMl29EN6tciVIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo2gDV%2FbtsufY59U9N%2FO38jSSV3LMl29EN6tciVIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;380&quot; data-filename=&quot;스크린샷 2023-09-15 오후 7.26.09.png&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;856&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;504 Gateway Time-out&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인해보니&lt;b&gt; 504 Time-out&lt;/b&gt; 에러가 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 차근차근 해결을 해보자 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결 1 - axios timeout 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 API 부분은 &lt;b&gt;axios&lt;/b&gt;로 코드를 불러와서 파싱한 후 리턴하는 코드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios 할 때 일정 시간을 초과하면 504에러가 뜰 수 있다는 얘기가 있어서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 &lt;b&gt;time-out 시간을 늘려주기&lt;/b&gt;로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-09-15 오후 7.48.24.png&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cs4pvb/btst6qC88bh/Oc06nTqoAkWrYKqmQ9bZx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cs4pvb/btst6qC88bh/Oc06nTqoAkWrYKqmQ9bZx1/img.png&quot; data-alt=&quot; axios - code&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cs4pvb/btst6qC88bh/Oc06nTqoAkWrYKqmQ9bZx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcs4pvb%2Fbtst6qC88bh%2FOc06nTqoAkWrYKqmQ9bZx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;351&quot; data-filename=&quot;edited_스크린샷 2023-09-15 오후 7.48.24.png&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; axios - code&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갑자기 504에러가 뜬 이유는 axios로 받아오는 &lt;b&gt;chatGpt 관련 처리시간이 늦어진듯&lt;/b&gt; 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 timeout 을 &lt;b&gt;10분&lt;/b&gt;으로 넉넉히 변경하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694776342050&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;timeout : 600000&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬에서 코드를 돌렸을때엔&lt;b&gt; 100초&lt;/b&gt;정도 뒤에 504에러없이 잘 출력되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 바로 staging로 배포를 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;staging Swagger&lt;/b&gt;에서 동일하게 해당 API를 돌려보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엥?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-09-15 오후 7.26.09.png&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;856&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o2gDV/btsufY59U9N/O38jSSV3LMl29EN6tciVIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o2gDV/btsufY59U9N/O38jSSV3LMl29EN6tciVIk/img.png&quot; data-alt=&quot;504 Gateway Time-out&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o2gDV/btsufY59U9N/O38jSSV3LMl29EN6tciVIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo2gDV%2FbtsufY59U9N%2FO38jSSV3LMl29EN6tciVIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;380&quot; data-filename=&quot;스크린샷 2023-09-15 오후 7.26.09.png&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;856&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;504 Gateway Time-out&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 이전과 같은&lt;b&gt; 504 에러&lt;/b&gt;가 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬에선 정상적으로 실행됬는데 staging에서 에러가 뜨는거 보면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유추해볼만한 &lt;b&gt;케이스는 두가지&lt;/b&gt;가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Nginx의 타임아웃 설정&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. AWS ELB의 타임아웃 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 1, 2번을 하나씩 해결해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;해결 2 - Nginx&amp;nbsp;timeout 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS &lt;b&gt;EC2&lt;/b&gt;에서 해당 인스턴스를 찾고&lt;b&gt; SSH 터미널&lt;/b&gt;을 사용해 접속하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-09-16 오후 10.32.14.png&quot; data-origin-width=&quot;1658&quot; data-origin-height=&quot;1424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wSA3u/btst87pTb90/eEVdPXbmpUxzpfWajWL6iK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wSA3u/btst87pTb90/eEVdPXbmpUxzpfWajWL6iK/img.png&quot; data-alt=&quot;EC2 Instance Connect&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wSA3u/btst87pTb90/eEVdPXbmpUxzpfWajWL6iK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwSA3u%2Fbtst87pTb90%2FeEVdPXbmpUxzpfWajWL6iK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;515&quot; data-filename=&quot;edited_스크린샷 2023-09-16 오후 10.32.14.png&quot; data-origin-width=&quot;1658&quot; data-origin-height=&quot;1424&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;EC2 Instance Connect&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;Nginx의 메인 설정 파일&lt;/b&gt;을 열어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694871564910&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo vi /etc/nginx/sites-available/default

// 뒤에 default 자리엔 server_name을 써주면 된다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nginx 설정 파일로 이동했으면 사진처럼 &lt;b&gt;location /&lt;/b&gt; 으로 이동해서 &lt;b&gt;timeout 코드를 추가&lt;/b&gt;해 주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-09-16 오후 10.57.57.png&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;197&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rI7xt/btsuegGoeph/wqhJGTMIz9X6BePldNknvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rI7xt/btsuegGoeph/wqhJGTMIz9X6BePldNknvk/img.png&quot; data-alt=&quot;Nginx 설정파일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rI7xt/btsuegGoeph/wqhJGTMIz9X6BePldNknvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrI7xt%2FbtsuegGoeph%2FwqhJGTMIz9X6BePldNknvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;499&quot; height=&quot;197&quot; data-filename=&quot;edited_스크린샷 2023-09-16 오후 10.57.57.png&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;197&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Nginx 설정파일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694872769727&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;location / {
    ...
    proxy_connect_timeout 600s;
    proxy_send_timeout 600s;
    proxy_read_timeout 600s;
    send_timeout 600s;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간은 넉넉히 &lt;b&gt;10분&lt;/b&gt;으로 변경했다.&lt;br /&gt;&lt;br /&gt;이제 Nginx 설정파일을 저장 &quot;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;:wq&lt;/b&gt;&lt;/span&gt;&quot; 하고 나오자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694872930023&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo nginx -s reload&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 해당 명령어로 &lt;b&gt;Nginx를 재시작&lt;/b&gt; 시켜주면 설정 끝이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다시 &lt;b&gt;Staging Swagger&lt;/b&gt;로 가서 해당 API를 실행 시켜주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-09-15 오후 7.26.09.png&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;856&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o2gDV/btsufY59U9N/O38jSSV3LMl29EN6tciVIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o2gDV/btsufY59U9N/O38jSSV3LMl29EN6tciVIk/img.png&quot; data-alt=&quot;504 Gateway Time-out&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o2gDV/btsufY59U9N/O38jSSV3LMl29EN6tciVIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo2gDV%2FbtsufY59U9N%2FO38jSSV3LMl29EN6tciVIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;380&quot; data-filename=&quot;스크린샷 2023-09-15 오후 7.26.09.png&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;856&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;504 Gateway Time-out&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엥?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시나 &lt;b&gt;Nginx 설정 코드&lt;/b&gt;가 반영이 안되는건가 싶어서 테스트 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1694873237963&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;location / {
    ...
    proxy_connect_timeout 3s;
    proxy_send_timeout 3s;
    proxy_read_timeout 3s;
    send_timeout 3s;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 설정 &lt;b&gt;SSH 터미널&lt;/b&gt;로 가서 Nginx 설정을 다음과 같이 &lt;b&gt;3초&lt;/b&gt;로 바꿔주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러고 Nginx를 &lt;b&gt;재시작&lt;/b&gt;하고 Staging Swagger에서 API를 실행해보니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확히 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;3초만에 504 Error&lt;/span&gt;&lt;/b&gt;가 나왔다..!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이제 Nginx time-out 설정은 &lt;b&gt;잘 반영되는걸 확인&lt;/b&gt;했으니 다시 원래대로&amp;nbsp;&lt;b&gt;600초&lt;/b&gt;로 변경해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;해결 3 - ELB timeout 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른게 전부 이상없으니 이제 마지막으로 &lt;b&gt;ELB time-out 설정&lt;/b&gt;을 바꿔보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;EC2 -&amp;gt; 로드 밸런서 -&amp;gt; 해당 ELB&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 이동해 ELB로 들어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;928&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AvSa4/btst7uljVxJ/qa6UwM6VwBJiQNQQgxnoh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AvSa4/btst7uljVxJ/qa6UwM6VwBJiQNQQgxnoh1/img.png&quot; data-alt=&quot;AWS ELB&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AvSa4/btst7uljVxJ/qa6UwM6VwBJiQNQQgxnoh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAvSa4%2Fbtst7uljVxJ%2Fqa6UwM6VwBJiQNQQgxnoh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;450&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;928&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AWS ELB&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크롤 내려서 &lt;b&gt;속성&lt;/b&gt;에서 &lt;b&gt;편집&lt;/b&gt;에 들어가서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;유휴 제한 시간&quot;&lt;/b&gt; 을 사진처럼 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;600초&lt;/b&gt;&lt;/span&gt;로 맞춰주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;ELB timeout 설정&lt;/b&gt;은 간단하게 끝났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Staging Swagger&lt;/b&gt;로 이동해서 기도를 하며 API를 날려보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-09-16 오후 11.23.08.png&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;299&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cL7IF1/btsufWU9V3j/ejK0UrOOGK6METC9GF4ET0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cL7IF1/btsufWU9V3j/ejK0UrOOGK6METC9GF4ET0/img.png&quot; data-alt=&quot; Success!!!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cL7IF1/btsufWU9V3j/ejK0UrOOGK6METC9GF4ET0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcL7IF1%2FbtsufWU9V3j%2FejK0UrOOGK6METC9GF4ET0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;457&quot; height=&quot;299&quot; data-filename=&quot;edited_스크린샷 2023-09-16 오후 11.23.08.png&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;299&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; Success!!!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;....!!!&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 정상적으로 &lt;b&gt;504 Error 없이 해결&lt;/b&gt;되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹에가서 한번 확인해보니, &lt;b&gt;80초&lt;/b&gt; 가량 걸려서 에러없이 잘 출력되는걸 확인했다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결완료 ^___^&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Error</category>
      <category>504</category>
      <category>elb</category>
      <category>error</category>
      <category>nginx</category>
      <category>timeout</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/60</guid>
      <comments>https://ilikezzi.tistory.com/60#entry60comment</comments>
      <pubDate>Sat, 16 Sep 2023 23:29:26 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 콜백 함수_코어 자바스크립트</title>
      <link>https://ilikezzi.tistory.com/59</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;1602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H2Es4/btssTqKJMPq/lCHZpOsgNtjn1C7IOAfBWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H2Es4/btssTqKJMPq/lCHZpOsgNtjn1C7IOAfBWK/img.png&quot; data-alt=&quot;코어 자바스크립트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H2Es4/btssTqKJMPq/lCHZpOsgNtjn1C7IOAfBWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH2Es4%2FbtssTqKJMPq%2FlCHZpOsgNtjn1C7IOAfBWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;617&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;1602&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코어 자바스크립트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;오늘은 4단원인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&quot;콜백 함수&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;를 포스팅 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에 &lt;b&gt;&quot;콜백 함수 내부에서의 this&quot;&lt;/b&gt; 에 대해서 깊게 다루니&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 포스팅인 &lt;b&gt;&quot;this&quot;&lt;/b&gt; 에 대해서 필수적으로 알고 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/58&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ilikezzi.tistory.com/58&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1693698289024&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Javascript] this_코어 자바스크립트&quot; data-og-description=&quot;오늘은 3단원인 &amp;quot;this&amp;quot; 를 포스팅 할 것이다. 지난번 포스팅한 &amp;quot;실행 컨텍스트&amp;quot; 도 읽어보면 도움이 될 듯하다. https://ilikezzi.tistory.com/55 [Javascript] 실행 컨텍스트_코어 자바스크립트 저번에 포스팅&quot; data-og-host=&quot;ilikezzi.tistory.com&quot; data-og-source-url=&quot;https://ilikezzi.tistory.com/58&quot; data-og-url=&quot;https://ilikezzi.tistory.com/58&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b1VZ70/hyTL8qsMMZ/zn5UFImYLVJ5WJNVvsrA2K/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/4WfHY/hyTMeKXsNh/hDJdkGtBC6KpEz0XYkGhk1/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/b1yF4v/hyTPygJcwZ/dtAPi77MpYIYZXqnfOlXqk/img.png?width=1038&amp;amp;height=1602&amp;amp;face=0_0_1038_1602&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/58&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ilikezzi.tistory.com/58&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b1VZ70/hyTL8qsMMZ/zn5UFImYLVJ5WJNVvsrA2K/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/4WfHY/hyTMeKXsNh/hDJdkGtBC6KpEz0XYkGhk1/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/b1yF4v/hyTPygJcwZ/dtAPi77MpYIYZXqnfOlXqk/img.png?width=1038&amp;amp;height=1602&amp;amp;face=0_0_1038_1602');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Javascript] this_코어 자바스크립트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 3단원인 &quot;this&quot; 를 포스팅 할 것이다. 지난번 포스팅한 &quot;실행 컨텍스트&quot; 도 읽어보면 도움이 될 듯하다. https://ilikezzi.tistory.com/55 [Javascript] 실행 컨텍스트_코어 자바스크립트 저번에 포스팅&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;04. 콜백 함수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;콜백 함수란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백 함수는 쉽게 말해 &lt;b&gt;함수 안에 함수&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;다른 함수의 인자로 전달&lt;/b&gt;되는 함수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기&amp;nbsp;작업이&amp;nbsp;끝나면&amp;nbsp;어떤&amp;nbsp;작업을&amp;nbsp;해야&amp;nbsp;할지를&amp;nbsp;콜백&amp;nbsp;함수로&amp;nbsp;지정할&amp;nbsp;수&amp;nbsp;있어서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 &lt;b&gt;비동기 작업에서 자주 사용&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백 함수는&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; 제어권&lt;/span&gt;&lt;/b&gt;과 관련이 깊다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 내가 친구에게 &quot;나 이따가 연락할 테니까, 그때 전화받아줘!&quot;라고 부탁했다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 친구는 &quot;전화받는 일&quot;이라는 특정 작업을 담당하게 되고, 그 &lt;b&gt;'제어권'&lt;/b&gt;을 가지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 전화를 걸면 친구는 그 전화를 받아 '약속한 대로' 행동을 하는게 이게 바로 제어권을 넘겨주는 상황이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;콜백 함수&lt;/b&gt;도 비슷하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 함수나 이벤트가 일어났을 때, &quot;이제 너 차례야, 이 일을 해줘!&quot;라고 다른 함수에게 &lt;b&gt;제어권&lt;/b&gt;을 넘기는 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;인자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1693699935218&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var newArr = [10, 20, 30].map(function (currentValue, index) {
  console.log(currentValue, index);
  return currentValue + 5;
});
console.log(newArr);

// 10 0
// 20 1
// 30 2
// [15, 25, 35]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 할당 되는 콜백함수 예제가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;map 메서드&lt;/b&gt;의 구조를 확인해보면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1693700101595&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Array.prototype.map(callback[, thisArg])
callback: function(currentValue, index, array)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map 메서드는 &lt;b&gt;첫번째 인자로 콜백함수&lt;/b&gt;를 받고, &lt;b&gt;생략가능한 두번째 인자로 콜백함수 내부에서의 this를 지정&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thisArg를 생략할 경우엔 일반 함수와 마찬가지로 &lt;b&gt;전역객체&lt;/b&gt;가 바인딩 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 코드에서 콘솔값이 할당되는건 쉽게 이해를 했을것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 한번 콜백함수 내부의 첫번째 인자를 index, 두번째 인자를 currentValue가 오게 변경해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1693700500233&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var newArr2 = [10, 20, 30].map(function (index, currentValue) {
  console.log(index, currentValue);
  return currentValue + 5;
});
console.log(newArr2);

// 10 0
// 20 1
// 30 2
// [5, 6, 7]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로만든 newArr2를 보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람은 &lt;b&gt;'index' , 'currentValue'&lt;/b&gt; 단어로 접근하기 때문에 순서를 바꿔도 의미가 바뀌지 않으니깐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 없을 것이라 생각하기 쉽지만, 컴퓨터는 그저 첫번째 두번째 &lt;b&gt;순서&lt;/b&gt;에 의해서만 구분한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 마지막에 콘솔값을 보면 각각 &lt;b&gt;[15, 25, 35] // [5, 6, 7]&lt;/b&gt; 로 서로 다르게 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;newArr2에&lt;b&gt; currentValue&lt;/b&gt;라고 명명한 인자의 &lt;b&gt;위치가 두번째&lt;/b&gt;라서 컴퓨터가 여기에&lt;b&gt; 인덱스 값&lt;/b&gt;을 부여하게 된 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;콜백함수를 호출하는 주제가 사용자가 아닌 map 메서드이므로&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하는 배열을 얻으려면 &lt;b&gt;map 메서드에 정의된 규칙에 따라 함수를 작성해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map메서드가 콜백함수를 호출할 때 인자에 어떤값들을 어떤순서로 넘길 것인지가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전적으로 map메서드&lt;/b&gt;에게 달린것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 콜백함수의 &lt;b&gt;제어권&lt;/b&gt;을 넘겨받은 코드는 콜백함수를 호출할 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인자에 &lt;b&gt;어떤값들을 어떤순서로 넘길 것&lt;/b&gt;인지에 대한 &lt;b&gt;제어권&lt;/b&gt;을 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;this&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백함수도 함수이기 때문에 &lt;b&gt;기본적으로는 this가 전역객체&lt;/b&gt;를 참조하지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제어권을 넘겨받을 코드에서 콜백함수에 &lt;b&gt;별도로 this가 될 대상을 지정한 경우&lt;/b&gt;엔 그 대상을 참조한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1693760512832&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;setTimeout(function () { console.log(this); }, 300); 

[1, 2, 3, 4, 5].forEach(function(x) {
	console.log(this);
});

// (1) Window {...}
// (2) Window {...}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 두 콜백함수 내부에서의 this는 콘솔을 찍어보면 둘 다&lt;b&gt; 전역객체&lt;/b&gt;를 가리킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘다 따로 &lt;b&gt;명시적으로 this를 바인딩하지 않았기&lt;/b&gt; 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 &lt;b&gt;전역 컨텍스트&lt;/b&gt;에서 실행되기 때문에 Window {...} 가 출력된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1693766295706&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const obj = {
  vals: [1, 2, 3],
  logValues: function (v, i) {
    console.log(this, v, i);
  },
};


obj.logValues(1, 2); 				// { vals: [1, 2, 3], logValues: f} 1 2
[4, 5, 6].forEach(obj.logValues);	// Window {...} 4 0
									// Window {...} 5 1
									// Window {...} 6 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;해당 코드에서 첫번째의 출력을 보면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;이름앞에 점&lt;/b&gt;이 있으니 &lt;b&gt;메서드로서 호출&lt;/b&gt; 한 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;따라서 &lt;b&gt;this는 obj&lt;/b&gt;를 가리키고 인자로 넘어온&lt;b&gt; 1, 2&lt;/b&gt; 가 출력된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;두번째의 출력은 다른 방식으로 작동한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;forEach&lt;/b&gt;에서 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;obj.logValues가 콜백으로 전달되면, 이 함수는 일반 함수로 호출된다&lt;/span&gt;&lt;/b&gt;.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그래서 &lt;b&gt;this가 전역 객체&lt;/b&gt;를 가리키는 거다. &lt;b&gt;(obj X)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 원래 obj.logValues는 obj라는 객체 안에 있었지만,&lt;b&gt; forEach 안에서는 그 연결이 끊어지게 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 this를 obj로 지정하고 싶다면 &lt;b&gt;별도로 this인자를 지정&lt;/b&gt;하거나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;call, apply, bind&lt;/b&gt; 같은 메서드를 사용해 this를 지정해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 &lt;b&gt;&quot;this&quot; 포스팅&lt;/b&gt;에서 다뤘지만 한번 더 &lt;b&gt;call, apply, bind&lt;/b&gt;에 대해서 짚고 넘어가자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;call&lt;/h4&gt;
&lt;pre id=&quot;code_1693766978386&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Func.call(obj, arg1, arg2, ...);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.&amp;nbsp; obj는 명시적으로 &lt;b&gt;this를 어떤 객체로 바인딩&lt;/b&gt;할지 정해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 그 다음으로 함수에 필요한 인자값들을 차례대로 넘겨준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;apply&lt;/h4&gt;
&lt;pre id=&quot;code_1693767143457&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Func.apply(obj, [arg1, arg2, ...]);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1.&amp;nbsp; obj는 명시적으로 &lt;b&gt;this를 어떤 객체로 바인딩&lt;/b&gt;할지 정해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. 그 다음으로 함수에 필요한 인자값들을 차례대로 넘겨준다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp; &amp;nbsp; (call 과 차이점은 인자를 &lt;b&gt;배열&lt;/b&gt; 형태로 넘긴다)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;bind&lt;/h4&gt;
&lt;pre id=&quot;code_1693767160682&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const boundFunc = Func.bind(obj);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. &lt;b&gt;새로운 함수&lt;/b&gt;를 만들어서 반환한다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. 그 함수의 &lt;b&gt;this는 bind로 지정한 객체&lt;/b&gt;로 고정되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;콜백 지옥&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백&amp;nbsp;지옥이라는&amp;nbsp;건,&amp;nbsp;&lt;b&gt;콜백&amp;nbsp;함수가&amp;nbsp;다른&amp;nbsp;콜백&amp;nbsp;함수&amp;nbsp;내부에서&amp;nbsp;또&amp;nbsp;호출되고,&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그 안에서 또 다른 콜백 함수가 호출되는 등&lt;/b&gt; 이런식으로 &lt;b&gt;깊어지는 상황&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게&amp;nbsp;되면&amp;nbsp;코드가&amp;nbsp;정말&amp;nbsp;&lt;b&gt;복잡해&lt;/b&gt;져서 읽기도 어렵고, 유지보수도 힘들어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1693767977812&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 콜백 지옥

setTimeout(() =&amp;gt; {
  console.log('첫 번째 작업');
  setTimeout(() =&amp;gt; {
    console.log('두 번째 작업');
    setTimeout(() =&amp;gt; {
      console.log('세 번째 작업');
    }, 1000);
  }, 1000);
}, 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백 지옥을 보면 들여쓰기가 깊어지는 것처럼 코드가 &amp;gt;)&amp;gt;)&amp;gt;)&amp;gt;) 이런 모양이 돼서, &quot;피라미드 코드&quot;라고도 부르기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 코드의 가독성을 낮추고, 오류를 찾기 어렵게 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 가독성 문제와 어색함을 동시에 해결하는 가장 간단한 방법은&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;익명의 콜백 함수를 모두 기명함수로 전환하는&lt;/b&gt; 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1693768082853&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 기명 함수

function thirdJob() {
  console.log('세 번째 작업');
}

function secondJob() {
  console.log('두 번째 작업');
  setTimeout(thirdJob, 1000);
}

function firstJob() {
  console.log('첫 번째 작업');
  setTimeout(secondJob, 1000);
}

setTimeout(firstJob, 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기명 함수는 &lt;b&gt;재사용&lt;/b&gt;하기 좋고, &lt;b&gt;디버깅&lt;/b&gt;할 때도 편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름이 있으니까&lt;b&gt; 함수의 목적&lt;/b&gt;이 뭔지 더 쉽게 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이렇게 일회성 함수를 전부 변수에 할당하는 것이 불만일수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 마침 &lt;b&gt;ES6에서 Promise&lt;/b&gt; 가 도입되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1693768239186&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Promise

const wait = ms =&amp;gt; new Promise(resolve =&amp;gt; setTimeout(resolve, ms));

wait(1000).then(() =&amp;gt; {
  console.log('첫 번째 작업');
  return wait(1000);
}).then(() =&amp;gt; {
  console.log('두 번째 작업');
  return wait(1000);
}).then(() =&amp;gt; {
  console.log('세 번째 작업');
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promise에 대해서 간략히 설명하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promise는 크게&lt;b&gt; resolve와 reject&lt;/b&gt; &lt;b&gt;두 가지 상태&lt;/b&gt;를 가지고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;resolve&lt;/b&gt;는&amp;nbsp;&lt;b&gt;작업이&amp;nbsp;성공적&lt;/b&gt;으로 끝났을 때 호출되고,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;reject&lt;/b&gt;는&amp;nbsp;&lt;b&gt;에러&lt;/b&gt;가 발생했을 때 호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드에서는 wait라는 함수를 선언했는데, 이 함수는 일정 시간(ms)이 지난 후에 resolve를 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 .then()을 통해 이후에 실행할 작업을 쭉 이어나갈 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 wait(1000)은 1초 후에 resolve되고, .then() 안의 첫 번째 작업이 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음에 또 wait(1000)을 호출하고, 두 번째 작업을 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 세 번째 작업까지 이어나간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Promise를 사용하면, &lt;b&gt;각 단계별로&lt;/b&gt; 어떤 작업을 해야 할지 &lt;b&gt;명확하게 표현&lt;/b&gt;할 수 있어서 코드가 훨씬 깔끔하고 이해하기 쉬워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 &lt;b&gt;ES2017&lt;/b&gt;에서는 가독성이 뛰어나면서 작성법도 간단한 새로운 기능이 추가되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 &lt;b&gt;async / await&lt;/b&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1693768569764&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// async / await

const wait = ms =&amp;gt; new Promise(resolve =&amp;gt; setTimeout(resolve, ms));

async function run() {
  await wait(1000);
  console.log('첫 번째 작업');
  
  await wait(1000);
  console.log('두 번째 작업');

  await wait(1000);
  console.log('세 번째 작업');
}

run();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비동기 작업&lt;/b&gt;을 수행하고자 하는 &lt;b&gt;함수앞에 async&lt;/b&gt;를 표기하고,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 내부에서 실질적인 &lt;b&gt;비동기 작업이 필요한 위치마다 await&lt;/b&gt;를 표기하는 것만으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤의 내용을 Promise로 자동 전환하고, 해당 내용이 resolve된 이후에야 다음으로 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 &lt;b&gt;Promise의 then&lt;/b&gt;과 흡사한 기능을 하게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 이렇게&lt;b&gt; 콜백 함수&lt;/b&gt;에 대해서 자세히 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 챕터는 &lt;b&gt;&quot;클로저&quot;&lt;/b&gt; 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/Javascript</category>
      <category>js</category>
      <category>코어 자바스크립트</category>
      <category>콜백 함수</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/59</guid>
      <comments>https://ilikezzi.tistory.com/59#entry59comment</comments>
      <pubDate>Mon, 4 Sep 2023 04:24:52 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] this_코어 자바스크립트</title>
      <link>https://ilikezzi.tistory.com/58</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;1602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cj6gmz/btsrCSh5P7o/GFXcsgFu6xGaiaCVh1nIJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cj6gmz/btsrCSh5P7o/GFXcsgFu6xGaiaCVh1nIJK/img.png&quot; data-alt=&quot;코어 자바스크립트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cj6gmz/btsrCSh5P7o/GFXcsgFu6xGaiaCVh1nIJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcj6gmz%2FbtsrCSh5P7o%2FGFXcsgFu6xGaiaCVh1nIJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;617&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;1602&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코어 자바스크립트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 3단원인 &lt;b&gt;&quot;this&quot; &lt;/b&gt;를 포스팅 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난번 포스팅한 &quot;&lt;b&gt;실행 컨텍스트&lt;/b&gt;&quot; 도 읽어보면 도움이 될 듯하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/55&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ilikezzi.tistory.com/55&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1692643670707&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Javascript] 실행 컨텍스트_코어 자바스크립트&quot; data-og-description=&quot;저번에 포스팅한 &amp;quot;데이터 타입&amp;quot; 에 이어서 다음 챕터인 &amp;quot;실행 컨텍스트&amp;quot;를 포스팅 할 것이다. https://ilikezzi.tistory.com/52 [Javascript] 데이터 타입_코어 자바스크립트 계획했던대로 자격증 취득도 다 &quot; data-og-host=&quot;ilikezzi.tistory.com&quot; data-og-source-url=&quot;https://ilikezzi.tistory.com/55&quot; data-og-url=&quot;https://ilikezzi.tistory.com/55&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bWbtgq/hyTFfQAjyA/0pyzw0e1vKUQKrKvI103j1/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/dthGdQ/hyTIFNBOfU/kIlKorGtTLTc9PARd6CEV0/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/b4V0vU/hyTIDoIz2U/ol3WO7VIVsXCOM9QXgPET1/img.png?width=1038&amp;amp;height=1602&amp;amp;face=0_0_1038_1602&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/55&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ilikezzi.tistory.com/55&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bWbtgq/hyTFfQAjyA/0pyzw0e1vKUQKrKvI103j1/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/dthGdQ/hyTIFNBOfU/kIlKorGtTLTc9PARd6CEV0/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/b4V0vU/hyTIDoIz2U/ol3WO7VIVsXCOM9QXgPET1/img.png?width=1038&amp;amp;height=1602&amp;amp;face=0_0_1038_1602');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Javascript] 실행 컨텍스트_코어 자바스크립트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;저번에 포스팅한 &quot;데이터 타입&quot; 에 이어서 다음 챕터인 &quot;실행 컨텍스트&quot;를 포스팅 할 것이다. https://ilikezzi.tistory.com/52 [Javascript] 데이터 타입_코어 자바스크립트 계획했던대로 자격증 취득도 다&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;this....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;'이것'&lt;/b&gt; 이라는 단어 그 자체로의 뜻을 가지지만, 가끔씩 &lt;b&gt;어디를 가르키는건지&lt;/b&gt; 헷갈렸는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 그 헷갈리던 this에 대해서 제대로 잡아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. this&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전역 공간에서의 this&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저 환경에서 전역객체는 &lt;b&gt;window&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js.환경에서 전역객체는 &lt;b&gt;global&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전역변수&lt;/b&gt;를&lt;span&gt; &lt;/span&gt;선언하면&lt;span&gt; &lt;/span&gt;자바스크립트&lt;span&gt; &lt;/span&gt;엔진은&lt;span&gt; &lt;/span&gt;이를&lt;span&gt; &lt;/span&gt;전역객체의&lt;span&gt; &lt;/span&gt;&lt;b&gt;프로퍼티로&lt;span&gt; &lt;/span&gt;할당한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 예제 코드를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692644408252&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 브라우저 환경 예시

var a = 1;
console.log(a); = 1
console.log(window.a) = 1
console.log(this.a) = 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 자바스크립트의&lt;span&gt; &lt;/span&gt;모든&lt;span&gt; &lt;/span&gt;변수는&lt;span&gt; &lt;/span&gt;실은&lt;span style=&quot;color: #ee2323;&quot;&gt; &lt;b&gt;특정객체의 프로퍼티&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이는 &lt;b&gt;var&lt;/b&gt;에만 해당 되는 얘기다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var&lt;/b&gt;는 &lt;b&gt;함수범위&lt;/b&gt;여서 현재 실행 컨텍스트의 전역 객체의 프로퍼티로 할당되지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;let, cons&lt;/b&gt;t는 &lt;b&gt;블록 범위&lt;/b&gt;여서 전역 객체의 프로퍼티로 &lt;b&gt;할당되지 않는다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692644971032&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var myVar = &quot;hello&quot;; // 전역 객체의 프로퍼티로 할당됨
let myLet = &quot;world&quot;; // 전역 객체의 프로퍼티로 할당되지 않음


console.log(window.myVar); // &quot;hello&quot;
console.log(window.myLet); // undefined&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 머쓱하지만 처음 알게된 부분이 있다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음부터&lt;b&gt; 전역객체의 프로퍼티로 할당&lt;/b&gt;한 경우에는 &lt;b&gt;삭제&lt;/b&gt;가 되는 반면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전역 변수&lt;/b&gt;로 선언한 경우에는 &lt;b&gt;삭제가 되지않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔소린지 코드로 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692645667614&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var a = 1;
delete window.a;                 // false
console.log(a, window.a, this.a) // 1 1 1

var b = 2;
delete b;                        // false
console.log(b, window.b, this.b) // 2 2 2



window.c = 3;
delete window.c;                 // true
console.log(c, window.c, this.c) // Uncaught ReferenceErrorr: c is not defined

window.d = 4;
delete d;                        // true
console.log(d, window.d, this.d) // Uncaught ReferenceErrorr: d is not defined&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 두개랑 아래 두개의 차이점을 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 두개는 &lt;b&gt;전역변수로 선언&lt;/b&gt;을 해서 삭제가 안되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 두개는 처음부터 &lt;b&gt;전역변수의 프로퍼티로 할당&lt;/b&gt;을 해서 문제 없이 삭제가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 그럴까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 사용자가 의도치 않게 삭제하는 것을 방지하는 차원에서 마련한 나름의 &lt;b&gt;방어 전략&lt;/b&gt;이라고 해석된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전역변수로 선언시,&lt;/b&gt; JS엔진이 이를 &lt;b&gt;자동&lt;/b&gt;으로 전역객체의 프로퍼티로 할당하면서 추가적으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 프로퍼티의 &lt;b&gt;configurable 속성&lt;/b&gt;(변경 및 삭제 가능성)을 &lt;b&gt;false&lt;/b&gt;로 정의해버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메서드로서 호출할 때의 this&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 함수로서의 호출과 메서드로서의 호출이 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드로서의 호출은 되게 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;점 표기법 (.)&lt;/b&gt; 이든 &lt;b&gt;대괄호 표기법&lt;/b&gt;이든, 어떤 함수를 호출할 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그&lt;b&gt; 함수이름 앞에 객체가 명시&lt;/b&gt;되어 있으면 메서드로서의 호출이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692646746846&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var obj = {
	method = function(x) { console.log(this, x); }
};

obj.method(1);    // { method: f } 1
obj['method'](2); // { method: f } 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;함수로서 호출할 때의 this&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분도 생각보다 단순하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;this 바인딩에 관해서는 함수를 &lt;b&gt;실행하는 당시의 주변환경은 중요하지 않고,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;오직&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 해당 함수를 &lt;span style=&quot;color: #ee2323;&quot;&gt;호출하는 구문 앞에서&lt;/span&gt;&lt;/span&gt; 점 또는 대괄호 표기&lt;span style=&quot;color: #333333;&quot;&gt;가 있는지 없는지&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;가 관건이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번 포스팅인 &lt;b&gt;2단원_실행 컨텍스트&lt;/b&gt;에서 나왔던&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 컨텍스트를 활성화할 당시에 &lt;b&gt;this가 지정되지 않은경우 전역객체&lt;/b&gt;를 바라본다고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6에서는 이 문제를 보완하고자&lt;b&gt; 화살표 함수&lt;/b&gt;를 도입했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화살표 함수는 &lt;b&gt;this를 바인딩&lt;/b&gt;하지 않고, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;선언될 당시의 상위 스코프의 this&lt;/span&gt;&lt;/b&gt;를 그대로 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서&amp;nbsp;특정&amp;nbsp;객체의&amp;nbsp;메소드&amp;nbsp;안에서&amp;nbsp;&lt;b&gt;비동기&amp;nbsp;작업을&amp;nbsp;할&amp;nbsp;때&amp;nbsp;this를&amp;nbsp;유지&lt;/b&gt;하고 싶을 때 많이 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 화살표 함수 안에서는 &lt;b&gt;this가 아예 없으며&lt;/b&gt;, &lt;b&gt;스코프체인상 가장 가까운 this&lt;/b&gt;에 접근하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692647763171&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var obj = {
  outer: function () {
    console.log(this);       // (1) { outer:f }
    var innerFunc = () =&amp;gt; {
      console.log(this);     // (2) { outer:f }
    };
    innerFunc();
  }
};
obj.outer();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드 처럼 두 콘솔의 this가 같은 곳을 바라보고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;생성자 함수 내부에서의 this&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692650015651&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Dog(name, breed) {
  this.name = name; // 여기서 this는 새로 생성되는 객체를 가리킨다.
  this.breed = breed;
}

var myDog = new Dog('Buddy', 'Golden Retriever');

console.log(myDog.name);  // 'Buddy'
console.log(myDog.breed); // 'Golden Retriever'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자&amp;nbsp;함수는&amp;nbsp;일반&amp;nbsp;함수와&amp;nbsp;달리&amp;nbsp;&lt;b&gt;new&amp;nbsp;&lt;/b&gt;키워드와&amp;nbsp;함께&amp;nbsp;호출되며,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;생성자&amp;nbsp;함수&amp;nbsp;내의&amp;nbsp;this는&amp;nbsp;생성되는&amp;nbsp;객체&lt;/span&gt;&lt;/b&gt;를 가리키게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;명시적으로 this를 바인딩하는 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상황별로 this에 어떤값이 바인딩되는지를 살펴봤지만 this에 별도의 대상을 바인딩하는 방법도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;call 메서드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692648190401&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Function.prototype.call(thisArg, arg1, arg2, ...);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;call 메서드는 함수를 호출하면서 &lt;b&gt;첫 번째 인자로 this 값을 바인딩&lt;/b&gt;하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 인자들을 그대로 &lt;b&gt;함수의 파라미터&lt;/b&gt;로 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- thisArg: &lt;b&gt;this로 바인딩할 값&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- arg1, arg2, arg3, ...: &lt;b&gt;함수에 전달될 인자들&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;apply 메서드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692648353904&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Function.prototype.apply(thisArg[, argsArray]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;apply 메서드는 call과 비슷한데, &lt;b&gt;인자들을 배열 형태로 전달&lt;/b&gt;한다는 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- thisArg: &lt;b&gt;this로 바인딩할 값&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- [argsArray]: &lt;b&gt;&lt;span&gt;함수에&lt;/span&gt; &lt;span&gt;전달될&lt;/span&gt; &lt;span&gt;인자들의&lt;/span&gt; &lt;span&gt;배열&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;call&lt;/span&gt;과&lt;span&gt; apply&lt;/span&gt;는&lt;span&gt; &lt;/span&gt;모양만&lt;span&gt; &lt;/span&gt;조금&lt;span&gt; &lt;/span&gt;다를&lt;span&gt; &lt;/span&gt;뿐&lt;span&gt; &lt;/span&gt;기능은&lt;span&gt; &lt;/span&gt;같다&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게말해, &lt;b&gt;배열로&lt;span&gt; &lt;/span&gt;인자&lt;/b&gt;를&lt;span&gt; &lt;/span&gt;넘기고&lt;span&gt; &lt;/span&gt;싶으면&lt;span&gt;&lt;b&gt; apply&lt;/b&gt;, &lt;/span&gt;그렇지&lt;span&gt; &lt;/span&gt;않으면&lt;b&gt;&lt;span&gt; call&lt;/span&gt;&lt;/b&gt;을&lt;span&gt; &lt;/span&gt;사용하면&lt;span&gt; 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692648577118&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Person(name, gender) {
  this.name = name;
  this.gender = gender;
}

function Student(name, gender, school) {
  Person.call(this, name, gender);
  this.school = school;
}

function Employee(name, gender, company) {
  Person.apply(this, [name, gender]);
  this.company = company;
}

const by = new Student('Blanc', 'male', '하버드');
const jn = new Employee('개발', 'male', 'JS');


console.log(by);
// {
//   name: 'Blanc',
//   gender: 'male',
//   school: '하버드'
// }

console.log(jn);
// {
//   name: '개발',
//   gender: 'male',
//   company: 'JS'
// }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 생성자 내부에서 &lt;b&gt;call , apply&lt;/b&gt; 로 &lt;b&gt;다른 생성자를 호출&lt;/b&gt;해 반복을 줄일 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음으로 &lt;b&gt;콜백함수 내에서의 this&lt;/b&gt;에 대해서 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692649159435&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var report = {
  sum: 0,
  count: 0,
  add: function() {
    var args = Array.prototype.slice.call(arguments);
    args.forEach(function (entry){
      this.sum += entry;
      ++this.count;
    }, this);
  },
  average: function(){
    return this.sum / this.count;
  }
};
report.add(60, 85, 95);
console.log(report.sum, report.count, report.average()); // 240 3 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;Array.prototype.slice.call(arguments)&lt;/span&gt;&lt;/b&gt;&lt;span&gt;를 사용해 배열로 변환하는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;forEach&lt;/b&gt;를 사용해서 배열을 순회한다.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forEach의&lt;b&gt; 두 번째 인수로 this&lt;/b&gt;를 전달하면, forEach 내의 콜백 함수에서 &lt;b&gt;이 this가 바인딩된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;report.add(60, 85, 95)를 호출해서 여기서 this는 report를 바라보게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;확실히 포스팅을 하고나니 &lt;b&gt;this&lt;/b&gt;에 대해서 제대로 알게된 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 챕터는 &lt;b&gt;&quot;콜백 함수&quot;&lt;/b&gt;이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/Javascript</category>
      <category>js</category>
      <category>this</category>
      <category>코어 자바스크립트</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/58</guid>
      <comments>https://ilikezzi.tistory.com/58#entry58comment</comments>
      <pubDate>Tue, 22 Aug 2023 05:38:12 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] console.dir()로 객체의 모든 depth 구조 출력</title>
      <link>https://ilikezzi.tistory.com/57</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I6QpV/btsq1KSz88P/NC5RtoutuVlbKM6q6Ua20K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I6QpV/btsq1KSz88P/NC5RtoutuVlbKM6q6Ua20K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I6QpV/btsq1KSz88P/NC5RtoutuVlbKM6q6Ua20K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI6QpV%2Fbtsq1KSz88P%2FNC5RtoutuVlbKM6q6Ua20K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;402&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 할 내용은 코드로 바로 확인 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-15 오전 4.37.30.png&quot; data-origin-width=&quot;1336&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cseLHZ/btsrgT08Unt/UNJDlkshny69okETwklLtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cseLHZ/btsrgT08Unt/UNJDlkshny69okETwklLtk/img.png&quot; data-alt=&quot;service 부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cseLHZ/btsrgT08Unt/UNJDlkshny69okETwklLtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcseLHZ%2FbtsrgT08Unt%2FUNJDlkshny69okETwklLtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;225&quot; data-filename=&quot;edited_스크린샷 2023-08-15 오전 4.37.30.png&quot; data-origin-width=&quot;1336&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;service 부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 &lt;b&gt;axios&lt;/b&gt;로 불러온 데이터를 파싱해서 쓰려고 했는데, &lt;b&gt;모든 depth의 데이터가 나오지 않았다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에도 이런적이 한 번 있었는데 이번에 또 같은 케이스여서 포스팅을 해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-15 오전 4.43.21.png&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xbDHg/btsrhFaxQxM/32XKXUraqzpAsyOtOgclZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xbDHg/btsrhFaxQxM/32XKXUraqzpAsyOtOgclZK/img.png&quot; data-alt=&quot;console.log(Openai_data.data)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xbDHg/btsrhFaxQxM/32XKXUraqzpAsyOtOgclZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxbDHg%2FbtsrhFaxQxM%2F32XKXUraqzpAsyOtOgclZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;161&quot; data-filename=&quot;스크린샷 2023-08-15 오전 4.43.21.png&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;318&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;console.log(Openai_data.data)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 사진처럼 comments: &lt;b&gt;[Array]&lt;/b&gt; 라고 나오는데 나는 그 값을 필요로해서 보고싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서&amp;nbsp;객체를&amp;nbsp;콘솔에&amp;nbsp;출력하면,&amp;nbsp;&lt;b&gt;기본적으로&amp;nbsp;일부&amp;nbsp;깊이까지만&amp;nbsp;출력&lt;/b&gt;되고,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그&amp;nbsp;이상의&amp;nbsp;깊이는&lt;b&gt;&amp;nbsp;[Array]&lt;/b&gt;나&lt;b&gt;&amp;nbsp;[Object]&amp;nbsp;&lt;/b&gt;형태로 간략하게 표시되는 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때&lt;b&gt; console.dir()&lt;/b&gt; 을 쓰면 해결 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자주 사용하는 console.log()와 console.dir()를 비교해 보면서 뭔지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;console.log()와&amp;nbsp;console.dir()&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- console.log()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법: 데이터를 &lt;b&gt;간단하고 빠르게&lt;/b&gt; 확인하고 싶을 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 형식: &lt;b&gt;일반적인 로그&lt;/b&gt; 출력에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깊이 제한: 중첩된 속성을 &lt;b&gt;일정 깊이&lt;/b&gt;까지만 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- console.dir():&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법: 객체의 &lt;b&gt;내부 구조를 자세히&lt;/b&gt; 보고 싶을 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 형식: &lt;b&gt;트리&lt;/b&gt; 형태로 객체의 구조를 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깊이 제한: &lt;b&gt;depth&lt;/b&gt; 옵션으로 출력 깊이를 조절할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;b&gt;null이면 모든 수준을&lt;/b&gt;, 숫자를 지정하면 해당 깊이만큼만 탐색한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1692044610755&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.dir(Newming_data.data, { depth: null }); // 무한 깊이까지 출력

console.dir(Newming_data.data, { depth: 2 }); // 2단계 깊이까지 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 코드는 작성하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;depth&lt;/b&gt;에 대해서 좀 더 자세히 살펴 보면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;console.dir()&amp;nbsp;메서드의&amp;nbsp;&lt;b&gt;두&amp;nbsp;번째&amp;nbsp;인자로&amp;nbsp;옵션&amp;nbsp;객체&lt;/b&gt;를&amp;nbsp;전달할&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서&amp;nbsp;depth&amp;nbsp;프로퍼티는&amp;nbsp;객체의&amp;nbsp;내부를&amp;nbsp;&lt;b&gt;얼마나&amp;nbsp;깊게&amp;nbsp;보여줄지&lt;/b&gt;&amp;nbsp;정하는&amp;nbsp;옵션인데,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;null로&amp;nbsp;설정하면&amp;nbsp;객체의&amp;nbsp;&lt;b&gt;모든&amp;nbsp;수준&lt;/b&gt;의 내용을 보여준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{depth:&amp;nbsp;숫자}:&amp;nbsp;숫자를&amp;nbsp;지정하면&amp;nbsp;&lt;b&gt;해당&amp;nbsp;깊이만큼만&lt;/b&gt; 탐색한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mm3QW/btsrgVkmJ9S/z8ZKoItFMXyHKAwoIW95P1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mm3QW/btsrgVkmJ9S/z8ZKoItFMXyHKAwoIW95P1/img.png&quot; data-alt=&quot;console.dir(Openai_data.data, { depth: null });&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mm3QW/btsrgVkmJ9S/z8ZKoItFMXyHKAwoIW95P1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmm3QW%2FbtsrgVkmJ9S%2Fz8ZKoItFMXyHKAwoIW95P1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;374&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;console.dir(Openai_data.data, { depth: null });&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 console.log(Openai_data.data) 부분을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;console.dir(Openai_data.data, { depth: null }); 이렇게 변경하니 원하는대로 &lt;b&gt;모든 depth&lt;/b&gt;의 데이터가 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한번 더 정리를 하자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;console.log()는 &lt;b&gt;빠르게 값 확인&lt;/b&gt;하기 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;console.dir()은 &lt;b&gt;객체 분석&lt;/b&gt;하기 좋고,&amp;nbsp; 세부적으로&lt;b&gt; 깊이를 조절&lt;/b&gt;할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/Javascript</category>
      <category>console.dir()</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/57</guid>
      <comments>https://ilikezzi.tistory.com/57#entry57comment</comments>
      <pubDate>Tue, 15 Aug 2023 05:38:22 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] new Set() 배열에서 쉽게 중복값 제거하기</title>
      <link>https://ilikezzi.tistory.com/56</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k9h3e/btsq0vm3GR4/7EwwCrDtHnLigxz6SV8op0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k9h3e/btsq0vm3GR4/7EwwCrDtHnLigxz6SV8op0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k9h3e/btsq0vm3GR4/7EwwCrDtHnLigxz6SV8op0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk9h3e%2Fbtsq0vm3GR4%2F7EwwCrDtHnLigxz6SV8op0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;1286&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 배열에서 중복값을 제거하는 방법에 대해서 포스팅을 해보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-11 오전 11.04.43.png&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;638&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Az5pc/btsq7dlfSWY/CiijuSxahRdc2N5xLscvFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Az5pc/btsq7dlfSWY/CiijuSxahRdc2N5xLscvFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Az5pc/btsq7dlfSWY/CiijuSxahRdc2N5xLscvFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAz5pc%2Fbtsq7dlfSWY%2FCiijuSxahRdc2N5xLscvFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;376&quot; data-filename=&quot;스크린샷 2023-08-11 오전 11.04.43.png&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-11 오전 11.04.09.png&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baY4LS/btsq0946v4u/iaomNlEF2mMZfbCzWCISLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baY4LS/btsq0946v4u/iaomNlEF2mMZfbCzWCISLk/img.png&quot; data-alt=&quot; console.log(dto.value_uuid)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baY4LS/btsq0946v4u/iaomNlEF2mMZfbCzWCISLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaY4LS%2Fbtsq0946v4u%2FiaomNlEF2mMZfbCzWCISLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;227&quot; data-filename=&quot;스크린샷 2023-08-11 오전 11.04.09.png&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; console.log(dto.value_uuid)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 간략하게 얘기하면 &lt;b&gt;투표항목을 클릭&lt;/b&gt;하면 &lt;b&gt;하위depth의 투표 항목&lt;/b&gt;까지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전부 불러오는 코드중 일부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 하위항목들을 찾아서 기존dto에 push하다가 console.log 창을보니 &lt;b&gt;중복된 값&lt;/b&gt;도 같이 쌓이고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 항목 찾을 때 기존항목&lt;b&gt; if문&lt;/b&gt;으로 비교 후 제거하거나, 정 안되면 &lt;b&gt;for문&lt;/b&gt;으로 돌려서 비교후 제외시켜도 되지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Array에서 바로 처리&lt;/b&gt;하는 방법이 있나 궁금해서 찾아보다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;new Set()&quot; 이라는 방법을 찾게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;new Set()&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Set 객체는 자바스크립트에서 유일한 값의 집합을 표현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 배열의 중복 값을 제거하려면 Set을 이용하면 정말 쉽게 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 방법은 다음과 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- new Set(numbers)는 numbers 배열의 &lt;b&gt;중복&amp;nbsp;값을&amp;nbsp;제거한&amp;nbsp;Set&amp;nbsp;객체&lt;/b&gt;를 만들어준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;스프레드 연산자 ...&lt;/b&gt;를&amp;nbsp;사용하면,&amp;nbsp;&lt;b&gt;Set&amp;nbsp;객체를&amp;nbsp;다시&amp;nbsp;배열로&lt;/b&gt; 변환할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691959294729&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const numbers = [1, 2, 2, 3, 4, 4, 5];
const uniqueNumbers = [...new Set(numbers)];

console.log(uniqueNumbers); // [1, 2, 3, 4, 5]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 기존코드에 적용을 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-11 오전 11.06.04.png&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;76&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKc7Hy/btsq2P56JBr/GfkUzrNiwuwwkAPw18wZck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKc7Hy/btsq2P56JBr/GfkUzrNiwuwwkAPw18wZck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKc7Hy/btsq2P56JBr/GfkUzrNiwuwwkAPw18wZck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKc7Hy%2Fbtsq2P56JBr%2FGfkUzrNiwuwwkAPw18wZck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;60&quot; data-filename=&quot;스크린샷 2023-08-11 오전 11.06.04.png&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;76&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-11 오전 11.06.29.png&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;244&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3lA7J/btsqZtQRt2N/bD3f5sDs52ji9PXjKoslhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3lA7J/btsqZtQRt2N/bD3f5sDs52ji9PXjKoslhK/img.png&quot; data-alt=&quot;console.log(dto.value_uuid)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3lA7J/btsqZtQRt2N/bD3f5sDs52ji9PXjKoslhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3lA7J%2FbtsqZtQRt2N%2FbD3f5sDs52ji9PXjKoslhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;207&quot; data-filename=&quot;스크린샷 2023-08-11 오전 11.06.29.png&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;244&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;console.log(dto.value_uuid)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 간단하게 &lt;b&gt;배열의 중복값을 제거&lt;/b&gt; 해버렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;new Set()은 간단하고 직관적이고, 코드 길이를 줄이고 가독성을 높일 수 있었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 복잡한 로직 없이도 중복 제거를 할 수 있어서 만족스럽다 !&lt;/p&gt;</description>
      <category>Programming Language/Javascript</category>
      <category>new Set()</category>
      <category>중복제거</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/56</guid>
      <comments>https://ilikezzi.tistory.com/56#entry56comment</comments>
      <pubDate>Mon, 14 Aug 2023 05:44:59 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 실행 컨텍스트_코어 자바스크립트</title>
      <link>https://ilikezzi.tistory.com/55</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;1602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vO81Q/btsqZb3CBmC/R71bDGsK9S40QLnemLjgMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vO81Q/btsqZb3CBmC/R71bDGsK9S40QLnemLjgMk/img.png&quot; data-alt=&quot;코어 자바스크립트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vO81Q/btsqZb3CBmC/R71bDGsK9S40QLnemLjgMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvO81Q%2FbtsqZb3CBmC%2FR71bDGsK9S40QLnemLjgMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;617&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;1602&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코어 자바스크립트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번에 포스팅한 &lt;b&gt;&quot;데이터 타입&quot;&lt;/b&gt; 에 이어서 다음 챕터인 &lt;b&gt;&quot;실행 컨텍스트&quot;&lt;/b&gt;를 포스팅 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/52&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ilikezzi.tistory.com/52&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691861121766&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Javascript] 데이터 타입_코어 자바스크립트&quot; data-og-description=&quot;계획했던대로 자격증 취득도 다 해서, 8월부터는 알고리즘과 팀프로젝트에 전념할 계획이였다. 하지만 알고리즘 스터디를 하기전에 JS 기본기를 탄탄하게 다져두고 하는게 깊은 이해에 도움이 &quot; data-og-host=&quot;ilikezzi.tistory.com&quot; data-og-source-url=&quot;https://ilikezzi.tistory.com/52&quot; data-og-url=&quot;https://ilikezzi.tistory.com/52&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/WvonF/hyTCBymSM1/3Zo4dk71ThvXzoqsDKQUv1/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/b2cGBH/hyTCMs8aOx/nmCEnXKf49mR15W7fkem8K/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/cSUczG/hyTCNlhUwq/9m94G2AOQdO27RZn2OMT90/img.png?width=1038&amp;amp;height=1602&amp;amp;face=0_0_1038_1602&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/52&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ilikezzi.tistory.com/52&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/WvonF/hyTCBymSM1/3Zo4dk71ThvXzoqsDKQUv1/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/b2cGBH/hyTCMs8aOx/nmCEnXKf49mR15W7fkem8K/img.png?width=800&amp;amp;height=1234&amp;amp;face=0_0_800_1234,https://scrap.kakaocdn.net/dn/cSUczG/hyTCNlhUwq/9m94G2AOQdO27RZn2OMT90/img.png?width=1038&amp;amp;height=1602&amp;amp;face=0_0_1038_1602');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Javascript] 데이터 타입_코어 자바스크립트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;계획했던대로 자격증 취득도 다 해서, 8월부터는 알고리즘과 팀프로젝트에 전념할 계획이였다. 하지만 알고리즘 스터디를 하기전에 JS 기본기를 탄탄하게 다져두고 하는게 깊은 이해에 도움이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 있는 저번 포스팅과 크게 이어지는 내용은 아니지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 &lt;b&gt;&quot;데이터 타입&quot;&lt;/b&gt;에 대한 기본적인 이해가 있어야 이번 포스팅을 쉽게 이해할 수 있을듯 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 실행 컨텍스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실행 컨텍스트란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-  실행 컨텍스트(Execution Context)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행할 코드에 &lt;b&gt;제공할 환경 정보&lt;/b&gt;들을 모아놓은 객체다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트의 동적 언어로서의 성격을 가장 잘 파악할 수 있는 중요한 개념이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-13 오전 2.45.04.png&quot; data-origin-width=&quot;3144&quot; data-origin-height=&quot;1446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFLKjF/btsq8ISz5TM/hdidNiQxVQk5BuOpU6OC9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFLKjF/btsq8ISz5TM/hdidNiQxVQk5BuOpU6OC9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFLKjF/btsq8ISz5TM/hdidNiQxVQk5BuOpU6OC9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFLKjF%2Fbtsq8ISz5TM%2FhdidNiQxVQk5BuOpU6OC9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;276&quot; data-filename=&quot;스크린샷 2023-08-13 오전 2.45.04.png&quot; data-origin-width=&quot;3144&quot; data-origin-height=&quot;1446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 개념이지만 한번 집고 넘어가자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택(Stack)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 출입구가 하나뿐인 깊은 우물 같은 데이터 구조다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 끝에서만 자료를 넣거나 뺄 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;- 앞서 실행 컨텍스트를 &quot;&lt;b&gt;실행할 코드에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;제공할 환경 정보들을 모아놓은 객체&quot;&lt;/b&gt;라고 했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이를 &lt;b&gt;콜 스택&lt;/b&gt;에 쌓아 올렸다가, 가장 위에 쌓여있는 컨텐스트와 관련 있는 코드를 하나씩 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐(Queue)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 양쪽이 모두 열린 파이프 같은 데이터 구조다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한 쪽 끝에서 넣고 반대 쪽 끝에서 빼는 식으로 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691863488824&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// --------------------------- (1)
var a = 1;
function outer() {
	function inner() {
    	console.log(a); // undefined
        var a = 3
    }
    inner(); //--------------- (2)
    console.log(a); // 1
}
outer(); // ------------------ (3)
console.log(a); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3220&quot; data-origin-height=&quot;1774&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcwmRG/btsqZuIC0ZY/Li94kK9DnYXpPPxWO25F3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcwmRG/btsqZuIC0ZY/Li94kK9DnYXpPPxWO25F3k/img.png&quot; data-alt=&quot; 콜스택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcwmRG/btsqZuIC0ZY/Li94kK9DnYXpPPxWO25F3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcwmRG%2FbtsqZuIC0ZY%2FLi94kK9DnYXpPPxWO25F3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;331&quot; data-origin-width=&quot;3220&quot; data-origin-height=&quot;1774&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; 콜스택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드의 콜스택 순서를 사진으로 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 처음 JS 코드를 실행하는 순간(1) 전역 컨텍스트가 콜스택에 push 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 콜스택에 쌓인&amp;nbsp;&lt;b&gt;전역 콘텍스트&lt;/b&gt; 관련된 코드를 실행하다가 (3)에서 Outer를 만나 콜스택에 push 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 이제 콜스택 맨 위에 Outer가 놓인 상태이므로 &lt;b&gt;전역 콘텍스트 관련 코드는 일시 중지&lt;/b&gt;하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; Outer 관련 컨텍스트, 즉 Outer 함수 내부의 코드를 순차적으로 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 다시 (2)에서 Inner 함수의 실행 컨텍스트가 콜스택에 push되서, Inner 함수 내부코드를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. Inner함수 실행이 끝나면 &lt;b&gt;&quot;pop&quot;&lt;/b&gt; 되면서 콜스택에서 제거된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 이제 아래에 있던 Outer 함수코드를 실행하고, 끝나면 pop 되면서 콜스택에서 제거된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 마지막으로 맨 아래에 있던 전역 콘텍스트를 마저 실행시키고, 끝나면 pop 되면서 끝난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 처럼 콜스택은 &lt;b&gt;후입선출(LIFO)&lt;/b&gt; 방식으로 동작하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 콜스택이 너무 깊어지면 &lt;b&gt;스택 오버플로우&lt;/b&gt;라는 문제가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 활성화된 &lt;b&gt;실행 컨텍스트에는 무엇이 담겨 있는지&lt;/b&gt; 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;span style=&quot;color: #9feec3;&quot;&gt;&lt;b&gt;LexicalEnvironment&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 코드의 실행 컨텍스트 내에서 식별자와 그에 해당하는 값이 어떻게 연결되는지 나타내는 환경이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말하면, 어떤 변수가 어떤 값을 가지고 있는지 관리해주는 역할이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- &lt;span style=&quot;color: #99cefa;&quot;&gt;VariableEnvironment&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 실행 컨텍스트에서 var로 선언된 변수들을 관리하는 환경이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선언시점의 &lt;span style=&quot;color: #9feec3;&quot;&gt;&lt;b&gt;LexicalEnvironment&lt;/b&gt;&lt;/span&gt;의 스냅샷으로 변경사항은 반영X&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6 이전에는 &lt;span style=&quot;color: #9feec3;&quot;&gt;&lt;b&gt;LexicalEnvironment&lt;/b&gt;&lt;/span&gt;와 거의 동일했지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;let과 const가 도입되면서&lt;span style=&quot;color: #9feec3;&quot;&gt;&lt;b&gt; LexicalEnvironment&lt;/b&gt;&lt;/span&gt;가 좀 더 복잡한 역할을 하게 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- &lt;span style=&quot;color: #c1bef9;&quot;&gt;ThisBinding&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;this 키워드의 값이 무엇인지 결정하는 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수가 어떻게 호출되었는지, 그리고 어떤 객체의 컨텍스트에서 실행되었는지에 따라 this의 값이 달라지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Hoisting&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691868659888&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function a() {
	console.log(b);  // (1)
    var b = 'bbb';   // 수집 대상 1 (변수선언)
    console.log(b);  // (2)
    function b() { } // 수집 대상 2 (함수선언)
    console.log(b);  // (3)
}
a();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 코드를 예시로 보고 하나씩 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. a 함수를 실행하는 순간 a 함수의 &lt;b&gt;실행컨텍스트가 생성&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 이때 변수명과 함수 선언정보를 위로 끌어올린다. &lt;b&gt;(호이스팅)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 변수는 선언부와 할당부로 나누어 &lt;b&gt;선언부만&lt;/b&gt; 끌어올림&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 함수 선언은 &lt;b&gt;함수 전체&lt;/b&gt;를 끌어 올린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691869828620&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function a() {
	var b;           // 수집 대상 1 (변수선언) 선언부만 끌어올린다.
    // function b() { } // 수집 대상 2 (함수선언) 함수 선언은 전체를 끌어올린다.
	var b = function b() { } // 변경부분!
   
    console.log(b);  // (1)
    b = 'bbb';       // 변수의 할당부는 자리에 남는다.
    console.log(b);  // (2)
    console.log(b);  // (3)
}
a();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호이스팅이 이뤄지면 다음과 같이 변환된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b&gt;3번째 주석 라인&lt;/b&gt;으로 처음에는 변환되지만, &lt;b&gt;4번째 라인&lt;/b&gt;과 같은 의미로 여겨진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 선언문을 사용하면 자바스크립트 엔진이 &lt;b&gt;해당 함수를 변수에 할당하는 과정을 내부적으로 처리&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호이스팅이 끝난 상태에서의 함수 선언문은&lt;b&gt; 함수명으로 선언한 변수&lt;/b&gt;에 &lt;b&gt;함수를 할당한 것 처럼&lt;/b&gt; 여긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 좀 복잡하게 느껴질 수 있는 부분인데, 이전 포스팅에서 &lt;b&gt;데이터 메모리 할당&lt;/b&gt;을 봤으면 이해가 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 각 콘솔에 대한 값은 이렇게 출력된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) : b함수 / (2) : 'bbb' / (3) : 'bbb'&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&quot;함수 선언문&quot;과 &quot;함수 표현식&quot;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 호이스팅을 다루는데에 꼭 알아둬야 할 &lt;b&gt;&quot;함수 선언문&quot;&lt;/b&gt;과&lt;b&gt; &quot;함수 표현식&quot;&lt;/b&gt;에 대해서 알아보자.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691874920446&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; function a() {} // 함수 선언문. 함수명 a가 곧 변수명
 a(); // 실행 OK
 
 var b = function() {} // (익명) 함수 표현식. 변수명 b가 곧 함수명
 b(); // 실행 OK
 
 var c = function d() {} // (익명) 기명 함수 표현식. 변수명 c , 함수명 d
 c(); // 실행 OK
 d(); // 에러!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.&amp;nbsp;함수&amp;nbsp;선언문&amp;nbsp;(Function&amp;nbsp;Declaration)&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수&amp;nbsp;선언문은&amp;nbsp;&lt;b&gt;&quot;function&quot;&amp;nbsp;키워드로&amp;nbsp;시작&lt;/b&gt;하고, 이름이 있는 함수를 선언한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호이스팅 - 함수 선언문은 코드가 실행되기 전에 메모리에 할당되어, 선언문이 있는 코드 블록 내 어디에서든 접근 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름 필수 - &lt;b&gt;함수에 반드시 이름&lt;/b&gt;이 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 함수 표현식 (Function Expression)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 표현식은 &lt;b&gt;변수에&lt;/b&gt; 함수를 할당하는 형태로 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호이스팅 &lt;b&gt;X&lt;/b&gt; - 변수 선언만 호이스팅되고, 함수는 할당 시점에 메모리에 저장돼. 따라서 선언 전에 호출하려고 하면 오류가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름이 선택: 함수에 &lt;b&gt;이름을 주지 않아도&lt;/b&gt; 된다. 이름을 준다면 디버깅에 도움이 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차이점을 한번 더 정리 해보면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호이스팅: 함수 선언문은 &lt;b&gt;전체 접근&lt;/b&gt; 가능, 함수 표현식은 &lt;b&gt;선언 후에만 접근&lt;/b&gt; 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선언 형태: 함수 선언문은&lt;b&gt; function 키워드&lt;/b&gt;로 시작, 함수 표현식은 &lt;b&gt;변수 할당&lt;/b&gt; 형태.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름 유무: 함수 선언문은 이름 &lt;b&gt;필수&lt;/b&gt;, 함수 표현식은 이름 &lt;b&gt;선택&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 포인트가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;협업을 할 때에 함수 선언문은 위험하다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;호이스팅을 제대로 이해한분들은 이게 무슨 얘기인지 눈치 챘을것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개발자가 같은 이름으로 함수를 선언하게 되면 나중에 선언한 함수가 &lt;b&gt;이전 선언을 덮어써&lt;/b&gt;버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해 예상치 못한 동작이나 버그가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 같은 이름의 함수가 여러 곳에서 선언되면, 나중에 코드를 &lt;b&gt;유지보수&lt;/b&gt;하거나 &lt;b&gt;리팩토링&lt;/b&gt;할 때 문제가 생길 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 함수가 어떻게 동작하는지 파악하기 어려워지고, 버그를 찾거나 수정하기 힘들어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 상대적으로 &lt;b&gt;함수 표현식이 안전&lt;/b&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스코프 체인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;스코프 체인&lt;/b&gt;에 대해서 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스코프 체인이란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스코프 체인은 &lt;b&gt;현재 실행 컨텍스트의 스코프&lt;/b&gt;에서 시작해서, &lt;b&gt;상위 스코프&lt;/b&gt;를 따라가며&lt;b&gt; 체인&lt;/b&gt;처럼 연결된 구조를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 체인은 &lt;b&gt;변수를 찾을 때&lt;/b&gt; 사용되며, 현재 스코프부터 시작해서 전역 스코프까지 이어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작동 방식은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 스코프에서 찾기: 변수를 찾을 때, &lt;b&gt;현재 스코프부터 찾기&lt;/b&gt; 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 스코프로 올라가기: 현재 스코프에 없으면, &lt;b&gt;상위 스코프로 올라가서 찾는다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역 스코프까지 반복: &lt;b&gt;전역 스코프까지&lt;/b&gt; &lt;b&gt;계속 올라가서 찾는다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾지 못하면 오류: 전역 스코프까지 갔는데도&lt;b&gt; 못 찾으면 ReferenceError&lt;/b&gt;를 내뱉는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 규칙을 이해하면&lt;b&gt; 변수가 어떻게 조회되고 동작&lt;/b&gt;하는지 이해하는 데 도움이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스코프 체인 예제 코드로 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1691877100264&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var a = 1;
var outer = function () {
    var inner = function() {
        console.log(a); // undefined
        var a = 3;
    };
    inner();
    console.log(a); // 1
};
outer();
console.log(a); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스코프 체인과 호이스팅 관점에서 동작순서를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 전역 스코프에서 &lt;b&gt;변수 a&lt;/b&gt; 와 &lt;b&gt;함수 outer&lt;/b&gt;가 &lt;b&gt;선언&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 변수 a에&lt;b&gt; 1을 할당&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. outer&amp;nbsp;함수가&amp;nbsp;호출되어&amp;nbsp;&lt;b&gt;실행&amp;nbsp;컨텍스트가&amp;nbsp;생성&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. outer&amp;nbsp;내부에서&amp;nbsp;&lt;b&gt;inner&amp;nbsp;함수가&amp;nbsp;선언&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. inner&amp;nbsp;함수가&amp;nbsp;호출되고,&amp;nbsp;새로운&amp;nbsp;&lt;b&gt;실행&amp;nbsp;컨텍스트가&amp;nbsp;생성&lt;/b&gt;된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;이 때, inner의 지역 스코프에서 a의 선언이 호이스팅되어 &lt;b&gt;undefined로 초기화&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. inner&amp;nbsp;함수&amp;nbsp;내에서&amp;nbsp;a를&amp;nbsp;출력하려고&amp;nbsp;하면,&amp;nbsp;현재&amp;nbsp;스코프에서&amp;nbsp;a의&amp;nbsp;값은&amp;nbsp;undefined이므로,&amp;nbsp;&lt;b&gt;undefined가&amp;nbsp;출력&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. inner&amp;nbsp;함수&amp;nbsp;내에서&amp;nbsp;&lt;b&gt;지역&amp;nbsp;변수&amp;nbsp;a에&amp;nbsp;3을&amp;nbsp;할당&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. inner&amp;nbsp;함수의&amp;nbsp;실행이&amp;nbsp;종료되고,&amp;nbsp;해당&amp;nbsp;&lt;b&gt;실행&amp;nbsp;컨텍스트가&amp;nbsp;스택에서&amp;nbsp;제거&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. outer&amp;nbsp;함수&amp;nbsp;내에서&amp;nbsp;전역&amp;nbsp;변수&amp;nbsp;a를&amp;nbsp;출력하려고&amp;nbsp;하면,&amp;nbsp;해당&amp;nbsp;스코프에서&amp;nbsp;&lt;b&gt;a의&amp;nbsp;값은&amp;nbsp;1이므로,&amp;nbsp;1이&amp;nbsp;출력&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10. outer&amp;nbsp;함수의&amp;nbsp;실행이&amp;nbsp;종료되고,&amp;nbsp;해당&amp;nbsp;&lt;b&gt;실행&amp;nbsp;컨텍스트가&amp;nbsp;스택에서&amp;nbsp;제거&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11. outer&amp;nbsp;함수&amp;nbsp;외부에서&amp;nbsp;전역&amp;nbsp;변수&amp;nbsp;a를&amp;nbsp;출력하면,&amp;nbsp;&lt;b&gt;전역&amp;nbsp;스코프에서&amp;nbsp;a의&amp;nbsp;값은&amp;nbsp;1&lt;/b&gt;이므로,&lt;b&gt;&amp;nbsp;1이&amp;nbsp;출력&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 스코프체인과 호이스팅 작동방식에 대해서 예제코드로 찝어보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 내용이 좀 길었지만 개념과 코드의 동작방식을 하나씩 살펴보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 실행 컨텍스트&lt;/b&gt;에 대해서 확실히 이해를 할 수 있을 것이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 챕터는 &lt;b&gt;&quot;this&quot;&lt;/b&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/Javascript</category>
      <category>js</category>
      <category>스코프체인</category>
      <category>실행 컨텍스트</category>
      <category>함수 선언문</category>
      <category>호이스팅</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/55</guid>
      <comments>https://ilikezzi.tistory.com/55#entry55comment</comments>
      <pubDate>Sun, 13 Aug 2023 07:08:24 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] CloudFront + ACM을 이용한 https 리다이렉팅 (Route53,S3)</title>
      <link>https://ilikezzi.tistory.com/54</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;1086&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kZWnJ/btsqZuIeYu5/55qYkKQ9tSPvekBuTw1KPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kZWnJ/btsqZuIeYu5/55qYkKQ9tSPvekBuTw1KPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kZWnJ/btsqZuIeYu5/55qYkKQ9tSPvekBuTw1KPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkZWnJ%2FbtsqZuIeYu5%2F55qYkKQ9tSPvekBuTw1KPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;392&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;1086&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직전에 &lt;b&gt;Route53 + S3로 정적 웹 호스팅&lt;/b&gt;하는 방법에 대해 포스팅을 했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/53&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ilikezzi.tistory.com/53&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691784659081&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[AWS] Route53 도메인 구매 및 S3 웹 호스팅&quot; data-og-description=&quot;얼마전에 해커톤 멘토링을 다녀와서 서버설계와 DB설계쪽에 부족함을 느껴서 주변에 프론트엔드 1명, AI 1명, 디자이너 1명을 섭외해서 팀프로젝트를 하기로했다. 주제선정과 기능선정이 끝나서 &quot; data-og-host=&quot;ilikezzi.tistory.com&quot; data-og-source-url=&quot;https://ilikezzi.tistory.com/53&quot; data-og-url=&quot;https://ilikezzi.tistory.com/53&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/by4z4Y/hyTCGsAXdW/7PWM1Su0nhcByhWWAATPok/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/9T33b/hyTCIqpQFC/SxUMPNWDCAkYzzkAHM8gU0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/du9T0U/hyTCGsAXfE/7bji7YNIlFDV31N3g1Ey5K/img.png?width=1670&amp;amp;height=1526&amp;amp;face=0_0_1670_1526&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/53&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ilikezzi.tistory.com/53&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/by4z4Y/hyTCGsAXdW/7PWM1Su0nhcByhWWAATPok/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/9T33b/hyTCIqpQFC/SxUMPNWDCAkYzzkAHM8gU0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/du9T0U/hyTCGsAXfE/7bji7YNIlFDV31N3g1Ey5K/img.png?width=1670&amp;amp;height=1526&amp;amp;face=0_0_1670_1526');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[AWS] Route53 도메인 구매 및 S3 웹 호스팅&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;얼마전에 해커톤 멘토링을 다녀와서 서버설계와 DB설계쪽에 부족함을 느껴서 주변에 프론트엔드 1명, AI 1명, 디자이너 1명을 섭외해서 팀프로젝트를 하기로했다. 주제선정과 기능선정이 끝나서&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 포스팅과 이어지는 내용이니 먼저 보고와서, 이 포스팅을 봐주면 좋을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 Route53 + S3 를 이용해서 정적 웹 호스팅을 해서 &lt;b&gt;http &lt;/b&gt;까지 완료했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는&lt;b&gt; CloudFront + ACM&lt;/b&gt; 을 이용해서 &lt;b&gt;https로 리다이렉팅&lt;/b&gt; 해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 왜 이 두가지 서비스를 사용하는지부터 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Amazon CloudFront&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;aws-cloudfront.svg&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn55nQ/btsqY0ue61Y/bsgabwKlW4hWRsqlT0POck/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn55nQ/btsqY0ue61Y/bsgabwKlW4hWRsqlT0POck/tfile.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn55nQ/btsqY0ue61Y/bsgabwKlW4hWRsqlT0POck/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn55nQ%2FbtsqY0ue61Y%2FbsgabwKlW4hWRsqlT0POck%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;300&quot; data-filename=&quot;aws-cloudfront.svg&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- AWS에서 제공하는 글로벌 콘텐츠 전송 네트워크(CDN) 서비스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CloudFront는 사용자에게 &lt;b&gt;빠른 데이터 전송 속도&lt;/b&gt;를 제공하려고 웹사이트의 콘텐츠를 &lt;b&gt;전 세계에 분산된 서버에 배포&lt;/b&gt;한다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 사용자가 요청하면 가장 &lt;b&gt;가까운 서버에서 콘텐츠를 제공&lt;/b&gt;하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;AWS&amp;nbsp;Certificate&amp;nbsp;Manager&lt;/b&gt;&amp;nbsp;&lt;b&gt;(ACM)&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bq4H45/btsqYEE0pNT/pQWkaBBP7Vxd1TxYa9VfC1/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bq4H45/btsqYEE0pNT/pQWkaBBP7Vxd1TxYa9VfC1/tfile.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bq4H45/btsqYEE0pNT/pQWkaBBP7Vxd1TxYa9VfC1/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbq4H45%2FbtsqYEE0pNT%2FpQWkaBBP7Vxd1TxYa9VfC1%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;300&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;SSL/TLS 인증서&lt;/b&gt;를 무료로 제공하고, 관리를 쉽게 해주는 서비스다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ACM을 사용하면, &lt;b&gt;HTTPS를 통한 안전한 연결&lt;/b&gt;을 쉽게 설정할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 인증서 갱신 같은거 걱정 없이 안전한 연결을 유지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약하자면 &lt;b&gt;웹사이트의 속도를 향상&lt;/b&gt;시키고, 사용자에게 &lt;b&gt;안전한 연결&lt;/b&gt;을 제공하기 위해서 사용하는 것이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 ACM으로 &lt;b&gt;SSL인증&lt;/b&gt;부터 받아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.05.49.png&quot; data-origin-width=&quot;1594&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F3NRd/btsq2iUaogh/Bkp8EkyNQk8wGzqCSagg4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F3NRd/btsq2iUaogh/Bkp8EkyNQk8wGzqCSagg4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F3NRd/btsq2iUaogh/Bkp8EkyNQk8wGzqCSagg4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF3NRd%2Fbtsq2iUaogh%2FBkp8EkyNQk8wGzqCSagg4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;105&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.05.49.png&quot; data-origin-width=&quot;1594&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&quot;버지니아 북부&quot;&lt;/b&gt;&lt;/span&gt; 리전을 선택 후&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ACM 서비스에 들어가서 인증서 -&amp;gt; &lt;b&gt;요청&lt;/b&gt;을 눌러주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.09.26.png&quot; data-origin-width=&quot;1458&quot; data-origin-height=&quot;1222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HItck/btsq1d6TIQq/jnvaGpPCh1l0yjq1i7hMjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HItck/btsq1d6TIQq/jnvaGpPCh1l0yjq1i7hMjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HItck/btsq1d6TIQq/jnvaGpPCh1l0yjq1i7hMjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHItck%2Fbtsq1d6TIQq%2FjnvaGpPCh1l0yjq1i7hMjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;503&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.09.26.png&quot; data-origin-width=&quot;1458&quot; data-origin-height=&quot;1222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 이름에 &lt;b&gt;www. ~~ 가 추가된 도메인&lt;/b&gt;과 &lt;b&gt;일반 도메인&lt;/b&gt;을 각각 써준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.10.29.png&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;1010&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/StIOT/btsq1cGSCV2/Q5U0tjtC5nryyPM7Ow3kok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/StIOT/btsq1cGSCV2/Q5U0tjtC5nryyPM7Ow3kok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/StIOT/btsq1cGSCV2/Q5U0tjtC5nryyPM7Ow3kok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FStIOT%2Fbtsq1cGSCV2%2FQ5U0tjtC5nryyPM7Ow3kok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;381&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.10.29.png&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;1010&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 해당 화면처럼 나올텐데 아래 &lt;b&gt;&quot;Route 53에서 레코드 생성&quot;&lt;/b&gt;을 눌러준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.15.56.png&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;1028&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5J4hs/btsqYTPjDD6/OzXk5vC4TwNlN0q9tGoRtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5J4hs/btsqYTPjDD6/OzXk5vC4TwNlN0q9tGoRtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5J4hs/btsqYTPjDD6/OzXk5vC4TwNlN0q9tGoRtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5J4hs%2FbtsqYTPjDD6%2FOzXk5vC4TwNlN0q9tGoRtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;390&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.15.56.png&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;1028&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2개가 생성 되었을텐데 &lt;b&gt;CNAME&lt;/b&gt; 과&lt;b&gt; CNAME값&lt;/b&gt;을 Route53에서 맞춰줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.16.12.png&quot; data-origin-width=&quot;1842&quot; data-origin-height=&quot;1444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dc4IO/btsq1JK7Pyc/vXiY3LmG1v9CY77sFqhF41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dc4IO/btsq1JK7Pyc/vXiY3LmG1v9CY77sFqhF41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dc4IO/btsq1JK7Pyc/vXiY3LmG1v9CY77sFqhF41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDc4IO%2Fbtsq1JK7Pyc%2FvXiY3LmG1v9CY77sFqhF41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;470&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.16.12.png&quot; data-origin-width=&quot;1842&quot; data-origin-height=&quot;1444&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Route53 호스팅 영역에서 &lt;b&gt;레코드 목록&lt;/b&gt;을 보면 방금 생성한 항목이 보일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에&lt;b&gt; CNAME 값&lt;/b&gt;을 비교해보고 &lt;b&gt;&quot;편집&quot;&lt;/b&gt;으로 동일한 값으로 맞춰준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(나는 자동으로 동일한 값으로 되어 있었다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값을 맞춰주었으면 1분정도 안에 다시 &lt;b&gt;ACM-&amp;gt;도메인&lt;/b&gt;으로 돌아가서 &lt;b&gt;&quot;상태&quot;&lt;/b&gt;를 확인해보면 &lt;b&gt;성공&lt;/b&gt;으로 변경되었을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 ACM에서 SSL인증은 끝이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음으로 이제 &lt;b&gt;CloudFront&lt;/b&gt; 설정을 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.31.16.png&quot; data-origin-width=&quot;1652&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cluWSd/btsq2kxFQSR/P9lkqfMU2PSCJqKdL1mRB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cluWSd/btsq2kxFQSR/P9lkqfMU2PSCJqKdL1mRB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cluWSd/btsq2kxFQSR/P9lkqfMU2PSCJqKdL1mRB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcluWSd%2Fbtsq2kxFQSR%2FP9lkqfMU2PSCJqKdL1mRB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;416&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.31.16.png&quot; data-origin-width=&quot;1652&quot; data-origin-height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;아까와 동일하게&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;버지니아 북부&quot;&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;리전을 선택 후&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CloudFront 서비스로 들어가서 &lt;b&gt;배포 생성&lt;/b&gt;을 눌러주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.37.35.png&quot; data-origin-width=&quot;1648&quot; data-origin-height=&quot;1432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lfuoK/btsqYSbPo8c/xwCKyknDgWbn9HzsuhFI40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lfuoK/btsqYSbPo8c/xwCKyknDgWbn9HzsuhFI40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lfuoK/btsqYSbPo8c/xwCKyknDgWbn9HzsuhFI40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlfuoK%2FbtsqYSbPo8c%2FxwCKyknDgWbn9HzsuhFI40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;1432&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.37.35.png&quot; data-origin-width=&quot;1648&quot; data-origin-height=&quot;1432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 도메인에 &lt;b&gt;S3 주소&lt;/b&gt;를 넣어줘야하는데, 직접 S3에 가서 복사를 해오자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.31.58.png&quot; data-origin-width=&quot;1622&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c93I5g/btsqYZB8yMI/CjuUKTKKy8sC39T3i0CLP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c93I5g/btsqYZB8yMI/CjuUKTKKy8sC39T3i0CLP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c93I5g/btsqYZB8yMI/CjuUKTKKy8sC39T3i0CLP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc93I5g%2FbtsqYZB8yMI%2FCjuUKTKKy8sC39T3i0CLP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;670&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.31.58.png&quot; data-origin-width=&quot;1622&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S3 버킷 -&amp;gt; 속성 -&amp;gt; 스크롤 맨 아래 &lt;b&gt;&quot;정적 웹 사이트 호스팅&quot;&lt;/b&gt; 의 &lt;b&gt;엔드포인트 복사&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복사한 값을 다시 원본 도메인에 붙혀 넣어주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.37.40.png&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;1264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hyt2w/btsq2jMjex0/PKZozr2qukowlf1voeELk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hyt2w/btsq2jMjex0/PKZozr2qukowlf1voeELk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hyt2w/btsq2jMjex0/PKZozr2qukowlf1voeELk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHyt2w%2Fbtsq2jMjex0%2FPKZozr2qukowlf1voeELk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;1264&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.37.40.png&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;1264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Origin Shield 활성화&lt;/b&gt;를 켜주고 &lt;b&gt;버지니아 북부&lt;/b&gt;로 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.38.05.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAH7Dl/btsqYpAYbVY/A6p76bTwrX2VNjjK3mWO7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAH7Dl/btsqYpAYbVY/A6p76bTwrX2VNjjK3mWO7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAH7Dl/btsqYpAYbVY/A6p76bTwrX2VNjjK3mWO7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAH7Dl%2FbtsqYpAYbVY%2FA6p76bTwrX2VNjjK3mWO7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;546&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.38.05.png&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;1398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Redirect HTTP to HTTPS&lt;/b&gt; 를 선택 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE&lt;/b&gt; 를 선택해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.41.51.png&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;1128&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btDfXv/btsq0ypNB4D/D1mynwoBcOanbx7EEZ55N1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btDfXv/btsq0ypNB4D/D1mynwoBcOanbx7EEZ55N1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btDfXv/btsq0ypNB4D/D1mynwoBcOanbx7EEZ55N1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtDfXv%2Fbtsq0ypNB4D%2FD1mynwoBcOanbx7EEZ55N1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;487&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.41.51.png&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;1128&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시 정책은 &lt;b&gt;CahingOptimized&lt;/b&gt; 를 선택해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.49.27.png&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;1350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6RE0l/btsqYOmZlSj/A2zTREnwaZZSTLxZTXdNr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6RE0l/btsqYOmZlSj/A2zTREnwaZZSTLxZTXdNr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6RE0l/btsqYOmZlSj/A2zTREnwaZZSTLxZTXdNr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6RE0l%2FbtsqYOmZlSj%2FA2zTREnwaZZSTLxZTXdNr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;556&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.49.27.png&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;1350&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 엣지 로케이션 사용&lt;/b&gt;을 선택하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대체 도메인은 &lt;b&gt;기존도메인&lt;/b&gt;과,&lt;b&gt; www.기존도메인&lt;/b&gt;&amp;nbsp;총 두가지를 써주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(처음에 한개만 썼다가 리다이렉팅 안되서 다 지우고 다시했다...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSL인증서는 &lt;b&gt;아까 ACM에서 했던 SSL인증서&lt;/b&gt;를 선택해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로써 CloudFront 설정도 마쳤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;CloudFront&lt;/b&gt;랑 &lt;b&gt;Route53&lt;/b&gt;이랑 붙혀주기만하면 끝난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.51.32.png&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;924&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4eonC/btsq0vNmArs/jcGrby1ZBrEmMNkhBshb31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4eonC/btsq0vNmArs/jcGrby1ZBrEmMNkhBshb31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4eonC/btsq0vNmArs/jcGrby1ZBrEmMNkhBshb31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4eonC%2Fbtsq0vNmArs%2FjcGrby1ZBrEmMNkhBshb31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;338&quot; data-filename=&quot;스크린샷 2023-08-12 오전 3.51.32.png&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;924&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Route53 -&amp;gt; 호스팅영역 -&amp;gt; 해당 호스팅 선택&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;레코드 생성&lt;/b&gt;을 눌러주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.52.16.png&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;1410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKIG1C/btsq1JqOVAQ/oj0RxRSl6iemrjydCUrYF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKIG1C/btsq1JqOVAQ/oj0RxRSl6iemrjydCUrYF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKIG1C/btsq1JqOVAQ/oj0RxRSl6iemrjydCUrYF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKIG1C%2Fbtsq1JqOVAQ%2Foj0RxRSl6iemrjydCUrYF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;722&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 3.52.16.png&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;1410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레코드 이름에&lt;b&gt; www&lt;/b&gt; 를 써주고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레코드 유형은&lt;b&gt; &quot;A - IPv4&quot;&lt;/b&gt; 를 선택해주고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값/트래픽 라우팅 대상은 &lt;b&gt;&quot;CloudFront 배포에 대한 별칭&quot;&lt;/b&gt; 으로 해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 아까 생성한&lt;b&gt; CloudFront를 선택&lt;/b&gt;하고 레코드 생성을 해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 전부 완료했다 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1분&lt;/b&gt;정도 기다리고&lt;b&gt; www.도메인&lt;/b&gt; 을 검색해보면 정상적으로 작동할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 4.00.17.png&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1898&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bks8MK/btsqZfSdkb0/kMuxiOLLudHNRUFtx8xq21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bks8MK/btsqZfSdkb0/kMuxiOLLudHNRUFtx8xq21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bks8MK/btsqZfSdkb0/kMuxiOLLudHNRUFtx8xq21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbks8MK%2FbtsqZfSdkb0%2FkMuxiOLLudHNRUFtx8xq21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;471&quot; data-filename=&quot;edited_스크린샷 2023-08-12 오전 4.00.17.png&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1898&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 프로젝트 &lt;b&gt;기능 플로우&lt;/b&gt; 작성하고, 전반적인 &lt;b&gt;서버 설계와 DB설계&lt;/b&gt;할 때쯤 분명 막힐텐데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때 다시 머리싸매면서 해결 후, 관련 내용 포스팅을 하러 와야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/AWS</category>
      <category>ACM</category>
      <category>AWS</category>
      <category>cloudfront</category>
      <category>https</category>
      <category>route53</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/54</guid>
      <comments>https://ilikezzi.tistory.com/54#entry54comment</comments>
      <pubDate>Sat, 12 Aug 2023 06:20:39 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] Route53 도메인 구매 및 S3 웹 호스팅</title>
      <link>https://ilikezzi.tistory.com/53</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDboc2/btsqBNuB6h8/P2PKIg7wYobevt0nAlxzyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDboc2/btsqBNuB6h8/P2PKIg7wYobevt0nAlxzyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDboc2/btsqBNuB6h8/P2PKIg7wYobevt0nAlxzyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDboc2%2FbtsqBNuB6h8%2FP2PKIg7wYobevt0nAlxzyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;300&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼마전에 해커톤 멘토링을 다녀와서 &lt;b&gt;서버설계&lt;/b&gt;와 &lt;b&gt;DB설계&lt;/b&gt;쪽에 부족함을 느껴서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주변에 프론트엔드 1명, AI 1명, 디자이너 1명을 섭외해서 팀프로젝트를 하기로했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주제선정과 기능선정이 끝나서 이제 각자 맡은일을 해야하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 &lt;b&gt;기획, 서버, DB, 백엔드&lt;/b&gt; 파트를 혼자서 전부 하기로했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모바일 &lt;b&gt;웹/앱&lt;/b&gt; 서비스로 진행하기로 해서 우선 프로젝트 도메인이 필요했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾아보니 시중에 도메인 판매하는 사이트도 많았지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사 테크니컬 리더님께서 역량 향상 명목으로 &lt;b&gt;회사 AWS계정&lt;/b&gt;을 사용하라고 하셨다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 한치의 고민도 없이 AWS로 접속했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-09 오전 5.32.20.png&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sq77R/btsqBo9JUNx/XKHX86BRxrhdOyWWKXMkt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sq77R/btsqBo9JUNx/XKHX86BRxrhdOyWWKXMkt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sq77R/btsqBo9JUNx/XKHX86BRxrhdOyWWKXMkt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsq77R%2FbtsqBo9JUNx%2FXKHX86BRxrhdOyWWKXMkt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;122&quot; data-filename=&quot;스크린샷 2023-08-09 오전 5.32.20.png&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Route 53 서비스를 검색 후 들어가서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-09 오전 5.34.53.png&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oIBCv/btsqwAJFHNh/AtSPtyv0DyRnMnNOm1oLFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oIBCv/btsqwAJFHNh/AtSPtyv0DyRnMnNOm1oLFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oIBCv/btsqwAJFHNh/AtSPtyv0DyRnMnNOm1oLFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoIBCv%2FbtsqwAJFHNh%2FAtSPtyv0DyRnMnNOm1oLFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;184&quot; data-filename=&quot;스크린샷 2023-08-09 오전 5.34.53.png&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등록된 도메인으로 들어가서, &quot;도메인 등록&quot;을 누르자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2534&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WMPvI/btsqD515KV1/qkSrQeG5NbKpS5tDt6IfZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WMPvI/btsqD515KV1/qkSrQeG5NbKpS5tDt6IfZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WMPvI/btsqD515KV1/qkSrQeG5NbKpS5tDt6IfZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWMPvI%2FbtsqD515KV1%2FqkSrQeG5NbKpS5tDt6IfZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;237&quot; data-origin-width=&quot;2534&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 사용하고 싶은 도메인주소를 검색하면 .com , .io , .net 등등 주소들과 가격이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그중에서 원하는 도메인을 선택하고 결제진행을 해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;1526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpLbDu/btsqwBoif7w/Pknl9G8yqKWXwNBgPyCnw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpLbDu/btsqwBoif7w/Pknl9G8yqKWXwNBgPyCnw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpLbDu/btsqwBoif7w/Pknl9G8yqKWXwNBgPyCnw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpLbDu%2FbtsqwBoif7w%2FPknl9G8yqKWXwNBgPyCnw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;1526&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;1526&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 개인정보와 결제정보를 입력해서 진행해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-09 오전 5.43.13.png&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wTbSW/btsqBGh0GSq/aS8kYUDf2thtKxRne5KkC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wTbSW/btsqBGh0GSq/aS8kYUDf2thtKxRne5KkC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wTbSW/btsqBGh0GSq/aS8kYUDf2thtKxRne5KkC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwTbSW%2FbtsqBGh0GSq%2FaS8kYUDf2thtKxRne5KkC1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;348&quot; data-filename=&quot;스크린샷 2023-08-09 오전 5.43.13.png&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기다리면 작성한 메일로 인증링크가 메일로 오는데 링크를 눌러주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1558&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XJv6z/btsqD6GGE6P/BKxGH6iZF9XAqdZ9UlzUYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XJv6z/btsqD6GGE6P/BKxGH6iZF9XAqdZ9UlzUYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XJv6z/btsqD6GGE6P/BKxGH6iZF9XAqdZ9UlzUYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXJv6z%2FbtsqD6GGE6P%2FBKxGH6iZF9XAqdZ9UlzUYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;83&quot; data-origin-width=&quot;1558&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 기다리면 Route53에서 등록이 된 걸 확인할 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 도메인 구매했으면 끝이지만, 배포전까지 해당 도메인에 html 파일이라도 띄워두고싶어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;S3 버킷과 연동&lt;/b&gt;시켜서 웹 호스팅을 하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 S3버킷을 만들어야 하는데 여기서 중요한게&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;연결할 도메인과 동일하게 버킷이름을 생성해 주어야한다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;1394&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IDDYd/btsqwWFHmKJ/lumTTfhmsvgSlPXoYPnxFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IDDYd/btsqwWFHmKJ/lumTTfhmsvgSlPXoYPnxFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IDDYd/btsqwWFHmKJ/lumTTfhmsvgSlPXoYPnxFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIDDYd%2FbtsqwWFHmKJ%2FlumTTfhmsvgSlPXoYPnxFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;498&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;1394&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리전은 &lt;b&gt;서울&lt;/b&gt;로 해주고 아래엔 &quot;ACL 비활성화&quot; 로 해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-09 오전 5.53.33.png&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;1244&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1T16o/btsqFspcW82/KNshKE1ybyTVLPoOD1KHe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1T16o/btsqFspcW82/KNshKE1ybyTVLPoOD1KHe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1T16o/btsqFspcW82/KNshKE1ybyTVLPoOD1KHe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1T16o%2FbtsqFspcW82%2FKNshKE1ybyTVLPoOD1KHe0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;1244&quot; data-filename=&quot;스크린샷 2023-08-09 오전 5.53.33.png&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;1244&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에 &quot;퍼블릭 엑세스 차단설정&quot; 은 모두 &lt;b&gt;해제&lt;/b&gt;하고 퍼블릭 상태에 체크를 해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 S3 버킷 생성은 끝났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 S3에 몇가지 설정을 변경해주어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그전에 S3에 업로드 시킬 &lt;b&gt;&quot;index.html&quot;&lt;/b&gt; 파일을 준비해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;S3 -&amp;gt; 객체 -&amp;gt; 업로드&amp;nbsp;&lt;/b&gt;순서로 준비된 &lt;b&gt;&quot;index.html&quot; &lt;/b&gt;을 업로드를 해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 S3설정을 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 5.59.38.png&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ethpp/btsqC7TtajF/LM66OqPm9dLB742suCMyF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ethpp/btsqC7TtajF/LM66OqPm9dLB742suCMyF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ethpp/btsqC7TtajF/LM66OqPm9dLB742suCMyF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEthpp%2FbtsqC7TtajF%2FLM66OqPm9dLB742suCMyF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;189&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 5.59.38.png&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;S3 -&amp;gt; 속성&lt;/b&gt; 탭 에서 아래로 내려서 &lt;b&gt;&quot;정적 웹 사이트 호스팅&quot;&lt;/b&gt; 에서 편집을 눌러주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-09 오전 6.01.10.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;1162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/21fl1/btsqwZbnRXa/d2bnBBi63oDrCJFLAqWNb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/21fl1/btsqwZbnRXa/d2bnBBi63oDrCJFLAqWNb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/21fl1/btsqwZbnRXa/d2bnBBi63oDrCJFLAqWNb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F21fl1%2FbtsqwZbnRXa%2Fd2bnBBi63oDrCJFLAqWNb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;745&quot; data-filename=&quot;스크린샷 2023-08-09 오전 6.01.10.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;1162&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;활성화, 정적 웹 호스팅&lt;/b&gt;에 체크를 해주고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스 문서와 오류 문서에 아까 업로드한&lt;b&gt; &quot;index.html&quot;&lt;/b&gt; 을 입력해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 저장을 해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 6.04.00.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K2lnY/btsqD4WrBqd/4ll6CB1k05UQOUkKPev7ok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K2lnY/btsqD4WrBqd/4ll6CB1k05UQOUkKPev7ok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K2lnY/btsqD4WrBqd/4ll6CB1k05UQOUkKPev7ok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK2lnY%2FbtsqD4WrBqd%2F4ll6CB1k05UQOUkKPev7ok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;175&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 6.04.00.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;S3 -&amp;gt; 정책&lt;/b&gt; 탭에서 아래로 내려서 버킷정책으로 이동하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 편집을 눌러주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_스크린샷 2023-08-09 오전 6.08.26.png&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BIHYV/btsqwAJFZl2/51IpPp2yWvONwKNfB0RbS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BIHYV/btsqwAJFZl2/51IpPp2yWvONwKNfB0RbS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BIHYV/btsqwAJFZl2/51IpPp2yWvONwKNfB0RbS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBIHYV%2FbtsqwAJFZl2%2F51IpPp2yWvONwKNfB0RbS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;391&quot; data-filename=&quot;edited_edited_스크린샷 2023-08-09 오전 6.08.26.png&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;버킷 ARN 을 복사&lt;/b&gt;하고 &lt;b&gt;정챙생성기 버튼&lt;/b&gt;을 눌러주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-09 오전 6.11.04.png&quot; data-origin-width=&quot;1518&quot; data-origin-height=&quot;1166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCUOlT/btsqB9jR9nQ/y1A9uOohCQl1dVfsU3cGN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCUOlT/btsqB9jR9nQ/y1A9uOohCQl1dVfsU3cGN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCUOlT/btsqB9jR9nQ/y1A9uOohCQl1dVfsU3cGN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCUOlT%2FbtsqB9jR9nQ%2Fy1A9uOohCQl1dVfsU3cGN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;461&quot; data-filename=&quot;스크린샷 2023-08-09 오전 6.11.04.png&quot; data-origin-width=&quot;1518&quot; data-origin-height=&quot;1166&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;S3 Bucket Policy , * , Amazon S3&lt;/b&gt; 를 차례대로 누르고&lt;br /&gt;&lt;br /&gt;Action에서 &lt;b&gt;&quot;GetObject&quot;&lt;/b&gt; 를 선택해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 아래 ARN 에서는 &lt;b&gt;복사한 ARN주소&lt;/b&gt;를 넣어주고 뒤에&lt;b&gt; /*&lt;/b&gt; 를 써서 Add statement를 누른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 만들어준 정책코드를 &lt;b&gt;복사&lt;/b&gt;해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;복사한 정책코드를 붙혀넣기&lt;/b&gt;해서 넣어주면 S3에서는 전부 다 설정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 6.17.07.png&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;684&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K26tL/btsqFrX89aE/eNfYcGFQREHE4ZnelzING1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K26tL/btsqFrX89aE/eNfYcGFQREHE4ZnelzING1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K26tL/btsqFrX89aE/eNfYcGFQREHE4ZnelzING1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK26tL%2FbtsqFrX89aE%2FeNfYcGFQREHE4ZnelzING1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;374&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 6.17.07.png&quot; data-origin-width=&quot;1098&quot; data-origin-height=&quot;684&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S3 설정이 끝났으니 Route 53에서 &lt;b&gt;호스팅영역&lt;/b&gt;으로 이동하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 호스팅 리스트에 아까 도메인 구매한게 없으면, &lt;b&gt;호스팅 영역 생성&lt;/b&gt;을 해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호스팅 영역 생성은 &lt;b&gt;&quot;구매한 도메인&quot;&lt;/b&gt; 과 &lt;b&gt;&quot;퍼블릭 호스팅 영역&quot;&lt;/b&gt;을 눌러주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 생성된 호스팅 영역을 생성 후 호스팅 영역을 눌러주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-09 오전 6.20.54.png&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;962&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfHZfn/btsqAxsjqfj/3RXT5Dng0b540KMlHKZNfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfHZfn/btsqAxsjqfj/3RXT5Dng0b540KMlHKZNfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfHZfn/btsqAxsjqfj/3RXT5Dng0b540KMlHKZNfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfHZfn%2FbtsqAxsjqfj%2F3RXT5Dng0b540KMlHKZNfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;427&quot; data-filename=&quot;스크린샷 2023-08-09 오전 6.20.54.png&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;962&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;&quot;레코드 생성&quot;&lt;/b&gt;으로 들어가주자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;단순 라우팅&quot;&lt;/b&gt; 을 누르고 &lt;b&gt;&quot;단순 레코드 정의&quot;&lt;/b&gt;를 눌러주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1720&quot; data-origin-height=&quot;1552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wYe83/btsqvhJ8gw7/Tw2YBHfkaudki6rEKEqKkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wYe83/btsqvhJ8gw7/Tw2YBHfkaudki6rEKEqKkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wYe83/btsqvhJ8gw7/Tw2YBHfkaudki6rEKEqKkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwYe83%2FbtsqvhJ8gw7%2FTw2YBHfkaudki6rEKEqKkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;541&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1720&quot; data-origin-height=&quot;1552&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레코드 이름은 &lt;b&gt;비워두거나&lt;/b&gt; www를 써주고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레코드 유형은&lt;b&gt; A - IPv4&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값/ 트래픽 라우트 대상은 &lt;b&gt;S3 -&amp;gt; 아까 고른 서울 리전 -&amp;gt; 생성한 S3 버킷&lt;/b&gt;이 나올텐데 눌러주자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(S3 이름을 도메인 이름과 &lt;b&gt;다르게 생성&lt;/b&gt;시 여기서 리전을 골라도 버킷이 보이지 않는다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;단순 레코드 정의&lt;/b&gt;를 해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 드디어 끝이다 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인에 들어가보면 &lt;b&gt;1분&lt;/b&gt;안에 S3에 업로드한게 호스팅 되서 나올 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1608&quot; data-origin-height=&quot;1156&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bv2srh/btsqwZCrEzt/a66NJ1ynakcrQkY0fHkPBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bv2srh/btsqwZCrEzt/a66NJ1ynakcrQkY0fHkPBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bv2srh/btsqwZCrEzt/a66NJ1ynakcrQkY0fHkPBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbv2srh%2FbtsqwZCrEzt%2Fa66NJ1ynakcrQkY0fHkPBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;431&quot; data-origin-width=&quot;1608&quot; data-origin-height=&quot;1156&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 나는 시간이 지나고 지나도 작동하지 않았다....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 해당 작업을 열댓번 다른케이스로 반복하고,&lt;b&gt; 구글링과 GPT&lt;/b&gt;한테 물어봐도 답을 찾지 못했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 밤새 머리를 싸매서 해결했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 6.35.54.png&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;1252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3fDW3/btsqC70gtcP/Odgz4vS0Bu4AhABEAqiBw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3fDW3/btsqC70gtcP/Odgz4vS0Bu4AhABEAqiBw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3fDW3/btsqC70gtcP/Odgz4vS0Bu4AhABEAqiBw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3fDW3%2FbtsqC70gtcP%2FOdgz4vS0Bu4AhABEAqiBw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;438&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 6.35.54.png&quot; data-origin-width=&quot;1716&quot; data-origin-height=&quot;1252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 6.38.12.png&quot; data-origin-width=&quot;2530&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ykGDq/btsqDdMQcyd/z7Yq8Gfh5ggvLcmzKwspX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ykGDq/btsqDdMQcyd/z7Yq8Gfh5ggvLcmzKwspX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ykGDq/btsqDdMQcyd/z7Yq8Gfh5ggvLcmzKwspX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FykGDq%2FbtsqDdMQcyd%2Fz7Yq8Gfh5ggvLcmzKwspX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;690&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 6.38.12.png&quot; data-origin-width=&quot;2530&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;두가지&lt;/b&gt;를 비교해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 호스팅 영역 -&amp;gt; 레코드 -&amp;gt; &lt;b&gt;NS 유형의 값/ 트래픽 라우팅 대상&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 등록된 도메인 -&amp;gt; &lt;b&gt;이름서버&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 1,2 번이 &lt;b&gt;동일&lt;/b&gt;해야지만 호스팅이 되지 않을까? 라는 생각을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 6.40.44.png&quot; data-origin-width=&quot;1648&quot; data-origin-height=&quot;934&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uAcSq/btsqvhi5m8W/oRzeKkB2sw7s5xkkbzFVCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uAcSq/btsqvhi5m8W/oRzeKkB2sw7s5xkkbzFVCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uAcSq/btsqvhi5m8W/oRzeKkB2sw7s5xkkbzFVCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuAcSq%2Fbtsqvhi5m8W%2FoRzeKkB2sw7s5xkkbzFVCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;340&quot; data-filename=&quot;edited_스크린샷 2023-08-09 오전 6.40.44.png&quot; data-origin-width=&quot;1648&quot; data-origin-height=&quot;934&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등록된 도메인 -&amp;gt; 이름 서버편집 -&amp;gt; &lt;b&gt;위 2번에 있던 4개의 Url&lt;/b&gt;로 동일하게 맞춰주자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러고 1분정도 지나서 새로고침을 해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2596&quot; data-origin-height=&quot;1790&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYNcLH/btsqC9qdqxB/AWxmdNi3a6DyXQ2CLoQc3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYNcLH/btsqC9qdqxB/AWxmdNi3a6DyXQ2CLoQc3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYNcLH/btsqC9qdqxB/AWxmdNi3a6DyXQ2CLoQc3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYNcLH%2FbtsqC9qdqxB%2FAWxmdNi3a6DyXQ2CLoQc3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;414&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2596&quot; data-origin-height=&quot;1790&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어 정상적으로 웹 호스팅이 되었다!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 지금은 &lt;b&gt;http&lt;/b&gt;여서 다음번에&lt;b&gt;&amp;nbsp;CloudFront&lt;/b&gt;를 사용해서&lt;b&gt; Https&lt;/b&gt;로 웹 호스팅을 할 예정이다.&lt;/p&gt;</description>
      <category>Programming/AWS</category>
      <category>AWS</category>
      <category>route53</category>
      <category>S3</category>
      <category>호스팅</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/53</guid>
      <comments>https://ilikezzi.tistory.com/53#entry53comment</comments>
      <pubDate>Wed, 9 Aug 2023 06:52:42 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 데이터 타입_코어 자바스크립트</title>
      <link>https://ilikezzi.tistory.com/52</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;계획했던대로 자격증 취득도 다 해서, 8월부터는 알고리즘과 팀프로젝트에 전념할 계획이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 알고리즘 스터디를 하기전에 JS 기본기를 탄탄하게 다져두고 하는게 깊은 이해에 도움이 될 것 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때마침 회사 프런트 엔드 직원분들이 &lt;b&gt;&quot;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;&lt;b&gt;모던 자바스크립트 Deep Dive&quot;&lt;/b&gt; 와 &lt;b&gt;&quot;코어 자바스크립트&quot;&lt;/b&gt; 두 책을 강추해주셨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;그동안 나는 인강이 좀 더 잘 맞는다고 생각했어서, 우선 끝까지 읽기에 상대적으로 얇은 책으로 선택했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-06 오후 10.38.04.png&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;1602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cItNL5/btsp90m5Lnj/cck3A5gIMVu8kELvBKdmkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cItNL5/btsp90m5Lnj/cck3A5gIMVu8kELvBKdmkk/img.png&quot; data-alt=&quot;코어 자바스크립트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cItNL5/btsp90m5Lnj/cck3A5gIMVu8kELvBKdmkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcItNL5%2Fbtsp90m5Lnj%2Fcck3A5gIMVu8kELvBKdmkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;617&quot; data-filename=&quot;스크린샷 2023-08-06 오후 10.38.04.png&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;1602&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코어 자바스크립트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 가볍게 &quot;혼동되는 개념만 잡고 빨리 알고리즘으로 넘어가야지. &quot; 라는 생각뿐이였는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1, 2 단원을 읽고 생각이 바뀌었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;남들이 이해한 내용을 듣기만 하는게 아닌, 책을 보면서 곰곰히 고민하고 이해하는것도 잘 정리가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 단원별로 포스팅하면서 한번 더 머리속에 정리를 해보려고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;01. 데이터 타입&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데이터&amp;nbsp;타입과&amp;nbsp;변수&amp;nbsp;선언&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691331069199&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var a;			// 변수 a 선언
a = 'abc';		// 변수 a에 데이터 할당

var a = 'abc'; 		// 변수 선언과 할당을 한 문장으로 표현&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 변수 선언과 데이터 할당에 대해서는 알고 있었지만 깊게 들어가 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3450&quot; data-origin-height=&quot;1264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uwCz2/btsp3lTSkBi/v0MUDoODtWWtDqN6BPxD1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uwCz2/btsp3lTSkBi/v0MUDoODtWWtDqN6BPxD1K/img.png&quot; data-alt=&quot; 데이터 할당에 대한 메모리 변화&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uwCz2/btsp3lTSkBi/v0MUDoODtWWtDqN6BPxD1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuwCz2%2Fbtsp3lTSkBi%2Fv0MUDoODtWWtDqN6BPxD1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;220&quot; data-origin-width=&quot;3450&quot; data-origin-height=&quot;1264&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; 데이터 할당에 대한 메모리 변화&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터할당에&lt;span&gt; &lt;/span&gt;대한&lt;span&gt; &lt;/span&gt;메모리&lt;span&gt; &lt;/span&gt;변화를 표로 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 변수 영역에서 빈 공간(@1003)을 우선 확보&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 확보한 공간의 식별자를 a로 지정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 데이터 영역의 빈 공간(@5004)에 문자열 'abc'를 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 앞서 저장한 문자열의 주소(@5004)를 @1003의 공간에 대입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 만약&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691331685929&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// var a = 'abc' 
var a = 'abcdef'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 데이터 영역에 새로운 값을 할당하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3226&quot; data-origin-height=&quot;1108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4tiS9/btsp9ptUvq2/CYVIl3FzqvNJXVebU8poQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4tiS9/btsp9ptUvq2/CYVIl3FzqvNJXVebU8poQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4tiS9/btsp9ptUvq2/CYVIl3FzqvNJXVebU8poQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4tiS9%2Fbtsp9ptUvq2%2FCYVIl3FzqvNJXVebU8poQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;206&quot; data-origin-width=&quot;3226&quot; data-origin-height=&quot;1108&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 데이터 영역에 빈 공간(@5005)에 문자열 'abcdef'를 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 앞서 저장한 문자열의 주소(@5005)를 @1003의 공간에 다시 대입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 기존 문자열에 새 값이 할당되더라도 &lt;b&gt;무조건 새로 만들어 별도의 공간에 저장한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;변수&lt;/b&gt;와 &lt;b&gt;상수&lt;/b&gt;를 구분 짓는 변경 가능성의 대상은 위 사진의 &lt;b&gt;변수 영역 메모리&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수:&amp;nbsp;한&amp;nbsp;번&amp;nbsp;할당된&amp;nbsp;데이터&amp;nbsp;영역에&amp;nbsp;&lt;b&gt;재할당이&amp;nbsp;가능.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상수:&amp;nbsp;재할당이&amp;nbsp;&lt;b&gt;불가능.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 불변성 여부를 구분 할 떄의 변경 가능성의 대상은 &lt;b&gt;데이터 영역 메모리&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691332607992&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var a = 10;
var b = a;

b = 15;

/////////////////

var obj1 = { c:10, d:&amp;rsquo;ddd&amp;rsquo; };
var obj2 = obj1;

obj2.c = 20;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 두 코드의 결과값 비교부터 해보자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691332701446&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;a !== b
obj1 === obj2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 결과가 바로 &lt;b&gt;기본형과 참조형 데이터의 가장 큰 차이점이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3138&quot; data-origin-height=&quot;1846&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eHWRef/btsp336CTDx/mB3j3KtKECa3At0NKOLr0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eHWRef/btsp336CTDx/mB3j3KtKECa3At0NKOLr0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eHWRef/btsp336CTDx/mB3j3KtKECa3At0NKOLr0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeHWRef%2Fbtsp336CTDx%2FmB3j3KtKECa3At0NKOLr0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;353&quot; data-origin-width=&quot;3138&quot; data-origin-height=&quot;1846&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사진으로 보면 이해가 바로 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;첫번째 case&lt;/b&gt;를 먼저 보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;b에 15라는 값이 할당 되는순간, 변수 영역 주소 1002에 있던 b는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 영역에서 빈 주소(@5004)를 찾아서 15를 저장하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저장한 문자열의 주소(@5004)를 @1002의 공간에 다시 대입한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서&lt;b&gt; 기본형 데이터&lt;/b&gt;를 복사했던 &lt;b&gt;a와 b 는 이제 다른 주소&lt;/b&gt;를 바라보고 &lt;b&gt;서로 다른 값&lt;/b&gt;이 된 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;두번째 case&lt;/b&gt;를 보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;obj2의 프로퍼티를 변경해도 변수 @1003과 @1004가 바라보는 데이터 주소는 변함이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 데이터 영역에 아직 20이 없으므로 새로운 공간 @5005에 저장하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@5002가 가리키는 변수 영역에서 다시 c를 찾아(@7103) 그곳에 @5005를 대입한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;참조형 데이터&lt;/b&gt;를 복사 했던 &lt;b&gt;obj1과 obj2는 여전히 같은 객체를 바라보고&lt;/b&gt; &lt;b&gt;있는 상태&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기본형&amp;nbsp;데이터&lt;/b&gt;:&amp;nbsp;실제&amp;nbsp;값이&amp;nbsp;저장되는&amp;nbsp;형태로,&amp;nbsp;값이&amp;nbsp;변경되면&amp;nbsp;새로운&amp;nbsp;메모리&amp;nbsp;공간에&amp;nbsp;저장.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참조형&amp;nbsp;데이터&lt;/b&gt;:&amp;nbsp;주소를&amp;nbsp;통해&amp;nbsp;값을&amp;nbsp;참조하는&amp;nbsp;형태로,&amp;nbsp;내부&amp;nbsp;프로퍼티가&amp;nbsp;변경되어도&amp;nbsp;참조&amp;nbsp;주소는&amp;nbsp;그대로.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691333912423&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var obj1 = { c:10, d:'ddd' };
var obj2 = obj1;

obj2 = { c: 15, d:'123' };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 &lt;b&gt;세번째 case&lt;/b&gt;를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 결과 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691333995002&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; obj1 !== obj2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 왜 같지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부의 프로퍼티를 변경한게 아니라 &lt;b&gt;데이터 자체를 변경&lt;/b&gt;한거라서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;obj2 의 변수 영역의 바라보는 &lt;b&gt;주소자체가 바뀌게 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 obj1 과 obj2는 이제&lt;b&gt; 서로 다른 주소를 바라보는 다른 값&lt;/b&gt;이 되어버린 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참조형 데이터가 '가변값'이라고 설명할 때의 '가변'은 참조형 데이터자체를 변경할 경우가 아니라&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;그 내부의 프로퍼티를 변경할 때만 성립된다. ⭐️&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본형과 참조형의 차이점과 메모리 상에서 어떻게 동작하는지 이해하면, 더욱 효과적인 코드를 작성할 수 있을 것 같다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;불변객체 이해하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불변 객체는 한 번 생성되면 그 상태를 변경할 수 없는 객체다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트와 같은 언어에서는 객체에 대한 변경을 막기 위해 불변 객체를 사용하는 경우가 종종 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 어떻게 이게 작동하는지 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.&amp;nbsp;얕은&amp;nbsp;복사(Shallow&amp;nbsp;Copy)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 객체의 &lt;b&gt;첫 번째 레벨만 복사해&lt;/b&gt;. 나머지는 참조로 연결되므로 &lt;b&gt;원본 객체에 영향을 줄 수 있다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&amp;nbsp;깊은&amp;nbsp;복사(Deep&amp;nbsp;Copy)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 내부의 모든 값을 하나하나 찾아 전부 복사해서&lt;b&gt;&amp;nbsp;독립된&amp;nbsp;원본&lt;/b&gt;을&amp;nbsp;만들어.&amp;nbsp;&lt;b&gt;원본 객체에 영향을 주지 않는다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기본형은 그대로 복사&lt;/b&gt;하고, &lt;b&gt;참조형&lt;/b&gt;은 내부의 프로퍼티들을 &lt;b&gt;재귀적으로 복사&lt;/b&gt;해야 깊은 복사가 이루어진다.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 깊은 복사의 예제코드를 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691334962954&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; var copyObjectDeep = function(target){
        var result = {};  
        if(typeof target === 'object' &amp;amp;&amp;amp; target !== null ){
          for(var prop in target){
            result[prop] = copyObjectDeep(target[prop]);
          }
        } else {
          result = target;
        }
      return result;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;좀 더 간단하게 깊은 복사를 처리 할 수 있는 &lt;b&gt;JSON을 활용한 깊은 복사&lt;/b&gt; 코드를 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691335138694&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var copyObjectViaJSON = function(target) {
    					return JSON.parse(JSON.stringify(target));
   						}
                        
// JSON.parse(...): 앞서 JSON 형식의 문자열로 변환된 target 객체를 다시 일반 자바스크립트 객체로 파싱한다. 
// 					그 결과로 완전히 새로운 객체가 생성된다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 Json문법으로 표현된 문자열로 전환했다가 다시JSON객체로 바꾸는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 방법은 메서드나 숨겨진 프로퍼티, getter/setter 등과 같이 JSON으로 변경할 수 없는 프로퍼티는 무시된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 순수한 정보만 다룰 때 활용하기 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;null과&amp;nbsp;undefined의&amp;nbsp;차이점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.&amp;nbsp;null&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입:&lt;b&gt;&amp;nbsp;typeof&amp;nbsp;null의&amp;nbsp;결과는&amp;nbsp;&quot;object&quot;&lt;/b&gt;.&amp;nbsp;이건&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;JavaScript의 초기 버전에서 발생한 버그로, 지금까지 수정되지 않았다.&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미: 명시적으로 값이 없음을 나타내고 싶을 때 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&amp;nbsp;undefined&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입:&amp;nbsp;typeof&amp;nbsp;undefined의&amp;nbsp;결과는&amp;nbsp;&lt;b&gt;&quot;undefined&quot;.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미: 변수가 선언되었지만 값이 할당되지 않았을 때 자동으로 할당되는 값.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;null과 undefined는 == (동등 비교)를 사용할 경우 서로 동등하다고 간주된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 null과 undefined만의 특별한 케이스다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=== (일치 비교)를 사용하면 null은 null과만 일치하고, undefined는 undefined와만 일치하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691335609057&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var n = null;

console.log(typeof n); // &quot;object&quot;
console.log(n == undefined) // true
console.log(n === undefined) // false
console.log(n == null) // true
console.log(n === null) // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;null과 undefined는 비슷한 개념이지만, 다르게 취급되는 경우가 있어서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가능한 &lt;b&gt;일치 비교(===)를 사용하는 습관&lt;/b&gt;을 들이는 것이 좋을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/Javascript</category>
      <category>JavaScript</category>
      <category>데이터 타입</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/52</guid>
      <comments>https://ilikezzi.tistory.com/52#entry52comment</comments>
      <pubDate>Mon, 7 Aug 2023 00:40:54 +0900</pubDate>
    </item>
    <item>
      <title>[해커톤] 인하대 해커톤 멘토 참여후기</title>
      <link>https://ilikezzi.tistory.com/51</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3122&quot; data-origin-height=&quot;1812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2hQJZ/btsnFK8x3gT/QcAkVDQMpqUOEeWW7gYg61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2hQJZ/btsnFK8x3gT/QcAkVDQMpqUOEeWW7gYg61/img.png&quot; data-alt=&quot; INHA SW NET-Zero 공동해커톤&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2hQJZ/btsnFK8x3gT/QcAkVDQMpqUOEeWW7gYg61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2hQJZ%2FbtsnFK8x3gT%2FQcAkVDQMpqUOEeWW7gYg61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;348&quot; data-origin-width=&quot;3122&quot; data-origin-height=&quot;1812&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; INHA SW NET-Zero 공동해커톤&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 인하대학교에서 진행한&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;INHA SW NET-Zero 공동해커톤&lt;/b&gt;에 &lt;b&gt;멘토&lt;/b&gt;로 참여한 후기를 포스팅 해보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 컴공 전공자임에도 불구하고 대학시절에 해커톤 참가를 한번도 안해봐서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;밤새면서 개발의 열정을 불태우는 분위기&lt;/b&gt;가 너무나 궁금했는데 이번에 우연히 기회가 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼마전 contect하게 된 AWS 직원분께서 &lt;b&gt;해커톤 멘토로 참여 제의&lt;/b&gt;를 하셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제의를 받고 처음엔 &quot;내가 누군가한테 조언을 줄 수 있는 입장인가?&quot; 라는 생각 때문에 잠시 망설였지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주니어 개발자로 1년간 경력을 쌓아오면서 &lt;b&gt;문제를 해결했던 경험&lt;/b&gt;이나 &lt;b&gt;다양한 트러블 슈팅 지식들&lt;/b&gt;이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌면 &lt;b&gt;밤새며 빠르게 개발을 해야하는 그들&lt;/b&gt;에게 도움을 줄 수 있겠다. 라는 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3112&quot; data-origin-height=&quot;1816&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oKmhC/btsnHRlxWlY/ha6T5h071MFH76mfCDrto0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oKmhC/btsnHRlxWlY/ha6T5h071MFH76mfCDrto0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oKmhC/btsnHRlxWlY/ha6T5h071MFH76mfCDrto0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoKmhC%2FbtsnHRlxWlY%2Fha6T5h071MFH76mfCDrto0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;350&quot; data-origin-width=&quot;3112&quot; data-origin-height=&quot;1816&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 나는 &lt;b&gt;AWS DevOps &lt;/b&gt;및&lt;b&gt; Backend 개발자&lt;/b&gt;로 멘토단에 들어가게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-16 오전 2.32.04.png&quot; data-origin-width=&quot;3112&quot; data-origin-height=&quot;1812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wpJQL/btsnIJVlAuy/fQKcoGS6napj78pbYnEzKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wpJQL/btsnIJVlAuy/fQKcoGS6napj78pbYnEzKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wpJQL/btsnIJVlAuy/fQKcoGS6napj78pbYnEzKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwpJQL%2FbtsnIJVlAuy%2FfQKcoGS6napj78pbYnEzKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;349&quot; data-filename=&quot;스크린샷 2023-07-16 오전 2.32.04.png&quot; data-origin-width=&quot;3112&quot; data-origin-height=&quot;1812&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 &lt;b&gt;NET-Zero 해커톤&lt;/b&gt;의 주제는 &lt;b&gt;탄소중립 실천&lt;/b&gt;이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인하대, 상명대, 경기대에서 총 20개 팀이 참여를 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-07-16 오전 3.13.05.png&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;1634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQPjzY/btsnFehLwoI/TbSLMH5qs7uEqQxGpwUkik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQPjzY/btsnFehLwoI/TbSLMH5qs7uEqQxGpwUkik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQPjzY/btsnFehLwoI/TbSLMH5qs7uEqQxGpwUkik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQPjzY%2FbtsnFehLwoI%2FTbSLMH5qs7uEqQxGpwUkik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;969&quot; data-filename=&quot;edited_스크린샷 2023-07-16 오전 3.13.05.png&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;1634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-16 오전 3.13.51.png&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;1724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cekVkd/btsnIK7MHFJ/LjEZFPFPIoIjlCts3ePK9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cekVkd/btsnIK7MHFJ/LjEZFPFPIoIjlCts3ePK9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cekVkd/btsnIK7MHFJ/LjEZFPFPIoIjlCts3ePK9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcekVkd%2FbtsnIK7MHFJ%2FLjEZFPFPIoIjlCts3ePK9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;998&quot; data-filename=&quot;스크린샷 2023-07-16 오전 3.13.51.png&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;1724&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;20개 팀들이 단상에서 각자 선정한 주제에 대해서 1분 발표를 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;인원이 100명이 넘다보니 역시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;신박한 아이디어와 좋은 의견&lt;/b&gt;들이 쏟아져 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-16 오전 3.17.38.png&quot; data-origin-width=&quot;1014&quot; data-origin-height=&quot;1308&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bytANz/btsnFE8meVt/NJUplx6knd31PH0aN8dpok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bytANz/btsnFE8meVt/NJUplx6knd31PH0aN8dpok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bytANz/btsnFE8meVt/NJUplx6knd31PH0aN8dpok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbytANz%2FbtsnFE8meVt%2FNJUplx6knd31PH0aN8dpok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;774&quot; data-filename=&quot;스크린샷 2023-07-16 오전 3.17.38.png&quot; data-origin-width=&quot;1014&quot; data-origin-height=&quot;1308&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웃겨서 찍은 사진인데 역시 chatGPT는 못참지...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발할 때 보니 거의 모든 학생들이 chatGPT를 활용하고 있더라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하긴 요새는 얼마나 &lt;b&gt;chatGPT를 잘 활용하느냐&lt;/b&gt;도 중요한 능력인듯 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1679&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bklcqr/btsnILySc3M/ut49RxjYth4jYNQTD40wc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bklcqr/btsnILySc3M/ut49RxjYth4jYNQTD40wc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bklcqr/btsnILySc3M/ut49RxjYth4jYNQTD40wc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbklcqr%2FbtsnILySc3M%2Fut49RxjYth4jYNQTD40wc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;336&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1679&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해커톤이 시작하니 다들 눈에 불을키고 으쌰으쌰하면서 개발을 하는데 너무나 멋있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멘토진들은 즉각 멘토링을 해주기 위해서&lt;b&gt; 선정한 주제와 설계&lt;/b&gt;를 살펴보며 준비를 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학생들의 초반과 막바지의 주된 질문은&lt;b&gt; AWS&lt;/b&gt;쪽이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2, RDS, 보안그룹, S3, Cloud9 등등..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SAA&lt;/b&gt;(AWS Certified Solutions Architect - Associate) 자격증은 취득하길 참 잘한것 같다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 서버를 설계하면&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;좀 더 빠르고 개발 시간을 줄이는데&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;좋지 않을까? 라는 조언을 할 수 있게 되었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 새벽시간에는 &lt;b&gt;백엔드&lt;/b&gt;쪽 질문이 쏟아져 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바, 스프링부트, 노드, 크롤링 등등...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멘토진들은 각자 분야의 맡아서 멘토링을 담당했는데 나는 백엔드에서 &lt;b&gt;노드쪽&lt;/b&gt;을 맡았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각자의 분야가 다르다보니 배울점도 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멘토링을 해주면서 내가 겪었던 문제들이 나오면 빠르게 해답을 주었지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나도 모르는 문제가 나오면 같이 해결하거나, 식은땀 흘리며 다른 멘토님의 힘을 빌렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멘토진들 정말 똑똑한분들이 많으셔서 든든했다..!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 분위기 속에 있으니 정말 &lt;b&gt;긍정적인 영향과 자극&lt;/b&gt;을 많이 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배우기도 많이 배웠고 무엇보다&lt;b&gt; 열정&lt;/b&gt;이 정말 대단했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멘토진들도 식사시간에 재미삼아 모니터링 시스템도 만들기도하고 개발을 하기도하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다들 개발에 진심인 사람들이 모이다보니 너무나 즐거웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-16 오전 3.46.00.png&quot; data-origin-width=&quot;2666&quot; data-origin-height=&quot;1662&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lWpxM/btsnD472GzU/xfzJcu8sN10YbJqDOT70J0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lWpxM/btsnD472GzU/xfzJcu8sN10YbJqDOT70J0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lWpxM/btsnD472GzU/xfzJcu8sN10YbJqDOT70J0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlWpxM%2FbtsnD472GzU%2FxfzJcu8sN10YbJqDOT70J0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;374&quot; data-filename=&quot;스크린샷 2023-07-16 오전 3.46.00.png&quot; data-origin-width=&quot;2666&quot; data-origin-height=&quot;1662&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-16 오전 3.46.26.png&quot; data-origin-width=&quot;1382&quot; data-origin-height=&quot;1676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crHH54/btsnFEN3fxM/0gbp8koFxkF0dU4dohb3OK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crHH54/btsnFEN3fxM/0gbp8koFxkF0dU4dohb3OK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crHH54/btsnFEN3fxM/0gbp8koFxkF0dU4dohb3OK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrHH54%2FbtsnFEN3fxM%2F0gbp8koFxkF0dU4dohb3OK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;728&quot; data-filename=&quot;스크린샷 2023-07-16 오전 3.46.26.png&quot; data-origin-width=&quot;1382&quot; data-origin-height=&quot;1676&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;귀여운 스티커랑 크록스도 받았다ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 내 맥북은 점점 더 지저분해져 간다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;1406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/65PIc/btsnHTjodnx/9dkZoX055oAJBmXYFbPEi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/65PIc/btsnHTjodnx/9dkZoX055oAJBmXYFbPEi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/65PIc/btsnHTjodnx/9dkZoX055oAJBmXYFbPEi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F65PIc%2FbtsnHTjodnx%2F9dkZoX055oAJBmXYFbPEi1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;981&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;1406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해커톤을 무사히 마치고 나서 학생들에게 멘토링 &lt;b&gt;피드백&lt;/b&gt;을 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누구한테&amp;nbsp;&lt;b&gt;도움이&amp;nbsp;된다는&amp;nbsp;건&amp;nbsp;정말&amp;nbsp;뿌듯한&amp;nbsp;일&lt;/b&gt;인&amp;nbsp;것&amp;nbsp;같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멘토진들끼리 다 같이 다음 해커톤에서도 멘토로 참석하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음번 멘토링을 위해서 좀 부족한 부분을 메꾸고 나도 프로젝트를 해보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발단계를 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;0 to 1 / 1 to 10 / 10 to 100&lt;/b&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;이처럼 3단계로 나누어 보았을때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그동안 회사에서 나는 주로 &lt;b&gt;1 to 10&lt;/b&gt; 이나 &lt;b&gt;10 to 100&lt;/b&gt; 위주의 일을 맡아서 해왔기 때문에&lt;br /&gt;&lt;br /&gt;설계단계부터 진행하는&lt;b&gt; 0 to 1&amp;nbsp;&lt;/b&gt;은 나한테 너무나 낯설고 어려웠다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이참에 거창하지는 않지만 따로 개인 프로젝트를 시작해보면서 &lt;b&gt;부족한 부분을 메꿀&lt;/b&gt;생각이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 얻은게 많은 첫 해커톤이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열심히 사시는 모든 개발자분들 존경합니다.&lt;/p&gt;</description>
      <category>Participation</category>
      <category>AWS</category>
      <category>멘토</category>
      <category>해커톤</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/51</guid>
      <comments>https://ilikezzi.tistory.com/51#entry51comment</comments>
      <pubDate>Sun, 16 Jul 2023 05:22:41 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] 국내 1호 AWS 굿즈 개봉기! (+ 개발진스)</title>
      <link>https://ilikezzi.tistory.com/50</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 처음으로 개발 내용 외에 포스팅을 해보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼마전에 &lt;b&gt;SAA-C03 합격후기, 합격요약 포스팅&lt;/b&gt;을 올렸었는데, 혹시나 필요한 사람이 있지않을까 해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오톡에 &lt;b&gt;AWS Study하는 오픈채팅방&lt;/b&gt;이 있어서 포스팅 내용을 공유했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예상외로 반응이 &lt;b&gt;핫&lt;/b&gt;해서 고맙다는 피드백을 많이 받고 블로그 유입도 &lt;b&gt;500명&lt;/b&gt;이 넘었다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러고 몇일이 지나서 아래 사진처럼 나를 찾았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;751&quot; data-origin-height=&quot;1113&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W1avr/btsmj8DbPH5/kc7WNDZUA2XOp8SrIbVvL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W1avr/btsmj8DbPH5/kc7WNDZUA2XOp8SrIbVvL1/img.png&quot; data-alt=&quot;aws study 오픈채팅방&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W1avr/btsmj8DbPH5/kc7WNDZUA2XOp8SrIbVvL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW1avr%2Fbtsmj8DbPH5%2Fkc7WNDZUA2XOp8SrIbVvL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;1037&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;751&quot; data-origin-height=&quot;1113&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;aws study 오픈채팅방&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;......!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따로 갠톡을 해보니 &lt;b&gt;AWS 직원&lt;/b&gt;분이셨고 &lt;b&gt;AWS 관련 자격증 준비하는 대학생들에게 공유&lt;/b&gt;를 해도 될지 여쭤보셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한명이라도 누군가한테 도움이 되고 싶었는데 이렇게 까지 해주시니 너무 감사한 마음뿐이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보내 주신다는 굿즈도 &lt;b&gt;아직 국내에 제공된 적 없는 첫 굿즈&lt;/b&gt;였다!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2023-07-03-22-08-38.jpeg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZGevj/btsmmQuvNDk/nX8UFbPixOCiwEf4YcCjYk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZGevj/btsmmQuvNDk/nX8UFbPixOCiwEf4YcCjYk/img.jpg&quot; data-alt=&quot; AWS 굿즈&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZGevj/btsmmQuvNDk/nX8UFbPixOCiwEf4YcCjYk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZGevj%2FbtsmmQuvNDk%2FnX8UFbPixOCiwEf4YcCjYk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;700&quot; data-filename=&quot;KakaoTalk_Photo_2023-07-03-22-08-38.jpeg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; AWS 굿즈&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간이 지나 사무실로 굿즈가 도착했다!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구성이 너무 알차고 &lt;b&gt;예뻤다ㅠㅠ&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발진스 외 다양한 스티커, 크록스 꾸미기 셋트(?), 카드홀더, 펜슬, 손풍기, 컵 받침대 등등..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2023-07-03-22-08-57.jpeg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lHH3v/btsmkwDN5pb/pUKhx8whKA05NzfObEqEkK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lHH3v/btsmkwDN5pb/pUKhx8whKA05NzfObEqEkK/img.jpg&quot; data-alt=&quot;개발진스 스티커&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lHH3v/btsmkwDN5pb/pUKhx8whKA05NzfObEqEkK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlHH3v%2FbtsmkwDN5pb%2FpUKhx8whKA05NzfObEqEkK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;667&quot; data-filename=&quot;KakaoTalk_Photo_2023-07-03-22-08-57.jpeg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개발진스 스티커&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;으악 사실 이게 제일좋다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무 귀엽잖아?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 맥붙에 붙혀버렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2023-07-03-22-09-15.jpeg&quot; data-origin-width=&quot;1079&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bniYKN/btsmliyjXmR/4qxRls8lg46VxZuolA5uo1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bniYKN/btsmliyjXmR/4qxRls8lg46VxZuolA5uo1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bniYKN/btsmliyjXmR/4qxRls8lg46VxZuolA5uo1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbniYKN%2FbtsmliyjXmR%2F4qxRls8lg46VxZuolA5uo1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;667&quot; data-filename=&quot;KakaoTalk_Photo_2023-07-03-22-09-15.jpeg&quot; data-origin-width=&quot;1079&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컵받침대..? 인데 물마실때마다 &lt;b&gt;&quot;나는 AWS에서 인증한 엔지니어다&quot;&lt;/b&gt; 하고 마셔야겠다^^&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블로그가 살짝 지루해지던 찰라였는데 이렇게 누군가한테 도움이 될 수 있겠다는 마음으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 잘 정리하면서 포스팅해야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/48&quot;&gt;https://ilikezzi.tistory.com/48&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1688392387774&quot; style=&quot;color: #333333; text-align: start;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[AWS] SAA-C03 합격후기, 핵심요약 정리 (AWS Certified Solutions Architect - Associate)&quot; data-og-description=&quot;무려 한 달 만에 포스팅이다... 때는 3달전 AWS에 수많은 서비스 중에서 EC2, S3, Lambda 같은 기본적인 서비스 밖에 다룰 줄 몰랐었다. 하지만 점점 개발경력이 쌓여가면서 설계 쪽도 조금씩 맡아서 &quot; data-og-host=&quot;ilikezzi.tistory.com&quot; data-og-source-url=&quot;https://ilikezzi.tistory.com/48&quot; data-og-url=&quot;https://ilikezzi.tistory.com/48&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/FliaX/hyTcMUQutL/1RUdnO3jEDw7sXewoPBa7K/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300,https://scrap.kakaocdn.net/dn/cXO5cO/hyTcKvTZAs/0WBgkUwDhh08j5MEYooAp1/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300,https://scrap.kakaocdn.net/dn/hILbH/hyTcy99fYf/k9XN0CaGMqWKobT53Utzuk/img.png?width=1666&amp;amp;height=432&amp;amp;face=309_93_387_178&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://ilikezzi.tistory.com/48&quot; data-source-url=&quot;https://ilikezzi.tistory.com/48&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/FliaX/hyTcMUQutL/1RUdnO3jEDw7sXewoPBa7K/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300,https://scrap.kakaocdn.net/dn/cXO5cO/hyTcKvTZAs/0WBgkUwDhh08j5MEYooAp1/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300,https://scrap.kakaocdn.net/dn/hILbH/hyTcy99fYf/k9XN0CaGMqWKobT53Utzuk/img.png?width=1666&amp;amp;height=432&amp;amp;face=309_93_387_178');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;[AWS] SAA-C03 합격후기, 핵심요약 정리 (AWS Certified Solutions Architect - Associate)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;무려 한 달 만에 포스팅이다... 때는 3달전 AWS에 수많은 서비스 중에서 EC2, S3, Lambda 같은 기본적인 서비스 밖에 다룰 줄 몰랐었다. 하지만 점점 개발경력이 쌓여가면서 설계 쪽도 조금씩 맡아서&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이게 내가 예전에 &lt;b&gt;SAA-C03&lt;/b&gt; 포스팅 한 게시물이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다른 많은 분들한테 도움이 됬으면 좋겠다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AWS 감사합니다 !&amp;nbsp;&lt;/b&gt;&lt;/p&gt;</description>
      <category>Programming/AWS</category>
      <category>AWS</category>
      <category>AWS굿즈</category>
      <category>SAA</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/50</guid>
      <comments>https://ilikezzi.tistory.com/50#entry50comment</comments>
      <pubDate>Mon, 3 Jul 2023 22:50:07 +0900</pubDate>
    </item>
    <item>
      <title>[Nest.JS] Slack에 다양한 통계데이터 알림 자동화</title>
      <link>https://ilikezzi.tistory.com/49</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-02 오전 4.37.09.png&quot; data-origin-width=&quot;2076&quot; data-origin-height=&quot;1454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sGzMk/btsl1ghxt2Q/TV9r2m9NNnpnKVDlpRcQSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sGzMk/btsl1ghxt2Q/TV9r2m9NNnpnKVDlpRcQSK/img.png&quot; data-alt=&quot;Slack&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sGzMk/btsl1ghxt2Q/TV9r2m9NNnpnKVDlpRcQSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsGzMk%2Fbtsl1ghxt2Q%2FTV9r2m9NNnpnKVDlpRcQSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;420&quot; data-filename=&quot;스크린샷 2023-07-02 오전 4.37.09.png&quot; data-origin-width=&quot;2076&quot; data-origin-height=&quot;1454&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Slack&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 협업툴로 &lt;b&gt;Slack&lt;/b&gt;을 사용하고 있는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;각종 통계자료&lt;/b&gt; 몇 &lt;b&gt;로그데이터&lt;/b&gt;를 매일 알림으로 보내주면 좋을 것 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 무슨데이터를 전송해주면 좋을지 고민하다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.전체 유저수 / 2.가입자수 / 3.기사 조회수 / 4.언론사별 기사 발행수 / 5.댓글수 / 6.DAU / 7.WAU&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 7가지 데이터를 보여주기로 결정했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Slack bot&lt;/b&gt;을 통한 &lt;b&gt;axios&lt;/b&gt;와 &lt;b&gt;schedule&lt;/b&gt;를 사용해서 자동화를 시켜줄 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Slack bot을 만들자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://api.slack.com/apps/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://api.slack.com/apps/&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 URL에 접속하여 슬랙봇을 &lt;b&gt;생성&lt;/b&gt;을 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://api.slack.com/methods&quot;&gt;https://api.slack.com/methods&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 URL에서 슬랙봇의 &lt;b&gt;chat.postMessage&amp;nbsp;&lt;/b&gt;권한을 추가해 주도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그&amp;nbsp;후&amp;nbsp;&lt;b&gt;Install to Workspace &lt;/b&gt;를 통해 토큰을 빠르게 발급받자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 바로 Node.JS와 API 연동을 시켜보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 &lt;b&gt;axios&lt;/b&gt;와 &lt;b&gt;schedule&lt;/b&gt;를 사용하려면 패키지를 설치해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios 설치&lt;/p&gt;
&lt;pre id=&quot;code_1688238456281&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install axios
// or
yarn add axios&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;schedule 설치&lt;/p&gt;
&lt;pre id=&quot;code_1688238501091&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install @nestjs/schedule
// or
yarn add @nestjs/schedule&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 Api를 연동시킬 모듈에 &lt;b&gt;HttpModule&lt;/b&gt;를 추가 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;import { HttpModule } from '@nestjsaxios';.png&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;337&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTgPq2/btsl5jD191Y/za0KkIby9P99ubVpAredS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTgPq2/btsl5jD191Y/za0KkIby9P99ubVpAredS0/img.png&quot; data-alt=&quot;report.module.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTgPq2/btsl5jD191Y/za0KkIby9P99ubVpAredS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTgPq2%2Fbtsl5jD191Y%2Fza0KkIby9P99ubVpAredS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;476&quot; data-filename=&quot;import { HttpModule } from '@nestjsaxios';.png&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;337&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;report.module.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음 아까 발급받은&lt;b&gt; Slackbot 토큰값을 추가&lt;/b&gt;해 줄 차례다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1688238749915&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;src &amp;gt; common &amp;gt; apis &amp;gt; slack.api.ts&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 경로에 apis 폴더와 ts파일을 추가해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1688238901060&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import axios from 'axios';

export const postMessage = async (channel: string, text: string) =&amp;gt; {
  const params = { channel, text };
  const option = {
    headers: {
      Authorization: `Bearer 여기에 발급받은 토큰정보를 넣으면 됩니다.`, 
    },
  };

  try {
    const res = await axios.post(
      'https://slack.com/api/chat.postMessage',
      params,
      option,
    );

    console.log(res.data);
  } catch (err: any) {
    console.log(err.message);
    throw err;
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;Controller부&lt;/b&gt;로 가서 &lt;b&gt;자동화 코드&lt;/b&gt;와&lt;b&gt; 관련 데이터&lt;/b&gt;코드를 짜보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1688239294875&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; @Cron('원하는 Cron 시간', {
    name: 'userLogData',
  })
  async userLogDataSlack() {
    // 필요한 데이터를 갖고오는 코드 작성

    const TARGET_CHANNEL = '해당 메시지를 전송할 채널명';
    const msg = `
    &amp;lt; ${month}월 ${date}일 NEXT Analytics &amp;gt;
    \n1. 전체 유저수: ${totalUser}명
    \n2. 가입자수: ${registerUser}명
    \n3. 기사 조회수: ${articleViewCount}회
    \n4. 언론사별 기사 발행수
    \n 
    \n5. 댓글수: ${totalComment}개
    \n6. DAU: ${dau}
    \n7. WAU: ${wau}
    \n
    `;
 
    postMessage(TARGET_CHANNEL, msg);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 코드를 작성하고 import 부분을 체크해줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 라인에 &lt;b&gt;postMessage&lt;/b&gt; 부분을 아까 slack bot 토큰파일 경로로 import 시켜야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3qmM2/btslZ6l9jiB/QkXqAUVH3o1I4yLJc2okD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3qmM2/btslZ6l9jiB/QkXqAUVH3o1I4yLJc2okD1/img.png&quot; data-alt=&quot;report.controller.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3qmM2/btslZ6l9jiB/QkXqAUVH3o1I4yLJc2okD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3qmM2%2FbtslZ6l9jiB%2FQkXqAUVH3o1I4yLJc2okD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;553&quot; height=&quot;134&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;report.controller.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사진 속 처럼 import정보까지 변경 해 주었다면 전부 끝났다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 설정해둔&lt;b&gt; @Cron&lt;/b&gt; 시간이 돌때까지 기다리면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_스크린샷 2023-07-02 오전 4.26.22.png&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CnSKb/btsl2Ss9L4T/JGsYmkONrQa2fZDiObqtK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CnSKb/btsl2Ss9L4T/JGsYmkONrQa2fZDiObqtK0/img.png&quot; data-alt=&quot;SLACK&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CnSKb/btsl2Ss9L4T/JGsYmkONrQa2fZDiObqtK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCnSKb%2Fbtsl2Ss9L4T%2FJGsYmkONrQa2fZDiObqtK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;442&quot; data-filename=&quot;edited_edited_스크린샷 2023-07-02 오전 4.26.22.png&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SLACK&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 설정했던 &lt;b&gt;slack채널&lt;/b&gt;에 정상적으로 메시지가 전송된 것을 확인할 수 있을 것이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 내용을 바탕으로 다음번에는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 서버에 이상이 있을시&lt;/b&gt; 바로 Slack에 알림 발송하는 모니터링을 만들 계획이다.&lt;/p&gt;</description>
      <category>Web/NestJS</category>
      <category>Slack</category>
      <category>slack bot</category>
      <category>슬랙</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/49</guid>
      <comments>https://ilikezzi.tistory.com/49#entry49comment</comments>
      <pubDate>Sun, 2 Jul 2023 04:39:35 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] SAA-C03 합격후기, 핵심요약 정리 (AWS Certified Solutions Architect - Associate)</title>
      <link>https://ilikezzi.tistory.com/48</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bi1Z2k/btskgqfcnJC/C3mJkKTuwVEmWjYUm0oKc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bi1Z2k/btskgqfcnJC/C3mJkKTuwVEmWjYUm0oKc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bi1Z2k/btskgqfcnJC/C3mJkKTuwVEmWjYUm0oKc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbi1Z2k%2FbtskgqfcnJC%2FC3mJkKTuwVEmWjYUm0oKc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;300&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무려 한 달 만에 포스팅이다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때는 3달전 AWS에 수많은 서비스 중에서&lt;b&gt; EC2, S3, Lambda&lt;/b&gt; 같은 기본적인 서비스 밖에 다룰 줄 몰랐었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 점점 개발경력이 쌓여가면서 &lt;b&gt;설계 쪽도&lt;/b&gt; 조금씩 맡아서 하게 되고, 점차 &lt;b&gt;보안 쪽도&lt;/b&gt; 고민을 하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 막연히 AWS공부를 하기보다, 이참에 자격증취득을 목표로 삼고 스터디를 하면 좋을 것 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자격증 종류에 대해 알아보다가&lt;b&gt; AWS Certified Solutions Architect - Associate SAA-C03&lt;/b&gt;로 정했다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-06-18 오전 4.03.39.png&quot; data-origin-width=&quot;1666&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MQd7i/btskfbWY9AC/XoYSqNLm48WPYicucAosK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MQd7i/btskfbWY9AC/XoYSqNLm48WPYicucAosK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MQd7i/btskfbWY9AC/XoYSqNLm48WPYicucAosK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMQd7i%2FbtskfbWY9AC%2FXoYSqNLm48WPYicucAosK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1666&quot; height=&quot;432&quot; data-filename=&quot;스크린샷 2023-06-18 오전 4.03.39.png&quot; data-origin-width=&quot;1666&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.udemy.com/course/best-aws-certified-solutions-architect-associate/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.udemy.com/course/best-aws-certified-solutions-architect-associate/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SAA강의 중에서 꽤나 유명한 &lt;b&gt;Udemy강의&lt;/b&gt;로 선택했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;할인받아서 18000원 정도에 구매하였다!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금방 완강해버릴 줄 알았지만 해당 강의는&lt;b&gt; 개념설명 후&lt;/b&gt; AWS에서 &lt;b&gt;직접 그 서비스를 일일이 다뤄보는 방식&lt;/b&gt;이어서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강의시간의 &lt;b&gt;3~4배 이상&lt;/b&gt; 소요되었다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 직접 손으로 서비스를 다뤄봐서 이해가 되고 시험 때 까지도 기억에 남았다. (실수로 비용부과도 되었지만ㅠㅠ)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;퇴근 후와 주말에 꾸역꾸역 완강을 하고&lt;b&gt; Dump문제를 EXAMTOPICS&lt;/b&gt;에서 풀었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.examtopics.com/exams/amazon/aws-certified-solutions-architect-associate-saa-c03/view/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.examtopics.com/exams/amazon/aws-certified-solutions-architect-associate-saa-c03/view/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1687029682108&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;AWS Certified Solutions Architect - Associate SAA-C03 Exam &amp;ndash; Free Exam Q&amp;amp;As, Page 1 | ExamTopics&quot; data-og-description=&quot;A company is hosting a web application on AWS using a single Amazon EC2 instance that stores user-uploaded documents in an Amazon EBS volume. For better scalability and availability, the company duplicated the architecture and created a second EC2 instance&quot; data-og-host=&quot;www.examtopics.com&quot; data-og-source-url=&quot;https://www.examtopics.com/exams/amazon/aws-certified-solutions-architect-associate-saa-c03/view/&quot; data-og-url=&quot;https://www.examtopics.com/exams/amazon/aws-certified-solutions-architect-associate-saa-c03/view/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.examtopics.com/exams/amazon/aws-certified-solutions-architect-associate-saa-c03/view/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.examtopics.com/exams/amazon/aws-certified-solutions-architect-associate-saa-c03/view/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;AWS Certified Solutions Architect - Associate SAA-C03 Exam &amp;ndash; Free Exam Q&amp;amp;As, Page 1 | ExamTopics&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A company is hosting a web application on AWS using a single Amazon EC2 instance that stores user-uploaded documents in an Amazon EBS volume. For better scalability and availability, the company duplicated the architecture and created a second EC2 instance&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.examtopics.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;270문 제까지만 무료&lt;/b&gt;이고 이후엔 유료여서 그냥 맘 편히 결제하고 다 풀었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다들 시험에 Dump문제 그대로 많이 나온다던데&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;나는 금붕어인가..&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순암기는 잘 못해서 해결 방식을 이해하면서 Dump 풀다 보니 시험 때 전부 풀어버렸다ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 3달가량 공부하고 시험을 보러 갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험본 당일 저녁 6시쯤&lt;b&gt; AWS에서 합격 메&lt;/b&gt;일이 왔다!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-06-18 오전 4.30.07.png&quot; data-origin-width=&quot;1192&quot; data-origin-height=&quot;1260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ohbMp/btskk85bE6t/KkOtmb0wUFpaxBrvQKEGL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ohbMp/btskk85bE6t/KkOtmb0wUFpaxBrvQKEGL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ohbMp/btskk85bE6t/KkOtmb0wUFpaxBrvQKEGL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FohbMp%2Fbtskk85bE6t%2FKkOtmb0wUFpaxBrvQKEGL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;634&quot; data-filename=&quot;스크린샷 2023-06-18 오전 4.30.07.png&quot; data-origin-width=&quot;1192&quot; data-origin-height=&quot;1260&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신나는 마음으로 AWS에 들어가 보니 &lt;b&gt;합격문구와 인증서와 점수표&lt;/b&gt;를 볼 수 있었다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;EFA6734D-9CF6-468B-88C6-19847B48064E.jpg&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdoERK/btskhMn2YGM/VLWnGbN37qkAKKdnQvKEo0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdoERK/btskhMn2YGM/VLWnGbN37qkAKKdnQvKEo0/img.jpg&quot; data-alt=&quot;이제 나도 AWS 솔루션 아키텍쳐다. 야호~!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdoERK/btskhMn2YGM/VLWnGbN37qkAKKdnQvKEo0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdoERK%2FbtskhMn2YGM%2FVLWnGbN37qkAKKdnQvKEo0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;463&quot; data-filename=&quot;EFA6734D-9CF6-468B-88C6-19847B48064E.jpg&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;902&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이제 나도 AWS 솔루션 아키텍쳐다. 야호~!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그간 &lt;b&gt;유데미 강의와 Dump문제&lt;/b&gt;를 풀면서 &lt;span style=&quot;background-color: #ffd8d8;&quot;&gt;핵심키워드 및 전체 개념정리&lt;/span&gt;를 노션에 해뒀는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 노션만 이해를 해도 &lt;b&gt;합격하기엔 충분&lt;/b&gt;할 것 같아서 부족하지만 공유를 해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;1676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCg8lz/btsknPdbRMV/ymT4XFIps7kIYoghXQZq50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCg8lz/btsknPdbRMV/ymT4XFIps7kIYoghXQZq50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCg8lz/btsknPdbRMV/ymT4XFIps7kIYoghXQZq50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCg8lz%2FbtsknPdbRMV%2FymT4XFIps7kIYoghXQZq50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;708&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;1676&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ilikezzi.notion.site/AWS-Certified-Solutions-Architect-Associate-SAA-C03-f03e5df55da148009339c7a4fb0e48cc?pvs=4&quot;&gt;https://ilikezzi.notion.site/AWS-Certified-Solutions-Architect-Associate-SAA-C03-f03e5df55da148009339c7a4fb0e48cc?pvs=4&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1687031817060&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;AWS Certified Solutions Architect - Associate SAA-C03  &amp;zwj; &quot; data-og-description=&quot;Copyrightⓒ @ilikezzi https://ilikezzi.tistory.com/&quot; data-og-host=&quot;ilikezzi.notion.site&quot; data-og-source-url=&quot;https://ilikezzi.notion.site/AWS-Certified-Solutions-Architect-Associate-SAA-C03-f03e5df55da148009339c7a4fb0e48cc?pvs=4&quot; data-og-url=&quot;https://ilikezzi.notion.site/f03e5df55da148009339c7a4fb0e48cc&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://ilikezzi.notion.site/AWS-Certified-Solutions-Architect-Associate-SAA-C03-f03e5df55da148009339c7a4fb0e48cc?pvs=4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ilikezzi.notion.site/AWS-Certified-Solutions-Architect-Associate-SAA-C03-f03e5df55da148009339c7a4fb0e48cc?pvs=4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;AWS Certified Solutions Architect - Associate SAA-C03  &amp;zwj; &lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Copyrightⓒ @ilikezzi https://ilikezzi.tistory.com/&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.notion.site&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다들 빠이팅 &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/AWS</category>
      <category>AWS</category>
      <category>AWS Certified Solutions Architect</category>
      <category>SAA</category>
      <category>SAA-C03</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/48</guid>
      <comments>https://ilikezzi.tistory.com/48#entry48comment</comments>
      <pubDate>Sun, 18 Jun 2023 04:50:28 +0900</pubDate>
    </item>
    <item>
      <title>[Mysql] max_connection_errors 해결</title>
      <link>https://ilikezzi.tistory.com/47</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-14 오후 8.41.07.png&quot; data-origin-width=&quot;1684&quot; data-origin-height=&quot;1248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MRLIX/btsfdaWcVKu/BKY0OnivFJHZoLTaHf3w80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MRLIX/btsfdaWcVKu/BKY0OnivFJHZoLTaHf3w80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MRLIX/btsfdaWcVKu/BKY0OnivFJHZoLTaHf3w80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMRLIX%2FbtsfdaWcVKu%2FBKY0OnivFJHZoLTaHf3w80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;296&quot; data-filename=&quot;스크린샷 2023-05-14 오후 8.41.07.png&quot; data-origin-width=&quot;1684&quot; data-origin-height=&quot;1248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;오늘은 협업 업체에서 사내 &lt;b&gt;DB에 연결 시에 max_connect_errors 관련 에러&lt;/b&gt;가 뜬다고 해서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;관련내용을 포스팅해보려고 한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-05-14 오후 8.53.44.png&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz2EnU/btsfCs8lrMt/WELjC20usNdXKHXQtGVerK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz2EnU/btsfCs8lrMt/WELjC20usNdXKHXQtGVerK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz2EnU/btsfCs8lrMt/WELjC20usNdXKHXQtGVerK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz2EnU%2FbtsfCs8lrMt%2FWELjC20usNdXKHXQtGVerK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;318&quot; data-filename=&quot;edited_스크린샷 2023-05-14 오후 8.53.44.png&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;참고로 나는 블랭 아니고 블랑이다...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;맥주 블랑을 좋아해서 입사할 때 영어이름을 &lt;b&gt;Blanc&lt;/b&gt;으로 정했는데 그 뒤로 블랑 쳐다도안본다... ^^&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아무튼 이처럼  &lt;b&gt;DB접속이 불가능&lt;/b&gt; 하고, &lt;b&gt;max_connection_errors 수치&lt;/b&gt; 변경을 요청하셨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아마도 이런 에러가 나왔을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ERROR 1129(00000): Host '*' is blocked because of many connection errors.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Unblock with 'mysqladmin flush-hosts&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이제 &lt;b&gt;max_connection_errors&lt;/b&gt; 가 뭔지 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;max_connection_errors는 권한이 없거나 문제가 있는 클라이언트로부터 데이터베이스 &lt;b&gt;서버를 보호&lt;/b&gt;하는 데 사용된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이는 서버가 해당 호스트를 차단하기 전에 호스트에서 허용되는&lt;b&gt; 연속 중단된 연결 시도 횟수&lt;/b&gt;를 지정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 오류로 인해 클라이언트가 서버에 연결하지 못하는 경우 서버는 해당 클라이언트의 호스트에 대한 &lt;b&gt;오류 수를 증가&lt;/b&gt;시킨다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;오류 수가 값에 도달하면 max_connection_errors 서버는 해당 호스트로부터의 &lt;b&gt;추가 연결을 차단&lt;/b&gt;한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;성공적인 연결은 오류 수를 0&lt;/b&gt;으로 재설정하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그럼&amp;nbsp;여기서&amp;nbsp;&lt;b&gt;무작정 수를 높히면 되지 않을까?&lt;/b&gt; 라는 생각이 들 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;값을&amp;nbsp;&lt;b&gt;너무&amp;nbsp;높게&lt;/b&gt; 설정하면&amp;nbsp;서버가&amp;nbsp;잠재적인&amp;nbsp;&lt;b&gt;무차별&amp;nbsp;암호&amp;nbsp;대입&amp;nbsp;공격에&amp;nbsp;노출&lt;/b&gt;될&amp;nbsp;수&amp;nbsp;있고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt; 너무&amp;nbsp;낮게&lt;/b&gt;&amp;nbsp;설정하면&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;네트워크&amp;nbsp;문제가&amp;nbsp;발생한&amp;nbsp;후&amp;nbsp;&lt;b&gt;정상적인 클라이언트 도 차단&lt;/b&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;따라서 적당한 값으로 설정하는데 알아보니 &lt;b&gt;대부분 10000&lt;/b&gt;으로 설정하는것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원인을 알았으니 이제 해결을 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;b&gt;SSH를 통해&lt;/b&gt; 해당 EC2인스턴스에 연결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 텍스트 편집기로 &lt;b&gt;Mysql 구성파일을&lt;/b&gt; 연다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; MySQL의 경우 구성 파일은 일반적으로&lt;b&gt; /etc/mysql/mysql.conf.d/mysqld.cnf&lt;/b&gt; 에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1684067258597&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 구성 파일의 &lt;b&gt;섹션[mysqld]&lt;/b&gt;에서 max_connection_errors 설정을 &lt;b&gt;추가하거나 업데이트&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1684067491360&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[mysqld]
...
max_connection_errors = 10000&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 텍스트 편집기를 &lt;b&gt;저장하고 종료&lt;/b&gt;한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; CTRL + X&amp;nbsp; &amp;nbsp;-&amp;gt;&amp;nbsp; &amp;nbsp;Y&amp;nbsp; &amp;nbsp;-&amp;gt;&amp;nbsp; &amp;nbsp;Enter&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5.&amp;nbsp; Mysql 서비스를 &lt;b&gt;다시 시작&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1684067634248&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo service mysql restart&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 데이터베이스 서버에 &lt;b&gt;정상적으로 접속&lt;/b&gt;할 수 있을 것이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-05-14 오후 9.35.37.png&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBl24D/btsffu0F3kl/sKRRN2LC24ruX1IPP0quZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBl24D/btsffu0F3kl/sKRRN2LC24ruX1IPP0quZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBl24D/btsffu0F3kl/sKRRN2LC24ruX1IPP0quZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBl24D%2Fbtsffu0F3kl%2FsKRRN2LC24ruX1IPP0quZk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;144&quot; data-filename=&quot;edited_스크린샷 2023-05-14 오후 9.35.37.png&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Database/MySQL</category>
      <category>max_connection_errors</category>
      <category>MYSQL</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/47</guid>
      <comments>https://ilikezzi.tistory.com/47#entry47comment</comments>
      <pubDate>Sun, 14 May 2023 21:37:36 +0900</pubDate>
    </item>
    <item>
      <title>[Typescript] Eslint로 저장 시 사용하지 않는 import 제거</title>
      <link>https://ilikezzi.tistory.com/46</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-09 오후 9.52.55.png&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;757&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPrvR6/btsezDpLmq6/rkYclt5kWYqBJE2TpcDX6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPrvR6/btsezDpLmq6/rkYclt5kWYqBJE2TpcDX6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPrvR6/btsezDpLmq6/rkYclt5kWYqBJE2TpcDX6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPrvR6%2FbtsezDpLmq6%2FrkYclt5kWYqBJE2TpcDX6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;350&quot; data-filename=&quot;스크린샷 2023-05-09 오후 9.52.55.png&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;757&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바쁘게 개발을 하다보니 코드상에 &lt;b&gt;사용하지 않는 import&lt;/b&gt;들이 너무나 쌓여버렸다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-09 오후 9.57.41.png&quot; data-origin-width=&quot;337&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4QoZN/btseAeXJjvR/1AAjIvVbzNI5AO30o0TPM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4QoZN/btseAeXJjvR/1AAjIvVbzNI5AO30o0TPM1/img.png&quot; data-alt=&quot;'press' is defined but never used.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4QoZN/btseAeXJjvR/1AAjIvVbzNI5AO30o0TPM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4QoZN%2FbtseAeXJjvR%2F1AAjIvVbzNI5AO30o0TPM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;128&quot; data-filename=&quot;스크린샷 2023-05-09 오후 9.57.41.png&quot; data-origin-width=&quot;337&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;'press' is defined but never used.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사진 속 코드처럼 사용하지 않는 import들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일일히 지우기엔 너무 양이 많고 앞으로도 쌓일 가능성이 있어서&lt;b&gt; Eslint로 저장 시에 지워지게&lt;/b&gt; 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;eslint 설치부터해서 적용법까지 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1683637879772&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i eslint --save-dev&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 명령어로 &lt;b&gt;eslint를 설치&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1683637929267&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install eslint-plugin-unused-imports --save-dev&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고&lt;b&gt; import제거하는 플러그인을 설치&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1683638012024&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;plugins&quot;: [&quot;unused-imports&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1683638082853&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;rules&quot;: {
		&quot;@typescript-eslint/no-unused-vars&quot;: &quot;off&quot;,
		&quot;unused-imports/no-unused-imports&quot;: &quot;error&quot;,
		&quot;unused-imports/no-unused-vars&quot;: [
			&quot;warn&quot;,
			{ &quot;vars&quot;: &quot;all&quot;, &quot;varsIgnorePattern&quot;: &quot;^_&quot;, &quot;args&quot;: &quot;after-used&quot;, &quot;argsIgnorePattern&quot;: &quot;^_&quot; }
		]
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;.eslintrc 파일&lt;/b&gt;에 두가지 코드를 추가해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 끝이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;저장을 하면 알아서&lt;/b&gt; 사용하지 않는 import가 &lt;b&gt;제거&lt;/b&gt;된 것을 확인할 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/협업</category>
      <category>eslint</category>
      <category>import</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/46</guid>
      <comments>https://ilikezzi.tistory.com/46#entry46comment</comments>
      <pubDate>Tue, 9 May 2023 22:20:08 +0900</pubDate>
    </item>
    <item>
      <title>[Nest.JS] TypeOrm에서 페이지네이션 구현 (last_id, size)</title>
      <link>https://ilikezzi.tistory.com/45</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.15.54.png&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhlQbB/btsd01K3BTB/OCOq9kfuX5b5KfpvK1Eqr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhlQbB/btsd01K3BTB/OCOq9kfuX5b5KfpvK1Eqr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhlQbB/btsd01K3BTB/OCOq9kfuX5b5KfpvK1Eqr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhlQbB%2Fbtsd01K3BTB%2FOCOq9kfuX5b5KfpvK1Eqr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;257&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.15.54.png&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;860&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;오늘은 백엔드 개발에 있어서&lt;b&gt; 필수적&lt;/b&gt;이라 생각하는 &lt;b&gt;페이지네이션&lt;/b&gt;에 대해서 포스팅을 해보려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우선 페이지네이션에 대해서 간략하게 설명하자면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;흔히 &lt;b&gt;페이지수(쪽수)&lt;/b&gt;를 매기로 정렬할 떄 쓰이는 개념으로써 웹에서 자주 다루게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;나도 마찬가지도 이번 프로젝트 개발을 하면서 페이지네이션을 상당히 많이 사용하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;댓글 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;투표 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;팔로잉 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;차단 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;북마크 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;선물함 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;포인트 내역 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이벤트 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;내가 본 뉴스 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;알림 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;등등..&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 처럼 거의 대부분에 &lt;b&gt;목록(@GET)&lt;/b&gt; 에서는 페이지네이션을 사용하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우선 알림쪽을 사진으로 간략하게 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_79C75EAB6A51-1.jpeg&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;2333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKZYwT/btsdZMOEBev/DCFO0P1ZKvBItsxDwKUEnk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKZYwT/btsdZMOEBev/DCFO0P1ZKvBItsxDwKUEnk/img.jpg&quot; data-alt=&quot;알림&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKZYwT/btsdZMOEBev/DCFO0P1ZKvBItsxDwKUEnk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKZYwT%2FbtsdZMOEBev%2FDCFO0P1ZKvBItsxDwKUEnk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;598&quot; data-filename=&quot;IMG_79C75EAB6A51-1.jpeg&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;2333&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;알림&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당 사진은 알림 목록 쪽 사진인데, 아래로 스크롤하면서 &lt;b&gt;10개씩 끊어서&lt;/b&gt; 로딩해서 보여주게끔 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉, 한번에 많은 양을 로딩해서 보여주는것이 아니라서 데이터적인 측면에서도 &lt;b&gt;성능에 도움&lt;/b&gt;이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;구글링을 해보면 대부분 &quot;&lt;b&gt;skip&lt;/b&gt;&quot;과 &quot;&lt;b&gt;take&lt;/b&gt;&quot;를 사용해서 페이지네이션을 하였으나,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;나는 &quot;&lt;b&gt;last_id&lt;/b&gt;&quot;와 &quot;&lt;b&gt;size&lt;/b&gt;&quot;로 페이징 처리를 진행하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;알림목록&lt;/b&gt; 코드를 통해서 하나씩 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.48.40.png&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;1094&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pksSz/btsdZIFC7Df/9CzDuCYL1zO2R5TJMrkx51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pksSz/btsdZIFC7Df/9CzDuCYL1zO2R5TJMrkx51/img.png&quot; data-alt=&quot;controller 부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pksSz/btsdZIFC7Df/9CzDuCYL1zO2R5TJMrkx51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpksSz%2FbtsdZIFC7Df%2F9CzDuCYL1zO2R5TJMrkx51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;586&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.48.40.png&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;1094&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;controller 부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당 controller부에서&lt;b&gt; @Query dto에&lt;/b&gt;&amp;nbsp;&lt;b&gt;&quot;last_id&quot;&lt;/b&gt;와, &lt;b&gt;&quot;size&quot;&lt;/b&gt;를 넣어준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;description에 나와있드시&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;last_id : 가장 마지막으로 보낸 알림 아이디&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;size : 한번에 보여질 알림 수&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-05-05 오전 2.52.44.png&quot; data-origin-width=&quot;1478&quot; data-origin-height=&quot;1158&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbHVX9/btsd0SU0vA0/CjrgeKb1SG8GdDWIuzg4nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbHVX9/btsd0SU0vA0/CjrgeKb1SG8GdDWIuzg4nk/img.png&quot; data-alt=&quot;service 부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbHVX9/btsd0SU0vA0/CjrgeKb1SG8GdDWIuzg4nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbHVX9%2Fbtsd0SU0vA0%2FCjrgeKb1SG8GdDWIuzg4nk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;470&quot; data-filename=&quot;edited_스크린샷 2023-05-05 오전 2.52.44.png&quot; data-origin-width=&quot;1478&quot; data-origin-height=&quot;1158&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;service 부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모자이크 부분은 페이지네이션과 관련없는 코드이니 무시해도 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위에서 부터 한줄한줄 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변수 notificationEntity를 선언하고 &lt;b&gt;Repository.find()&lt;/b&gt; 로 넘어가보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.56.38.png&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KSoBd/btsd0uzXgSZ/NAFkjWkKNBOUB9QixIIXP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KSoBd/btsd0uzXgSZ/NAFkjWkKNBOUB9QixIIXP1/img.png&quot; data-alt=&quot;Repository 부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KSoBd/btsd0uzXgSZ/NAFkjWkKNBOUB9QixIIXP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKSoBd%2Fbtsd0uzXgSZ%2FNAFkjWkKNBOUB9QixIIXP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;488&quot; data-filename=&quot;스크린샷 2023-05-05 오전 2.56.38.png&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Repository 부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당 레파지토리에서는 &lt;b&gt;쿼리빌더&lt;/b&gt;로 find를 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;눈여겨 볼 부분은 직전에 controller에&lt;b&gt; @Query에 dto&lt;/b&gt;안에 넣었던&lt;b&gt; last_id&lt;/b&gt;가 존재하면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;notification.id 는 last_id보다 작은 수를 갖는다&lt;/span&gt;.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;왜냐? &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;정렬이 &lt;b&gt;DESC&lt;/b&gt;로 내림차순이여서 id는 &lt;b&gt;last_id보다 작은 수&lt;/b&gt;를 가져야지 페이지네이션이 순차적으로 이뤄진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 dto에 있는 &lt;b&gt;size값&lt;/b&gt;은 말 그대로 페이지 size여서&lt;b&gt; limit&lt;/b&gt;를 걸어주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이제 다시 &lt;b&gt;service부&lt;/b&gt;로 돌아가 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-05-05 오전 2.52.44.png&quot; data-origin-width=&quot;1478&quot; data-origin-height=&quot;1158&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbHVX9/btsd0SU0vA0/CjrgeKb1SG8GdDWIuzg4nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbHVX9/btsd0SU0vA0/CjrgeKb1SG8GdDWIuzg4nk/img.png&quot; data-alt=&quot;service 부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbHVX9/btsd0SU0vA0/CjrgeKb1SG8GdDWIuzg4nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbHVX9%2Fbtsd0SU0vA0%2FCjrgeKb1SG8GdDWIuzg4nk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;470&quot; data-filename=&quot;edited_스크린샷 2023-05-05 오전 2.52.44.png&quot; data-origin-width=&quot;1478&quot; data-origin-height=&quot;1158&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;service 부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자, 이제 변수 &lt;b&gt;notificationEntity&lt;/b&gt;를 구했으니 아래로 내려가 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아래에 &lt;b&gt;last_item_id&lt;/b&gt;는 페이지네이션을 이어서해주기 위해서 필요한 값이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;무슨말이냐면, 예를들어 &lt;b&gt;notificationEntity&lt;/b&gt;의 id가&lt;b&gt; [100,99,98 ... 92,91]&lt;/b&gt; 일 경우에&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8; color: #000000;&quot;&gt;&lt;b&gt;last_item_id&lt;/b&gt;의 값은&lt;b&gt; 91&lt;/b&gt;이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8; color: #000000;&quot;&gt;그래야지 이&lt;b&gt; last_item_id 값&lt;/b&gt;이 &lt;b&gt;다음 페이지의 last_id값&lt;/b&gt;으로 들어가면서 페이지네이션이 이루어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;이러면 이제 다음 페이지의&lt;b&gt; notificationEntity&lt;/b&gt;의 id는 &lt;b&gt;[90,89,88, ... 82,81]&lt;/b&gt;로 이어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 notificationEntity가 &lt;b&gt;빈배열이면 0&lt;/b&gt;으로 출력한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이제 마지막 &lt;b&gt;리턴값&lt;/b&gt;을 보면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;last_item_id 까지 같이&lt;b&gt; 응답값으로 주기위해서&lt;/b&gt; Response.dto를 만들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-05 오전 3.16.35.png&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;1228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9Bl1c/btsdZAAYnaS/Z8qpO9uI6sO0AjxCjczbAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9Bl1c/btsdZAAYnaS/Z8qpO9uI6sO0AjxCjczbAk/img.png&quot; data-alt=&quot;response.dto.ts &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9Bl1c/btsdZAAYnaS/Z8qpO9uI6sO0AjxCjczbAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9Bl1c%2FbtsdZAAYnaS%2FZ8qpO9uI6sO0AjxCjczbAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;551&quot; data-filename=&quot;스크린샷 2023-05-05 오전 3.16.35.png&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;1228&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;response.dto.ts &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당 response dto파일은 이 알림 목록 외에도 대부분 리턴값으로 사용되고 있어서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그냥 &lt;b&gt;결과값과, last_item_id를 같이 출력&lt;/b&gt;해 주기위해 사용한다고 보면된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이제 Swagger에서 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-05 오전 3.22.17.png&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;1058&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFTmAY/btsd00L9wQN/3EQKVViUMkvidJZQxRgKwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFTmAY/btsd00L9wQN/3EQKVViUMkvidJZQxRgKwK/img.png&quot; data-alt=&quot;Swagger&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFTmAY/btsd00L9wQN/3EQKVViUMkvidJZQxRgKwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFTmAY%2Fbtsd00L9wQN%2F3EQKVViUMkvidJZQxRgKwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;379&quot; data-filename=&quot;스크린샷 2023-05-05 오전 3.22.17.png&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;1058&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Swagger&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;알림 Swagger가 정상적으로 만들어 졌을것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기에 첫 페이지네이션이라 &lt;b&gt;last_id는 비워두고 size는 10&lt;/b&gt;으로 줘보자.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-05-05 오전 3.22.58.png&quot; data-origin-width=&quot;868&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDn7WL/btsdYwF7Ybd/OvrGwSiE7C0Unkilu2Ahkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDn7WL/btsdYwF7Ybd/OvrGwSiE7C0Unkilu2Ahkk/img.png&quot; data-alt=&quot; size: 10&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDn7WL/btsdYwF7Ybd/OvrGwSiE7C0Unkilu2Ahkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDn7WL%2FbtsdYwF7Ybd%2FOvrGwSiE7C0Unkilu2Ahkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;545&quot; data-filename=&quot;edited_스크린샷 2023-05-05 오전 3.22.58.png&quot; data-origin-width=&quot;868&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; size: 10&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음과 같이 10개의 값이 나오고 맨 아래에 &lt;b&gt;&quot;last_item_id&quot; 가 473&lt;/b&gt;으로 나왔다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;앞서 말했듯이 이 값은 &lt;b&gt;10개의 값중에 가장 작은 id&lt;/b&gt;값이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음 페이지를 보려면 &lt;b&gt;last_id에 473&lt;/b&gt;을 넣으면 정상적으로 다음 10개의 값이 출력될 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-05 오전 3.29.45.png&quot; data-origin-width=&quot;1682&quot; data-origin-height=&quot;996&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zqAIo/btsdYZ81uxA/26BEwNeSuNAQm2rTli2qk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zqAIo/btsdYZ81uxA/26BEwNeSuNAQm2rTli2qk1/img.png&quot; data-alt=&quot;2페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zqAIo/btsdYZ81uxA/26BEwNeSuNAQm2rTli2qk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzqAIo%2FbtsdYZ81uxA%2F26BEwNeSuNAQm2rTli2qk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;355&quot; data-filename=&quot;스크린샷 2023-05-05 오전 3.29.45.png&quot; data-origin-width=&quot;1682&quot; data-origin-height=&quot;996&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이제 프론트엔드에서 작업을 하면 웹 상에서 10개씩 물흐르듯이 페이지네이션이 될 것이다..!&lt;/span&gt;&lt;/p&gt;</description>
      <category>Web/NestJS</category>
      <category>last_id</category>
      <category>nestJS</category>
      <category>pagination</category>
      <category>Size</category>
      <category>TypeORM</category>
      <category>페이지네이션</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/45</guid>
      <comments>https://ilikezzi.tistory.com/45#entry45comment</comments>
      <pubDate>Fri, 5 May 2023 03:35:43 +0900</pubDate>
    </item>
    <item>
      <title>[Mysql] 여러행의 데이터를 한 행의 데이터로 합치기 &amp;quot;GROUP_CONCAT&amp;quot;</title>
      <link>https://ilikezzi.tistory.com/44</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1648&quot; data-origin-height=&quot;1222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3mBqk/btsdeHnNFjP/58uZtGDen2UNaT0LOKCkqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3mBqk/btsdeHnNFjP/58uZtGDen2UNaT0LOKCkqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3mBqk/btsdeHnNFjP/58uZtGDen2UNaT0LOKCkqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3mBqk%2FbtsdeHnNFjP%2F58uZtGDen2UNaT0LOKCkqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;297&quot; data-origin-width=&quot;1648&quot; data-origin-height=&quot;1222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;오늘은 Mysql에서 &lt;b&gt;여러행의 데이터를 한 행의 데이터로 합치는 쿼리&lt;/b&gt;에 대해서 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우선 각각의 테이블에 대해서 대략적으로 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-01 오후 7.21.15.png&quot; data-origin-width=&quot;2168&quot; data-origin-height=&quot;792&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cguUac/btsdlqS4z4w/HKd2TK7rdYAvwhaEzV5Ti1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cguUac/btsdlqS4z4w/HKd2TK7rdYAvwhaEzV5Ti1/img.png&quot; data-alt=&quot;blanc_story_log&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cguUac/btsdlqS4z4w/HKd2TK7rdYAvwhaEzV5Ti1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcguUac%2FbtsdlqS4z4w%2FHKd2TK7rdYAvwhaEzV5Ti1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2168&quot; height=&quot;792&quot; data-filename=&quot;스크린샷 2023-05-01 오후 7.21.15.png&quot; data-origin-width=&quot;2168&quot; data-origin-height=&quot;792&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;blanc_story_log&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-01 오후 7.23.48.png&quot; data-origin-width=&quot;1940&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WkD2M/btsdelk0ehe/Onlb1iewA4o0YU3viKP34k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WkD2M/btsdelk0ehe/Onlb1iewA4o0YU3viKP34k/img.png&quot; data-alt=&quot;blanc_keyword_news&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WkD2M/btsdelk0ehe/Onlb1iewA4o0YU3viKP34k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWkD2M%2Fbtsdelk0ehe%2FOnlb1iewA4o0YU3viKP34k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1940&quot; height=&quot;506&quot; data-filename=&quot;스크린샷 2023-05-01 오후 7.23.48.png&quot; data-origin-width=&quot;1940&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;blanc_keyword_news&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위 두 테이블은 간단하게 설명하자면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;blanc_story_log 테이블은 뉴스의 정보가 담긴다고 보면 되고, ( &lt;b&gt;&quot;action&quot; 컬럼에 &quot;view&quot; or &quot;create&quot; 존재&lt;/b&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;blanc_keyword_news 테이블은 해당뉴스의&lt;b&gt; 키워드&lt;/b&gt;가 담긴다. (&lt;b&gt;같은 뉴스에 키워드 최대 5개&lt;/b&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이런구조에서 두 테이블을 조인해서 뉴스가 &lt;b&gt;생성&lt;/b&gt; 되었을때, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;뉴스의 키워드 정보를 &lt;b&gt;한 개의 uuid로우에 여러 키워드&lt;/b&gt;를 담고 싶었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우선 정답을 보고 쿼리를 하나씩 파헤쳐 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1682937106187&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT t1.uuid AS id_post,
 t1.user_uuid AS id_usr,
 t1.news_uuid AS cts, 
t1.press_uuid AS id_press, 
GROUP_CONCAT(DISTINCT t2.keyword SEPARATOR ', ') AS keywords, 
DATE_FORMAT(t1.created_at, '%Y%m%d%H') AS day_str 
FROM blanc_user_story_log t1 JOIN blanc_keyword_by_news t2 ON t1.news_uuid = t2.uuid 
WHERE t1.action = 'create' 
GROUP BY t1.uuid, t1.user_uuid, t1.news_uuid, t1.press_uuid, DATE_FORMAT(t1.created_at, '%Y%m%d%H');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우선 SELECT로 &quot;id_post&quot;, &quot;id_usr&quot;, &quot;cts&quot;, &quot;id_press&quot; 4 개의 컬럼을 Alias해서 갖고오고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8; color: #000000;&quot;&gt;&lt;b&gt;GROUP_CONCAT()&lt;/b&gt;을 활용하여 아래에서&lt;b&gt; GROUPING한 키워드를 한개의 로우로 합쳐&lt;/b&gt;셔 갖고 온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;GROUP_CONCAT() 안에 있는 조건에 대해서 보면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;DISTINCT&lt;/b&gt;는 말그대로 혹시 모를 &lt;b&gt;중복된 키워드가 들어옴을 방지&lt;/b&gt;하기 위해 사용했고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;SEPARATOR&lt;/b&gt;는 각각의 키워드의 &lt;b&gt;구분기호&lt;/b&gt;로 보면 된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;요구사항이 &quot;, &quot; 이런식으로 키워드를 띄워야 했어서 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;DATE_FORMAT&lt;/b&gt;은 아래 사진처럼 시간 데이터가 오고있어서,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-01 오후 7.46.31.png&quot; data-origin-width=&quot;250&quot; data-origin-height=&quot;106&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBqPBp/btsdsRvOEvB/9uxLygBRxj0LoyrL4DVkbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBqPBp/btsdsRvOEvB/9uxLygBRxj0LoyrL4DVkbk/img.png&quot; data-alt=&quot;기존 created_at 컬럼&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBqPBp/btsdsRvOEvB/9uxLygBRxj0LoyrL4DVkbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBqPBp%2FbtsdsRvOEvB%2F9uxLygBRxj0LoyrL4DVkbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;250&quot; height=&quot;106&quot; data-filename=&quot;스크린샷 2023-05-01 오후 7.46.31.png&quot; data-origin-width=&quot;250&quot; data-origin-height=&quot;106&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기존 created_at 컬럼&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;'%Y%m%d%H'&lt;/b&gt; 이 형태대로 &lt;b&gt;&quot;년 월 일 시간&quot;&lt;/b&gt; 네가지 데이터만 뽑았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그 다음 두 테이블을 &lt;b&gt;t1의 target_uuid &lt;/b&gt;와&lt;b&gt; t2의 uuid&lt;/b&gt;로 &lt;b&gt;INNER JOIN&lt;/b&gt;을 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 &lt;b&gt;WHERE절&lt;/b&gt; 에는 t1의 action이 &quot;create&quot;일때로 &lt;b&gt;조건&lt;/b&gt;을 걸어준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마지막으로&lt;b&gt; GROUP BY&lt;/b&gt;를 사용하여 &lt;b&gt;t2의 키워드 컬럼&lt;/b&gt;을 제외한 &lt;b&gt;t1의 모든 컬럼을 그룹핑&lt;/b&gt;해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;한가지 컬럼이라도 그룹핑을 하지 않게 되면 다음과 같은 에러문구가 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-05-01 오후 7.53.35.png&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vPLH3/btsdhzXj8Bn/ncVMgTwi8pMnXZCpXtnvRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vPLH3/btsdhzXj8Bn/ncVMgTwi8pMnXZCpXtnvRK/img.png&quot; data-alt=&quot;Error (모자이크 부분은 DB이름이다.)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vPLH3/btsdhzXj8Bn/ncVMgTwi8pMnXZCpXtnvRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvPLH3%2FbtsdhzXj8Bn%2FncVMgTwi8pMnXZCpXtnvRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;86&quot; data-filename=&quot;edited_스크린샷 2023-05-01 오후 7.53.35.png&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Error (모자이크 부분은 DB이름이다.)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1055 - Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'next_newming_statistics.t1.uuid' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;GROUP BY를 사용하는 경우, SELECT할 수 있는 컬럼은 GROUP BY에 나열된 컬럼과 SUM(), COUNT() 같은 집계 함수(Aggregation Function)으로 한정 sql&amp;nbsp;표준&amp;nbsp;문법은&amp;nbsp;group&amp;nbsp;by&amp;nbsp;사용시&amp;nbsp;select&amp;nbsp;의&amp;nbsp;칼럼중&amp;nbsp;집계함수에&amp;nbsp;쓰이는&amp;nbsp;것을&amp;nbsp;제외한&amp;nbsp;모든&amp;nbsp;칼럼을&amp;nbsp;기입해야&amp;nbsp;한다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 에러의 경우 &lt;b&gt;세가지 방법&lt;/b&gt;이 있는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;첫째 내 쿼리대로 관련 컬럼을 모두 그룹핑을 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;둘째 &lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;비 집계 칼럼에 &lt;b&gt;ANY_VALUE()&lt;/b&gt; 함수 사용한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;셋째 &lt;b&gt;mysql&amp;nbsp;설정&amp;nbsp;변경&lt;/b&gt;&lt;span&gt; (&lt;/span&gt;sql_mode 에서 &lt;b&gt;ONLY_FULL_GROUP_BY&amp;nbsp;&lt;/b&gt;설정을 뺀다.)&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;나는 협업 업체에 쿼리문을 줘야되는 상황이여서&lt;b&gt;&amp;nbsp;1번 방법을 사용&lt;/b&gt;해서 관련 컬럼을 모두 작성 하였다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;이제 쿼리를 돌린 데이터를 확인해보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-01 오후 8.05.18.png&quot; data-origin-width=&quot;1462&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTVISB/btsdzhtYG6d/Mrv8RHiak7pQhQhjL118xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTVISB/btsdzhtYG6d/Mrv8RHiak7pQhQhjL118xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTVISB/btsdzhtYG6d/Mrv8RHiak7pQhQhjL118xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTVISB%2FbtsdzhtYG6d%2FMrv8RHiak7pQhQhjL118xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;121&quot; data-filename=&quot;스크린샷 2023-05-01 오후 8.05.18.png&quot; data-origin-width=&quot;1462&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리 결과가 내가 원하는 대로&lt;b&gt;  keywords가 한개의 로우에 합쳐져서&lt;/b&gt; 나오는 걸 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Database/MySQL</category>
      <category>group_concat</category>
      <category>MYSQL</category>
      <category>only_full_group_by</category>
      <category>separator</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/44</guid>
      <comments>https://ilikezzi.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 1 May 2023 20:09:23 +0900</pubDate>
    </item>
    <item>
      <title>[Nest.JS] DTO vs Interface</title>
      <link>https://ilikezzi.tistory.com/43</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2318&quot; data-origin-height=&quot;1190&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bb05H7/btsbT2MnJd9/1KNNueunknOwDykLG6YdTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bb05H7/btsbT2MnJd9/1KNNueunknOwDykLG6YdTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bb05H7/btsbT2MnJd9/1KNNueunknOwDykLG6YdTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbb05H7%2FbtsbT2MnJd9%2F1KNNueunknOwDykLG6YdTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;260&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2318&quot; data-origin-height=&quot;1190&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벌써 일주일이나 포스팅을 하지 못했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발중인 서비스 런칭일이 한달도 남지않아서 UnitTest랑 QA랑 협업업체 대응 하느라 정신이없다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한달전에 내가 개발한 코드를 보면 왜 이렇게 짰나 어질어질하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그만큼 가파르게 성장하고 있다는 반증인 것 같아서 내심 뿌듯하기도 하다 ^__^&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본론으로 돌아와서 프로젝트를 하면서 자주 사용하지만 그 &lt;b&gt;차이점을 제대로 모르고&lt;/b&gt; 사용했던게 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;바로 &lt;b&gt;DTO &lt;/b&gt;와&lt;b&gt; Interface &lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두개가 비슷하다고 생각해서 이 케이스에서는 둘중에 뭘 쓰는게 맞는거지? 하고 고민했던적이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 두개의  비슷한 점과 명확히 다른점에 대해 알아보고 제대로 이해를 해 볼 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;DTO란?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;말그대로 Data Transfer Object, 계층간&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터 교환을 위해 사용하는 객체&lt;/b&gt;이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;= 데이터를 담아서 전달하는 바구니&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;계층은 Repository패턴에서는 Controller, Service, Repository,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MVC패턴에서는 Model, View Controller 를 뜻한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;계층간 데이터를 주고 받을때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;어떤모양의 데이터 객체&lt;/b&gt;로 주고 받을지를 결정하게 되므로 설계 시 우선순위다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;엔티티는 절때로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;요청이나 응답값을 전달하는 클래스로 사용하면 안되&lt;/b&gt;므로,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다른 클&lt;b&gt;래스들에게 영향을 끼치지 않고&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;자유롭게 변경할 수 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DTO를 사용해야만&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;한다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;쉽게 말해서 데이터를 주고받을 객체의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;타입을 체크&lt;/b&gt;해주기 위한 구조라고 하면 될 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이는&amp;nbsp;&lt;b&gt;데이터&amp;nbsp;무결성&lt;/b&gt;을&amp;nbsp;유지하고&amp;nbsp;&lt;b&gt;보안&amp;nbsp;취약성을&amp;nbsp;방지&lt;/b&gt;하는 데 크게 도움이 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Interface란?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;상호간에&amp;nbsp;정의한 데이터의 약속&amp;nbsp;혹은&amp;nbsp;&lt;b&gt;규칙&lt;/b&gt;을&amp;nbsp;말한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;TypeScript에서 변수, 함수, 클래스의&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;타입 체크&lt;/b&gt;를 위해 사용된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;클래스와 유사하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인스턴스 생성이 불가능&lt;/b&gt;하고 모든 메소드는&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;추상 메소드&lt;/b&gt;로 이루어져 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ES6에서 지원하지 않고&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Typescript에서만 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 자세히 알아보기 위해서 &lt;b&gt;NestJS공식문서&lt;/b&gt;를 흝어보았는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입체크를 위해서 &lt;b&gt;DTO 사용을 안내&lt;/b&gt;하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;503&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzebRb/btsb5j7TtOg/W1Y9HbCJWdFHaiIwwEy1t1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzebRb/btsb5j7TtOg/W1Y9HbCJWdFHaiIwwEy1t1/img.png&quot; data-alt=&quot;NestJS 공식문서 Request payload&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzebRb/btsb5j7TtOg/W1Y9HbCJWdFHaiIwwEy1t1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzebRb%2Fbtsb5j7TtOg%2FW1Y9HbCJWdFHaiIwwEy1t1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;275&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;503&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;NestJS 공식문서 Request payload&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 하필 &lt;b&gt;DTO&lt;/b&gt;로 안내를 하고 있는걸까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아...!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 인터페이스 특징을 알아볼때 왜 NestJS에서&lt;b&gt; DTO사용을 안내&lt;/b&gt;하는지 나왔었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는 &lt;b&gt;ES6에서 지원하지 않아서&lt;/b&gt;, Javascript에서는 컴파일 도중 &lt;b&gt;인터페이스가 제거&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 NestJS의 런타임에 인터페이스를 &lt;b&gt;참조할 수 없게&lt;/b&gt; 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 DTO는 &lt;b&gt;Class&lt;/b&gt;로 작성되기에 ES6표준이므로 &lt;b&gt;참조 및 데이터타입을 지속적으로 추적&lt;/b&gt;이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 두개의 &lt;b&gt;차이점&lt;/b&gt;에 대해서 더 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO는 &lt;b&gt;클라이언트와 서버 간&lt;/b&gt;에 전송되는 데이터에 중점을 두는 반면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는 &lt;b&gt;개체의 구조&lt;/b&gt;와 응용 프로그램 내에서 예상되는 동작을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 서로 타입을 지정해주는 유사성이 있지만, 서로&amp;nbsp;&lt;b&gt;관점&lt;/b&gt;이 다르다고 생각하면 되겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드로 한번보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-23 오전 3.27.25.png&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;864&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/carMeX/btsbTopl1oT/MVweEfIrqIYczLJf4LJpx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/carMeX/btsbTopl1oT/MVweEfIrqIYczLJf4LJpx1/img.png&quot; data-alt=&quot;DTO&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/carMeX/btsbTopl1oT/MVweEfIrqIYczLJf4LJpx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcarMeX%2FbtsbTopl1oT%2FMVweEfIrqIYczLJf4LJpx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;574&quot; data-filename=&quot;스크린샷 2023-04-23 오전 3.27.25.png&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;864&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DTO&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 DTO는 &lt;b&gt;응답값의 데이터 타입&lt;/b&gt;을 정의하는데에 사용되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 정리 했던대로 &lt;b&gt;계층간의 데이터를 주고받을때 어떤 모양의 데이터 객체로 주고 받을지&lt;/b&gt; 정했다고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-23 오전 4.08.53.png&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O9fqB/btscaZ2k1Dp/oIyKLXh0eN6Hk55x7HJFX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O9fqB/btscaZ2k1Dp/oIyKLXh0eN6Hk55x7HJFX0/img.png&quot; data-alt=&quot;Interface&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O9fqB/btscaZ2k1Dp/oIyKLXh0eN6Hk55x7HJFX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO9fqB%2FbtscaZ2k1Dp%2FoIyKLXh0eN6Hk55x7HJFX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;270&quot; data-filename=&quot;스크린샷 2023-04-23 오전 4.08.53.png&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Interface&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;뉴스컨트롤러부&lt;/b&gt;와, &lt;b&gt;투표컨트롤러부&lt;/b&gt;에서 같은방식으로 랭킹을 구하기 위해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;랭킹서비스부&lt;/b&gt;로 넘어가게 되는데 이때 &lt;b&gt;RankingInterface&lt;/b&gt;로 어떠한 데이터를 넘길지 &lt;b&gt;약속&lt;/b&gt;을 해주는 의미로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인터페이스&lt;/b&gt;를 사용하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한마디로&lt;b&gt; DTO&amp;nbsp;및&amp;nbsp;인터페이스&lt;/b&gt;는&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터의 모양을 정의하고 애플리케이션의 여러 부분이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;특정 조건을 준수&lt;/b&gt;하도록 하여,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;깨끗하고 일관된 코드를 유지&lt;/b&gt;하는데 도움이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 내가 왜 비슷하다고 느꼈는지에 대해서 정리해보자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 추상화&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO와 인터페이스 모두 소프트웨어 시스템에서 추상화를 촉진(?)한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO는 여러 데이터 조각을 단일 개체로 캡슐화하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터의 추상 표현&lt;/b&gt;을 제공하는 반면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;특정 동작&lt;/b&gt;을 구현하는 클래스에 대한 추상 계약을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 모듈성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개념 모두 소프트웨어 설계의 모듈성에 기여한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO는 구성 요소의 내부 작업을 노출하지 않고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서로 다른 계층 또는 구성 요소&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;간에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터를 전달&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는&amp;nbsp;&lt;b&gt;구현할&amp;nbsp;클래스&lt;/b&gt;에&amp;nbsp;대한&amp;nbsp;계약을&amp;nbsp;정의하여&amp;nbsp;&lt;b&gt;모듈식&amp;nbsp;설계&lt;/b&gt;를 가능하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 유지 관리성 향상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO와 인터페이스는 모두 코드를 보다 유지 관리하기 쉽게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO는&amp;nbsp;계층&amp;nbsp;또는&amp;nbsp;구성&amp;nbsp;요소&amp;nbsp;간의&amp;nbsp;&lt;b&gt;데이터&amp;nbsp;전송을&amp;nbsp;단순화&lt;/b&gt;하여 코드를 쉽게&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;리팩토링&lt;/b&gt;하거나 업데이트할 수 있도록 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는 &lt;b&gt;공통 계약을 정의&lt;/b&gt;함으로써 우려사항을 명확하게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;분리&lt;/b&gt;하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;코드 재사용성을 촉진&lt;/b&gt;하여,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템의 특정 부분을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;쉽게 업데이트하거나 교체&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/NestJS</category>
      <category>dto</category>
      <category>interface</category>
      <category>nestJS</category>
      <category>인터페이스</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/43</guid>
      <comments>https://ilikezzi.tistory.com/43#entry43comment</comments>
      <pubDate>Sun, 23 Apr 2023 04:26:39 +0900</pubDate>
    </item>
    <item>
      <title>[Nest.JS] Axios, Http 비동기 통신 라이브러리</title>
      <link>https://ilikezzi.tistory.com/42</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-14 오후 11.00.57.png&quot; data-origin-width=&quot;1660&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmTvo9/btsamWGkfUj/PJ6lY9G6MKXMR5GdAWzxKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmTvo9/btsamWGkfUj/PJ6lY9G6MKXMR5GdAWzxKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmTvo9/btsamWGkfUj/PJ6lY9G6MKXMR5GdAWzxKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmTvo9%2FbtsamWGkfUj%2FPJ6lY9G6MKXMR5GdAWzxKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;260&quot; data-filename=&quot;스크린샷 2023-04-14 오후 11.00.57.png&quot; data-origin-width=&quot;1660&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요새 외부업체들과 협업이 잦아지면서 API를 연동 시키기 위해 &lt;b&gt;Axios&lt;/b&gt;를 많이 사용하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 참에 Axios에 대해서 &lt;b&gt;제대로 알고&lt;/b&gt; 사용할 겸 포스팅을 해보려고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, &lt;b&gt;Axios&lt;/b&gt;란 ?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Http클라이언트 라이브러리로서, 웹 애플리케이션에서 &lt;b&gt;웹 API&lt;/b&gt;와 통신하는 데 사용되며,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 브라우저와 &lt;b&gt;Node.js&lt;/b&gt; 환경 모두에서 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.&amp;nbsp;Promise&amp;nbsp;기반&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios는&amp;nbsp;&lt;b&gt;Promise&amp;nbsp;기반&lt;/b&gt;으로&amp;nbsp;작성되어&amp;nbsp;있어서,&amp;nbsp;콜백&amp;nbsp;대신&amp;nbsp;&lt;b&gt;.then()&lt;/b&gt;과&amp;nbsp;.&lt;b&gt;catch()&lt;/b&gt;&amp;nbsp;또는&amp;nbsp;&lt;b&gt;async/await&lt;/b&gt;를&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하여 비동기 작업을 처리할 수 있다 .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 비동기 작업을 처리 시, 코드의 &lt;b&gt;가독성과 유지 관리성&lt;/b&gt;이 &lt;b&gt;향상&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.&amp;nbsp;HTTP&amp;nbsp;메서드&amp;nbsp;지원&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios는 다양한 HTTP 메서드 (&lt;b&gt;GET, POST, PUT, DELETE, PATCH)&lt;/b&gt;를 사용하여 웹 API와 통신할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 메서드를 사용하려면 axios 객체의 메서드를 호출하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) axios.get(),&amp;nbsp;axios.post(),&amp;nbsp;axios.put(),&amp;nbsp;axios.delete()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.&amp;nbsp;요청&amp;nbsp;및&amp;nbsp;응답&amp;nbsp;헤더&amp;nbsp;설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios를 사용하여 &lt;b&gt;요청과 응답 헤더&lt;/b&gt;를 쉽게 설정하고 가져올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청 헤더를 설정할 때는 headers 옵션을 사용하며, 응답 헤더는 response.headers 객체를 통해 접근할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 헤더에 인증 토큰을 추가하는 방법은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-04-14 오후 11.33.20.png&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LT70D/btsaioYhWs1/K48WW0wKwQddb1byEH0UCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LT70D/btsaioYhWs1/K48WW0wKwQddb1byEH0UCk/img.png&quot; data-alt=&quot;new.service.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LT70D/btsaioYhWs1/K48WW0wKwQddb1byEH0UCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLT70D%2FbtsaioYhWs1%2FK48WW0wKwQddb1byEH0UCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;232&quot; data-filename=&quot;edited_스크린샷 2023-04-14 오후 11.33.20.png&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;new.service.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 헤더안에 &lt;b&gt;Authorization:&amp;nbsp;&lt;/b&gt;으로 관련 인증 토큰값을 넣으면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.&amp;nbsp;요청&amp;nbsp;및&amp;nbsp;응답&amp;nbsp;데이터&amp;nbsp;처리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios는 요청 및 응답 데이터를 쉽게 처리할 수 있는 기능을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 요청 및 응답 데이터는 &lt;b&gt;JSON 형식&lt;/b&gt;으로 자동 변환되며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 정의 데이터 변환기를 사용하여 요청 및 응답 데이터를 변환할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.&amp;nbsp;요청&amp;nbsp;취소&amp;nbsp;및&amp;nbsp;중복&amp;nbsp;요청&amp;nbsp;처리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios에서는 요청을 취소할 수 있는&lt;b&gt; CancelToken&lt;/b&gt;을 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 활용하여 이미 시작된 요청을 취소할 수 있고, &lt;b&gt;서버의 부하를 줄일 수&lt;/b&gt; 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6. 타임아웃 및 에러 처리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios는 요청에 대한 타임아웃을 설정할 수 있으며, 타임아웃이 발생하면 에러를 자동으로 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;b&gt;네트워크 오류, 서버 응답 오류&lt;/b&gt; 등 다양한 종류의 에러를 적절하게 처리할 수 있는 기능을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;Axios 사용방법&lt;/b&gt;에 대해서 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681483311100&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install axios&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS에서 Axios를 사용하려면 다음 명령을 사용하여 &lt;b&gt;설치&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Axios를 활용한 간단한 &lt;b&gt;예제 코드&lt;/b&gt;를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. Get&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_스크린샷 2023-04-14 오후 11.56.21.png&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDZ1g9/btsamXFgOXi/d0O3a4ZnL6WXtOGFA9LFc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDZ1g9/btsamXFgOXi/d0O3a4ZnL6WXtOGFA9LFc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDZ1g9/btsamXFgOXi/d0O3a4ZnL6WXtOGFA9LFc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDZ1g9%2FbtsamXFgOXi%2Fd0O3a4ZnL6WXtOGFA9LFc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;256&quot; data-filename=&quot;edited_edited_스크린샷 2023-04-14 오후 11.56.21.png&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;382&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 간단하게 headers의 값만 넣어서 &lt;b&gt;get요청&lt;/b&gt;을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. Post&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_스크린샷 2023-04-14 오후 11.58.48.png&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xmZeh/btsagqI2ZQR/u2RVh5KCA0jZXO3A6SSEU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xmZeh/btsagqI2ZQR/u2RVh5KCA0jZXO3A6SSEU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xmZeh/btsagqI2ZQR/u2RVh5KCA0jZXO3A6SSEU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxmZeh%2FbtsagqI2ZQR%2Fu2RVh5KCA0jZXO3A6SSEU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;272&quot; data-filename=&quot;edited_edited_스크린샷 2023-04-14 오후 11.58.48.png&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;452&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Req 값으로 &quot;id_usr&quot;를 넣어야 해서 url 뒤에 넣어주면 정상적으로 &lt;b&gt;post&lt;/b&gt;가 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 요청 및 응답 인터셉터&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681484520314&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const axios = require('axios');

// 요청 인터셉터
axios.interceptors.request.use((config) =&amp;gt; {
  config.headers['Authorization'] = 'Bearer YOUR_ACCESS_TOKEN';
  return config;
}, (error) =&amp;gt; {
  return Promise.reject(error);
});

// 응답 인터셉터
axios.interceptors.response.use((response) =&amp;gt; {
  if (response.status === 200) {
    console.log('Request successful');
  }
  return response;
}, (error) =&amp;gt; {
  if (error.response.status === 401) {
    console.log('Unauthorized');
  }
  return Promise.reject(error);
});

axios.get('https://google.com/posts')
  .then((response) =&amp;gt; {
    console.log(response.data);
  })
  .catch((error) =&amp;gt; {
    console.error(error);
  });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 요청 취소&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681484612114&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const axios = require('axios');

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('https://google.com/posts', {
  cancelToken: source.token,
})
  .then((response) =&amp;gt; {
    console.log(response.data);
  })
  .catch((error) =&amp;gt; {
    if (axios.isCancel(error)) {
      console.log('Request canceled:', error.message);
    } else {
      console.error(error);
    }
  });

// 요청 취소
source.cancel('Operation canceled by the user.');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5. 타임아웃 설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681484674753&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const axios = require('axios');

axios.get('https://google.com/posts', {
  timeout: 1000, // 1초 이내에 응답이 없으면 타임아웃
})
  .then((response) =&amp;gt; {
    console.log(response.data);
  })
  .catch((error) =&amp;gt; {
    if (error.code === 'ECONNABORTED') {
      console.log('Timeout error:', error.message);
    } else {
      console.error(error);
    }
  });&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Web/NestJS</category>
      <category>axios</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/42</guid>
      <comments>https://ilikezzi.tistory.com/42#entry42comment</comments>
      <pubDate>Sat, 15 Apr 2023 00:08:27 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] null 병합연산자 &amp;quot;??&amp;quot;</title>
      <link>https://ilikezzi.tistory.com/41</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-11 오후 8.59.43.png&quot; data-origin-width=&quot;1530&quot; data-origin-height=&quot;1538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1Xngz/btr9AtMRhvd/SRHcRIJ7mfj09x7KmzV290/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1Xngz/btr9AtMRhvd/SRHcRIJ7mfj09x7KmzV290/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1Xngz/btr9AtMRhvd/SRHcRIJ7mfj09x7KmzV290/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1Xngz%2Fbtr9AtMRhvd%2FSRHcRIJ7mfj09x7KmzV290%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;402&quot; data-filename=&quot;스크린샷 2023-04-11 오후 8.59.43.png&quot; data-origin-width=&quot;1530&quot; data-origin-height=&quot;1538&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은&lt;b&gt; 병합연산자 &quot;??&quot;&lt;/b&gt; 에 대해서 포스팅 해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;?? 예시를 보면 바로 이해가 갈 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;A ?? B&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A가&lt;b&gt; null 또는&lt;/b&gt;&amp;nbsp;&lt;b&gt;undefined&lt;/b&gt;이면 &lt;b&gt;B&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그게 &lt;b&gt;아니라면 A&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 전부다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 언제쓰면 유용한지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-11 오후 9.24.45.png&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;336&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCNFX7/btr9A4zdoy3/gbWcjqKBwkYeVNhG9FajSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCNFX7/btr9A4zdoy3/gbWcjqKBwkYeVNhG9FajSK/img.png&quot; data-alt=&quot;notice.query.repository.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCNFX7/btr9A4zdoy3/gbWcjqKBwkYeVNhG9FajSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCNFX7%2Fbtr9A4zdoy3%2FgbWcjqKBwkYeVNhG9FajSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;336&quot; data-filename=&quot;스크린샷 2023-04-11 오후 9.24.45.png&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;notice.query.repository.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;dto.last_id가 null&lt;/b&gt;이거나 &lt;b&gt;undefined&lt;/b&gt;일때 &lt;b&gt;0으로 변환&lt;/b&gt;해서 이후 0과 대소 비교를 하는 코드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 &lt;b&gt;숫자 0을 구분 지어 &lt;/b&gt;다뤄야 할때 아주 유용하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-04-11 오후 9.36.40.png&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BYdPm/btr9DV2CoG0/6XdWKTHwHzbnP4y49PE2ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BYdPm/btr9DV2CoG0/6XdWKTHwHzbnP4y49PE2ck/img.png&quot; data-alt=&quot;comment.service.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BYdPm/btr9DV2CoG0/6XdWKTHwHzbnP4y49PE2ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBYdPm%2Fbtr9DV2CoG0%2F6XdWKTHwHzbnP4y49PE2ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;137&quot; data-filename=&quot;edited_스크린샷 2023-04-11 오후 9.36.40.png&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;210&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;comment.service.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 이런 dto.parent_uuid에 대한 이런 구구절절 말도안되는 코드도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681216850160&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dto.parent_sort_depth = dto.parent_uuid ?? 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;한줄로&lt;/b&gt; 끝내버릴수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 0 외에도 &lt;b&gt;기본값을 할당&lt;/b&gt;하는 좋은 용도로 사용할 수 있다.&lt;/p&gt;</description>
      <category>Programming Language/Javascript</category>
      <category>??</category>
      <category>JavaScript</category>
      <category>null</category>
      <category>undefined</category>
      <category>병합연산자</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/41</guid>
      <comments>https://ilikezzi.tistory.com/41#entry41comment</comments>
      <pubDate>Tue, 11 Apr 2023 21:52:34 +0900</pubDate>
    </item>
    <item>
      <title>[Nest.JS] DTO 객체의 키 이름 변경 @Transform</title>
      <link>https://ilikezzi.tistory.com/40</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-06 오전 2.14.17.png&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;866&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zfuwY/btr8iZMQ5Xu/nCUrCKA99LXEJJFYkRWCF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zfuwY/btr8iZMQ5Xu/nCUrCKA99LXEJJFYkRWCF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zfuwY/btr8iZMQ5Xu/nCUrCKA99LXEJJFYkRWCF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzfuwY%2Fbtr8iZMQ5Xu%2FnCUrCKA99LXEJJFYkRWCF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;259&quot; data-filename=&quot;스크린샷 2023-04-06 오전 2.14.17.png&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;866&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 DTO 객체의 키 이름을&lt;b&gt; @Transform&lt;/b&gt; 데코레이터를 사용하여 바꾸는 방법에 대해 포스팅을 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;음,, 이렇게만 얘기해서는 무슨소린지 헷갈리니 바로 예제 코드로 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1680787149910&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;findBookmark=[
  {
    target_uuid: 123,
    name: Blanc,
    ...
  },
  {
    target_uuid: 234,
    name: Jack,
    ...
  },
  {
    target_uuid: 345,
    name: Scott,
    ...
  }
]
 
 /////////////////////////////
 
BookmarkReadDto={
  @Expose()
  @ApiProperty()
  uuid: string;
  
  @Expose()
  @ApiProperty(
  name: string;
  
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수&lt;b&gt; findBookmark : []&lt;/b&gt; 와 &lt;b&gt;BookmarkReadDto&lt;/b&gt;가 해당 코드처럼 각각 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 Response값으로 &lt;b&gt;BookmarkReadDto &lt;/b&gt;형태가 필요하므로 &lt;b&gt;plainToInstance&lt;/b&gt;로 매핑을 해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 &lt;b&gt;원하는 형태의 DTO로 매핑&lt;/b&gt; 시켜줄 수 있는 &lt;b&gt;plainToInstance&lt;/b&gt;에 대한 설명이 있으니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한번 읽어보면 도움이 될 것이다...!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ilikezzi.tistory.com/9&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1680789214334&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Nest.JS] class-transform의 plainToInstance를 활용한 Object Mapping&quot; data-og-description=&quot;Class-transform을 다루기전에 Model Mapper에 대해서 먼저 대략적으로 알아보자. Model Mapper 이 Model Mapper란 쉽게 말해 object에 필드값을 원하는 모양의 object로 매핑시켜주는 라이브러리다. Typescript에서 Mo&quot; data-og-host=&quot;ilikezzi.tistory.com&quot; data-og-source-url=&quot;https://ilikezzi.tistory.com/9&quot; data-og-url=&quot;https://ilikezzi.tistory.com/9&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PA1aV/hyScs3hDX7/qBh6B5ogiRXR9GsYX9L8t1/img.png?width=800&amp;amp;height=190&amp;amp;face=0_0_800_190,https://scrap.kakaocdn.net/dn/ogp0p/hyScAfV83p/lCa35HkINrPHMQEl4doQ0k/img.png?width=800&amp;amp;height=190&amp;amp;face=0_0_800_190,https://scrap.kakaocdn.net/dn/mTEAa/hySa5BR619/k5Ko7q8A8k1io7xeavmckk/img.jpg?width=1536&amp;amp;height=1536&amp;amp;face=0_0_1536_1536&quot;&gt;&lt;a href=&quot;https://ilikezzi.tistory.com/9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ilikezzi.tistory.com/9&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PA1aV/hyScs3hDX7/qBh6B5ogiRXR9GsYX9L8t1/img.png?width=800&amp;amp;height=190&amp;amp;face=0_0_800_190,https://scrap.kakaocdn.net/dn/ogp0p/hyScAfV83p/lCa35HkINrPHMQEl4doQ0k/img.png?width=800&amp;amp;height=190&amp;amp;face=0_0_800_190,https://scrap.kakaocdn.net/dn/mTEAa/hySa5BR619/k5Ko7q8A8k1io7xeavmckk/img.jpg?width=1536&amp;amp;height=1536&amp;amp;face=0_0_1536_1536');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Nest.JS] class-transform의 plainToInstance를 활용한 Object Mapping&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Class-transform을 다루기전에 Model Mapper에 대해서 먼저 대략적으로 알아보자. Model Mapper 이 Model Mapper란 쉽게 말해 object에 필드값을 원하는 모양의 object로 매핑시켜주는 라이브러리다. Typescript에서 Mo&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ilikezzi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 본론으로 돌아와서, 우선 &lt;b&gt;매핑을&lt;/b&gt; 시켜보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-04-06 오후 10.29.31.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7u63y/btr8vxv1Cy7/p0wDzrgrkR4tpeGZclWk8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7u63y/btr8vxv1Cy7/p0wDzrgrkR4tpeGZclWk8K/img.png&quot; data-alt=&quot; bookmark.service.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7u63y/btr8vxv1Cy7/p0wDzrgrkR4tpeGZclWk8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7u63y%2Fbtr8vxv1Cy7%2Fp0wDzrgrkR4tpeGZclWk8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;73&quot; data-filename=&quot;edited_스크린샷 2023-04-06 오후 10.29.31.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; bookmark.service.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 &lt;b&gt;plainToInstance&lt;/b&gt;를 사용하여 매핑을 시켜주었으나, 여기서 고민이 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;findBookmark&lt;/b&gt;에 있는 객체의 &lt;b&gt;target_uuid&lt;/b&gt; 라는 &lt;b&gt;key값&lt;/b&gt;&lt;/span&gt;을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매핑한 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;BookmarkReadDto&lt;/b&gt;의 객체의 &lt;b&gt;uuid &lt;/b&gt;라는&lt;b&gt; key값&lt;/b&gt;&lt;/span&gt;으로 변경해서 사용해야했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 강제로 &lt;b&gt;for문을 돌면서 map함수&lt;/b&gt;를 사용해서 &lt;b&gt;findBookmark&lt;/b&gt;의 &lt;b&gt;target_uuid값&lt;/b&gt;을 추출해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 &lt;b&gt;&lt;b&gt;BookmarkReadDto&lt;/b&gt;&lt;/b&gt;의&lt;b&gt;&lt;b&gt; uuid key값&lt;/b&gt;&lt;/b&gt;을 가진 객체에 넣을까 했는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무 비효율적인것 같아서 다른방법을 찾게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 찾게 된게 &lt;b&gt;DTO&lt;/b&gt;에서 &lt;b&gt;@Transform&lt;/b&gt; 데코레이터 사용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-06 오후 10.40.36.png&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oz8DK/btr8ut8MyEE/JJrBvWglkN9oKCcPKuNiZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oz8DK/btr8ut8MyEE/JJrBvWglkN9oKCcPKuNiZk/img.png&quot; data-alt=&quot;bookmark.dto.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oz8DK/btr8ut8MyEE/JJrBvWglkN9oKCcPKuNiZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Foz8DK%2Fbtr8ut8MyEE%2FJJrBvWglkN9oKCcPKuNiZk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;299&quot; data-filename=&quot;스크린샷 2023-04-06 오후 10.40.36.png&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;bookmark.dto.ts&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해당 DTO파일에서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1680788599434&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Transform(({ obj }) =&amp;gt; obj.target_uuid)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한줄만 추가해주면 끝이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@Transform&lt;/b&gt; 데코레이터가 &lt;b&gt;uuid&lt;/b&gt; 속성에 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데코레이터는 원래 개체를 나타내는 obj 속성을 포함하는 개체를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 다음 원래 개체의 &lt;b&gt;target_uuid&lt;/b&gt; 속성을 반환하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 DTO를 사용할 때 &lt;b&gt;uuid 속성이 target_uuid 값&lt;/b&gt;으로 설정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굉장히 간단하면서 편리하다..!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 매핑한 &lt;b&gt;b&lt;/b&gt;&lt;b&gt;&lt;b&gt;ookmarkReadDto&lt;/b&gt;&lt;/b&gt;를 콘솔을 찍어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1680788903895&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bookmarkReadDto=[
  {
    uuid: 123,
    name: Blanc,
    ...
  },
  {
    uuid: 234,
    name: Jack,
    ...
  },
  {
    uuid: 345,
    name: Scott,
    ...
  }
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 원했던대로 &lt;b&gt;key값이 target_uuid --&amp;gt;&amp;nbsp; uuid&lt;/b&gt; 로 잘 바뀐걸 확인할 수 있을것이다.&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/NestJS</category>
      <category>@Transform</category>
      <category>dto</category>
      <category>nestJS</category>
      <category>plainToInstance</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/40</guid>
      <comments>https://ilikezzi.tistory.com/40#entry40comment</comments>
      <pubDate>Thu, 6 Apr 2023 22:51:32 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] AWS 사용량 예산 초과 시 이메일로 알림 받기</title>
      <link>https://ilikezzi.tistory.com/39</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-02 오후 3.14.31.png&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2YAe6/btr7xVDEbjE/shQZSKXl5plrkrdQnDUCDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2YAe6/btr7xVDEbjE/shQZSKXl5plrkrdQnDUCDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2YAe6/btr7xVDEbjE/shQZSKXl5plrkrdQnDUCDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2YAe6%2Fbtr7xVDEbjE%2FshQZSKXl5plrkrdQnDUCDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;210&quot; data-filename=&quot;스크린샷 2023-04-02 오후 3.14.31.png&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 AWS 예산 초과 시 이메일로 알림받는 법에 대해 포스팅을 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 클라우드 서비스를 사용하다보면 &lt;b&gt;예상치 못한 사용량 급증&lt;/b&gt;이나,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 모를 &lt;b&gt;엑세스키 해킹을 통한 요금 폭탄&lt;/b&gt;을 맞을 수 있으므로 필수적으로 해주는게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 루트 계정 외에&lt;b&gt; IAM 관리자계정&lt;/b&gt;으로 하려면, 루트계정에서 권한을 변경을 해줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루트계정으로 로그인해서&lt;b&gt; My account&lt;/b&gt;에서 내려보면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결제 정보에 대한 IAM 사용자 및 역할 액세스가 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-02 오후 2.55.13.png&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;882&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qaEZD/btr7hTf9oVT/iTuA6GB2NEe7fjw1RYnOC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qaEZD/btr7hTf9oVT/iTuA6GB2NEe7fjw1RYnOC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qaEZD/btr7hTf9oVT/iTuA6GB2NEe7fjw1RYnOC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqaEZD%2Fbtr7hTf9oVT%2FiTuA6GB2NEe7fjw1RYnOC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;425&quot; data-filename=&quot;스크린샷 2023-04-02 오후 2.55.13.png&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;882&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이부분에서 IAM 액세스 활성화 버튼을 눌러서 &lt;b&gt;업데이트&lt;/b&gt;를 해주면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;관리자인 IAM 사용자&lt;/b&gt;가 청구데이터에 접근할수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 권한을 설정을 변경하였으니 관리자인 IAM사용자나, ROOT계정 모두 진행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;Budgets&lt;/b&gt;으로 이동해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-02 오후 2.59.06.png&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;1438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AfmFe/btr7gg3Pw6Q/aVgtPZ1NwOC96RZOyLHVRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AfmFe/btr7gg3Pw6Q/aVgtPZ1NwOC96RZOyLHVRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AfmFe/btr7gg3Pw6Q/aVgtPZ1NwOC96RZOyLHVRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAfmFe%2Fbtr7gg3Pw6Q%2FaVgtPZ1NwOC96RZOyLHVRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;553&quot; data-filename=&quot;스크린샷 2023-04-02 오후 2.59.06.png&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;1438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예산 생성&lt;/b&gt;으로 이동하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-02 오후 3.00.41.png&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;1576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K7J2V/btr7hwSAaLG/uNJTR1lSJ0SK35kgijGqR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K7J2V/btr7hwSAaLG/uNJTR1lSJ0SK35kgijGqR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K7J2V/btr7hwSAaLG/uNJTR1lSJ0SK35kgijGqR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK7J2V%2Fbtr7hwSAaLG%2FuNJTR1lSJ0SK35kgijGqR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;764&quot; data-filename=&quot;스크린샷 2023-04-02 오후 3.00.41.png&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;1576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;템플릿 사용을 권장하고,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프리티어 사용자는 &lt;b&gt;제로지출예산&lt;/b&gt;, 아닌경우는 &lt;b&gt;월별 비용 예산&lt;/b&gt;을 눌러준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 자신이 원하는 &lt;b&gt;예산 금액&lt;/b&gt;과, &lt;b&gt;알림받을 이메일&lt;/b&gt;을 입력해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-02 오후 3.01.52.png&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpXIah/btr7f0mQCo6/XWOkhtQlOBmy6eufJbndsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpXIah/btr7f0mQCo6/XWOkhtQlOBmy6eufJbndsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpXIah/btr7f0mQCo6/XWOkhtQlOBmy6eufJbndsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpXIah%2Fbtr7f0mQCo6%2FXWOkhtQlOBmy6eufJbndsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;728&quot; data-filename=&quot;스크린샷 2023-04-02 오후 3.01.52.png&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 설정 &lt;b&gt;지출금액에 85%&lt;/b&gt;에 도달했을때와,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실제 지출의 100%&lt;/b&gt;에 도달할경우,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예상 지출이 100%에 도달할 것으로 예상&lt;/b&gt;되는 경우에 알림을 받게 됩니다.&lt;/p&gt;</description>
      <category>Programming/AWS</category>
      <category>AWS</category>
      <category>사용량</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/39</guid>
      <comments>https://ilikezzi.tistory.com/39#entry39comment</comments>
      <pubDate>Sun, 2 Apr 2023 15:35:14 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] split() 지정 구분기호로 문자열을 배열로 분할</title>
      <link>https://ilikezzi.tistory.com/38</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-30 오전 1.46.43.png&quot; data-origin-width=&quot;1540&quot; data-origin-height=&quot;1538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl3mzb/btr6Qo7U2HD/z61PpfWxfckXdxColRAeCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl3mzb/btr6Qo7U2HD/z61PpfWxfckXdxColRAeCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl3mzb/btr6Qo7U2HD/z61PpfWxfckXdxColRAeCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl3mzb%2Fbtr6Qo7U2HD%2Fz61PpfWxfckXdxColRAeCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;399&quot; data-filename=&quot;스크린샷 2023-03-30 오전 1.46.43.png&quot; data-origin-width=&quot;1540&quot; data-origin-height=&quot;1538&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은&lt;b&gt; 문자열&lt;/b&gt;을 원하는 지정구분 기호로 &lt;b&gt;배열로 분할&lt;/b&gt;하는 법에 대해서 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;케이스는 이러하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-30 오전 1.49.42.png&quot; data-origin-width=&quot;214&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxCEYp/btr6QTGLMK1/nTatsKVbA6ZvnMnxrazhFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxCEYp/btr6QTGLMK1/nTatsKVbA6ZvnMnxrazhFk/img.png&quot; data-alt=&quot;DB &amp;quot;sort_depth&amp;quot; 컬럼&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxCEYp/btr6QTGLMK1/nTatsKVbA6ZvnMnxrazhFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxCEYp%2Fbtr6QTGLMK1%2FnTatsKVbA6ZvnMnxrazhFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;150&quot; height=&quot;221&quot; data-filename=&quot;스크린샷 2023-03-30 오전 1.49.42.png&quot; data-origin-width=&quot;214&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DB &quot;sort_depth&quot; 컬럼&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 DB에 &lt;b&gt;sort_depth&lt;/b&gt;라는 컬럼이 존재하는데 해당 값들은 string으로 이루어져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 사진에 아랫쪽에 있는&lt;b&gt; &quot;118,121,122,123&quot;&lt;/b&gt; 의 크기(길이?)를 구해 4라는 값을 얻고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 우선 &lt;b&gt;배열&lt;/b&gt;로 변환한 다음,&lt;b&gt; length()&lt;/b&gt;를 사용하여 크기를 구할 계획이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 배열로 변환할때 &quot; &lt;b&gt;,&lt;/b&gt; &quot; 이 콤마 단위로 구분을 해서 넣어 줘야되는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 &lt;b&gt;split()&lt;/b&gt;를 사용하면 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;split()&lt;/b&gt;이란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;지정된 구분 기호&lt;/b&gt;에 따라 문자열을 하위 문자열 &lt;b&gt;배열로 분할&lt;/b&gt;할 수 있는 내장 JavaScript 문자열 메서드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법은 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1680109398571&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = &quot;118,121,122,123&quot;;
const arr = str.split(&quot;,&quot;); // ,로 분할 하겠다.

console.log(arr); // outputs [&quot;118&quot;, &quot;121&quot;, &quot;122&quot;, &quot;123&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 사용해주면 쉽게 배열로 분할 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 배열 arr을 &quot;&lt;b&gt;arr.length&lt;/b&gt;&quot;를 사용하면 원하는 &lt;b&gt;문자열의 크기&lt;/b&gt;를 구할수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-30 오전 2.05.44.png&quot; data-origin-width=&quot;858&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6YMD0/btr6OUzy5nk/8qAUBD1IbtdFtqoT6PRkOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6YMD0/btr6OUzy5nk/8qAUBD1IbtdFtqoT6PRkOk/img.png&quot; data-alt=&quot;service부 관련코드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6YMD0/btr6OUzy5nk/8qAUBD1IbtdFtqoT6PRkOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6YMD0%2Fbtr6OUzy5nk%2F8qAUBD1IbtdFtqoT6PRkOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;227&quot; data-filename=&quot;스크린샷 2023-03-30 오전 2.05.44.png&quot; data-origin-width=&quot;858&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;service부 관련코드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Programming Language/Javascript</category>
      <category>JavaScript</category>
      <category>split</category>
      <category>배열분할</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/38</guid>
      <comments>https://ilikezzi.tistory.com/38#entry38comment</comments>
      <pubDate>Thu, 30 Mar 2023 02:08:23 +0900</pubDate>
    </item>
    <item>
      <title>[NestJS] DB커넥션을 최소화하고 Service부에 부하를 줘야하는 이유.</title>
      <link>https://ilikezzi.tistory.com/37</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-27 오후 10.43.54.png&quot; data-origin-width=&quot;1247&quot; data-origin-height=&quot;649&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTZj4G/btr6tVqWVK0/CkZ99YFRcXDVLy4Buq7k30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTZj4G/btr6tVqWVK0/CkZ99YFRcXDVLy4Buq7k30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTZj4G/btr6tVqWVK0/CkZ99YFRcXDVLy4Buq7k30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTZj4G%2Fbtr6tVqWVK0%2FCkZ99YFRcXDVLy4Buq7k30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;260&quot; data-filename=&quot;스크린샷 2023-03-27 오후 10.43.54.png&quot; data-origin-width=&quot;1247&quot; data-origin-height=&quot;649&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 별건 아니고, 배포중인 어플에서 뉴스 댓글 목록을 불러올때&lt;b&gt; 2~3초 가량 소요&lt;/b&gt;되서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드를 &lt;b&gt;리팩토링&lt;/b&gt; 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리팩토링은 왜 할까 ?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 성능향상, 가독성 향상&amp;nbsp; &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 유사한 내용이 반복될때 &lt;span&gt;코드의 중복 제거 &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;3. 새로운 기능을 추가할 때&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 세가지 이유가 제일 핵심적인 이유다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 코드를 Swagger에서 돌려 보았을때 두 눈을 의심했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-03-27 오후 10.09.45.png&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;1310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bie1IF/btr6buCleCi/nSs1opB9lPSKpDlqoKkmF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bie1IF/btr6buCleCi/nSs1opB9lPSKpDlqoKkmF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bie1IF/btr6buCleCi/nSs1opB9lPSKpDlqoKkmF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbie1IF%2Fbtr6buCleCi%2FnSs1opB9lPSKpDlqoKkmF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;1035&quot; data-filename=&quot;edited_스크린샷 2023-03-27 오후 10.09.45.png&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;1310&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 목록 불러오는 &lt;b&gt;@Get API&lt;/b&gt;를&lt;b&gt; 단 한번&lt;/b&gt; 실행 시킨것이다....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 Response값으로 다양한 값이 필요하긴 하지만 이건 말이 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러니 목록 불러올때 2~3초 가량 로딩시간이 걸렸던 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행된 사진 속 쿼리문을 보니 &lt;b&gt;중복된 테이블에서 SELECT&lt;/b&gt;가 여러번 이루어 지는걸로 보아&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;for문&lt;/b&gt;을 돌면서 그 안에서 &lt;b&gt;DB커넥션&lt;/b&gt;이 여러번 이뤄지고 있는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능관점에서&lt;b&gt; DB커넥션수를 최소화&lt;/b&gt;하고&lt;b&gt; Service부에 부하&lt;/b&gt;를 가하는게 훨씬 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;첫째. 성능&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 데이터베이스 연결은 메모리, CPU 및 네트워크 대역폭과 같은 &lt;b&gt;리소스&lt;/b&gt;를 소비한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 수를 줄임으로써 &lt;b&gt;오버헤드를 최소화&lt;/b&gt;하고 애플리케이션의 &lt;b&gt;성능을 향상&lt;/b&gt;시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 애플리케이션이 과부하 상태에서도 응답성을 유지하는 데 도움이 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;둘째. 확장성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션이 커짐에 따라 데이터베이스에 대한&lt;b&gt; 동시 연결 수가 증가&lt;/b&gt;할 수 있는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 수를 줄이면 애플리케이션이 효율적으로 확장되고 데이터베이스에서 부과하는 제한 없이 &lt;b&gt;더 많은 사용자를 수용&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;셋째. 연결 Pool 고갈&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 데이터베이스에는 동시에 처리할 수 있는 &lt;b&gt;최대 연결 수&lt;/b&gt;가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 제한에 도달하면 새 연결 요청이 대기하거나 거부되어 애플리케이션에서 &lt;b&gt;지연 또는 오류&lt;/b&gt;가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 수를 줄이면 연결 풀이 고갈되는 것을 방지하고 애플리케이션을&lt;b&gt; 안정적으로 유지&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;넷째. 비용 절감&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스팅 공급자와 클라우드 서비스는 종종 사용하는 데이터베이스&lt;b&gt; 연결 수에 따라 요금을 부과&lt;/b&gt;하기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 수를 줄이면 호스팅 비용도 &lt;b&gt;절약&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이정도면 필수적으로 해야되는게 맞는것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Service부에서 필요한 DB커넥션은 최소화하면서 불필요한 쿼리 최대한 로직으로 풀어서 &lt;b&gt;리팩토링을&lt;/b&gt; 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-03-27 오후 9.55.59 (1).png&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhpKcQ/btr6eSXliao/KYev0GelpNvwXZkWaIA7e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhpKcQ/btr6eSXliao/KYev0GelpNvwXZkWaIA7e1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhpKcQ/btr6eSXliao/KYev0GelpNvwXZkWaIA7e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhpKcQ%2Fbtr6eSXliao%2FKYev0GelpNvwXZkWaIA7e1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;301&quot; data-filename=&quot;edited_스크린샷 2023-03-27 오후 9.55.59 (1).png&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리팩토링을 다 하고 Swagger에서 동일하게 코드를 실행시켰더니&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 말도안되는 차이,,,,,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포를 하고 댓글 불러오는 부분에서 로딩시간이 걸렸던것도 &lt;b&gt;완전히&lt;/b&gt; 사라졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로도 &lt;b&gt;DB커넥션은 무조건 최소화&lt;/b&gt;하고 &lt;b&gt;불 필요한 쿼리수는 줄이도록&lt;/b&gt; 하자.&lt;/p&gt;</description>
      <category>Web/NestJS</category>
      <category>DB커넥션</category>
      <category>nestJS</category>
      <category>리팩토링</category>
      <category>성능</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/37</guid>
      <comments>https://ilikezzi.tistory.com/37#entry37comment</comments>
      <pubDate>Mon, 27 Mar 2023 23:18:32 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] &amp;quot;some()&amp;quot; 배열의 객체에 원하는 값이 있으면 True 반환</title>
      <link>https://ilikezzi.tistory.com/36</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-25 오후 10.16.10.png&quot; data-origin-width=&quot;1534&quot; data-origin-height=&quot;1524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAmJ2O/btr5OcPRHiz/REbCUj0d5k57nJyESiQwaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAmJ2O/btr5OcPRHiz/REbCUj0d5k57nJyESiQwaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAmJ2O/btr5OcPRHiz/REbCUj0d5k57nJyESiQwaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAmJ2O%2Fbtr5OcPRHiz%2FREbCUj0d5k57nJyESiQwaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;397&quot; data-filename=&quot;스크린샷 2023-03-25 오후 10.16.10.png&quot; data-origin-width=&quot;1534&quot; data-origin-height=&quot;1524&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Javascript에서 배열의 요소를 순차적으로 순회하면서 &lt;b&gt;특정 조건을 만족하는지 체크&lt;/b&gt;하는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;some()함수&lt;/b&gt;를 다룰 것이다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;some함수의 특징은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- true를 만족하는 요소를 찾을 때까지 &lt;b&gt;callback&lt;/b&gt; 함수를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 만족하는 요소가 없거나 빈 배열인 경우 &lt;b&gt;false&lt;/b&gt;를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 처리하는 요소의 범위는 callback 함수의 첫 호출 전에 설정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;likeTotal이라는 배열안에 객체의 &lt;b&gt;&quot;user_uuid&quot;&lt;/b&gt;라는&lt;b&gt; key값&lt;/b&gt;에, &lt;b&gt;&quot;user&quot;&lt;/b&gt;라는 &lt;b&gt;value값&lt;/b&gt;이 있으면 true를 반환 하고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 코드를 확인해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1679751398682&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const likeTotal = [
  { user_uuid: '1234', likes: 10 },
  { user_uuid: '5678', likes: 5 },
  { user_uuid: 'user', likes: 3 },
  { user_uuid: 'abcd', likes: 7 }
];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 코드는 likeTotal이라는 배열이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 배열안 세번째 객체에 user_uuid라는 key값에&lt;b&gt; 'user&lt;/b&gt;' 라는 값이 있어서 &lt;b&gt;True&lt;/b&gt;를 반환해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1679751779889&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const userLikeTotal = likeTotal.some(item =&amp;gt; item.user_uuid === 'user');

console.log(userLikeTotal);
// return -&amp;gt; &quot;true&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 &lt;b&gt;some()&lt;/b&gt;함수를 사용하면 원하는 조건에 맞게 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각&amp;nbsp;항목의&amp;nbsp;&lt;b&gt;&quot;user_uuid&quot;&amp;nbsp;&lt;/b&gt;속성이&amp;nbsp;문자열&amp;nbsp;&lt;b&gt;&quot;user&lt;/b&gt;&quot;와&amp;nbsp;같은지&amp;nbsp;확인하는&amp;nbsp;콜백&amp;nbsp;함수와&amp;nbsp;함께&amp;nbsp;some() 함수가 이 배열에서 호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하나 이상의 항목이 이 조건을 만족&lt;/b&gt;하면 some() 함수는&lt;b&gt; true&lt;/b&gt;를 반환하고 UserLikeTotal에는&lt;b&gt; true 값이 할당&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/Javascript</category>
      <category>array</category>
      <category>JavaScript</category>
      <category>some</category>
      <category>배열</category>
      <author>대파양파애비</author>
      <guid isPermaLink="true">https://ilikezzi.tistory.com/36</guid>
      <comments>https://ilikezzi.tistory.com/36#entry36comment</comments>
      <pubDate>Sat, 25 Mar 2023 22:50:15 +0900</pubDate>
    </item>
  </channel>
</rss>