<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>세상엔 배울 게 많다</title>
    <link>https://djunnni.tistory.com/</link>
    <description>https://github.com/Djunnni</description>
    <language>ko</language>
    <pubDate>Tue, 16 Jun 2026 05:39:08 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>djunnni</managingEditor>
    <image>
      <title>세상엔 배울 게 많다</title>
      <url>https://tistory1.daumcdn.net/tistory/5359263/attach/f9121ca970d6402bb47f10c2847e1c83</url>
      <link>https://djunnni.tistory.com</link>
    </image>
    <item>
      <title>PUT vs PATCH</title>
      <link>https://djunnni.tistory.com/34</link>
      <description>&lt;h1&gt;PUT vs PATCH&lt;/h1&gt;
&lt;p&gt;PUT과 PATCH 모두 리소스에 변화를 주고 있다. 따라서 resource 관점에서는 safe하지 않은 메서드다.&lt;/p&gt;
&lt;p&gt;2가지 방식에 대해 다음 관점들로 이해해 볼 필요가 있다.&lt;/p&gt;
&lt;h3&gt;3가지 관점&lt;/h3&gt;
&lt;h4&gt;1. update&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;리소스에 대해 직접적으로 접근할 수 있는 Key 값이 있다고 해야한다.&lt;br&gt;ex) products?id=2&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;
&lt;li&gt;PUT : resource에 대해 전체 내용을 바꾸며, 리소스에서 지원하는 필드가 비어있다면 nullable 하다.&lt;/li&gt;
&lt;li&gt;PATCH : resource에서 일부분을 수정하며, 리소스에서 정의된 필드만 바꾼다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;ex) PUT
{ item: &amp;#39;아이폰 XS&amp;#39;, price: 100000, color: &amp;#39;spaceGray&amp;#39; } 가 있다.

put를 통해 API를 수정해보자.

{ item: &amp;#39;아이폰 XS&amp;#39;, price: 4000, color: &amp;#39;spaceGray&amp;#39; } -&amp;gt; { item: &amp;#39;아이폰 XS&amp;#39;, price: 4000, color: &amp;#39;spaceGray&amp;#39; }
{ item: &amp;#39;아이폰 XS&amp;#39; } -&amp;gt; { item: &amp;#39;아이폰 XS&amp;#39;, price: null, color: null }

ex) PATCH
{ item: &amp;#39;아이폰 XS&amp;#39;, price: 100000, color: &amp;#39;spaceGray&amp;#39; } 가 있다.

patch를 통해 API를 수정하자.

{ item: &amp;#39;아이폰 X&amp;#39; } -&amp;gt; { item: &amp;#39;아이폰 X&amp;#39;, price: 100000, color: &amp;#39;spaceGray&amp;#39; }
{ item: &amp;#39;아이폰 XS&amp;#39;, price: 100000, color: &amp;#39;white&amp;#39; } -&amp;gt; { item: &amp;#39;아이폰 XS&amp;#39;, price: 100000, color: &amp;#39;white&amp;#39; }&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;2. resource가 없을 시,&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;리소스에 대해 직접적으로 접근할 수 있는 Key 값이 있다고 해야한다.&lt;br&gt;ex) products/iphone&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;
&lt;li&gt;PUT: 리소스가 없다고 판단해 새롭게 추가한다.&lt;/li&gt;
&lt;li&gt;PATCH: 리소스가 없다고 판단하고 생성하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 멱등성&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;PUT -&amp;gt; resource에 대한 changed resource를 변경하는 것&lt;/li&gt;
&lt;li&gt;PATCH -&amp;gt; resource에 대해 변경을 request하는 것 &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;그렇기 때문에 patch는 resource를 다루지 않는다는 의미에서 idempotent(멱등)하지 않다라고 보는 것이지 resource 타입으로 보면 멱등하다고도 볼 수 있다. 즉 멱등하게 운영해도 된다.&lt;/p&gt;
&lt;h3&gt;참고&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.qu3vipon.com/idempotence-of-patch&quot;&gt;https://www.qu3vipon.com/idempotence-of-patch&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc5789#section-2&quot;&gt;https://datatracker.ietf.org/doc/html/rfc5789#section-2&lt;/a&gt;&lt;/p&gt;</description>
      <category>CS/Client</category>
      <category>HTTP</category>
      <category>PUT vs POST</category>
      <author>djunnni</author>
      <guid isPermaLink="true">https://djunnni.tistory.com/34</guid>
      <comments>https://djunnni.tistory.com/34#entry34comment</comments>
      <pubDate>Fri, 13 Oct 2023 00:26:13 +0900</pubDate>
    </item>
    <item>
      <title>S3에 올린 데이터를 기간이 지나고 난 뒤 자동삭제 하는 방법</title>
      <link>https://djunnni.tistory.com/33</link>
      <description>&lt;h1&gt;들어가며,&lt;/h1&gt;
&lt;p&gt;AWS S3에 올린 객체가 특정 날짜에 삭제되거나 몇일이 지나 삭제가 됐으면 좋겠다고 생각할 때가 있다.&lt;/p&gt;
&lt;p&gt;이 경우 어떻게 해야 되는지 살펴보자&lt;/p&gt;
&lt;h2&gt;1. S3 Bucket LifeCycle Rule을 설정&lt;/h2&gt;
&lt;p&gt;S3 LifeCycle Rule은 객체 자체에 Rule을 설정할 수 없어 Bucket 단위로 설정이 가능하다.&lt;/p&gt;
&lt;p&gt;batch 작업으로 유저가 등록한 파일을 자동 제거하는 규칙을 설정한 rule이 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;생명주기 이름을 기입한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;규칙 범위를 선택한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;하나 이상의 필터로 이 규칙을 범위 제한&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;버킷의 모든 객체에 적용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;필터 유형 설정&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;객체 태그 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;객체 크기 제한 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;수명 주기 규칙 작업 설정&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;스토리지 간 현재/이전 버전 이동&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;객체에 현재 버전 만료&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;설정하고 싶은 기간의 일 수를 기입합니다. ex) 7&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;객체의 이전버전 영구 삭제&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;객체가 최신이 아닌 버전이 된 후 경과한 일수 필드에 &amp;quot;1&amp;quot;을 입력합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;모든 버전을 삭제하고 싶다면 유지할 최신 버전 수 필드를 비우세요.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;만료된 객체 삭제 마커 또는 완료되지 않은 멀티파트 업로드 삭제 현재 버전 만료와 함께 사용 불가&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;추가적인 내용은 &lt;a href=&quot;https://repost.aws/ko/knowledge-center/s3-empty-bucket-lifecycle-rule&quot;&gt;여기&lt;/a&gt;서 볼 수 있습니다.&lt;/p&gt;
&lt;h2&gt;NestJS에서는 어떻게 사용할 수 있을까?&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;권한 여부 확인&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;s3PutObject&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;s3DeleteObject&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;s3PutObjectTagging&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;s3RequestObjectTag&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. c3api에 적용된 Upload 방법을 이용해서 설명함&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;tagging을 통해 추가가 가능하다. tagging은 key=value 형태로 여러개를 넣고 싶으면 &amp;amp;을 추가해야한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ex) expiration_day=7&amp;amp;delete=force&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const upload = new Upload({
      client: this.s3Client,
      params: {
        Bucket: bucketName,
        Key: key,
        Body: Readable.from(file.buffer),
        ContentType: file.mimetype,
        ACL: acl ?? &amp;#39;private&amp;#39;,
        ...(expires &amp;amp;&amp;amp; { Expires: expires }),
        ...(tagging &amp;amp;&amp;amp; { Tagging: tagging }), // TAG 설정 &amp;#39;expiration_day=7&amp;#39;
      },
    });&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;참고&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://repost.aws/ko/knowledge-center/s3-empty-bucket-lifecycle-rule&quot;&gt;https://repost.aws/ko/knowledge-center/s3-empty-bucket-lifecycle-rule&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/@dnorth98/using-s3-batch-to-tag-data-for-removal-a569fef7ac0&quot;&gt;https://medium.com/@dnorth98/using-s3-batch-to-tag-data-for-removal-a569fef7ac0&lt;/a&gt;&lt;/p&gt;</description>
      <category>CS/Infra</category>
      <author>djunnni</author>
      <guid isPermaLink="true">https://djunnni.tistory.com/33</guid>
      <comments>https://djunnni.tistory.com/33#entry33comment</comments>
      <pubDate>Mon, 9 Oct 2023 13:23:27 +0900</pubDate>
    </item>
    <item>
      <title>S3에서 Presigned URL 사용하기</title>
      <link>https://djunnni.tistory.com/32</link>
      <description>&lt;h2&gt;Presigned URL 적용 이전까지 일반적인 파일 업로드 상황&lt;/h2&gt;
&lt;p&gt;서비스에서 이전까지 S3와 관련된 SDK를 통해 stream이나 메모리에 올려둔 파일을 업로드 했다.&lt;br&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y5CDM/btsxsnClgPY/PK5zXHZGtByiRTV8KLKxZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y5CDM/btsxsnClgPY/PK5zXHZGtByiRTV8KLKxZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y5CDM/btsxsnClgPY/PK5zXHZGtByiRTV8KLKxZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY5CDM%2FbtsxsnClgPY%2FPK5zXHZGtByiRTV8KLKxZ1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이 경우에는 다음과 같은 단점이 존재하게 된다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;서버에서 파일업로드 외에도 다양한 API 작업을 수행할텐데 파일업로드에 리소스(메모리, CPU)를 사용하게 된다.&lt;/li&gt;
&lt;li&gt;Network Traffic 비용이 서버로 이동할 때, AWS로 전달할 때 2중으로 쓰인다. (AWS 등의 정책에 따라 무료일 수 있다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Presigned URL은 어떤 일을 하나?&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;미리 서버에서 파일이 업로드 될 것을 예상하고 params를 가지고 있는 URL을 하나 생성한다.&lt;/li&gt;
&lt;li&gt;URL을 Client에게로 전달해 유저가 직접 AWS로 파일 업로드 or 다운로드를 가능하도록 조치한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E1N1i/btsxLlDsGNJ/2o6HqdP25kSjQ1eibKavl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E1N1i/btsxLlDsGNJ/2o6HqdP25kSjQ1eibKavl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E1N1i/btsxLlDsGNJ/2o6HqdP25kSjQ1eibKavl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE1N1i%2FbtsxLlDsGNJ%2F2o6HqdP25kSjQ1eibKavl1%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;얻을 수 있는 장점&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;서버의 리소스를 사용하지 않고 업로드가 가능하다.&lt;/em&gt; (제일 큰 장점이 아닐까 싶다)&lt;/li&gt;
&lt;li&gt;Lambda나 별도의 서비스를 활용해 추가처리를 할 수 있다. (크게 와닿진 않음)&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>CS/Infra</category>
      <category>AWS</category>
      <category>PresignedURL</category>
      <category>S3</category>
      <author>djunnni</author>
      <guid isPermaLink="true">https://djunnni.tistory.com/32</guid>
      <comments>https://djunnni.tistory.com/32#entry32comment</comments>
      <pubDate>Mon, 9 Oct 2023 13:22:29 +0900</pubDate>
    </item>
    <item>
      <title>EUC-KR 인코딩을 사용하는 서버와 통신하기</title>
      <link>https://djunnni.tistory.com/31</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 문제 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS로 서비스하고 있는 데 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;토스페이먼츠의 에스크로 등록 API는 EUC-KR 인코딩이 되어있다. 그로 인해 정상적으로 등록되지 못해 의도하지 않는 결과를 얻게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;이 문제를 파악하기 위해 공부했던 내용은&amp;nbsp;&lt;a href=&quot;https://djunnni.tistory.com/10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://djunnni.tistory.com/10&lt;/a&gt;&amp;nbsp;에서 확인할 수 있습니다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;90&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fmc3q/btsxsS28v4Y/EKTTylkbKOoJNBWvDyp9x1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fmc3q/btsxsS28v4Y/EKTTylkbKOoJNBWvDyp9x1/img.png&quot; data-alt=&quot;&amp;quot;정보 없음&amp;quot; 이 UTF-8에서 EUC-KR로 변환에 실패해 의도치 않는 결과가 나왔다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fmc3q/btsxsS28v4Y/EKTTylkbKOoJNBWvDyp9x1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFmc3q%2FbtsxsS28v4Y%2FEKTTylkbKOoJNBWvDyp9x1%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;586&quot; height=&quot;90&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;90&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&quot;정보 없음&quot; 이 UTF-8에서 EUC-KR로 변환에 실패해 의도치 않는 결과가 나왔다&lt;/figcaption&gt;
&lt;/figure&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;2. 기존 환경&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS 공식 문서에서 제공하고 있는 HttpModule을 이용해 외부 API를 호출하고 있다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://docs.nestjs.com/techniques/http-module&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.nestjs.com/techniques/http-module&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Axios의 application/x-www-form-urlencoded 처리 과정&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;httpModule은 내부적으로 axios를 사용하고 있다. Content-Type을 application/x-www-form-urlencoded로 설정하고 POST를 보내고 있다. 외부 라이브러리를 사용하고 있어 어떻게 요청을 처리하는 지 확인할 필요가 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@nestjs/axios의 package.json을 확인하면 axios 1.5.0 버전을 사용하고 있다. &lt;a href=&quot;https://github.com/axios/axios&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;axios의 github code&lt;/a&gt;로 dive 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;README에서&amp;nbsp; 제공하고 있는데 기본적으로 URLSearchParams를 활용하고 있으며 JavaScript Object를 JSON으로 직렬화해주고 있다.&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-10-08 오후 4.33.44.png&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/labRM/btsxkDlM5Gu/dbhfX9DAksQioRixQKRBvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/labRM/btsxkDlM5Gu/dbhfX9DAksQioRixQKRBvk/img.png&quot; data-alt=&quot;axios application/x-www-form-urlencoded 설명&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/labRM/btsxkDlM5Gu/dbhfX9DAksQioRixQKRBvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlabRM%2FbtsxkDlM5Gu%2FdbhfX9DAksQioRixQKRBvk%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;1710&quot; height=&quot;488&quot; data-filename=&quot;스크린샷 2023-10-08 오후 4.33.44.png&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;axios application/x-www-form-urlencoded 설명&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;a href=&quot;https://github.com/axios/axios/blob/a48a63ad823fc20e5a6a705f05f09842ca49f48c/lib/defaults/index.js#L72&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;axios/lib/defaults/index.js &lt;/a&gt;를 확인해보면 transformRequest 함수가 존재하는데 요청에 대해서 데이터를 변환해주는 함수다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-10-08 오후 7.33.48.png&quot; data-origin-width=&quot;1278&quot; data-origin-height=&quot;1428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDkr0t/btsxidnnHkf/JJ4ypTJb9SxP1IMgUW7dBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDkr0t/btsxidnnHkf/JJ4ypTJb9SxP1IMgUW7dBK/img.png&quot; data-alt=&quot;axios/lib/default/index.js 일부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDkr0t/btsxidnnHkf/JJ4ypTJb9SxP1IMgUW7dBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDkr0t%2FbtsxidnnHkf%2FJJ4ypTJb9SxP1IMgUW7dBK%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;640&quot; height=&quot;715&quot; data-filename=&quot;스크린샷 2023-10-08 오후 7.33.48.png&quot; data-origin-width=&quot;1278&quot; data-origin-height=&quot;1428&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;axios/lib/default/index.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;여기서 우리가 볼만한 정보는 3가지였다. 첫번째는 URLSearchParams를 사용하는 지 검증하는 부분과 isObjectPayload 여부를 확인하는 부분 그리고 Buffer 또는 File, Blob이면 그대로를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;isObjectPayload는 toURLEncodedForm을 호출하는데 아래와 같은 함수로 구성되어 있다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;toFormData는 data를 platform.classes.URLSearchParams으로 바꾸기 위해 visitor라는 option을 전달하여 생성하고 있다.&lt;br /&gt;node환경에서 value가 버퍼면 base64로 추가하는 의도로 보인다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-10-08 오후 4.40.34.png&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwne0M/btsxkB9jS9G/1C0SzPKXYRNURT46Ff5PYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwne0M/btsxkB9jS9G/1C0SzPKXYRNURT46Ff5PYk/img.png&quot; data-alt=&quot;axios url encoded form&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwne0M/btsxkB9jS9G/1C0SzPKXYRNURT46Ff5PYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbwne0M%2FbtsxkB9jS9G%2F1C0SzPKXYRNURT46Ff5PYk%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;680&quot; height=&quot;271&quot; data-filename=&quot;스크린샷 2023-10-08 오후 4.40.34.png&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;axios url encoded form&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1 URLSearchParams의 변환하는 방식&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;a href=&quot;https://url.spec.whatwg.org/#interface-urlsearchparams&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://url.spec.whatwg.org/#interface-urlsearchparams&lt;/a&gt; 에서 class interface를 확인할 수 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URLSearchParams는 URL의 query string을 만들어주는 utility method다. URLSearchParams은 Record 형태로 key-value 쌍으로 삽입이 가능하다. URL은 영어, 숫자, 기타 특수기호를 제외한 나머지는 %기호를 사용해 hex 코드로 변환된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 URLSearchParams에 한글이 들어가면 hex코드로 변환된 형태로 output을 받는다고 이해하면 된다. 이 변환하는 과정에서 선행조건으로 배워둬야 할 것은 encodeURI와 encodeURIComponent 다.&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.1.1 encodeURI&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 문자를 제외한 나머지를 전부 이스케이프 처리합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;A&amp;ndash;Z a&amp;ndash;z 0&amp;ndash;9 - _ . ! ~ * ' ( ) &lt;br /&gt;; / ? : @ &amp;amp; = + $ , # -&amp;gt; URI 구문의 일부일 수 있음.&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1.2 encodeURIComponent&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 문자를 제외한 나머지를 전부 이스케이프 처리합니다. encodeURI와 달리 URI 구분자를 이스케이프하면서 value를 있는 그대로 서버로 보내줄 수 있습니다. 만약에 &quot;lag&amp;amp;born&quot;을 보내고 싶다면 encodeURIComponent를 사용해야 정확한 값을 보낼 수 있게 됩니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;A&amp;ndash;Z a&amp;ndash;z 0&amp;ndash;9 - _ . ! ~ * ' ( )&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;URLSearchParams에서는 key와 value 모두 encodeURIComponent로 인코딩되어 처리가 됩니다. 간단하게 코드를 테스트해보면 쉽게 알 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1696753318233&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const params = new URLSearchParams();
params.append(&quot;name&amp;amp;age&quot;, &quot;daniel&amp;amp;25&quot;)

console.log(params.toString()) // name%26age=daniel%2625&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;정리해보면 axios는 application/x-www-form-urlencode에서 object 또는 urlSearchParams로 들어온 데이터를 urlSearchParams로 바꾼다. urlSearchParams는 encodeURIComponent를 사용해 key와 value를 인코딩한다. 인코딩은 UTF-8이 기본이다.&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;4. 어떻게 axios post를 호출해야 될까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios에서 urlSearchParams을 통해 UTF-8로 인코딩되는 건 좋지만 우리에게 필요한 건 EUC-KR입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios는 Buffer, Stream일 경우에는 그대로 data를 반환하도록 되어있습니다. 그 말은 body로 넣을 부분에 처음부터 EUC-KR로 들어간 Buffer를 전달하면 그대로 전달이 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1696761799245&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private async escrowAxios(url: string, obj: Data): Promise&amp;lt;string&amp;gt; {
    const { data } = await firstValueFrom(
      this.httpService
        .post&amp;lt;string&amp;gt;(url, converToBuffer(obj), { // convertToBuffer 목표: obj를 받아 euc-kr이 적용된 버퍼를 반환한다.
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
          },
          responseType: 'arraybuffer',
        })
        .pipe(
          catchError((error: any) =&amp;gt; {
            return of({ data: error.message });
          }),
        ),
    );
    return iconv.decode(data, EUC_KR);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 convertToBuffer를 구현하는 함수를 작성하면 완료가 됩니다.&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;5. convertToBuffer 목표&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 일단 목표는 Buffer로 변하는 과정에서 Buffer에 들어있는 데이터는 EUC-KR을 통해 변환이 되어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. body에 들어가는 데이터는 URLSearchParams의 결과 형태처럼 도출해야합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;key=value&amp;amp;key2=value2&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 제공하는 API에서는 key에 들어가는 경우는 모두 영어이며 외부로부터 직접적인 위해를 가하지 못하기 때문에 value에 대해서만 검증을 하고 변환작업을 수행하면 됩니다.&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.1 코드 구현하기&lt;/h4&gt;
&lt;pre id=&quot;code_1696763117716&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * data를 받아 EUC-KR 문자열로 변환합니다.
 */
function convertToEucKrBuffer(obj: Data): string {
	let buffer = '';
	Object.entries(data).forEach(([key, value]) =&amp;gt; {
      // iconv로 EUC-KR로 변환한 데이터를 HEX(16진수) String을 받아 2칸씩 자릅니다.
  	buffer += 
		`${key}=${appendPercentPer2Byte(
			iconv.encode(value, EUC_KR).toString('hex')
			)
		}&amp;amp;`;
	});

	return buffer.slice(0, -1);
}

/**
 *  HEX(16진수) String을 받아 2칸마다 % 기호를 추가합니다.
 */
function appendPercentPer2Byte(str: string): string {
	return [...value].reduce((acc, cur, idx) =&amp;gt; {
		if (idx % 2 === 0) {
			return `${acc}%${cur}`;
        }
		return `${acc}${cur}`;
	}, '');
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.2 처리하면서&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. iconv-lite에서 encoding을 통해 출력을 해보면 Buffer에 잘 들어간다. 하지만 toString을 해보면 '%' 기호가 빠진다. 별도로 추가해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. JS에서 console.log 할 때, ? 표시가 뜨는 이유는 해당 인코딩을 지원하지 않아 발생하는 문제일 수 있다. 그럴 땐, decode 사이트를 이용해서 변환확인을 해봐야 한다.&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;서비스간에 사용하는 encoding을 확인하고 개발하는 습관을 항상 가지기&lt;/p&gt;</description>
      <category>Problem Solving/작업일기</category>
      <author>djunnni</author>
      <guid isPermaLink="true">https://djunnni.tistory.com/31</guid>
      <comments>https://djunnni.tistory.com/31#entry31comment</comments>
      <pubDate>Mon, 9 Oct 2023 13:07:05 +0900</pubDate>
    </item>
    <item>
      <title>Node.js 12에서 16로 한번에 업데이트 적용후기 - 배포편</title>
      <link>https://djunnni.tistory.com/25</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;도입&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@djunnni/Node.js-12%EC%97%90%EC%84%9C-16%EB%A1%9C-%ED%95%9C%EB%B2%88%EC%97%90-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8-%EC%A0%81%EC%9A%A9%ED%9B%84%EA%B8%B0-%ED%99%98%EA%B2%BD-%EC%84%B8%ED%8C%85%ED%8E%B8&quot;&gt;Node.js 12에서 16로 한번에 업데이트 적용후기 - 환경 세팅편&lt;/a&gt;에 이어 2번째 편이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포 프로세스(무중단 배포 등)에 대해 자세히 다루긴 어렵지만 간단하게 어떻게 환경들을 맞춰나가고 진행을 해나갔는지만 적어보자.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;_무중단 배포와 관련해서는 앞으로 구름 블로그 또는 팀원으로 들어오시면 더 자세하게 알 수 있습니다!!&lt;br /&gt;_&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;진행전 공유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 우리 환경은 다음과 같았다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;제목&lt;/th&gt;
&lt;th&gt;개발서버&lt;/th&gt;
&lt;th&gt;배포서버&lt;/th&gt;
&lt;th&gt;운영서버&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ubuntu&lt;/td&gt;
&lt;td&gt;18.04&lt;/td&gt;
&lt;td&gt;16.04&lt;/td&gt;
&lt;td&gt;18.04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;python&lt;/td&gt;
&lt;td&gt;3.7.2&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gcc&lt;/td&gt;
&lt;td&gt;7.4.0&lt;/td&gt;
&lt;td&gt;4.8&lt;/td&gt;
&lt;td&gt;4.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;node.js&lt;/td&gt;
&lt;td&gt;12.xx&lt;/td&gt;
&lt;td&gt;12.0x&lt;/td&gt;
&lt;td&gt;12.xx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm&lt;/td&gt;
&lt;td&gt;6.xx&lt;/td&gt;
&lt;td&gt;6.xx&lt;/td&gt;
&lt;td&gt;6.xx&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. python과 gcc 버전 올리기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올리게 된 이유는 관련된 dependency가 있는 node-gyp에서 python3.6버전, gcc 5.2.0 이상을 요구했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;python3 업데이트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;python3 --version
# Python 3.5.2
sudo add-apt-repository ppa:deadsnakes/ppa # 해당 PPA가 python 공식인듯? 최근 3.9까지 릴리즈함.
sudo apt-get update
sudo apt-get install python3.6 -y

# python3 버전 수동 변경
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5 2

# 해당 버전 선택
sudo update-alternatives --config python3
There are 2 choices for the alternative python3 (providing /usr/bin/python3).

  Selection    Path                Priority   Status
------------------------------------------------------------
* 0            /usr/bin/python3.5   2         auto mode
  1            /usr/bin/python3.5   2         manual mode
  2            /usr/bin/python3.6   1         manual mode
Press &amp;lt;enter&amp;gt; to keep the current choice[*], or type selection number: 2

python3 --version
# Python 3.6.2&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;gcc 업데이트
&lt;pre class=&quot;smali&quot;&gt;&lt;code&gt;#ppa 추가
add-apt-repository ppa:ubuntu-toolchain-r/test
apt-get update
apt-get install gcc-5 g++-5
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;버전확인&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gcc --version&lt;br /&gt;g++ --versionn&lt;/p&gt;
&lt;h1&gt;패키지 관리 목록&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sudo update-alternatives --display gcc&lt;/p&gt;
&lt;h1&gt;sudo update-alternatives --install&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;priority가 낮으면 높은 우선순위&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 10&lt;br /&gt;sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 20&lt;br /&gt;sudo update-alternatives --config gcc&lt;br /&gt;There are 2 choices for the alternative gcc (providing /usr/bin/gcc).&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Selection Path Priority Status&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0 /usr/bin/gcc-4.8 20 auto mode&lt;br /&gt;1 /usr/bin/gcc-4.8 20 manual mode&lt;br /&gt;2 /usr/bin/gcc-5 10 manual mode&lt;br /&gt;Press enter to keep the current choice[*], or type selection number: 2
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. git version 올리기&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/djunnni/post/3c34f9ca-e87e-4584-bfa9-c51fa07fca59/Untitled.png&quot; alt=&quot;husky 버전업 이슈&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;husky에서 요구하는 최소 버전이 2.13.0 이상이다.&lt;br /&gt;2.7.4을 사용하고 있었기에 올릴 필요가 있었다.&lt;/p&gt;
&lt;pre class=&quot;smali&quot;&gt;&lt;code&gt;sudo add-apt-repository ppa:git-core/ppa -y
sudo apt-get update
sudo apt-get install git -y&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. npm cache clean -f&lt;/h3&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;npm cache clean -f &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 실행해줬다. 앞서 npm6에 깔린 cache들을 전부 날려주고 다시 설치하기 위함.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. npm isntall&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git pull을 받아 앞서 적용된 node16에서의 package-lock.json이 존재한 상황이다.&lt;br /&gt;npm install을 운영서버나 배포서버에서 자유롭게 설치가 가능해졌다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. forever app restartall&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forever를 통해 restart 하면서 새롭게 적용된 node16이 완료됨.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 일부러 hotfix를 열어 자동배포가 가능한지 확인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정서버로 자동배포가 되게 테스트를 진행함. 문제가 보이지 않아 일단은 완료.&lt;br /&gt;혹시나 싶어 2-3일은 수동배포도 병행하도록 체크.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 개발팀에 node16설치방법 문서공유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node16으로 환경을 바꿔서 개발할 수 있도록 팀원에게 문서를 공유했고 미리 세팅을 할 수 있도록 조치를 취했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 먼저 올라온 PR의 경우에는 node16으로 적용하고 다시 테스트를 해본 뒤 적용하도록 요청을 드렸다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. node16&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;앞으로 해당 서비스는 node16으로 동작하면서 FE에서만 적용했던 javascript 새로운 문법을 BE에서도 사용할 수 있게 되었다.&lt;/b&gt;&lt;br /&gt;팀원들이 코딩하는데에 불편사항을 해소시켜 줄 수 있어서 다행이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TODO&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 앞으로 해야할 부분은 lagacy에 대한 peer dependency를 마저 조사하고 하나씩 버전업을 진행해야 한다.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;2. code내에 우리가 따로 package.json에 명시하지 않은채 import해서 사용하고 있는 라이브러리는 없는지 추가 체크&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고사이트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.koriel.kr/gcc-g-dareun-beojeon-cugahago-paekiji-gwanrihagi/&quot;&gt;GCC, G++ 다른 버전 추가하고 패키지 관리하기&lt;/a&gt;&lt;/p&gt;</description>
      <category>Problem Solving/작업일기</category>
      <category>nodejs</category>
      <author>djunnni</author>
      <guid isPermaLink="true">https://djunnni.tistory.com/25</guid>
      <comments>https://djunnni.tistory.com/25#entry25comment</comments>
      <pubDate>Mon, 9 Oct 2023 00:00:18 +0900</pubDate>
    </item>
    <item>
      <title>2023년 9월 10일 - 너디너리 데모데이</title>
      <link>https://djunnni.tistory.com/30</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #3b3b3b;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt;오늘 너디너리 데모데이에 다녀오면서 여러 세션을 들어봤다.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt;들어본 이야기중 괜찮아 남겨보고 싶었다.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #0451a5;&quot;&gt;1.&lt;/span&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt; 근간이 되는 능력을 기르면 새로운 지식을 빠르게 받아드릴 수 있다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #0451a5;&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt; 지속적으로 작은 성공을 해보기&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #0451a5;&quot;&gt;3.&lt;/span&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt; 실패하길 두려워하지 말기&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #0451a5;&quot;&gt;4.&lt;/span&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt; one way door, two way door에 대해 전략을 펼쳐보기&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #0451a5;&quot;&gt;&amp;nbsp; &amp;nbsp; -&lt;/span&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt; 실패를 빨리하면 할수록 리스크는 줄어든다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #0451a5;&quot;&gt;5.&lt;/span&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt; 문서작성능력은 꾸준히 하자&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;</description>
      <category>회고록/Daily</category>
      <category>너디너리데모데이</category>
      <author>djunnni</author>
      <guid isPermaLink="true">https://djunnni.tistory.com/30</guid>
      <comments>https://djunnni.tistory.com/30#entry30comment</comments>
      <pubDate>Sun, 8 Oct 2023 15:48:30 +0900</pubDate>
    </item>
    <item>
      <title>2023년 5월 30일 - SSAFY 마지막 일</title>
      <link>https://djunnni.tistory.com/29</link>
      <description>&lt;p&gt;삼성청년 SW 아카데미 마지막일입니다.&lt;/p&gt;
&lt;p&gt;마지막까지 프로젝트를 진행하고 퇴소하게 되었는데 회고로 남기고 싶어서 글을 써봤습니다.&lt;/p&gt;
&lt;p&gt;SSAFY(삼성 청년 SW 아카데미)는 1년의 교육과정으로 상반기에는 자바를 활용한 알고리즘, Spring, MySQL에 대해서 사용하는 방법을 배울 수 있으며 하반기에는 공통, 특화, 자율 3가지 프로젝트를 진행할 수 있습니다.&lt;/p&gt;
&lt;p&gt;SSAFY에 입과했던 이유로는 2가지가 있습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Java 계열로 백엔드 역량을 쌓고 싶었던 점&lt;/li&gt;
&lt;li&gt;개발자 커뮤니티에 참여해보고 싶었던 점&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 두가지를 이루는데, SSAFY는 많은 도움이 되었던 것 같네요. 뛰어난 친구들과 함께 프로젝트를 진행하면서 이뤄보고 싶었던 목표를 달성해볼 수 있었습니다.&lt;/p&gt;
&lt;p&gt;그 밖에 SSAFY에서 AWS 서비스를 직접 신청해보면서 금액안에서 해결해볼 수 있는 방안들을 모색하고 적용해볼 수 있어 즐거웠습니다.&lt;/p&gt;
&lt;p&gt;2023년 취업시장은 어려운 상황인 것 같습니다. 뛰어난 친구들이 모두 상반기 코테, 면접에서 떨어지고 있으며 컨설턴트님들도 말씀하시는 것 만큼 상황이 좋지 못합니다. 저 역시도 면접에서 좋은 성과를 얻지 못한 적이 많습니다. 그래도 꾸준히 노력해보며 블로그나 글로 계속 표현해보려고 합니다 :)&lt;/p&gt;
&lt;p&gt;싸피를 통해 얻은 건&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;동료&lt;/li&gt;
&lt;li&gt;알고리즘 자신감&lt;/li&gt;
&lt;li&gt;개발자로서 동기부여 (앞으로 열심히 살기)&lt;/li&gt;
&lt;li&gt;스프링을 활용한 서비스 개발 능력&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PS) 싸피 마지막들어 BEST MEMBER가 한 번 됐네요. 받아보기 어려운 거 같아요 ㅎ&lt;br&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDA7BX/btsxrjz0qzR/sbK9ckcGXBWkCTw7w5qu9k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDA7BX/btsxrjz0qzR/sbK9ckcGXBWkCTw7w5qu9k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDA7BX/btsxrjz0qzR/sbK9ckcGXBWkCTw7w5qu9k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDA7BX%2Fbtsxrjz0qzR%2FsbK9ckcGXBWkCTw7w5qu9k%2Fimg.jpg&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;그 밖에 프로젝트하면서 동료들로부터 좋은 평가를 받아볼 기회가 있어서 공유하려고 합니다. 사회에서 많은 분들과 프로젝트 할 때에도 기록으로 항상남겨보고 반성해봐야겠어요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJ7zZr/btsxh8zJSLf/Ac4mRuym2K7bPoKitT8N31/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJ7zZr/btsxh8zJSLf/Ac4mRuym2K7bPoKitT8N31/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJ7zZr/btsxh8zJSLf/Ac4mRuym2K7bPoKitT8N31/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJ7zZr%2Fbtsxh8zJSLf%2FAc4mRuym2K7bPoKitT8N31%2Fimg.jpg&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kEVdd/btsxg4jSXl9/xM6NdU0NymlOzX80LmV6Nk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kEVdd/btsxg4jSXl9/xM6NdU0NymlOzX80LmV6Nk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kEVdd/btsxg4jSXl9/xM6NdU0NymlOzX80LmV6Nk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkEVdd%2Fbtsxg4jSXl9%2FxM6NdU0NymlOzX80LmV6Nk%2Fimg.jpg&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>회고록/Daily</category>
      <category>SSAFY 퇴소</category>
      <author>djunnni</author>
      <guid isPermaLink="true">https://djunnni.tistory.com/29</guid>
      <comments>https://djunnni.tistory.com/29#entry29comment</comments>
      <pubDate>Sun, 8 Oct 2023 15:47:16 +0900</pubDate>
    </item>
    <item>
      <title>2023년 4월 7일 - SSAFY 2번째 프로젝트 종료</title>
      <link>https://djunnni.tistory.com/28</link>
      <description>&lt;h3&gt;들어가며&lt;/h3&gt;
&lt;p&gt;SSAFY 8기 두번째 프로젝트(특화)가 종료됐습니다.&lt;/p&gt;
&lt;p&gt;프로젝트를 진행하면서 스스로 회고를 해보면 좋겠다는 생각이 들었어요.&lt;/p&gt;
&lt;h3&gt;잘한 점&lt;/h3&gt;
&lt;h4&gt;1. MSA(Micro Service Architecture)&lt;/h4&gt;
&lt;p&gt;이번 프로젝트에서 처음으로 MSA를 활용하면서 Eureka, Spring Cloud Gateway, 각 어플리케이션 서비스 서버와 데이터베이스를 따로 두는 경험을 했습니다.&lt;/p&gt;
&lt;p&gt;다같이 학습을 위해 기간 중 일주일을 공부하는데 시간을 쏟았습니다. 확실히 그 주에 끝내겠다는 생각으로 강의를 접하니까 어떻게 구현해야할 지 보이고 설계도 편했습니다.&lt;/p&gt;
&lt;p&gt;다만 실제로 여러 서비스가 함께 구동되며 동작하다보니 타 어플리케이션에서 Transaction 중 Request를 받으면 검증 차 방문해도 데이터를 읽어올 수 없어 동기화 문제도 발생했었습니다.&lt;/p&gt;
&lt;p&gt;| 카프카를 통해서 데이터베이스의 Sync를 맞춘다던지, Read, Write를 나누어 하나의 데이터베이스에서 필요한 내용을 읽게 한다는 등 다른 방법들을 알아보는 시간이 필요할 것 같아서 마지막 프로젝트에서 적용해볼 예정입니다.&lt;/p&gt;
&lt;p&gt;그 밖에 필요한 API 호출에 대해서 문서정리를 잘 했다는 게 뿌듯했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCxwlP/btsxkiIRRI8/DxsytYHXWwywnJEa2F3Rdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCxwlP/btsxkiIRRI8/DxsytYHXWwywnJEa2F3Rdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCxwlP/btsxkiIRRI8/DxsytYHXWwywnJEa2F3Rdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCxwlP%2FbtsxkiIRRI8%2FDxsytYHXWwywnJEa2F3Rdk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;필요한 서비스에 따라 &lt;code&gt;Tag&lt;/code&gt;로 구분지어 필요한 API를 상세보기 구현해 두었습니다. &lt;/p&gt;
&lt;p&gt;서비스간 시퀀스 다이어그램을 통해 전달되는 과정을 간략히 설명, Request, Response 그 밖에 DTO에 대해 작성해두어 FE, 다른 어플리케이션에서 수월히 사용하는데 지장이 없었고 질문도 적었습니다.&lt;/p&gt;
&lt;p&gt;이 부분은 다음번에도 잘 챙겨가야겠습니다.&lt;/p&gt;
&lt;h4&gt;2. JPA&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;이번에는 queryDSL을 사용하지 않고 JPA, JPQL만으로 개발을 해봤습니다. 이번에 새롭게 배운 건 hibernate에서 CRUD에 대한 쿼리가 한 트랜잭션에서 발생할 때, 순서가 정해진다는 걸 알았습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;어떻게 확인했었냐면 바로 delete 후, insert를 새롭게 하는데 중복 ID에 걸렸던 상황이 있었기 때문입니다. 검색읉 통해 좀 새로운 부분을 알았습니다.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;p&gt;집계 함수(group by) 사용 시, JPQL에서 리턴은 &lt;code&gt;Object[]&lt;/code&gt;로 받는 다는 점입니다. 그렇기 때문에 해결하는 방법으로는 &lt;/p&gt;
&lt;p&gt; 2-1. interface dto를 만들어서 받는 방법(이번)&lt;br&gt; 2-2. queryDSL&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;앞으로도 queryDSL을 사용할 기회가 많다고 생각해 직접 JPQL + interfaceDTO를 만들어서 진행해봤습니다.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;JPA에서 deleteAll에 대해서 여러번 요청이 발생하는 것을 방지하기 위해서 deleteAllInBatch를 통해서 지운 방법이 신선했습니다. 다만 놀란 건 아래와 같은 쿼리 처리..?&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;Hibernate: delete from deposit_transaction_history where 
transaction_history_id=? or 
transaction_history_id=? or 
transaction_history_id=? or 
transaction_history_id=? or 
transaction_history_id=? or 
transaction_history_id=?&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이럴거면 직접 JPQL로 작성하는 게 더 이득이라고 판단하기까지 했었죠.&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;순환참조 무한루프&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;양방향관계에 대해서는 여전히 어렵다고 느껴지긴 하는데 무조건 좋다고는 생각이 안들더군요. 어짜피 Lazy로딩을 하는 경우도 있을 것이고 또한 어딘가로 PK를 넘겨서 바로 전체조회를 하는 경우도 있었기에 적절한 JOIN을 고려하는 생각도 해봐야겠습니다.&lt;/p&gt;
&lt;p&gt;이번에 무한루프는 ToString을 양방향관계의 1부분에서 막아서 해결했습니다. 운영상 알 필요가 없는 부분이었죠.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;delete에 대한 flush를 할 필요성&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;레코드를 삭제하다보면 특정경우에 select문만 수행하고 제거를 안합니다. 제가 파악했을 땐, 연관관계에 속해있거나 어딘가에 참조가 되어있어 스스로 삭제가 못하게 된 것으로 보여 flush를 통해 entityManager를 DB와 적절한 동기화를 수행해야 한다고 생각합니다.&lt;/p&gt;
&lt;h4&gt;Sonarqube&lt;/h4&gt;
&lt;p&gt;소나큐브를 통해 codesmell을 많이 줄여나갈 수 있었습니다. 덕분에 스스로도 정적인 부분의 코드를 수정하고 필요한 annotation을 재정비할 수 있었습니다.&lt;br&gt;기회가 되면 테스트 코드까지 검증을 받아야겠습니다.&lt;/p&gt;
&lt;h3&gt;부족한 점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;엔티티 설계 대한 고민을 많이 하지 못한 점&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;항상 모든걸 다 만들고 할 수는 없지만 적어도 entity에 대한 모델 검증은 확실히 진행해야겠다고 생각했습니다. 안그러면 시간이 지나 모델이 무너져 애매하게 쿼리와 코드를 작성하기 때문입니다. 사전에 방지할 수 있도록 모델은 신중해야 겠습니다.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;TEST code의 부족함&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;테스트 코드를 이번에 많이 작성하지 못했는데 그 이유로 꼽은 건 OCP, LSP, DIP를 많이 지키지 못했던 것 같습니다. MVC 패턴에서도 각 모델 간에 운영할 코드가 있을 텐데 service레이어에서만 다루는게 맞을 까 고민하다보니 구분을 잘 짓지 못했던게 아닐까 싶습니다.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;WebClient&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;WebFlux에서 WebClient는 RestTemplate를 대체할 중요한 요소라고 생각합니다. 이번에 사용은 했지만 적절한 API 핸들링이 부족했다고 판단되어 시간되면 공부가 필요할 것 같습니다.&lt;/p&gt;
&lt;h3&gt;앞으로&lt;/h3&gt;
&lt;p&gt;앞으로 위에 나온 부족한 점을 채우고 팀원과 프로젝트에 대한 충분한 소통과 함께 격려할 수 있는 프로젝트를 진행해야겠습니다.&lt;/p&gt;</description>
      <category>회고록/Daily</category>
      <category>SSAFY 특화프로젝트 회고</category>
      <author>djunnni</author>
      <guid isPermaLink="true">https://djunnni.tistory.com/28</guid>
      <comments>https://djunnni.tistory.com/28#entry28comment</comments>
      <pubDate>Sun, 8 Oct 2023 15:45:07 +0900</pubDate>
    </item>
    <item>
      <title>PL이 늘 고민해야 될 것</title>
      <link>https://djunnni.tistory.com/27</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #3b3b3b;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt;구름시절 함께 일하던 동료가 준 포스트잇이 생각나서 적어봤어요.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt;프로덕트 리더가 조직의 프로덕트 방향을 이끄는 건 맞지만&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt;늘 고민해야 하는 건&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt;&quot;사용자에게 합리적인 가치를 전하는가?&quot;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt;&quot;사용자의 이용을 유지(Retiention)하기에 충분한가?&quot;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt;&quot;경험이 충분히 매끄러운가?&quot;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #3b3b3b;&quot;&gt;하는 부분이다. 제품에서도, 브랜딩에서도.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;</description>
      <category>회고록/Daily</category>
      <author>djunnni</author>
      <guid isPermaLink="true">https://djunnni.tistory.com/27</guid>
      <comments>https://djunnni.tistory.com/27#entry27comment</comments>
      <pubDate>Sun, 8 Oct 2023 15:42:15 +0900</pubDate>
    </item>
    <item>
      <title>Node.js 12에서 16로 한번에 업데이트 적용후기 - 환경 세팅편</title>
      <link>https://djunnni.tistory.com/24</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Node.js 버전을 올리게 된 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내에서 사용하는 Node.js 12를 쓰는 곳이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때문에 최신 javascript에 적용된 여러 기능(Nullish coalescing operator(??) 등)들을 사용하지 못하고 있어 팀원들의 요청사항이 생기고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마침 12버전은 2022년 4월 30일을 끝으로 유지보수 기간이 만료가 되기 때문에 최신 LTS로 한 번에 올려보기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업에 도움을 준 tyler, grey에게 고맙다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/djunnni/post/a70ae9ca-a1d1-46e4-9281-f2b8d380edda/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%209.28.50.png&quot; alt=&quot;node.js lts cycle&quot; /&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nodejs.org/ko/about/releases/&quot;&gt;https://nodejs.org/ko/about/releases/&lt;/a&gt; 에서 릴리즈를 확인할 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 올리기 전, 고려해야할 사항&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발, 배포, 운영서버의 환경을 점검해야 할 필요가 있었다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;ubuntu version&lt;/li&gt;
&lt;li&gt;python, gcc, git version&lt;/li&gt;
&lt;li&gt;node package version&lt;/li&gt;
&lt;li&gt;package version up에 따른 바뀔 code 확인&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번에 대해서는 배포를 진행하면서 중요하다는 걸 알게됐다.&lt;br /&gt;특정 packages에서 gcc와 python에 대해 최소버전을 명시했기 때문!&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 현재 상황&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;제목&lt;/th&gt;
&lt;th&gt;개발서버&lt;/th&gt;
&lt;th&gt;배포서버&lt;/th&gt;
&lt;th&gt;운영서버&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ubuntu&lt;/td&gt;
&lt;td&gt;18.04&lt;/td&gt;
&lt;td&gt;16.04&lt;/td&gt;
&lt;td&gt;18.04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;python&lt;/td&gt;
&lt;td&gt;3.7.2&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gcc&lt;/td&gt;
&lt;td&gt;7.4.0&lt;/td&gt;
&lt;td&gt;4.8&lt;/td&gt;
&lt;td&gt;4.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;node.js&lt;/td&gt;
&lt;td&gt;12.xx&lt;/td&gt;
&lt;td&gt;12.0x&lt;/td&gt;
&lt;td&gt;12.xx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm&lt;/td&gt;
&lt;td&gt;6.xx&lt;/td&gt;
&lt;td&gt;6.xx&lt;/td&gt;
&lt;td&gt;6.xx&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 전체 버전 업을 진행하기 전 내가 취한 작업은?&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;컨테이너 이미지를 node16에 맞춰 새롭게 만들었다.&lt;/li&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전 지식)&lt;br /&gt;구름의 모든 서비스는 goormIDE를 통해 개발환경을 구축하고 서비스를 배포 및 운영한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;기존 node12의 환경에서 package.json에 명시된 패키지들을 살펴보면서 git documentation을 읽으면서 node16을 지원하는 버전을 찾아서 올렸다.(하면서 bug-fix가 필요한 패키지도 함께 업데이트를 진행했고 모든 걸 한꺼번에 올릴 시 어디서 문제가 터지는 지 찾기 힘들어 2개씩 올려진행했다.)&lt;/li&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;React&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux, javascript-serialize 등&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;webpack&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;babel, babel plugin, @loadable, style-loader, sass-loader, node-sass, webpack-dev-middleware, webpack-hot-middleware 등&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;환경 세팅&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;husky, prettier, jest 등&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;버전이 올라가면서 모듈별 deprecated된 함수들을 찾고 올바른 사용법에 맞게 변경작업 시작&lt;/li&gt;
&lt;li&gt;[node12] 올바르게 변경된 부분은 git commit을 진행해서 publish 함.&lt;/li&gt;
&lt;li&gt;[node16] git pull로 바뀐 package.json을 설치해보고 구동시켜보기&lt;br /&gt;(당연히 다른 부분에서 에러가 터지므로 계속 반복)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 나는 어떻게 node16에 맞는 패키지를 찾았고 적용했지?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) webpack과 webpack-dev-middleware!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/djunnni/post/1c32affb-3b48-445b-a0ce-7c07a78cee50/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.18.33.png&quot; alt=&quot;webpack4 버전&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;webpack4, webpack-dev-middleware 3.7.2를 사용하고 있었다. 내 목표는 webpack-dev-middleware를 최신중에 4버전을 지원하는 구간을 찾아야했다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/djunnni/post/a70aae43-cc0a-4139-a335-cbb489d49508/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.21.38.png&quot; alt=&quot;webpack-dev-middleware&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;npm에 webpack-dev-middleware의 최신이 5.3.1임을 확인&lt;br /&gt;해당 패키지가 webpack4를 지원하는지 확인이 필요했다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/djunnni/post/042a8a41-a5f2-4920-831d-5652204e75f0/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.23.48.png&quot; alt=&quot;github,webpack-dev-middleware&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;webpack-dev-middleware의 패키지를 확인하고자 github으로 들어와 package.json을 열어봤다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/djunnni/post/25fd15c0-bbb4-4883-afac-503dafa20f26/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.24.52.png&quot; alt=&quot;github,webpack-dev-middleware peerdependency&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;아래로 내려보면 peerDependency로 webpack4를 지원하는 걸 확인 그러면 이제 할 작업은 3에서 5로 major버전이 2번 바뀌었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 사이에 바뀐 패치사항을 확인해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/djunnni/post/89c467f1-493d-471f-8cb9-405685ec4e86/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.31.29.png&quot; alt=&quot;release 노트확인&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;릴리즈 노트를 통해 major버전이 변경될 때, &lt;b&gt;features, breaking changes&lt;/b&gt;를 확인했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바뀐 부분이 있다면 code에도 적용을 시켜줘야해서 중요하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/djunnni/post/69418872-8e4e-4b96-89a7-710da89efa57/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.35.13.png&quot; alt=&quot;release 노트보고 제거할 옵션 찾기&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;아래에 보면 watchOptions가 지워졌다. 앞으로 webpack.config.js에서 가져다 써야 함으로 코드에 반영해주기로 했다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/djunnni/post/ab690649-f380-411f-ac95-f1a6001acb3c/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.36.32.png&quot; alt=&quot;watchOptions 넣기&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;webpack-dev-middleware는 3에서 5버전으로 올렸다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/djunnni/post/647f50a5-348d-4136-848b-c033e5e3248f/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.18.48.png&quot; alt=&quot;webpack-dev-middleware버전&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 실행해보면서 확인 완료.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 작업을 다른 패키지들에도 동일하게 진행했다. 생각보다 평소에 버전관리를 안하다보니 시간이 오래걸렸던 거 같다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. node12 -&amp;gt; node16으로 올리기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node버전을 올리는 방법은 nvm, n도 있지만 해당 방법으로 올리는 걸 비추천한다!&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;n을 통해 올렸을 경우, 아래와 같은 문제가 발생할 수 있다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n, nvm으로 올리면 node로 명령어를 실행했을 경우와 /usr/local/bin/node간의 명령어가 꼬이는 경우가 발생할 수 있다. 이 경우, EACCES가 발생할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/djunnni/post/395c405c-c441-4a8e-a6d3-96f8b647afe1/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.01.43.png&quot; alt=&quot;n으로 버전을 올렸을 경우&quot; /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;그러면 어떻게 올려야 할까?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 있던 node와 관련해 전부 지우고 curl로 node를 직접 받는 편이 좋다.&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;# node가 어디에 설치되어있는지 확인
whereis node

# node 관련 모든 경로 삭제
rm -rf /usr/bin/node
rm -rf /usr/include/node
rm -rf /usr/local/bin/node
rm -rf /usr/local/include/node # legacy-node 인듯
rm -rf /usr/share/man/man1/node*
rm -rf /usr/local/lib/node_modules/
rm -rf /usr/local/bin/npm
rm -rf ~/.npm
rm -rf ~/.node-gyp
apt remove nodejs -y

curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs
# 혹시 아래와 같이 뜬다면 node 6버전 부터 받고 다시 16버전 받는거 반복
# node -v
# The program 'node' is currently not installed. You can install it by typing:
# curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
# apt install nodejs&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. npm install&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node12에서 16으로 넘어오면서 npm 버전또한 6에서 8로 바뀌게 되었다.&lt;br /&gt;이 경우에는 설치를 하기 위해서&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;1. npm cache clean -f 
2. rm -rf node_modules, package-lock.json
3. npm install --legacy-peer-deps // peer-dependency가 맞지 않아도 일단 설치.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3번을 한 이유는, npm8로 넘어오면서 7일 때, 나온 peer dependency에서 막히면 설치를 멈추는 경우를 방지하기 위해서 진행했다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. 실행해보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 실행하던 방법으로 서버를 켜보고 package.json에 바뀐 리스트 중 몇가지 주요기능들에 대해 확인해봤다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다음이야기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 적어보면서 알게 된 점은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;무조건 버전 업이 정답은 아니지만 LTS는 파악할 수 있는 hook이나 기타 설정할 수 있는게 있을지 확인해보자&quot;&lt;br /&gt;&quot;개발과 운영환경의 설정은 최대한 같게 유지하자&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포와 관련해서는 다음 편에 적어보도록 할 예정이다.&lt;/p&gt;</description>
      <category>Problem Solving/작업일기</category>
      <category>LTS 개선</category>
      <category>nodejs 버전 관리</category>
      <author>djunnni</author>
      <guid isPermaLink="true">https://djunnni.tistory.com/24</guid>
      <comments>https://djunnni.tistory.com/24#entry24comment</comments>
      <pubDate>Sun, 8 Oct 2023 15:31:51 +0900</pubDate>
    </item>
  </channel>
</rss>