<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Winney_Seo</title>
        <link>https://velog.io/</link>
        <description>프론트엔드 엔지니어</description>
        <lastBuildDate>Wed, 01 Sep 2021 15:23:28 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Winney_Seo</title>
            <url>https://images.velog.io/images/winney_77/profile/61849027-06fd-4655-83c9-78c84f1e488f/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Winney_Seo. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/winney_77" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[leetcode] twoSum]]></title>
            <link>https://velog.io/@winney_77/leetcode-twoSum</link>
            <guid>https://velog.io/@winney_77/leetcode-twoSum</guid>
            <pubDate>Wed, 01 Sep 2021 15:23:28 GMT</pubDate>
            <description><![CDATA[<p>문제 :<a href="https://leetcode.com/problems/two-sum/">https://leetcode.com/problems/two-sum/</a></p>
<p>해결방법</p>
<pre><code>const twoSum = (nums, target) =&gt; {
  const arr =[];
  for (let i = 0; i &lt; nums.length; i++) {
    for (let j = i + 1; j &lt; nums.length; j++) {
      if (nums[i] + nums[j] === target) {
        arr.push(i);
        arr.push(j);
      }
    }
  }
  return arr
}</code></pre><p>수정</p>
<pre><code>const twoSum = (nums, target) =&gt; {
  const arr = [];
  nums.forEach((num,i) =&gt; {
    nums.forEach((num, j) =&gt; {
      if (j &gt; i &amp;&amp; nums[i] + nums[j] === target)
        arr.push(i, j);
    })
  })
  return arr;
}</code></pre><p>기존의 for문 대신 forEach를 사용하는 방법으로 수정해보았다. 
어디선가 for문은 촌스럽다!하는 글을 보고 시도해보았지만 runtime은 3배쯤 증가하고 memory도 0.5MB쯤 더 사용하는 것을 보고 그냥 촌스럽게 써야겠다는 생각을 했다. </p>
<p>참고로 if 안에 j &gt; i를 넣은 건 해당 조건을 넣지 않을 경우 중복되는 경우의 수가 나오기 때문이다. </p>
<p>for문을 통해 배열을 2개 놓고 하나씩 짝지어가며 비교하는 거라 O(n^2)만큼의 시간이 걸린다. </p>
<p>다른 풀이를 보니 hash table을 사용한 방법도 있었다. 당연하지만 나는 생각 못 했다ㅋㅋ.... </p>
<p>해당 블로그에서 hash table을 사용한 방법을 more elegant solution이라고 말하는데 나도 곧 그런 elegant solution을 먼저 생각하는 날이 올거라 믿는다. </p>
<p>hash table 사용</p>
<pre><code>const twoSum = (nums, target) =&gt; {
  const hash = {};
  for (let i = 0; i &lt; nums.length; i++) {
    const otherNum = target - nums[i];
    if (hash[otherNum] !== undefined) {
      return [hash[otherNum], i];
    }
    hash[nums[i]] = i;
  }
}</code></pre><p>for문을 한 번 쓰다보니 O(n)만큼의 시간이 걸린다. 
어떤 때에 hash table을 써야하는지 다시 한 번 기억할 기회였다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[computer networking] 2. Application(4)]]></title>
            <link>https://velog.io/@winney_77/computer-networking-2.-Application3</link>
            <guid>https://velog.io/@winney_77/computer-networking-2.-Application3</guid>
            <pubDate>Sun, 15 Aug 2021 13:18:27 GMT</pubDate>
            <description><![CDATA[<h2 id="26-peer-to-peer-applications">2.6 Peer-to-Peer Applications</h2>
<ul>
<li><p>peer란 간헐적으로 서로 연결된 host pair</p>
</li>
<li><p>peer는 서비스 공급자가 소유하지 않고 사용자가 제어하는 데스크탑과 랩탑이다.</p>
</li>
<li><p>두 가지 종류<br>1) a single source to a large number of peers 예) BitTorrent
2) a database distributed over a large community of peers (DHT, Distributed Hash Table)</p>
</li>
</ul>
<h3 id="scalability-of-p2p-architectures--vs-client-server-architechtures">Scalability of P2P Architectures  (vs client-server architechtures)</h3>
<ul>
<li><strong>distribution time</strong> : 파일 복사본을 모든 N개 peer에 가져오는데 걸리는 시간</li>
<li>Dcs : client-server architecture ㅊ
client-server architechture에서 distribution에 도움되는 peer는 없다.</li>
<li>distribution time에는 upload, download 시간, bandwidth, 병목현상으로 인한 시간 등이 포함되어 있다.</li>
<li>서버는 N개 peers에 각 파일 복사본을 전송해야한다. → NF bits를 전송. 
upload rate : <strong>Us</strong>, distribution에 걸리는 시간은 <strong>NF/<em>Us</em>.</strong></li>
<li>dmin: the lowest download rate. <strong>dmin = min{d1,dp,...,dN}.</strong></li>
<li>minimum distribution time : <strong>F/<em>dmin</em></strong></li>
<li><strong>client-server distribution time은 N이 커질 수록 distribution time이 커진다.</strong></li>
<li>P2P 아키텍쳐를 보면 각 peer는 파일 분산해서 서버를 본다. peer가 일부 파일 데이터를 수신하면 자체 업로드 용량을 사용해 데이터를 다른 피어로 재배포 할 수 있다. client-server 아키텍쳐에 비해 계산이 복잡하다. 왜냐하면 distribution time은 각 peer가 파일의 일부를 다른 peer로 배포하는 방법에 따라 달라지기 때문</li>
<li>처음에는 서버만 해당 파일을 가지고 있다. Thus, the minimum distribution time is at least <strong>F/us.</strong></li>
<li>다운로드 속도가 가장 낮은 피어는 F/dmin초 이내에 파일의 모든 F비트를 가져올 수 없다. 따라서 최소 분포 시간은 최소 F/dmin</li>
<li>시스템 전체 업로드 용량 = 서버의 업로드 용량 + 각 피어의 업로드 용량, 즉 (총 = us + u1 + … + UN)</li>
<li>Thus, the minimum distribution time is also at least <strong>NF/(us + u1 + … + uN).</strong></li>
<li><strong>Peer-to-Peer distribution time은 N이 커져도 distribution time이 크게 커지지 않는다.</strong> 
→ 로그함수 모양, 각 peer가 server의 역할을 분담하기 때문에.</li>
</ul>
<h3 id="distributed-hash-tables-dhts">Distributed Hash Tables (DHTs)</h3>
<ul>
<li><strong>client-server architecture</strong> : 하나의 중앙 서버에 모든 <strong>(key-value) pair를 저장</strong>한다.</li>
<li>simple database 구현 방법 : a centralized version of this simple database. <strong>key, value pair</strong>가 포함되어 있다.</li>
<li>key를 사용해서 데이터베이스에 query한다. 일치하는 key-value pair가 있으면 데이터베이스에서 해당 값을 반환한다.</li>
<li>P2P에서 수백만개의 peer의 key-value 값을 저장하는 방법<ul>
<li>각 peer는 (key-value) pair 전체 중 작은 하위 집합만을 가진다. → 전체를 가지고 있지 않다.<ol>
<li>모든 peer는 특정 key로 distributed database를 query한다. </li>
<li>distributed database는  (key-value) pair가 있는 peer를 찾고 해당 peer는 (key-value) pair을 query한 peer로 반환합니다. </li>
<li>모든 peer는 새  (key-value) pair를 데이터페이스에 삽입 할 수 있다. 
이런 <strong>분산 데이터베이스를 distributed hash table(DHT)</strong>라 한다. </li>
</ol>
</li>
</ul>
</li>
<li>P2P 파일 공유 context에서 DHT 서비스 설명 :<ul>
<li>key : contents 이름, value: contents 복사본이 있는 peer의 IP 주소<ul>
<li>DHT 데이터베이스가 peer를 통해 분산되기 때문에 일부 peer가 &#39;Linux&#39; 키를 담당하며 해당 (key-value) pair를 갖게 된다. 
→ 밥과 찰리가 각각 최신 리눅스 배포의 복사본을 가지고 있다고 하는 경우 
즉, DHT 데이터베이스에는 <strong>(Linux, IPBob)와 (Linux, IPCharlie)</strong>의 두 개의 (key-value) pair 포함된다.</li>
<li>구체적인 순서</li>
</ul>
<ol>
<li>앨리스가 &#39;Linux&#39; 복사본을 가지고 싶어한다고 가정 
→ 어떤 peer가 리눅스 복사본을 가지고 있는지 알아야함</li>
<li>&#39;Linux&#39;를 key로 DHT에 query한다. </li>
<li>DHT는 peer인 데이브가 키 &#39;Linux&#39;를 담당한다고 판단한다.</li>
<li>DHT는 peer 데이브에 연결 해 데이브로부터 (key-value) pair인 (Linux, IPBob) 및 (Linux, IPCharlie)을 가져와 Alice에게 전달한다.</li>
<li>Alice는 IPBob 또는 IPCharlie에서 최신 Linux 배포를 다운로드한다.</li>
</ol>
</li>
</ul>
</li>
<li>일반적인 (key, value) pairs에 대한 DHT 설계 문제<ul>
<li>(key, value) pairs을 모든 peers에 무작위로 분산시키고 각 peer가 모든 참여 peer의 IP 주소 목록을 유지하도록 하는 건 문제이다. 
이런 방법은 어떤 peer가 query를 보낼 때 다른 모든 peer에 query를 보내야지만 (key, value) pairs를 포함하는 peer와 일치하는 pair를 응답받을 수 있다. 이런 방식은 <strong>확장 불가능</strong>하고 <strong>각 peer는 다른 모든 peers에 대해 알아야</strong> 할 뿐만 아니라 <strong>각 query를 모든 peer에게 전송</strong>해야하는 문제가 있다.</li>
<li>해결 :<ul>
<li><strong>식별자를 각 peer에 할당</strong>한다. 여기에서 각 식별자는 고정 n에 대해 [0, 2^n-1]이다. 
→ 각 peer에 정수를 할당한다고 생각하면 된다.</li>
<li>실제로는 위의 <strong>키 값은 정수가 아니다</strong> → 이런 키로 정수 생성을 위해 <strong>각 키를 범위의 정수에 매핑하는 해시함수를 사용</strong>한다.</li>
<li>해시 함수는 두 개의 다른 입력이 동일한 출력을 가질 수 있는 다대일 함수이나 해시 함수는 시스템의 모든 피어가 사용할 수 있는 것으로 가정한다. 즉, <strong>&#39;key&#39;는 원래 &#39;key&#39;의 해시를 참조</strong>하는 것이다.</li>
<li>예를 들어 원래 키가 &quot;Led Zeppelin IV&quot;인 경우 DHT에서 사용되는 키는 &quot;Led Zeppelin IV&quot;의 해시에 해당하는 정수</li>
</ul>
</li>
<li>Distributed Hash function에 hash가 사용되는 이유</li>
</ul>
</li>
<li>DHT에  (key, value) pairs을 저장하는 문제<ul>
<li>가장 중요한 문제는 <strong>peer에게 key를 할당하는 규칙</strong>을 정의하는 것</li>
<li>각 peer가 정수 식별자를 가지고 있고 각 key도 동일한 범위의 정수라는 점에서, 자연스러운 접근법은 <strong>식별자가 key에 가장 가까운 peer에 각(key, value) pairs을 할당</strong>하는 것</li>
<li>&quot;가장 가까운&quot; → 편의상 가장 가까운 피어를 키의 <strong>가장 가까운 후속 피어로 정의</strong>한다고 가정</li>
<li>책 그림 참조 : 
n=4라고 가정 했을 때 모든 peer와 key 식별자는 [0, 15]사이에 있다. 더 나아가 식별자가 1, 3, 4, 5, 8, 10, 12 및 15인 8개의 피어가 시스템에 있다고 마지막으로 (key, value) pairs을 저장한다고 가정한다.</li>
<li>(11, 조니 우)는 8명 중에 한 명이고 가장 근접한 규칙을 사용하면 peer12가 가장 근접한 후속 peer이다. 때문에 peer12에 (11, 조니 우)를 저장한다.</li>
<li>앨리스는 열쇠에 가장 가까운 피어를 어떻게 결정할까? 
: 앨리스는 시스템의 모든 peer(peer ID 및 해당 IP주소)를 추적해야하는 경우 가장 가까운 피어를 로컬로 확인할 수 있다. 하지만 이런 방식의 경우 각 피어가 DHT의 다른 모든 피어를 추적해야하며 이는 비현실적이다.</li>
</ul>
</li>
</ul>
<h3 id="circular-dht">Circular DHT</h3>
<ul>
<li>peer가 원형으로 되어 있다고 생각하자. 방향은 오른쪽.</li>
<li>순환 배치에서 peer는 자신의 직전 peer와 직후 peer만을 알고 있다. 아깡의 예를 보면 peer5sms peer 8과 peer 4만을 알고 있다. 이런 peer의 순환 배치는 overlay network의 특수한 경우이다. 
peer는 물리적 링크, 라우터 및 호스트로 구성된 &#39;underlay&#39; 컴퓨터 네트워크 위에 상주하는 추상 논리적 네트워크를 형성하지만 <strong>overlay network는 링크의 물리적 링크가 아닌 peer pairs 간의 가상 연결을 의미</strong>한다.</li>
<li>peer3이 key 11을 찾을 때 peer3은 메시지를 시계방향으로 돌린다. 피어가 이런 메시지를 받을 때마다 직전, 직후 식별자(peer)만을 알기 때문에 해당 key에 대한 책임이 있는지(가장 가까운지) 여부를 판단 할 수 있고 책임지지 않는 경우 그냥 메시지를 다음으로 넘긴다. 이는 key 11에 가장 가까운 peer 12에 전달 될 때까지 지속된다.</li>
<li>circular DHT는 각 peer가 관리해야하는 overlay 정보의 양을 줄여준다.</li>
<li>하지만 최악의 경우 각 피어가 인접한 두 피어만 알고 있지만 키를 담당하는 노드를 찾기위해 DHT의 모든 N 노드가 원을 중심으로 메시지를 전달해야 할 수도 있다. (N/2 메시지).</li>
<li>이를 해결하기 위해 &#39;<strong>shortcut</strong>&#39;이 있다. 각 peer는 <strong>직전, 직후의 peer뿐만아니라 근접한 다른 peer를 추적</strong>한다.  &#39;shortcut&#39;는 query message의 routing이 신속하게 이루어지도록 사용된다.</li>
</ul>
<h3 id="peer-churn-피어-변동">Peer Churn (피어 변동)</h3>
<ul>
<li>peer는 임의로 탈퇴하거나 가입할 수 있다.</li>
<li>이를 위해 각 peer는 두 개의 후속 peer의 IP address를 알고 있어야한다.</li>
<li>후속 peer 중 하나가 이탈하면 그 다음의 peer에 대한 IP address를 가지도록 업데이트한다.</li>
<li>각 peer는 두 후속 peer들이 살아 있는지 확인을 위해 주기적으로 ping messages를 보낸다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Computer Networking] Application(3)]]></title>
            <link>https://velog.io/@winney_77/Computer-Networking-Application3</link>
            <guid>https://velog.io/@winney_77/Computer-Networking-Application3</guid>
            <pubDate>Sun, 08 Aug 2021 12:58:24 GMT</pubDate>
            <description><![CDATA[<h2 id="25-dns---internets-directory-service">2.5 DNS - Internet&#39;s Directory Service</h2>
<ul>
<li><strong>hostname</strong> : internet host 식별자 예) <a href="http://www.yahoo.com">www.yahoo.com</a> 하지만 이런 hostname은 인터넷 내의 위치 정보를 제공하기에는 빈약하다. 게다가 hostname은 다양한 길이의 알파벳 철자를 포함하기 때문에 routers에서 처리하기 힘들다.
→ hosts는 <strong>IP addresses</strong>에의해 식별된다.</li>
<li><strong>IP addresses</strong> : 4바이트로 구성되며 계층구조가 견고하다. 각 마침표는 0 - 255까지의 십진수 표기법으로 표현된다. IP addresses는 계층적이다. 왼쪽에서 오른쪽으로 스캔하며 인터넷에서 host가 위치한 위치에 대해 구체적인 정보를 얻는다.</li>
</ul>
<h3 id="services-provided-by-dns">Services Provided by DNS</h3>
<ul>
<li><p>host를 식별할 때 두가지 방법 : <strong>hostname과 IP address</strong></p>
</li>
<li><p>사람 : hostname, routers : IP address</p>
</li>
<li><p>DNS(domain name system) : hostname을 IP address로 변환하는 일을 한다.</p>
<ol>
<li>DNS의 <strong>계층으로 구현된 분산 데이터베이스</strong>이다.  </li>
<li>hosts가 분산 데이터베이스에 쿼리할 수 있게 하는 <strong>application-layer protocol</strong>이다.</li>
</ol>
</li>
<li><p>DNS 서버는 berkeley internet name domain(BIND) 소프트웨어를 실행하는 유닉스 시스템인경우가 많다. <strong>DNS protocol은 UDP를 통해 실행</strong>되며 port 53을 사용한다.</p>
</li>
<li><p>DNS는 hostname에서 IP address로 변환하기 위해 HTTP, SMTP, FTP와 같은 <strong>다른 application-layer protocol에서 사용</strong>된다.</p>
</li>
<li><p>과정</p>
<ol>
<li>동일한 유저 시스템이 DNS application의 <strong>client 측을 실행</strong>한다.</li>
<li>브라우저는 URL에서 <strong>hostname을 추출해 DNS application의 client 측으로 hostname을 전달</strong>한다. </li>
<li>DNS client는 <strong>DNS server로 hostname이 포함된 query를 보낸다.</strong> </li>
<li>DNS client는 <strong>hostname에 대한 IP address가 포함된 응답을 받는다.</strong> </li>
<li>DNS로부터 IP address를 받은 후 브라우저는 해당 <strong>IP address의 port 80번에 해당하는 HTTP server process에 TCP connection을 시작</strong>한다. </li>
</ol>
</li>
<li><p>IP address는 종종 <strong>근접한 DNS server에 caching</strong> 되기 때문에 DNS <strong>네트워크 트래픽과 평균 DNS 딜레이를 줄이는데 도움</strong>을 준다.</p>
</li>
<li><p>DNS는 hostname에서 IP address를 변환하는데 추가적인 중요 서비스를 제공한다.</p>
<ul>
<li><p><strong>Host aliasing</strong>(별칭) : 복잡한 hostname은 하나 이상의 별칭을 가질 수 있다. 
<a href="http://relay1.west-coast.enterprise.com/"><em>relay1.west-coast.enterprise.com</em></a> → </p>
</li>
<li><p><em>canonical hostname(정식 호스트이름) :** *enterprise.com</em> and <a href="http://www.enterprise.com"><em>www.enterprise.com</em></a> <strong>,</strong> DNS는 application 호출로 제공된 별칭 호스트 이름과 호스트의 IP 주소를 가져 올 수 있다. 
순서: <strong>host alias name &gt; host canonical name &gt; IP address</strong></p>
</li>
<li><p><strong>Mail server aliasing</strong>(메일 서버 별칭) :host의 IP address뿐만 아니라 제공된 alias hostname를 위한 canonical hostname을 가져오기 위해 mail application에서 DNS를 호출 할 수 있다.<br>예) <a href="mailto:heathers@nextunicorn.kr">heathers@nextunicorn.kr</a>에서 nextunicorn.kr이 도메인 이름이기에 이를 이용해 서버의 IP 주소를 찾아 TCP 연결</p>
</li>
<li><p><strong>Load distribution</strong> : DNS는 복제된 웹 서버 간에 load distribution을 수행하는데도 사용된다. cnn.com과 같은 사이트는 여러 서버를 통해 복제되고 각 서버는 서로 다른 end-system에서 실행된다. 그렇기에 복제된 웹 서버는 IP 주소 집합이 하나의 표준 호스트(canonical hostname)과 연결된다. DNS database에는 이 IP address 집합이 포함되어 있다. client가 주소 집합에 매핑된 이름에 대해 DNS query를 만들면 server는 전체 IP 주소 집합에 매핑된 이름에 대해 DNS query를 만들면 서버는 전체 IP 주소 집합으로 응답하지만 각 응답 내의 주소 순서를 회전한다. client는 일반적으로 HTTP 요청 메시지를 집합에 먼저 나열된 IP address로 전송하므로 DNS 순환은 트래픽을 복제된 서버 간에 분산시킨다
→ <strong>동일 도메인 주소에 접근하는 client들에게 IP 주소를 분산시킨다</strong>
일반적으로 DNS 서버에는 <strong>하나의 도메인의 여러 IP 주소 List</strong>를 가지고 있다. 접속하는 client들에게 이 list를 모두 주는데 보통 첫번째 주소를 사용하기 때문에 <strong>서버가 list를 rotation</strong>해서 보내준다.</p>
<h2 id="overview-of-how-dns-works">Overview of How DNS Works</h2>
</li>
<li><p>hostname-to-IP-address translation service</p>
</li>
<li><p>DSN가 하나로 구성되어 있다면 client가 요청하거나 DNS가 응답할 때 편할 것이다. 하지만 오늘날에 맞지 않음</p>
</li>
<li><p>중앙화된 설계의 문제점 :</p>
<ul>
<li><strong>single point of failure</strong> : DNS server가 다운되면 모든 인터넷도 다운된다.</li>
<li><strong>traffic vlume</strong> : 하나의 DNS server에서 모든 query에 응답하게 된다.</li>
<li><strong>distant centralize database</strong> : 물리적인 거리가 멀면 delay가 심화된다.</li>
<li><strong>maintenance</strong> : DNS server가 하나라면 매일 새로운 host를 업데이트되어야 한다.</li>
</ul>
<h2 id="a-distributed-hierarchical-database">A Distributed, Hierarchical Database</h2>
</li>
<li><p>scale문제를 해결하기 위해 DNS는 전 세계에 분산된 수많은 계층적 형태의 서버를 사용한다.</p>
</li>
<li><p>mapping은 DNS servers에 분산되어 있다.</p>
</li>
<li><p>DNS servers는 3계층이 있다.</p>
<ul>
<li><strong>root DNS servers</strong></li>
<li><strong>TLD(top-level domain) DNS servers</strong></li>
<li><strong>authoritative DNS servers</strong></li>
</ul>
</li>
<li><p>예) <a href="http://www.amazone.com">www.amazone.com</a> 찾기</p>
<ol>
<li>client는 root server에 접근해 TLD server(.com)의 IP주소를 받는다.</li>
<li>client는 TLD server에서 authoritative server(amazon.com)의 IP 주소를 받는다.</li>
<li>clicent는 authoritative server(amazon.com)에서 <a href="http://www.amazone.com%EC%9D%98">www.amazone.com의</a> IP 주소를 받는다. </li>
</ol>
</li>
<li><p><strong>Root DNS servers</strong> : 전 세계에 13개가 있다.</p>
</li>
<li><p><strong>Top-level domain (TLD) servers</strong> : 이 서버들은 com, org, net, edu, gov 등의 신뢰할만한 TLD, uk, fr, ca, kr 등의 국가 TLD 등이 있다.</p>
</li>
<li><p><strong>Authoritative DNS servers</strong></p>
</li>
<li><p>DNS server의 또 다른 중요한 타입 : <strong>local DNS server(a default name server)</strong></p>
<ul>
<li>서버의 계급에 엄격히 따르지 않는다. 대신 DNS 구조에도 중앙화로 되어있다. 각 ISP(학교, 회사 등)이 local DNS server를 가진다.</li>
<li>host가 DNS query를 만들 때 query는 local DNS server로 보내지고 proxy처럼 역할을 하며 query를 DNS server 계층으로 전달한다.</li>
<li>DNS name resolution example<ul>
<li>recursive queries: 기본</li>
<li>iterated query: local DNS server에 따라</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="dns-caching">DNS Caching</h3>
<ul>
<li>DNS caching</li>
<li>장점 : delay를 줄임, DNS message 수를 줄임(traffic 낮춤)</li>
<li>hostname/IP address pair가 DNS server에 cache되고 동일한 hostname을 가진 다른 query가 DNS server에 도착하면 DNS server는 hostname에 대한 권한 없이도 원하는 IP address를 제공한다.</li>
<li>local DNS server는 TLD 서버의 IP 주소도 cache 할 수 있기 때문에 local DNS server는 query chain을 우회할 수 있고 일반적으로 우회한다.</li>
<li>단, cache한게 오래되어 있을 수 있다. 만약 name host의 IP address가 변경되었다면 TTL(Time to live)이 만료될 때까지 인터넷 전체는 알 수 없다.</li>
</ul>
<h2 id="dns-records-and-messages">DNS Records and Messages</h2>
<ul>
<li>DNS server는 hostname과 IP address mapping을 제공하는 RR(resource record)을 포함해 DNS distributed database store resource records(RRs)를 함께 구현한다.</li>
<li>resource record(RR) 형태 :  (name, value, type, TTL)<ul>
<li>TTL: time to live of the resource record, cache에서 리소스를 제거할 시기를 결정한다.</li>
</ul>
</li>
<li>query와 reply 메시지 형태는 같다.</li>
<li>nslookup 은 name server 관련한 조회를 할 수 있는 명령어</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Computer Networking] Application(2)]]></title>
            <link>https://velog.io/@winney_77/Computer-Networking-Application2</link>
            <guid>https://velog.io/@winney_77/Computer-Networking-Application2</guid>
            <pubDate>Sun, 01 Aug 2021 13:45:43 GMT</pubDate>
            <description><![CDATA[<h1 id="24-electronic-mail-in-the-internet-전자-메일">2.4 Electronic Mail in the Internet 전자 메일</h1>
<ul>
<li>mail system의 주요 component: <strong>user agents(UA)</strong>, <strong>mail servers, Simple Mail Transfer Protocol(SMTP)</strong></li>
<li><strong>Outgoing message queue</strong> : 발신 문자 대기열</li>
<li><strong>mailbox</strong>는 mail server 중 하나에 위치해있다.</li>
<li>메일서버로 메일 전송을 못 할 시 <strong>message queue</strong>(메세지 대기열)이후에 <strong>주기적으로 전송시도</strong>를 한다. (30분 정도마다) 며칠동안 실패하면 서버는 메시지를 삭제하고 발신자에게 메시지로 알린다.</li>
<li>SMTP는 인터넷 전자 메일을 위한 애플리케이션 계층 프로토콜이다. 발신자로부터 수신자에게 메일 전달을 위해 TCP의 믿을만한 데이터 전송 서비스(reliable data transfer service)를 사용한다.</li>
<li>client와 server 측을 가지고 있다.</li>
</ul>
<h2 id="smtp">SMTP</h2>
<ul>
<li><p>http보다 오래되었다.</p>
</li>
<li><p>메일 메시지의 header뿐만 아니라 body도 7-bit ASCII로 제한된다. 80년대에는 대용량 이미지 등을 메일로 보내지 않았기 때문에 적합한 형태였다. 
그렇기에 오늘날 멀티미디어 전송을 위해 몇 가지 과정을 더 거쳐야 한다.</p>
<ol>
<li><p>이진 멀티미디어 데이터를 ASCII로 인코딩</p>
</li>
<li><p>SMTP 전송</p>
</li>
<li><p>해당 ASCII 메시지를 다시 이진수로 디코딩</p>
<p>→ 이에 비해 HTTP는 전송 전에 멀티미디어 테이터를 ASCII로 인코딩할 필요가 없다. </p>
</li>
</ol>
</li>
<li><p>SMTP 과정</p>
<ol>
<li>앨리스가 자신의 user agent를 호출 후 밥의 주소(IP address) 제공 및 메시지 작성, 발신 지시</li>
<li>앨리스의 user agent는 메시지를 앨리스의 mail server로 보낸다. 메시지는 message queue에 놓이게된다. </li>
<li>SMTP의 client 측인 앨리스의 mail server는 message queue에 담긴 message를 확인하고 SMTP server에 TCP connection을 연다.</li>
<li>초기 SMTP handshaking 후 SMTP client는 앨리스의 메시지를 TCP connection으로 전송합니다.  </li>
<li>밥의 mail server인 SMTP의 서버측은 메시지를 수신합니다. 이후 밥의 메일 서버는 밥의 mailbox에 메시지를 놓습니다. </li>
<li>밥은 원할 때 그의 user agent를 호출해 메시지를 읽습니다. </li>
</ol>
</li>
<li><p>중요점</p>
<ol>
<li>일반적으로 <strong>SMTP는 두 메일 서버가 세계 반대쪽에 위치하더라도 중간 mail server를 사용해서 메시지를 보내지 않는다</strong>는 점이다. TCP connection은 <strong>두 server를 direct로 연결</strong>한다. <ul>
<li>만약 밥의 server가 down되면 메시지는 앨리스의 mail server에서 <strong>계속 전송 시도</strong>를 한다.</li>
<li>SMTP는 사람의 면대면 만남과 흡사하다. 첫 handshaking은 서로 인사를 하는 과정이며 이 때 SMTP client는 발신인의 이메일 주소와 수신자의 이메일 주소를  표시한다.</li>
<li>SMTP는 TCP를 통해 메시지를 에러없이 전달한다.</li>
</ul>
</li>
<li><strong>SMTP는 persistent connection을 사용</strong>한다.<ul>
<li>만약 같은 mail server에 여러 메일을 보낼 경우 같은 TCP connection을 사용해서 보낸다. 이 때는 client에서 <strong>MAIL FROM:</strong>  을 사용해서 각각이 독립된 메일임을 알려준다.</li>
</ul>
</li>
<li><strong>SMTP는 CRLF를 사용</strong>한다. <ul>
<li>CRLF : CR(carriage return) + LF(line feed)이다. 
텍스트의 한 줄이 끝남을 표시하는 문자 또는 문자열을 의미하며 특수문자로 눈에는 보이지 않는다. 개행문자, 줄바꿈 문자, EOL(end-of-line)과 같은 뜻이다. 
기종이나 운영체제에 따라 새줄 문자를 나타내는 코드가 다를 수도 있기에 텍스트를 다른 시스템으로 전송할 때 새줄 문자의 치환작업도 필요한다. </li>
<li>LF :  아스키 코드 16진수로 OA, 기능은 커서를 현재 행의 다음 행으로 즉, 아래로 내리기</li>
<li>CR:  아스키 코드 16진수로 OD, 기능은 커서를 현재 행을 맨 좌측으로 옮기기
즉, &#39;커서를 아래로 내리는 동작&#39; + &#39;커서의를 행의 맨 앞으로 보내는 동작&#39; = &#39;다음줄로 행갈이&#39;
사용 : </li>
<li>도스/윈도우는 CR+LF로 하나의 행길이, </li>
<li>유닉스/리눅스: LF로 하나의 행갈이, </li>
<li>맥에서는 CR로 하나의 행갈이 표현,</li>
</ul>
</li>
</ol>
</li>
</ul>
<h2 id="http와-비교">HTTP와 비교</h2>
<ul>
<li>HTTP는 <strong>web server에서 web client</strong>로 파일을 전송한다. SMTP는 메시지를 <strong>mail server에서 mail server</strong>로 전송한다.</li>
<li><strong>HTTP는 pull protocol</strong>이다. <strong>SMTP는 push protocol</strong>이다. 그렇기에 HTTP의 TCP connection은 파일을 <strong>받는 쪽에서 시작</strong>하고 SMTP의 TCP connection은 파일을 <strong>보내는 쪽에서 시작</strong>한다.</li>
<li>이미지 파일등의 binary data를 보낼 때 HTTP는 인코딩 과정이 필요 없지만 <strong>SMTP는 ASCII 코드로 인코딩 과정이 필요</strong>하다.</li>
<li>HTTP는 각각의 객체를 자체 HTTP 응답 메시지에 <strong>캡슐화</strong>를 한다. SMTP는 메시지의 <strong>모든 객체를 하나의 메시지</strong>에 넣는다.</li>
</ul>
<h2 id="mail-message-formats">Mail Message Formats</h2>
<ul>
<li>SMTP에는 header와 body가 있고 header에는 지엽적인 정보가 들어간다. 이런 형식은 RFC에서 지정하고 있다. header에는 <strong>From:</strong>, <strong>To:</strong>와 같은 내용이 들어가고 <strong>subject:</strong> 와 같은 옵션도 있다.</li>
<li>이러한 header의 형식은 SMTP command의 MAIL FROM, RCPT TO와 같은 command과 다르다. 여기서의 format은 메일의 형식이다.</li>
<li>header의 아래에는 빈 줄이 있고 그 아래에 body가 있다.</li>
</ul>
<h2 id="mail-access-protocols">Mail Access Protocols</h2>
<ul>
<li><p>위의 예시들은 <strong>밥이 자신의 mail server에 로그인</strong>을 해서 메일을 읽는다고 가정했다. 하지만 오늘날에는 <strong>client-server architecture</strong>를 사용한다. 즉, 일반적인 사용자는 PC, 노트북, 스마트폰 등 다양한 end system에서 메일을 읽는다.</p>
</li>
<li><p>위에서 만약에 밥의 mail box가 그의 local PC에 있다면 밥은 메일을 받기 위해서 항상 PC가  켜진채로 인터넷에 연결되어 있어야 한다. 하지만 대부분의 사용자는 local PC에서 상시 공유 메일 서버에 저장된 편지함에 접근합니다. 이 <strong>mail server는 다른 사용자와 공유되고 일반적으로 사용자의 ISP에서 관리</strong>한다.</p>
</li>
<li><p><strong>SMTP의 사용</strong>은 <strong>발신자 → 발신자의 mail server → 수신자의 mail server → 수신자</strong>의 과정에서 사용됩니다. 발신자가 굳이 발신자의 mail server로 보내는 이유는 <strong>만약 수신자가 연결 될 수 없는 상태일 경우에 server가 주기적으로 메시지 전송을 하기 위함</strong>이다.</p>
</li>
<li><p>위의 과정에서 수신자의 mail server → 수신자의 경우 SMTP를 사용하지 않는다. SMTP는 push protocol이기 때문이다. 대신 메일에 접근 할 수 있는 protocol을 사용한다. 주로 <strong>POP3(post office protocol - version3), IMAP(internet mail access protocol), HTTP</strong>가 사용된다.</p>
<p>  <img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d7d933ae-cbc6-4aeb-bb26-c3ec428d2089/_2021-06-28__9.40.17.png" alt="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d7d933ae-cbc6-4aeb-bb26-c3ec428d2089/_2021-06-28__9.40.17.png"></p>
<p>  <img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d7d933ae-cbc6-4aeb-bb26-c3ec428d2089/_2021-06-28__9.40.17.png" alt="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d7d933ae-cbc6-4aeb-bb26-c3ec428d2089/_2021-06-28__9.40.17.png"></p>
</li>
</ul>
<h3 id="pop3">POP3</h3>
<ul>
<li>기능적으로 제한되어 있어 짧고 읽기 쉽다.</li>
<li>user agent에서 mail server로 110번 포트를 사용해서 <strong>TCP connection을 연다</strong>. 이후 3단계를 거친다. <strong>인증(authorization),  트랜잭션(transaction), 갱신(update)단계</strong>이다.</li>
<li>인증 : <strong>유저 인증을 위해 username과 password를 보낸다.</strong>  두 가지 command가 있는데 user <username>, pass<password>이다.</li>
<li>트랜잭션 : user agent는 메시지를 가져온다. 이 때 user agent는 삭제를 위해 메시지에 표시하고 삭제마크를 지우고 메일 통계를 가져온다.<br>response는 두가지로 <strong>+OK, -ERR</strong>가 있다. &#39;download and delete&#39; 또는 &#39;download and keep&#39;으로 구성할 수 있다.  user agent가 작동중인 모드에 따라 달라진다. download and delete 모드에서는 UA가 list, retr, dele command를 실행한다.</li>
<li>갱신 : client에서 QUIT command를 실행한 후 갱신하고 POP3를 종료한다. 이 때 <strong>mail server에서는 삭제 표시 된 메시지를 삭제</strong>한다.</li>
<li>UA는 먼제 mail server에 저장된 메시니의 각 크기 별로 나열하도록 요청한다. 이 후 UA는 mail server에서 각 메시지를 검색하고 삭제한다. quit command 이후 POP3 서버는 갱신단계로 들어가 읽은 메시지를 삭제한다.</li>
<li>문제 : download-and-delete 모드의 문제는 수신자인 bob이 PC, 노트북, 휴대폰 같은 다양한 end system에서 메시지에 접을 하고 싶을 때 다른 컴퓨터를 사용해서 다시 메일을 읽고 싶을 때 메일을 읽을 수 없다는 점이이다.</li>
<li>download-and-keep 모드의 경우 밥은 여러 컴퓨터에서 메일을 다시 읽을 수 있다.</li>
<li>POP3 세션동안 UA과 mail server는 일부 정보 상태를 유지하고 삭제된 것으로 표시된 유저 메시지를 추적할 수 있다. 하지만 POP3 서버는 POP3 세션 전체에 상태정보를 전달하지 않는다. 이렇게 전반적으로 상태정보가 부족하면 POP3 서버 구현이 크게 간소화 된다.</li>
</ul>
<h3 id="imap">IMAP</h3>
<ul>
<li>POP3는 로컬에서 폴더를 만들어 관리 할 수는 있으나 원격에서 모든 컴퓨터로 접근 할 수 있는 폴더 계증을 유지하지는 못한다. 즉, <strong>사용자가 원격 폴더를 만들고 메시지를 할당하는 수단</strong>을 가지지 않는다. IMAP는 이를 해결하기 위해 나왔다.</li>
<li><strong>IMAP 서버는 각 메일를 폴더와 연결</strong>한다. 처음 메시지가 왔을 때 서버는 수신자의 INBOX 폴더와 연결한다. IMAP는 유저에게 폴더를 생성하고 메시지를 옮길 수 있으며 <strong>원격 폴더에서 특정 기준과 일치하는 메시지를 찾을 수 있는 command를 제공</strong>한다.</li>
<li>POP3과 다르게 IMAP는 <strong>IMAP 세션 전체에 유저의 상태 정보를 유지</strong>한다. 예를 들면 폴더 이름과 폴더와 관련된 메시지가 표시된다.</li>
<li>IMAP의 또다른 특징은 UA가 메시지 구성요소를 가져 올 수 있는 command를 가지는 것이다. 예를 들면 <strong>UA는 메시지의 header나 MIME 메시지의 일부만 가질 수 있다.</strong> 이는 a low-bandwidth connection(저대역폭 연결)에 유용하다. 이는 유저가 느린 속도로 메시지의 모든 정보를 받지 않기를 원할 때 일부만 받아서 볼 수 있다.</li>
</ul>
<h3 id="web-based-e-mail">Web-based E-mail</h3>
<ul>
<li>많은 유저는 웹 브라우저를 이용해 메일을 보내고 접근한다. 이 말은 대부분의 UA는 보통 웹 브라우저이고 <strong>HTTP를 통해 원격 mailbox과 상호작용</strong>한다는 것이다.</li>
<li>그렇기에 대부분의 경우 </li>
<li><em>발신자 UA → 발신자 mail server : HTTP
발신자 mail server → 수신자 mail server : SMTP
수신자 mail server → 수신자 UA : HTTP*</em>
로 이루어진다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[마이크로 서비스 아키텍쳐]]></title>
            <link>https://velog.io/@winney_77/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C-%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90</link>
            <guid>https://velog.io/@winney_77/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C-%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90</guid>
            <pubDate>Sun, 06 Jun 2021 13:25:44 GMT</pubDate>
            <description><![CDATA[<p> : 글을 읽고 기억 할 수 있는 키워드 위주 요약</p>
<ul>
<li>작은 규모의 자율적인 서비스로 구성</li>
<li>각 서비스는 독립적이며 단일 비즈니스로 구성</li>
<li>작은 개발팀이 개발 할 수 있는 개발 코드베이스</li>
<li>서비스는 해당 데이터나 외부 상태 유지</li>
<li>각 서비스의 내부 구현 사항은 외부 서비스에서 가려짐 </li>
<li>다중저장소 프로그래밍을 지원 -&gt; 각 서비스는 개별 라이브러리 등 사용가능</li>
</ul>
<p><img src="https://images.velog.io/images/winney_77/post/aecbb8c8-f192-4d94-bbe4-0466637b7a44/microservices-logical.png" alt=""></p>
<p>-** API 게이트웨이** :  API 게이트웨이는 클라이언트의 진입점입니다. 클라이언트는 서비스를 직접 호출하는 대신, 호출을 백 엔드의 적절한 서비스에 전달하는 API 게이트웨이를 호출</p>
<ul>
<li>장점 : <ul>
<li>클라이언트와 서비스가 분리</li>
<li>서비스가 웹 우호적이 아닌 AMQP 등의 메시징 프로토콜을 사용 가능, API 게이트웨이는 인증</li>
<li>로깅, SSL 종료, 부하 분산 등의 다른 교차 기능을 수행 가능</li>
<li>제한, 캐싱, 변환 또는 유효성 검사와 같은 즉시 사용 가능한 정책</li>
</ul>
</li>
</ul>
<p>마이크로 서비스 아키텍쳐 특징</p>
<ul>
<li>장점<ul>
<li>민첩성</li>
<li>집중화된 소규모 팀</li>
<li>소규모 코드 기준</li>
<li>기술의 혼합</li>
<li>결함 격리</li>
<li>확장성</li>
<li>데이터 격리</li>
</ul>
</li>
<li>단점<ul>
<li>복잡성</li>
<li>개발 및 테스트</li>
<li>통제 부족</li>
<li>네트워크 정체 및 대기 시간</li>
<li>데이터 무결정</li>
<li>관리</li>
<li>버전 관리</li>
<li>기술 수준</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[싱글톤 패턴 (singleton pattern)]]></title>
            <link>https://velog.io/@winney_77/%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4-singleton-pattern</link>
            <guid>https://velog.io/@winney_77/%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4-singleton-pattern</guid>
            <pubDate>Sat, 22 May 2021 08:58:18 GMT</pubDate>
            <description><![CDATA[<h3 id="용어">용어</h3>
<ul>
<li>소프트웨어 디자인 패턴(소프트웨어 디자인 설계) :  소프트웨어 공학의 소프트웨어 디자인에서 특정 문맥에서 공통적으로 발생하는 문제에 대해 재사용 가능한 해결책이다.(wiki) 즉, 소프트웨어 설계 시 특정 문제를 반복해서 해결할 때 재사용할 수 있는 해결책을 의미한다. 주로 생성 패턴, 구조패턴, 행위 패턴 3가지로 나눈다. </li>
</ul>
<h1 id="싱글톤-패턴singleton-pattern">싱글톤 패턴(singleton pattern)</h1>
<ul>
<li>자바에서 많이 사용하는 패턴</li>
<li>생성 패턴의 하나이다. </li>
<li>전역 변수를 사용하지 않고 객체를 하나만 생성하도록 하며, 생성된 객체를 어디에서든지 참조할 수 있도록 하는 패턴</li>
<li>싱글톤 패턴의 클래스는 생성자가 여러 차례 호출되어도 실제로 생성되는 객체는 하나이며 최초 생성 이후 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. </li>
<li>애플리케이션이 시작될 때 어떤 클래스가 <strong>최초 한번만 메모리를 할당</strong>하고(Static) 그 메모리에 인스턴스를 만들어 사용하는 디자인패턴. 즉, 생성자의 호출이 반복적으로 이뤄져도 실제로 생성되는 객체는 최초 생성된 객체를 반환한다.</li>
</ul>
<h2 id="장점">장점</h2>
<ul>
<li>메모리 낭비를 줄일 수 있다. 
: 최초 한 번만 메모리 할당 이후 한 번의 인스턴스 생성으로 재사용 가능 하기 때문</li>
<li>다른 클래스의 인스턴스들이 데이터 공유하기가 쉽다. 
: 싱글톤 클래스의 인스턴스는 전역 인스턴스 이기 때문</li>
</ul>
<h2 id="단점">단점</h2>
<p> : 싱글톤 인스턴스가 전역성을 띄면서 생기는 문제이다. </p>
<ul>
<li>싱글톤 인스턴스가 너무 많은 일을 하거나 많은 데이터를 공유 할 경우 다른 클래스의 인스턴스와 결합도가 높아져 객체 지향 설계 원칙의 &#39;개방-폐쇄 원칙&#39;에 어긋 날 수 있다. </li>
<li><blockquote>
<p>수정, 테스트가 어려워진다. </p>
</blockquote>
</li>
<li><blockquote>
<p>싱글톤 객체 수정으로 사이드 이펙트가 생길 수 있다. </p>
</blockquote>
</li>
<li><blockquote>
<p>멀티 쓰레드 환경에서 동기화처리 문제가 생긴다. (인스턴스가 2개 생성 된다는 등의 문제)</p>
</blockquote>
</li>
</ul>
<hr>
<p>출처 </p>
<ul>
<li><a href="https://elfinlas.github.io/2019/09/23/java-singleton/">https://elfinlas.github.io/2019/09/23/java-singleton/</a></li>
<li><a href="https://gmlwjd9405.github.io/2018/07/06/singleton-pattern.html">https://gmlwjd9405.github.io/2018/07/06/singleton-pattern.html</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[IIFE 즉시 실행 함수 표현식]]></title>
            <link>https://velog.io/@winney_77/%EB%AD%90%EC%93%B0%EC%A7%80</link>
            <guid>https://velog.io/@winney_77/%EB%AD%90%EC%93%B0%EC%A7%80</guid>
            <pubDate>Tue, 04 May 2021 09:04:01 GMT</pubDate>
            <description><![CDATA[<h3 id="용어">용어</h3>
<ul>
<li><strong>함수 선언식</strong>(function declaration) : 호이스팅에 영향 받음<pre><code>function sum(a, b) {
return a + b;
}</code></pre></li>
<li><strong>함수 표현식</strong>(function expression) : 호이스팅에 영향 받지 않음</li>
<li><strong>익명 함수</strong> : 이름이 없는 함수, 변수에 익명함수를 할당하거나 다른 함수의 매개변수로 사용가능하다. 코드를 보면 <code>sum</code>변수에 익명함수가 할당 되어 있다.<pre><code>var sum = function() {
return a + b;
}</code></pre></li>
<li><strong>스코프</strong>(scope) : 어떠한 식별자(변수)에 접근 할 수 있는 범위</li>
<li><strong>클로저</strong>(closur) <ul>
<li>어떤 함수(외부함수)에서 선언한 변수를 참조하는 내부함수에서만 발생하는 현상</li>
<li>외부 함수의 LexicalEnvironment가 가비지 컬렉팅되지 않는 현상</li>
</ul>
</li>
<li><strong>1급 시민</strong>(first-class citizen) 
: 1급 시민의 *<em>조건 *</em><ul>
<li>변수(variable)에 담을 수 있다</li>
<li>인자(parameter)로 전달할 수 있다</li>
<li>반환값(return value)으로 전달할 수 있다</li>
</ul>
</li>
<li><strong>1급 객체</strong>(first-class object) : 1급 시민의 조건을 가진 객체</li>
<li><strong>1급 함수</strong>(first-class function) : 1급 시민의 조건을 갖춘 함수, JavaScript에서는 함수도 객체이기 때문에 JavaScript의 함수는 1급 객체이자 1급 함수이다. </li>
<li>함수의 실행 : 함수뒤에 <code>()</code>가 있으면 실행의 의미이다. </li>
</ul>
<h1 id="1-iife-즉시-실행-함수">1. IIFE 즉시 실행 함수</h1>
<p> IIFE(Imemediately-invoked function expression)는 정의된 즉시 실행되는 자바스크립트 함수이다. </p>
<h2 id="목적">목적</h2>
<ul>
<li>로컬 블록 내에서 지역 변수 호이스팅을 방지</li>
<li>글로벌 네임스페이스의 오염을 방지 : IIFE는 익명함수를 사용할 수 있기 때문</li>
<li>함수 내 정의된 변수에 대한 프라이버시를 유지하면서 동시에 메서드에 대한 공개 액세스를 허용
(from Wiki)</li>
</ul>
<p>간단하게 말하면 주로 private scope를 만들기 위해 IIFE를 사용한다. </p>
<p>즉, 함수 내에서 변수를 선언해 함수의 스코프를 함수 내로 제한하고 즉시 함수를 실행시키면서 함수명에 의한 호이스팅(함수 선언식 사용 시)이나 전역 변수 오염을 막음으로서 예상치 못한 버그, 에러 등을 예방할 수 있다. 
ES6 이전에는 모듈화를 할 때 IIFE 패턴을 많이 사용했다고 한다. </p>
<h2 id="코드-예시">코드 예시</h2>
<h3 id="1번">1번</h3>
<ul>
<li><code>()</code>안에 익명함수를 선언하고 <code>()</code>를 밖에 사용해 즉시 실행한다.<pre><code>(function() {
console.log(&#39;IIFE&#39;);
})();
</code></pre></li>
</ul>
<p>(()=&gt; {
  console.log(&#39;IIFE arrow function&#39;)
})()</p>
<pre><code>- 에러 : 익명함수를 반드시 ```()```로 감싸야한다. </code></pre><p>function() {
  console.log(&#39;no wrapping parentheses&#39;)
}() // error</p>
<pre><code>### 2번
- 함수 실행을 의미하는 ```()```가 내부에 있다.</code></pre><p>(function() {
  console.log(&#39;IIFE&#39;);
});</p>
<p>(()=&gt; {
  console.log(&#39;IIFE arrow function&#39;)
}())</p>
<pre><code>### 3번
- 이름이 있는 IIFE</code></pre><p>(function callIIFE() {
  console.log(&#39;named IIFE&#39;);
})();</p>
<p>```</p>
<h1 id="2-iife-꼭-알아야하나">2. IIFE 꼭 알아야하나?</h1>
<p>이 부분이 가장 의문이었다. 이전에 IIFE에 대해 처음 알게되었을 때 ES6의 등장으로 잘 사용할 일이 없다는 글을 보았었다.
하지만 어디에나 레거시 코드가 있고 괄호()로 감싸져있는 함수를 볼 때마다 낯설게만 느껴졌다. 
현 직장의 코드에서는 IIFE를 본 적이 없으나 비슷한 개념으로 사용하고 있는 부분들이 있어서 처음 해당 코드를 볼 때 IIFE가 생각나지 않아 한참이나 헤맸었다. 
게다가 검색을 하다보면 IIFE를 사용한 코드 예시가 아주 드물지만 있어서 뭔지는 알아야겠다고 생각했다. 
과거와 항상 함께하는 한 알아야할 지식이라고 생각한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JSX.Element / ReactNode / ReactElement]]></title>
            <link>https://velog.io/@winney_77/JSX.Element-ReactNode-ReactElement</link>
            <guid>https://velog.io/@winney_77/JSX.Element-ReactNode-ReactElement</guid>
            <pubDate>Wed, 14 Apr 2021 11:44:26 GMT</pubDate>
            <description><![CDATA[<p>Typescript를 사용하면서 가장 어렵다고 생각하는 부분이 컴포넌트나 기타 라이브러리의 타입을 어떻게 지정하는가에 대한 부분이라고 생각한다. 
오늘도 React.Element를 찾다가 StackOverFlow에 좋은 답변이 있어서 정리해보려고 한다. </p>
<h3 id="용어">용어</h3>
<ul>
<li>네임 스페이스 (name space) : 구분이 가능하도록 정해놓은 범위나 영역. 이름을 한 곳에 모아 충돌을 방지하고 해당 이름으로 선언된 변수는 함수를 쉽게 가져다 쓸 수 있다록 만든 메커니즘.
❗️ 네임 스페이스 패턴(name space pattern)을 검색하면 더 확실히 알 수 있다.  </li>
</ul>
<h1 id="1-reactelement">1. ReactElement</h1>
<p>React.element는 type과 props를 가진 객체이다. </p>
<pre><code>type Key = string | number

interface ReactElement&lt;P = any, T extends string | JSXElementConstructor&lt;any&gt; = string | JSXElementConstructor&lt;any&gt;&gt; {
  type : T;
  props : P;
  key: Key | null;
}</code></pre><h1 id="2-reactnode">2. ReactNode</h1>
<p>ReactNode는 ReactElement, ReactFragment, string, number, ReactNode의 Array, null, undefined, boolean이다. </p>
<pre><code>type ReactText = string | number;
type ReactChild = ReactElement | ReactText;

interface ReactNodeArray extends Array&lt;ReactNod&gt; {}
type ReactFragment = {} | ReactNodeArray;

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;</code></pre><h1 id="3-jsxelement">3. JSX.Element</h1>
<p>JSX.Element는 props와 type이 any인 제네릭 타입을 가진 ReactElement이다. JSX는 글로벌 네임 스페이스에 있기 때문에 다양한 라이브러리에서 자체 라이브러리의 방법대로 실행 될 수 있다. </p>
<p>리액트의 경우 다음과 같이 실행된다. </p>
<pre><code>declare global {
  namespace JSX {
    interface Element extends React.ReactElement&lt;any, any&gt; {}
  }
}</code></pre><p>예시</p>
<pre><code>&lt;p&gt; // ReactElement = JSX.Element
  &lt;Custom&gt; // ReactElement = JSX.Element
    {true &amp;&amp; &#39;test&#39;} // ReactNode
  &lt;/Custom&gt;
&lt;/p&gt;</code></pre><h1 id="4-class-component와-functional-component의-render-시-return-값-차이">4. Class component와 Functional component의 render 시 return 값 차이</h1>
<ul>
<li><strong>Class Component</strong>는 <strong>ReactNode</strong>를 return<pre><code>render(): ReactNode;</code></pre></li>
<li><strong>Functional Component</strong>는 <strong>ReactElement</strong>를 return</li>
<li>Functional component는 _stateless components_이다. <pre><code>interface StatelessComponent&lt;P = {}&gt; {
(props: P &amp; { children? : ReactNode }, context?: any): ReactElement | null;
}</code></pre></li>
</ul>
<h1 id="5-그래서-타입-선언-시-class-component와-functional-component는-어떻게-다를까">5. 그래서 타입 선언 시 Class component와 Functional component는 어떻게 다를까?!</h1>
<p>✏️ Class Component는 ReactNode를 타입으로 지정한다. ReactNode는 그 자체로 다양한 타입을 지니기 때문에 충분!
✏️ Functional Component는 ReactElement는 object 형태로 null 값을 가지고 있지 않기 때문에 union을 사용해서 null 값을 줘야한다. 💯 <code>ReactElement | null</code></p>
<pre><code>const Example = () : ReactElement | null =&gt; {
  if(condition) {
    return null;
  };

  return &lt;h1&gt;Hello World&lt;/h1&gt;
};</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[CSS 주의점 ]]></title>
            <link>https://velog.io/@winney_77/CSS-%EC%A3%BC%EC%9D%98%EC%A0%90</link>
            <guid>https://velog.io/@winney_77/CSS-%EC%A3%BC%EC%9D%98%EC%A0%90</guid>
            <pubDate>Sun, 04 Apr 2021 08:51:47 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>css를 사용하면서 반복적인 실수를 할 때가 있다. 이번에도 이전에 했던 실수를 또 하게 되었다. 앞으로 이 포스팅에 반복되는 실수(?)들을 하나씩 채워나갈 생각이다. </p>
</blockquote>
<h3 id="1-transform-scale05을-통한-크기-변환">1. transform: scale(0.5)을 통한 크기 변환</h3>
<p>원래 element의 크기가 width: 100px, height: 100px 이라면 <code>transform: scale(0.5)</code>적용 시 width: 50px, height: 50px로 크기가 줄어든다. 여기서 중요한 점은 기존 공간을 유지 한 채 크기가 줄어든다는 것이다!</p>
<p><img src="https://images.velog.io/images/winney_77/post/c90dc45e-568d-48ae-9010-7a54d30ae766/%ED%99%94%EB%A9%B4%20%EC%BA%A1%EC%B2%98%202021-04-04%20174628.png" alt=""></p>
<p>보면 <code>transform : scale(0.5)</code>를 사용한 경우 <code>div</code>안의 글자크기도 함께 줄어들었지만 원본 크기만큼의 공간을 유지한 채 크기가 줄어들었다. 왜냐하면 원본크기는 여전히 <code>width: 100px, height:100px</code>이기 때문</p>
<p>하지만 <code>width, height</code>를 이용해 크기를 줄였을 때는 원본 자체가 50<em>50이 된 것이기 때문에 100</em>100만큼의 공간이 남지 않는다. </p>
<p>이게 왜 중요하냐면 위쪽에 <code>margin-top : 12px</code>을 줄 때 <code>transform: scale(0.5)</code>로 크기 조정을 했을 경우 실제로는 <code>12px + α</code>만큼의 margin이 생겨 생각과는 다른 위치에 element가 있을 것이기 때문</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[useCallback과 useMemo]]></title>
            <link>https://velog.io/@winney_77/useCallback%EA%B3%BC-useMemo</link>
            <guid>https://velog.io/@winney_77/useCallback%EA%B3%BC-useMemo</guid>
            <pubDate>Sun, 28 Mar 2021 10:45:13 GMT</pubDate>
            <description><![CDATA[<p>이전부터 <code>useCallback</code>과 <code>useMemo</code>를 알고 있었지만 최근에 실제로 써보면서 다시 관련 내용을 찾아보는 나를 발견하고 블로그에 간단히 정리해보기로 했다. 
참조 : <a href="https://medium.com/@jan.hesters/usecallback-vs-usememo-c23ad1dc60">https://medium.com/@jan.hesters/usecallback-vs-usememo-c23ad1dc60</a></p>
<h3 id="미리-알아야-하는-단어">미리 알아야 하는 단어</h3>
<ul>
<li>일급 함수(first-class function) : 함수를 다른 변수와 같이 다룰 수 있는 함수를 말한다. 예를 들면 함수를 다른 함수의 인자로 넘길 수 있고 다른 함수로 반환할 수 있다. 당연히 변수에 함수를 할당하는 것도 가능하다. </li>
<li>고차 함수(higher-order function, HOF) : 함수를 인자로 전달 받거나 함수를 결과로 반환하는 함수.</li>
<li>고차 컴포넌트(higher-order component, HOC) : 리액트 컴포넌트를 재사용하기 위한 기술. 컴포넌트를 가져와서 새 컴포넌트를 반환하는 기술이다. </li>
<li>참조 평등(Referential equality) : 참조 평등은 두 객체에 대한 포인터가 동일하다는 것을 의미한다. 즉, 두 객체는 같은 메모리 위치에 포함되어 포인터가 동일한 객체를 참조하는 것을 알 수 있다. (<code>===</code>와 <code>==</code>) </li>
</ul>
<h1 id="1-리액트-공식홈페이지-정의">1. 리액트 공식홈페이지 정의</h1>
<h2 id="1-usecallback">1) useCallback</h2>
<pre><code>const memoizedCallback = useCallback(
  () =&gt; {
    doSomething(a, b);
  },
  [a, b],
);</code></pre><blockquote>
<p>메모이제이션된 콜백을 반환한다. 메모이제이션된 콜백은 콜백의 의존성(dependency)이 변경되었을 때만 변경된다. </p>
</blockquote>
<h2 id="2-usememo">2) useMemo</h2>
<pre><code>const memoizedValue = useMemo(() =&gt; computeExpensiveValue(a,b), [a,b]);</code></pre><blockquote>
<p>메모이제이션된 값을 반환한다. 의존성(dependency)가 변경되었을 때만 메모이제이션된 값을 다시 계산한다. 이를 통해 불필요한 연산을 피한다. 
<code>useMemo</code>로 전달된 함수는 렌더링 중에 실행된다! side effect는 <code>useEffect</code>에서 하는 일이고 <code>useMemo</code>에서 하는 일이 아니다. 
의존성 배열에 아무 것도 없으면 매 랜더링마다 새 값을 계산한다. </p>
</blockquote>
<p><code>useCallback(fn, deps)</code>은 <code>useMemo(() =&gt; fn, deps)</code>와 같다. </p>
<h1 id="2-사전-지식">2. 사전 지식</h1>
<h2 id="1-일급-함수first-function">1) 일급 함수(first-function)</h2>
<p>함수를 다른 변수와 같이 다룰 수 있는 함수를 말한다.</p>
<pre><code>const number = 1;
const greeting = &#39;hello&#39;;
function foo() {
  return &#39;bar&#39;;
}

// 변수에 할당한 함수
const otherFoo = function() {
  return &#39;bar&#39;;
}
// 변수에 할당한 함수(Arrow Function)
const anotherFoo = () =&gt; &#39;bar&#39;;

number;
greeting;
foo();
otherFoo();
anotherFoo();</code></pre><h3 id="함수를-변수에-할당할-수-있으면-어떤-것들을-할-수-있을까">함수를 변수에 할당할 수 있으면 어떤 것들을 할 수 있을까?!</h3>
<ul>
<li><strong>다른 함수의 인자</strong>로 사용하기</li>
<li><strong>함수의 반환값</strong>으로 사용하기 
(함수의 반환 값이 함수가 될 수있기에)</li>
<li>객체의 키 값으로 사용하기</li>
<li><strong>배열의 값</strong>으로 사용하기</li>
<li>Map 객체의 키로 사용하기</li>
</ul>
<h2 id="2-고차-함수-higher-order-function">2) 고차 함수 (Higher-order function)</h2>
<p>함수를 인자로 전달 받거나 함수를 결과로 반환하는 함수.
** 다음의 실행 값이 무엇이 나올지 생각해보자**</p>
<pre><code>const identity = x =&gt; x;
identity(1);
identity(foo); 
identity(foo)();</code></pre><p>** 결과 **</p>
<pre><code>identity(1); // 1
identity(foo); // ƒ foo() {
  return &#39;bar&#39;;
  }
identity(foo)(); // &#39;bar&#39;</code></pre><p><code>identity(foo)</code>가 함수를 <code>return</code>한 부분이 중요하다.
<code>identity(foo)()</code>는 <code>return</code>한 함수를 실행시킨 결과를 반환했다.</p>
<h2 id="3-참조-평등referential-equality">3) 참조 평등(Referential equality)</h2>
<p>참조 평등은 두 객체에 대한 포인터가 동일하다는 것을 의미한다.
** 결과를 예상해보자**</p>
<pre><code>const anotherFoo = () =&gt; &#39;bar&#39;;
function sameFoo() {
  return &#39;bar&#39;;
}
const fooReference = foo;

&#39;hello&#39; === &#39;hello&#39;;
greeting === otherGreeting;

foo === foo;
foo === otherFoo;
foo === anotherFoo;
foo === sameFoo;
foo === fooReference;</code></pre><p><strong>결과</strong></p>
<pre><code>&#39;hello&#39; === &#39;hello&#39;; // true
greeting === otherGreeting; //true

foo === foo; // true
foo === otherFoo; // false
foo === anotherFoo; // false
foo === sameFoo; // false
foo === fooReference; //true</code></pre><p>여기서 눈 여겨봐야 하는 부분은 <code>greeting === otherGreeting; //true</code>와 <code>foo === sameFoo; // false</code>의 결과가 전혀 다른 것이다. 
<code>foo</code>와 <code>smaeFoo</code>는 실제로 같지 않다. 즉, *<em>포인터의 위치가 같지 않다. *</em></p>
<h1 id="3-usecallback과-usememo">3. useCallback과 useMemo</h1>
<p>자, 위의 사전 지식을 열심히 습득했다면 이제 <code>useCallback</code>과 <code>useMemo</code>의 차이를 짐작할 수 있다!!!!
** <code>useCallback</code>과 <code>useMemo</code>가 무엇을 반환하는지 생각해보자**</p>
<pre><code>useCallback(fn, deps)
useMemo(fn, deps)</code></pre><p><strong>결과</strong>
<code>useCallback</code>은 호출되지 않은 함수를 반환
<code>useMemo</code>호출한 함수의 결과를 반환</p>
<p><code>identity(foo);</code>와 <code>identity(foo)();</code>의 결과 차이를 다시 생각해보자!!</p>
<p><strong><code>useCallback</code>과 <code>useMemo</code>의 사용</strong></p>
<pre><code>function foo() {
  return &#39;bar&#39;;
}

CONST memoizedCallback = useCallback( foo, []);
CONST memoizedResult = useMemo( foo, []);</code></pre><p>** 위를 바탕으로 다음의 실행 결과를 예상해보자**</p>
<pre><code>memoizedCallback;
memoizedResult;
memoizedCallback();
memoizedResult();</code></pre><p><strong>결과</strong></p>
<pre><code>memoizedCallback; 
// f foo() {
  return &#39;bar&#39;;
}
memoizedResult; // &#39;bar&#39;
memoizedCallback(); // &#39;bar&#39;
memoizedResult(); // TypeError</code></pre><h1 id="4-실제-리액트에서">4. 실제 리액트에서</h1>
<p>리액트에서 <code>useCallback</code>과 <code>useMemo</code>가 사용되는 모습</p>
<pre><code>function MyComponent({foo, initial}) {
  const memoizedCallback = useCallback(() =&gt; {
    someFunc(foo, bar);
  }, [foo, bar]);

  const memoizedResult = useMemo(() =&gt; someOtherFunc(foo, bar), [foo, bar]);
  // 등등
}</code></pre><ul>
<li><code>useCallback</code>은 deps를 사용하는 함수를 호출하는 inline callback을 사용한다. </li>
<li><code>useMemo</code>은 일부 함수를 호출하고 그 결과를 반환하는 &quot;create function&quot;을 사용한다. <h2 id="1-잘-못-사용된-usecallback">1) 잘 못 사용된 useCallback!!</h2>
</li>
<li><ul>
<li>왜 다음은 잘 못 되었을까?**<pre><code>function sum(a, b) {
console.log(&#39;sum() ran&#39;);
return a + b;
}
</code></pre></li>
</ul>
</li>
</ul>
<p>function App() {
  const [val1, setVal1] = useState(0);
  const [val2, setVal2] = useState(0);
  const [name, setName] = useState(&#39;Jim&#39;);</p>
<p>  const result = useCallback(sum(val1, val2), [val1, val2]);</p>
<p>  return (
    <div className="App">
      &lt;input
        value={val1}
        onChange={({ target }) =&gt;
          setVal1(parseInt(target.value || 0, 10))
        }
      /&gt;
      &lt;input
        value={val2}
        onChange={({ target }) =&gt;
          setVal2(parseInt(target.value || 0, 10))
        }
      /&gt;
      &lt;input
        placeholder=&quot;Name&quot;
        value={name}
        onChange={({ target }) =&gt; setName(target.value)}
      /&gt;
      <p>{result}</p>
    </div>
  );
}</p>
<pre><code>**힌트 : ```useCallback```은 함수를 반환하지 값을 반환하지 않는다**

**답**
 : ```useCallback```는 값의 메모이제이션에 사용할 수 없다. 즉. ```useCallback(fn(), [deps])```로는 사용 불가

 ## 2) 앗, 나의 실수는?</code></pre><p> import React, { useEffect, useState } from &#39;react&#39;;
import ListItem from &#39;@material-ui/core/ListItem&#39;;
import ListItemText from &#39;@material-ui/core/ListItemText&#39;;</p>
<p>function User({ userId }) {
  const [user, setUser] = useState({ name: &#39;&#39;, email: &#39;&#39; });</p>
<p>  const fetchUser = async () =&gt; {
    const res = await fetch(
      <code>https://jsonplaceholder.typicode.com/users/${userId}</code>
    );
    const newUser = await res.json();
    setUser(newUser);
  };</p>
<p>  useEffect(() =&gt; {
    fetchUser();
  }, []);
  return (
    <ListItem dense divider>
      <ListItemText primary={user.name} secondary={user.email} />
    </ListItem>
  );
}</p>
<p>export default User;</p>
<pre><code> 해당 컴포넌트를 실행시킨다면 Infinity Loop를 확인 할 수 있다. 
 **클로저** 때문...!
</code></pre><p> const fetchUser = async () =&gt; {
  const res = await fetch(
    <code>https://jsonplaceholder.typicode.com/users/${userId}</code>
  );
  const newUser = await res.json();
  setUser(newUser); // 🔴 setState triggers re-render
};</p>
<p>useEffect(() =&gt; {
  fetchUser();
}, [fetchUser]); // fetchUser is a new function on every render</p>
<pre><code> ```setState```가 계속 랜더링이 되도록 만든다. 
 그럼 해결책은 어떤 것이 있을까?

 ### (1) 클로저 해결 
 : ```useEffect```내로 ```fetchUser``` 함수를 이동시켜 클로저 문제를 해결</code></pre><p> // 1. Way to solve the infinite loop
useEffect(() =&gt; {
  const fetchUser = async () =&gt; {
    const res = await fetch(
      <code>https://jsonplaceholder.typicode.com/users/${userId}</code>
    );
    const newUser = await res.json();
    setUser(newUser); // Triggers re-render, but ...
  };</p>
<p>  fetchUser();
}, [userId]); // ✅ ... userId stays the same.</p>
<pre><code>
 ### (2) useCallback 사용!
 : ```userId```가 바뀌면 ```fetchUser```가 호출된다.  </code></pre><p> // 2. Way to solve the infinite loop
const fetchUser = useCallback(async () =&gt; {
  const res = await fetch(
    <code>https://jsonplaceholder.typicode.com/users/${userId}</code>
  );
  const newUser = await res.json();
  setUser(newUser);
}, [userId]);</p>
<p>useEffect(() =&gt; {
  fetchUser();
}, [fetchUser]); // ✅ fetchUser stays the same between renders</p>
<pre><code>
 ## 3) 비효율적인 함수를 어떻게 바꿀까?
 기능에는 문제가 없지만 랜더링 될 때마다 실행되는 함수... 어떻게 할까?</code></pre><p> // Some FP magic 🧙🏼‍♂️
const filter = (f, arr) =&gt; arr.filter(f);
const prop = key =&gt; obj =&gt; obj[key];
const getName = prop(&#39;name&#39;);
const strIncludes = query =&gt; str =&gt; str.includes(query);
const toLower = str =&gt; str.toLowerCase();
const pipe = (...fns) =&gt; x =&gt; fns.reduce((y, f) =&gt; f(y), x);
const nameIncludes = query =&gt;
  pipe(
    getName,
    toLower,
    strIncludes(toLower(query))
  );</p>
<p>function UserList({ query, users }) {
  // 🔴 Recalculated on every render
  const filteredUsers = filter(nameIncludes(query), users);
  // ...
}</p>
<pre><code> ### 해결!
 : ```query```와 ```users```가 변경 되지 않으면 ```filteredUser``` 호출 없이 기존 값을 가져오도록!</code></pre><p> function UserList({query, users}) {
   // ✅ Recalculated when query or users change
   const filteredUsesr = useMemo(
   () =&gt; filter(nameIncludes(query), users),
   [query, users]
   );
 };</p>
<pre><code></code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[OG는 뭘까]]></title>
            <link>https://velog.io/@winney_77/OG%EB%8A%94-%EB%AD%98%EA%B9%8C</link>
            <guid>https://velog.io/@winney_77/OG%EB%8A%94-%EB%AD%98%EA%B9%8C</guid>
            <pubDate>Sun, 21 Mar 2021 08:31:12 GMT</pubDate>
            <description><![CDATA[<ul>
<li>링크 미리보기 제목, 설명, 이미지 결정하는 오픈 그래프 태그!</li>
<li>페이스북, 네이버, 카카오톡 등 어떤 링크에 대한 미리보기 제공 → 어떻게?! 오픈 그래프 프로토콜로!</li>
<li>사용자 클릭 전에 미리 해당 웹사이트를 크롤러가 방문, HTML head의 메타 데이터 크롤링하여 미리보기 화면 생성</li>
<li>주요 html meto 태그 : title, description, image</li>
</ul>
<pre><code class="language-jsx">&lt;html&gt;
  &lt;head&gt;
      &lt;meta property=&quot;og-title&quot; content=&quot;뿌린만큼 거두리라 다운받기&quot;&gt;
      &lt;meta property=&quot;og-description&quot; content=&quot;뿌린만큼 거두리라 &lt;br&gt; 가장쉽고 (중략)&quot;&gt;
      &lt;meta property=&quot;og-image&quot; content=&quot;http://lh3.googleusercontent.com/-v-...&quot;&gt;
  &lt;/head&gt;
&lt;/html&gt;</code></pre>
<ul>
<li>구체적 작동 원리<ol>
<li>사용자가 링크를 입력창에 입력</li>
<li>페이스북, 네이버 블로그, 카카오톡 입력창의 문자열이 &#39;link&#39;임을 파악(보통 정규표현식으로 해당 문자열이 링크라는 것을 알아냄)</li>
<li>&#39;link&#39;라는 것이 파악되면 페이스북, 네이버 블로그, 카카오톡의 크롤러는 미리 그 웹 사이트를 방문해 HTML head의 오픈 그래프(Open Graph) 메타 데이터 긁어옴</li>
<li>이 중 og:title, og:description, og:image가 각각 제목, 설명 ,이미지 정보를 나타낸다. </li>
<li>그 정보를 바탕으로 미리보기 화면을 생성한다. </li>
</ol>
</li>
<li>but, 캐시 저장 부분이 있다면 정보를 변경하더라도 캐시로 저장된 부분으로 인해 변경전 정보가 나올 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스]]></title>
            <link>https://velog.io/@winney_77/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</link>
            <guid>https://velog.io/@winney_77/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</guid>
            <pubDate>Wed, 10 Mar 2021 14:37:23 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>정말 오랜만에 프로그래머스를 풀었다. 마지막 블로그 이후 띄엄띄엄하다가 어느순간 안 풀었는데 계속 신경이 쓰여서 오늘!!! 완전 각 잡고 다시 풀어보았다.</p>
</blockquote>
<h1 id="완주하지-못-한-선수">완주하지 못 한 선수</h1>
<p><strong>문제 설명</strong>
수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.</p>
<p>마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.</p>
<p><strong>제한사항</strong></p>
<ul>
<li>마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다.</li>
<li>completion의 길이는 participant의 길이보다 1 작습니다.</li>
<li>참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다.</li>
<li>참가자 중에는 동명이인이 있을 수 있습니다.</li>
</ul>
<p><strong>입출력 예시</strong>는 밑의 링크에서 확인!!</p>
<p>출처: <a href="https://programmers.co.kr/learn/courses/30/lessons/42576">https://programmers.co.kr/learn/courses/30/lessons/42576</a></p>
<h2 id="첫번째-작성">첫번째 작성</h2>
<pre><code>function solution(participant, completion) {
  const participants = {};

  for(let key of participant) {
    if(!participants[key]) {
      participants[key] = 1;
    } else if(participants[key]) {
      participants[key] += 1
    }
  };

  for(let key of completion) {
    if(participants[key]) {
      participants[key] -= 1;
    }
  }

  for(let person in participants) {
    if(participants[person] &gt; 0) {
      return person;
    }
  }
};</code></pre><p>생각의 흐름으로 작성한 풀이이다. 문제만 읽고 어떻게 풀어야할지 전혀 감을 못 잡다가 프로그래머스에 해시 키워드로 문제가 되어 있어서 <code>Object[key] = value</code>만 생각하고 풀었다. 
문제는 해결했지만 다른 사람들 풀이를 보니 유난히 문제 풀이 방법이 길어보이고 특히 <code>for...in</code>이 반복문으로 쓰는 것을 권장하지 않는다는 댓글을 보고 다시 작성해보았다. </p>
<h2 id="두번째-작성">두번째 작성</h2>
<pre><code>function solution(participant, completion) {
   participant.sort()
   completion.sort()

  for(let i = 0; i &lt; participant.length; i++) {
    if(participant[i] !== completion[i]) {
      return participant.slice(i, i+1)[0]
    }
  }
};</code></pre><p>아주 많이 줄어들었다. 일단 <code>sort()</code>를 쓰는 것은 옛날에 이 문제를 봤을 때 생각하고 지나갔었는데 이번에 다른 사람 풀이를 보면서 기억이 나서 썼다. 
그리고 <code>for...in</code>문을 사용하지 않았다! 댓글대로 <code>for...in</code>문을 사용하지 않으니 70ms -&gt; 50ms로 속도가 줄었다. 
하지만 정렬된 참가자와 완주자의 각 위치를 비교해서 완주하지 못 한 사람만 잘라내다 보니 결과가 배열로 나왔다. 이렇게 <code>[&#39;leo&#39;]</code>!!
하지만 문제에서 요구한 결과 타입은 string으로 한 명만 결과로 도출되도록 되어있었다. 그래서 index <code>[0]</code>을 마지막에 적어뒀지만 뭔가 하드코딩같아보여서 별로이다. </p>
<h2 id="다른-사람-풀이">다른 사람 풀이</h2>
<pre><code>function solution(participant, completion) {
    participant.sort();
    completion.sort();

    for(let i in participant) {
        if(completion.includes(participant[i]) == false) 
        return participant[i];

        completion.splice(completion.indexOf(participant[i]), 1);
    };
};</code></pre><p>다른 분 풀이에서 주석처리한 부분만을 가져왔다. 왜냐하면 그 분이 주석처리 하지 않은 방법에는 <code>for...in</code>문이 사용되었기 때문이다.
나는 <code>slice</code>를 사용했지만 여기에는 <code>splice</code>가 사용되었다. 차이는 새 배열을 반환하느냐 여부이다. 
그리고 이번에 <code>splice</code>가 속도가 느린 메서드라는 사실을 알았다. 유일하게 시간초과로 통과하지 못 했는데 제출 당시와 현재의 프로그래머스가 다르기 때문이 아닐까 싶다. 앞으로 가급적이면 <code>slice</code>를 쓰는 방향이 좋다는 것을 알았다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[제너레이터(Generator)]]></title>
            <link>https://velog.io/@winney_77/%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0Generator</link>
            <guid>https://velog.io/@winney_77/%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0Generator</guid>
            <pubDate>Sun, 07 Mar 2021 04:54:37 GMT</pubDate>
            <description><![CDATA[<p>❓ redux-saga를 익히고 있는 도중 generator에 대해서 반드시 이해하고 넘어가야 할 것같아서 공부하고 있다. 
블로그에 간단히 정리하며 마무리 지을 생각이다. </p>
<blockquote>
<h2 id="generator란">Generator란?</h2>
<p>비동기 작업을 동기적으로 표현하기 위한 방법 중 하나이다. 
그 외 Promise, async/await가 있다. </p>
</blockquote>
<h1 id="1-제너레이터는-어떻게-작성할까">1. 제너레이터는 어떻게 작성할까?</h1>
<ul>
<li><code>function*</code>과 같이 <code>*</code>를 <code>function</code> 뒤에 붙이면 제너레이터가 된다. </li>
<li>제너레이터 내부에 <code>yield</code>를 입력하면 제너레이터를 중지 및 재개 할 수 있다.</li>
<li><code>next</code>를 통해 제너레이터를 실행할 수 있다. <pre><code>function* sayHello() {
console.log(&#39;제너레이터 시작&#39;)
yield &#39;안녕&#39;;
console.log(&#39;첫번째 yield의 비동기 작업 끝낸 후 실행&#39;);
yield &#39;나는 Winney야&#39;
console.log(&#39;두번째 yield의 비동기 작업 끝낸 후 실행&#39;);
yield &#39;앞으로 잘 지내자&#39;
console.log(&#39;제너레이터 끝&#39;);
};
</code></pre></li>
</ul>
<p>const gen = sayHello();</p>
<p>gen.next(); // 1번
gen.next(); // 2번
gen.next(); // 3번
gen.next(); // 4번</p>
<pre><code>
# 2. 제너레이터의 실행은 어떻게 될까?
작성 방법을 알았으니 제너레이터가 어떻게 실행되는지 파악해야 할 차례이다. 
다음은 위의 예시를 실행한 결과이다.</code></pre><p>// 1번 gen.next() 실행
&#39;제너레이터 시작&#39;
{ value: &#39;안녕&#39;, done: false }</p>
<p>// 2번 gen.next() 실행
&#39;첫번째 yield의 비동기 작업(안녕) 끝낸 후 실행&#39;
{ value: &#39;나는 Winney야&#39;, done: false }</p>
<p>// 3번 gen.next() 실행
&#39;두번째 yield의 비동기 작업(나는 Winney야) 끝낸 후 실행&#39;
{ value: &#39;앞으로 잘 지내자&#39;, done: false }</p>
<p>// 4번 gen.next() 실행
&#39;제너레이터 끝&#39;
{ value: undefined, done: true }</p>
<pre><code>여기서 중요한 부분은 ```next```를 이용해서 제너레이터를 작성했을 때 해당 제너레이터의 실행은 **```yield```작성한 부분에서 멈춘다**는 것이다. 

이후 다시 ```next```로 제너레이터를 실행했을 때 이전 ```yield```의 다음 줄에서부터 실행되어 그 다음 ```yield``에서 제너레이터가 멈추는 것은 반복한다는 것이다. 

즉, 위에서 말한 **```yield```를 입력하면 제너레이터를 중지 및 재개 할 수 있다.**는 의미의 ```yield```는 코드가 어딘가에서 멈춰서 비동기작업을 하고 해당 작업이 끝나면 다시 제너레이터가 실행 될 수 있게 하는 키워드라는 의미이다. 

그리고 위의 실행 결과를 통해 ```yield```는 객체형태로 ```value```와 ```done```을 반환하는 것을 알 수 있다. 

- ```value``` : ```yield```실행 결과의 반환 값
- ```done```: 제너레이터가 완전히 종료되었는지를 확인하는 값

때문에 4번째 ```gen.next()```의 ```yield``` 반환값을 확인하면 ```{ value: undefined, done: true }```를 확인 할 수 있다. 

이전 3번째 ```yield```가 마지막으로 실행되며 멈춘 다음 줄에서 4번째 ```gen.next()```가 실행되므로 ``` console.log(&#39;제너레이터 끝&#39;);```가 실행된 후 제너레이터가 끝난다. 
그렇기에 ```yield```가 없어서 반환값이 없으므로 ```value```는 ```undefined```가 나오고 제너레이터는 완전히 종료되었으므로 ```done```은 ```true```가 된다. 

# 3. 제너레이터로 어떤 것들을 표현 할 수 있을까?
제너레이터는 기본적으로 비동기 작업을 동기적으로 표현하므로서 가독성있게 표현하기 위한 것이다. (하지만 난 아무리 봐도 동기적으로 보인다... 물론 비동기 작업이 있다는 것을 알지만.. 😂)
## 제너레이터로 표현 할 수 있는 것
- API 호출 : 대표적인 비동기 작업!
- 자연수 표현하기
: 개인적으로 자연수 표현한 제너레이터를 보고 나도 모르게 내가 제너레이터를 함수처럼 생각하고 있었던 문제를 알 수있었다!</code></pre><p>function* countNaturalNum() {
  let num = 0;
  while(true) {
    num += 1
    yield num;
  }
}</p>
<p>const gen = countNaturalNum()
gen.next(); // { value: 1, done: false }
gen.next(); // { value: 2, done: false }
gen.next(); // { value: 3, done: false }
gen.next(); // { value: 4, done: false }</p>
<pre><code>만약에 함수였다면 무한루프를 돌았을 것이지만 제너레이터를 사용하면서 자연수를 표현할 수 있게 되었다. 

# 4. next에 인자를 넣으면 어떻게 될까?
&gt;❗ **예시와 결과가 나오는데 예시만 보고 꼭 결과를 예측해볼 것**
- ```next```의 문법 : ```gen.next(value)```
- ```next```에는 매개변수가 있고 ```value```는 제너레이터에 전달된다. 

그리고 이미 배웠다시피 ```next```는 ```value```와 ```done``` 프로퍼티를 가진 객체를 반환한다.

## 1번 예시</code></pre><p>function* getArg() {
  while(true) {
    let value = yield null;
    console.log(value);
  }
}</p>
<p>const gen = getArg()
gen.next(1); // 1번
gen.next(2); // 2번</p>
<pre><code>## 1번 예시의 결과는 어떻게 나올까?</code></pre><p>// 1번
{ value: null, done: false }</p>
<p>// 2번
2
{ value: null, done: false }</p>
<pre><code>- 1번의 경우 : ```yield null```에서 멈추었기 때문에 ```yield```의 결과인 ```null```이 ```value: null```로 나타났다. 
- 2번의 경우 : 첫번째 ```yield``` 다음 줄부터 실행되기 때문에 ```console.log(value)```가 실행된다. 당연히 ```next(2)```에서 ```2```가 인자로 들어갔기 때문에 ```2```가 출력되고 while반복문이기에 다시 돌아가서 ```yield null```이 실행되어 ```value: null```가 나타난다. 

## 2번 예시</code></pre><p>function* getArg() {
  returnedYield = yield &#39;foo&#39;;
  yield returnedYield;
}</p>
<p>const gen = getArg()
gen.next(1); // 1번
gen.next(2); // 2번</p>
<pre><code>## 2번 예시의 결과는 어떻게 나올까?</code></pre><p>// 1번
{ value: &#39;foo&#39;, done: false }</p>
<p>// 2번
{ value: 2, done: false }</p>
<p>```
제너레이터를 익히며 제일 어려웠던 부분이다!!</p>
<blockquote>
<p>💥 <strong>중요</strong>
<strong>분명 <code>gen.next(1)</code>에서 1을 전달했는데 왜 <code>value</code>는 <code>&#39;foo&#39;</code>로 나올까?</strong>
<strong><code>returnedYield</code>는 어디로 갔나?</strong></p>
</blockquote>
<ul>
<li>mdn <code>yield</code> 문법 : <code>[rv] = yield [expression];</code>
여기서 중요한 부분은 <code>[expression]</code>이다. 우리가 알아야 할 것은 <code>next(value)</code>에서 저 <code>value</code> 매개변수가 <code>yield</code>에게 전달되고 그 자리가 <code>[expression]</code> 자리라는 것이다. (<code>yield</code>오른쪽)
때문에 <code>gen.next(1);</code>를 통해서 <code>1</code>을 <code>yield &#39;foo&#39;</code>에 전달하므로서 <code>yield 1</code>되었다. </li>
<li><em>하지만 <code>yield 1</code>이 <code>returnedYield</code>에 전달되는 것은 다음 <code>yield</code>가 실행될 때이다. *</em>
그렇기에 1번 결과에서 우리는 <code>value: &#39;foo&#39;</code>를 확인 할 수 있고 2번결과에서는 이미 <code>next(2)</code>를 통해 <code>yield</code>가 <code>2</code>를 <code>value</code>로 가진 상황에서 <code>returnedYield</code>를 반환하게 되므로 <code>{ value: 2, done: false }</code>과 같은 결과가 나온 것이다. </li>
</ul>
<p>참조 StackOverFlow : <a href="https://stackoverflow.com/questions/37354461/how-does-generator-next-processes-its-parameter">https://stackoverflow.com/questions/37354461/how-does-generator-next-processes-its-parameter</a></p>
<p>개인적으로 <code>next</code>에 인자를 전달한 값을 예측하는게 제일 어려운 부분이었다. 
<code>iterator</code>와 <code>iterable</code>에 관해서도 작성하고 싶지만 다음에 전반적으로 다루어 보도록 하고 제너레이터에 관한 내용을 마무리한다,</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Typescript 2. Operator]]></title>
            <link>https://velog.io/@winney_77/Typescript-2.-Operator</link>
            <guid>https://velog.io/@winney_77/Typescript-2.-Operator</guid>
            <pubDate>Sun, 28 Feb 2021 10:36:02 GMT</pubDate>
            <description><![CDATA[<h1 id="5-type이-두-가지-이상일-때는-어떻게-type-지정을-할까">5. type이 두 가지 이상일 때는 어떻게 type 지정을 할까?</h1>
<h2 id="유니온-타입union-type">유니온 타입(Union Type)</h2>
<p> : 복수의 타입을 쓸 수 있게 한다. JS의 OR 연산자의 역할과 같다. (||)</p>
<pre><code>let address: string | number;
function writeTitle(title : string | number) {
  console.log(title);
};

writeTitle(&#39;Winney Log&#39;);
writeTitle(100);</code></pre><h1 id="6-유니온-타입-대신-any를-쓸-수도-있지-않을까">6. 유니온 타입 대신 any를 쓸 수도 있지 않을까?</h1>
<p>: 유니온 타입을 사용하면 타입 가드가 되어서 해당 타입을 추론해주고 이해 맞는 API를 자동완성 해주기 때문에 에러발생을 줄일 수 있다!!</p>
<pre><code>function writeTitle(title: string | number) {
  // if문을 통해 타입 가드
  if(typeof title === &#39;string&#39;) {
    title.toUpperCase() // 문자열 API 자동완성
  }
  if(typeof title === &#39;number&#39;) {
    title.toString() // 숫자 API 자동완성
  }
  throw new TypeError(&#39;Title must be string or number&#39;);
}</code></pre><h1 id="7-유니온-타입이--라면-도-있나">7. 유니온 타입이 | 라면 &amp;도 있나?</h1>
<h2 id="인터섹션-타입intersection-type">인터섹션 타입(Intersection Type)</h2>
<p> : 여러 타입을 모두 만족하는 하나의 타입. &amp; 사용.</p>
<pre><code>interface Person {
  name: string;
  age: number;
}

interface Developer {
  name: string;
  skill: string;
}

function askSomeone(someone: Person &amp; Developer) {
  console.log(someone.name); 
  console.log(someone.age);
  console.log(someone.skill);
};

const whoAmI = {
  name: &#39;winney&#39;,
  age: 10,
  skill: &#39;typescript&#39;
};

askSomeone(whoAmI); // 정상
askSomeone({name:&#39;winney&#39;, age:10, skill:&#39;typescript&#39;}); // 정상</code></pre><h1 id="8-유니온-타입과-인터섹션-타입을-쓸-때-꼭-알아야-하는-건-뭐가-있을까">8. 유니온 타입과 인터섹션 타입을 쓸 때 꼭 알아야 하는 건 뭐가 있을까?</h1>
<p>: 각각의 타입을 typescript가 어떻게 추론하는지 알아야한다!!</p>
<h2 id="유니온-타입과-인터섹션-타입의-차이">유니온 타입과 인터섹션 타입의 차이</h2>
<pre><code>interface Person {
  name: string;
  age: number;
}

interface Developer {
  name: string;
  skill: string;
}

function askSomeone1(someone: Person | Developer) {
  console.log(someone.name); 
  console.log(someone.age);  // 에러
  console.log(someone.skill); // 에러
};

function askSomeone2(someone: Person &amp; Developer) {
  console.log(someone.name); 
  console.log(someone.age);
  console.log(someone.skill);
};</code></pre><p>❗ 에러가 난다는 것 === typescript가 API 자동완성을 안 해준다는 것
=&gt; typescript가 타입 추론을 못 한다.</p>
<p><code>askSomeone1</code>과 <code>askSomeone2</code>의 차이에서 알 수 있는 것</p>
<ul>
<li>유니온 타입은 공통된 property에 대해서만 type 보장을 한다.
=&gt; <code>Person</code>과 <code>Developer</code>의 공통 property는 <code>name</code>이기 때문에 <code>age</code>과 <code>skill</code>은 에러</li>
<li>인터섹션 타입은 모든 property를 보장한다. </li>
</ul>
<h1 id="9-유니온-타입에서-공통된-속성-외에-사용하고-싶은-속성은-어떻게-적용할까">9. 유니온 타입에서 공통된 속성 외에 사용하고 싶은 속성은 어떻게 적용할까?</h1>
<p>: 타입 가드 사용!!</p>
<pre><code>// 타입 가드
function isDeveloper(someone: Person | Developer): someone is Developer{
  return (someone as Developer).skill !== undefined;
}

function askSomeone(someone: Person | Developer) {
  console.log(someone.name);
  if(isDeveloper(someone)) {
    console.log(someone.skill); // 타입이 Deeveloper이면 skill 사용가능
  } else {
    console.log(someone.age) // 타입이 Person이면 age 사용가능
  }
};

askSomeone({name:&#39;winney&#39;, age: 10});
askSomeone({name:&#39;winney&#39;, skill:&#39;typescript&#39;})</code></pre><p>타입 가드를 사용해서 <code>askSomeone</code> 실행 시 에러없이 사용가능하다. 
<code>askSomeone</code>실행 시 각 타입에 맞는 값들을 넣으면 알아서 타입에 맞게 실행된다.</p>
<p>더해서 </p>
<pre><code>askSomeone({name:&#39;winney&#39;, age:10, skill:&#39;typescript&#39;});</code></pre><p>당연하지만 의 예시를 실행 할 시 <code>name</code>과 <code>skill</code>만 console에 출력된다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Typescript 1. 타입]]></title>
            <link>https://velog.io/@winney_77/Typescript-1.-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@winney_77/Typescript-1.-%ED%83%80%EC%9E%85</guid>
            <pubDate>Sun, 07 Feb 2021 10:29:21 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>🌈 최근 타입스크립트를 익히고 있다. 
과거 프로젝트를 하며 타입 때문에 고생했던 적이 있어서 타입을 지정해준다는 것만으로도 굉장한 매력을 느끼고 있고 개인적으로 JS보다 재미있다. 물론 처음 배우는 거라 그럴 수도 있지만 typescript를 재밌다고 느끼는게 중요하지 않을까?! 하나씩 정리해보고자 한다.</p>
</blockquote>
<h1 id="1-왜-타입스크립트를-쓸까">1. 왜 타입스크립트를 쓸까?</h1>
<p>제일 중요한 부분이라고 생각한다. 왜 쓰는가?</p>
<ol>
<li>정적 타입 지원으로 컴파일 단계에서 오류를 확인 할 수 있다.</li>
<li>IDE와 같은 도구의 지원을 받을 수 있다.</li>
<li>interface, generic을 통해 OOP 지원을 받을 수 있다.</li>
<li>ESNext를 지원한다. </li>
</ol>
<h1 id="2-어떤-타입들이-있을까">2. 어떤 타입들이 있을까?</h1>
<p>먼저 기본타입만 확인해보자.</p>
<ul>
<li>string : <code>let animal: string = &#39;dog&#39;;</code></li>
<li>number : <code>let ten: number = 10;</code></li>
<li>array 
: <code>let fruit: Array&lt;string&gt; = [&#39;banana&#39;, &#39;apple&#39;];</code>
: <code>let fruit: string[] = [&#39;banana&#39;, &#39;apple&#39;];</code></li>
<li>tuple : <code>let address: [string, number] = [&#39;seoul&#39;, 20]</code></li>
<li>object : <pre><code>let person: {name: string, age:number} = {
  name: &#39;winney&#39;, 
  age: 10,
  };</code></pre></li>
<li>boolean : <code>let open: boolean = true;</code></li>
</ul>
<p>추가적인 타입은 나중에 작성할 예정!</p>
<h1 id="3-함수는-어떻게-타입을-지정할까">3. 함수는 어떻게 타입을 지정할까?</h1>
<h2 id="1-인자와-반환값-모두-지정">1) 인자와 반환값 모두 지정</h2>
<pre><code>let sum = (a: number, b: number) : number =&gt; {
    return a + b;
}</code></pre><p>반드시 인자가 2개 있어야한다. </p>
<h2 id="2-optional-parameter">2) Optional parameter</h2>
<pre><code>let sum = (a: number, b?: number) : number =&gt; {
    return a + b;
}</code></pre><p>인자 뒤에 ?를 붙여서 인자가 없어도 에러가 나지 않게 할 수 있다. 
❗ optional parameter는 반드시 뒤에 위치해 있어야 한다. 
다음과 같은 경우 ts에서 인식하지 못 한다.</p>
<pre><code>let sum = (a?: number, b: number) : number =&gt; {
    return a + b;
}</code></pre><h1 id="4-객체-property-지정을-더-현명하게-할-수-없을까">4. 객체 property 지정을 더 현명하게 할 수 없을까?</h1>
<ul>
<li>interface를 이용하면 객체 property를 여기저기 중복없이 지정할 수 있다.<pre><code>interface Person {
  name: string;
  age: number;
}
</code></pre></li>
</ul>
<p>let winney: Person = {
    name: &#39;winney&#39;,
    age: 10,
}</p>
<p>let printUser = (user: Person) =&gt; {
    console.log(user)
}</p>
<pre><code>interface 사용으로 다양한 곳에 객체의 타입을 편하게 지정 할 수 있다.</code></pre><p>interface Developer extends Person {
    skill: string
}</p>
<p>let winney: Developer = {
    name: &#39;winney&#39;,
    age: 10,
    skill: &#39;ts&#39;
}</p>
<pre><code>- interface는 확장이 가능하다 =&gt; OOP

추가로 타입 별칭이라는 부분이 있다. </code></pre><p>type Person = {
 name: string;
 age: number;
}</p>
<p>```
형태는 interface와 비슷하다.
하지만 interface와 달리 확장이 되지 않고 preview가 interface와는 다르게 보인다. </p>
<p>대부분의 경우 interface를 많이 사용한다. 하지만 어떤 걸 사용하든 일괄적으로 사용하도록 해야한다. </p>
<p>출처 </p>
<ul>
<li>타입스크립트-입문 강의</li>
<li><a href="http://typescriptlang.org/">http://typescriptlang.org/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 68 day 프로그래머스]]></title>
            <link>https://velog.io/@winney_77/TIL-68-day-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-emjp7fny</link>
            <guid>https://velog.io/@winney_77/TIL-68-day-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-emjp7fny</guid>
            <pubDate>Mon, 25 Jan 2021 03:13:33 GMT</pubDate>
            <description><![CDATA[<p>1937년 Collatz란 사람에 의해 제기된 이 추측은, 주어진 수가 1이 될때까지 다음 작업을 반복하면, 모든 수를 1로 만들 수 있다는 추측입니다. 작업은 다음과 같습니다.</p>
<blockquote>
<p>1-1. 입력된 수가 짝수라면 2로 나눕니다. 
1-2. 입력된 수가 홀수라면 3을 곱하고 1을 더합니다.
2. 결과로 나온 수에 같은 작업을 1이 될 때까지 반복합니다.</p>
</blockquote>
<p>예를 들어, 입력된 수가 6이라면 6→3→10→5→16→8→4→2→1 이 되어 총 8번 만에 1이 됩니다. 위 작업을 몇 번이나 반복해야하는지 반환하는 함수, solution을 완성해 주세요. 단, 작업을 500번을 반복해도 1이 되지 않는다면 –1을 반환해 주세요.</p>
<ul>
<li>입력된 수, num은 1 이상 8000000 미만인 정수입니다.</li>
<li>입출력 예시 :
n =&gt; result
6 =&gt; 8
16 =&gt; 4
626331 =&gt; -1 (508회 나옴)</li>
</ul>
<h2 id="작성">작성</h2>
<pre><code>function solution(num) {
  let count = 0;
  if(num === 1) return count;

  while(num !== 1) {
    if(num % 2 === 0) {
      count++
      num=num /2
      if(num === 1) return count;
    } else if(num % 2 !== 0) {
      count++
      num = num*3+1
      if(num===1) return count;
    }
  if(count &gt;= 500)return -1
  }  
}</code></pre><p>반복을 몇 번 하게 될지 모르므로 while문을 사용했다.
처음에 조건으로 <code>while(num===1)</code> 이라고 작성하는 바람에 계속 실행이 되지 않았는데 나중에서야 알게되어 수정했다. 
그리고 <code>if(num === 1) return count;</code>이 부분도 어디에 추가해야할지 헤매다가 같이 문제푸는 분의 도움을 받아 추가되었다.
여전히 한 줄 한 줄 뜯어보는 부분이 부족하다고 느껴진다. </p>
<h2 id="다른-사람-풀이">다른 사람 풀이</h2>
<pre><code>function solution(num) {
  let count = 0;
  while(num !== 1 &amp;&amp; count &lt;500) {
    num % 2 === 0 ? num = num/2 : num = num *3 +1;
    count++
  }
  return num === 1 ? count : -1;
}</code></pre><p>가장 마음에 들었던 풀이이다. 
풀이 과정이 짧은 분들은 더 있었지만 개인적으로 가독성을 제일 우선으로 코드를 작성해야한다고 생각하고 그런 면에서 짧다고 가독성이 좋다고 생각하지는 않기 때문에 제일 마음에 들었다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 68 day 프로그래머스]]></title>
            <link>https://velog.io/@winney_77/TIL-68-day-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</link>
            <guid>https://velog.io/@winney_77/TIL-68-day-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</guid>
            <pubDate>Wed, 20 Jan 2021 04:15:11 GMT</pubDate>
            <description><![CDATA[<h1 id="2016년">2016년</h1>
<p>2016년 1월 1일은 금요일입니다. 2016년 a월 b일은 무슨 요일일까요? 두 수 a ,b를 입력받아 2016년 a월 b일이 무슨 요일인지 리턴하는 함수, solution을 완성하세요. 요일의 이름은 일요일부터 토요일까지 각각 SUN,MON,TUE,WED,THU,FRI,SAT</p>
<p>입니다. 예를 들어 a=5, b=24라면 5월 24일은 화요일이므로 문자열 TUE를 반환하세요.</p>
<ul>
<li>2016년은 윤년입니다.</li>
<li>2016년 a월 b일은 실제로 있는 날입니다. (13월 26일이나 2월 45일같은 날짜는 주어지지 않습니다)</li>
<li>입출력 예시 
: a, b =&gt; return
: 5, 24  =&gt; TUE</li>
</ul>
<h2 id="작성-코드">작성 코드</h2>
<pre><code>function solution(a, b) {
    var answer = &#39;&#39;;
  const days = [&#39;FRI&#39;,&#39;SAT&#39;,&#39;SUN&#39;,&#39;MON&#39;,&#39;TUE&#39;,&#39;WED&#39;,&#39;THU&#39;];
  const monthDates=[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];


  let date = 0;
  for(let i = 0; i &lt; a-1; i++) {
    date += monthDates[i];
  }

  let number = (b + date) % 7;
  if(number === 0) {
    return days[6];
  }
    return days[number-1];
}</code></pre><p>처음 문제를 봤을 때 2월 29일, 30일, 31일로 월을 나눠서 생각했다가 7, 8월에 연속으로 31일이 나오기 때문에 처음 생각 포기했다. </p>
<p>그 후로 아무 생각이 안 나다가 그냥 모든 날짜를 더해서 나머지로 요일을 확인하면 되지 않을까? 하고 작성하게 된 코드이다. 
처음 작성 했을 때는 if문이 없었기 때문에 나머지가 0일 경우 days의 맨 마지막에 있는 &#39;THU&#39;를 반환하지 못 했기에 if를 추가 했다. </p>
<p>다른 분들 풀이를 보니 new Date를 사용한 풀이가 있었댜. 생각지도 못 한 방법이라 굉장히 신선했다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 67 day 프로그래머스]]></title>
            <link>https://velog.io/@winney_77/TIL-67-day-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</link>
            <guid>https://velog.io/@winney_77/TIL-67-day-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</guid>
            <pubDate>Tue, 19 Jan 2021 06:11:50 GMT</pubDate>
            <description><![CDATA[<h1 id="체육복">체육복</h1>
<p>점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 4번 학생은 3번 학생이나 5번 학생에게만 체육복을 빌려줄 수 있습니다. 체육복이 없으면 수업을 들을 수 없기 때문에 체육복을 적절히 빌려 최대한 많은 학생이 체육수업을 들어야 합니다.</p>
<p>전체 학생의 수 n, 체육복을 도난당한 학생들의 번호가 담긴 배열 lost, 여벌의 체육복을 가져온 학생들의 번호가 담긴 배열 reserve가 매개변수로 주어질 때, 체육수업을 들을 수 있는 학생의 최댓값을 return 하도록 solution 함수를 작성해주세요.</p>
<blockquote>
<ul>
<li>전체 학생의 수는 2명 이상 30명 이하입니다.</li>
</ul>
</blockquote>
<ul>
<li><p>체육복을 도난당한 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.</p>
</li>
<li><p>여벌의 체육복을 가져온 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.</p>
</li>
<li><p>여벌 체육복이 있는 학생만 다른 학생에게 체육복을 빌려줄 수 있습니다.</p>
</li>
<li><p>여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있습니다. 이때 이 학생은 체육복을 하나만 도난당했다고 가정하며, 남은 체육복이 하나이기에 다른 학생에게는 체육복을 빌려줄 수 없습니다.</p>
</li>
<li><p>입출력 예시 
: n, lost, reserve =&gt; return
(5, [2, 4], [1, 3, 5]) =&gt; 5
(5, [2, 4], [3]) =&gt; 4
(3, [3], [1]) =&gt; 2</p>
</li>
</ul>
<h2 id="수정-전">수정 전</h2>
<pre><code>function solution(n, lost, reserve) {
  const students = new Array(n).fill(1)

  lost.forEach((student) =&gt; {
    students[student-1]--;
  })

  reserve.forEach((student) =&gt; {
    students[student-1]++;
  })

  for(let i =0; i &lt; students.length;i++) {
    if(students[i] === 0 &amp;&amp; students[i-1] === 2) {
       students[i-1]--
        students[i]++
    } else if (students[i] === 0 &amp;&amp; students[i+1] === 2) {
      students[i+1]--
      students[i]++ 
    } 
  }

return students.filter(student =&gt; student &gt;= 1).length
}</code></pre><p>이 문제는 나에게 어려웠다.
문제에 따라 생각을 정리하고 코드를 작성하기 시작했는데 정리가 덜 된 건지 내가 잘 못 작성한 건지 코드가 생각처럼 작동 하지 않았다.
(핑계를 대보자면 요즘 잠을 잘 못 자는데 오늘 2시간 자서 그렇다고 하고싶...)</p>
<p>처음에는 <code>students</code>배열을 새로 만들지 않고 <code>lost</code>, <code>reserve</code>를 각각 filter로 걸러서 비교하는 방법을 사용하려고 했는데 이 부분이 생각한 것처럼 작동 되지 않아서 헤매다가 그냥 새 배열을 만들어서 쓰는 방법으로 바꾸었다. 
요즘 filter 쓰는 것에 살짝 꽂혀서 여기저기 쓰고 있는지라 반드시 filter를 쓰겠다는 집념이 return에 나타난다...ㅋㅋㅋㅋㅋㅋ</p>
<p>새 배열을 이용한 방법은 생각보다 쉽게 풀 수 있었다.
테스트 케이스 통과하는데서 버벅거리긴 했지만 +-를 거꾸로 작성해서 통과가 안 되었던 부분이라 역시 오타부터 봐야되구나 싶었다. </p>
<h2 id="수정-후">수정 후</h2>
<pre><code>function solution(n, lost, reserve) {
  const students = new Array(n).fill(1)

  lost.forEach((student) =&gt; {
    students[student-1]--;
  })

  reserve.forEach((student) =&gt; {
    students[student-1]++;
  })

  students.forEach((student, i) =&gt; {
      if(students[i] === 0 &amp;&amp; students[i-1] === 2) {
       students[i-1]--
        students[i]++
    } else if (students[i] === 0 &amp;&amp; students[i+1] === 2) {
      students[i+1]--
      students[i]++ 
    }
})

return students.filter(student =&gt; student &gt;= 1).length
}</code></pre><p>기존의 for문을 forEach로 바꾸었다. 전반적으로 보기 좋게 하고 싶기에 별로 만족스럽지는 않다.<br>게다가 naming... 진짜 너무 어려운 것같다. 다른 사람의 풀이를 볼 때마다 느끼지만 naming이 가독성에 어마어마한 영향을 끼친다는 걸 새삼 알게된다. 지금도 만족스러운 이름들을 아니지만 많이 써보면서 내 스타일을 찾아나가야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 66 day 프로그래머스]]></title>
            <link>https://velog.io/@winney_77/TIL-66-day-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</link>
            <guid>https://velog.io/@winney_77/TIL-66-day-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</guid>
            <pubDate>Mon, 18 Jan 2021 04:29:31 GMT</pubDate>
            <description><![CDATA[<h1 id="문자열-내-p와-y의-개수">문자열 내 p와 y의 개수</h1>
<p>대문자와 소문자가 섞여있는 문자열 s가 주어집니다. s에 &#39;p&#39;의 개수와 &#39;y&#39;의 개수를 비교해 같으면 True, 다르면 False를 return 하는 solution를 완성하세요. &#39;p&#39;, &#39;y&#39; 모두 하나도 없는 경우는 항상 True를 리턴합니다. 단, 개수를 비교할 때 대문자와 소문자는 구별하지 않습니다.</p>
<p>예를 들어 s가 pPoooyY면 true를 return하고 Pyy라면 false를 return합니다.</p>
<ul>
<li>문자열 s의 길이 : 50 이하의 자연수</li>
<li>문자열 s는 알파벳으로만 이루어져 있습니다.</li>
<li>입출력 예시 : 
&#39;pPoooyY&#39;  =&gt; true
&#39;Pyy&#39;  =&gt; false<h2 id="수정-전">수정 전</h2>
<pre><code>function solution(s){
  var answer = true;
  let pCount = 0;
  let yCount = 0;
  const sArr = s.toLowerCase().split(&#39;&#39;);
  for(let s of sArr) {
      if(s === &#39;p&#39;) {
          pCount++
      }else if(s === &#39;y&#39;){
          yCount++
      }
  }
  if(pCount === 0 &amp;&amp; yCount === 0) {
      return true;
  }else if(pCount === yCount) {
      return true
  }else {
      return false
  }
}</code></pre>또 생각한 그대로 작성해나갔다. 
통과는 되었는데 생각해보니 filter를 쓸 수 있지 않을까 해서 수정해보았다.</li>
</ul>
<h2 id="수정-후">수정 후</h2>
<pre><code>function solution(s) {
  const lowerArr = s.toLowerCase().split(&#39;&#39;);
  const pArr = lowerArr.filter(p =&gt; p === &#39;p&#39;);
  const yArr = lowerArr.filter(y =&gt; y === &#39;y&#39;);
  return pArr.length === yArr.length ? true : false;
}</code></pre><p>코드 길이가 절반은 줄었고 한 번에 알아보기도 쉬워졌다. 
하지만 filter를 중복으로 쓰고 있다는 느낌이라 좀 아쉬운 느낌이다. </p>
<h2 id="다른-사람-풀이-01">다른 사람 풀이 01</h2>
<pre><code>function numPY(s) {
  return s.match(/p/ig).length == s.match(/y/ig).length;
}</code></pre><p>이 풀이를 보면서 <code>match</code>에 대해 알게되었다. 
하지만 이 경우에는 &#39;p&#39;와 &#39;y&#39;가 없을 경우의 예외처리가 되지 않는 다는 댓글을 보았다. 생각해보니 p와 y가 없다면 배열이 만들어지지 않아져 null값이 나올 것이고 length를 구할 수 없다. 
나는 if문을 이용해서 수정했지만 놀랍게도 아주 간단하게 예외처리를 한 풀이가 있어서 안 가져 올 수가 없었다.</p>
<h2 id="다른-사람-풀이-02">다른 사람 풀이 02</h2>
<pre><code>function solution(s) {
  return match = s.match(/p/ig)?.length === s.match(/y/ig)?.length;
}</code></pre><p><code>?</code>를 추가해 예외처리를 끝냈다. 오...
<code>null === null</code>라는 점을 이용한 풀이인데 전혀 생각도 못 했다. 
역시 꾸준히 써보고 생각하는 연습이 필요한 것같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 65 day 프로그래머스]]></title>
            <link>https://velog.io/@winney_77/TIL-65-day-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</link>
            <guid>https://velog.io/@winney_77/TIL-65-day-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4</guid>
            <pubDate>Fri, 15 Jan 2021 04:17:24 GMT</pubDate>
            <description><![CDATA[<h1 id="모의고사">모의고사</h1>
<p>수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다.</p>
<p>1번 수포자가 찍는 방식: 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
2번 수포자가 찍는 방식: 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, ...
3번 수포자가 찍는 방식: 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, ...</p>
<p>1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성해주세요.</p>
<ul>
<li><p>시험은 최대 10,000 문제로 구성되어있습니다.</p>
</li>
<li><p>문제의 정답은 1, 2, 3, 4, 5중 하나입니다.</p>
</li>
<li><p>가장 높은 점수를 받은 사람이 여럿일 경우, return하는 값을 오름차순 정렬해주세요.</p>
</li>
<li><p>입출력 예시 : 
[1,2,3,4,5]    =&gt; [1],
[1,3,2,4,2]    =&gt; [1,2,3]</p>
<pre><code>function solution(answers) {
const answer = [];
const firstStudent = [1,2,3,4,5];
const secondStudent = [2,1,2,3,2,4,2,5];
const thirdStudent = [3,3,1,1,2,2,4,4,5,5];

const firstStudentAnswerCount = answers.filter((answer, index) =&gt;
  answer === firstStudent[index % firstStudent.length]).length
const secondStudentAnswerCount = answers.filter((answer, index) =&gt; 
    answer === secondStudent[index % secondStudent.length]).length
const thirdStudentAnswerCount = answers.filter((answer, index) =&gt; 
   answer === thirdStudent[index % thirdStudent.length]).length
</code></pre></li>
</ul>
<p>const maxArr = [firstStudentAnswerCount,secondStudentAnswerCount,thirdStudentAnswerCount]</p>
<p>  for(let i =0 ; i &lt; maxArr.length; i++) {
    const max = Math.max (firstStudentAnswerCount,secondStudentAnswerCount,thirdStudentAnswerCount)
    if (maxArr[i] &gt;= max) {
      answer.push(i+1)
    }
  }  </p>
<p>  return answer;
}</p>
<p>```</p>
<ol>
<li>각 학생이 답을 찍는 패턴을 배열로 만든다.</li>
<li>각 학생들이 맞춘 답의 개수를 찾는다. (filter 사용)</li>
<li>학생들이 맞출 답의 개수를 배열에 담는다.(maxArr)</li>
<li>맞춘 답 중 가장 큰 수를 찾는다. (max)</li>
<li>for문으로 가장 많이 맞춘 답의 개수(max)와 각 학생이 맞춘 답의 개수를 비교해 해당 학생의 번호(i+1)을 answer 배열에 넣는다. </li>
</ol>
<p>이번에 가장 막혔던 부분은 answers의 길이가 학생의 답 패턴 배열보다 무조건 긴데 이걸 어떻게 answers 끝까지 비교할 것인가였다. 
원래는 <code>Math.ceil(answers.length/studentAnswer.length)</code>를 해서 나온 값을 studentAnswer에 붙여서 for문을 할까라고 막연히 생각하다가 실현하기 힘들다는 생각이 들어서 포기했다. </p>
<p>계속 아이디어가 생각이 안 나서 결국 찾아봤는데 나머지 값을 구해서 반복적으로 answer를 비교하는 방법이 있었다. 역시 사람들이 똑똑하다...</p>
<p>그 이후로는 문제 풀이가 매끄럽게 흘러갔다. </p>
<p>마지막의 for문의 경우 지금은 학생 수가 3명이고 문제 자체도 3명으로 고정되어 있지만 학생이 늘어난다면 for문이 더 맞지 않을까해서 for문을 사용하게 되었다. </p>
<p>전체적으로 학생 수가 늘어날 경우를 감안해서 작성한 코드는 아니지만 만약에 학생 수도 늘어난다면 많은 부분을 고쳐야 할 것 같다. filter도 지금처럼 사용하기는 힘들겠고 maxArr도 지금처럼 직접 요소를 주는게 아닌 Array.push를 써야겠다. </p>
<p>프로그래머스 분류에 완전탐색이라고 되어 있던데 조만간 완전탐색에 대해 알아봐야겠다.</p>
]]></description>
        </item>
    </channel>
</rss>