<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>kong_woon.log</title>
        <link>https://velog.io/</link>
        <description>좋은 문장이 될 FE 개발자</description>
        <lastBuildDate>Thu, 08 Jun 2023 09:49:55 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>kong_woon.log</title>
            <url>https://velog.velcdn.com/images/kong_woon/profile/f3b53fbc-c52a-4391-8041-20403e3bda12/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. kong_woon.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/kong_woon" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Nogwari] React GlobalStyle]]></title>
            <link>https://velog.io/@kong_woon/Nogwari-React-GlobalStyle</link>
            <guid>https://velog.io/@kong_woon/Nogwari-React-GlobalStyle</guid>
            <pubDate>Thu, 08 Jun 2023 09:49:55 GMT</pubDate>
            <description><![CDATA[<p>리액트에서 CSS 스타일을 주는 방법으로 Styled-component 를 주로 사용한다. 노과리 프로젝트에서도 마찬가지이다.
styled-components 의 <strong>createGlobalStyle</strong> 을 페이지에 적용하는 
방법을 알아보자.</p>
<p>ResetStyle.ts</p>
<pre><code class="language-js">import { css } from &quot;styled-components&quot;;
export const ResetStyle = css`
  a {
    color: inherit;
    text-decoration: none;
  }

  a:focus {
    outline: 0;
  }

  a:active,
  a:hover {
    outline: 0;
  }
`</code></pre>
<p>style 경로를 만들고 초기 설정할 디자인(reset.css)을 만든다. 여기서 정해준 CSS 요소는 전체 페이지에 들어갈 요소이다.</p>
<p>globalStyle.ts</p>
<pre><code class="language-js">import { createGlobalStyle } from &quot;styled-components&quot;;
import { ResetStyle } from &quot;./reset&quot;;

export const GlobalStyle = createGlobalStyle&lt;{ theme: Theme }&gt;`
${ResetStyle};
html {
  height: 100%;
}

`</code></pre>
<p>같은 경로에 globalStyle.ts 파일을 만들고 <code>createGlobalStyle</code> 을 가져온다. 이 녀석은 어플리케이션 레벨 스타일링을 하는 녀석이다. 우리가 컴포넌트 안에서 styled-component 로 만든 녀석들처럼 개별적으로 동작하는 게 아닌, 최상위 컴포넌트에서 이 녀석을 정의해두면 모든 컴포넌트에 해당 스타일이 적용된다. 여기에 우리가 reset 에 만든 ResetStyle 을 지정해준다.</p>
<p>App.js</p>
<pre><code class="language-js">import { GlobalStyle } from &quot;./styles/globalStyles.ts&quot;;

function App() {
    return (
      &lt;BrowserRouter&gt;
          &lt;GlobalStyle /&gt;
          &lt;header&gt;
              &lt;p&gt;
                      노과리 프로젝트
              &lt;/p&gt;
              &lt;/header&gt;
      &lt;/BrowserRouter&gt;
</code></pre>
<p>페이지의 최상단인 App 에서 위에서 만든 GlobalStyle 을 넣어주면, App 에서 라우터를 타는 모든 컴포넌트에 전역 디자인을 넣을 수 있게 된다</p>
<h3 id="▶-마치며">▶ 마치며</h3>
<blockquote>
<p>사실 테마까지 넣어서 다크 모드, 라이트 모드도 만들어서 블로그를 쓰고 싶었는데, 막혀서 나누어서 글을 쓴다. 
그저 그런 개발자와 뛰어난 개발자가 나누어지는 조건은, 이런 식으로 찡찡거리지 않는 게 아닐까? 잉웅앵웅</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NoGwari] EC2 Memory Swap]]></title>
            <link>https://velog.io/@kong_woon/NoGwari-EC2-Memory-Swap</link>
            <guid>https://velog.io/@kong_woon/NoGwari-EC2-Memory-Swap</guid>
            <pubDate>Thu, 08 Jun 2023 08:04:31 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>AWS EC2 에서 npm run start 를 할 때 일정 퍼센트에서 멈춘다면,,</p>
</blockquote>
<p>package.json 에 문제가 있나? npm 이 꼬였나? 한참 생각하다가, EC2 의 RAM 문제라는 것을 알았다.</p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/9c54c4b5-f737-4ee4-854f-746d8eabf88d/image.png" alt=""></p>
<p>스왑파일을 사용하여 메모리를 할당해주는 방법으로 문제해결이 가능하다.</p>
<h3 id="▶-swap-이란">▶ SWAP 이란?</h3>
<p>활성 상태가 아니거나 다른 데이터, 긴급히 필요하지 않은 RAM의 콘텐츠를 스왑 파일에 페이징해 RAM을 확보하는 것을 말한다.
파티션에 스왑 공간을 만들 수도 있다.</p>
<h3 id="▶-메모리-스왑">▶ 메모리 스왑</h3>
<blockquote>
<p><code>sudo dd if=/dev/zero of=/swapfile bs=128M count=16</code></p>
</blockquote>
<ol>
<li>스왑 파일을 생성
bs*count만큼 메모리가 할당된다. 
128M * 16 = 2gb 의 메모리가 할당</li>
</ol>
<blockquote>
<p><code>sudo chmod 600 /swapfile</code></p>
</blockquote>
<ol start="2">
<li>스왑 파일의 읽기 및 쓰기 권한을 업데이트 한다.</li>
</ol>
<blockquote>
<p><code>sudo mkswap /swapfile</code></p>
</blockquote>
<ol start="3">
<li>Linux 스왑 영역을 설정한다.</li>
</ol>
<blockquote>
<p><code>sudo swapon /swapfile</code></p>
</blockquote>
<ol start="4">
<li>스왑 공간에 스왑 파일을 추가하여 즉시 사용할 수 있도록 한다.</li>
</ol>
<blockquote>
<p><code>sudo swapon -s</code></p>
</blockquote>
<ol start="5">
<li>프로시저의 상태를 확인한다.
방금전에 생성한 파일이 보이면 성공이다.</li>
</ol>
<blockquote>
<p><code>sudo vim /etc/fstab</code></p>
</blockquote>
<ol start="6">
<li>vi 편집기로 위 파일을 열고 마지막 줄에 아래의 내용을 추가한다
부팅 시 스왑 파일을 시작하는 설정이다</li>
</ol>
<blockquote>
<p><code>/swapfile swap swap defaults 0 0</code></p>
</blockquote>
<ol start="7">
<li>free 명령어로 ec2 메모리 상태를 확인.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/cd1c32aa-2c18-4f00-b68e-486154475bde/image.png" alt=""></p>
<p>됐다!</p>
<h3 id="▶-마치며">▶ 마치며</h3>
<blockquote>
<p>나중에 더 고성능이 필요할 때는 비용을 지불하고 고성능 서버를 이용해야겠지? 돈 내는 거 무섭다</p>
</blockquote>
<p>이거 참고했다</p>
<p><a href="https://repost.aws/ko/knowledge-center/ec2-memory-swap-file">AWS - EC2 swap 에 대한 질문</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Nogwari] NPM 꼬였다
]]></title>
            <link>https://velog.io/@kong_woon/Nogwari-NPM-%EA%BC%AC%EC%98%80%EC%9D%84-%EB%95%8C</link>
            <guid>https://velog.io/@kong_woon/Nogwari-NPM-%EA%BC%AC%EC%98%80%EC%9D%84-%EB%95%8C</guid>
            <pubDate>Wed, 07 Jun 2023 06:46:05 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>npm ERR! Cannot read properties of null (reading &#39;resolve&#39;)</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/aeb1256d-8c66-499a-b764-6a47ebe7fa5c/image.png" alt=""></p>
<p>로컬에서 npm 이 꼬였을 때는 빠르게 커버가 가능하지만, EC2 서버에서 꼬였을 때는 좀 골치 아프다. node module 을 지우고 받을 때마다 시간이 너무 오래 걸리기 때문인데, 여러 번의 시도 끝에 다음 과정을 해결할 수 있었다</p>
<blockquote>
<ol>
<li><code>rm -r node_modules/</code></li>
</ol>
</blockquote>
<p>node_module 을 전체 삭제한다.</p>
<blockquote>
<ol start="2">
<li><code>npm cache clear --force</code></li>
</ol>
</blockquote>
<p>캐쉬를 지운다.</p>
<blockquote>
<ol start="3">
<li><code>npm install</code></li>
</ol>
</blockquote>
<p>재설치</p>
<p>나의 경우 타입스크립트를 나중에 추가하는 과정에서 에러가 났기 때문에 다음 명령어도 입력해준다.</p>
<h3 id="▶-추가">▶ 추가</h3>
<pre><code class="language-js">   for (let i = startIndex ?? 0; i &lt; array.length; i++) {
                             ^
SyntaxError: Unexpected token &#39;?&#39;
</code></pre>
<p>만약 위 에러가 날 경우에는 자바스크립트 버전이 nullish 병합을 허용하지 않는 버전이기 때문이다. 
아래 명령어를 입력해주면 된다.</p>
<blockquote>
</blockquote>
<p><code>sudo apt update</code>
<code>sudo apt install nodejs</code></p>
<h3 id="▶-마치며">▶ 마치며</h3>
<blockquote>
<p>동일한 package.json을 사용하더라도 Ubuntu의 Node.js 환경에서는 다른 Node.js 버전을 사용할 수 있습니다. 프로젝트를 실행하기 전에 node 명령어가 올바른 버전의 Node.js를 가리키는지 확인하고, 필요한 경우 Node.js 버전을 전환해야 한다. 이런 걸로 시간낭비 좀 그만하고 싶다</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Front] 시멘틱태그(sementic tag)]]></title>
            <link>https://velog.io/@kong_woon/Front-%EC%8B%9C%EB%A9%98%ED%8B%B1%ED%83%9C%EA%B7%B8sementic-tag</link>
            <guid>https://velog.io/@kong_woon/Front-%EC%8B%9C%EB%A9%98%ED%8B%B1%ED%83%9C%EA%B7%B8sementic-tag</guid>
            <pubDate>Mon, 05 Jun 2023 04:14:21 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/kong_woon/post/efa1b195-5e38-4ba1-a59f-bcac8e961f18/image.png" alt=""></p>
<h3 id="▶-시멘틱태그란">▶ 시멘틱태그란?</h3>
<p>Semantic은 &#39;의미의&#39;, &#39;의미론적인&#39;이라는 뜻을 가진 형용사이다. 
따라서 <strong>시맨틱 태그</strong>란 의미가 있는 태그를 말한다.</p>
<p>div나 span과 같이 의미가 없는 태그는 태그 이름만 보고는 어떤 내용인지 전혀 유추할 수가 없는 반면, form, table, article 등 의미가 있는 태그는 내용을 명확하게 정의한다.</p>
<p>그렇다면 의미있는 태그를 사용함으로써 얻는 장점은 무엇일까??</p>
<h3 id="▶-시멘틱태그의-장점">▶ 시멘틱태그의 장점</h3>
<blockquote>
<ol>
<li>SEO 최적화에 유리. (SEO: Search Engine Optimization)</li>
</ol>
</blockquote>
<p>검색엔진은 태그를 기반으로 페이지 내 검색 키워드의 우선순위를 판단한다. 따라서 제목은 h1, 중요한 단어는 strong 또는 em을 사용하는 등 의미에 맞는 올바른 태그를 사용하는 것이 중요하다.</p>
<blockquote>
<ol start="2">
<li>효율적인 웹 접근성</li>
</ol>
</blockquote>
<p>일반적인 브라우저에서는 차이가 없지만 스크린리더(시각장애인을 위한 웹 서핑 프로그램)와 같은 환경에서는 웹 접근성과 사용성을 향상시켜준다.</p>
<blockquote>
<ol start="3">
<li>유지보수의 용이성</li>
</ol>
</blockquote>
<p>의미가 있는 태그는 개발자에게 명확한 의미를 전달한다.
W3C에 따르면 &quot;시맨틱 웹을 사용하면 애플리케이션, 기업 및 커뮤니티에서 데이터를 공유하고 재사용할 수 있다&quot;고 한다.</p>
<p>예를 들어, 끝없는 div(div &gt; div &gt; div ...)를 탐색하는 것보다 시맨틱 태그를 사용한 코드 블록을 찾는 것이 훨씬 쉽다.</p>
<h3 id="▶-시멘틱태그의-종류">▶ <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element">시멘틱태그의 종류</a></h3>
<p><code>&lt;header&gt;</code> 
머리글, 제목, 헤더</p>
<p><code>&lt;nav&gt;</code> 
네비게이션, 목차, 리스트 등 다른 페이지로의 이동을 위한 링크 공간을 위주로 표현</p>
<p><code>&lt;aside&gt;</code> 
좌측과 우측 사이드 위치의 공간을 의미하며, 본문 외에 부수적인 내용을 주로 표현하는 태그</p>
<p><code>&lt;section&gt;</code> 
주제, 카테고리 별로 섹션을 구분하는 용도의 태그로 주로 사용. 같은 테마를 가진 여러개의 콘텐츠의 그룹화</p>
<p><code>&lt;article&gt;</code> 
기사, 블로그 등 텍스트 위주의 페이지를 구성할때 주로 사용. </p>
<p><code>&lt;footer&gt;</code> 
바닥글, 문서 하단에 들어가는 정보 구분 공간을 표현하는 태그</p>
<p><code>&lt;address&gt;</code> 
콘텐츠 작성자나 사이트 소유자의 정보등을 부가적으로 담는 기능</p>
<p><code>&lt;hgroup&gt;</code> 
제목과 관련된 부제목을 묶는 태그</p>
<p><code>&lt;main&gt;</code> 
이름처럼 문서 <code>&lt;body&gt;</code>의 중심 주제, 주요 내용 또는 응용 프로그램의 중심 기능과 직접 관련되어나 확장되는 콘텐츠를 나타낸다.</p>
<p><code>&lt;details&gt;</code> 
주변 문맥에서 표시된 구절의 관련성 또는 중요성으로 인해 참조 또는 표기 목적으로 표시되거나 강조된 텍스트를 나타냅니다.</p>
<p><code>&lt;figure&gt;</code> 
이미지, 다이어그램, 사진 등 독립적인 컨튼츠 정의시 사용</p>
<p><code>&lt;figcaption&gt;</code> 
<code>&lt;figure&gt;</code> 요소의 설명 캔션(caption) 정의</p>
<p><code>&lt;mark&gt;</code> 
현재 맥락에 관련이 깊거나 중요한 부분 강조</p>
<p><code>&lt;time&gt;</code> 
시간의 특정 지점 또는 구간, datetime과 같은 속성을 이용해 알림같은 기능 구현</p>
<p><code>&lt;summary&gt;</code> 
details 요소에 대한 요약, 캡션 또는 범례를 지정합니다. summary 요소를 클릭하면 상위 details 요소의 상태가 열리고 닫힙니다.</p>
<h3 id="▶-마치며">▶ 마치며</h3>
<blockquote>
<p>실무에서 본 시멘틱 태그는 header 와 nav, section, articel, footer 뿐이다. 블로그를 쓰면서 시멘틱 태그의 장점 중 SEO 최적화에 관련된 부분을 재고하는 기회가 되었다. 처음 프론트엔드를 하기로 공부했을 당시엔 이해 못하고 넘어간 부분들이 다시 공부했을 때 이해되는 쾌감, 지적 만족은 은은한 만족감을 갖게 한다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Nogwari] 구글 소셜 로그인 붙이기(로컬)]]></title>
            <link>https://velog.io/@kong_woon/Nogwari-%EA%B5%AC%EA%B8%80-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%B6%99%EC%9D%B4%EA%B8%B0%EB%A1%9C%EC%BB%AC</link>
            <guid>https://velog.io/@kong_woon/Nogwari-%EA%B5%AC%EA%B8%80-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%B6%99%EC%9D%B4%EA%B8%B0%EB%A1%9C%EC%BB%AC</guid>
            <pubDate>Mon, 05 Jun 2023 03:13:27 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/kong_woon/post/00d885b8-f138-4dbc-af04-d0efcd3fb909/image.png" alt=""></p>
<h3 id="▶-구글-소셜-로그인-과정">▶ 구글 소셜 로그인 과정</h3>
<h4 id="1-google-api를-요청하기-위해선-google-cloud-platform이하-gcp에서-oauth인증을-위해-사용할-애플리케이션을-등록하고-client-id와-client-secret을-받아와야-한다">1. Google API를 요청하기 위해선 Google Cloud Platform(이하 GCP)에서 OAuth인증을 위해 사용할 애플리케이션을 등록하고 Client ID와 Client Secret을 받아와야 한다.</h4>
<blockquote>
<p>1-1. 프로젝트 생성을 한다</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/0b5594f8-5bbc-4a5f-9ede-bdef69eb7fd7/image.png" alt=""></p>
<blockquote>
<p>1-2. OAuth 동의 화면을 다음과 같이 작성한다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/56ad805e-364d-4795-ba3e-bc7e7b9945fc/image.png" alt=""></p>
<blockquote>
<p>1-3. OAuth 클라이언트 아이디를 생성</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/7fcfb86b-c97b-4ec8-9d73-8fdc78e6c5f7/image.png" alt=""></p>
<blockquote>
<p>※ localhost 와 localhost:port 를 둘 다 적어주어야 한다!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/da89bba6-4ccc-491c-9b33-c7b438c80920/image.png" alt=""></p>
<blockquote>
<p>완료!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/c94cc2a4-8f83-48ed-b8bd-c24525170ed6/image.png" alt=""></p>
<h4 id="2-구글-로그인-코드-작성">2. 구글 로그인 코드 작성</h4>
<pre><code class="language-js">
import {GoogleLogin} from &quot;@react-oauth/google&quot;;
import {GoogleOAuthProvider} from &quot;@react-oauth/google&quot;;
import jwtDecode from &quot;jwt-decode&quot;;

const GoogleLoginButton = () =&gt; {
    const clientId = &#39;${clientKey}&#39;
    return (
        &lt;&gt;
            &lt;GoogleOAuthProvider clientId={clientId}&gt;
                &lt;GoogleLogin
                    onSuccess={(res) =&gt; {
                        console.log(jwtDecode(res.credential));
                    }}
                    onFailure={(err) =&gt; {
                        console.log(err);
                    }}
                /&gt;
            &lt;/GoogleOAuthProvider&gt;
        &lt;/&gt;
    );
};
</code></pre>
<h4 id="3-끝">3. 끝</h4>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/00d885b8-f138-4dbc-af04-d0efcd3fb909/image.png" alt=""></p>
<h3 id="▶-마치며">▶ 마치며</h3>
<blockquote>
<p>배포한 사이트에서 clientKey 가 허락되지 않았다는 이슈로 막히고 있다 문제 해결 뒤 그 과정을 공유하고자 한다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Nogwari] EC2 서버 포트 번호 지우기 & pm2]]></title>
            <link>https://velog.io/@kong_woon/Nogwari-EC2-%EC%84%9C%EB%B2%84-%ED%8F%AC%ED%8A%B8-%EB%B2%88%ED%98%B8-%EC%A7%80%EC%9A%B0%EA%B8%B0-pm2</link>
            <guid>https://velog.io/@kong_woon/Nogwari-EC2-%EC%84%9C%EB%B2%84-%ED%8F%AC%ED%8A%B8-%EB%B2%88%ED%98%B8-%EC%A7%80%EC%9A%B0%EA%B8%B0-pm2</guid>
            <pubDate>Fri, 02 Jun 2023 07:35:49 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/kong_woon/post/cc06d53c-8e57-44e3-9fe0-6b4294a4cf90/image.png" alt=""></p>
<h3 id="▶-3000-을-지우자">▶ :3000 을 지우자!</h3>
<p>당연히 내가 3000포트에서 실행주고 있기 때문에 3000포트로 접속해야 페이지 접속이 가능하다.</p>
<p>하지만 보통 웹페이지에 접근할 때는 뒤에 포트번호가 붙지 않는다.</p>
<p>여기서 우리가 알아야 할 건 일반적으로 우리가 웹페이지에 접속할 때는 기본 포트가 뒤에 붙어있는데, </p>
<p><strong>http의 경우 : 80</strong> 
<strong>https의 경우 : 443</strong> </p>
<p>이다.</p>
<p>기본 포트는 보이지 않도록 설정되있기 때문에 위 포트로 접속하면 포트는 보이지 않는다. 
http 프로토콜로 접속한 사이트에 <code>:80</code> 을 붙여도 80이라는 포트가 보이지 않게 된다는 것이다.</p>
<p>그렇기에 80 포트로 연결됐을 때 3000 포트로 리다이렉트만 해주면 된다.</p>
<p>아래는 그 명령어이다.</p>
<p>sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3000</p>
<p>이것만 하면 포트 번호를 지워도 잘 보인다! 라고 생각했는데, 접속 오류가 뜬다!</p>
<h3 id="▶-왜-오류가-떠">▶ 왜 오류가 떠?</h3>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/abb6c667-b918-4436-a6ad-6164cbbc1eba/image.png" alt=""></p>
<p>EC2 인스턴스 인바운드 규칙에 80 포트가 없기 때문이었다. 추가하면 된다.</p>
<h3 id="▶-터미널-꺼도-계속-남아있으면-좋겠어">▶ 터미널 꺼도 계속 남아있으면 좋겠어!</h3>
<p>인스턴스의 터미널을 종료할 경우 사이트가 뜨지 않는데, 이 문제를 해결하기 위해선 <code>pm2</code> 라이브러리를 사용하면 된다.</p>
<p><code>pm2</code> 는 백그라운드에서 서버를 실행시켜주기 때문에 인스턴스에서 서버를 종료해도 계속 배포 환경이 실행될 수 있게 해준다.</p>
<p>pm2 를 설치한 후</p>
<blockquote>
<p>sudo npm -g install pm2</p>
</blockquote>
<p>설치한 후 pm2 명령어를 통해 파일을 실행해보자.</p>
<blockquote>
<p>pm2 start &#39;npm start&#39;</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/c0729f8c-1c3f-491c-95cc-7c76d49cd08a/image.png" alt=""></p>
<p>이제 터미널을 종료해도 페이지가 잘 접속된다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Nogwari] 프론트 EC2 에 배포 2]]></title>
            <link>https://velog.io/@kong_woon/Nogwari-%ED%94%84%EB%A1%A0%ED%8A%B8-EC2-%EC%97%90-%EB%B0%B0%ED%8F%AC-2</link>
            <guid>https://velog.io/@kong_woon/Nogwari-%ED%94%84%EB%A1%A0%ED%8A%B8-EC2-%EC%97%90-%EB%B0%B0%ED%8F%AC-2</guid>
            <pubDate>Fri, 02 Jun 2023 05:59:43 GMT</pubDate>
            <description><![CDATA[<h3 id="▶-ssh를-통하여-인스턴스-접속">▶ ssh를 통하여 인스턴스 접속</h3>
<p>SSH를 통한 EC2 접속</p>
<p>인스턴스에 접속하기 위해서는 1편에서 만든 pem 파일(키페어)이 준비되어야 한다</p>
<p><code>ssh -i &quot;pem 파일명&quot; ubuntu@*********.ap-northeast-2.compute.amazonaws.com</code></p>
<p>터미널에 <code>ubuntu@ip-17</code> 로 시작하면 연결이 성공한 것이다.</p>
<h3 id="▶-설치">▶ 설치</h3>
<p>프로젝트를 실행하기 위해 인스턴스 서버에 설치할 것들은 다음과 같다.</p>
<p>npm
node.js
git
프로젝트(git clone)
업데이트</p>
<ol>
<li><p>우선 다음 명령어로 update를 진행줘야한다.
<code>sudo apt update</code></p>
</li>
<li><p>npm을 설치해준다.
<code>sudo apt install npm</code></p>
</li>
<li><p>node.js을 설치해준다.
<code>sudo apt install nodejs</code></p>
</li>
<li><p>git 을 설치한다.
<code>sudo apt install git</code></p>
</li>
<li><p>github에 등록된 나의 프로젝트 가져오기
<code>git clone https://github.com/~~~~~~~.git</code></p>
</li>
</ol>
<p>그리고 프로젝트 루트로 들어간 후</p>
<p><code>npm i</code> 이후 <code>npm run build</code> 를 하면 된다.</p>
<h3 id="▶-실행">▶ 실행</h3>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/a00051d7-d4df-456e-ac1b-54d56d991ddc/image.png" alt=""></p>
<p>배포 완료.</p>
<p>혹시 url 로 접속 시 페이지를 찾을 수 없다면 인바인드 규칙을 확인하자.</p>
<p>보안 그룹 -&gt; 인바운드 규칙 탭 -&gt; 인바운드 규칙 편집에서</p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/d5d5a678-c3e3-47c7-b4ec-3fc393493440/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/72d0d075-e345-470f-86ed-4cfcbeccbfb5/image.png" alt=""></p>
<p>해당 포트 번호를 추가해주면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Nogwari] 프론트 EC2 에 배포 1]]></title>
            <link>https://velog.io/@kong_woon/Nogwari-%ED%94%84%EB%A1%A0%ED%8A%B8-EC2-%EC%97%90-%EB%B0%B0%ED%8F%AC-1%ED%8E%B8</link>
            <guid>https://velog.io/@kong_woon/Nogwari-%ED%94%84%EB%A1%A0%ED%8A%B8-EC2-%EC%97%90-%EB%B0%B0%ED%8F%AC-1%ED%8E%B8</guid>
            <pubDate>Fri, 02 Jun 2023 05:25:31 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/kong_woon/post/9af0a730-a60e-4060-a2cd-ae969f0b51aa/image.png" alt=""></p>
<p><em><del>지우다보니 구멍투성이</del></em></p>
<p>노과리 프로젝트를 AWS EC2에 배포했다.</p>
<h3 id="▶-배포-과정">▶ 배포 과정</h3>
<ol>
<li>인스턴스 시작을 누른다</li>
</ol>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/e69a26fa-40fb-4695-82eb-015826dc1db5/image.png" alt=""></p>
<ol start="2">
<li>이름을 입력한다</li>
</ol>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/3b5fdf23-dd79-4d70-8a90-17f6654d308a/image.png" alt=""></p>
<ol start="3">
<li>가상 머신 OS 를 선택한다. (ubuntu 선택)</li>
</ol>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/dc919088-f6f3-428e-a158-b404d0bdfbb5/image.png" alt=""></p>
<ol start="4">
<li>키 페어 생성</li>
</ol>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/b3541170-654e-4aeb-912c-59805c5693fe/image.png" alt=""></p>
<ol start="5">
<li>네트워크 설정</li>
</ol>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/620734ed-f134-40b9-91a6-38a470a3c722/image.png" alt=""></p>
<ol start="6">
<li>인스턴스 유형 선택</li>
</ol>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/a0957c42-6c72-4059-b7e3-4e13f1dfb739/image.png" alt=""></p>
<p>이제 우리는 AWS EC2 인스턴스가 준비되었다!</p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/e557f628-dc71-4283-839e-dff56fa6cb4b/image.png" alt=""></p>
<p><del>2편에 계속</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Front] React 의 상태 관리]]></title>
            <link>https://velog.io/@kong_woon/CS-JWT-%EC%9C%A0%EC%A7%80%ED%95%98%EB%8A%94-%EB%B2%95</link>
            <guid>https://velog.io/@kong_woon/CS-JWT-%EC%9C%A0%EC%A7%80%ED%95%98%EB%8A%94-%EB%B2%95</guid>
            <pubDate>Sun, 28 May 2023 07:59:16 GMT</pubDate>
            <description><![CDATA[<h3 id="▶-react의-상태관리">▶ React의 상태관리</h3>
<p>리액트는 단방향 데이터 흐름을 가진다. 상위 컴포넌트에서 State를 가지고 이에 의존하는 하위 컴포넌트가 있다면 props로 해당 state를 넘겨준다.</p>
<p>만약 루트 컴포넌트에서 해당 state가 필요한 컴포넌트 사이에 다른 컴포넌트들이 많이 존재하면 심각한 <strong>Props Drilling</strong>이 발생하게 된다.</p>
<h3 id="▶-props-drilling-이-뭐야">▶ Props Drilling 이 뭐야?</h3>
<pre><code class="language-js">import React from &quot;react&quot;;
import &quot;./styles.css&quot;;

export default function App() {
  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;FirstComponent content=&quot;Who needs me?&quot; /&gt;
    &lt;/div&gt;
  );
}

function FirstComponent({ content }) {
  return (
    &lt;div&gt;
      &lt;h3&gt;I am the first component&lt;/h3&gt;;
      &lt;SecondComponent content={content} /&gt;|
    &lt;/div&gt;
  );
}

function SecondComponent({ content }) {
  return (
    &lt;div&gt;
      &lt;h3&gt;I am the second component&lt;/h3&gt;;
      &lt;ThirdComponent content={content} /&gt;
    &lt;/div&gt;
  );
}

function ThirdComponent({ content }) {
  return (
    &lt;div&gt;
      &lt;h3&gt;I am the third component&lt;/h3&gt;;
      &lt;ComponentNeedingProps content={content} /&gt;
    &lt;/div&gt;
  );
}

function ComponentNeedingProps({ content }) {
  return &lt;h3&gt;{content}&lt;/h3&gt;;
}</code></pre>
<p>props drilling이란 위 코드처럼 props를 하위 컴포넌트로 전달하는 과정에서 몇 개의 컴포넌트를 뚫고 들어가는 형태를 말한다.
props drilling이 너무 많이 발생하면 컴포넌트 의존성이 생기고, props를 추적하는 게 어려워진다. <del>그냥 딱 보기에도 어렵다</del></p>
<h3 id="▶-리덕스">▶ 리덕스</h3>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/33fd6bb5-3e82-477e-bac4-6346fa778e64/image.png" alt=""></p>
<p>전역 상태 저장소가 있고, 어디서든 해당 저장소에 접근할 수 있다면 문제는를 해결할 수 있다.</p>
<h3 id="▶-리덕스의-특징">▶ 리덕스의 특징</h3>
<p>Single source of truth
: 동일한 데이터는 항상 같은 곳에서 가지고 온다. 즉, 스토어라는 하나뿐인 데이터 공간이 있다.</p>
<p>State is read-only
: 상태는 Action이라는 객체를 통해서만 상태를 변경할 수 있다.</p>
<p>Change are made with pure function
: 변경은 순수 함수로만 가능하다</p>
<h3 id="▶-리덕스-장단점">▶ 리덕스 장단점</h3>
<p>장점 </p>
<blockquote>
<p>컴포넌트들의 의존성을 분리한다.
Redux DevTools 확장 프로그램을 이용해 상태 파악을 할 수 있다.</p>
</blockquote>
<p>단점</p>
<blockquote>
<p>수많은 설정 코드가 필요하다.
API 통신 관련 코드를 전역적으로 관리해야 한다.</p>
</blockquote>
<h3 id="▶-마치며">▶ 마치며</h3>
<p>위에서 아래로 가는 게 어려우니 그냥 공용 창고 하나 만들어놓고 집어넣고 꺼내쓰고 하자! 낙수효과는 유지보수가 어렵다.</p>
<p>이거 보는 게 낫다</p>
<p><a href="https://hanamon.kr/%ec%83%81%ed%83%9c%ea%b4%80%eb%a6%ac%eb%8f%84%ea%b5%ac-%ed%95%84%ec%9a%94%ec%84%b1/">https://hanamon.kr/%ec%83%81%ed%83%9c%ea%b4%80%eb%a6%ac%eb%8f%84%ea%b5%ac-%ed%95%84%ec%9a%94%ec%84%b1/</a> 하나몬 - 상태 관리 도구(State Management Tools)의 필요성</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Nogwari] ⚠️깃 인증 에러]]></title>
            <link>https://velog.io/@kong_woon/Nogwari-%EA%B9%83-%EC%9D%B8%EC%A6%9D-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@kong_woon/Nogwari-%EA%B9%83-%EC%9D%B8%EC%A6%9D-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Fri, 26 May 2023 06:13:13 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/kong_woon/post/5d003ecf-04b7-4223-8199-ded93beb8e8f/image.png" alt=""></p>
<blockquote>
<p><strong>The requested URL returned error: 403</strong>
이 녀석 때문에 1시간을 날렸다.</p>
</blockquote>
<p>403 오류는 해당 레포지토리 주소에 접근 권한이 없을 경우 발생한다고 한다.</p>
<p>프로젝트를 <code>clone</code> 후 첫 커밋을 푸쉬하려고 했는데 위와 같은 에러가 떴다. </p>
<h5 id="문제의-원인은-권한에-있었다">문제의 원인은 권한에 있었다.</h5>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/f16deb68-71ba-48cd-a3cf-00853d8c15c7/image.png" alt=""></p>
<p>깃허브에서 Organization 을 만들어 협업을 할 때 푸쉬를 하기 위해선 권한을 &#39;Member&#39; 가 아닌 &#39;Owner&#39; 로 줘야 한다. </p>
<p>이 오류로 시간이 오래 걸린 이유는, 
&#39;Member&#39; 권한에 레포지토리 생성 권한이 포함되어 있기 때문이다.
당연히 내가 만든 레포지토리에 푸쉬가 가능할 거라고 생각했는데, 도대체 레포지토리 만드는 건 &#39;Member&#39; 가 되는데, 푸쉬는 &#39;Owner&#39; 여야 하는지 모르겠다.</p>
<p>혹시 같은 에러가 나면, 깃 권한을 한 번 확인해보자.</p>
<blockquote>
<p>_ <code>user.email</code> 이 깃허브에 email 과 달라도 같은 에러가 날 수 있다. <code>git config --list</code> 로 확인해보자.
_</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] 브라우저 렌더링 원리]]></title>
            <link>https://velog.io/@kong_woon/JavaScript-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@kong_woon/JavaScript-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Fri, 26 May 2023 05:53:12 GMT</pubDate>
            <description><![CDATA[<h3 id="▶-브라우저-렌더링">▶ 브라우저 렌더링</h3>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/0056f8a1-fca0-476b-b460-f752aeb971c9/image.png" alt=""></p>
<p>브라우저 렌더링은 웹 페이지의 HTML, CSS, JavaScript 코드를 해석하고, 이를 시각적인 형태로 사용자에게 보여주는 과정을 말한다.  일반적으로 브라우저 렌더링 과정은 다음과 같다.</p>
<ol>
<li>HTML 파싱: 브라우저는 웹 페이지의 HTML 코드를 파싱하여 DOM(Document Object Model) 트리를 생성. DOM 트리는 HTML 문서의 계층 구조를 나타내며, 웹 페이지의 구조와 내용을 표현한다.</li>
</ol>
<p>-&gt; 따라서 브라우저가 아닌 Node 환경에서는 접근할 수 없다..!</p>
<ol start="2">
<li><p>CSS 파싱: 브라우저는 HTML 파싱 중에 외부 CSS 파일과 <code>&lt;style&gt;</code> 태그 내의 CSS 코드를 파싱하여 CSSOM(CSS Object Model) 트리를 생성한다. CSSOM 트리는 웹 페이지의 스타일 정보를 포함하며, DOM 트리와 연관되어 각 요소의 스타일 규칙을 결정한다.</p>
</li>
<li><p>렌더 트리 구축: DOM 트리와 CSSOM 트리를 결합하여 렌더 트리(Render Tree)를 생성한다. 렌더 트리는 화면에 실제로 표시되는 요소들로 구성되며, 각 요소의 시각적인 속성과 상대적인 위치를 가지고 있다. 
일부 요소들은 렌더 트리에 포함되지 않을 수도 있다. 예를 들어, <code>&lt;head&gt;</code> 태그 내의 요소들은 렌더 트리에 포함되지 않는다.</p>
</li>
<li><p>렌더 트리 배치: 브라우저는 렌더 트리를 기반으로 각 요소의 위치와 크기를 계산한다. 이 과정을 레이아웃(Layout) 이라고도 한다.
브라우저 창의 크기 변경 등과 같이 렌더링에 영향을 주는 변화가 발생할 때 다시 수행된다.</p>
</li>
<li><p>렌더 트리 그리기: 브라우저는 레이아웃이 완료된 후, 실제로 화면에 내용을 그립니다. 이 과정을 페인팅(Painting)이라 한다. 브라우저는 렌더 트리의 각 요소를 화면에 맞는 위치에 그린다.</p>
</li>
<li><p>상호작용: 브라우저는 사용자의 입력 및 상호작용에 대한 이벤트를 처리하고, 필요한 경우 변경된 부분만 다시 렌더링하여 적절한 반응성을 제공한다.</p>
</li>
</ol>
<p>이 과정은 브라우저(예: Chromium, Firefox 등)의 렌더링 엔진에 의해 수행되며, 브라우저에 따라 세부적인 동작과 최적화가 다를 수 있다.</p>
<h3 id="▶-dom이란">▶ DOM이란?</h3>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/42f46a28-02fd-45c8-a84b-5dfd47ab6fe3/image.png" alt="">
<a href="https://www.yalco.kr/@javascript-abyss/16-1/">얄코 - DOM의 개념</a> (DOM(Document Object Model) 트리)</p>
<h4 id="html-코드가-설계도라면-브라우저가-공장-브라우저에선-html-코드를-해석parsing-해서-dom-이라는-제품트리을-만든다">HTML 코드가 설계도라면 브라우저가 공장. 브라우저에선 HTML 코드를 해석(Parsing) 해서 DOM 이라는 제품(트리)을 만든다.</h4>
<h3 id="▶-마치며">▶ 마치며</h3>
<p>내가 쓴 코드가 화면에 어떻게 그려지는지 궁금하다. 개발자란 그런 궁금중을 실천하는 사람이어야 한다. 냅다 코드만 찍어내는 게 아니라</p>
<p>이거 보는 게 좋다
<a href="https://bbangson.tistory.com/87">https://bbangson.tistory.com/87</a> 웹 브라우저는 어떻게 작동하는가?
<a href="https://www.yalco.kr/@javascript-abyss/16-1/">https://www.yalco.kr/@javascript-abyss/16-1/</a> 얄코의 DOM 설명</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] async, await]]></title>
            <link>https://velog.io/@kong_woon/JavaScript-async-await</link>
            <guid>https://velog.io/@kong_woon/JavaScript-async-await</guid>
            <pubDate>Thu, 25 May 2023 11:11:14 GMT</pubDate>
            <description><![CDATA[<h3 id="▶-비동기-프로그래밍">▶ 비동기 프로그래밍</h3>
<p>엄마가 세탁기를 돌리고 청소를 하라고 했을 때,
세탁이 끝날 때까지 기다린 후 청소를 한다면 <strong>동기적 방식</strong>
세탁기를 누르고 청소를 하고 있다면 <strong>비동기적 방식</strong> 이다.</p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/da18de0e-1175-43d1-8e6d-916cc69115dd/image.png" alt=""></p>
<h3 id="▶-비동기-방식이-필요한-경우">▶ 비동기 방식이 필요한 경우</h3>
<ul>
<li><p>Web API 요청 (서버에서 데이터를 받아올 때)</p>
</li>
<li><p>파일 읽기 (서버 쪽에서 파일을 읽어올 때)</p>
</li>
<li><p>암호화/복호화</p>
</li>
<li><p>작업 예약 (몇 초 후에 해야 되는 작업이 필요할 때)</p>
</li>
</ul>
<h3 id="▶-async-await">▶ async await</h3>
<p>async/await는 비동기적인 작업을 처리할 수 있는 ES2017 문법이다.</p>
<p>async 함수를 정의하면 함수 내부에서 await 키워드를 이용하여 비동기적으로 처리되는 작업이 완료될 때까지 기다린 후, 결과값을 반환하는 처리를 할 수 있다. </p>
<p>만약 async 를 사용하지 않고 동기적으로 코드가 돌아가게 한다면,</p>
<pre><code class="language-js">
function sleep(ms) {
    return new Promise(resolve =&gt; setTimeout(resolve, ms));
}

const getDog = async () =&gt; {
    await sleep(1000);
    console.log(&#39;멍멍&#39;);
};

const getRabbit = async () =&gt; {
    await sleep(500);
    console.log(&#39;토끼토끼&#39;);
};
const getTurtle = async () =&gt; {
    await sleep(3000);
    console.log(&#39;거북거북&#39;);
};

async function process() {
    getDog();
    getRabbit();
    getTurtle();
}

process();

===================================

출력

토끼토끼
멍멍
거북거북
</code></pre>
<p>process 에선 멍멍이 -&gt; 토끼 -&gt; 거북이 순으로 호출해도 호출되는 순서는 토기 -&gt; 멍멍이 -&gt; 거북이 순이다. 이는 await 를 걸어두지 않았기 때문에 먼저 끝나는 녀석부터 화면에 나오기 때문이다.</p>
<pre><code class="language-js">
function sleep(ms) {
    return new Promise(resolve =&gt; setTimeout(resolve, ms));
}

const getDog = async () =&gt; {
    await sleep(1000);
    console.log(&#39;멍멍&#39;);
};

const getRabbit = async () =&gt; {
    await sleep(500);
    console.log(&#39;토끼토끼&#39;);
};
const getTurtle = async () =&gt; {
    await sleep(3000);
    console.log(&#39;거북거북&#39;);
};

async function process() {
    await getDog();
    await getRabbit();
    await getTurtle();
}

process();

===================================

출력

멍멍
토끼토끼
거북거북
</code></pre>
<p>이렇게 하면 제대로 나오는 것을 확인할 수 있다.</p>
<h3 id="▶-마치며">▶ 마치며</h3>
<p>첫 회사에 입사했을 때, API 를 호출 후 호출한 데이터를 이용해 차트를 만들어야 했는데, 제대로 호출한 것 같았는데 어쩔 때는 표가 제대로 나오고 어쩔 때는 표가 제대로 안 나와서 뭘까 했던 적이 있다. API 호출이 끝난 후 차트를 찍었어야 했는데, 차트가 렌더링된 후 API 호출이 끝났기 때문이다. 
지금 생각해보면 진짜 아무것도 몰랐던 시기였는데, 그 시기만큼 무언가를 빠르고 간절하게 흡수했던 적이 없었던 것 같다.</p>
<p>블로그 글보다 이거 보면 좋다
<a href="https://www.youtube.com/watch?v=m0icCqHY39U">https://www.youtube.com/watch?v=m0icCqHY39U</a> (얄코의 비동기 프로그래밍)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript]  Closure]]></title>
            <link>https://velog.io/@kong_woon/React-React-%EC%97%90%EC%84%9C%EC%9D%98-Closure</link>
            <guid>https://velog.io/@kong_woon/React-React-%EC%97%90%EC%84%9C%EC%9D%98-Closure</guid>
            <pubDate>Sun, 21 May 2023 04:26:35 GMT</pubDate>
            <description><![CDATA[<h3 id="▶-closure-란">▶ Closure 란?</h3>
<p>MDN 에선 Closure 를 이렇게 정의했다.</p>
<blockquote>
<p>클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. 클로저를 이해하려면 자바스크립트가 어떻게 변수의 유효범위를 지정하는지(Lexical scoping)를 먼저 이해해야 한다.</p>
</blockquote>
<p>렉시컬(lexical)의 의미는 &quot;문맥적 코드&quot; 이다. 
스코프(scope)의 의미는 &quot;유효 범위&quot; 이다.</p>
<p>결국 <strong>렉시콜 스코프</strong>는 <strong>문맥적으로 보는 코드의 유효 범위</strong></p>
<p><strong>렉시콜 스코핑</strong> 은 <strong>유효 범위를 지정하는 방법</strong> 을 뜻하는 것 같다.</p>
<pre><code class="language-js">function outer() {
  var name = &quot;kong&quot;; 

  function inner() {
    alert(name);
  }

  inner();
}
outer();
</code></pre>
<p>outer()함수를 실행하면 outer안에 있는 inner를 실행한다.
inner는 부모 함수에 있는 name 변수를 가져온다.
여기서 inner라는 함수의 위치. name 에 lexical scope 가 중요하다.</p>
<p>name이라는 변수는 outer의 지역 변수이다. 따라서 outer 외부에서는 사용할 수 없지만, 내부에서는 사용 가능하다. 그러므로 inner안에서도 해당 변수 name은 유효.</p>
<pre><code class="language-js">
const a = 1;

function outer(){
  const b = 2;
  const c = 3;

  function inner(){
    const b = 4;
    console.log(a, b, c);
  }
  inner();
}

outer();

=================

  출력: 1, 4, 3</code></pre>
<pre><code class="language-js">function madeAddr(x) {
    return function (y) {
        return x + y;
    }
}

const add3 = madeAddr(3);
console.log(add3(2)) // 5;

const add7 = madeAddr(7);
console.log(add7(2)) // 9;
console.log(add3(10)) // 13;
</code></pre>
<p>add3 함수가 생성된 뒤에도 상위함수인 makeAddr 의 x에 접근 가능하다.</p>
<p>즉 <strong>함수가 &quot;생성될 때&quot;의 외부 변수를 기억하여 생성 이후에도 계속 접근 가능한 것이 클로저</strong>이다.</p>
<p>정보와 은닉</p>
<pre><code class="language-js">
function makeCounter(){
    let count = 0; // 은닉화
    return function(){
        return count++;
    }
}

let counter = makeCounter();

console.log(counter()); // 0
console.log(counter()); // 1
console.log(counter()); // 2
</code></pre>
<p>위 코드의 count 라는 변수는 <strong>&quot;오직&quot;</strong> makeCounter 로만 수를 바꿀 수 있다. 이것을 은닉화라고 부른다.</p>
<h3 id="▶-마치며">▶ 마치며</h3>
<p>누군가 어떤 말을 했을 당시에 그 의미가 사랑과 존중이었어도 시간, 해석, 그 사람에 대한 편견, 상황에 따라 바뀐다.
입맛대로 가공되어 구석을 굴러다니는 단어들을 보고 있을 때면 &#39;말한다&#39;는 동사가 참 허무하다고 느낄 때가 있다.</p>
<p>JavaScript 에서의 &#39;의미&#39; 는 그에 비해 쉬운 편이다. 어떤 의미이든 <strong>생성되었을 때</strong> 의 상황과 정의만 기억하면 되니까.</p>
<p>도움받은 곳
<a href="https://www.youtube.com/watch?v=tpl2oXQkGZs">https://www.youtube.com/watch?v=tpl2oXQkGZs</a> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[jest] jest 를 이용한 코테 자체 테스트]]></title>
            <link>https://velog.io/@kong_woon/jest-jest-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%BD%94%ED%85%8C-%EC%9E%90%EC%B2%B4-%ED%85%8C%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@kong_woon/jest-jest-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%BD%94%ED%85%8C-%EC%9E%90%EC%B2%B4-%ED%85%8C%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Sat, 20 May 2023 10:58:46 GMT</pubDate>
            <description><![CDATA[<p>프로그래머스의 코딩 테스트를 보면</p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/6c210899-21de-4eea-a9c9-dbfc56783c45/image.png" alt=""></p>
<p>저렇게 테스트 케이스 추가하기가 있는데,</p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/f6ac907d-58f3-43f4-abb9-6eaf171c78f4/image.png" alt=""></p>
<p>이 녀석을 로컬에서 추가할 수 있으면 좋겠다고 생각해 Jest 를 사용해 자체 테스트를 도입해봤다.</p>
<h2 id="▶-jest-란">▶ jest 란?</h2>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/aa9f0252-badb-45ea-a41a-5b599d49ad7d/image.png" alt=""></p>
<p>Facebook(현 Meta) 출신의 jest는 React와 더불어 많은 자바스크립트 개발자들로 부터 좋은 반응을 얻고 있는 테스팅 라이브러리이다.
jest는 라이브러리 하나로, <strong>Test Runner</strong>와 <strong>Test Matcher</strong> 그리고 <strong>Test Mock</strong> 프레임워크까지 제공해준다고 하는데, 이 녀석들이 뭔지는 다음에.</p>
<h2 id="▶-사용법">▶ 사용법</h2>
<ol>
<li>설치</li>
</ol>
<p>npm 명령어를 통해 jest를 설치한다.</p>
<pre><code>npm i -D jest</code></pre><ol start="2">
<li>준비</li>
</ol>
<p>package.json 에서 스크립트 명령을 test 를 &#39;jest&#39; 로 변경한다.</p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/65b7fe48-4298-4287-933c-0fd6d7fcc365/image.png" alt=""></p>
<p>테스트할 대상의 기능을 모듈로 익스포트한다.</p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/a52a310e-aa9f-427d-b23b-bcf8e327e313/image.png" alt=""></p>
<p>테스트를 위한 파일을 만들고, 방금 익스포트했던 모듈을 임포트하여 테스트한다.</p>
<pre><code class="language-js">const oddEven = require(&quot;./oddEven.js&quot;);

it(&#39;짝수 홀수 테스트&#39;, () =&gt; {
    expect(oddEven.solution(7)).toBe(&quot;Odd&quot;);
});</code></pre>
<blockquote>
<p>Test 파일은 xxx.spec.js 혹은 xxx.test.js 형식으로 만들어야 한다.</p>
</blockquote>
<ol start="3">
<li>실행</li>
</ol>
<p>터미널에서 <code>npm test</code> 를 입력하면 끝</p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/99c4e0ad-c6c5-4260-b38b-a817c6f4d913/image.png" alt=""></p>
<p>※ <em>아래처럼 그룹으로 묶어서 테스트도 가능하다</em></p>
<pre><code class="language-js">describe(&#39;멋쟁이 테스트 그룹&#39;, () =&gt; {
    it(&#39;짝수 홀수 테스트&#39;, () =&gt; {
        expect(oddEven.solution(7)).toBe(&quot;Odd&quot;);
    });

    it(&#39;이진 탐색 테스트&#39;, () =&gt; {
        expect(binary.binarySearch([1,4,6,9,100,200], 9)).toBe(3);
    });
});</code></pre>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/7caaf2c2-76b8-4d51-acf5-edce3f671aaf/image.png" alt=""></p>
<h2 id="▶-그-외-jest-명령어">▶ 그 외 jest 명령어</h2>
<pre><code>toBe(a) // 예상한 값이 매개변수와 같은 값일 것인지 확인합니다.
toEqual(obj) // 매개변수(객체)와 같은 값일 것이라 예상합니다. 객체가 가진 값의 비교가 가능합니다.
not.toBe(a) // 뒤의 결과를 부정하는 값과 비교합니다.

toBeNull() // 예상한 값이 null 인지 확인합니다.
toBeUndefined() // 예상한 값이 undefined 인지 확인합니다.
toBeDefined() // 예상한 값이 undefined 가 아닌지 확인합니다.
toBeTruthy() // 예상한 값이 truthy 한 값인지 확인합니다.
toBeFalsy() // 예상한 값이 falsy 한 값인지 확인합니다.

toBeGreaterThan(number); // number보다 큰 값인지 확인합니다.
toBeGreaterThanOrEqual(number); // number보다 크거나 같은 값인지 확인합니다.
toBeLessThan(number); // number보다 작은 값인지 확인합니다.
toBeLessThanOrEqual(number); // number보다 작거나 같은 값인지 확인합니다.
toBeCloseTo(float) // float인 매개변수와 같은 값인지 확인합니다. 부동소수점 에러를 해결하기 위해 고안되었습니다.

toMatch(string) // string을 포함하는 문자열인지 확인합니다.
toContain(&#39;item&#39;) // item을 포함하는 배열(iterator)인지 확인합니다.

toThrow() // 예외를 발생시키는지 확인합니다.</code></pre><h2 id="▶-마치며">▶ 마치며</h2>
<p>간단한 유닛 테스트를 하나 작성해봤다.
이 글은 jest 에 관한 정말 기초적인 사용법이며 추후 jest 에 관해 더 올릴 생각이다.</p>
<p>jest 공식 문서
<a href="https://jestjs.io/docs/getting-started">https://jestjs.io/docs/getting-started</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자료구조] 이진탐색]]></title>
            <link>https://velog.io/@kong_woon/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%9D%B4%EC%A7%84%ED%83%90%EC%83%89%ED%8A%B8%EB%A6%AC</link>
            <guid>https://velog.io/@kong_woon/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%9D%B4%EC%A7%84%ED%83%90%EC%83%89%ED%8A%B8%EB%A6%AC</guid>
            <pubDate>Fri, 19 May 2023 05:59:18 GMT</pubDate>
            <description><![CDATA[<h3 id="▶-질문">▶ 질문</h3>
<blockquote>
<p>정렬된 자연수로 이루어진 배열 &#39;list&#39; 중 특정 수 &#39;num&#39; 의 index를 찾아야 한다. 최적의 알고리즘은 무엇인가?</p>
</blockquote>
<p>신입 면접 때 받았던 질문이다. 이진 탐색이 어떻게 쓰이는지 몰랐던 나는 아래와 같이 대답했다.</p>
<pre><code class="language-js">function solution(list, num) {
  return list.findIndex(x =&gt; x === num);
}</code></pre>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/fe354fe2-209f-4ccc-84ae-1e298b122ae2/image.png" alt=""></p>
<p>완벽한 오답이었다.</p>
<h3 id="▶-풀이">▶ 풀이</h3>
<p>면접관은 내게 이진 탐색에 관해 물어봤던 것이었다.
아래 코드는 위 코드와 같지만, 이진 탐색을 사용해 짠 코드이다.</p>
<pre><code class="language-js">function binarySearch(list, num) {
    let left = 0;
    let right = list.length-1;
    let mid = 0;

    while(left&lt;=right){

        mid = parseInt((left+right)/2)

        if(num === list[mid]) {
            return mid;
        } else{
            if(num &lt; list[mid]) {
                right = mid-1
            }
            else{
                left = mid+1
            }
        }
    }
}</code></pre>
<p>변수는 총 3개를 사용한다.</p>
<ul>
<li>최소 범위의 수를 뜻하는 left 변수(혹은 start)</li>
<li>최대 범위의 수를 뜻하는 right 변수(혹은 end)</li>
<li>특정 값이 담길 가운데 값 mid 변수</li>
</ul>
<p>중간 값 ( mid )보다 찾고자하는 값이 크다면 left의 값은 mid + 1이 되고</p>
<p>중간 값 ( mid )보다 찾고자하는 값이 작다면 right의 값은 mid -1이 된다.</p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/646ba006-611f-4da6-a6c7-45666b1c4b8c/image.png" alt=""></p>
<p>&#39;51&#39; 을 찾고 싶을 때 앞에서 수를 증가하면 5 step 이 필요하지만, 
앞 뒤로 하나씩 수를 올리고 줄여가며 원하는 숫자를 찾는다면, 3 step 이면 가능하다.</p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/bee40366-e556-4552-bf9f-f68c6e0cd286/image.png" alt=""></p>
<p>선형 탐색으로 문제를 해결했을 때는 O(n) 이지만
이진 탐색을 쓰면 시간복잡도가 O(logn) 이 된다. </p>
<p>실제로 이진탐색을 사용하면 풀리는 문제가 코딩 테스트나 백준 및 프로그래머스와 같은 사이트에서 많이  나오고 있다.</p>
<h3 id="▶-마치며">▶ 마치며</h3>
<p>소화화기 어려운 삶의 거대한 문제를 마주했을 때 순차적으로 문제를 해결하려 하지 말고 문제를 분류 후 하나씩 해결하다보면, 큰 문제를 효율적으로 해결하는 경우가 종종 있다. 이진 탐색을 통해 문제 해결에 대한 효율적인 접근 방식에 관해 더 치밀하게 고민해보자.</p>
<p>술자리에서 업다운 게임을 할 때만 이진 탐색을 하지 말고.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 달리기 경주 - JavaScript]]></title>
            <link>https://velog.io/@kong_woon/Algorithm-%EB%8B%AC%EB%A6%AC%EA%B8%B0-%EA%B2%BD%EC%A3%BC-JavaScript</link>
            <guid>https://velog.io/@kong_woon/Algorithm-%EB%8B%AC%EB%A6%AC%EA%B8%B0-%EA%B2%BD%EC%A3%BC-JavaScript</guid>
            <pubDate>Wed, 17 May 2023 13:11:27 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/kong_woon/post/45aca54f-01e2-4825-98b9-24cb6400de00/image.png" alt=""></p>
<p>[프로그래머스 - 달리기 경주]
(<a href="https://school.programmers.co.kr/learn/courses/30/lessons/178871">https://school.programmers.co.kr/learn/courses/30/lessons/178871</a>)
난이도 : Level 1
정답률 : 39%</p>
<h3 id="▶-풀이">▶ 풀이</h3>
<blockquote>
</blockquote>
<p>Player 를 index 를 value로 가진 Map 데이터로 전환 후 
callings 배열을 순회하며 경주 순위를 재설정</p>
<pre><code class="language-js">function solution(players, callings) {
    const playerMap = new Map();
    // 멥 데이터로 전환
    players.forEach((x, idx) =&gt; {
        playerMap.set(x, idx);
    })
    callings.forEach((v, idx) =&gt; {
       // 멥 세팅
        playerMap.set(v, playerMap.get(v) - 1);
        playerMap.set(players[playerMap.get(v)], playerMap.get(v) + 1);
      // player 배열 세팅
        const tmp = players[playerMap.get(v) + 1];
        players[playerMap.get(v) + 1] = players[playerMap.get(v)];
        players[playerMap.get(v)] = tmp;
    });
    return players;
}</code></pre>
<h3 id="▶-삽질">▶ 삽질</h3>
<pre><code class="language-js">function solution(players, callings) {
    callings.forEach(v =&gt; {
        const findPlayer = players.findIndex(p =&gt; p === v);
        const tmp = players[findPlayer];
        players[findPlayer] = players[findPlayer - 1];
        players[findPlayer - 1] = tmp;
    });
    return players;
}</code></pre>
<p><span style="color: red"> -&gt; findIndex 로 인덱스를 찾을 경우 시간복잡도가 O(n^2) 이 된다.
</span></p>
<h3 id="▶-다른-풀이">▶ 다른 풀이</h3>
<pre><code class="language-js">function solution(players, callings) {
    const rank = {};
    players.forEach((c,i) =&gt; rank[c] = i);
    for(const winner of callings){
        let winnerI = rank[winner];
        let loserI = winnerI - 1;

        rank[winner]--;
        rank[players[loserI]]++;

        players[winnerI] = players[loserI];
        players[loserI] = winner;
    }
    return players;
}
같은 방식이지만 가독성 면에서 훨씬 보기 좋다고 생각되는 풀이</code></pre>
<p>굳이 Map 을 고집할 필요는 없었을 것 같다.</p>
<h3 id="▶-고찰">▶ 고찰</h3>
<blockquote>
</blockquote>
<p>맵 안에서 findIndex를 하는 방법을 떠올리는 것에는 오랜 시간이 들지 않았는데, 그 방법이 타임이 걸려 Map 을 하는 방식을 떠올리는데 시간이 오래 걸렸다. 
맵을 두 개 만들지 않고, 배열의 인덱스로 바꾸는 방법은 괜찮게 떠올린 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 요격 시스템 - JavaScript]]></title>
            <link>https://velog.io/@kong_woon/Algorithm-%EC%9A%94%EA%B2%A9-%EC%8B%9C%EC%8A%A4%ED%85%9C-JavaScript</link>
            <guid>https://velog.io/@kong_woon/Algorithm-%EC%9A%94%EA%B2%A9-%EC%8B%9C%EC%8A%A4%ED%85%9C-JavaScript</guid>
            <pubDate>Tue, 16 May 2023 05:47:11 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/kong_woon/post/4b9ad956-5d90-4fbd-8125-8b4f461e8dc0/image.png" alt=""></p>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/181188">프로그래머스 - 요격 시스템</a>
난이도 : Level 2
정답률 : 33%</p>
<h3 id="▶-문제">▶ 문제</h3>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/5006cf61-a759-4521-80aa-6244e51955da/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/25503eba-7a7b-4027-9261-e6795c48fef0/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/6c69425f-f8e6-4ffd-9f73-1967bf155fb2/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/kong_woon/post/0b7e27e7-defe-48b6-9282-281927819915/image.png" alt=""></p>
<h3 id="▶-풀이">▶ 풀이</h3>
<blockquote>
</blockquote>
<p>시작 좌표가 작은 순으로 정렬 후 끝 좌표가 다음 미사일의 첫 부분보다 작으면, 다음 미사일의 끝으로 좌표를 설정 후 카운트를 추가한다.</p>
<pre><code class="language-js">function solution(targets) {
    var answer = 1;
    // 스타트 지점이 작은 기준으로 정렬한다
    targets.sort((s,e) =&gt; s[0] - e[0]);
    // 정렬된 미사일에 최종 지점을 기준으로 시작한다.
    let loc = targets[0][1];
    targets.forEach(mi =&gt; {
        // 시작 좌표가 지정된 좌표보다 작을 경우 중
        if(mi[0] &lt; loc) {
            // 마지막 좌표가 지정된 좌표보다 작을 경우
            if (mi[1] &lt; loc) {
                // 좌표를 재설정한다.
                loc = mi[1];
            }
        // 시작 좌표가 지정된 좌표보다 크거나 같을 경우에 카운트를 올린다
        }  else {
                loc = mi[1]
                answer++;
            }
    })
    return answer;
}</code></pre>
<h3 id="▶-삽질">▶ 삽질</h3>
<ul>
<li>첫번째 미사일(s)와 두번째 미사일(e)의 차가 1일 경우 발사할 미사일의 좌표는 s + e / 2 로 고정이다.
미사일 간의 차가 1일 경우의 발사할 미사일을 고정해두고 차가 클 경우 이미 배열에 있는 곳을 제거하고 추가하면 되지 않을까?</li>
</ul>
<p><span style="color: red"> -&gt; 두 차이를 기준으로 로직을 짤 경우 차가 2 이상일 때는 발사해야 하는 가장 효율적인 지점을 알 수 없다.
</span></p>
<ul>
<li>targets 배열의 가장 큰 수와 가장 작은 수의 간격들을 모두 배열에 추가하고 그 중 가장 많이 겹치는 부분을 제외한 나머지는 제거하면 되지 않을까?</li>
</ul>
<p><span style="color: red"> -&gt; 획기적으로 잘못된 발상이었다. 반복문을 모든 간격에서 돌려야 하기에 불필요한 연산이 너무 많이 생긴다.
</span></p>
<h3 id="▶-다른-풀이">▶ 다른 풀이</h3>
<p>나와 비슷한 풀이가 많았다.
그 중 미사일의 마지막 부분에 0.5 를 빼거나 추가하는 풀이들이 종종 보였는데, 아마 나처럼 입출력 그래프 예시를 보고 간격에서 x축이 숫자와 숫자 사이라는 발상을 떠올린 것 같다. </p>
<pre><code class="language-js">   targets.forEach(target =&gt; {  
        if(currentMax === -1) {
            currentMax = target[1];
            return;
        } 
        if(target[0] &gt;= currentMax) {
            currentMax = target[1];
            result++;
            return;
       }
    });

* else 를 쓰지 않고 조건문을 탈출하는 풀이가 인상적이었다.</code></pre>
<h3 id="▶-고찰">▶ 고찰</h3>
<blockquote>
</blockquote>
<p>입출력 예시 그래프를 보고 targets에 x축이 고정되었다고 믿어 sort 해야 한다는 생각을 하기까지 오래 걸렸다. 데이터를 유연하게 바라볼 필요가 있다. </p>
]]></description>
        </item>
    </channel>
</rss>