<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>young_mason.log</title>
        <link>https://velog.io/</link>
        <description>Frontend Developer</description>
        <lastBuildDate>Mon, 10 Oct 2022 08:34:15 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>young_mason.log</title>
            <url>https://velog.velcdn.com/images/young_mason/profile/9f4c6576-a995-4979-ae90-1b2834fda351/image.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. young_mason.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/young_mason" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[React] useImperativeHandle hook으로 하위 컴포넌트의 상태 관리하기]]></title>
            <link>https://velog.io/@young_mason/useImperativeHandle</link>
            <guid>https://velog.io/@young_mason/useImperativeHandle</guid>
            <pubDate>Mon, 10 Oct 2022 08:34:15 GMT</pubDate>
            <description><![CDATA[<h2 id="useimperativehandle">useImperativeHandle</h2>
<pre><code class="language-js">useImperativeHandle(ref, createHandle, [deps])</code></pre>
<blockquote>
<h3 id="docs"><a href="https://ko.reactjs.org/docs/hooks-reference.html#useimperativehandle">Docs</a></h3>
<p>useImperativeHandle은 ref를 사용할 때 부모 컴포넌트에 노출되는 인스턴스 값을 사용자화(customizes)합니다. 항상 그렇듯이, 대부분의 경우 ref를 사용한 명령형 코드는 피해야 합니다. useImperativeHandle는 forwardRef와 더불어 사용하세요.</p>
</blockquote>
<p><code>useImperativeHandle</code>훅은 부모 컴포넌트에서 자식 컴포넌트의 State를 관리해야할 경우 사용할 수 있는 훅입니다. </p>
<p>즉 자식의 상태변경을 부모가 하거나, 자식 컴포넌트의 State 핸들러를 부모에서 호출하는 경우 사용할 수 있습니다</p>
<p>이 훅의 단순한 사용예시는 공식문서와 여러 블로그에 잘 나와있어요. 
_<a href="https://velog.io/@jay/useImperativeHandle-%EB%96%A0%EB%A8%B9%EC%97%AC%EB%93%9C%EB%A6%BD%EB%8B%88%EB%8B%A4">useImperativeHandle 떠먹여드립니다.</a> _</p>
<p>이 글에서는 아래와 같은 기능 차트 기능개발 도중 제가 겪은 문제를 해결하는 과정에 대해 설명드리겠습니다!</p>
<h3 id="요구사항">요구사항</h3>
<p><img src="https://velog.velcdn.com/images/young_mason/post/771d44c1-90fb-4815-9530-082faf1fa3c5/image.png" alt=""></p>
<p>위 차트 상의 라인을 클릭하면 아래 처럼 동작하여야 합니다.</p>
<ol>
<li>클릭 지점의 데이터를 이용하여 툴팁 활성화 (showTooltip)</li>
<li>차트 데이터를 Parent로 전달하면서 테이블 컴포넌트 활성화</li>
<li>테이블 컴포넌트가 활성화될때 기존 컴포넌트와 전환되어야함</li>
</ol>
<pre><code class="language-jsx">function Parent() {
  const chartData = [....];  
  const [tableData, setTableData] = useState();

  return (
    &lt;Container&gt;
      &lt;Chart
        data={chartData}
        setTableData={setTableData}
      /&gt;

      ... 

      {showTable
        ? &lt;Table data={tableData} /&gt;
        : &lt;OtherComp /&gt;
      }

    &lt;/Container&gt;
  )
}


function Chart({ data, setTableData}) {
  const [showTooltip, setShowTooltip] = useState();
  return (
    &lt;LineChart&gt;
      &lt;Line onClick={(d) =&gt; {
        setShowTooltip(true)};
        setTableData(d);
      }/&gt;
      ...
      {showTooltip &amp;&amp; &lt;Tooltip /&gt;}
    &lt;/LineChart&gt;
  )
}
</code></pre>
<p>실제 코드를 단순화한 예시입니다. 
우선 차트와 테이블을 감싸고 있는 부모컴포넌트가 있구요</p>
<p>라인 차트를 클릭했을때 tooltip을 활성화하고, 부모에서 관리되고 있는 tableData 상태를 업데이트 해줍니다</p>
<p>아래와 같은 컴포넌트 구조에서 테이블의 x 버튼을 눌렀을때 차트 컴포넌트의 툴팁도 함께 닫으려면 어떻게 해야 할까요?</p>
<p><img src="https://velog.velcdn.com/images/young_mason/post/9b5ee3a2-27d1-4ac7-a8f0-778afa15fd29/image.png" alt=""></p>
<p>가장 단순한 해결책은 차트 내부의 showTooltip 상태를 부모로 끌어올려서 관리하는 방법입니다.</p>
<p>하지만 이렇게 했을때 맘에 안드는 부분이 있습니다</p>
<p>Tooltip은 차트 데이터를 이용하고 있으며 UI상 차트에 종속 되어있습니다. 단순 close를 하기 위해 tooltip의 상태를 상위로 끌어올리면 props가 추가되면서 상태가 복잡해지고 관심사가 뒤섞여 이해하기 어려운 코드가 되어버리죠.</p>
<p>물론 이 경우 상태관리 라이브러리는 좋은 대안이 될 것 같습니다. 하지만 상태 공유 라이브러리를 사용하지 않는 프로젝트라면, 이 기능을 위해 상태 공유 라이브러리를 도입하는건 무리가 있습니다. 또한 Context API는 불필요한 리렌더링 방지를 위한 최적화 작업까지 필요하여 번거롭다고 느껴집니다.</p>
<p>따라서 해결해야될 문제를 단순하게 정의하면 아래와 같아요</p>
<blockquote>
<p>state를 끌어올리지 않고, 상태관리 라이브러리나 Context API 를 사용하지 않으면서  <strong><em>Chart 컴포넌트의 showTooltip 상태를 부모에서 관리하기</em></strong></p>
</blockquote>
<p>이 문제를 useImperativeHandle 과 forwarRef를 해결할 수 있었습니다</p>
<p>코드 먼저 살펴볼게요</p>
<pre><code class="language-jsx">function Parent() {
  const chartData = [....];  
  const chartRef = useRef(); // ref 선언
  const [tableData, setTableData] = useState();

  return (
    &lt;Container&gt;
      &lt;Chart
        ref={chartRef}
        data={chartData}
        setTableData={setTableData}
      /&gt;  
      &lt;Table 
        data={tableData}
        onClickClose={() =&gt; {
          chartRef.current?.onCloseTooltip(); // 자식 컴포넌트에서 전달받은 메소드를 실행합니다.
        }}
      /&gt;
    &lt;/Container&gt;
  )
}


const Chart = forwardRef(({ data, setTableData }, chartRef) =&gt; {

  const [showTooltip, setShowTooltip] = useState(false);

  // hook을 이용하여 Parent에서 사용할 메소드를 선언해줍니다
  useImperativeHandle(chartRef, () =&gt; ({
    onCloseTooltip: () =&gt; {
      setShowTooltip(false);
    }
  }))

  return (
    &lt;LineChart&gt;
      &lt;Line onClick={(d) =&gt; {
        setShowTooltip(true)};
        setTableData(d);
      }/&gt;
      ...
      {showTooltip &amp;&amp; &lt;Tooltip /&gt;}
    &lt;/LineChart&gt;
  )
})

</code></pre>
<p>먼저 ref를 하위컴포넌트로 전달하기 위해서 자식 컴포넌트를 forwardRef로 감싸줍니다.</p>
<p>다음, 자식 컴포넌트 안에서 useImperativeHandle을 사용하면 되는데, 첫번째 인자로 전달받은 ref를 넣어줍니다. 그리고 두번째 인자로는 객체를 리턴하는 함수를 넣어줍니다. </p>
<p>여기서 두번째 인자의 함수 리턴값에 변수나 메소드를 넣어주면 부모컴포넌트에서 ref.current 를 통해 접근 가능해집니다.  </p>
<p>저의 경우 onClickCloseTooltip에 setState 함수를 넣어줘서, 부모 컴포넌트에서 tooltip을 닫는 함수를 호출할 수 있게 되었습니다.</p>
<p>state를 끌어올릴 경우 불필요하게 부모컴포넌트까지 리렌더링 되는 문제도 덤으로 해결됩니다 :)</p>
<h3 id="요약">요약</h3>
<blockquote>
</blockquote>
<p>useImperativeHandle 와 forwardRef를 활용하면 state 끌어올리거나 상태관리 툴을 사용하지 않고서도 부모가 자식컴포넌트의 상태를 관리할 수 있으며, 부모와 자식 컴포넌트간의 관심사 분리를 유지할 수 있습니다!</p>
<p>위 예시에서는 단순히 tooltip을 close 하는 기능을 위해 useImperativeHook을 사용했지만, 조금더 복잡하고 다양한 메소드 혹은 state 들을 정의해서 부모에게 전달해줘야 할 경우 더 유용할 것 같네요.</p>
<p>하지만 공식문서에 나와있듯 가능한 ref를 사용한 명령형 코드는 피하는 것이 좋습니다. 
( 아마 렌더링 이후 DOM에 직접 접근하게 되고, 리액트의 선언형 문법과 괴리가 생길 수 있기 때문이지 않을까 생각해봅니다 )</p>
<p>따라서 관심사의 분리 or 가독성 등 명백히 이점이 있을때 useImpertative를 사용하는 것이 좋을것같습니다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React-Native] ios에서 흰화면이 뜨는 문제]]></title>
            <link>https://velog.io/@young_mason/React-Native-ios%EC%97%90%EC%84%9C-%ED%9D%B0%ED%99%94%EB%A9%B4%EC%9D%B4-%EB%9C%A8%EB%8A%94-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@young_mason/React-Native-ios%EC%97%90%EC%84%9C-%ED%9D%B0%ED%99%94%EB%A9%B4%EC%9D%B4-%EB%9C%A8%EB%8A%94-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Mon, 03 Oct 2022 06:38:08 GMT</pubDate>
            <description><![CDATA[<h1 id="문제-상황">문제 상황</h1>
<p>아이폰에서 리치고 앱을 사용하다가 일정 시간이 지나거나, 혹은 다른 작업 후 다시 실행시켰을 때 흰 화면 상태에서 작동이 멈추는 문제가 있었습니다.</p>
<p><img src="https://velog.velcdn.com/images/young_mason/post/56d4c1e7-4f98-4358-9682-ec753d010e9f/image.png" alt="terminated-screen"></p>
<h1 id="문제-원인">문제 원인</h1>
<p>react-native-webview 모듈에서 발생한 문제로</p>
<p>기기가 일정 부분 이상 메모리 리소스를 사용할경우 웹뷰가 강제 종료(terminated) 되는 현상으로 파악하였습니다</p>
<h1 id="문제-해결-방법-및-과정">문제 해결 방법 및 과정</h1>
<p>100% 재현되는 플로우를 찾기위해 여러가지 시도를 해보다가, 리치고 앱 사용후 약 20개정도의 앱을 연달아서 실행시킨 후 돌아왔을때 100% 재현되는 것을 확인했습니다.</p>
<p>실제 어떤 로그가 찍히는지 보기위해 react-native ios 빌드 관련 세팅을 진행하였습니다</p>
<p>RN 및 X-Code 세팅 중 m1 mac 관련 이슈들이 발생하여 아래 블로그 참고하여 해결했습니다.</p>
<p>(<strong><a href="https://iot624.tistory.com/165">M1 Mac에 React-Native 설치 삽질기</a></strong>)</p>
<p>빌드를 성공 시킨 후 후 흰화면 재현시 어떤 로그가 뜨는지 확인하고자했는데</p>
<p>iOS Simulator 환경에서는 흰화면 문제가 재현이 되질 않았습니다.</p>
<p>그래서 iOS 기기에 직접 앱을 빌드한 후 문제상황을 재현시켜서  아래와 같은 로그를 확인하였습니다</p>
<p><img src="https://velog.velcdn.com/images/young_mason/post/ce57cb2a-5e6c-48d1-9669-30b350ed9b21/image.png" alt="terminated-log"></p>
<p>드디어 문제의 로그가 나왔네요..</p>
<p><strong>[native] Webview Process Terminated</strong></p>
<p>위 로그를 구글링해서 아래 스택오버 플로우 링크를 통해 원인과 해결방법을 찾을 수 있었습니다</p>
<p><a href="https://stackoverflow.com/questions/61723317/react-native-webview-process-terminated">https://stackoverflow.com/questions/61723317/react-native-webview-process-terminated</a></p>
<p><img src="https://velog.velcdn.com/images/young_mason/post/3ca30571-4f44-4536-bae8-b5a18662d9f4/image.png" alt=""></p>
<p>위 답변에 따르면 iOS 웹뷰가 너무 많은 리소스를 사용할 경우 등의 이유로 앱이 멈추는(crashing/freezing) 문제라고 하며, Webview 컴포넌트의 <code>onContentProcessDidTerminate</code> props 콜백으로 terminated 된 이후 액션을 정의 할 수 있다고 합니다 ex) reload</p>
<p>이제 추가해야될 코드가 뭔지 알게 되었습니다</p>
<pre><code class="language-tsx">
  &lt;WebView 
    ref={setWebviewRef}
    source={source}
    onLoad={() =&gt; onWebviewLoad(webviewRef.current, fcmToken)}
    onMessage={e =&gt; onMessage(e, localRef, props.navigation)}
    ...

    // 아래 코드 추가
    onContentProcessDidTerminate={() =&gt; {
      webviewRef.current?.reload();
    }}
  /&gt;
</code></pre>
<p>위와 같이 코드를 추가 한 후 다시 한번 기기에서 20개 정도의 앱을 실행시키면서 재현을 시켜보았습니다</p>
<p><img src="https://velog.velcdn.com/images/young_mason/post/c67c4fc1-01b1-4648-9686-005b5f829384/image.png" alt="log2"></p>
<p>마찬가지로 메모리 문제때문에 앱이 Terminated 되었지만</p>
<p>이후 성공적으로 앱이 리로딩되어 홈화면으로 돌아가졌음을 확인 하였습니다.</p>
<p>뿌-듯</p>
<p><img src="https://velog.velcdn.com/images/young_mason/post/fec82cc5-00bd-4cd4-8e2f-10584dc60eb1/image.png" alt="result"></p>
<p><img src="https://velog.velcdn.com/images/young_mason/post/346da0d5-7e87-4f50-837e-30cae829f274/image.png" alt="user-feedback"></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] Map 에 대하여]]></title>
            <link>https://velog.io/@young_mason/JS-Data-Structure-Map%EA%B3%BC-Set-%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</link>
            <guid>https://velog.io/@young_mason/JS-Data-Structure-Map%EA%B3%BC-Set-%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</guid>
            <pubDate>Tue, 16 Mar 2021 11:31:48 GMT</pubDate>
            <description><![CDATA[<h2 id="map">Map</h2>
<p>Map은 키-값을 저장할 수 있는 자료구조입니다.
기존의 키-값을 저장할 수 있는 객체 (Object)가 있는데 Map은 또 왜 있는 걸까요?   ES6이후에 등장한 Map에 대해서 알아보겠습니다.</p>
<h3 id="1-map은-key에-다양한-자료형을-허용합니다">1. Map은 key에 다양한 자료형을 허용합니다</h3>
<p>자바스크립트 객체는 모든 키를 문자열로 변환합니다. 반면에, Map은 자료형에 대한 제한이 없습니다. 
그래서 키로 객체가 허용된다는 점이 재밌습니다 🙂</p>
<pre><code class="language-js">let map = new Map();

// set 메소드의 첫번째 인자로 key,두 번째 인자로 value를 전달하여 Map의 요소를 생성할 수 있습니다
// 자기 자신을 반환하므로 체이닝(chaning ) 가능합니다
map
  .set(&#39;1&#39;, &#39;str1&#39;)
  .set(1, &quot;num1&quot;);

// get 메소드의 key 를 입력하여 value에 접근할 수 있습니다
map.get(1) ;  // &quot;num1&quot;
map.get(&#39;1&#39;) ; // &quot;str1&quot;

// 객체도 key가 될 수 있습니다
let user = {
  &#39;name&#39; : &#39;Mason&#39;
}

map.set(user, 29);
map.get(user) // 29;
</code></pre>
<hr>
<h3 id="2-map은-size-프로퍼티-등-유용한-메서드나-프로퍼티가-있습니다">2. Map은 size 프로퍼티 등 유용한 메서드나 프로퍼티가 있습니다</h3>
<p>기존 Object의 크기를 알아내기 위해선 Object.keys(obj) 로 모든 key 배열을 만든 뒤 length에 접근해야 하는 번거로움이 있습니다.</p>
<p>하지만, Map에는 size라는 프로퍼티가 Map의 요소 수를 기억하고 있기 때문에, <code>map.size</code> 를 바로 호출하여 한번에 Map의 크기를 알아낼 수 있습니다</p>
<p>이 밖에 메소드들을 아래에 정리하였습니다.</p>
<p>** [ Map의 메소드 ] **</p>
<ul>
<li><code>new Map()</code> : 맵 생성</li>
<li><code>map.set(key, value)</code> : key와 value 저장</li>
<li><code>map.get(key)</code> : key에 해당하는 값 반환 (없을 경우 undefined)</li>
<li><code>map.has(key)</code> : key의 존재여부 boolean으로 반환</li>
<li><code>map.delete(key)</code> : key와 해당하는 값 삭제</li>
<li><code>map.clear()</code> : 맵 안의 모든 요소 제거</li>
<li><code>map.size</code> : 요소의 개수 반환</li>
</ul>
<hr>
<h3 id="3-map-은-순회-가능-iterable-합니다">3. Map 은 순회 가능 (iterable) 합니다</h3>
<p>기존 Object는 iterable 하지 않기 때문에 순회 하기 위해서 먼저 모든 key의 배열을 얻어낸 후 그 key의 배열을 순회하게 됩니다.
(<code>Symbol.iterator</code> 를 이용하여 iterable 객체로 만들어주는 방법도 있긴 합니다)</p>
<p>반면, Map은 삽입된 순서를 기억하며 메소드를 이용하여 삽입된 순서대로 순회 가능합니다. ( 객체는 프로퍼티 순서를 기억 못해요 ) </p>
<p>** [ Map 순회 메소드 ] **</p>
<ul>
<li><code>map.keys()</code> – 각 요소의 키가 담긴 iterable 객체 반환</li>
<li><code>map.values()</code> – 각 요소의 값이 담긴 iterable 객체를 반환</li>
<li><code>map.entries()</code> – 요소의 [키, 값]을 한 쌍으로 하는 iterable 객체를 반환</li>
</ul>
<pre><code class="language-js">// new Map 안에 키, 값을 요소로 가지는 배열을 인자로 전달하여 초기값을 넣어줄 수 있습니다

let meals = new Map([
  [&#39;breakfast&#39;, &#39;bread&#39;],
  [&#39;lunch&#39;, &#39;짜장면&#39;],
  [&#39;dinner&#39;, null]  // 아직안먹었어요ㅋㅋ
])

for (let meal of meals.keys()) {
  console.log(meal) 
}
//  breakfast, lunch, dinner


// forEach 메소드도 사용 가능합니다
meals.forEach((val, key, map) =&gt; {
 console.log(`${val}: ${key}`);
})
// breakfast: bread ... 

</code></pre>
<hr>
<p>Mozilla Mdn 문서에 나와있는 Map과 Object와의 차이점을 정리하였습니다</p>
<p><img src="https://images.velog.io/images/young_mason/post/eaa5df69-fcfc-440b-a53d-2dba0d524342/image.png" alt="ㅇ"></p>
<h2 id="결론">결론</h2>
<p>키에 다양한 자료형이 필요한 경우,
size에 자주 접근해야 하는 경우,
key-value의 추가와 제거, 순회가 빈번하게 발생하는 경우 
Map을 사용하면 좋을 것 같네요 : )</p>
<p><a href="https://ko.javascript.info/map-set">참고자료</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[RxJS 공식문서 Overview 번역]]></title>
            <link>https://velog.io/@young_mason/RxJS-%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C-Overview-%EB%B6%80%EB%B6%84-%EB%B2%88%EC%97%AD</link>
            <guid>https://velog.io/@young_mason/RxJS-%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C-Overview-%EB%B6%80%EB%B6%84-%EB%B2%88%EC%97%AD</guid>
            <pubDate>Wed, 10 Mar 2021 15:20:51 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>🌟 RxJS <a href="https://rxjs-dev.firebaseapp.com/guide/overview">공식문서</a> 의 Overview 부분을 번역하면서 학습한 내용입니다. 중간중간 의역이 들어간 부분이 많습니다.  사실과 다른 부분이 있다면 지적해주시면 감사드리겠습니다 :) </p>
</blockquote>
<h2 id="intro">Intro</h2>
<p><strong>RxJS는 연속된 Observable을 이용하여 비동기와 이벤트 기반의 프로그래밍을 구현하기 위한 라이브러리입니다.</strong></p>
<p>RxJS는 코어 타입 Observable과 위성 타입 (Observer, Schedulers, Subjects) 그리고 Array 메소드에서 착안한 operators (map, filter, reduce, every, etc.. ) 를 제공하여, 비동기 이벤트를 제어합니다. </p>
<p><strong><em>이벤트 처리에 특화된 Lodash라고 생각해주세요</em></strong></p>
<blockquote>
<p><strong>lodash?</strong>
자바스크립트 유틸리티 라이브러리로써 array, collection, date, number, object등이 있으며, 데이터를 쉽게 다룰 수 있도록 도와줍니다.</p>
</blockquote>
<p>ReactiveX는 Observer 패턴과 Iterator 패턴을 결합시키고, 함수형 프로그래밍과 collections를 결합하여 연속된 이벤트를 처리하기 위한 이상적인 방식에 대한 니즈를 충족시켜줍니다.</p>
<p>비동기 이벤트 관리를 해결하기위한 RxJS의 주요 컨셉은 다음과 같습니다</p>
<ul>
<li><code>Observable</code>: 향후 얻게될 값이나 이벤트를 호출 할 수 있는 콜렉션에 대한 아이디어를 표현합니다</li>
<li><code>Observer</code>: Observable이 전달한 값을 어떻게 받을지에 대한 정보가 들어있는 콜백들 콜렉션</li>
<li><code>Subscription</code>: Observable의 실행을 나타냅니다. 주로 실행을 취소하는데 가장 유용합니다.</li>
<li><code>Operators</code>: 순수함수이며 map, filter, concat, reduce 같은 기능을 다루면서 함수형 프로그래밍을 가능하게 합니다</li>
<li><code>Subject</code> : EventEmitter와 동일한 기능을 하고, 다수의 Observer에 데이터값과 이벤트를 전달 할 수 있는 유일한 방법입니다.</li>
<li><code>Schedulers</code>:동시성(concurrency)을 컨트롤하기 위해 중앙화된 디스패처.  setTImeout이나 requestAnimationFrame 등에서 연산이 발생할 때 조정할 수 있음</li>
</ul>
<h2 id="first-examples">First examples</h2>
<p>원래는 자바스크립트를 이용하여 이벤트 리스너를 이렇게 등록하죠</p>
<pre><code class="language-jsx">document.addEventListener(&#39;click&#39;, () =&gt; console.log(&quot;Clicked!&quot;));</code></pre>
<p>RxJS를 이용할경우는?  Observable을 만들면 됩니다</p>
<pre><code class="language-jsx">import { fromEvent } from &#39;rxjs&#39;;

fromEvent(document, &#39;click&#39;).subscribe(() =&gt; console.log(&quot;Clicked!&quot;)); </code></pre>
<h3 id="purity">Purity</h3>
<p>RxJS는 순수함수를 이용하여 데이터를 생성할 수 있다는 강점이 있습니다. 즉, 에러를 줄일 수 있음을 의미하죠</p>
<p>보통은 비순수함수를 만들게되어, 다른 코드가 state를 어지럽히게 되는 경우가 생깁니다</p>
<pre><code class="language-jsx">let count = 0;
document.addEventListener(&#39;click&#39;, () =&gt; console.log(`Clicked ${++count} times`))</code></pre>
<p>RxJS를 이용하여 state를 묶어둘 수 있습니다</p>
<pre><code class="language-jsx">import { fromEvent } from &#39;rxjs&#39;;
import { scan } from &#39;rxjs/operatores&#39;;

fromEvent(document, &#39;click&#39;)
  .pipe(scan(count =&gt; count + 1, 0))
  .subscribe(count =&gt; console.log(`Clicked ${count} times`))</code></pre>
<p>Scan 기능은 array의 reduce 메소드 처럼 동작합니다. 콜백에 노출된 값을 인자로 받습니다. 콜백의 리턴값이 이후에 실행될 때 누적되어 이후에 실행될때의 값이됩니다.</p>
<h3 id="flow">Flow</h3>
<p>RxJS 는 이벤트가 Observer를 통해 흐르는 방식을 제어하는데 도움이 되는 모든 범위의 Operator들을 가지고 있습니다.</p>
<p>초당 최대 한 번의 클릭을 허용하려고 할 때 일반적인 자바스크립트로는 이렇게 할 수 있습니다</p>
<pre><code class="language-jsx">let count = 0;
let rate = 1000;
let lastClick = Date.now() - rate;
document.addEventListener(&#39;click&#39;, () =&gt; {
  if (Date.now() - lastClick &gt;= rate) {
    console.log(`Clicked ${++count} times`);
    lastClick = Date.now();
  }
})</code></pre>
<p>RxJS는 어떨까요?</p>
<pre><code class="language-jsx">import { fromEvent } from &#39;rxjs&#39;;
import { throttleTime, scan } from &#39;rxjs/operators&#39;;

fromEvent(document, &#39;click&#39;)
  .pipe(
    throttleTime(1000),
    scan(count =&gt; count + 1, 0)
  ) 
  . subscribe(count =&gt; console.log(`Clicked ${count} times`));</code></pre>
<p>그밖에도 flow를 컨트롤 할 수 있는 operator는 filter, delay, debounceTime, take, takeUntil, distinct, distinctUntilChanged 등 이 있습니다</p>
<h3 id="values">Values</h3>
<p>Observable을 통해 전달된 값을 변화시키는 것도 가능합니다</p>
<p>아래는 현재 마우스의 x좌표를 매번 클릭마다 추가하는 기능입니다 (자바스크립트버전)</p>
<pre><code class="language-jsx">let count = 0;
const rate = 1000;
let lastClick = Date.now() - rate;
document.addEventListener(&#39;click&#39;, event =&gt; {
  if (Date.now() - lastClick &gt;= rate) {
    count += event.clientX;
    console.log(count);
    lastClick = Date.now();
  }
})</code></pre>
<p>RxJS로 하면?!</p>
<pre><code class="language-jsx">import { fromEvent } from &#39;rxjs&#39;;
import { throttleTime, map, scan } from &#39;rxjs/operators&#39;;

fromEvnet(document, &#39;click&#39;)
  .pipe(
    throttleTime(1000),
    map(event =&gt; event.clientX),
    scan((count, clientX) =&gt; count + clientX, 0)
  )
  .sibscribe(count =&gt; console.log(count))</code></pre>
<p>이외에도 value를 조작하는 operato는 pluck, pairwise, sample 등이 있습니다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TSJ] EC2 인스턴스 특정시간에 자동으로 시작, 종료하기]]></title>
            <link>https://velog.io/@young_mason/TSJ-EC2-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%ED%8A%B9%EC%A0%95%EC%8B%9C%EA%B0%84%EC%97%90-%EC%9E%90%EB%8F%99%EC%9C%BC%EB%A1%9C-%EC%8B%9C%EC%9E%91-%EC%A2%85%EB%A3%8C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@young_mason/TSJ-EC2-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%ED%8A%B9%EC%A0%95%EC%8B%9C%EA%B0%84%EC%97%90-%EC%9E%90%EB%8F%99%EC%9C%BC%EB%A1%9C-%EC%8B%9C%EC%9E%91-%EC%A2%85%EB%A3%8C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 07 Mar 2021 15:19:29 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💡 지난 주에 AWS 25달러 과금되고 열받아서 EC2 자동화 구현한 썰입니다</p>
</blockquote>
<h3 id="문제-상황-발생">문제 상황 발생</h3>
<p>두 번의 팀 프로젝트에서 팀장을 맡으면서, 두 프로젝트 모두 제 AWS 계정으로 EC2에 서버 배포를 진행하게 되었습니다. </p>
<p>AWS 프리티어의 경우 EC2 무료 작업시간을 최대 750h로 제공하는데, 2월달에 인스턴스 두개가 풀로 돌아가면서 1200 시간 정도를 사용하게 되어, 생각보다 금액이 쎄게 나왔습니다. 25달러로 약 3만원정도..  🤬  </p>
<p>거의 치킨 두마리 값을 날려버렸는데, 3월은 31일까지 있기때문에 그 이상이 계속해서 과금될게 분명했습니다..</p>
<h3 id="머리굴리기">머리굴리기</h3>
<p>팀원들이 취업 포트폴리오에 쓰고 있는 프로젝트 서버를 갑자기 중지시킬 수는 없는 노릇이고, 팀원들에게 서버비 달라고 하기도 어려운 문제여서 고민이 많이 됐습니다.</p>
<p>그러다가 보통 인사 담당자님들이 밤 늦은 시간에 지원자들의 프로젝트를 볼 확률이 매우 낮을 거라는 생각이 불현듯 들었고, 거기다가 저와 팀원들도 밤 늦은 시간에 딱히 서버 구동이 필요하지 않았습니다. </p>
<p>그래서, 만약 자는 시간에 <strong>자동으로 EC2 인스턴스를 켜고 끌 수 있다면</strong> 어떨까?? 하는 생각이 들었습니다. 대충 계산했을 때 2월달에 쓴 1200시간에서 40% 정도 줄이면 700시간 정도 정도 되니까 과금을 막을 수 있을 것 같았습니다. </p>
<h3 id="해결과정">해결과정</h3>
<p><strong>[Lambda &amp; CloudWatch]</strong></p>
<p>여러 키워드로 구글링 해본 끝에 AWS의 Lambda 와 CloudWatch 라는 서비스의 존재를 알게되었습니다  </p>
<blockquote>
</blockquote>
<p>🌟 Lambda
코드를 등록해놓고 실행해서 AWS에서 이용중인 작업을 컨트롤 할 수 있게 해주는 서비스. </p>
<blockquote>
<p>🌟 CloudWatch
AWS 실시간 모니터링 서비스이며, 생성된 Lambda함수가 트리거되는 시간을 지정해서, 해당 시간에 자동으로 실행하도록 만들어줄 수 있음!</p>
</blockquote>
<p>해결 과정을 간단하게 요약하면 아래와 같습니다</p>
<ol>
<li>IAM으로 역할 설정 (Ec2 켜고 끄는 기능 설정)</li>
<li>Lambda 함수코드 작성</li>
<li>CloudWatch에서 일정 생성 후 Lambda 코드 연결</li>
</ol>
<p>:: Reference  ::</p>
<p><a href="https://cholol.tistory.com/506">👉 블로그 포스팅</a>
<a href="https://aws.amazon.com/ko/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/">👉 AWS 공식 가이드</a></p>
<p>Cloud Watch 에서 자동실행 날짜를 입력하는 키워드가 처음 보는 방식이라 헷갈렸지만 레퍼런스를 보면서 큰 문제 없이 구현하였습니다.</p>
<p>Cloud Watch에서 트리거시간을 조절해가면서 정상적으로 EC2 인스턴스가 종료되고 실행되었고 로그가 잘 찍히는 것을 확인했습니다!</p>
<p>그런데 여기서 또다른 문제 발생.. 인스턴스가 실행되었음에도 서버가 작동하지 않아 ssh로 접속하여 확인해보니, 인스턴스를 껐다 키게 될 경우 기존에 pm2로 구동되던 서버 프로세스가 종료되며 자동으로 실행되지 않는 문제가 있었습니다. </p>
<p>매일 아침 마다 ssh로 접속해서 pm2 start를 입력해 줄 수는 없는일이기 때문에 이제는 다시 인스턴스가 실행될 때 서버가 자동으로 돌아가도록 할 수 있는 방법을 찾아봐야 했습니다</p>
<p><strong>[PM2 startup]</strong></p>
<p>여기서 조금 오래 헤매게 되었는데, 여러 블로그와 Stack overflow 자료를 찾아보다가 기존에 사용중이던 PM2라이브러리의 기능 하나가 눈에 들어오게 되었습니다. </p>
<p>바로 <strong>Startup</strong> 이라는 기능입니다. 터미널에서 <code>pm2 startup</code> 을 실행하면, 현재 pm2 start로 실행중인 프로세스들을 우분투 시작프로그램으로 지정해줄 수 있습니다. </p>
<p><a href="https://pm2.keymetrics.io/docs/usage/startup/">👉 공식 문서</a></p>
<p>이 명령어를 적용한 후에 인스턴스를 껐다가 키자 거짓말처럼 자동으로 서버코드가 실행되었습니다.</p>
<p>이후 Cloud Watch와 Lambda를 이용하여 자동으로 인스턴스가 시작될때도 서버가 실행되는지 테스트하여 정상적으로 동작하는 걸 확인하였습니다</p>
<h3 id="결과">결과</h3>
<p>이로써 EC2 인스턴스 실행을 자동화하여 오전 9시부터 저녁 9시까지 12시간 동안만 돌아가게 만들어서, 프리티어 750시간을 넘지 않게 만들었습니다! </p>
<p>자동화를 이용하여 비용을 줄이게 된 첫번째 경험이었고, 과금된 금액보다 더 갚진 지식을 얻은것 같아 아주 기쁩니다 👍</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS Algorithm] 자바스크립트 Sorting - 심화편 #02 Quick sort]]></title>
            <link>https://velog.io/@young_mason/dd</link>
            <guid>https://velog.io/@young_mason/dd</guid>
            <pubDate>Tue, 23 Feb 2021 07:46:00 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💡 자바스크립트 언어로 자료구조 &amp; 알고리즘에 대해 배운 내용을 기록합니다</p>
</blockquote>
<h2 id="📖-intro">📖 Intro</h2>
<hr>
<p>이전에 알아보았던 bubble, insertion, selection 정렬은 전반적으로 O(n^2) 의 시간복잡도를 가지므로, 배열의 길이가 커졌을때 상당히 비효율적인 알고리즘이 됩니다.</p>
<p>이러한 시간복잡도를 O(n logn)으로 개선할 수 있는 정렬 알고리즘들이 있습니다. 대표적인 것들이 Merge, Quick, Radix Sort인데요, 이 알고리즘들은 보다 더 효율적이지만, 그만큼 구현하기에 더 복잡하다는 점이 있습니다.</p>
<p>이번 포스트에서는 퀵 정렬 (Quick Sort)의 작동 방식을 알아보면서 자바스크립트 코드로 구현해보겠습니다.</p>
<h2 id="📖-퀵-정렬-quick-sort">📖 퀵 정렬 (Quick Sort)</h2>
<hr>
<p><img src="https://images.velog.io/images/young_mason/post/43235884-7492-4ca3-b578-9f8b019b38db/quickSort.gif" alt=""></p>
<ul>
<li>병합 정렬처럼, 길이가 0이나 1인 배열은 항상 정렬되어 있는 상태라는 점을 활용합니다</li>
<li>하나의 요소를 Pivot 으로 선택해서, 정렬되 배열에서 pivot이 몇번째 인덱스에 위치해야 하는지 찾아가는 방식으로 작동합니다!</li>
<li>한번 Pivot이 적절한 위치에 배치되면, Pivot 양쪽에 모든요소들에 Quick sort를 적용합니다</li>
</ul>
<p><strong>Pivot Function</strong></p>
<ul>
<li>Quick sort를 구현하려면, 먼저 Pivot 양쪽에 있는 배열에서 요소를 정렬하는 기능을 구현하는 것이 유용합니다.</li>
<li>배열이 주어지면, 이 함수는 하나의 요소를 Pivot으로 지정해야 합니다</li>
<li>다음 모든 요소들을 재배치해서, Pivot 보다 작은 요소들은 왼쪽에, Pivot보다 큰 요소들은 오른쪽에 배치합니다</li>
<li>이 때 양 쪽에 배치된 요소들의 순서는 그대로 갑니다</li>
<li>이 함수는 새 배열을 만들지 않아야 합니다.</li>
</ul>
<p><strong>Pivot Picking</strong></p>
<ul>
<li>퀵 정렬의 런타임은 피벗을 선택하는 방법에 따라 달라집니다</li>
<li>정렬하려는 데이터 셋의 대략적인 중간 값을 Pivot으로 선택하는 것이 이상적입니다.</li>
<li>우선 단순하게 하기 위해 항상 피벗을 첫 번째 요소로 선택하겠습니다.</li>
</ul>
<p><strong>Quicksort Pseudocode</strong></p>
<ul>
<li>인자 세 개를 받습니다 :  배열, 시작 인덱스(default 0), 종료 인덱스(default 배열길이-1)</li>
<li>시작 인덱스를 Pivot으로 설정합니다</li>
<li>현재 Pivot 인덱스를 변수에 저장합니다 ( Pivot이 종료되어야 할 위치를 찾아갑니다 )</li>
<li>배열의 시작부터 종료지점까지 반복합니다<ul>
<li>Pivot이 현재 값보다 더 크다면, pivot 인덱스를 증가시키고, 현재 요소와 pivot 인덱스의 요소의 위치를 바꿔줍니다</li>
</ul>
</li>
<li>시작 요소와 Pivot 인덱스의 요소 위치를 바꿔줍니다</li>
<li>pivot 인덱스를 리턴합니다</li>
</ul>
<pre><code class="language-js">
function pivot (arr, start = 0, end = arr.length - 1, i++) {
  const swap = (arr, idx1, idx2) =&gt; {
    [arr[idx1], arr[idx2]] = [arr[idx2], arr[idx1]);
  }

  // 일단 피벗이 항상 첫번째 요소라고 가정합니다
  let pivot = arr[start];
  let swapIdx = start;

  for (let i = start + 1; i &lt;= end; i++) {
    if (pivot &gt; arr[i]) {
      swapIdx++;
      swap(arr, swapIdx, i);
    }
  }

  // start와 swapIdx의 위치를 바꿔줍니다
  swap(arr, start, swapIdx);
  return swapIdx;
}


// [3,1,6,8,2,4]
// -&gt; return 2 --&gt; [2,1,3,8,6,4]</code></pre>
<p><strong>quicksort pseudocode</strong></p>
<ul>
<li>주어진 array에 위에서 구현한 pivot함수를 실행합니다</li>
<li>함수가 업데이트된 pivot 인덱스를 리턴하면, 해당 인덱스의 왼쪽 부분과 오른쪽부분에 재귀적으로 pivot 함수를 호출한다</li>
<li>left, right의 요소가 2개 미만일때 함수의 호출이 멈춘다</li>
</ul>
<pre><code class="language-js">
function quickSort(arr, left = 0, right = arr.length-1) {
  if (left &lt; right) {
    let pivotIndex = pivot(arr, left, right) 
    //left
    quickSort(arr, left, pivotIndex-1);
    //right
    quickSort(arr, pivotIndex+1, right);

    return arr;
  }
}</code></pre>
<h2 id="📖-시간복잡도">📖 시간복잡도</h2>
<hr>
<p><img src="https://images.velog.io/images/young_mason/post/a31fe66b-13a4-4682-90d0-b3898c8c748b/image.png" alt=""></p>
<h2 id="📖-reference">📖 Reference</h2>
<hr>
<p><a href="https://visualgo.net/en/sorting">Visualgo</a>
<a href="https://www.toptal.com/developers/sorting-algorithms">Sorting Algorithm Animations</a>
<a href="https://www.udemy.com/course/js-algorithms-and-data-structures-masterclass/">Udemy - Javascript Algorithms and Data Structures Masterclass</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS Algorithm] 자바스크립트 Sorting - 심화편 #01 Merge sort]]></title>
            <link>https://velog.io/@young_mason/JS-Algorithm-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Sorting-%EC%8B%AC%ED%99%94%ED%8E%B8-01-Merge-sort</link>
            <guid>https://velog.io/@young_mason/JS-Algorithm-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Sorting-%EC%8B%AC%ED%99%94%ED%8E%B8-01-Merge-sort</guid>
            <pubDate>Fri, 19 Feb 2021 04:17:46 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💡 자바스크립트 언어로 자료구조 &amp; 알고리즘에 대해 배운 내용을 기록합니다</p>
</blockquote>
<h2 id="📖-intro">📖 Intro</h2>
<hr>
<p>이전에 알아보았던 bubble, insertion, selection 정렬은 전반적으로 O(n^2) 의 시간복잡도를 가지므로, 배열의 길이가 커졌을때 상당히 비효율적인 알고리즘이 됩니다.</p>
<p>이러한 시간복잡도를 O(n logn)으로 개선할 수 있는 정렬 알고리즘들이 있습니다. 대표적인 것들이 Merge, Quick, Radix Sort인데요, 이 알고리즘들은 보다 더 효율적이지만, 그만큼 구현하기에 더 복잡하다는 점이 있습니다.</p>
<p>이번 포스트에서는 병합 정렬 (Merge Sort)의 작동 방식을 알아보면서 자바스크립트 코드로 구현해보겠습니다.</p>
<h2 id="📖-병합-정렬-merge-sort">📖 병합 정렬 (Merge Sort)</h2>
<hr>
<p>병합정렬은 병합(merging)과 정렬(sorting) 두가지 큰 기능으로 구성됩니다. 길이가 0이나 1인 배열은 항상 정렬되어 있는 상태라는 점을 활용해서, 배열을 0개 혹은 1개의 요소로 모두 분리시킨 뒤, 배열을 새롭게 재구성(병합) 하면서 정렬시키는 정렬 방식입니다.</p>
<p><img src="https://images.velog.io/images/young_mason/post/af729cee-04c9-4ad8-9449-4942d44853cf/mergeSort2.gif" alt=""></p>
<h3 id="1-merge-함수-만들기">1. merge 함수 만들기</h3>
<p>병합 정렬을 구현하기 위해서, 먼저 두개의 정렬된 배열을 하나로 병합하는 함수를 구현해보겠습니다. </p>
<p>병합되는 배열은 정렬 되어 있어야하며, 두 Input 배열의 모든 요소가 들어있어야 합니다. 또한, Input 배열들이 수정되면 안됩니다.</p>
<p>두 배열의 모든 요소를 순회하게 되므로 O(n+m) 의 시간복잡도와 공간복잡도로 동작하게 됩니다. </p>
<p><strong>[Pseudocode]</strong></p>
<ul>
<li>빈 배열을 만들고, 각 input 배열의 0번째 인덱스를 포인터(i, j) 변수에 저장해둔다</li>
<li>반복문을 통해 두 배열을 동시에 탐색한다<ul>
<li>만약 첫번째 배열의 값이 두번째 배열의 값보다 작다면, 첫번째 배열의 값을 result 배열에 담고 첫번째 배열의 포인터를 증가시킨다</li>
<li>만약 첫번째 배열의 값이 두번째 배열의 값보다 크다면, 두번째 배열의 값을 result 배열에 담고 두번째 배열의 포인터를 증가시킨다</li>
<li>만약 한 배열의 순회가 끝나면, 나머지 배열의 남은 요소들을 차례대로 result 배열에 담는다</li>
</ul>
</li>
</ul>
<pre><code class="language-js">function merge(arr1, arr2) {
  let result = [];
  let i = 0;
  let j = 0;

  while ( i &lt; arr1.length &amp;&amp; j &lt;arr2.length) {
    if (arr2[j] &gt; arr1[i]) {
      result.push(arr1[i]);
      i++;
    }
    else {
      result.push(arr2[j]);
      j++;
  }

  while ( i &lt; arr1.length) {
    result.push(arr[i]);
    i++;
  }  

  while ( j &lt; arr2.length) {
    result.push(arr[j]);
    j++;
  }

  return result;  
}</code></pre>
<h3 id="2-merge-sort-구현하기">2. Merge sort 구현하기</h3>
<p>이제 위에서 만든 merge 함수를 활용하여, Merge sort의 전체 로직을 구성해보겠습니다.</p>
<p><strong>[Pseudocode]</strong></p>
<ul>
<li>빈 배열 혹은 1개 요소만 남을 때 까지 배열을 반으로 쪼갠다</li>
<li>정렬된 상태의 쪼개진 배열을 위에서 구현한 merge 함수를 실행하면서 원래의 배열 길이가 될 때까지 병합시킨다</li>
<li>병합 &amp; 정렬된 배열을 리턴한다</li>
</ul>
<pre><code class="language-js">function mergeSort(arr) {
  let (arr.length &lt;= 1) return arr;

  let mid = Math.floor(arr.length / 2)
  let left = mergeSort(arr.slice(0, mid));
  let right = mergeSort(arr.slice(mid));

  return merge(left, right);
}</code></pre>
<p>위 코드가 동작하는 방식을 간단하게 도식화하면 아래와 같습니다.</p>
<p><img src="https://images.velog.io/images/young_mason/post/3209f515-21e0-4175-825a-d3b93cdfa3b8/mergeSort.gif" alt=""></p>
<h2 id="📖-시간복잡도">📖 시간복잡도</h2>
<hr>
<p>지금까지 살펴본 병합 정렬 알고리즘의 시간복잡도는 아래와 같습니다</p>
<p><img src="https://images.velog.io/images/young_mason/post/b167a833-0a26-4a52-8a21-c71431257b8c/image.png" alt=""></p>
<p>전반적으로 O(n logn)의 시간복잡도를 갖습니다. 
n logn 이라는 시간복잡도는 조금 생소한데요, 어떻게 n logn 이 되는지 간단하게 살펴보겠습니다</p>
<p>먼저, 배열을 계속해서 반씩 쪼개는 알고리즘의 시간복잡도는 O(logn)입니다.</p>
<ul>
<li>배열의 길이 4 -&gt; 실행횟수 2</li>
<li>배열의 길이 8 -&gt; 실행횟수 3</li>
<li>배열의 길이 16 -&gt; 실행횟수 4
...</li>
</ul>
<p>두 번째로 배열이 쪼개지고 난 뒤 다시 병합할 때 (merge 함수) 는 모든 배열의 요소를 순회하게 되므로 시간복잡도는 O(n)입니다.</p>
<p>아래 그림에서 보듯 쪼개진 level 마다 모든 요소를 탐색하면서 병합 &amp; 정렬을 실행하면서 시간복잡도는 O (n logn)이 됩니다</p>
<p><img src="https://images.velog.io/images/young_mason/post/0d3080ed-0dfe-49ea-a229-850293ed8aa9/image.png" alt=""></p>
<p>이전에 살펴보았던 3가지 기본 정렬 알고리즘보다 시간복잡도가 상당히 개선되었음을 알 수 있습니다.</p>
<h2 id="📖-reference">📖 Reference</h2>
<hr>
<p><a href="https://visualgo.net/en/sorting">Visualgo</a>
<a href="https://www.toptal.com/developers/sorting-algorithms">Sorting Algorithm Animations</a>
<a href="https://www.udemy.com/course/js-algorithms-and-data-structures-masterclass/">Udemy - Javascript Algorithms and Data Structures Masterclass</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS Algorithm] 자바스크립트 Sorting - 기본편 (Bubble, Selection, Insertion)]]></title>
            <link>https://velog.io/@young_mason/Algorithm-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Sorting-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Basic%ED%8E%B8</link>
            <guid>https://velog.io/@young_mason/Algorithm-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Sorting-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Basic%ED%8E%B8</guid>
            <pubDate>Wed, 17 Feb 2021 05:20:57 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💡 자바스크립트 언어로 자료구조 &amp; 알고리즘에 대해 배운 내용을 기록합니다</p>
</blockquote>
<h2 id="📖-intro">📖 Intro</h2>
<p>정렬(Sorting) 은 데이터들을 특정한 순서에 따라 재배치하는 프로세스를 의미합니다</p>
<p>ex) </p>
<ul>
<li>숫자를 오름차순으로 정렬</li>
<li>이름을 알파벳순으로 정렬</li>
<li>영화들을 개봉년도에 따라 정렬</li>
<li>영화들을 매출에 따라 정렬</li>
</ul>
<p>정렬은 매우 흔한 작업이기 때문에 구현과정을 파악하는 것은 좋은 공부가 될 것 같습니다. </p>
<p>정렬에는 다양한 방식들이 있고, 각각 장점과 단점이 있습니다. 정렬 알고리즘들 중에서 가장 기본적인 버블, 선택, 삽입 정렬이 어떤 방식으로 실행되는지, 자바스크립트 코드로는 어떻게 구현되는지 알아보겠습니다</p>
<h2 id="📖-basic-sorting-algorithms">📖 Basic Sorting Algorithms</h2>
<h3 id="1-버블-정렬-bubble-sort">1. 버블 정렬 (Bubble Sort)</h3>
<p>가장 큰 값이 버블처럼 위로 올라가는 모양을 하게 되는 알고리즘입니다</p>
<p><img src="https://images.velog.io/images/young_mason/post/1b3c7830-cbdc-450f-af4f-dcefe2f140d3/bubbleSort.gif" alt=""></p>
<p><strong>Pseudocode</strong></p>
<ul>
<li>i라는 변수를 통해 배열의 마지막 지점에서 시작지점까지 순회하는 반복문을 만듭니다</li>
<li>j라는 변수를 통해 시작점부터 i - 1 까지 순회하는 이중 반복문을 만듭니다</li>
<li>배열의 j번째 요소가 j + 1번째 요소보다 크면, 두 개의 위치를 바꿉니다 (Swap)</li>
<li>만약 Inner Loop 에서 Swap이 발생하지 않는다면, 모두 정렬된 것이므로 반복문을 종료합니다</li>
<li>정렬된 요소를 return 합니다</li>
</ul>
<pre><code class="language-js">function bubbleSort(arr) {
  let noSwaps;
  for (let i = arr.length; i &gt; 0; i--) {
      noSwaps = true;
      for (let j = 0; j &lt; i - 1; j++) {
        if (arr[j] &gt; arr[j+1]) {
            let temp = arr[j];
            arr[j] = arr[j+1];
            arr[j+1] = temp;
            noSwaps = false;

         }
      }
    if (noSwaps) break;
   }
  return arr;
}</code></pre>
<h3 id="2-선택-정렬-selection-sort">2. 선택 정렬 (Selection Sort)</h3>
<p>가장 작은 값을 탐색한다음 Swap을 통해 앞부분에 배치시키는 정렬방식입니다.</p>
<p><img src="https://images.velog.io/images/young_mason/post/d92024f1-c463-4674-8c16-b247587e8a78/selectionSort.gif" alt=""></p>
<p><strong>Pseudocode</strong></p>
<ul>
<li>첫번째 요소를 min이라는 변수에 저장합니다</li>
<li>반복문을 통해 min을 다음요소들과 비교하면서 가장 작은 값을 min에 할당합니다</li>
<li>만약 min이 최초에 저장한 값이 아니라면, 두 값을 swap 합니다</li>
<li>arr의 모든 요소에 위 작업을 반복한 후 정렬된 배열을 리턴합니다</li>
</ul>
<pre><code class="language-js">function selectionSort(arr) {
  const swap = (arr, idx1, idx2) =&gt; {
    [arr[idx1], arr[idx2]] = [arr[idx2], arr[idx1]];
  }

  for (let i = 0; i &lt; arr.length; i++) {
      if (arr[min] &gt; arr[j]) {
        min = j;
      }
   }

  if (arr[min] !== arr[i]) {
     swap(arr, i, min);
  }

  return arr;
}
</code></pre>
<h3 id="3-삽입-정렬-insertion-sort">3. 삽입 정렬 (Insertion Sort)</h3>
<p>배열 두번째 요소부터 모든 요소를 앞부분에 이미 정렬된 배열 부분과 비교하여, 자신의 위치를 찾아 삽입하는 방식의 정렬 알고리즘입니다</p>
<p><img src="https://images.velog.io/images/young_mason/post/37bc591b-c64e-498b-bea6-98f0c40da0f2/insertionSort.gif" alt=""></p>
<p><strong>Pseudocode</strong></p>
<ul>
<li>배열의 두번째 요소를 Pick</li>
<li>두 번째 요소를 첫번째요소와 비교하고, 필요하다면 Swap</li>
<li>다음 요소로 계속 반복, 만약 순서가 틀리다면, 정렬된 부분을 순회하면서 정확한 위치에 배치한다</li>
<li>정렬될때까지 반복한다</li>
</ul>
<pre><code class="language-js">function insertionSort(arr) {

  for (let i = 1; i &lt; arr.length; i++) {
    let currentVal = arr[i];
    let targetIdx = 1;

    for (let j = i - 1; j &gt;= 0 &amp;&amp; arr[j] &gt; currentVal; j--) {
        targetIdx = j;
        arr[targetIdx + 1] = arr[targetIdx]; 
    }
    if (targetIdx) {
      arr[targetIdx] = currentVal;
    }
  }
  return arr;
}
</code></pre>
<h2 id="📖-시간복잡도">📖 시간복잡도</h2>
<p>지금까지 알아본 3가지 정렬 알고리즘의 시간복잡도는 아래와 같습니다</p>
<p><img src="https://images.velog.io/images/young_mason/post/22867372-81de-4730-a25a-5215029247df/image.png" alt=""></p>
<p>전반적으로 O(n^2) 의 비효율적인 시간복잡도를 갖습니다.
이미 어느정도 정렬이 되어있는 배열에서 버블 정렬과 삽입 정렬을 실행할 경우, O(n)의 시간복잡도를 갖게됩니다. 선택 정렬의 경우 이미 정렬이 어느정도 되어있다 하더라도 모든 요소들을 순회하면서 최소값을 탐색하게 되므로, 여전히 시간복잡도는 O(n^2)이 됩니다</p>
<h2 id="📖-reference">📖 Reference</h2>
<p><a href="https://visualgo.net/en/sorting">Visualgo</a>
<a href="https://www.toptal.com/developers/sorting-algorithms">Sorting Algorithm Animations</a>
<a href="https://www.udemy.com/course/js-algorithms-and-data-structures-masterclass/">Udemy - Javascript Algorithms and Data Structures Masterclass</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 02 - Types]]></title>
            <link>https://velog.io/@young_mason/TypeScript-02-Types</link>
            <guid>https://velog.io/@young_mason/TypeScript-02-Types</guid>
            <pubDate>Sat, 13 Feb 2021 13:46:12 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>🌟  타입스크립트를 학습하면서 배운 내용들을 블로그에 기록합니다 (feat. 드림코딩)</p>
</blockquote>
<h2 id="✐-타입이란-타입의-원칙">✐ 타입이란? (타입의 원칙)</h2>
<ul>
<li>변수는 데이터를 담을 상자와 같다. 타입을 지정해준다는 것은 이 상자에 라벨을 붙여서 안에 들어가야할 내용물을 명시하는 것이라고 이해할 수 있다.</li>
<li>변수 뿐만 아니라 객체의 키와 값, 함수의 Input, ouput에서도 타입을 명시해주는 것이 좋다</li>
<li>최대한 타입이 보장되는 방식으로 선택해서 프로그래밍 하는것이 중요하다!</li>
</ul>
<h2 id="✐-basic-types">✐ Basic Types</h2>
<ul>
<li><strong>number</strong>  |  <strong>string</strong>  |  <strong>boolean</strong></li>
</ul>
<pre><code class="language-tsx">const num: number = -6;  // number

const str: string = &#39;hello&#39;;  // string

const boal: boolean = false;  // boolean</code></pre>
<ul>
<li><strong>undefined</strong> | <strong>null</strong>  | <strong>unkwown</strong> | <strong>any</strong></li>
</ul>
<pre><code class="language-tsx">/* undefined */ 

let name: undefined; // 💩 이런식으론 잘 쓰이지 않음

let age: number | undefined // number타입 혹은 undefined
age = undefined;
age = 1;  

/* null */

let person: null; // 💩
let person: string | null;

/* unknown : 💩 모든 타입이 허용되므로 잘 쓰이지 않음 */

let notSure: unknown = 0;
notSure = &#39;he&#39;;
notSure = true;

/* any : 💩 모든 타입이 허용되므로 잘 쓰이지 않음 */

let anything: any = 0;
anything = &#39;hello&#39;;
</code></pre>
<ul>
<li><strong>void</strong> | <strong>never</strong> | <strong>object</strong></li>
</ul>
<pre><code class="language-tsx">/* void : 아무것도 리턴하지 않는 함수의 타입 (생략 가능) */

function print(): void {
  console.log(&#39;hello&#39;);
  return;
}

let unusable: void = undefined; // 💩

/* never : 절대 리턴되지 않는 함수에 대해 명시하기 위해 쓰임 (에러, 무한루프 등)  */

function throwError(message: string): never {
  throw new Error(message);
  // while (true) {}
}

/* object : function, array 모두 object에 포함되므로 보다 더 정확하게 명시해야함 */ 

let obj: object; //💩
function acceptSomeObject(obj: object) {}
acceptSomeObject({ name : &#39;Mason&#39; })
</code></pre>
<h2 id="✐-function">✐ Function</h2>
<ul>
<li><strong>Basic</strong></li>
</ul>
<pre><code class="language-tsx">function add(num1: number, num2: number): number {
  return num1 + num2;
}

/* Promise 리턴하는 경우 */
function fetchNum(id: string): Promise&lt;number&gt; {
  // fetch code...
  return new Promise((resolve, reject) =&gt; {
    resolve(100);
  });
}</code></pre>
<ul>
<li><strong>인자를 옵셔널하게 받는 경우 ( Optional Parameter )</strong></li>
</ul>
<pre><code class="language-tsx">function printName(firstName: string, lastName?: string) {
  console.log(firstName);
  console.log(lastName);
}

printName(&#39;Steve&#39;, &#39;Jobs&#39;);  // &#39;Steve&#39;, &#39;Jobs&#39;
printName(&#39;Mason&#39;); // &#39;Mason&#39;, &#39;undefined&#39;</code></pre>
<ul>
<li><strong>인자에 디폴트 값을 추가하는 경우 ( Default Parameter )</strong></li>
</ul>
<pre><code class="language-tsx">function printMessage(message: string = &#39;default message&#39;) {
  console.log(message);
}

printMessage(); // &#39;default message&#39;</code></pre>
<ul>
<li><strong>인자 개수가 정해져 있지 않은 경우 ( Rest Parameter )</strong></li>
</ul>
<pre><code class="language-tsx">function addNumbers(...numbers: number[]): number {
  return numbers.reduce((a, b) =&gt; a + b);
}

addNumbers(1, 2); // 3
addNumbers(1, 2, 3, 4, 5); // 15</code></pre>
<h2 id="✐-array">✐ Array</h2>
<ul>
<li><strong>array</strong></li>
</ul>
<pre><code class="language-tsx">// 첫 번째 방법 - elementType[]
const fruits: string[] = [&#39;apple&#39;, &#39;banana&#39;];

// 두 번째 방법 - Array&lt;elementType&gt;
const scores: Array&lt;number&gt; = [1, 3, 4];

// immutable 배열 인자로 받기
function printArray(fruits: readonly string[]) {}</code></pre>
<ul>
<li><strong>tuple</strong></li>
</ul>
<pre><code class="language-tsx">let student: [string, number];
student = [&#39;name&#39;, 123];
student = [123, &#39;name&#39;]; // Error!
student[0]; // name;
student[1]; // 123

const [name, age] = student;

// Tuple은 인덱스로 접근해야 하므로 가독성이 떨어지는 편..
// 주로 interface, type alias, class 방식으로 대체하여 사용</code></pre>
<h2 id="✐-type-alias">✐ Type Alias</h2>
<ul>
<li><strong>커스텀 타입 만들기 ( Type Alias )</strong></li>
</ul>
<pre><code class="language-tsx">type Text = string; // Text 라는 타입을 생성
const name: Text = &#39;Mason&#39; // name 변수에 Text 타입 적용

// 객체에 type alias 적용하기
type Student = {
  name: string,
  age: number
}

const me: Student {
  name: &#39;Mason&#39;,
  age: 29
}</code></pre>
<ul>
<li><strong>값 자체를 타입으로 결정할 수 있음 ( String Literal Types )</strong></li>
</ul>
<pre><code class="language-tsx">
type JSON = &#39;json&#39;;
const json: JSON = &#39;json&#39;;
const json: JSON = &#39;others&#39; // Error!</code></pre>
<h2 id="✐-union">✐ Union</h2>
<ul>
<li><p><strong>여러 값을 타입으로 지정 할 수 있음 ( Union Types )</strong></p>
<p>활용도가 높다 👍 </p>
</li>
</ul>
<pre><code class="language-tsx">type Direction = &#39;left&#39; | &#39;right&#39; | &#39;up&#39; | &#39;down&#39;;
function move(direction: Direction) {
  console.log(direction);
}
move(&#39;down&#39;);

type TileSize = 8 | 16 | 32;
const tile: TileSize = 16;
</code></pre>
<ul>
<li><strong>실전 로그인 예제</strong></li>
</ul>
<pre><code class="language-tsx">// Discriminated Union
// 동일한 키(result), 다른 값을 가지게 함 
// -&gt; printLoginState 함수 내에서 state.result 에 접근할 수 있음

type SuccessState = {
  result:&#39;success&#39;;
  response: string;
}
type failState = {
  result: &#39;fail&#39;;
  reason: string;
}
type LoginState = SuccessState | FailState;

function login(): LoginState {
  return {
    result: &#39;success&#39;,
    response: {
      body: &#39;logged in!&#39;
    }
  };
}

function printLoginState(state: LoginState) {
  if(state.result) {
    console.log(`🎉 ${state.response.body}`);
  } else {
    console.log(`😭 ${state.reason}`)
  }
}</code></pre>
<h2 id="✐-intersection-types">✐ Intersection Types</h2>
<ul>
<li><strong>다양한 타입들을 묶어서 선언할 수 있음</strong></li>
</ul>
<pre><code class="language-tsx">type Student = {
  name: string;
  score: number;
}

type Worker = {
  employeeId: number;
  work: () =&gt; void;
}

function internWork(person: Student &amp; Worker) {
  console.log(person.name, person.employeeId, person.work());
}

internWork({
  name: &#39;mason&#39;,
  score: 1,
  employeeId: 123,
  work: () =&gt; {}
})</code></pre>
<h2 id="✐-enum">✐ Enum</h2>
<ul>
<li><strong>여러가지 상수 값들을 한 곳에 모아서 정의할 수 있도록 도와주는 타입</strong></li>
</ul>
<pre><code class="language-tsx">// JavaScript
const MAX_NUM = 6;
const MAX_STUDENTS_PER_CLASS = 10;
const DAYS_ENUM = Object.freeze({&quot;MONDAY&quot;: 0, &quot;TUESDAY&quot;: 1, &quot;WEDNESDAY&quot;: 2});
const dayOfToday = DAYS_ENUM.MONDAY;

// TypeScript
enum Days {
  Monday, // enum에 값을 할당 할 수 있다. ex) Monday = &#39;mon&#39;
  Tuesday,
  Wednesday,
}

// 값이 할당 되지 않으면 0부터 차례대로 할당된다
let day = Days.Monday
console.log(day) // -&gt; 0 .. 

// enum에 값이 할당된 뒤 다른 값을 할당할 수 있다 (타입이 정확하게 보장되지 않음)
day = 10

// 따라서 타입스크립트에서 enum을 가급적 쓰지 않는 것이 좋으며 Union 타입으로 대체 가능하다
type dayOfWeek = &#39;Monday&#39; | &#39;Tuesday&#39; | &#39;Wednesday&#39;
</code></pre>
<h2 id="✐-inference">✐ Inference</h2>
<ul>
<li><strong>타입 추론 ( Type Inference )</strong></li>
</ul>
<pre><code class="language-tsx">let text = &#39;hello&#39;;
text = 1 // Error!

// 인자에 타입을 명시하지 않으면 any로 추론
function print(message = &#39;hello&#39;) {
  console.log(message);
}
print(&#39;hello&#39;);
print(1);

function add(x: number, y: number) {
    return x + y;
}
// 리턴 타입을 명시하지 않아도 number로 추론
const result = add(1, 2) // type: number
</code></pre>
<p>그래도 타입은 정확하게 명시해 주는게 좋다 😭</p>
<h2 id="✐-type-assertion">✐ Type Assertion</h2>
<ul>
<li><strong>정말 있다고 장담할 수 있을 때 사용하기 ( ! )</strong></li>
</ul>
<pre><code class="language-tsx">function jsStrFunc(): any {
    return 2;
  }
  const result = jsStrFunc();
  console.log((result as string).length);
  console.log((&lt;string&gt;result).length);

  const wrong: any = 5;
  console.log((wrong as Array&lt;number&gt;).push(1)); // 😱

  function findNumbers(): number[] | undefined {
    return undefined;
  }
  const numbers = findNumbers()!;
  numbers.push(2); // 😱

  const button = document.querySelector(&#39;class&#39;)!;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 01 - Intro]]></title>
            <link>https://velog.io/@young_mason/TypeScript-01-Intro</link>
            <guid>https://velog.io/@young_mason/TypeScript-01-Intro</guid>
            <pubDate>Sat, 13 Feb 2021 03:56:53 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>🌟  타입스크립트를 학습하면서 배운 내용들을 블로그에 기록합니다 (feat. 드림코딩)</p>
</blockquote>
<h2 id="✐-typescript란">✐ TypeScript란?</h2>
<h3 id="superset-of-javascript"><strong>Superset of JavaScript</strong></h3>
<p>→  자바스크립트에 <strong>Type</strong>을 더해서 컴파일시 타입에 관련된 에러를 잡을 수가 있다.</p>
<p>→  <strong>class</strong>, <strong>interface</strong>, <strong>generic</strong>을 활용하여 강력한 객체지향 프로그래밍 언어를 구현할 수 있다</p>
<p>→  모든 브라우저 호환되도록 만들 수 있다</p>
<p>→  클라이언트, 서버 모두 가능</p>
<h2 id="✐-기존-javascript-의-특징">✐ 기존 JavaScript 의 특징</h2>
<h3 id="런타임에서-타입이-결정된다-dynamically-typed">런타임에서 타입이 결정된다 (<strong>Dynamically Typed</strong>)</h3>
<p>→ 장점 : Easy, Flexible, Fast</p>
<p>→ 단점 : 가독성이 좋지 않으며, 개발시에 이슈를 잡아내는 것이 아니기 때문에 사용자가 애플리케이션을 사용할때 에러가 터지므로 위험하다</p>
<p>→ EC6 이후 Class 문법이 도입되었지만 다른 언어에 비해 객체지향 기능이 적다</p>
<h2 id="✐-typescript가-뜨는-이유">✐ TypeScript가 뜨는 이유</h2>
<h3 id="1-컴파일시-타입이-결정된다-statically-typed">1. 컴파일시 타입이 결정된다 (<strong>Statically Typed)</strong></h3>
<p>타입이 정적으로 결정된다 (코딩할 때) 타입에러를 즉각적으로 받아볼 수 있다</p>
<p>→ 개발시에 실시간으로 에러에 대한 검사를 받을 수 있어서 안정적이고 확장이 쉬운 소프트웨어를 만들 수 있다</p>
<h3 id="2--객체-지향-프로그래밍-object-oriented-programming">2.  객체 지향 프로그래밍 (Object-Oriented Programming)</h3>
<ul>
<li>Modularity</li>
<li>Reusabilit</li>
<li>Extensible</li>
<li>Maintainability</li>
</ul>
<p>→ 생산성, 높은 퀄리티 코드, 빠른 제품 완성</p>
<h2 id="✐-typescript-세팅">✐ TypeScript 세팅</h2>
<h3 id="기본-설치">기본 설치</h3>
<pre><code class="language-js">// Global 에 설치하기
npm install -g typescript

// 프로젝트 내에 설치하기
npm install typescript --save-dev
</code></pre>
<h3 id="노드-환경에서-실행하려면">노드 환경에서 실행하려면?</h3>
<pre><code class="language-js">// 컴파일 : main.js 파일 생성 후 node로 실행
tsc main.ts
node main.js

// ts-node : 노드 환경에서 컴파일과 실행을 한번에
npm install -g ts-node
ts-node main.ts     

// ts-node watch : 저장하면 자바스크립트 코드에 자동으로 반영해줌
ts-node main.ts -watch
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Momojito] 파이널 프로젝트에 Next.js 적용 후 느낀 장점들]]></title>
            <link>https://velog.io/@young_mason/%ED%8C%8C%EC%9D%B4%EB%84%90-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-Next.js-%EC%A0%81%EC%9A%A9-%ED%9B%84-%EB%8A%90%EB%82%80-%EC%9E%A5%EC%A0%90%EB%93%A4</link>
            <guid>https://velog.io/@young_mason/%ED%8C%8C%EC%9D%B4%EB%84%90-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-Next.js-%EC%A0%81%EC%9A%A9-%ED%9B%84-%EB%8A%90%EB%82%80-%EC%9E%A5%EC%A0%90%EB%93%A4</guid>
            <pubDate>Sun, 07 Feb 2021 12:41:32 GMT</pubDate>
            <description><![CDATA[<p>👇 Momojito에 대해 자세히 알아보러 가시려면?👇
<a href="https://momojito.net/">배포 주소</a> , <a href="https://github.com/codestates/momojito_Client">Github Repo</a>, <a href="https://youtu.be/0S49UQj-SDo">서비스 발표 영상</a></p>
<p>기획 단계를 마무리하고 본격적인 개발에 들어가면서 가장 먼저 한 것은 React에서 Next.js 프레임워크를 이용하기 위한 환경을 세팅하는 것이었습니다.</p>
<p>Next.js는 Dynamic Routing과 Pre-Rendering을 기반으로, 빌드 시점에 정적인 html 페이지들을 생성해서 깜빡임 없는 빠른 페이지 전환을 가능하게 하는 프레임워크입니다.
서버 사이드 랜더링과 클라이언트 사이드 랜더링을 필요에 따라 이용할 수 있도록 지원하며, 각 페이지마다 SEO를 최적화시키는데 유용합니다.</p>
<p>팀원 중 도현님께서 이런 신문물의 존재와, 칵테일 요소마다 상세페이지를 가지게 되는 저희 프로젝트 구조에 적용하기 적합하다는 점을 설명해주셔서, 주저없이 사용해보기로 결정하였습니다. </p>
<p>코드스테이츠 정규 과정에서 배우지 않았던 스택이라 세팅부터 막막했지만, 공식문서 번역에 투자했던 하루이틀의 시간과, 이미 어느정도 next.js 컨셉에 대해 이해를 하고 계셨던 팀원분 덕분에 프로젝트에 적용할 수 있었습니다.</p>
<h3 id="파일-시스템-기반의-라우팅으로-폴더-구조를-세팅하기-편리하다-dynamic-routing">파일 시스템 기반의 라우팅으로, 폴더 구조를 세팅하기 편리하다. (Dynamic Routing)</h3>
<p>create-next-app 명령어를 이용하여 초기 환경을 셋업하고 나서, pages 디렉토리 안에 리액트 컴포넌트 파일을 생성하면, 해당되는 파일명에 따라 라우팅 페이지가 자동으로 생성됩니다. 따라서 라우팅 구조를 만드는 방식이 이전에 사용했던 React-dom-router 보다 상당히 간편했습니다.</p>
<p><img src="https://images.velog.io/images/young_mason/post/3331112e-1b13-4bf3-800c-2561e2ec03dd/image.png" alt=""></p>
<p>주어진 데이터에 따라서 라우팅을 하는 것도 가능합니다. pages 디렉토리 안에 새로운 디렉토리를 생성 후 대괄호로 감싼 [id].js파일을 만들고  json 형식으로 된 데이터에서 id값을 넘겨받게 되면,  데이터에 있는 모든 id 값에 따라 라우팅이 구성됩니다. 다이나믹 라우팅 기능을 이용하여 제품의 상세페이지같은 서비스들의 동적 페이지 생성이 가능해집니다.</p>
<p><img src="https://images.velog.io/images/young_mason/post/86072d77-ba0b-4cc8-8b5b-209085ff7efc/image.png" alt=""></p>
<h3 id="static-site-generation을-통해-빠른-페이지-전환이-가능하다">Static Site Generation을 통해 빠른 페이지 전환이 가능하다</h3>
<p>Static-Site Generation는 Pre-rendering 방식 중 하나입니다. <code>getStaticProps</code> 메소드를 통해 동적인 데이터를 받을 수 있고, 빌드 시점에 HTML파일들을 생성하며, 생성된 html파일을 모든 유저가 동일하게 내려받게 됩니다. 각 페이지마다 생성된 정적인 html파일들을 배포하게 되면 페이지들간 전환 시 딜레이타임이 눈에띄게 줄어듭니다.</p>
<p><img src="https://images.velog.io/images/young_mason/post/cbe82056-9285-4572-9ef5-2040d29889ab/image.png" alt=""></p>
<p><code>getStaticPaths</code> 메소드를 이용하면, Dynamic routing 으로 생성된 모든 페이지들을 정적으로 생성할 수 있습니다.</p>
<p><img src="https://images.velog.io/images/young_mason/post/f49262fa-be32-4fe2-8124-76867fcd3a2a/ssg.png" alt=""></p>
<h3 id="seo-최적화에-유리하다">SEO 최적화에 유리하다</h3>
<p>Next.js를 이용하면 필요한 부분만 렌더링하여 페이지마다 메타태그 설정에 어려움이 있는 기존 SPA의 단점을 보완할 수 있습니다.</p>
<p>Static Site를 통해 모든 html을 미리 생성할 때, 각 상세페이지마다 쉽게 메타태그를 설정해줄 수 있어서, 검색엔진에서 검색 시 모든 페이지마다 메타태그 내에 정보들이 노출될 수 있도록 해주는 효과를 얻을 수 있습니다.</p>
<p><img src="https://images.velog.io/images/young_mason/post/d022b8fe-5960-4ce5-9d0d-7a904cc51e16/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Momojito] 칵테일 컨텐츠 제공 서비스  :: React&Next.js 4주 프로젝트 돌아보기]]></title>
            <link>https://velog.io/@young_mason/Momojito-%EC%B9%B5%ED%85%8C%EC%9D%BC-%EC%BB%A8%ED%85%90%EC%B8%A0-%EC%84%9C%EB%B9%84%EC%8A%A4-ReactNext.js-4%EC%A3%BC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%8F%8C%EC%95%84%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@young_mason/Momojito-%EC%B9%B5%ED%85%8C%EC%9D%BC-%EC%BB%A8%ED%85%90%EC%B8%A0-%EC%84%9C%EB%B9%84%EC%8A%A4-ReactNext.js-4%EC%A3%BC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%8F%8C%EC%95%84%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Sun, 07 Feb 2021 12:32:23 GMT</pubDate>
            <description><![CDATA[<h2 id="intro">Intro</h2>
<p>코드스테이츠에서 <strong>파이널 프로젝트</strong>로 약 4주간 진행했던 프로젝트가 마무리 됐습니다. 
퍼스트 프로젝트에 이어 새로운 팀에서 다시 한 번  <strong>팀장</strong> 역할을 맡았고 마찬가지로 <strong>프론트엔드</strong> 개발을 담당하였습니다.</p>
<p>서비스이름은 Momojito (모모히또) 입니다. 모모히또는 초보자들에게 생소한 칵테일 정보에 대해 쉽게 접근할 수 있는 칵테일 컨텐츠 제공 서비스입니다. </p>
<p>모두가 스마트폰을 이용하여 간단한 정보들을 탐색한다는 점을 고려해서, 모바일 웹 환경에서의 이용을 중점으로 개발하였습니다. 물론 데스크톱에서도 반응형 UI로 이용하실 수 있습니다 👍</p>
<p>개발에 사용한 기술 스택은 아래와 같습니다</p>
<p><strong>[Front-End]</strong> react(hooks), next.js, d3.js, react-spring, styled-component, axios 
<strong>[Back-End]</strong> node.js, express, jwt, mySQL, sequelize, bcrypt
<strong>[Deploy]</strong> Vercel, S3, EC2, Route53, ELB, ACM, RDS</p>
<p>👇 더 자세히 알아보러 가시려면?👇
<a href="https://momojito.net/">배포 주소</a> , <a href="https://github.com/codestates/momojito_Client">Github Repo</a>, <a href="https://youtu.be/0S49UQj-SDo">서비스 발표 영상</a></p>
<p><img src="https://images.velog.io/images/young_mason/post/12bfbda6-14fe-40cb-b178-37d64d77ca80/main.gif" alt=""></p>
<p><img src="https://images.velog.io/images/young_mason/post/64e6da80-1f86-4b3f-abd1-ea5e614912e1/worldcup.gif" alt=""></p>
<p><img src="https://images.velog.io/images/young_mason/post/fb7dd2b6-fd2b-4794-87e6-bfb352e30e67/quiz.gif" alt=""></p>
<p>재료별 필터링 기능과 함께 대중적인 칵테일 정보들을 탐색 해볼 수 있으며, 이 뿐만 아니라 <strong>퀴즈</strong>, <strong>칵테일 지도</strong>, <strong>이상형 월드컵</strong> 같은 다양한 컨텐츠들도 준비되어 있습니다</p>
<p>이번 글에서는 4주간 프로젝트가 어떤 식으로 흘러갔는지, 어떤 것들을 배우고 느꼈는지 돌아보려고 합니다.</p>
<h2 id="기획-feat-figma의-중요성">기획 (feat. Figma의 중요성)</h2>
<p>첫 프로젝트 회의 때 모두가 무엇인가에 이끌린것처럼 &quot;주류&quot; 관련 키워드에 꽂혀있다가 칵테일 얘기가 나왔습니다. 그럼 칵테일을 주제로 했을 때 어떤 점이 좋을까? 생각해보니 </p>
<ol>
<li>국내에 딱히 칵테일 인포사이트라고 할만한 곳이 없다</li>
<li>칵테일 사진이 들어가면 뭔가 그냥 예쁘다 (레퍼런스로 찾아본 사이트들이 그냥 다 이뻤음..) -&gt; UI 구성에 유리하다</li>
<li>칵테일이 재료의 조합으로 이루어진다는 점을 이용해 다양한 컨텐츠를 구성해볼 수 있다</li>
</ol>
<p>문제라고 할만한게 한가지 있었다면...
&quot;팀원 중 칵테일에 대해 아는사람이 아무도 없다는 것&quot; 😭</p>
<p>이번 기회에 몰랐던 칵테일까지 공부해버리자 마인드로 이렇게 모모히또 프로젝트 (부제: 칵테일 1도 모르는 남자 4명이서 칵테일 정보 사이트를 만든다면?!) 는 시작되었습니다</p>
<p>지난 2주 프로젝트때, 기획단계에서 UI 구성을 디테일하게 해야지 나중에 스트레스 안받는다는 걸 뼈저리게 느꼈었고, 모바일 환경에 대한 기획을 하지 않았던 것에 대한 아쉬움이 컸었습니다. 그래서 이번 기획 기간동안에는 Figma를 이용해서 모바일 UI를 먼저 구성하고, 시간이 걸리더라도 최대한 최종 결과물과 일치하도록 디테일하게 그리기로 팀원들과 합의하고 작업을 시작했습니다. </p>
<p>그 결과... </p>
<p><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fdbd47513-557d-4ca9-a867-fbd761777b9c%2FUntitled.png?table=block&id=416c8a8f-cd63-405e-b89e-97587a304539&spaceId=14cff50a-9d15-48cd-a262-2724a8ab38ba&width=3080&userId=505f5c27-9d71-4cf4-8174-1ef8968c448d&cache=v2" alt=""></p>
<p><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Ff5a0017b-2ef1-4a04-af2d-2134b7d00641%2FUntitled.png?table=block&id=b71f05da-feca-47b2-a9f0-7b0bb55cf73c&spaceId=14cff50a-9d15-48cd-a262-2724a8ab38ba&width=3080&userId=505f5c27-9d71-4cf4-8174-1ef8968c448d&cache=v2" alt=""></p>
<p>이전 프로젝트 때보다 훨씬 발전된 형태로 목업 UI 를 그려놓고 시작할 수 있었습니다. 놀라웠던 점은, 어느정도의 디테일들이 들어간 목업 UI가 구성된 이후부터 팀원들과 커뮤니케이션이 훨씬 쉬워졌다는 것이었습니다. <strong>더 이상 서로가 눈에 안보이는 추상적이고, 주관적인 언어로 의견을 주고받는게 아니라 시각화된 UI를 바탕으로 의견을 주고 받을 수 있게 되어서 커뮤니케이션 효율이 크게 올라갔다는 느낌을 받았습니다.</strong> </p>
<p>이후 와이어프레임, DB스키마, API문서와 같이 기획단계에서 정할 수 있는 것들은 최대한 정한 뒤 공용 Notion 으로 매일 업데이트되는 내용을 체크리스트와 캘린더 형식으로 공유하면서 진행하였습니다. <strong>협업 시 모두가 같은 페이지에서 같은 목표를 공유하는 것의 중요성도 느낄 수 있었습니다</strong></p>
<p><img src="https://images.velog.io/images/young_mason/post/8665afa3-7350-4866-b4f3-6d8822545bc0/image.png" alt=""></p>
<p>(팀 노션)</p>
<p>기획내용에 대해 더 자세히 알고싶으시다면?  👉 <a href="https://github.com/codestates/momojito_Client/wiki">Github wiki</a></p>
<h2 id="nextjs--누구냐-넌">Next.js ?? 누구냐 넌</h2>
<p>기획 단계를 마무리하고 본격적인 개발에 들어가면서 가장 먼저 한 것은 React에서 Next.js 프레임워크를 이용하기 위한 환경을 세팅하는 것이었습니다.</p>
<p>Next.js는 Dynamic Routing과 Pre-Rendering을 기반으로, 빌드 시점에 정적인 html 페이지들을 생성해서 깜빡임 없는 빠른 페이지 전환을 가능하게 하는 프레임워크입니다.
서버 사이드 랜더링과 클라이언트 사이드 랜더링을 필요에 따라 이용할 수 있도록 지원하며, 각 페이지마다 SEO를 최적화시키는데 유용합니다.</p>
<p>팀원 중 도현님께서 이런 신문물의 존재와, 칵테일 요소마다 상세페이지를 가지게 되는 저희 프로젝트 구조에 적용하기 적합하다는 점을 설명해주셔서, 주저없이 사용해보기로 결정하였습니다. </p>
<p>코드스테이츠 정규 과정에서 배우지 않았던 스택이라 세팅부터 막막했지만, 공식문서 번역에 투자했던 하루이틀의 시간과, 이미 어느정도 next.js 컨셉에 대해 이해를 하고 계셨던 팀원분 덕분에 프로젝트에 적용할 수 있었습니다.</p>
<p>Next.js를 사용하면서 느꼈던 점은 따로 포스팅 하였습니다. 
👉 <a href="https://velog.io/@young_mason/%ED%8C%8C%EC%9D%B4%EB%84%90-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-Next.js-%EC%A0%81%EC%9A%A9-%ED%9B%84-%EB%8A%90%EB%82%80-%EC%9E%A5%EC%A0%90%EB%93%A4">파이널 프로젝트에 Next.js 적용 후 느꼈던 장점들</a></p>
<h2 id="재사용-가능한-ui-컴포넌트-만들기">재사용 가능한 UI 컴포넌트 만들기</h2>
<p>파이널 프로젝트를 진행하면서 이전까지 생각하지 못했던 개념을 팀원분들께 배울 수 있었습니다. 바로 <strong>재사용 가능한 컴포넌트</strong>를 만든다는 개념인데요, 2주 프로젝트때는 이런 개념에 대해 생각하지 못했기 때문에 버튼, 모달 등 주로 쓰는 컴포넌트를 그때그때 새로 만들어서 중복되는 코드가 생기는 것을 그냥 방치했었습니다.</p>
<p>하지만 이번에는 props 로 받을 변수를 적절하게 세팅함으로써, 하나의 컴포넌트 파일을 만들어 여러 곳에서 재사용 가능하도록 만들기 위해 노력하였습니다.</p>
<p>예를들어, 퀴즈 컨텐츠와 이상형 월드컵 컨텐츠를 끝까지 플레이 하시면 나오는 결과페이지에 <strong>카카오톡 공유하기</strong> 기능과 <strong>댓글</strong> 기능이 있습니다. 이 두 기능 모두 하나의 컴포넌트에서 props로 컨텐츠가 이상형월드컵인지 퀴즈인지에 대한 정보를 전달받아서 다른 데이터를 출력합니다.</p>
<p>대부분의 버튼과 캐러샐, 모달창도 팀원들과 함께 이런 방식으로 컴포넌트를 모듈화해서 최대한 재사용 가능하게끔 구현할 수 있었습니다. 이로 인해 <strong>코드 가독성이 좋아졌으며 파일 구조가 예전해비해 훨씬 더 단순해졌다는 것을 느낄 수 있었습니다</strong></p>
<p><img src="https://images.velog.io/images/young_mason/post/ed22c4af-f7e3-4971-a8b6-7fcc9f93dd78/image.png" alt=""></p>
<p>(퀴즈 결과페이지)</p>
<h2 id="기타-전반적인-회고">기타 전반적인 회고</h2>
<h3 id="좋았던-점">[좋았던 점]</h3>
<ul>
<li><p>먼저 개인적으로도 그렇고 팀원들도 상당히 만족했던 프로젝트였습니다. 기획단계에서 3주차까지 개발할 <strong>기본기능(Bare minimum)</strong>들을 정하고, 4주차에 시간이 남으면 구현할 <strong>심화기능(Advanced Task)</strong>을 정했었는데 그러한 일정들이 딱딱 맞아서 3주차때 정말 모든 기본 기능에 <strong>반응형 UI</strong>와 배포까지 완료되어 있었습니다. 이미 3주차 결과물로도 충분히 만족스러웠고, 4주차에는 버그 해결과 몇몇 심화기능에만 집중하면 되는 상황이었기 때문에 프로젝트 전반적으로 받았던 스트레스가 적었습니다.</p>
</li>
<li><p>위와 연결되는 내용인데, 팀웍이 너무 좋았습니다. 팀원들 모두가 프로젝트에 성실하셨고 적극적으로 좋은 의견을 계속 제시해주셨습니다. 어떻게 보면 초반에 타이트하게 일정을 잡은 느낌이 있었는데, 무리없이 하나하나 문제들을 해결해나가시는 것을 보면서 저도 힘이 많이 났던 것 같습니다. <strong>배울 점 많은 팀원들과 같이 하게 된게 가장 좋았던 점입니다.</strong></p>
</li>
<li><p>개인적으로는 전체 페이지 UI / UX 에 대해 주도적으로 관여하면서 여러가지 시도해본 것들이 많았기 때문에 좋은 경험이 되었습니다. 특히 유저가 로그인을 하지 않아도 많은 기능을 이용해볼 수 있도록 구현된 점이 만족스럽습니다. Pinterest 통해 얻은 칵테일 이미지들의 배경을 제거하는 작업, 칵테일 설명 하나하나 가져와서 편집하는 일, 칵테일맵 애니메이션에 들어갈 벡터이미지를 구하는 등 코딩 외적인 일들도 많았지만 지금 생각하면 <strong>UI/UX에 대한 시야가 조금 더 넓어지게 된 계기가 된 것 같습니다.</strong> </p>
</li>
<li><p>이번 프로젝트를 통해 배운 새로운 스택(next.js, d3.js)들이 상당히 맘에 듭니다. next.js에 대해서는 블로깅과 기술발표 영상을 통해 프론트엔드 기술에 대한 이해도를 넓힐 수 있었습니다. 또한 d3를 통해 칵테일맵을 구현한건 다른 팀원분이었지만, <strong>데이터 시각화</strong>라는 키워드를 어떻게 적재적소에 쓸 수 있는지 처음 알게 되었습니다. 이번 프로젝트를 계기로 데이터 시각화에 더욱더 많은 관심을 가지게 되었습니다.</p>
</li>
</ul>
<h3 id="아쉬웠던-점">[아쉬웠던 점]</h3>
<ul>
<li><p>전체적으로 모바일 UI를 먼저 구성하고, 이후에 데스크톱 UI를 구성하다보니 대부분의 모바일 UI 요소들을 데스크톱에서 재사용하게 되었습니다. (데스크톱 UI 목업 그릴때쯤 이미 체력 고갈...ㅠ) 그래서 데스크톱에서 봤을 때 매력이 좀 떨어진다는 점이 아쉬습니다. <strong>디자이너의 중요성을 절실히 깨달았습니다..</strong></p>
</li>
<li><p>서비스 자체에 매력이 있나..? 고 자문했을 때 자신있게 답하기 어려울 것 같습니다. 결국 인포사이트는 컨텐츠의 양과 질이 중요한데, 확보한 칵테일 데이터가 생각보다 적습니다.. 특히 칵테일 재료에 대한 데이터들은 이름만 나열되있고 디테일 까지 구현하기까지는 손이 모자랐기에 이런 점들이 아쉽습니다.</p>
</li>
</ul>
<h2 id="앞으로의-계획">앞으로의 계획</h2>
<p>최우선 목표는 프론트엔드 개발자로의 취업입니다.</p>
<p>아직 타입스크립트를 이용해본 적이 없기 때문에, 개인적으로 타입스크립트를 학습하면서 리팩토링 해보려고 합니다.</p>
<p>또한, 데이터 시각화라는 분야에 관심이 많이 가기 시작했습니다. d3를 이용해 대시보드를 만들어보는 프로젝트에도 개인적으로 도전해보고 싶습니다 :) </p>
<h2 id="개발하면서-참고한-사이트들">개발하면서 참고한 사이트들</h2>
<p><a href="https://www.thecocktaildb.com/">✐ 칵테일DB.com</a>
<a href="https://www.absolutdrinks.com/ko/">✐ 앱솔루트 공식사이트 </a>
<a href="https://namu.wiki/w/%EB%AA%A8%ED%9E%88%ED%86%A0?from=%EB%AA%A8%ED%9E%88%EB%98%90">✐ 갓무위키</a>
<a href="https://www.youtube.com/watch?v=qYlzca11Tbc&amp;t=1s">✐  [youtube] 살면서 알아두면 좋을 74가지 칵테일</a>
<a href="https://codesandbox.io/embed/j0y0vpz59">✐ 칵테일 이상형 월드컵 레퍼런스</a>
<a href="https://observablehq.com/@d3/zoomable-circle-packing">✐ 칵테일 지도에 사용한 d3.js 레퍼런스</a>
<a href="http://haveadrink.msiek.com/">✐ 언젠간 꼭 이렇게 만들어보고 싶습니다...🥲</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Next.js 공식 튜토리얼 뿌시기] 2. Pre-rendering과 Static Generation]]></title>
            <link>https://velog.io/@young_mason/Next.js-%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C-%EB%BF%8C%EC%8B%9C%EA%B8%B0-2</link>
            <guid>https://velog.io/@young_mason/Next.js-%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C-%EB%BF%8C%EC%8B%9C%EA%B8%B0-2</guid>
            <pubDate>Sat, 30 Jan 2021 14:27:35 GMT</pubDate>
            <description><![CDATA[<p>프로젝트에 적용하기 위해 학습목적으로 직접 공식문서의 튜토리얼 부분을 번역하였습니다. 혹시 부족한 부분이 있다면 코멘트 남겨주시면 감사드리겠습니다 :)</p>
<p><a href="https://nextjs.org/learn/basics/data-fetching/pre-rendering">https://nextjs.org/learn/basics/data-fetching/pre-rendering</a></p>
<h3 id="✐-pre-rendering">✐ Pre-rendering</h3>
<p>기본적으로, Next.js는 모든 페이지를 미리 불러옵니다(<strong><em>pre-rendering</em></strong>). 이것은 Next.js가 클라이언트 자바스크립트로 모든 작업을 수행하는 것이 아니라, 각 페이지들에 대한 HTML을 미리 생성한다는 것을 의미합니다. Pre-rendering 기능은 퍼포먼스 및 SEO 성능을 향상시킵니다.</p>
<p>생성된 각각의 HTML에는 해당 페이지에 필요한 최소한의 자바스크립트 코드만 연결되어 있습니다. 페이지가 브라우저에서 로드되면, 그에 따른 자바스크립트 코드가 실행되면서 페이지를 완전히 interactive 하게 만듭니다. 이 과정을 <strong>hydration</strong> 이라고 부릅니다</p>
<h3 id="✐-pre-rendering-확인하기">✐ Pre-rendering 확인하기</h3>
<p>다음 과정을 따라가면, pre-rendering이 작동하는 것을 확인하실 수 있습니다.</p>
<ul>
<li>브라우저에서 자바스크립트 사용을 중지시킵니다.</li>
<li>그 다음, <a href="https://next-learn-starter.now.sh/">여기 페이지로 접속해보세요</a></li>
</ul>
<p>자바스크립트 없이도 App이 렌더되는 것을 볼 수 있습니다. 이것은 Next.js가 정적인 HTML을 미리 불러와서, 자바스크립트 코드 없이도 UI를 확인할 수 있도록 해주기 때문입니다.</p>
<p>만약 일반적인 React.js 앱에서 Next.js없이 이 과정을 진행한다면, 앱을 실행시키기 위해서는 자바스크립트를 사용해야한다는 오류메세지를 볼 수 있을겁니다. 이것은 정적인 HTML이 pre-render 되지 않았기 때문입니다.</p>
<h3 id="✐-pre-rendering-vs-no-pre-rendering">✐ Pre-rendering vs No Pre-rendering</h3>
<p><strong>Pre-rendering</strong> </p>
<ul>
<li>initial Load : 먼저 미리 받아온 HTML이 화면에 보여집니다.</li>
<li>Hydration : 리액트 컴포넌트가 초기화되면서 앱이 interactive 하게 바뀝니다. <code>&lt;Link/&gt;</code> 처럼 interactive한 컴포넌트들은 자바스크립트가 로드된 이후 활성화됩니다 .
<img src="https://images.velog.io/images/young_mason/post/84b4ae5a-9da6-4419-a27b-6a4e20ee7560/pre-rendering.png" alt=""></li>
</ul>
<p><strong>No Pre-rendering</strong> </p>
<ul>
<li>initial Load : 앱이 렌더되지 않습니다</li>
<li>Hydration : 리액트 컴포넌트가 초기화되면서 앱이 interactive하게 바뀝니다 .
<img src="https://images.velog.io/images/young_mason/post/e5e00a95-39ce-4d9a-9d59-c87ffba2ac0b/no-pre-rendering.png" alt=""></li>
</ul>
<h3 id="두-가지-방식의-pre-rendering">두 가지 방식의 Pre-rendering</h3>
<p>Next.js에는 두가지 Pre-rendering 방식이 있습니다. 언제 페이지에 대한 HTML을 생성하는지에 따라 차이가 있습니다.</p>
<ul>
<li><strong>Static Generation</strong> : 
빌드 시 HTML을 생성하며, 각 요청에 따라 재사용됩니다.<img src="https://images.velog.io/images/young_mason/post/159c7c8b-823a-47a8-8448-d18d9eb291de/static-generation.png" alt=""></li>
</ul>
<ul>
<li><strong>Server-side Rendering</strong> : 
각 요청에 따라 HTML을 생성합니다. 
<img src="https://images.velog.io/images/young_mason/post/9954aab7-046a-4334-b018-a04c934dec69/server-side-rendering.png" alt=""></li>
</ul>
<blockquote>
<p><code>npm run dev</code> 혹은 <code>yarn dev</code> 명령어를 통해 development mode 가 실행되어있는 경우, Static Generation을 이용한 경우에도, 각 요청에 대해 모든 페이지가 미리 렌더링됩니다.</p>
</blockquote>
<h3 id="✐-페이지마다-다르게-설정하기">✐ 페이지마다 다르게 설정하기</h3>
<p>중요한 사실은, Next.js에서 각 페이지에 사용할 Pre-rendering 방식을 선택할 수 있다는 것입니다. 대부분의 페이지들에 Static Generation 방식을 사용하고, 나머지는 Server-side Rendering 방식을 사용하는 &quot;하이브리드&quot; Next.js 앱을 만들 수 있습니다.
<img src="https://images.velog.io/images/young_mason/post/44ec993b-fcd5-44f7-8532-c160f681ddf5/per-page-basis.png" alt=""></p>
<h3 id="✐-언제-사용해야-할까요">✐ 언제 사용해야 할까요?</h3>
<p>Static Generation vs Server-side Rendering </p>
<p>가능하면 언제든지 Static Generation 방식을 사용하는 것이 좋습니다. 왜냐하면 페이지가 한 번에 만들어져서 CDN을 통해 제공될 수 있기 때문입니다. 이를 통해 서버가 모든 요청에 대해 페이지를 렌더링하는 것 보다 훨씬 더 빠르게 만들 수 있습니다.</p>
<p>Static Generation은 다음과 같이 여러 방식의 페이지에서 사용할 수 있습니다</p>
<ul>
<li>마케팅 </li>
<li>블로그 포스트</li>
<li>E-커머스 제품리스트</li>
<li>Help and documentation</li>
</ul>
<p>&quot;유저의 요청보다 먼저 이 페이지를 렌더링 해도 될까?&quot; 에 대한 답이 Yes 라면, Static Generation을 사용하시면 됩니다.</p>
<p>반대로, 유저의 요청보다 먼저 페이지를 렌더링 할 수 없는 상황이라면, Static Generation은 좋은 방식이 아닙니다. 이 경우 페이지에 업데이트된 데이터가 자주 표시되고, 매 요청마다 페이지의 컨텐츠가 달라질 수 있습니다.</p>
<h3 id="✐--data-유무에-따른-static-generation">✐  Data 유무에 따른 Static Generation</h3>
<p>Data 유무에 따라 Static Generation 을 수행할 수 있습니다</p>
<p>현재까지 저희가 만들었던 페이지들은 외부 데이터 fetching이 필요하지 않았습니다. 이러한 페이지들은 앱이 프로덕션 용으로 빌드될 때 정적으로 생성됩니다. 
<img src="https://images.velog.io/images/young_mason/post/d8fdc08e-34b8-44c7-89ee-e8847b6134b8/static-generation-without-data.png" alt=""></p>
<p>하지만 어떤 페이지에서는, 특정한 외부 데이터를 처음에 fetch 하지 않으면 HTML을 렌더할 수 없는 상황이 존재할 수 있습니다. 즉 빌드 시 파일 시스템에 접근하거나, 외부 API를 fetch 하거나 혹은 데이터베이스에 query해야 할 수 있습니다. </p>
<p>Next.js는 이러한 케이스처럼 <strong>데이터가 필요한 Static Generation</strong> 또한 지원합니다.</p>
<p><img src="https://images.velog.io/images/young_mason/post/472fb221-6b03-4244-b7bd-0fe3f12d59f2/static-generation-with-data.png" alt=""></p>
<h3 id="✐-데이터가-필요한-static-generation과-getstaticprops">✐ 데이터가 필요한 Static Generation과 &#39;getStaticProps&#39;</h3>
<p>데이터가 필요한 정적 렌더링은 어떤 방식으로 작동할까요?</p>
<p>Next.js는 특정 페이지 컴포넌트를 export 할 때 <code>getStaticProps</code> 라는 <strong>비동기</strong> 함수를 함께 export 할 수 있습니다. 이렇게 되면,</p>
<ul>
<li><code>getStaticProps</code> 가 프로덕션 빌드 시 실행됩니다</li>
<li>함수 내에서 외부 데이터를 호출한 다음, 이를 해당 페이지에 props로 전달 할 수 있습니다</li>
</ul>
<pre><code class="language-jsx">export default function Home(props) { ... }

export async function getStaticProps() {
  // 파일시스템, API, DB 로부터 데이터 가져오기
  const data = ...

  // props 키의 값이 &#39;Home&#39;컴포넌트로 전달됩니다
  return {
    props: ...
  }
}
</code></pre>
<p><code>getStaticProps</code>를 사용하면 Next.js에 이렇게 명령할 수 있습니다. </p>
<p><strong>&quot;이 페이지는 데이터에 의존하고 있으니까 빌드 시 이 페이지를 pre-rendering 할 때, 데이터에 관한 부분을 먼저 해결하도록 해!&quot;</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Next.js 공식 튜토리얼 뿌시기]  1. Page]]></title>
            <link>https://velog.io/@young_mason/Next.js-%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C-%EB%BF%8C%EC%8B%9C%EA%B8%B0-1-Page</link>
            <guid>https://velog.io/@young_mason/Next.js-%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C-%EB%BF%8C%EC%8B%9C%EA%B8%B0-1-Page</guid>
            <pubDate>Sat, 30 Jan 2021 04:27:47 GMT</pubDate>
            <description><![CDATA[<p>프로젝트에 적용하기 위해 학습목적으로 직접 공식문서의 튜토리얼 부분을 번역하였습니다. 혹시 부족한 부분이 있다면 코멘트 남겨주시면 감사드리겠습니다 :) </p>
<p><a href="https://nextjs.org/learn/basics/navigate-between-pages/pages-in-nextjs">https://nextjs.org/learn/basics/navigate-between-pages/pages-in-nextjs</a></p>
<h3 id="✐-페이지에-대해">✐ 페이지에 대해</h3>
<p>Next.js에서는 <code>pages</code> 디렉토리 내 리액트 컴포넌트에 따라 페이지가 구성되며, 각 페이지의 파일 이름에 따라 라우팅됩니다.</p>
<ul>
<li><code>pages/index.js</code> 는 <code>/</code> 엔드포인트로 연결됩니다</li>
<li><code>pages/posts/first-posts.js</code> 는 <code>/posts/first-post</code> 엔드포인트로 연결됩니다.</li>
</ul>
<p>저흰 <code>pages/index.js</code> 파일을 이미 갖고 있으므로, <code>pages/posts/first-post.js</code> 파일을 생성하여 어떻게 동작하는지 살펴보겠습니다.</p>
<h3 id="✐-새-페이지-만들기">✐ 새 페이지 만들기</h3>
<p><code>pages</code> 에 <code>posts</code> 디렉토리를 생성합니다
<code>posts</code> 디렉토리에 <code>first-post.js</code> 파일을 생성하고, 아래와 같은 코드를 작성해보겠습니다</p>
<pre><code class="language-js">export default function FirstPost() {
  return &lt;h1&gt;First Post&lt;/h1&gt;
}</code></pre>
<p>컴포넌트 이름은 임의로 정해주셔도 되시만, 반드시 <strong>default</strong> 로 export 해주셔야 합니다</p>
<p>이제, 개발서버가 동작하는지 확인하는지 확인하고, 아래 url로 접속해보면 
<a href="http://localhost:3000/posts/first-post">http://localhost:3000/posts/first-post</a></p>
<p>다음과 같은 페이지를 확인하실 수 있습니다 
<img src="https://images.velog.io/images/young_mason/post/543b6d6e-46cc-46db-bf61-83192587869e/image.png" alt=""></p>
<p>정리하자면, Next.js에서는 <code>pages</code> 디렉토리안에 자바스크립트 파일을 생성하고, URL path가 될 부분을 파일명으로 설정하여 각각 다른 페이지를 생성할 수 있습니다.</p>
<p>어떻게 보면, HTML이나 PHP 파일을 사용하여 웹사이트를 구축하는 것과 비슷합니다. 대신 HTML가 아닌, JSX를 작성하고 React 컴포넌트를 사용합니다.</p>
<p>이제, 새로 만든 페이지에 Link 를 추가하여 홈페이지에서 이동이 가능하게끔 만들어 보겠습니다</p>
<h3 id="✐-link-컴포넌트">✐ Link 컴포넌트</h3>
<p>보통 웹사이트에서 페이지간 링크 위해서는 <code>&lt;a&gt;</code> HTML 태그를 이용합니다.</p>
<p>Next.js 에서는 <code>next/link</code> 로부터 <code>Link</code> 컴포넌트를 가져와서 <code>&lt;a&gt;</code> 태그를 감쌉니다. <code>&lt;Link&gt;</code> 컴포넌트는 애플리케이션내 다른페이지로의 <strong>Client-side rendering</strong>을 지원해줍니다.</p>
<h3 id="✐-link-사용하기">✐ Link 사용하기</h3>
<p>먼저, <code>pages/index.js</code> 파일을 열고, <code>Link</code> 컴포넌트를 <code>next/link</code> 에서 가져오는 코드를 맨 윗줄에 작성해보겠습니다</p>
<pre><code class="language-jsx">import Link from &#39;next/link&#39;</code></pre>
<p>그다음 아래와 같은 <code>h1</code> 태그를 찾은 다음</p>
<pre><code class="language-jsx">&lt;h1 className=&quot;title&quot;&gt;
  Learn &lt;a href=&quot;https://nextjs.org&quot;&gt;Next.js!&lt;/a&gt;
&lt;/h1&gt;</code></pre>
<p>이렇게 바꿔보겠습니다</p>
<pre><code class="language-jsx">&lt;h1 className=&quot;title&quot;&gt;
   Read{&#39; &#39;}
  &lt;Link href=&quot;/posts/first-post&quot;&gt;
    &lt;a&gt;this page!&lt;/a&gt;
  &lt;/Link&gt;
&lt;/h1&gt;</code></pre>
<p>보시는 것 처럼, <code>Link</code> 컴포넌트는 <code>&lt;a&gt;</code> 태그와 비슷합니다. <code>&lt;a href=&quot;...&quot;</code> 대신에, <code>Link href=&quot;...&quot;</code>를 사용하고 그 안에 <code>&lt;a&gt;</code>태그를 넣어주시면 됩니다.</p>
<p>그럼, 잘 작동하는지 확인해보겠습니다. 
<img src="https://images.velog.io/images/young_mason/post/509e8660-00aa-42e1-a98f-79ed05231530/links.gif" alt=""></p>
<p>이제 각 페이지에 link를 삽입할 수 있고, 자유롭게 앞 뒤로 이동할 수도있습니다</p>
<blockquote>
<ul>
<li>Next.js app이 아닌 외부 페이지로 링크하려면 <code>&lt;Link&gt;</code> 제외하고 <code>&lt;a&gt;</code> 태그만 이용</li>
</ul>
</blockquote>
<ul>
<li><code>className</code> 과 같은 attributes를 추가하려면 <code>&lt;Link&gt;</code> 가 아닌 <code>&lt;a&gt;</code> 태그에 추가해야함.  <a href="https://github.com/vercel/next-learn-starter/blob/master/snippets/link-classname-example.js">예시</a></li>
</ul>
<h3 id="✐-client-side-navigation">✐ Client-Side Navigation</h3>
<p><code>Link</code> 컴포넌트는 Next.js 앱 내의 페이지 간 <strong>Client-side navigation</strong> 을 지원합니다</p>
<p>이는 자바스크립트를 이용하여 페이지를 전환시켜서, 브라우저의 기본 렌더링보다 더 빠른 성능을 보여줍니다.</p>
<p>이를 확인하기 위핸 간단한 방법을 준비했습니다</p>
<ul>
<li>브라우저 개발자 도구를 이용하여 <code>&lt;html&gt;</code>태그의 <code>background</code> CSS 속성을 <code>yellow</code> 로 변경합니다</li>
<li>링크를 클릭해서 페이지를 전환해봅니다</li>
<li>페이지가 바뀌어도 배경 색상이 노란색인걸 확인할 수 있습니다.</li>
</ul>
<p>이것은 브라우저가 전체 페이지를 로드하지 않고, Client-side navigation이 동작하고 있음을 보여줍니다.</p>
<p><img src="https://images.velog.io/images/young_mason/post/b6626cf9-931d-4b53-ab41-dd8f936ebc27/client-side.gif" alt=""></p>
<p>만약 <code>&lt;Link&gt;</code> 대신 <code>&lt;a&gt;</code>태그를 사용하였다면, 브라우저가 완전히 refresh되므로 링크를 클릭했을 때 배경 색상이 초기화될 것입니다.</p>
<h3 id="✐-code-splitting--prefetching">✐ Code splitting &amp; prefetching</h3>
<p>Next.js는 <strong>code splitting</strong> 을 자동적으로 수행하여, 각각의 페이지는 그 페이지가 필요로 하는 것만을 로드합니다. 즉, 홈페이지가 렌더될때, 다른 페이지의 코드는 처음에 가져오지 않습니다.</p>
<p>따라서 만약 수백개의 페이지가 있더라도, 홈페이지는 빠르게 로딩될 것입니다.</p>
<p>또한, 요청한 페이지의 코드만 로딩된다는 것은 페이지가 분리된다는 것을 의미합니다. 만약 특정 페이지에서 에러가 나타나더라도, 애플리케이션의 다른 부분들은 정상적으로 작동합니다.</p>
<p>추가적으로, 프로덕션 빌드 시 <code>Link</code> 컴포넌트가 브라우저 화면에 나타날 때마다 Next.js는 백그라운드에서 링크된 페이지의 코드를 자동으로 <strong>prefetch</strong> 해줍니다. 링크를 클릭하면 대상 페이지의 코드가 이미  백그라운드에서 로드되어있으며, 페이지 전환이 거의 즉시 이루어집니다!</p>
<h3 id="✐-정리">✐ 정리</h3>
<p>Next.js는 아래의 기능을 이용해서 애플리케이션이 최상의 퍼포먼스를 보여주도록 자동으로 최적화해줍니다</p>
<blockquote>
<ul>
<li>client-side navigation : 자바스크립트를 이용한 페이지 전환</li>
</ul>
</blockquote>
<ul>
<li>code splitting : 필요한 코드만 로드</li>
<li>prefetching : Link 대상 페이지의 코드를 미리 로드하여, 페이지 전환을 즉시 이뤄지게 함</li>
</ul>
<p>Next.js를 이용하여 <code>pages</code> 디렉토리 내의 파일들을 이용하여 라우팅을하고, 다른 라이브러리의 도움 없이 내장 되어있는 <code>Link</code> 컴포넌트를 사용할 수 있습니다.</p>
<p><a href="https://nextjs.org/learn/basics/navigate-between-pages/client-side">Link 컴포넌트에 더 알아보기</a>
<a href="https://nextjs.org/docs/routing/introduction">전반적인 라우팅에 관하여 더 알아보기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mentor-To-Mentee] 멘토와 멘티를 연결해주는 질의응답 플랫폼 | React&Redux 2주 프로젝트 돌아보기]]></title>
            <link>https://velog.io/@young_mason/2%EC%A3%BC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Mentor-To-Mentee-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@young_mason/2%EC%A3%BC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Mentor-To-Mentee-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 10 Jan 2021 12:20:30 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>코드스테이츠에서 모든 스프린트가 끝난 후 2주간 진행하였던 팀 프로젝트의 회고입니다 </p>
<p>저는 팀 VVS 에서 팀장 역할과 프론트엔드 개발, 그리고 서비스 배포를 담당하였습니다.</p>
<p>프로젝트명은 Mentor-to-Mentee로, 진로 상담과 관련하여 멘토와 멘티를 이어주는 서비스를 개발하였습니다. 멘티가 원하는 멘토를 선택하여, 질문을 보내고, 멘토는 받은 질문에 대해 답변을 보냅니다.</p>
<p>개발에 사용된 기술은 아래와 같습니다</p>
<p>프론트엔드 : React-hook, Redux, Styled component</p>
<p>백엔드 : Mysql, Express.js jwt, Sequelize, Multer-s3</p>
<p>배포 : EC2, ELB, S3, Route53, ACM</p>
<p>👇더 자세히 알고싶으시다면?👇
<a href="http://vvs-mentortomentee.com/">배포 링크</a>, <a href="https://github.com/codestates/Mentor-To-Mentee-client">Github 레포</a></p>
<p><img src="https://user-images.githubusercontent.com/44192757/107332238-43afe780-6af7-11eb-82ca-f566b751c789.gif" alt=""></p>
<p><img src="https://user-images.githubusercontent.com/44192757/107331505-5a097380-6af6-11eb-8471-a1004982d955.gif" alt=""></p>
<h2 id="첫-시작-팀장과-팀이름-정하기">첫 시작, 팀장과 팀이름 정하기</h2>
<p>팀이 정해지고, 구글 밋에 모여 팀장과 팀이름 얘기를 나누던중 팀원분이 던진 한마디.. 
&quot;그냥 사다리타시죠 ㅋㅋ&quot; 
이게 맞는건가 싶었는데 결국 내가 되버렸다ㅠ 팀원들 모두 더할 나위없이 좋았던 분들이라 의견 잘 조율하고 코딩 외적으로 생각해야 할 것들 (위키 만들기, 태스크카드 작성 등)을 발빠르게 챙겨서 팀원들이 불편하지 않도록 하자는 생각으로 현실을 받아들였다</p>
<h2 id="프로젝트-주제-선정">프로젝트 주제 선정</h2>
<p>팀원 중 한명이 멘토와 멘티가 질문 답변을 손쉽게 주고받을 수 있는 서비스를 만들자는 의견을 냈다.</p>
<p>검색해보니 잇다, 코멘토 같은 기존 서비스가 있어서 걱정했지만 클론할 수 있는 명확한 서비스가 있고 2주면 충분히 주요기능을 구현하면서 그동안 배웠던 기술 스택을 더욱더 갈고닦을 수 있을거라 판단되어 오히려 잘됐다는 생각이 들었다.</p>
<p>팀원 모두가 충분히 우리에게 좋은 주제라는 점에 동의했고, 잇다를 참고하여 2주간 나름대로 모든 기본 CRUD가 녹아있는 서비스를 완성해보기로 결정하였다.</p>
<h2 id="기획">기획</h2>
<p>지금 생각해보면, 가장 중요한 기간이었다. 정해진 SR 일정은 이틀이었지만 부족하여 3일 풀타임을 기획에 쏟았다. 기획은 모두가 같은 지점을 바라보게 만드는 과정이기 때문에, 나중에 서로 다른 생각을 가지지 않게 하기 위해서는 조금 괴로워도 빡빡하게 할 수 밖에 없었다.</p>
<p>기획단계를 거치면서 몇가지 느낀 점들을 끄적여볼까 한다.</p>
<h3 id="1-기획은-겸손하게">1. 기획은 겸손하게</h3>
<p>해시태그, 필터링, 검색기능처럼 그럴 듯해 보이는 아이디어는 모두가 &#39;오 대박인데 고고하시죠&#39; 라는 입장이었다. 직접 코드를 짜기 전까지는..😭</p>
<p>2주동안 가장 기본적인 질문답변 CRUD를 구현하고 위의 기능까지 도전하는데 충분하리라 생각했지만, 결국 시간이 부족하여 기획했던 기능들을 정리해야 했다.  </p>
<p>시간적인 제한이 있는 프로젝트에서 정확한 기획을 하기 위해서는 축적되어있는 경험이 많아야 한다는 걸 이번 프로젝트를 통해 크게 느꼈다. 나는 아직 어린이고 갈 길이 멀기에.. 개발 기획은 가능한 보수적이고 겸손하게 해야겠다. </p>
<h3 id="2-디테일이-중요하다">2. 디테일이 중요하다</h3>
<p>다양한 기능을 개발하는 것보다 하나의 기능에 많은 디테일을 넣는 연습이 필요할 것 같다. </p>
<p>로그인 페이지에 계정정보 인풋과 로그인 버튼을 만드는 일은 비교적 쉬운 일이었다. 하지만 placeholder, 유효성 검사, 로그인 버튼 마우스오버 효과 등 우리가 흔히 웹페이지에서 보는 로그인 페이지와 같은 상태로 만들기 위해서 꽤나 많은 것들이 필요했다.</p>
<p>기획단계에서 이런 디테일을 구현하는 시간까지 예측하려면, 이러한 디테일을 100% 구현하는 개발연습을 꾸준히 해야겠다.</p>
<h3 id="3-시각화된-자료를-바탕으로-얘기를-나누는-것이-중요하다">3. 시각화된 자료를 바탕으로 얘기를 나누는 것이 중요하다.</h3>
<p>백문이 불여일견이라고.. 눈에 보이지 않는 것을 가지고 얘기하다보면 어느새 서로 다른 얘길 하게 된다. (뭔가 의견을 나누는데 같은 말이 반복되면서 계속 빙빙 도는 느낌)</p>
<p>그런 일을 최대한 줄이기 위해 Figma로 대략적인 페이지 디자인과 와이어프레임을 만들었고, DBdiagram으로 스키마 디자인을 하였으며, Notion으로 아이디어와 API문서를 정리하였다.</p>
<p>이러한 툴들을 사용하여 작업들을 미리 해놓는 것이 익숙하지 않았던 탓에 어느 정도 완성될때까진 조금 괴로운 시간이었다. 눈에 보이지 않는 기획을 해야한다는 점 때문에 기획 어느정도로 마무리하고 일단 빨리 코딩을 시작하고 싶은 유혹도 계속 있었다.</p>
<p>우여곡절 끝에 완벽한 상태는 아니지만 모든 개발 flow가 시각화된 상태로 완성되었을 때, 마음이 편해지면서 정확한 방향성이 잡힌듯한 느낌이 들었다. </p>
<ul>
<li>Work Flow (Client)</li>
</ul>
<p><img src="https://images.velog.io/images/young_mason/post/02a74bf9-9162-482d-9657-81508cdb9239/image.png" alt=""></p>
<ul>
<li>Work Flow (Server)</li>
</ul>
<p><img src="https://images.velog.io/images/young_mason/post/a47fe834-f5ca-40c1-9add-be6959057349/image.png" alt=""></p>
<ul>
<li>Prototype</li>
</ul>
<p><img src="https://images.velog.io/images/young_mason/post/983c232d-8c62-440e-8d5b-75899bd60b22/image.png" alt=""></p>
<ul>
<li>DB Scheme
<img src="https://images.velog.io/images/young_mason/post/d66eb664-6a67-477a-b9ed-378d9c268b14/image.png" alt=""></li>
</ul>
<p>대략적인 자료들이 완성된 이후로 팀원들간 의견을 더 잘 이해할 수 있게 되었다.</p>
<p>이러한 툴들을 이용해서 빠르고 정확하게 시각화된 자료를 만드는 능력과, 그 자료를 토대로 의견을 나누는 것이 중요하다는 것을 깨달았다.</p>
<h2 id="깃-워크-플로우">깃 워크 플로우</h2>
<p>깃을 통한 협업. 이번 프로젝트가 진행되는데 필수적인 역할을 하면서, 동시에 가장 속을 썩였던 녀석이기도 하다. </p>
<p>이전 스프린트까지는 clone, commit, push, pull request 와 페어의 레포에서 pull 받는 정도가 사용하는 기능의 전부였다. 그런데 프로젝트 시작 전 팀프로젝트의 깃 협업 방법에 대한 세션에서 dev branch, feature branch, upstream, origin 같은 것들이 등장하니깐 멘탈이 스르륵 나가기 시작했다</p>
<ul>
<li>git flow (출처: codestates)
<img src="https://images.velog.io/images/young_mason/post/1fc5c190-4ab1-4ea7-ba0f-3fc758e1e6da/image.png" alt=""></li>
</ul>
<p>팀원들에게 내가 이해한 내용을 공유하면서도 이게 맞는건지 확신이 들지 않았고, 이거는 직접 해보면서 부딪힐 수 밖에없었다..
처음 코드리뷰를 진행하고 팀장이었던 나부터 첫 커밋을 한 뒤 pr을 보내려고 하는데, 내가 브랜치를 안따고 작업해서 첫날부터 꼬여버렸던.. 아픈 기억도 있다. (이때 팀원분들이 괜찮다고 덕분에 다음에 실수 안할 거 같다고 얘기해주신거 너무 감동이었음..)</p>
<p>팀원 작업물과 conflict 생긴 것들 해결해가면서 매일매일 반복하다보니 점점 어떤 flow로 다른 팀원이 작업한 내용과 merge하는 것이 효율적인지에 대해 이해하게 되었고, 새롭게 알게된 방법들을 팀원들과 그때그때 공유했다.</p>
<p><img src="https://images.velog.io/images/young_mason/post/674a5c64-984c-48da-8bf1-1ada1b9fb0de/image.png" alt=""></p>
<p>2주 프로젝트가 끝난 후 마무리 줌 세션에서, 엔지니어분이 가출한 브랜치 없이 git flow를 잘 이행한 예로 우리 프로젝트의 Git Network graph를 보여주셨다. 이때 억소리 내면서 팀원분들이랑 카톡했는데 ㅋㅋ 첫 커밋부터 꼬인거 푼다고 고생했던게 생각나면서.. 이때가 제일 짜릿했던 것 같다</p>
<h2 id="개선할-점">개선할 점</h2>
<h3 id="1--프론트와-백엔드-함께-기능을-완성해가기">1.  프론트와 백엔드 함께 기능을 완성해가기</h3>
<p>기획이 완료되고 개발을 착수한뒤 프론트는 빠르게 전반적인 스켈레톤 UI 를 다 만들어놓고, 백엔드는 db와 개발환경 셋업을 모두 끝낸 뒤 기능들을 구현하기 시작했었다. </p>
<p>기능개발이 들어간 이후에는 프론트랑 백엔드 개발 속도에 차이가 생기게 됐는데, 이 과정에서 프론트와 백엔드 사이의 소통이 충분하지 않아서 프론트는 나름대로 https 요청들을 구현해 놓고 서버 코드와 테스트하지 않은 상태로 다른 기능 구현을 시작했던것같다. 나중에 구현해놓았다고 생각하고 넘어갔던 기능들에서 하나 둘씩 문제가 발생하면서 막바지에 큰 스트레스로 다가왔었다.</p>
<p>프론트엔드와 백엔드 사이에 개발 속도를 잘 맞추고, 기능별로 하나하나씩 테스트하면서 완성해가는 방식으로 했으면 더 좋았을 것 같다는 생각이 든다.</p>
<h3 id="2-유저-입장에서-로그인-시점을-고려하기">2. 유저 입장에서 로그인 시점을 고려하기</h3>
<p>유저의 입장에서 로그인을 하지 않으면 서비스에 접근하기 어렵도록 만들었던 점이 아쉬웠다. 
처음에 기획을 하면서 로그인은 당연히 필수적인 기능으로 생각했기에 메인에다 배치를 해놨었는데, 다른 팀의 발표를 보면서 유저가 로그인을 하지 않아도 서비스를 이용 가능하게 만드는 것이 더 좋은 유저경험을 만든다는 점을 느끼게 되었다. 
앞으로 서비스를 만들 때 유저의 로그인 시점을 고려하고, 유저가 로그인 없이 최대한 많은 기능을 체험해볼수 있도록 해야겠다.</p>
<h3 id="3-모바일-친화적인-서비스-만들기">3. 모바일 친화적인 서비스 만들기</h3>
<p>기획단계에서 이 서비스가 모바일 화면에서 어떻게 보여질지를 고려하지 못했다. 요즘은 모바일을 통해서 서비스를 먼저 접하는 경우가 더 많기 때문에, 앞으로는 모바일 화면을 우선적으로 고려하여 개발하는 것이 좋을 것 같다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TSJ] 쿠키 sameSite 옵션]]></title>
            <link>https://velog.io/@young_mason/TSJ-%EC%BF%A0%ED%82%A4-sameSite-%EC%98%B5%EC%85%98</link>
            <guid>https://velog.io/@young_mason/TSJ-%EC%BF%A0%ED%82%A4-sameSite-%EC%98%B5%EC%85%98</guid>
            <pubDate>Thu, 17 Dec 2020 04:34:46 GMT</pubDate>
            <description><![CDATA[<p>프로젝트전 마지막 HA 에서, 가장 많은 삽질을 하게했던 주인공은.. 바로 쿠키의 sameSite 옵션이었다.</p>
<p>내가 구현하고자 했던 것은 http요청 환경에서 express-session 미들웨어를 이용하여 로그인 인증을 구현하는 것이었다. 과정은 아래와 같다</p>
<ol>
<li><p>먼저, 클라에서 서버로 로그인정보를 Post메소드를 통해 보내고, 로그인정보가 서버 DB에 있을 경우 세션에 db 회원번호를 저장한 뒤 응답으로 암호화된 쿠키 전달.</p>
</li>
<li><p>클라에서 다시 GET메소드로 서버에 회원정보 요청. 서버에서는 암호화된 쿠키를 해석하여 유효한 세션인지 파악하고, 세션객체에 있는 db 회원번호와 일치하는 회원정보를 db에서 가져와서 응답으로 해당정보 보내줌.</p>
</li>
</ol>
<h3 id="어떤-문제가-발생했나">어떤 문제가 발생했나..?</h3>
<p>1번은 성공적으로 보였지만 2번에서 서버로 get 요청을 보낼때 쿠키가 전달이 안됨... 그래서 서버에서 get요청에 대해 <code>req.session</code>으로 콘솔에 찍어봤을때 회원번호가 들어있지 않았음</p>
<p>삽질 당시 코드는 아래와 같았다.</p>
<pre><code class="language-js">// 클라이언트 
axios.post(&#39;http://localhost:4000/signin&#39;, 
           {email, password}, 
           {withCredentials: true}
          )
//서버
// - session 설정
app.use(session({
  secret: //시크릿 키,
  resave: false,
  saveUninitialized: true,
  cookie: {
    httpOnly: true,
    maxAge: 1000 * 60 * 5,
    sameSite: &#39;none&#39;,
  }
}))

// - cors 설정
app.use(cors({
  origin: &#39;http://localhost:3000&#39;,
  credentials: true
}))</code></pre>
<h3 id="삽질-당시-나의-생각">삽질 당시 나의 생각</h3>
<p>sameSite 옵션이 none 일 경우 모든 요청 메소드에 대해 쿠키를 전달하는 것,  여기서 <code>secure: true</code> 옵션을 추가할경우 https 요청시에만 쿠키전달 가능.</p>
<p>하지만 현재는 http 요청을 주고받는 환경이다. 따라서 secure 옵션을 붙이지 않으면 정상적으로 쿠키 전송이 가능할거야. 저번에 삽질하다 알게된 credential 옵션도 잘 붙였고.. 근데 왜안됨..?</p>
<h3 id="해결">해결</h3>
<p>http에서 https로 요청방식을 변경 한 뒤 <code>sameSite:&#39;none&#39;</code> 은 유지하고, <code>secure:true</code> 옵션을 추가하였더니, 정상적으로 작동 하는 것을 확인했다. 정상적으로 작동하는건 확인했지만 http와 어떤 차이가 있는건지에 대해서 이해하지 못하고 일단 모든 HA 요구조건을 완성한 뒤 제출하였다</p>
<h3 id="해결-후-알게-된-것들">해결 후 알게 된 것들</h3>
<p>구글링 끝에 올해 초 크롬 브라우저의 업데이트에 관한 내용을 확인 할 수 있었다</p>
<p>정리하자면, 크롬 80버전부터 CSRF공격으로 부터의 보안강화를 위해 sameSite 기본 속성값이 &#39;none&#39;에서 &#39;lax&#39;로 변경된다는 것이었다
즉, GET 요청에 대해서만 쿠키 전송이 가능하다</p>
<p>samesite가 none이지만 secure 속성이 없을경우 브라우저에서는 아래 그림과 같은 경고 아이콘이 뜨고, 마우스 오버시 다음 문구가 나온다.</p>
<p>This set-cookie had the &quot;SameStie=None&quot; attribute but did not have the &quot;Secure&quot; attribute. which is required in order to use &quot;SameSite=None&quot;</p>
<p><img src="https://images.velog.io/images/young_mason/post/4ddef4df-b9df-4823-98fb-12e9f0a49683/image.png" alt=""></p>
<p>결론:
다른 도메인으로 쿠키를 전달 하고 싶은 경우
SameSite 옵션은&#39;None&#39; Secure 옵션은 true 여야만한다. -&gt; 사이트가 https 여야만 한다.</p>
<p>참고 자료:
<a href="https://ifuwanna.tistory.com/223">https://ifuwanna.tistory.com/223</a>
<a href="https://www.hahwul.com/2020/01/18/samesite-lax/">https://www.hahwul.com/2020/01/18/samesite-lax/</a></p>
<p>해결안된 궁금증 : 
http, localhost 환경에서 secure: strict 로 하면 도메인이 달라도 쿠키전송이되던데, 이건 왜되는거지?  헬데에 물어보자</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2020. 12. 09 TIL] https, cookie]]></title>
            <link>https://velog.io/@young_mason/2020.-12.-09-TIL-https-cookie</link>
            <guid>https://velog.io/@young_mason/2020.-12.-09-TIL-https-cookie</guid>
            <pubDate>Wed, 09 Dec 2020 15:12:37 GMT</pubDate>
            <description><![CDATA[<h3 id="1-https-란">1. HTTPS 란?</h3>
<p>http에서 보안장치가 추가되어 있는 통신 방식이다.
https에서 마지막 s는 Over Secure Socket Layer의 약자이다</p>
<h3 id="2-ssl">2. SSL</h3>
<p>SSL 인증서는 클라이언트와 서버간의 통신을 제3자가 보증해주는 전자화된 문서다. 클라이언트가 서버에 접속한 직후에 서버는 클라이언트에게 이 인증서 정보를 전달한다.</p>
<p>[생활코딩]
<a href="https://opentutorials.org/course/228/4894">https://opentutorials.org/course/228/4894</a></p>
<h3 id="3-cookie">3. Cookie</h3>
<ul>
<li>어떤 웹사이트에 들어갔을 때, 서버가 일방적으로 클라이언트에 전달하는 작은 데이터</li>
<li>서버가 웹 브라우저에 정보를 저장하고 불러올 수 있느 ㄴ수단</li>
<li>해당 도메인에 대해 쿠키가 존재하면, 웹 브라우저는 도메인에게 http요청 시 쿠키를 함께 전달</li>
</ul>
<p><img src="https://images.velog.io/images/young_mason/post/fda3aa02-bfe9-4823-8dc6-0996e77fafa0/image.png" alt=""></p>
<h3 id="4-오늘의-삽질">4. 오늘의 삽질</h3>
<p>https 요청과 cookie 를 이용한 로그인 서비스를 구현하는 스프린트를 진행하였다.</p>
<p>진행순서는 크게 아래와 같았다</p>
<ol>
<li><p>클라이언트 : POST /login 요청으로 id, password 전달</p>
</li>
<li><p>서버
2-1) req.body 에 있는 id, password가 DB에 없으면 404 응답코드와 함께 에러메세지 전달
2-2) DB에 일치하면 해당 record의 id값을 200 응답코드와 함께 Cookie로 전달</p>
<pre><code class="language-javascript">res.cookie(&#39;id&#39;, `${userInfo.id}`, { secure: true, httpOnly: true, sameSite: &#39;None&#39; })</code></pre>
</li>
<li><p>클라이언트 : 정상적인 응답을 받으면 Cookie 저장, 로그인 상태를 변경해준 뒤 GET /userinfo 요청과 함께 Cookie 전달</p>
</li>
<li><p>서버 : 
2-1) Cookie값이 없으면, 400 상태코드와 함께 에러메세지 전달
2-2) Cookie값이 있으면, DB에서 해당 id의 userData를 응답코드와 함께 전달</p>
</li>
</ol>
<p>진행 도중 2-2 를 통해 오는 Response Header 에는 Cookie가 정상적으로 들어오는 것을 확인 하였는데, 3 에서 Get 요청을 보낼 때 Request Header에 Cookie가 찍히지 않는 문제가 발생하였다.</p>
<p>GET 요청 헤더에 쿠키를 하드코딩해서도 넣어보고, node-fetch 요청을 axios 로도 변경해보고, 서버로 돌아가 쿠키 옵션도 만져보고 별의 별짓을 다해봤는데 바뀌는게 없었다 ㅜ
결국 미친듯한 구글링 끝에 깨달음을 얻었는데...</p>
<blockquote>
<p><strong>서버와 클라이언트가 쿠키를 주고받기 위해서는 클라이언트의 요청과 서버의 cors 설정에 credentials 관련 옵션을 true로 설정해줘야 한다</strong></p>
</blockquote>
<p>아래의 코드처럼 서버에 Cors 설정을 추가하고,  axios 요청에 인자로 {withCredentials : true} 를 넣어서 해결할 수 있었다.</p>
<pre><code class="language-javascript">//server

app.use(cors({ 
  origin: true,
  methods: &quot;GET, POST, OPTIONS&quot;,
  credentials: true
}))

//Client 
await axios
    .get(&quot;https://localhost:4000/users/userinfo&quot;, {
        withCredentials: true
      })
      .then((data) =&gt; this.props.setUserInfo(data.data.data))
      .catch((err) =&gt; { if (err) { alert(err) } })
</code></pre>
<h3 id="5-공부해야-할-것들">5. 공부해야 할 것들</h3>
<ol>
<li><p>위 코드에서 server쪽 Cors 설정 중 origin 에 대한 이해가 필요할 것 같다. 이 상태에서 &#39;*&#39; 를 넣거나 &#39;<a href="https://localhost:3000/&#39;">https://localhost:3000/&#39;</a> 을 넣었을 때 적용이 되지 않는 이유가 궁금하다</p>
</li>
<li><p>기능 구현은 하였으나 Credential 옵션이 하는 역할에 대한 이해 하지 못하였다</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2020. 12. 07 TIL] ORM, Sequelize]]></title>
            <link>https://velog.io/@young_mason/2020.-12.-07-TIL-ORM-Sequelize</link>
            <guid>https://velog.io/@young_mason/2020.-12.-07-TIL-ORM-Sequelize</guid>
            <pubDate>Mon, 07 Dec 2020 15:01:35 GMT</pubDate>
            <description><![CDATA[<h2 id="orm-이란">ORM 이란?</h2>
<p>Object-Relational Mapping</p>
<p><img src="https://images.velog.io/images/young_mason/post/f4d249a8-fd85-4484-a044-5639680ab774/image.png" alt=""></p>
<p>관계형 데이터베이스의 record에 접근할 때, 자바스크립트의 객채 혹은 class를 다루듯이 접근할 수 있도록 도와주는 tool.</p>
<blockquote>
<p>Sequelize 는 Node.js 기반의 ORM 이다.</p>
</blockquote>
<h2 id="장점">장점</h2>
<ul>
<li>Migration 을 이용한 이력관리</li>
<li>배포하는 환경과 개발하는 환경을 분리하여 관리할 수 있다</li>
</ul>
<h2 id="개발환경-세팅하기">개발환경 세팅하기</h2>
<ol>
<li><p>sequelize 설치하기</p>
<pre><code>npm install --save sequelize</code></pre></li>
<li><p>CLI 환경 만들기</p>
</li>
</ol>
<p>아래 공식문서 내 Migrations 카테고리를 확인하면서, 커맨드를 통해 데이터베이스 model과 migration을 정의할 수 있다</p>
<p><a href="https://sequelize.org/master/manual/migrations.html">https://sequelize.org/master/manual/migrations.html</a></p>
<p>2-1 Sequelize - CLI 설치</p>
<pre><code>npm install --save-dev sequelize-cli</code></pre><p>2-2 Project Bootstrapping</p>
<pre><code>npx sequelize-cli init</code></pre><p>2-3 config, models, migrations, seeders 폴더가 생성 된 것 확인. config.json 에서는 어떤 방식으로 데이터베이스와 연결할지 세팅할 수 있다.</p>
<ol start="3">
<li>모델 만들기
model:generate 커맨드를 아래와 같은 양식으로 입력한다
두가지 옵션을 입력해야 한다</li>
</ol>
<ul>
<li>name : 모델의 이름 ( 테이블명 )</li>
<li>attributes : 모델의 속성 리스트 ( 칼럼 )</li>
</ul>
<pre><code>npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string</code></pre><ol start="4">
<li>Migration</li>
</ol>
<p>세팅된 모델과 migration 이 정의된 파일을 기반으로, 데이터베이스의 테이블을 구성한다.</p>
<pre><code>npm sequelize-cli db:migrate</code></pre><p>이전에 수정된 이력들을 담는 폴더가 생성되어, 원하는 수정시점으로 이동 하는 등의 이력관리가 가능하다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2020. 12. 02 TIL] My SQL]]></title>
            <link>https://velog.io/@young_mason/2020.-12.-02-TIL-My-SQL</link>
            <guid>https://velog.io/@young_mason/2020.-12.-02-TIL-My-SQL</guid>
            <pubDate>Wed, 02 Dec 2020 12:02:28 GMT</pubDate>
            <description><![CDATA[<h2 id="sql이란">SQL이란</h2>
<ul>
<li>Structured Query Language → 구조화된 query 언어</li>
</ul>
<h2 id="그럼-query란">그럼 Query란?</h2>
<ul>
<li>직역을 하자면 &#39;질의문&#39;</li>
<li>가장 친숙한 예시로는 검색창에 적는 검색어도 Query의 일종</li>
<li>저장되어있는 정보를 필터하기 위한 질문</li>
</ul>
<h2 id="그래서-다시-sql이란">그래서 다시 SQL이란?</h2>
<ul>
<li>데이터베이스 용 프로그래밍 언어!</li>
<li>데이터베이스에 query를 보내 원하는 데이터만을 뽑아올 수 있다.</li>
</ul>
<h2 id="rdbms">RDBMS</h2>
<ul>
<li>Relational Database Management System</li>
<li>RDMBS 는 SQL 기반</li>
<li>SQL Server, DB2, Oracle, MySQL  - - -</li>
</ul>
<h2 id="table">Table</h2>
<ul>
<li>RDBMS에서 data는 table 에 저장된다.</li>
<li>records( row )와 column으로 구성됨</li>
</ul>
<h2 id="sql-query">SQL Query</h2>
<ul>
<li><strong>SELECT</strong> - extracts data from a database</li>
</ul>
<pre><code class="language-sql">
SELECT * FROM Customers // Customers (table) 에서 모든 데이터 가져오기

SELECT PostalCode, City FROM Customers // Customers 에서 PostalCode, City 데이터(column) 가져오기 

SELECT DISTINCT Country FROM Customers; // distinct 중복되는 row 제거

SELECT COUNT ( DISTINCT Country ) FROM Customers; // 중복제거 후 데이터 개수
</code></pre>
<ul>
<li>Where</li>
</ul>
<pre><code class="language-sql">SELECT * FROM Customers
WHERE CustomerID = 1;

// CustomerID column의 값이 1인 모든 데이터 가져오기

SELECT * FROM Customers
WHERE NOT Country=&#39;Germany&#39; AND NOT Country=&#39;USA&#39;;

// Country 값이 &#39;Germany&#39;, &#39;USA&#39;가 아닌 모든 데이터 가져오기
</code></pre>
<p><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/88513d3e-76c2-4fdc-8bca-cda55b99851e/Untitled.png" alt="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/88513d3e-76c2-4fdc-8bca-cda55b99851e/Untitled.png"></p>
<ul>
<li>Order By</li>
</ul>
<pre><code class="language-sql">SELECT * FROM Customers
ORDER BY Country;

// Country column 에 따라 정렬됨 (오름차순)

SELECT * FROM Customers
ORDER BY Country DESC;

// Country column 에 따라 정렬됨 (내림차순)

SELECT * FROM Customers
ORDER BY Country ASC, CustomerName DESC;

// Counry 오름차순 -&gt; CustomerName 내림차순 (??) -&gt; 헬프데스크 각</code></pre>
<ul>
<li><strong>INSERT INTO</strong> - inserts new data into a database</li>
</ul>
<pre><code class="language-sql">//두가지방법이 있따
// 1. column name과 그에따른 value 특정 (값이 안들어간 column 은 null)
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);

// 2. column 특정하지 않고 모든 column 에 추가, 이 경우 column 순서에 맞게 value 입력해야함
INSERT INTO table_name
VALUES (value1, value2, value3, ...);</code></pre>
<ul>
<li>Null values</li>
</ul>
<pre><code class="language-sql">SELECT column_names
FROM table_name
WHERE column_name IS NULL;

SELECT column_names
FROM table_name
WHERE column_name IS NOT NULL;</code></pre>
<ul>
<li><strong>UPDATE</strong> - updates data in a database</li>
</ul>
<pre><code class="language-sql">
// ID가 1인 데이터 업데이트
UPDATE Customers
SET ContactName = &#39;Alfred Schmidt&#39;, City= &#39;Frankfurt&#39;
WHERE CustomerID = 1;

// 국가가 Mexico 인 모든 데이터 업데이트
UPDATE Customers
SET ContactName=&#39;Juan&#39;
WHERE Country=&#39;Mexico&#39;;

// 주의! where 조건을 적지 않으면 모든 records가 업데이트됨
UPDATE Customers
SET ContactName=&#39;Juan&#39;;</code></pre>
<ul>
<li><strong>DELETE</strong> - deletes data from a database</li>
</ul>
<pre><code class="language-sql">DELETE FROM table_name WHERE condition;

// CustomerName이 Alfreds인 records 삭제
DELETE FROM Customers WHERE CustomerName=&#39;Alfreds Futterkiste&#39;;

// Customers 모든 records 삭제 (테이블은 남겨둠)
DELETE FROM Customers
</code></pre>
<ul>
<li>Select Top (My SQL)</li>
</ul>
<pre><code class="language-sql">SELECT column_name(s)
FROM table_name
WHERE condition
LIMIT number;

//5개까지만 보여줌 ( My SQL ) 위에꺼랑 같은의미
SELECT * FROM Customers LIMIT 5;

// country가 Genrmany 인 값 3개 보여줌
SELECT * FROM Customers
WHERE Country=&#39;Germany&#39;
LIMIT 3;
</code></pre>
<ul>
<li>Functions</li>
</ul>
<pre><code class="language-sql">// Min, Max
SELECT MIN(column_name) //MAX
FROM table_name
WHERE condition;

// Price 최소값을 SmallestPrice라는 column name으로 반환
SELECT MIN(Price) AS SmallestPrice
FROM Products;

//Count, Sum, AVG

SELECT AVG(column_name) // Count , Sum
FROM table_name
WHERE condition;</code></pre>
<ul>
<li>LIKE - column 에서 특정한 Pattern을 검색하기 위해 사용</li>
</ul>
<pre><code class="language-sql">SELECT column1, column2, ...
FROM table_name
WHERE columnN LIKE pattern;

// a로 시작하지 않는 데이터 검색
SELECT * FROM Customers
WHERE CustomerName NOT LIKE &#39;a%&#39;;</code></pre>
<p><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/109b29f4-9e67-4163-8d13-4baa04f2ad0f/Untitled.png" alt="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/109b29f4-9e67-4163-8d13-4baa04f2ad0f/Untitled.png"></p>
<ul>
<li>WildCard Characters</li>
</ul>
<p><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/cf0b5e42-2016-4556-9872-8d5af1aa3cab/Untitled.png" alt="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/cf0b5e42-2016-4556-9872-8d5af1aa3cab/Untitled.png"></p>
<ul>
<li>IN ( 여러개의 or 조건을 축약할수잇음)</li>
</ul>
<pre><code class="language-sql">SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1, value2, ...);

SELECT * FROM Customers
WHERE Country IN (&#39;Germany&#39;, &#39;France&#39;, &#39;UK&#39;);

SELECT * FROM Customers
WHERE Country IN (SELECT Country FROM Suppliers);</code></pre>
<ul>
<li>Between</li>
</ul>
<pre><code class="language-sql">SELECT column_name(s)
FROM table_name
WHERE column_name BETWEEN value1 AND value2;</code></pre>
<p>inner Join </p>
<p>on으로 명시된 특성만 반영되서 출력;</p>
<p>as</p>
<p>alias → 별명</p>
<p>SELECT * FROM users u INNER JOIN pets</p>
<ul>
<li><strong>CREATE DATABASE</strong> - creates a new database</li>
<li><strong>ALTER DATABASE</strong> - modifies a database</li>
<li><strong>CREATE TABLE</strong> - creates a new table</li>
<li><strong>ALTER TABLE</strong> - modifies a table</li>
<li><strong>DROP TABLE</strong> - deletes a table</li>
<li><strong>CREATE INDEX</strong> - creates an index (search key)</li>
<li><strong>DROP INDEX</strong> - deletes an index</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[RESTful API]]></title>
            <link>https://velog.io/@young_mason/RESTful-API</link>
            <guid>https://velog.io/@young_mason/RESTful-API</guid>
            <pubDate>Sun, 29 Nov 2020 08:59:10 GMT</pubDate>
            <description><![CDATA[<h2 id="rest">REST</h2>
<ul>
<li>REpresentational State Transfer</li>
<li>웹 서비스를 만드는데 사용되는 제약(constraint) 모음</li>
<li>Roy T.Fielding 
// web을 망가뜨리지 않고, 어떻게 http를 개선할 수 있을까?</li>
</ul>
<h2 id="rest의-요소">REST의 요소</h2>
<ul>
<li><p>Method</p>
<p>POST: create // Idempotent(x)
GET: Select // Idempotent(o)
PUT: Update // Idempotent(o)
DELETE: Delete // Idempotent(o)</p>
<blockquote>
<p>Idempotent: 여러 번 연산을 수행하여도 결과가 달라지지 않는 성질.
   POST는 상태를 변화시키기 때문에 Idempotent (x)</p>
</blockquote>
</li>
<li><p>Resource</p>
<p>  &#39;<a href="http://myweb/users&#39;">http://myweb/users&#39;</a> 와 같은 URI
  모든 것을 Resource (명사)로 표현하고, 세부 Resource에는 id를 붙임</p>
</li>
</ul>
<ul>
<li><p>Message</p>
<p>  메시지 포맷이 존재
  : JSON, XML 과 같은 형태가 있음 (최근에는 JSON을 씀)</p>
<pre><code>    ```text
HTTP POST, http://myweb/users/
{
    &quot;users&quot; : {
        &quot;name&quot; : &quot;terry&quot;
    }
}
```</code></pre><h2 id="rest-특징">REST 특징</h2>
<ul>
<li><p>Uniform Interface</p>
<p>: HTTP 표준만 맞는다면, 어떤 기술도 가능한 Interface 스타일
예) REST API 정의를 HTTP + JSON로 하였다면 C, JAVA, Python, IOS 플랫폼 등 특정 언어    나 기술 등에 종속 받지 않고, 모든 플랫폼에 사용이 가능한 Loosely Coupling구조</p>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>