<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>devSpring</title>
        <link>https://velog.io/</link>
        <description>즐겁게 배우고 꾸준히 블로깅하는 개발자입니다 ;&gt;</description>
        <lastBuildDate>Sat, 20 Nov 2021 19:38:29 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>devSpring</title>
            <url>https://images.velog.io/images/denmark-choco/profile/aa13f7c8-183f-4235-ad30-f844f82e200a/KakaoTalk_Photo_2021-02-14-17-12-47.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. devSpring. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/denmark-choco" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[kakao Login API - KOE010(401)]]></title>
            <link>https://velog.io/@denmark-choco/kakao-Login-API-KOE010401</link>
            <guid>https://velog.io/@denmark-choco/kakao-Login-API-KOE010401</guid>
            <pubDate>Sat, 20 Nov 2021 19:38:29 GMT</pubDate>
            <description><![CDATA[<h2 id="kakao-login-401-error">KAKAO LOGIN 401 ERROR</h2>
<h3 id="🧨-발생-상황">🧨 발생 상황</h3>
<p>시작전!! 카카오 login api는 인가코드를 받은 후, 토큰을 발급받을 수 있습니다.(<a href="https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api">카카오 디벨로퍼에서 로그인 로직 확인하기</a>)</p>
<p>에러 발생상황은 인가코드를 받은 후 axios를 이용해 토큰을 받기위한 post요청 중 401이 발생했다.</p>
<p>구글 콘솔 네트워크 탭에서 에러코드와 상태를 확인해보니 KOE010(invalid_client)이었고 리서치를 시작했다.</p>
<p><a href="https://developers.kakao.com/docs/latest/ko/kakaologin/trouble-shooting">카카오 디벨로퍼</a> 공식 페이지에서 확인해보면 클라이언트 시크릿 기능을 활성화한 앱에서 값을 전달하지 않는 경우 발생한다고 적혀있는것을 볼 수 있다. [내 애플리케이션] &gt; [카카오 로그인] &gt; [보안]에서 생성한 클라이언트 시크릿 코드를 client_secret 파라미터로 전달할 수 있다고 나와있지만 놀랍게도 나는 클라이언트 시크릿을 활성화하지 않은 상태였다.🤔</p>
<p>kakao access token KOE010이라는 키워드로 검색을 했고 내가 해결한 방법은 QueryString으로 body를 전달하지 않아서 발생하는 에러였다. QueryString을 적용하지 않았는데 클라이언트 시크릿 코드를 보내라는 공식문서에 당황!! 그래도 다른 분들의 질문으로 도움을 받아 해결할 수 있었다.</p>
<p>검색을 하면서 찾은 해결 방법들을 아래에 링크 걸어두었습니다.</p>
<h3 id="💡-해결-방법-">💡 해결 방법 :</h3>
<ul>
<li><p><strong><a href="https://devtalk.kakao.com/t/client-secret/113202">Content-Type</a></strong>
Token 요청 시 Content-Type값 : application/x-www-form-urlencoded </p>
</li>
<li><p><strong><a href="https://developers.kakao.com/docs/latest/ko/kakaologin/trouble-shooting">활성화된 클라이언트 시크릿 적용</a>(활성화해둔 경우)</strong>
[내 애플리케이션] &gt; [카카오 로그인] &gt; [보안]에서 생성한 클라이언트 시크릿 코드 확인</p>
</li>
<li><p><strong><a href="https://devtalk.kakao.com/t/react-invalid-client-koe010/114139">body QueryString 형식으로 전달</a></strong>
JSON.stringfy()가 아닌 QueryString으로 전달을 해야한다</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTTP 웹 기본 지식(진행중)]]></title>
            <link>https://velog.io/@denmark-choco/HTTP-%EC%9B%B9-%EA%B8%B0%EB%B3%B8-%EC%A7%80%EC%8B%9D</link>
            <guid>https://velog.io/@denmark-choco/HTTP-%EC%9B%B9-%EA%B8%B0%EB%B3%B8-%EC%A7%80%EC%8B%9D</guid>
            <pubDate>Sat, 26 Jun 2021 06:16:49 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>인프런의 <a href="https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC/dashboard">모든 개발자를 위한 HTTP 웹 기본 지식</a>강좌를 듣고 공부한 내용입니다. 개인이 보기 위해 적은 정보라서 설명이 부족할 수 있습니다. </p>
</blockquote>
<h1 id="httphypertext-transfer-protocol">HTTP(HyperText Transfer Protocol)</h1>
<p><img src="https://images.velog.io/images/denmark-choco/post/2869503c-12cd-4ab1-bbfe-a96fab6550ed/http.png" alt=""></p>
<p>html, text뿐만아니라 image, 음성, 영상, 파일, json, xml, api 등 거의 모든 형태의 데이터 전송 가능하다</p>
<p>서버간 데이터를 주고 받을 때도 대부분 HTTP를 사용한다</p>
<h2 id="특징">특징</h2>
<h3 id="클라이언트-서버-구조">클라이언트 서버 구조</h3>
<p>클라이언트가 서버에 http요청을 보내고 서버로부터 응답이 올때까지 기다리다가 서버로부터 http응답을 받는다</p>
<h3 id="stateful-stateless">Stateful, Stateless</h3>
<p><img src="https://images.velog.io/images/denmark-choco/post/9d52f8b8-e9eb-4439-a0f9-eb54d9458eca/stateless.png" alt=""></p>
<p>http는 무상태 프로토콜(stateless)을 지향한다</p>
<p>무상태 프로토콜의 의미는 어떠한 이전 요청과도 무관한 각각의 요청을 독립적인 트랜잭션으로 취급하는 통신 프로토콜로 클라이언트에서 서버로 요청을 보내고 받는 일련의 과정이 독립적으로 이루어지고 서버에서는 이전 클라이언트 상태를 유지하지 않는다.</p>
<p>stateless의 의미를 풀어서 설명을 해보자.</p>
<p>클라이언트에서 서버로 요청을 보내고 서버는 이에 응답을 전달한다. 클라이언트에서 서버로 다시 한번더 요청을 전달하면 서버는 처음에 클라이언트에서 전달받은 요청에 대한 상태를 유지하지 않는다. 그래서 클라이언트에서 서버로 요청시에 처음에 전달했던 데이터를 같이 보내야 서버에서 원하는 응답을 받을 수 있다. 여기에는 매번 이전에 보냈던 데이터도 포함해서 재요청을 하다보니 요청시 전달되는 데이터가 많다는 단점이 있다. 하지만 갑자기 서버가 다운되는 경우와 같은 해당 서버가 아닌 다른 서버를 이용해야하는 경우, 전혀 다른 서버에 요청을 해도 요청에 필요한 데이터들을 같이 전달하기때문에 새로운 서버를 통해 원하는 응답을 받는 것이 가능해진다.</p>
<p>Stateful는 정반대의 의미이다. 처음에 클라이언트에서 요청했던 데이터를 서버에서는 저장하고 있다. 그래서 클라이언트에서 서버로 재 요청시 이전 데이터를 제외하고 서버로 요청을 해도 서버는 처음에 전달받은 데이터를 가지고 있어서 클라이언트에서 원하는 데이터를 받을 수 있게 된다. 이경우에는 요청시 전달하는 데이터의 양은 적지만 서버가 바뀌는 경우, 바뀐 서버에게 클라이언트에서 요청받은 저장된 데이터를 전달해주어야하는 단점이 발생한다.</p>
<p>실무에서 stateless를 선호하고 있지만 http를 사용함에 있어 모든것을 stateless로 적용하는 것은 어려울 수 있다.</p>
<p>예시로 로그인이다. 서버를 로그인이 된 상태로 유지를 해줘야하는데 이것을 유지하기 위해 브라우저 쿠키와 서버의 세션등을 사용해서 상태를 유지한다.</p>
<p>이러한 경우에도 상태유지는 최소한으로 하는 것이 좋다.</p>
<h3 id="비-연결성connectionless">비 연결성(connectionless)</h3>
<p><img src="https://images.velog.io/images/denmark-choco/post/192b51df-9d0b-4625-860f-5fc6dae6b80b/%E1%84%87%E1%85%B5%E1%84%8B%E1%85%A7%E1%86%AB%E1%84%80%E1%85%A7%E1%86%AF%E1%84%89%E1%85%A5%E1%86%BC.png" alt=""></p>
<p>http는 기본적으로 연결을 유지하지 않는 모델이다.</p>
<p>클라이언트에서 서버로 요청을 하는 경우, 서버로부터 응답을 받으면 연결을 끊어지게 된다. 연결이 유지되는 경우, 연결된 클라이언트만큼 서버의 자원이 소진되게 되어서 최소한의 자원으로 서버를 사용할 수 있도록 비연결성을 유지한다.</p>
<p>비연결성을 유지하면 1시간동안 수천명이 서비스를 사용해도 실제 서버에서 동시에 처리하는 요청은 수십개 이하로 매우 작다.</p>
<p>하지만 요청시마다 tcp/ip 연결을 매번 새로 진행을 하게되고 tcp/ip의 특징인 3 way handshake시간도 추가된다. 이 단점을 해결하기 위해서 일정시간동안은 연결을 유지하는 http지속연결(persistent Connections)을 사용하고 있고 최근에는 더 최적화가 되었다.</p>
<h3 id="http-메세지">HTTP 메세지</h3>
<p><img src="https://images.velog.io/images/denmark-choco/post/3951da7c-087d-4421-b620-af4059a91597/http%E1%84%86%E1%85%A6%E1%84%89%E1%85%A6%E1%84%8C%E1%85%B52.jpeg" alt=""></p>
<h4 id="시작라인">시작라인</h4>
<ul>
<li>request line(요청 메세지)<ul>
<li>메소드  / request target =&gt; 절대경로 + 쿼리 / http version</li>
</ul>
</li>
</ul>
<ul>
<li>status line(응답 메세지)<ul>
<li>http version / status code / reason-pharse</li>
</ul>
</li>
</ul>
<h4 id="http-해더header">HTTP 해더(header)</h4>
<ul>
<li>field name: value</li>
<li>field name은 대소문자 구문없어서 자유롭게 작성이 가능하다</li>
</ul>
<p>전송이 필요한 모든 부가정보가 들어있다. 임의의 해더도 가능하다</p>
<p>예) 메세지 바디의 크기, 압축, 인증 등등</p>
<h4 id="http-바디body">HTTP 바디(body)</h4>
<p>실제 전송할 데이터</p>
<hr>
<h2 id="메서드">메서드</h2>
<h3 id="메서드의-속성">메서드의 속성</h3>
<p><img src="https://images.velog.io/images/denmark-choco/post/806b5ae7-f02f-4799-8c5a-50e5c8f80352/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-06-26%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.05.49.png" alt=""></p>
<ul>
<li><p>안전(Safe Methos)</p>
</li>
<li><p>멱등(Idempotent Methods) : 한번 호출이든 여러번 호출이든 결과가 같다</p>
</li>
<li><p>캐시 가능(Cacheable Methods) : 응답결과 리소스를 캐시해서 사용해도 가능(get, head정도만 사용된다)</p>
</li>
</ul>
<h3 id="get">GET</h3>
<ul>
<li><p>리소스 조회</p>
</li>
<li><p>서버에 전달하고 싶은 데이터는 query로 전달</p>
</li>
<li><p>body에 데이터를 전달할 수 있지만 권장하지 않음</p>
</li>
</ul>
<h3 id="post">POST</h3>
<ul>
<li><p>요청 데이터 처리</p>
</li>
<li><p>메세지 body를 통해 서버로 데이터 전달</p>
</li>
<li><p>서버는 요청 데이터 처리</p>
</li>
<li><p>주로 신규 리소스 등록에 사용</p>
</li>
<li><p>프로세스를 처리해야하는 경우에도 사용</p>
</li>
</ul>
<h3 id="put">PUT</h3>
<ul>
<li><p>리소스 대체</p>
</li>
<li><p>해당 리소스가 없으면 생성</p>
</li>
<li><p>클라이언트에서 리소스를 식별</p>
</li>
<li><p>기존 리소스를 완전히 덮어쓰기가 된다</p>
</li>
</ul>
<h3 id="patch">PATCH</h3>
<ul>
<li>리소스 부분 변경</li>
</ul>
<h3 id="delete">DELETE</h3>
<ul>
<li>리소스 삭제</li>
</ul>
<h3 id="기타-메서드">기타 메서드</h3>
<ul>
<li>HEAD : get과 동일하지만 메세지 부분을 제외하고, 상태 줄과 헤더만 변경</li>
<li>OPTIONS : 대상 리소스 대한 통신 가능 옵션(메서드)을 설명(주로 CORS에서 사용)</li>
</ul>
<hr>
<h2 id="상태코드">상태코드</h2>
<p>클라이언트가 보낸 요청의 처리상태를 응답에서 알려주는 기능을 한다.</p>
<h3 id="1xx-정보-요청을-받았으며-프로세스-중">1xx (정보): 요청을 받았으며 프로세스 중</h3>
<h3 id="2xx-성공-요청-성공">2xx (성공): 요청 성공</h3>
<ul>
<li><p>200 : OK</p>
</li>
<li><p>201 : Created. 클라이언트의 요청으로 서버에 새로운 리소스 생성.</p>
</li>
<li><p>202 : Acceted. 요청이 접수가 되었으나 처리가 되지 않음.</p>
</li>
<li><p>204 : No Content. 서버가 성공적으로 요청을 수행했지만 응답 페이로드 본문에 보낼 데이터가 없음.</p>
</li>
</ul>
<h3 id="3xx-리다이렉션-요청-완료를-위해-추가-작업-조치가-필요">3xx (리다이렉션): 요청 완료를 위해 추가 작업 조치가 필요</h3>
<p><strong>영구 리다이렉션</strong></p>
<ul>
<li><p>리소스의 url가 영구적으로 이동</p>
</li>
<li><p>원래 url사용 x</p>
</li>
<li><p>검색 엔진 등에서도 변경인지</p>
</li>
<li><p>301(Moved Permanently): 리다이렉트시 요청 메서드가 GET으로 변하고 본문이 제거될 수 있음.</p>
</li>
<li><p>308(Permanent Redirect) : 301과 기능은 같고, 본문이 남는다는 차이가 있음.</p>
</li>
</ul>
<p><strong>일시적인 리다이렉션</strong></p>
<ul>
<li><p>리소스의 uri가 일시적으로 변경</p>
</li>
<li><p>검색 엔진 등에서 url을 변경하면 안됨</p>
</li>
<li><p>예시 =&gt; PRG(Post/Redirect/Get)</p>
</li>
<li><p>302(Found): 리다이렉트시 요청 메서드가 get으로 변하고, 본문이 제거될 수 있음.</p>
</li>
<li><p>303(See Other): 리다이렉트시 요청 메소드 get으로 변경</p>
</li>
<li><p>307(Temporary Redirect): 302와 기능은 같음. 리다이렉트시 요청 메소드와 본문 유지.</p>
</li>
</ul>
<p><strong>기타 리다이렉션</strong></p>
<ul>
<li><p>300(Multiple Choice) : 많이 사용하지 않는다</p>
</li>
<li><p>304(Not Modified): 클라이언트에게 리소스가 수정되지 않았음을 알려주고, 클라이언트에서는 저장된 캐시를 재사용한다.</p>
</li>
</ul>
<h3 id="4xx-클라이언트-오류-요청의-문법이-잘못되었거나-요청을-처리할-수-없음">4xx (클라이언트 오류): 요청의 문법이 잘못되었거나 요청을 처리할 수 없음</h3>
<ul>
<li><p>400(Bad Request) : 클라이언트가 잘못된 요청을 해서 서버가 요청을 처리할 수 없음</p>
</li>
<li><p>401(Unauthorized) : 클라이언트가 해당 리소스에 대한 인증이 필요함</p>
</li>
<li><p>403(Forbidden) : 서버가 요청을 이해했지만 승인을 거부함</p>
</li>
<li><p>404(Not Found) : 요청 리소스가 서버에 없음</p>
</li>
</ul>
<h3 id="5xx-서버-오류-서버가-명백히-유효한-요청에-대해-충족을-실패">5xx (서버 오류): 서버가 명백히 유효한 요청에 대해 충족을 실패</h3>
<ul>
<li><p>500(Internal Server Error) : 서버 내부 문제로 오류 발생</p>
</li>
<li><p>503(Service Unavailable) : 서버의 일시적인 과부하 또는 예정된 작업으로 잠시 요청을 처리할 수 있음</p>
</li>
</ul>
<hr>
<h2 id="헤더1---일반헤더">헤더1 - 일반헤더</h2>
<h3 id="http-body">HTTP BODY</h3>
<p><img src="https://images.velog.io/images/denmark-choco/post/0dc445a2-7609-4ef0-ac50-5819fe62187f/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-06-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.36.16.png" alt=""></p>
<ul>
<li><p>http 전송에 필요한 모든 부가정보</p>
</li>
<li><p>메세지의 본문을 통해 표현 데이터 전달</p>
</li>
<li><p>메세지 본문은 payload라고도 한다</p>
</li>
</ul>
<h4 id="표현">표현</h4>
<ul>
<li><p>Content-Type : 표현 데이터의 형식</p>
</li>
<li><p>Content-Encoding : 표현 데이터의 압축 방식</p>
</li>
<li><p>Content-Language : 표현 데이터의 자연 언어</p>
</li>
<li><p>Content-Length : 표현 데이터의 길이. 바이트 단위</p>
</li>
</ul>
<h4 id="콘텐츠-협상">콘텐츠 협상</h4>
<ul>
<li><p>클라이언트가 선호하는 표현 요청</p>
</li>
<li><p>요청하는 자연언어는 우선순위를 정해서 서버로 전달 가능</p>
</li>
</ul>
<h4 id="전송-방식">전송 방식</h4>
<ul>
<li><p>단순 전송</p>
</li>
<li><p>압축 전송</p>
</li>
<li><p>분할 전송(Transfer-Encoding) : 용량이 큰 경우 사용. Content-Length를 넣지 않음</p>
</li>
<li><p>범위 전송</p>
</li>
</ul>
<h4 id="일반-정보">일반 정보</h4>
<ul>
<li><p>From : 유저 에이전트의 이메일 정보</p>
</li>
<li><p>Referer : 이전 웹 페이지 주소</p>
</li>
<li><p>User-Agent : 유저 에이전트 애플리케이션 정보</p>
</li>
<li><p>Server : 요청을 처리하는 오리진 서버의 소프트웨어 정보</p>
</li>
<li><p>Date : 메시지가 생성된 날짜</p>
</li>
</ul>
<h4 id="특별한-정보">특별한 정보</h4>
<ul>
<li><p>Host : 요청한 호스트 정보(도메인)</p>
</li>
<li><p>Location : 페이지 리다이렉션</p>
</li>
<li><p>Allow : 허용 가능한 HTTP 메서드</p>
</li>
<li><p>Retry-After : 유저 에이전트가 다음 요청을 하기까지 기다려야 하는 시간</p>
</li>
</ul>
<h4 id="인증">인증</h4>
<ul>
<li><p>Authorization : 클라이언트 인증 정보를 서버에 전달</p>
</li>
<li><p>WWW-Authenticate : 리소스 접근시 필요한 인증 방법 정의. 401응답과 함께 사용</p>
</li>
</ul>
<h4 id="쿠키">쿠키</h4>
<ul>
<li><p>Set-Cookie : 서버에서 클라이언트로 쿠키 전달(응답)</p>
</li>
<li><p>Cookie : 클라이언트가 서버에서 받은 쿠키를 저장하고, http 요청시 서버로 전달</p>
</li>
<li><p>보안에 민감한 데이터는 저장하면 안됨(주민번호, 신용카드 번호 등등)</p>
</li>
<li><p>세션쿠키와 영속쿠키</p>
</li>
<li><p>보안</p>
<ul>
<li>Secure : 쿠키는 http, https를 구분하지 않고 전송. Secure를 적용하면 https인 경우에만 전송.<ul>
<li>HttpOnly : XSS 공격 방지. 자바스크립트에서 쿠키 접근 불가</li>
<li>SameSite : XSRF 공격 방지</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="헤더2---캐시와-조건부-요청">헤더2 - 캐시와 조건부 요청</h2>
<hr>
<h4 id="reference">Reference</h4>
<ul>
<li><p><a href="https://velog.io/@taehyunkim/HTTP">http 이미지 출처</a></p>
</li>
<li><p><a href="https://hackernoon.com/everything-you-ever-wanted-to-know-about-websockets-literally-a05f36432999">http stateless 이미지</a></p>
</li>
<li><p><a href="https://feel5ny.github.io/2019/08/15/HTTP_003_01/">http 메세지 이미지</a></p>
</li>
<li><p><a href="https://ko.wikipedia.org/wiki/HTTP">http 속성 이미지</a></p>
</li>
<li><p><a href="https://ko.wikipedia.org/wiki/HTTP_%EC%83%81%ED%83%9C_%EC%BD%94%EB%93%9C">http 상태코드</a></p>
</li>
<li><p><a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Messages">http body 이미지</a></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[인터넷 네트워크]]></title>
            <link>https://velog.io/@denmark-choco/%EC%9D%B8%ED%84%B0%EB%84%B7-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC</link>
            <guid>https://velog.io/@denmark-choco/%EC%9D%B8%ED%84%B0%EB%84%B7-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC</guid>
            <pubDate>Wed, 23 Jun 2021 04:41:05 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/denmark-choco/post/ca1056d3-a5e4-4e9f-8665-f74cec275120/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-06-23%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.40.26.png" alt=""></p>
<h4 id="intro">intro</h4>
<p>인프런에서 김영한님의 &#39;<a href="https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC#">모든 개발자를 위한 HTTP 웹 기본 지식</a>&#39;의 강의를 듣고 정리하는 시리즈입니다.</p>
<p>http를 실업무에서 사용해보았고 지금도 사용하고 있고 앞으로도 사용할 예정이지만 정확하게 정의를 내리고 누군가에게 설명을 하기에는 어려운 부분이었다.</p>
<p>이번 강의를 통해서 http와 인터넷의 흐름을 이해하고 실무에 필요한 http기본 지식을 익히는 시간을 가질 수 있을 것이다. </p>
<p>아래의 글은 강의를 보면서 서칭과 공부한 내용을 정리하고 있습니다. 강의 내용을 바탕으로 추가된 내용이 있을 수 있어 강의의 내용과 다를 수 있고 더 상세한 이미지등의 자료는 첨부하지 않았습니다. </p>
<h2 id="ipinternet-protocol">IP(Internet Protocol)</h2>
<p><img src="https://images.velog.io/images/denmark-choco/post/3faad4ea-06a7-4974-bae0-ff8bc59868c5/vector.png" alt=""></p>
<p>ip란 송신 호스트와 수신 호스트가 패킷 교환 네트워크(패킷 스위칭 네트워크, Packet Switching Network)에서 정보를 주고받는 데 사용하는 정보 위주의 규약이라고 위키피디아에서 확인된다.</p>
<p>쉽게 설명하면 ip는 패킷이라는 단위로 데이터가 교환되는데 패킷안에서는 출발지 ip와 목적지 ip, 데이터가 포함되어 있다.</p>
<h4 id="한계😵">한계😵</h4>
<ul>
<li>비연결성 : 패킷을 받을 대상이 없거나 서비스 불능 상태여도 패킷 전송</li>
<li>비신뢰성 : 중간에 패킷이 사라지거나 순서가 바뀌어서 전송될 수 있음</li>
<li>프로그램 구분 : 같은 ip를 사용하는 서버에서 통신하는 애플리케이션이 둘 이상인 경우 구분이 어려움</li>
</ul>
<h2 id="tcp">TCP</h2>
<p><img src="https://images.velog.io/images/denmark-choco/post/051e1575-31ad-4362-937e-4c8ca679f455/999DED345B7A26DF05.png" alt=""></p>
<p>TCP는 IP의 한계를 보완해준다.</p>
<p>위키피디아에서는 근거리 통신망이나 인트라넷, 인터넷에 연결된 컴퓨터에서 실행되는 프로그램 간에 일련의 옥텟을 안정적으로, 순서대로, 에러없이 교환할 수 있게 한다고 확인된다.</p>
<p>TCP는 출발지 port, 목적지port, 전송제어, 순서, 검증정보 등이 추가적으로 들어가서 데이터를 감싸고 이것을 ip패킷에 담아서 전송이 되어 안정적으로 데이터를 주고 받을 수 있게 된다.</p>
<h4 id="특징전송제어-프로토콜">특징(전송제어 프로토콜)</h4>
<ul>
<li><p>연결지향 : tcp 3 way handshake(가상연결)
<img src="https://images.velog.io/images/denmark-choco/post/09f3c023-be30-427b-916c-16d393076b59/tcp-handshake-diagram.png" alt=""></p>
</li>
<li><p>데이터 전달 보증 : 잘 도착했는지 받은 곳에서 잘 받았다고 답변이 옴</p>
</li>
<li><p>순서 보장</p>
</li>
<li><p>신뢰할 수 있는 프로토콜</p>
</li>
<li><p>현재는 대부분 tcp 사용</p>
</li>
</ul>
<h2 id="port">PORT</h2>
<p>0 ~ 1023: 잘 알려진 포트, 사용하지 않는 것이 좋음
0 ~ 65535 : 할당가능</p>
<ul>
<li>ftp - 20, 21</li>
<li>telnet - 23</li>
<li>http - 80</li>
<li>https - 443</li>
</ul>
<h2 id="dns">DNS</h2>
<p><img src="https://images.velog.io/images/denmark-choco/post/d69ef32b-3056-4884-a7d4-c99a22e5016f/dns.png" alt=""></p>
<p>DNS는 우리가 인터넷을 편리하게 쓰게 해주는 것으로, 영문/한글 주소를 IP 네트워크에서 찾아갈 수 있는 IP로 변환해 준다</p>
<h3 id="회고">회고</h3>
<p>회사에서 이번달부터 인프런 강의를 제공해주는 복지가 생겼다.🥳
공부하는 기간에는 열심히 블로그를 작성했었지만 이직을 하고 공부를 하기도 했지만 블로그를 작성하지 않고 업무에 더 몰입했었다. 지금도 업무는 많지만 매일 꾸준히 조금씩 시간을 다시 블로그를 조금씩 작성해보려고 한다.</p>
<h4 id="reference">reference</h4>
<ul>
<li><p><a href="https://ko.wikipedia.org/wiki/%EC%9C%84%ED%82%A4%EB%B0%B1%EA%B3%BC:%EB%8C%80%EB%AC%B8">wikipedia =&gt; https://ko.wikipedia.org/wiki/%EC%9C%84%ED%82%A4%EB%B0%B1%EA%B3%BC:%EB%8C%80%EB%AC%B8</a></p>
</li>
<li><p><a href="https://ko.vpnmentor.com/tools/ipinfo/">IP이미지출처</a></p>
</li>
<li><p><a href="https://www.cloudflare.com/ko-kr/learning/ddos/glossary/tcp-ip/">TCP이미지출처</a></p>
</li>
<li><p><a href="https://ming9mon.tistory.com/2">tcp/ip 4계층 이미지 출처</a></p>
</li>
<li><p><a href="https://fidanzatedinerd.altervista.org/i-migliori-server-dns-gratis/">DNS 이미지 출처</a></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ourCat_컴포넌트 구현 및 배포]]></title>
            <link>https://velog.io/@denmark-choco/ourCat%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B5%AC%ED%98%84-%EB%B0%8F-%EB%B0%B0%ED%8F%AC</link>
            <guid>https://velog.io/@denmark-choco/ourCat%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B5%AC%ED%98%84-%EB%B0%8F-%EB%B0%B0%ED%8F%AC</guid>
            <pubDate>Sun, 14 Feb 2021 08:00:49 GMT</pubDate>
            <description><![CDATA[<h1 id="💡-sprint1">💡 sprint#1</h1>
<p>이번 명절에도 코로나로 인해 집에서 프로젝트를 진행하기로 했다.</p>
<p>프론트 팀원인 김대현 개발자와 협업을 진행했고 미팅은 Google Meet을 사용했다. 먼저 prettier와 eslint를 적용하고 github project &amp; issue 연결해서 칸반차트를 적용했다. github에서 제공하는 서비스를 최대한 이용해보고자 wiki도 같이 작성했다. </p>
<p><img src="https://images.velog.io/images/denmark-choco/post/f81f5ed6-1b4b-4da1-ad58-234a0b0fa7ad/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.15.26.png" alt=""></p>
<h2 id="mixin">Mixin</h2>
<p>font와 color는 공통적으로 사용하는 요소라는 것을 감안해 styled-components의 ThemeProvider을 이용해 theme을 적용했다.</p>
<p>그리고 프로젝트에 atomic 디자인을 적용하기로 했으니 컴포넌트를 먼저 구현하기로 했다. 컴포넌트 구현시  재사용성을 고려하며 구현을 하다보니 공통적으로 받는 props가 있었고 이것을 mixin해야할 필요성을 느꼈다. props의 interface도 동일하게 적용해야해서 타입도 같이 지정을 해주었다.</p>
<pre><code class="language-typescript">// props의 interface
export interface IComponent {
    id?: string;
    name?: string;
    className?: string;
    children?: React.ReactNode;

    font?: fontType;
    weight?: fontWeightType;
    position?: string;
    top?: string;
    right?: string;
    bottom?: string;
    left?: string;
    width?: string;
    height?: string;
    margin?: string;
    padding?: string;
    border?: string;
    borderRadius?: string;
    color?: string;
    opacity?: number;
}
// props의 css
import { css } from &#39;styled-components&#39;;
import { IComponent } from &#39;common/Interfaces/IComponent&#39;;

export const ComponentMixin = css&lt;IComponent&gt;`
  position: ${props =&gt; props.position &amp;&amp; props.position};
  top: ${props =&gt; props.top &amp;&amp; props.top};
  right: ${props =&gt; props.right &amp;&amp; props.right};
  bottom: ${props =&gt; props.bottom &amp;&amp; props.bottom};
  left: ${props =&gt; props.left &amp;&amp; props.left};
  width: ${props =&gt; props.width &amp;&amp; props.width};
  height: ${props =&gt; props.height &amp;&amp; props.height};
  margin: ${props =&gt; props.margin &amp;&amp; props.margin};
  padding: ${props =&gt; props.padding &amp;&amp; props.padding};
  border: ${props =&gt; props.border &amp;&amp; props.border};
  border-radius: ${props =&gt; props.borderRadius &amp;&amp; props.borderRadius};
  color: ${props =&gt; props.color &amp;&amp; props.color};
  opacity: ${props =&gt; props.opacity &amp;&amp; props.opacity};
  font: ${props =&gt; props.font &amp;&amp; props.theme.fonts[props.font]};
  font-weight: ${props =&gt; props.weight ? props.theme.fontWeights[props.weight] : 400};
`;</code></pre>
<h2 id="컴포넌트-구현">컴포넌트 구현</h2>
<p>mixin을 적용하여 컴포넌트를 구현하면 props의 길이도 짧아져 가독성이 좋아지고 컴포넌트별로 필요한 props만 추가하면 사용하는 입장에서도 훨씬 가볍게 느껴지는  느낌이었다.</p>
<pre><code class="language-typescript">// mixin props interface를 적용
import { IComponent } from &#39;common&#39;;
import * as S from &#39;./style&#39;;

export interface IRangeProps extends IComponent {
  onClick?: React.MouseEventHandler&lt;HTMLElement&gt;;
  onChange?: React.ChangeEventHandler&lt;HTMLElement&gt;;
  ref?: React.RefObject&lt;HTMLInputElement&gt;;
  defaultValue?: string | string[] | number;
  maxStep?: string;
  minStep?: string;
  step?: string;
}

export const Range: React.FC&lt;IRangeProps&gt; = ({
  maxStep = &#39;100&#39;,
  minStep = &#39;0&#39;,
  step = &#39;10&#39;,
  ...props
}) =&gt; {
  return &lt;S.Wrap type=&quot;range&quot; min={minStep} max={maxStep} step={step} {...props} /&gt;;
};
// mixin props css를 적용
import { ComponentMixin } from &#39;common&#39;;
import { IRangeProps } from &#39;./index&#39;;
import styled from &#39;styled-components&#39;;

export const Wrap = styled.input&lt;IRangeProps&gt;`
  ${ComponentMixin};
  cursor: pointer;
  &amp;::-webkit-slider-thumb {
    -webkit-appearance: none;
    margin-top: -4px;
    width: 4px;
    height: 12px;
    border-radius: 6px;
    background-color: ${props =&gt; props.theme.colors.MAIN};
  }
  &amp;::-webkit-slider-runnable-track {
    height: 4px;
    background-color: ${props =&gt; props.theme.colors.GRAY[400]};
    border-radius: 10px;
  }
`;</code></pre>
<h2 id="deploy">Deploy</h2>
<p>nextJS를 배포하기 위해서 Netlify, vercel등을 알아보았다. 처음에는 vercel을 이용해서 배포를 하려고 했지만 레포가 개인 레포가 아니면 요금이 발생한다고 해서 Netlify로 배포를 했다</p>
<p>배포방법은 간단했다. 먼저 package.json파일에 아래의 script를 추가해준다.</p>
<pre><code class="language-typescript"> &quot;scripts&quot;: {
    ...,
    &quot;netlify-deploy&quot;: &quot;next build &amp;&amp; next export&quot;
  },</code></pre>
<p>Netlify 홈페이지에 접속해 로그인을 한 후 &#39;New site from Git&#39;버튼을 클릭한다.</p>
<p><img src="https://images.velog.io/images/denmark-choco/post/14b3ee60-1be4-44dc-8584-88b27fa63373/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.53.31.png" alt=""></p>
<p>&#39;GitHub&#39;버튼을 클릭하고 레포를 클릭해준다.</p>
<p><img src="https://images.velog.io/images/denmark-choco/post/eb4c3908-90e0-4156-a98a-536ae3bd5408/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.54.51.png" alt=""></p>
<p>레포가 보이지 않는 경우 아래에 &#39;Configure Netlify on GitHub&#39;버튼을 눌러 레포를 찾아준다.</p>
<p><img src="https://images.velog.io/images/denmark-choco/post/3db94323-0e27-4871-a07b-31a77b6c7a11/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.57.05.png" alt=""></p>
<p>레포를 선택하면 배포환경을 세팅하는 화면이 나온다. 빌드 명령어는 실제 배포시 사용될 명령어를 입력하고 아래의 폴더이름은 아무거나 넣어도 된다고 해서 그대로 적용했다.</p>
<p><img src="https://images.velog.io/images/denmark-choco/post/ea408c5c-2b92-4674-8184-53b63a840d81/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.58.07.png" alt=""></p>
<p>이렇게 배포를 하면 완성이다. 처음에는 이상한 도메인을 주는데 &#39;Domain Setting&#39;에 들어가서 도메인은 변경이 가능하다.</p>
<h4 id="reference">Reference</h4>
<ul>
<li><a href="https://taeny.dev/javascript/nextjs-with-deployment-platform/#6--netlify-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0">nextJS 뭘로 배포할까? (Netlify, Vercel, Github page)</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ourCat_project]]></title>
            <link>https://velog.io/@denmark-choco/ourCatproject</link>
            <guid>https://velog.io/@denmark-choco/ourCatproject</guid>
            <pubDate>Sun, 14 Feb 2021 07:07:10 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/denmark-choco/post/2cf822e3-328a-4734-bfb2-97faff25ba42/ourCatLogo.png" alt=""></p>
<h1 id="🥳-ourcat">🥳 ourCat</h1>
<p>OurCat URL =&gt; <a href="https://ourcat.netlify.app/">https://ourcat.netlify.app/</a>
ourCat GitHub =&gt; <a href="https://github.com/ourCat/ourCat_frontend">https://github.com/ourCat/ourCat_frontend</a></p>
<p>개발자 지인들과 사이드 프로젝트를 계획하고 있었다. 작년부터 대화는 오가고 있었고 2021년 1월 1일부터 본격적으로 시작했다. 중간에 디자이너 취준생인 지인의 도움으로 모바일버전의 간단한 디자인은 도움을 받을 수 있었고 이후에는 프론트 개발자 2명, 벡엔드 개발자 1명으로 진행이 되었다.</p>
<p>1월은 웹버전의 디자인이나 기술스택을 정하고 공부하는 시간으로 정하고 매주 어떤 공부를 했는지 공유하는 방식으로 진행했다. </p>
<p>2월부터는 본격적으로 gitHub에 레포를 만들고 개발환경 세팅에 들어갔다.</p>
<h2 id="💻-about-project">💻 About Project</h2>
<p>우리 주변에는 많은 길고양이들이 있습니다.</p>
<p>짧은 순간, 스쳐지나간 이름 없는 고양이들에게도</p>
<p>누군가에게 잊혀지지 않는 &#39;어떤&#39; 고양이가 될 수 있는 공간이 되었으면 좋겠습니다.</p>
<p>우리 동네 고양이들의 소식통!! &#39;ourCat&#39;으로 고양이의 이름과 특징을 공유하고 사진을 업로드할 수 있는 어플입니다.</p>
<p>나만의 고양이가 아닌 우리의 고양이를 공유하고 커뮤니티를 형성 할 수 있습니다.</p>
<h2 id="🕰-meeting-time">🕰 Meeting time</h2>
<blockquote>
<p>매주 일요일 오후 6시</p>
</blockquote>
<p>매주 commit과 코드리뷰를 통해 진행과정을 공유하고 피드백을 주고 받습니다.</p>
<h2 id="🧱-stack">🧱 stack</h2>
<p><img src="https://images.velog.io/images/denmark-choco/post/03e2c6c6-6ee3-4692-ac43-bf68b969e16f/My%20First%20Board.jpg" alt=""></p>
<ul>
<li><p>Design : Figma, Photoshop, Illustrator</p>
</li>
<li><p>Front-end : React, TypeScript, Next, Axios, styled-component, Atomic Design Pattern</p>
</li>
<li><p>Back-end : Nodejs, Express, MongoDB</p>
</li>
</ul>
<h2 id="🔄-function-flow">🔄 function flow</h2>
<p><img src="https://images.velog.io/images/denmark-choco/post/71f6e4ad-1eae-41ea-9f1c-3e58a7945ac5/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-13%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.50.21.png" alt=""></p>
<h2 id="👤-ourteam-position">👤 Ourteam Position</h2>
<ul>
<li><p>장봄 : Front-End</p>
</li>
<li><p>김대현 : Front-End</p>
</li>
<li><p>김민재 : Back-End</p>
</li>
</ul>
<h2 id="🤙-ourteam-rule">🤙 Ourteam Rule</h2>
<ul>
<li><p><strong>매주</strong> <strong>행아웃</strong> 미팅으로 회의 및 상황 공유할 예정입니다</p>
<p>  → 12/13 일요일 18시 시작 ~ 진행중</p>
</li>
<li><p>매달 하루는 오프라인 회의를 진행할 예정입니다.</p>
<p>  → 일정 미정(코로나 버프로 당분간 X)</p>
</li>
<li><p>슬랙에 공지사항이 올라오면 이모지로 확인여부 전달합니다.</p>
</li>
<li><p>진행 중 회의 건 발생시 깃에 이슈 작성 후 어떤 이슈를 왜 발생했는지 작성 후 공유</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Dropdown(Select & option)]]></title>
            <link>https://velog.io/@denmark-choco/DropdownSelect-option</link>
            <guid>https://velog.io/@denmark-choco/DropdownSelect-option</guid>
            <pubDate>Wed, 06 Jan 2021 12:56:09 GMT</pubDate>
            <description><![CDATA[<h1 id="⚙️-dropdown-component">⚙️ Dropdown Component</h1>
<p><img src="https://images.velog.io/images/denmark-choco/post/77ee7c05-2441-4f2f-96b6-03c030186c61/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-01-06%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%209.23.46.png" alt=""></p>
<p>드롭다운은 html태그 중 select와 option태그를 이용해서 구현을 하면 쉽게 dropdown을 구현할 수 있습니다. 태그의 속성을 이용하면 option을 Group으로 묶어서 사용도 가능하고 미리 default값을 적용해 selet된 상태로 보여질 수도 있습니다. </p>
<h3 id="dropdown-component-custom">Dropdown Component Custom</h3>
<p>기능적으로는 사용이 바로 가능하지만 디자인적인 측면에서는 전혀 멋지지 않습니다. 그래서 커스텀을 하거나 라이브러리의 기능을 가져와서 적용하는 경우가 많습니다.</p>
<p>라이브러리를 적용하지 않고 기본적으로 적용되는 css가 아닌 기업에서 요청받은 경우나 웹페이지에 어울리는 디자인으로 적용하려는 경우에는 쉽지 않았습니다.</p>
<p>select나 option을 커스텀하는 방법은 여러가지가 있습니다. 첫번째 방법은 태그에 바로 css를 적용하는 방법입니다. 하지만 이 방법을 적용하는 경우에도 어려운 경우가 많습니다. 두번째 방법은 select와 option태그를 display: none으로 적용해 보이지 않게 하고 div태그나 Label태그 등 을 이용해 새롭게 만드는 방법도 있습니다.</p>
<h3 id="dropdown-component-custom_arrow-icon-component">Dropdown Component Custom_arrow icon component</h3>
<p><img src="https://images.velog.io/images/denmark-choco/post/400b0190-a474-452d-9d38-4fc62ee1b7e1/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-01-06%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%209.39.35.png" alt=""></p>
<p>근무중인 기업에서 사용하기 위해 dropdown컴포넌트를 구현하는 과정에서 얻은 정보를 공유하려고 합니다. 
커스텀을 하는 과정에서 select태그에서 기본적으로 적용하는 화살표 아이콘은 보이지 않게 css에 appearance: none;을 적용했습니다.</p>
<p>그리고 빈자리에 화살표 이미지를 svg icon component로 구현해서 컴포넌트에 배치했습니다. 하지만 여기서 문제가 발생했습니다. 아이콘을 누르면 option이 open되지 않고 focus만 적용되었습니다. 아이콘이 select태그와 형제관계여서 아이콘을 누르면 select를 선택할 수 없었습니다. </p>
<p>구글링을 열심히 했지만 원인을 알아내기가 힘들었습니다. 다른 코드에서는 select에 css로 background에 이미지를 적용해서 icon component가 아닌 이미지로 적용을 했습니다. 하지만 component를 적용해서 커스텀을 하고 싶었고 버그를 팀원들에게 공유했습니다.</p>
<pre><code class="language-tsx">import React from &#39;react&#39;;
import { weightType } from &#39;components/atoms/Label&#39;;
import { Color, Icon } from &#39;core&#39;;
import * as S from &#39;./style&#39;;

export type DropdownSizeType = &#39;medium&#39; | &#39;small&#39;;

export interface DropdownProps {
  id?: string;
  className?: string;
  disable?: boolean;
  selected?: string;
  Children?: React.ReactNode;
  width?: string;
  sizing?: DropdownSizeType;
  weight?: weightType;
  margin?: string;
  letterSpacing?: string;
  backgroundColor?: string;
  onChange?: (event: React.ChangeEvent&lt;HTMLSelectElement&gt;) =&gt; void;
}

export const Dropdown: React.FC&lt;DropdownProps&gt; = ({
  id = &#39;Dropdown&#39;,
  className,
  disable = true,
  selected = &#39;&#39;,
  Children,
  width = &#39;366px&#39;,
  sizing = &#39;medium&#39;,
  weight = &#39;500&#39;,
  margin,
  letterSpacing = &#39;-0.64px&#39;,
  backgroundColor,
  onChange,
}) =&gt; {
  return (
    &lt;S.WrapDropdown htmlFor={id}&gt;
      &lt;S.SelectDropdown
        id={id}
        className={className}
        disable={disable}
        selected={selected}
        width={width}
        sizing={sizing}
        weight={weight}
        margin={margin}
        letterSpacing={letterSpacing}
        backgroundColor={backgroundColor}
        disabled={disable ? false : true}
        onChange={onChange}
      &gt;
        {Children}
      &lt;/S.SelectDropdown&gt;
      &lt;S.ContainerIcon&gt;
        &lt;Icon.IcDown
          fillColor={disable ? Color.GREY[600] : Color.GREY[500]}
          size={sizing === &#39;medium&#39; ? 24 : 20}
        /&gt;
      &lt;/S.ContainerIcon&gt;
    &lt;/S.WrapDropdown&gt;
  );
};
</code></pre>
<p>다른 라이브러리에서는 어떻게 구현이 되었는지 확인하는 과정에서 material-ui 라이브러리의 코드를 분석했습니다. icon component를 적용했는데 기능은 작동을 하고 있어서 코드를 분석해보니 새로운 css를 발견했습니다.</p>
<pre><code class="language-css">/* 아이콘을 클릭시 select가 활성화될 수 있도록 icon component에 적용 */
  pointer-events: none;</code></pre>
<p>pointer-events에 none을 적용하면 클릭을 할 수 없도록 비활성화 되어 icon은 보이지만 select을 가리지 않아 기능을 구현할 수 있었습니다.</p>
<p>SVG 콘텐츠에 pointer-events를 지정하지 않은 경우, visiblePainted 값과 동일한 방법을 사용합니다.</p>
<p>none 값의 경우 요소가 포인터 이벤트의 대상이 아님을 가리키는 동시에, 이벤트가 요소를 &quot;뚫고&quot; 들어가 &quot;아래&quot; 요소를 대상으로 하도록 만듭니다.</p>
<p>3시간동안 이러한 이슈를 해결하기 위해서 구글링을 했지만 원하는 결과를 찾지 못해서 미래의 누군가에게 필요한 정보일거라 생각이 들었습니다. </p>
<p>오늘 하루도 단짠단짠했습니다⭐️</p>
<h4 id="📒-reference">📒 Reference</h4>
<ul>
<li><p><a href="https://material-ui.com/components/selects/">material-ui</a></p>
</li>
<li><p><a href="https://developer.mozilla.org/ko/docs/Web/CSS/pointer-events">mozilla</a></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Atomic Desgin Pattern]]></title>
            <link>https://velog.io/@denmark-choco/Atomic-Desgin-Pattern</link>
            <guid>https://velog.io/@denmark-choco/Atomic-Desgin-Pattern</guid>
            <pubDate>Wed, 06 Jan 2021 12:21:23 GMT</pubDate>
            <description><![CDATA[<h1 id="⚙️-atomic-desgin-pattern">⚙️ Atomic Desgin Pattern</h1>
<p><img src="https://images.velog.io/images/denmark-choco/post/33db0b77-ad1d-4807-bf84-25bfc9411398/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-01-06%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%209.11.28.png" alt=""></p>
<p>아코믹 디자인 패턴은 가장 작은 단위의 컴포넌트를 만들어, 큰 단위로 쌓아나가며 각각의 UI 단위를 만들어 나가는 디자인 패턴입니다.</p>
<p>atoms에 해당하는 컴포넌트를 예를들면 Label, Button 등이 이에 해당됩니다. atoms를 조합하면 molecules가 되고 Organisms은 molecules의 큰 단위입니다. 이렇게 디자인을 적용하면 처음 컴포넌트를 구현하는 시간은 오래걸릴 수 있으나 atoms단위 컴포넌트들을 재사용성이 높게 구현한 경우 page구현시간은 단축이 가능합니다. 그리고 추후에 유지, 보수를 하는 경우에도 시간을 단축할 수 있습니다.</p>
<p>근무중인 기업에서 새로 적용하는 디자인 패턴으로 컴포넌트를 구현하기 전 어떤 방식으로 아토믹 디자인을 적용하고 분류할지 디자인팀과 의논을 하고 진행을 했습니다. 아토믹 디자인이 명확하게 정하기엔 고려할 부분과 각자의 관점에 따라 달라질 수 있어서 조금씩 다를 수 있습니다.</p>
<h4 id="📒-reference">📒 Reference</h4>
<ul>
<li><a href="https://github.com/connect-foundation/2019-12">Atomic Desgin Pattern</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[첫 취업을 하기까지..!❤️]]></title>
            <link>https://velog.io/@denmark-choco/%EC%B2%AB-%EC%B7%A8%EC%97%85%EC%9D%84-%ED%95%98%EA%B8%B0%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@denmark-choco/%EC%B2%AB-%EC%B7%A8%EC%97%85%EC%9D%84-%ED%95%98%EA%B8%B0%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Sun, 25 Oct 2020 06:06:27 GMT</pubDate>
            <description><![CDATA[<h1 id="⚙️-준비단계">⚙️ 준비단계</h1>
<p>올해 초부터 코딩을 시작해서 9개월간 정신없이 공부를 했고 코드스테이츠를 시작하고나서는 더 개발자의 세계에 빠져들었고 까먹고 있었던 나의 열정적인 모습을 다시 찾을 수 있었다. 공부를 하면서 울기도 하고 학교에서 선생님이 알려주면 받아먹는 방식이 아닌 구글링을 하면서 스스로 찾고 알아내야하는 공부방법에 당황하기도 했다. 하지만 적응기간없이 바로 실전에  투입되어 적응 할 수 밖에 없었다. 그러고 정신차려보니 나는 어느새 웹페이지를 만들면서 프로젝트를 진행하고 있었고 연초에는 상상도 못했던 대화들을 동기들과 나누면서 개발자다운(과거의 나와 비교해서..ㅎㅎ) 대화를 하고 있다는 것에 짜릿했고 신기했다. </p>
<p>사실 코드스테이츠의 수료는 3주가 지났었지만 아직 포트폴리오도 시작하지 못했고 스터디를 진행하면서 이력서를 수정하고 취업은 적어도 1달은 소요될거라 생각하고 준비를 했다. 이전에 코드스테이츠에서 진행한 선배 세션에서 이력서는 최소 100개는 지원하고 면접도 많이 보고 스킬이 어느정도 생기면 그때 취업할 수 있는 기회가 찾아온다는 말을 기억하고 있어서 천천히 준비를 해야겠다고 생각했다. </p>
<p>하지만 처음 생각과는 다르게 코드스테이츠에서 달렸는데 갑자기 여유를 가지고 스스로 공부를 하려고 하니 덜컥 겁이 났다. 이러다가 겨우 되찾은 나의 열정을 또 놓치고 이전의 게으른 나를 보게 될까봐 무서웠다. 그래서 이력서준비부터 스터디와 공부, 이력서 지원까지 모든일에 열정을 다해야지 밤에 잠을 잘 수 있었다. 그렇게 좋아하던 게임도 눈에 들어오지 않았다. 추석에 가족들과 시간을 보내지도 않았다. 지인들은 열심히 한다고 말을 해주었지만 동기들이 취업하고 떠난 자리에 혼자 덩그러니 혼자 남을까봐 나름 겁이 났던거 같다.</p>
<h1 id="🛠-재도전">🛠 재도전</h1>
<p>처음에는 이력서를 완성하자마자 여기저기 지원을 하기 시작했다. 매일 아침마다 합격메일이 있을까 확인을 했지만 &#39;안타깝게도&#39;라는 말로 시작하는 불합격 메일만 꾸준히 들어왔고 30군데이상 지원을 했는데 1군데도 서류통과를 하지 못했다. 처음에는 덤덤하게 예상한 결과라고 생각하고 받아들였는데 일주일이 넘어가니 걱정이 마음속에서 피어나기 시작했다. 이력서에 걸린 링크는 비틀리를 이용해서 링크를 들어와서 확인하는 면접관이 있는지 확인 할 수 있었다. 그래서 비틀리로 이력서의 링크를 얼마나 확인해주셨을까 확인을 해봤는데 결과는 아무도 링크를 타고 나의 노션이나 블로그에 들어오지 않는다는 것이었다.😭</p>
<p>원인을 찾던 중 멘토(나 혼자 멘토라고 생각하는 중이다)이자 지인인 현직 개발자분의 날카로운 피드백으로 원인을 알 수 있었고 이력서를 다시 작성하기 시작했다. 주니어로서 나의 열정과 발전가능성을 보여야겠다는 생각으로 수정을 했고 다시 지원을 했다. 이력서만 달라졌을 뿐인데 지원을 하자마자 면접이 일주일에 3개씩 잡히고 과제도 들어오기 시작했다. 물론 지원을 최소 50곳은 했었고 그 중에 4곳에서 서류통과가 되었다. </p>
<h1 id="🥳-첫-발걸음">🥳 첫 발걸음</h1>
<p>10월부터 서류가 통과되었다는 메일을 받을 수 있었다. 회사에 찾아가서 면접을 보기도 했고 행아웃이나 줌으로 화상면접을 보기도 했다. 알고리즘 문제를 풀기도 했고 기술질문을 받기도 했고 과제를 먼저 받아보기도 했다. 면접에서 분위기 좋았다고 생각을 했는데 불합격이 되기도 했고 다른 기술스택으로 거절할 수 밖에 없는 경우도 있었고 선임이 없는 경우도 있었다. </p>
<p>그러다가 한 기업에서 면접을 봤고 기술스택도 좋았으며 실력이 좋은 선임이 있는 회사에서 면접을 보게 되었다. 나의 이력서와 블로그, 기술영상, 깃헙에 커밋메세지까지 확인하시고 면접을 진행해서 좋은 분위기에서 면접을 진행 할 수 있었다. 합격여부는 그다음날 바로 전화로 전달받았고 바로 다음주부터 출근을 시작했다.</p>
<p>불안한 마음에 너무 급하게 서둘러서 취업하는 것은 아닐까 걱정했지만 기술스택도 좋았고 나의 이력서를 꼼꼼하게 봐주신 것, 그리고 빠르게 취업해서 배우는 것이 혼자서 공부를 하는 것 보다 더 많은 것을 얻을 수 있다는 생각이 들었어서 나의 직감을 믿기로 했다. 그리고 나는 기본적으로 인복이 좀 좋은 편이다.😆 </p>
<p>지금 이 글을 쓰는 오늘은 딱 회사 1주일다니고 첫 주말이다. 직장인에게 주말은 행.복.이라는 것을 지금 몸소 체험중에 있다. 첫 일주일을 다닌 소감은 &#39;힘들었지만 좋았다&#39;이다. 첫날은 다른 회사에 비해 팀원들이 많이 친하고 정말 분위기가 자유로워서 놀랐다. 개발자들은 각자 업무에 집중하고 이어폰끼고 조용한 분위기에서 업무가 진행된다고 들었는데 나의 예상과 달리 조용하기 보단 편안하게 수다를 즐기며 돈독한 느낌이 드는 밝은 분위기였다. 사람들이 다 성격이 너무 좋아서 나의 인복이 이렇게 잭팟을 터트리는구나 생각했다.</p>
<p>그리고 수요일부터 협업을 위한 개발환경을 배우기 시작했다. 스타트업이고 리뉴얼을 준비하고 있어서 빠른 업무를 위해서 개발환경도 빠르게 세팅하기로 했다. circleCI를 공부하고 적용해서 typescript와 GraphQL, storybook을 익히고 있다. 모든게 처음 접하다보니 한꺼번에 많은 것을 흡수하는데 시간이 좀 걸리거 같다. 평일과 주말에도 공부를 하고 급하지 않게 천천히 익혀나가보려고 한다. 물론 빨리 익히고 싶지만...나는 열심히 노력하는 비범하지 못한 개발자인걸...나의 모토는 포기하지 않고 꾸준히 조금씩 나아가는 것이기 때문에 열심히 공부를 하려 한다.</p>
<p>지금은 앞으로 1년간 경력을 쌓으면서 발전할 생각에 기분이 좋다. 일을 마치고 집에서 공부를 하는 것도 기대되고 재밌을거 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript]]></title>
            <link>https://velog.io/@denmark-choco/TypeScript-pt3k1hb3</link>
            <guid>https://velog.io/@denmark-choco/TypeScript-pt3k1hb3</guid>
            <pubDate>Fri, 16 Oct 2020 08:05:33 GMT</pubDate>
            <description><![CDATA[<h1 id="🤔-typescript란">🤔 TypeScript란?</h1>
<p>TypeScript는 MicroSoft에서 개발하고 유지/관리하는 오픈소스입니다. javascript의 상위호환으로 코드가 실행되기 전에 실행되는 도구이고 TS파일 컴파일을 통해 타입이나 유형이 올바른지 체크하여 오류 발생을 방지하고 정적 타입을 이용하여 코딩을 할 수 있도록 도와줍니다.</p>
<h2 id="⚙️-사용법">⚙️ 사용법</h2>
<h4 id="1-npm-i-typescript">1. npm i typescript</h4>
<h4 id="2-tsconfigjson-설정">2. tsconfig.json 설정</h4>
<p>tsconfig.json에서 TypeScript를 어떻게 javascrtipt로 변환하는지 정해준다</p>
<pre><code class="language-js">{
    &quot;compilerOptions&quot;: { // 실제 컴파일 할 경우 적용되는 옵션들
      &quot;module&quot;: &quot;commonjs&quot;, //어떤 모듈 방식으로 컴파일할지 설정
      &quot;target&quot;: &quot;ES2015&quot;, // 어떤 버전으로 컴파일할지 작성
      &quot;sourceMap&quot;: true, // 해당하는 .map 파일을 생성
      &quot;outDir&quot;: &quot;dist&quot; // 컴파일한 것들을 dist에 저장
    },
    &quot;include&quot;: [&quot;src/**/*&quot;], // 컴파일할 경로 설정
    &quot;exclude&quot;: [&quot;node_modules&quot;] // 컴파일 대상을 제외하는 옵션
}</code></pre>
<h4 id="3-컴파일">3. 컴파일</h4>
<p>타입스크립트는 .ts 확장자를 가진 파일로 작성할 수 있고, index.ts파일을 작성하고 터미널에 tsc를 작성하면 index.js와 index.js.map이 생성된다.</p>
<p>nodejs는 typescript를 이해하지 못하기 때문에 일반적인 javascript코드로 컴파일하는 작업이 필요하다</p>
<h2 id="💡-types">💡 Types</h2>
<p>TypeScript는 일반 변수, 매개 변수, 객체 속성 등에 타입을 지정할 수 있습니다.</p>
<pre><code class="language-js">// javascript
const name = &quot;Nicolas&quot;,
  age = 24,
  gender = &quot;male&quot;;

const sayHi = (name, age, gender?) =&gt; {
  console.log(`Hello ${name}, you are ${age}, you are a ${gender}`);
};

sayHi(name, age);</code></pre>
<p>위의 코드는 javascript 코드입니다. gender뒤에 ?는 필수가 아닌 선택적으로 값을 받는다는 의미입니다. 아래의 코드는 타입을 지정한 typescript입니다.</p>
<pre><code class="language-ts">// TypeScript
const sayHi = (name: string, age: number, gender?: string): string =&gt; {
  return `Hello ${name}, you are ${age}, you are a ${gender}`;
};

console.log(sayHi(&quot;Nicolas&quot;, 24, &quot;male&quot;));

export {};</code></pre>
<p>이와 같이 타입을 지정해줄 수 있습니다. 타입을 지정했는데 알맞은 타입이 입력되지 않으면 컴파일조차 진행되지 않고 코드 작성하는 시점에서 에러가 발생합니다.</p>
<p>타입 선언은 아래와 같습니다.</p>
<h4 id="1-불린-boolean">1. 불린: Boolean</h4>
<pre><code class="language-ts">let isDone: boolean = false;</code></pre>
<h4 id="2-숫자-number">2. 숫자: Number</h4>
<pre><code class="language-ts">let num: number;
let integer: number = 6;
let float: number = 3.14;
let hex: number = 0xf00d; // 61453
let binary: number = 0b1010; // 10
let octal: number = 0o744; // 484
let infinity: number = Infinity;
let nan: number = NaN;</code></pre>
<h4 id="3-문자열-string">3. 문자열: String</h4>
<pre><code class="language-ts">let str: string;
let red: string = &#39;Red&#39;;
let green: string = &quot;Green&quot;;
let myColor: string = `My color is ${red}.`;
let yourColor: string = &#39;Your color is&#39; + green;</code></pre>
<h4 id="4-배열-array">4. 배열: Array</h4>
<pre><code class="language-ts">// 문자열만 가지는 배열
let fruits: string[] = [&#39;Apple&#39;, &#39;Banana&#39;, &#39;Mango&#39;];
// Or
let fruits: Array&lt;string&gt; = [&#39;Apple&#39;, &#39;Banana&#39;, &#39;Mango&#39;];

// 숫자만 가지는 배열
let oneToSeven: number[] = [1, 2, 3, 4, 5, 6, 7];
// Or
let oneToSeven: Array&lt;number&gt; = [1, 2, 3, 4, 5, 6, 7];

// 유니언 타입(다중 타입)
let array: (string | number)[] = [&#39;Apple&#39;, 1, 2, &#39;Banana&#39;, &#39;Mango&#39;, 3];
// Or
let array: Array&lt;string | number&gt; = [&#39;Apple&#39;, 1, 2, &#39;Banana&#39;, &#39;Mango&#39;, 3];

// 항목의 값을 단언할 수 없다
let someArr: any[] = [0, 1, {}, [], &#39;str&#39;, false];</code></pre>
<h4 id="5-튜플-tuple--정해진-타입의-고정된-길이length-배열">5. 튜플: Tuple =&gt; 정해진 타입의 고정된 길이(length) 배열</h4>
<pre><code class="language-ts">// Tuple
let user: [number, string, boolean] = [1234, &#39;HEROPY&#39;, true];
console.log(user[0]); // 1234
console.log(user[1]); // &#39;HEROPY&#39;
console.log(user[2]); // true

// readonly 키워드를 사용해 읽기 전용 튜플을 생성
let a: readonly [string, number] = [&#39;Hello&#39;, 123];</code></pre>
<h4 id="6-열거형-enum-">6. 열거형: Enum =&gt;</h4>
<pre><code class="language-ts">// 기본적으로 0부터 시작하며 값은 1씩 증가
enum Week {
  Sun, //0
  Mon, //1
  Tue, //2
  Wed, //3
  Thu, //4
  Fri, //5
  Sat  //6
}

// 수동으로 값을 변경할 수 있으며, 값을 변경한 부분부터 다시 1씩 증가
enum Week {
  Sun, //0
  Mon = 22, //22
  Tue, //23
  Wed, //24
  Thu, //25
  Fri, //26
  Sat  //27
}</code></pre>
<h4 id="7-모든-타입-any">7. 모든 타입: Any</h4>
<pre><code class="language-ts">const list: any[] = [1, true, &#39;Anything!&#39;];</code></pre>
<h4 id="8-알-수-없는-타입-unknown">8. 알 수 없는 타입: Unknown</h4>
<pre><code class="language-ts">let a: any = 123;
let u: unknown = 123;

let v1: boolean = a; // 모든 타입(any)은 어디든 할당할 수 있습니다.
let v2: number = u; // 알 수 없는 타입(unknown)은 모든 타입(any)을 제외한 다른 타입에 할당할 수 없습니다.
let v3: any = u; // OK!
let v4: number = u as number; // 타입을 단언하면 할당할 수 있습니다.</code></pre>
<h4 id="9-객체-object">9. 객체: Object</h4>
<pre><code class="language-ts">let obj: object = {};
let arr: object = [];
let func: object = function () {};

let userA: { name: string, age: number } = {
  name: &#39;HEROPY&#39;,
  age: 123
};

let userB: { name: string, age: number } = {
  name: &#39;HEROPY&#39;,
  age: false, // Error
  email: &#39;thesecon@gmail.com&#39; // Error
};</code></pre>
<h4 id="10-유니언union--2개-이상의-타입을-허용하는-경우">10. 유니언(Union) =&gt; 2개 이상의 타입을 허용하는 경우</h4>
<pre><code class="language-ts">let union: (string | number);
union = &#39;Hello type!&#39;;
union = 123;
union = false; // Error - TS2322: Type &#39;false&#39; is not assignable to type &#39;string | number&#39;.</code></pre>
<h4 id="11-인터섹션intersection--ampersand를-사용해-2개-이상의-타입을-조합하는-경우">11. 인터섹션(Intersection) =&gt; &amp;(ampersand)를 사용해 2개 이상의 타입을 조합하는 경우</h4>
<pre><code class="language-ts">// 기존 타입들이 조합 가능하다면 인터섹션을 활용할 수 있습니다.
interface IUser {
  name: string,
  age: number
}
interface IValidation {
  isValid: boolean
}
const heropy: IUser = {
  name: &#39;Heropy&#39;,
  age: 36,
  isValid: true // Error -  TS2322: Type &#39;{ name: string; age: number; isValid: boolean; }&#39; is not assignable to type &#39;IUser&#39;.
};
const neo: IUser &amp; IValidation = {
  name: &#39;Neo&#39;,
  age: 85,
  isValid: true
};</code></pre>
<h2 id="📁-interfaces">📁 interfaces</h2>
<p>interface 키워드를 사용해 값이 특정한 형태(shape)를 제약하고 interface는 컴파일되지 않습니다.</p>
<pre><code class="language-ts">interface Human {
  name: string;
  age: number;
  gender: string;
}

const person = {
  name: &quot;nicolas&quot;,
  age: 22,
  gender: &quot;male&quot;
};

const sayHi = (person: Human): string =&gt; {
  return `Hello ${person.name}, you are ${person.age}, you are a ${
    person.gender
  }!`;
};

console.log(sayHi(person));

export {};</code></pre>
<h2 id="📁-classes">📁 classes</h2>
<p>interface는 컴파일되지 않지만 classes는 컴파일이 되고 코드를 컨트롤 할 수 있게 해줍니다.
클래스가 어떤 속성을 가져야하는지 그 속성이 어떤 권한을 가지고 있는지 선언해야합니다.</p>
<h4 id="접근-제한자">접근 제한자</h4>
<ul>
<li><p>public (어디서든 접근 가능)</p>
</li>
<li><p>private (외부 접근 불가)</p>
</li>
<li><p>protected (내부접근 가능, 서브클래스 접근 또한 가능)</p>
</li>
</ul>
<pre><code class="language-ts">class Human {
  public name: string;
  private age: number;
  public gender: string;
  constructor(name: string, age: number, gender: string) {
    this.name = name;
    this.age = age;
    this.gender = gender;
  }
}

const lynn = new Human(&quot;Lynn&quot;, 18, &quot;female&quot;);

  const sayHi = (lynn: Human): string =&gt; {
    return `Hello ${lynn.name}, you are ${lynn}, you are a ${
      lynn.gender
    }!`;
  };

  console.log(sayHi(lynn));

  export {};</code></pre>
<h4 id="📚-reference">📚 Reference</h4>
<ul>
<li><p><a href="https://www.typescriptlang.org/docs/handbook/intro.html">TypeScript</a>
<code>https://www.typescriptlang.org/docs/handbook/intro.html</code></p>
</li>
<li><p><a href="https://heropy.blog/2020/01/27/typescript/">한눈에 보는 타입스크립트</a>
<code>https://heropy.blog/2020/01/27/typescript/</code></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[버블링(Bubbling) & 캡처링(Capturing)]]></title>
            <link>https://velog.io/@denmark-choco/%EB%B2%84%EB%B8%94%EB%A7%81Bubbling-%EC%BA%A1%EC%B2%98%EB%A7%81Capturing</link>
            <guid>https://velog.io/@denmark-choco/%EB%B2%84%EB%B8%94%EB%A7%81Bubbling-%EC%BA%A1%EC%B2%98%EB%A7%81Capturing</guid>
            <pubDate>Mon, 12 Oct 2020 17:08:58 GMT</pubDate>
            <description><![CDATA[<h1 id="✨-event를-처리하는-방법">✨ Event를 처리하는 방법</h1>
<h4 id="1-html-요소에-직접-이벤트-처리기-속성을-설정">1. HTML 요소에 직접 이벤트 처리기 속성을 설정</h4>
<p>직접 태그에 적용하는 방법입니다. </p>
<pre><code class="language-html">&lt;input type=&quot;button&quot; onclick=&quot;buttonClick()&quot;&gt;</code></pre>
<h4 id="2-dom-요소-객체의-이벤트-처리기-프로퍼티에-설정">2. DOM 요소 객체의 이벤트 처리기 프로퍼티에 설정</h4>
<p>DOM 요소를 가져와서 on을 이용해서 이벤트를 적용하는 방법입니다.</p>
<pre><code class="language-js">let btn = document.getElementById(&quot;button&quot;);
btn.onclick = buttonClick();</code></pre>
<h4 id="3-addeventlistener">3. addEventListener</h4>
<blockquote>
<p>target.addEventListener(type, listener[, options]);</p>
</blockquote>
<p>javascript에는 이벤트를 추가하는 방법 중 가장 추천하는 방법은 addEventListener입니다. 이유는 타겟에 같은 이벤트를 중복으로 등록할 수 있기 때문입니다.</p>
<ul>
<li><strong>[ options ]</strong> 이벤트 리스너에 대한 특성을 지정하는 옵션 객체입니다<ul>
<li>capture : 세번째 인자에서 useCapture는 용어 그대로 캡처링 여부를 뜻합니다. 기본값은 false이고 ture로 설정해주면 이벤트가 전파됩니다.</li>
</ul>
</li>
</ul>
<pre><code class="language-js">let button = document.querySelector(&#39;button&#39;);
button.addEventListener(&#39;click&#39;, addItem);

function addItem(event) {
    console.log(event);
}</code></pre>
<h2 id="🧼-버블링bubbling">🧼 버블링(Bubbling)</h2>
<p><img src="https://images.velog.io/images/denmark-choco/post/d0af78ce-65cd-42c6-ba7e-b03530bfaa4f/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-10-13%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%201.51.10.png" alt=""></p>
<p>버블링은 타겟에 이벤트가 발생하면 가장 최상단의 조상 요소를 만날 때까지 이벤트 핸들러가 동작합니다. </p>
<p>아래의 코드에서 p태그를 클릭하면 상단의 form태그까지 이벤트가 순차적으로 발생하게 됩니다. </p>
<pre><code class="language-html">&lt;form onclick=&quot;alert(&#39;form&#39;)&quot;&gt;FORM
  &lt;div onclick=&quot;alert(&#39;div&#39;)&quot;&gt;DIV
    &lt;p onclick=&quot;alert(&#39;p&#39;)&quot;&gt;P&lt;/p&gt;
  &lt;/div&gt;
&lt;/form&gt;</code></pre>
<p>만약 이벤트 전파를 방지하고 싶은 경우, <strong>event.stopPropagation()</strong>를 사용하면 됩니다.</p>
<pre><code class="language-html">&lt;body onclick=&quot;alert(`버블링은 여기까지 도달하지 못합니다.`)&quot;&gt;
  &lt;button onclick=&quot;event.stopPropagation()&quot;&gt;클릭해 주세요.&lt;/button&gt;
&lt;/body&gt;</code></pre>
<h2 id="📷-캡처링capturing">📷 캡처링(Capturing)</h2>
<p>캡처링은 버블링과 반대 방형으로 진행되는 이벤트 전파 방식입니다. 최상위 조상에서 타겟까지 이벤트가 전파되는 과정입니다.</p>
<h4 id="📚-reference">📚 Reference</h4>
<ul>
<li><p><a href="https://ko.javascript.info/bubbling-and-capturing">버블링과 캡처링</a>
<code>https://ko.javascript.info/bubbling-and-capturing</code></p>
</li>
<li><p><a href="https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/">이벤트 버블링, 이벤트 캡처 그리고 이벤트 위임까지</a>
<code>https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/</code></p>
</li>
<li><p><a href="https://mygumi.tistory.com/315">이벤트 버블링과 캡처링</a>
<code>https://mygumi.tistory.com/315</code></p>
</li>
<li><p><a href="https://developer.mozilla.org/ko/docs/Web/API/EventTarget/addEventListener">EventTarget.addEventListener()</a>
<code>https://developer.mozilla.org/ko/docs/Web/API/EventTarget/addEventListener</code></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Lifecycle, React Hook lifeCycle]]></title>
            <link>https://velog.io/@denmark-choco/React-Lifecycle-React-Hook-lifeCycle</link>
            <guid>https://velog.io/@denmark-choco/React-Lifecycle-React-Hook-lifeCycle</guid>
            <pubDate>Tue, 06 Oct 2020 14:21:15 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>처음 react를 공부하면서 생명주기도 같이 <a href="https://velog.io/@denmark-choco/javascriptReact#1-data-flow">블로깅</a> 했었습니다. 하지만 최근에 프로젝트를 하면서 react의 생명주기와 react Hook의 생명주기가 어떤 차이가 있는지 궁금했습니다. 오늘은 react와 react hook의 생명주기를 비교하고 블로깅했습니다😊</p>
</blockquote>
<h1 id="⭐️-react-lifecycle">⭐️ React Lifecycle</h1>
<p>React는 컴포넌트가 실행되거나 업데이트되거나 제거될 때 특정 메서드를 호출합니다.</p>
<p><img src="https://images.velog.io/images/denmark-choco/post/bb8c4054-e3dc-466d-8aec-ca6c232c540c/1_cEWErpe-oY-_S1dOaT1NtA.jpeg" alt=""></p>
<h2 id="mount마운트">[Mount(마운트)]</h2>
<p>컴포넌트 인스턴스가 생성되어 DOM상에 삽입될 때 호출됩니다.</p>
<h4 id="constructor--컴포넌트가-마운트되기-전에-호출">constructor() =&gt; 컴포넌트가 마운트되기 전에 호출</h4>
<h4 id="render--컴포넌트를-dom에-마운트하기-위해-호출">render =&gt; 컴포넌트를 DOM에 마운트하기 위해 호출</h4>
<h4 id="componentdidmount--컴포넌트가-마운트된-직후-즉-트리에-삽입된-직후에-호출">componentDidMount =&gt; 컴포넌트가 마운트된 직후, 즉 트리에 삽입된 직후에 호출</h4>
<h2 id="update업데이트">[Update(업데이트)]</h2>
<h4 id="render--컴포넌트를-dom에-마운트하기-위해-호출-1">render =&gt; 컴포넌트를 DOM에 마운트하기 위해 호출</h4>
<h4 id="componentdidupdate--갱신이-일어난-직후에-호출">componentDidUpdate =&gt; 갱신이 일어난 직후에 호출</h4>
<hr>
<h1 id="⭐️-react-hook-lifecycle">⭐️ React Hook lifeCycle</h1>
<p>React Hook은 함수형 component에서 클래스형 component의 기능을 구현한 개념입니다. 예를들면 클래스에서만 사용 가능했던 state를 hook을 이용해 함수형 component에서도 useState를 이용해서 상태변수를 선언할 수 있습니다.그리고 React Hook에서는 useEffect를 통해 react클래스의 componentDidMount나 componentDidUpdate, componentWillUnmount와 같은 목적으로lifeCycle를 관리합니다.</p>
<p><img src="https://images.velog.io/images/denmark-choco/post/45c244b4-0e73-4662-b4ac-d10bebab15eb/cc006f00-a420-11e9-99a6-d0bdf5f0c7bb.png" alt=""></p>
<h2 id="useeffect">[useEffect]</h2>
<h3 id="1-componentdidmount-componentdidupdate-수행">1. componentDidMount, componentDidUpdate 수행</h3>
<p>useEffect는 컴포넌트 안에서 불러내어 state변수나 props에 접근이 가능하고, 기본적으로 첫번째 렌더링과 이후의 모든 업데이트에서 수행됩니다. 두번째 인자로 조건을 걸어 첫번째 렌더링이나 특정한 조건일때만 수행되도록 하는 것도 가능합니다.</p>
<pre><code class="language-js">  useEffect(() =&gt; {
    // 브라우저 API를 이용하여 문서 타이틀을 업데이트합니다.
    document.title = `You clicked ${count} times`;
  });</code></pre>
<h3 id="2-정리clean-up의-실행">2. 정리(clean-up)의 실행</h3>
<p>모든 effect는 정리를 위한 함수를 반환할 수 있습니다. 이 점이 구독의 추가와 제거가 하나의 effect를 구성하는 것입니다. 정리되는 시점은 컴포넌트가 마운트 해제되는 때에 실행됩니다. </p>
<pre><code class="language-js">  useEffect(() =&gt; {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // effect 이후에 어떻게 정리(clean-up)할 것인지 표시합니다.
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });</code></pre>
<h3 id="3-effect를-건너뛰어-성능-최적화">3. Effect를 건너뛰어 성능 최적화</h3>
<p>모든 렌더링 이후에 effect를 정리하거나 적용하는 것이 때때로 성능 저하를 발생시키는 경우도 있습니다. 특정 값들이 리렌더링 시에 변경되지 않는다면 effect를 건너뛰도록 할 수 있습니다. useEffect는 선택적으로 두번째 인수를 배열로 넘기면 가능합니다.</p>
<pre><code class="language-js">useEffect(() =&gt; {
  document.title = `You clicked ${count} times`;
}, [count]); // count가 바뀔 때만 effect를 재실행합니다.</code></pre>
<hr>
<h4 id="💡-reference">💡 Reference</h4>
<ul>
<li><a href="https://ko.reactjs.org/docs/react-component.html">REACT 공식문서</a>
<code>https://ko.reactjs.org/docs/react-component.html</code></li>
</ul>
<ul>
<li><p><a href="https://velog.io/@cyranocoding/React-Life-Cycle-%EC%8B%9C%EB%A6%AC%EC%A6%88Mount-%ED%8E%B8">React Life Cycle 시리즈(Mount 편)</a>
<code>https://velog.io/@cyranocoding/React-Life-Cycle-%EC%8B%9C%EB%A6%AC%EC%A6%88Mount-%ED%8E%B8</code></p>
</li>
<li><p><a href="https://ko.reactjs.org/docs/hooks-overview.html">Hook 개요 공식문서</a>
<code>https://ko.reactjs.org/docs/hooks-overview.html</code></p>
</li>
<li><p><a href="https://medium.com/@krpeppermint100/js-useeffect%EB%A5%BC-%ED%86%B5%ED%95%9C-react-hooks%EC%9D%98-lifecycle-%EA%B4%80%EB%A6%AC-3a65844bcaf8">[JS]useEffect를 통한 React Hooks의 Lifecycle 관리</a>
<code>https://medium.com/@krpeppermint100/js-useeffect%EB%A5%BC-%ED%86%B5%ED%95%9C-react-hooks%EC%9D%98-lifecycle-%EA%B4%80%EB%A6%AC-3a65844bcaf8</code></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드스테이츠 수료🥳]]></title>
            <link>https://velog.io/@denmark-choco/%EC%BD%94%EB%93%9C%EC%8A%A4%ED%85%8C%EC%9D%B4%EC%B8%A0-%EC%88%98%EB%A3%8C</link>
            <guid>https://velog.io/@denmark-choco/%EC%BD%94%EB%93%9C%EC%8A%A4%ED%85%8C%EC%9D%B4%EC%B8%A0-%EC%88%98%EB%A3%8C</guid>
            <pubDate>Tue, 29 Sep 2020 13:52:01 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/denmark-choco/post/ab622079-3483-4eef-8fd9-e87dde3c7a53/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-09-29%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.51.18.png" alt=""></p>
<h1 id="수료">수료</h1>
<p>시작할때에는 20주동안 고등학생과 같은 생활을 할 수 있을까 걱정이 많았다. 시작하는 날이 올수록 걱정으로 잠이 안오고 잘 버틸 수 있을까에 대한 답이 없는 고민으로 몇일을 보냈는데 수료날이 오다니...! 감동😭 코딩을 시작하고 나의 인생에 터닝포인트를 지나고 있다는 생각이 든다. </p>
<p>올해 초 처음으로 생활코딩으로 html을 배우고 코딩을 처음 접하게 되었고 코딩이 이런거구나 라는 생각을 할 때 javascript를 만나고 전혀 다른 느낌의 코딩이 나타나서 깜짝 놀랐었고 처음 코드스테이츠에서 했던 무엇을 모르는지 알 수 있게 된다는 말을 이해하게 되고 지금은 배울게 많고 무엇을 해야할지 알게 되어 더 정신없이 지내고 있다. </p>
<p>코드스테이츠는 확실히 과정이 알차다. 처음에는 왜 알려준다고 하고 안 알려주는 거지...내돈!!이라고 생각했다. 아마 나와 같은 생각을 한 동기들이 있었을 꺼라 생각한다. 지금까지 공부하는 방법은 선생님이 알려주면 우리는 외우고 반복하는 것이였는데 개발자 공부는 전혀 다른 방법으로 알려주고 다른 방법으로 접근하는 것이 이상했고 핑계라고 생각했다. 수료를 마친 후 지금은 완벽한 공부방법이었다고 생각한다. 내가 왜 직접해야하는지 이유를 경험으로 믿음이 생겼고 이 방법말고는 개발자의 공부를 하는 것은 어렵다는 것을 알았다. </p>
<p>수료를 하고 과정은 끝이 났지만 배움은 이제 시작이라는 생각이 들었고 배운것을 나누고 공유하는 문화를 가진 개발자를 사랑하게 되었고 협업하는 것에 중독되어 지금은 갈증이 난다. 좋아하는 게임을 스스로 중단하고 공부에 이렇게 즐거움을 느낄 수 있다고 1도 예상할 수 없었는데 지금은 매일매일 어떤걸 공부할지 생각하고 계획을 세우는 게 재밌기까지 하다. 동기들이 나보고 열심히한다고 말해주는데 기분이 좋다. 열심히하는 것처럼 보이는데 힘들다고 느껴지지 않는다. 이상한 경험을 하고 있다. 공부를 열심히 하는 건 힘든거라고 생각했는데...ㅎㅎ</p>
<p>이제 동기들과 20주간 잡아왔던 공부흐름을 그대로 이어가 스터디를 진행하고 있다. 스터디 계획을 정하고 같이 공부를 했을때 좋은 영향을 받았던 동기몇명에게 같이 스터디할것을 권했고 지금은 5명의 동기와 진행하고 있다.</p>
<h1 id="스터디">스터디</h1>
<p><img src="https://images.velog.io/images/denmark-choco/post/232b88af-b72b-4ea9-a95f-c81300bfd3aa/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-09-29%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.48.07.png" alt=""></p>
<ul>
<li><p>Rule
팀원들과 매일 오전 10시부터 오후 6시까지 모각코를 진행한다. 행아웃에서 얼굴이나 화면공유를 진행하고 오후 5시 30분에는 서로 공부한 내용을 공유하기로 했다.</p>
</li>
<li><p>알고리즘 스터디
그리고 가장 중요한 알고리즘 스터디!! 
매주 각자 1문제씩 선정해서 공유하고 본인문제 외 가능한만큼만 문제를 풀어오면 된다. 매주 토요일 오전 10시 코드리뷰를 진행한다. 문제는 깃헙과 노션으로 공유하기로 했다.</p>
</li>
<li><p>javascript 스터디
이 스터디는 동기분중 한분이 추천해주셨는데 너무 기대되는 스터디이다. 매주 한명이 선정되어 &#39;You Don&#39;t Know JS&#39;책의 주제를 정해 발표를 하는 것이다. 내용이 좋아서 강연과 토론의 중간정도의 스터디가 될 거 같다. 이것도 깃헙과 노션에 공유하기로 했다. </p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[FinalProject를 마무리하며]]></title>
            <link>https://velog.io/@denmark-choco/FinalProject%EB%A5%BC-%EB%A7%88%EB%AC%B4%EB%A6%AC%ED%95%98%EB%A9%B0</link>
            <guid>https://velog.io/@denmark-choco/FinalProject%EB%A5%BC-%EB%A7%88%EB%AC%B4%EB%A6%AC%ED%95%98%EB%A9%B0</guid>
            <pubDate>Wed, 23 Sep 2020 16:29:32 GMT</pubDate>
            <description><![CDATA[<h1 id="meekcy">Meekcy</h1>
<h2 id="✨intro">✨Intro</h2>
<ul>
<li><p>프로젝트 명 : Meekcy</p>
</li>
<li><p>프로젝트 형태 : 기업협업 프로젝트</p>
</li>
<li><p>팀원 : 장봄(팀장), 박재영, 김동훈, 황태하</p>
</li>
<li><p>배포링크 : <a href="http://meekcy.s3-website.ap-northeast-2.amazonaws.com">http://meekcy.s3-website.ap-northeast-2.amazonaws.com</a></p>
</li>
<li><p>노션링크 : <a href="https://www.notion.so/Meekcy-b71c14b9da38493a9e125807b9c2f100">https://www.notion.so/Meekcy-b71c14b9da38493a9e125807b9c2f100</a></p>
</li>
</ul>
<h2 id="🔥project">🔥Project</h2>
<p><img src="https://images.velog.io/images/denmark-choco/post/0143e034-d18e-4bf8-9897-88e93ac22c33/erik-witsoe-GF8VvBgcJ4o-unsplash.jpg" alt=""></p>
<p>소중한 사람들과 만나고 싶지만 만남에 제약이 있을때 Meekcy에서 만나 추억을 만드세요. </p>
<p>Meekcy는 시간과 장소에 제약을 받지 않습니다.</p>
<p>Meekcy는 현재 상영중인 영화, 드라마, 교육 등 다양한 컨텐츠로 지루할 틈이 없습니다. 또한 원하는 장소와 편한시간에 지인들과 컨텐츠를 시청하면서 동시에 채팅으로 소통을 할 수 있는 Streaming Service입니다. Meekcy는 같은 경험을 공유하는 문화를 만듭니다. </p>
<p>몸은 멀지만 마음은 더 가까워지세요!</p>
<h3 id="사용-스택-및-스택-아키택쳐">사용 스택 및 스택 아키택쳐</h3>
<ul>
<li><p>Stack</p>
<blockquote>
<p><img src="https://images.velog.io/images/denmark-choco/post/c0d373e0-d270-4aad-a7db-06f18ea78ac2/My%20First%20Board%20(5).jpg" alt=""></p>
</blockquote>
</li>
<li><p>Stack Architecture</p>
<blockquote>
<p><img src="https://images.velog.io/images/denmark-choco/post/221ebf98-ef37-4511-a29d-5722b9e23e60/My%20First%20Board%20(6).jpg" alt=""></p>
</blockquote>
</li>
</ul>
<h3 id="기능-flow">기능 Flow</h3>
<ul>
<li><p>UX Flow (Web)</p>
<blockquote>
<p><img src="https://images.velog.io/images/denmark-choco/post/92e94101-b81c-4f24-bff1-8475a3446541/UX%20Flow%20(Web)01.png" alt="">
<img src="https://images.velog.io/images/denmark-choco/post/fe1f8f4f-4960-4bbf-b28b-3518cdcfa2ad/UX%20Flow%20(Web)02.png" alt="">
<img src="https://images.velog.io/images/denmark-choco/post/6814c99d-7fb5-46ed-af4b-8d4850f535c6/UX%20Flow%20(Web)03.png" alt="">
<img src="https://images.velog.io/images/denmark-choco/post/0d2e3fdd-f954-4d46-81b7-22f491127b3e/UX%20Flow%20(Web)04.png" alt=""></p>
</blockquote>
</li>
<li><p>UX Flow (Mobile)</p>
<blockquote>
<p><img src="https://images.velog.io/images/denmark-choco/post/155ff489-1388-413f-86bd-ba2316bcecf4/UX%20Flow%20(Mobile)01.jpg" alt="">
<img src="https://images.velog.io/images/denmark-choco/post/67054645-f029-4a93-a822-101aff325cae/UX%20Flow%20(Mobile)02.jpg" alt=""></p>
</blockquote>
</li>
</ul>
<h2 id="⭐stack">⭐Stack</h2>
<h4 id="stack">Stack</h4>
<p>React, redux, styled-reset, styled-Component, axios, socket.io</p>
<h4 id="works">Works</h4>
<ol>
<li><code>공동 작업</code><ul>
<li>Software Requirement(SR) : 서비스기획, 기능리스트업, 페이지별 기획, 포지션 내 기능 분배, 와이어프레임, 디자인</li>
<li>github의 Task, Project 작성</li>
<li>오전회의 및 기업미팅</li>
</ul>
</li>
<li><code>개발 환경 설정</code><ul>
<li>Presentational and Container Components패턴 적용 및 라우터 분리</li>
<li>styled-components와 styled-reset를 이용한 CSS기본환경 적용</li>
<li>Logo파비콘적용</li>
<li>LoadingPage와 WarningPage 구현</li>
<li>dotenv로 환경변수설정</li>
</ul>
</li>
<li><code>LoginPage</code><ul>
<li>react-google-login을 이용해 GoogleLogin 기능 구현</li>
<li>axios psot로 서버에 구글토큰 전달 후 JWT토큰을 전달 받는 flow구현</li>
<li>JWT토큰 localstorage에 저장 후 useEffect와 redux를 이용한 로그인 유지 기능 구현</li>
<li>로그인이 되지 않은 사용자 진입시 LoginPage로 연결기능 구현</li>
</ul>
</li>
<li><code>ListPage</code><ul>
<li>ListPage에 시청중인 리스트의 endTime을 progress로 구현</li>
<li>styled-components를 이용한 css와 반응형 구현</li>
</ul>
</li>
<li><code>Modal창</code><ul>
<li>Modal창에 서버에서 보내준 trailer를 연결한 예고편 버튼 구현</li>
<li>Modal창의 useLayoutEffect를 이용한 text반응형 구현</li>
<li>styled-components를 이용한 css와 반응형 구현</li>
</ul>
</li>
<li><code>StreamingPage</code><ul>
<li>StreamingPage의 채팅창 토글아이콘 구현 및 Layout과 반응형 구현</li>
<li>video의 play, pause, currentTime변경시 방에 있는 다른 사용자들에게 환경전달하는 socket기능 구현</li>
<li>socket을 통해 send된 video환경을 적용하는 기능 구현</li>
<li>이미 방에 접속중인 유저가 새 링크로 다른 방에 접속시 warning기능 구현</li>
<li>이미 방에 접속중인 유저가 새 방을 생성시 알림기능 구현</li>
<li>styled-components를 이용한 css와 반응형 구현</li>
</ul>
</li>
<li><code>Deployment</code><ul>
<li>S3배포</li>
</ul>
</li>
</ol>
<h2 id="📝회고">📝회고</h2>
<p>첫번째 프로젝트와 비교하면 마지막 프로젝트에서는 성장이 느껴졌다. </p>
<p>프로젝트를 시작하기 전 SR의 중요성과 이것들을 정리하는 문서화 작업이 좋아졌고 더 세심하고 상세하게 준비를 할 수 있게 되었다. notion을 이용해서 팀원들과 문서화를 했고 마크다운을 사용하는데 자연스러워졌다. 지금은 노션을 사용하는 것이 더 편해졌고 다양한 도전을 시도해보고 있다. </p>
<p>gitHub의 사용도 익숙해졌다. 이전에는 remote하고 pull을 받는것도 긴장되는 작업이었고 두려웠지만 지금은 두려움이 없어지고 그 자리에 흥미가 생겼다. task카드를 작성하고 sprint를 구별하고 label을 만들고 commit메세지도 vim을 이용해서 통일했다. 이제는 readme를 꾸미고 github을 꾸미고 싶어졌다. 프로젝트가 끝났지만 주말에 팀원들과 github을 꾸미는 것을 익히기로 했다.</p>
<p>그리고 기업협업을 하게 되어 기업의 담당자분과 매주 미팅을 진행했고 코드리뷰를 받았으며 기업에 방문해서 회사분위기와 회사팀원들과의 미팅을 가지고 많은 조언과 생각을 공유했다. 개발자로 공부를 했고 진짜 취업 할 준비를 해야겠다는 생각이 들었다. 좋은 기업이었고 팀원들간에 따뜻한 분위기가 너무 좋았어서 나도 빨리 취업을 해서 팀원들과 협업을 하고 싶다는 생각이 들었다.</p>
<p>가장 중요한  프로젝트에서 코딩을 하는 것, 새로운 기술을 받아들이고 적용하는 시간이 줄었다. 이건 좋은 습관을 가져와서 러닝커프가 조금은 줄었다고 생각한다. 그 방법은 아주 심플하다. 공식문서를 보고 started를 보고 작은 프로젝트로 직접 실험을 하고 디버깅을 해보고 콘솔로 흐름을 파악한 뒤 프로젝트에 적용하는 방법으로 진행했다. 귀찮은 방법일 수 있지만 확실하게 이해하고 적용하는데 더 적은 시간이 걸렸으며 디버깅을 하거나 버그발견시에도 더 빨리 해결할 수 있었다.</p>
<p>프로젝트가 끝나고 하루는 코드를 리펙토링하고 왜 이렇게 코드를 작성했는지 공부하는 시간을 가졌다. 다른 팀원들의 코드도 같이 공부하고 나의 코드도 다시보고 정리 할 수 있어서 나의 프로젝트라고 당당하게 말할 수 있겠다고 생각했다.</p>
<p>나중에 개발자로 취업하고 이 글을 보면 어떤 기분일지 궁금하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[GoogleLogin 후 로그인 유지하기 ]]></title>
            <link>https://velog.io/@denmark-choco/GoogleLogin-%ED%9B%84-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%9C%A0%EC%A7%80%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@denmark-choco/GoogleLogin-%ED%9B%84-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%9C%A0%EC%A7%80%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 03 Sep 2020 14:28:31 GMT</pubDate>
            <description><![CDATA[<h1 id="로그인-유지">로그인 유지</h1>
<p>새로고침을 해도 로그인을 유지하기 위해서 react-redux를 이용했다.</p>
<p>isLogin이라는 상태값을 만들어서 기본값을 false로 하고 loacalStorage에 token값이 있는지 확인하고 token이 있는 경우에는 action을 전달해서 isLogin의 값을 true로 변경해서 로그인을 유지할 수 있다. 그리고 token값이 없거나 로그아웃으로 token을 삭제한 경우 isLogin이 false가 되어 로그인 화면으로 돌아가게 하는 것을 목표로 만들었다.</p>
<h2 id="react-redux의-store와-action-reducer">react-redux의 store와 action, reducer</h2>
<p>처음으로 react-redux를 구현하기때문에 한 파일에 전부 구현을 한 후 action, reducer, store로 나누기로 했다. </p>
<pre><code class="language-js">import { createStore } from &#39;redux&#39;;
import { composeWithDevTools } from &#39;redux-devtools-extension&#39;;

const LOGINCHECK = &#39;logincheck&#39;;
const LOGOUTCHECK = &#39;logoutcheck&#39;;

export const loginCheck = () =&gt; {
    return {
        type: LOGINCHECK,
    };
};

export const logoutClickevent = () =&gt; {
    console.log(&#39;logoutaction&#39;);
    return {
        type: LOGOUTCHECK,
    };
};

const initialStore = { isLogin: false };

const reducer = (state = initialStore, action) =&gt; {
    switch (action.type) {
        case LOGINCHECK:
            return { ...state, isLogin: true };
        case LOGOUTCHECK:
            console.log(&#39;enter&#39;);
            return { ...state, isLogin: false };
        default:
            return state;
    }
};

const store = createStore(reducer, composeWithDevTools());

export default store;</code></pre>
<h2 id="login-유지">Login 유지</h2>
<p>로그인을 하고 새로고침을 하면 react-redux에서 isLogin이 false로 기본값이 되어 있어서 true로 변경을 해줘야 로그인이 유지가 될 수 있다. useEffect를 이용해서 localStorage에 token이 있는 경우 action을 전달해서 isLogin을 true로 변경해줬다. useEffect의 두번째인자에 []을 넣어서 반복해서 확인하는 것을 방지하고 처음한번만 확인하게 해줬다.</p>
<pre><code class="language-js">import React, { useEffect } from &#39;react&#39;;
import { useSelector, useDispatch } from &#39;react-redux&#39;;
import { loginCheck } from &#39;./modules/actions/changeLoginStatus&#39;;
import { BrowserRouter as Router, Route, Switch } from &#39;react-router-dom&#39;;
import ListPage from &#39;./pages/ListPage&#39;;
import Login from &#39;./pages/LoginPage&#39;;
import GlobalStyles from &#39;./components/GlobalStyles&#39;;

function App() {
    const dispatch = useDispatch();
    const isLogin = useSelector((state) =&gt; state.changeLoginStatus.isLogin);
    console.log(&#39;isLogin&#39;, isLogin);
    const localStoragetokenCheck = localStorage.getItem(&#39;token&#39;);

    useEffect(() =&gt; {
        if (localStoragetokenCheck) {
            // 로그인유지를 위해서 isLogin을 true로 변경해줘야한다.
            dispatch(loginCheck());
        }
    }, []);

    return (
        &lt;&gt;
            &lt;Router&gt;
                &lt;Switch&gt;
                    {isLogin ? (
                        &lt;Route path=&quot;/&quot; component={ListPage}&gt;&lt;/Route&gt;
                    ) : (
                        &lt;Route path=&quot;/&quot; exact component={Login}&gt;&lt;/Route&gt;
                    )}
                &lt;/Switch&gt;
            &lt;/Router&gt;
            &lt;GlobalStyles /&gt;
        &lt;/&gt;
    );
}

export default App;</code></pre>
<h2 id="logout">Logout</h2>
<p>로그아웃 버튼을 클릭하면 localStorage에 저장되어 있는 token을 삭제하고 dispatch를 이용해서 isLogin을 false로 바꿔준다.</p>
<pre><code class="language-js">import React from &#39;react&#39;;
import { useDispatch } from &#39;react-redux&#39;;
import { logoutClickevent } from &#39;../modules/actions/changeLoginStatus&#39;;
import styled from &#39;styled-components&#39;;

const Header = () =&gt; {
    const dispatch = useDispatch();
    return (
        &lt;Nav&gt;
            &lt;LogoWrap&gt;
                &lt;Logo&gt;&lt;/Logo&gt;
            &lt;/LogoWrap&gt;
            &lt;LogoutBtn
                onClick={() =&gt; {
                    localStorage.removeItem(&#39;token&#39;);
                    dispatch(logoutClickevent());
                }}
            &gt;
                LOGOUT
            &lt;/LogoutBtn&gt;
        &lt;/Nav&gt;
    );
};

export default Header;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[GoogleLogin]]></title>
            <link>https://velog.io/@denmark-choco/GoogleLogin-JWT</link>
            <guid>https://velog.io/@denmark-choco/GoogleLogin-JWT</guid>
            <pubDate>Tue, 01 Sep 2020 02:55:03 GMT</pubDate>
            <description><![CDATA[<h1 id="googlelogin-api">GoogleLogin API</h1>
<p>구글 로그인을 위해서 OAuth API를 사용해서 로그인을 구현할 수 있다. 처음에는 <a href="https://opentutorials.org/course/2473/16571">생활코딩</a> 영상을 보고 익숙해진다음 블로깅을 시작했다. </p>
<p>전체적인 흐름과 틀을 잡은 후 Google API Console에 가서 계정을 만들고 아래와 같이 진행을 했다.</p>
<h4 id="1-새-프로젝트만들기">1. 새 프로젝트만들기</h4>
<p><img src="https://images.velog.io/images/denmark-choco/post/678123b6-1ac6-4346-a31f-3ec4700f69ff/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-09-01%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.22.13.png" alt=""></p>
<h4 id="2-api-개요로-이동을-클릭해서-이동한다">2. API 개요로 이동을 클릭해서 이동한다</h4>
<h4 id="3-사용자-인증정보를-클릭한-후-oauth-클라이언트-id를-클릭한다">3. 사용자 인증정보를 클릭한 후 OAuth 클라이언트 ID를 클릭한다</h4>
<p><img src="https://images.velog.io/images/denmark-choco/post/b7b40979-6344-4a88-9646-169c3ebc1cbd/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-09-01%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.24.14.png" alt=""></p>
<h4 id="4-웹-애플리케이션을-선택하고-작성을-하면-클라이언트id와-보안비밀번호가-발급된다">4. 웹 애플리케이션을 선택하고 작성을 하면 클라이언트ID와 보안비밀번호가 발급된다.</h4>
<h1 id="react-google-login">React-google-login</h1>
<pre><code class="language-js">import React from &#39;react&#39;;
import styled from &#39;styled-components&#39;;
import { GoogleLogin } from &#39;react-google-login&#39;;
import dotenv from &#39;dotenv&#39;;
// 클라이언트 ID는 보안을 위해서 dotenv를 이용한다
import axios from &#39;axios&#39;;
dotenv.config();

const responseGoogle = (res) =&gt; {
  // 서버로 토큰을 전달한 후 JWT토큰을 받고 localStorage에 저장해야한다
    console.log(res.tokenId);
    axios
        .post(&#39;http://localhost:4000/auth&#39;, {
            id_token: res.tokenId,
        })
        .then(function (response) {
            localStorage.setItem(&#39;token&#39;, response.data.token);

            // isLogin 상태값을 true로 변경한다.
            dispatch(loginCheck());
        })
        .catch(function (error) {
            console.log(error);
        });
};

const responseFailGoogle = (err) =&gt; {
  // 에러발생시
    console.log(err);
};

const Login = (props) =&gt; {
    console.log(props);
    return (
        &lt;Container&gt;
            &lt;BGIMG&gt;&lt;/BGIMG&gt;
            &lt;Logo&gt;&lt;/Logo&gt;
            &lt;LoginWrap&gt;
                &lt;LoginTitle&gt;LOGIN&lt;/LoginTitle&gt;
                &lt;LoginDetailText&gt;
                    비대면 온라인 소셜, Community, Hyper connect &lt;LoginStrongText&gt;Meekcy&lt;/LoginStrongText&gt;
                &lt;/LoginDetailText&gt;
                &lt;LoginBtn&gt;
                    &lt;GoogleLogin
                        clientId={process.env.REACT_APP_GOOGLE_CLIENTID}
                        buttonText=&quot;Login with Google&quot;
                        onSuccess={responseGoogle}
                        onFailure={responseFailGoogle}
                        cookiePolicy={&#39;single_host_origin&#39;}
                    /&gt;
                &lt;/LoginBtn&gt;
                &lt;LoginDetailText&gt;
                    Powered by &lt;LoginStrongText&gt;DaBom&lt;/LoginStrongText&gt;
                &lt;/LoginDetailText&gt;
            &lt;/LoginWrap&gt;
        &lt;/Container&gt;
    );
};

export default Login;</code></pre>
<h4 id="reference">Reference</h4>
<ul>
<li><a href="https://electricburglar.tistory.com/150">react로 google login 구현</a>
<code>https://electricburglar.tistory.com/150</code></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JWT(JSON Web Token)]]></title>
            <link>https://velog.io/@denmark-choco/JWTJSON-Web-Token</link>
            <guid>https://velog.io/@denmark-choco/JWTJSON-Web-Token</guid>
            <pubDate>Tue, 01 Sep 2020 02:16:06 GMT</pubDate>
            <description><![CDATA[<h1 id="jwt토큰-기반-인증-방식이란">JWT(토큰 기반 인증 방식)이란?</h1>
<p>JWT은 일반적으로 클라이언트와 서버, 서비스와 서비스 사이 통신시 권한 인가를 위해 인증에 필요한 정보들을 암호화시킨 토큰을 뜻한다. URL에 대해 안전한 문자열로 구성되어 있기 때문에 HTTP어디든 위치할 수 있다. 그래서 세션/쿠키 방식과 유사하게 사용자는 Access Token을 HTTP 헤더에 실어 서버로 보낼 수 있다. 주로 회원 인증이나 정보 전달에 사용된다.</p>
<p><img src="https://images.velog.io/images/denmark-choco/post/989a380d-172e-43c9-a7b6-ba98d510cccb/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-07-29%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.47.43.png" alt=""></p>
<h2 id="구조">구조</h2>
<p>토큰을 만들기 위해서는 크게 3가지 Header,Payload, Verify Signature으로 이루어지며,  Json 형태인 각 부분은 Base64로 인코딩 되어 표현된다.  Base64는 암호화된 문자열이 아니고, 같은 문자열에 대해 항상 같은 인코딩 문자열을 반환한다.</p>
<pre><code class="language-js">HEADER.PAYLOAD.SIGNATURE</code></pre>
<h3 id="1-header해더">1. Header(해더)</h3>
<p>토큰의 헤더는 typ와 alg 두가지 정보로 구성된다. </p>
<pre><code class="language-js">{
  &quot;alg&quot;: &quot;HS256&quot;, // alg는 서명 시 사용하는 알고리즘
  &quot;typ&quot;: &quot;JWT&quot;  // kid는 서명 시 사용하는 키(Public/Private Key)를 식별하는 값
}</code></pre>
<p>위의 JSON객체를 문자열로 직렬화하고 UTF-8과 Base64 URL-Safe로 인코딩하면 아래처럼 해더가 생성된다.</p>
<pre><code class="language-js">Base64URLSafe(UTF-8(&#39;{&quot;alg&quot;: &quot;ES256&quot;,&quot;kid&quot;: &quot;Key ID&quot;}&#39;)) =&gt; eyJhbGciOiJFUzI1NiIsImtpZCI6IktleSBJRCJ9</code></pre>
<h3 id="2-payload페이로드">2. Payload(페이로드)</h3>
<p>토큰의 페이로드에는 토큰에서 사용할 정보의 조각들인 클레임(Claim)이 담겨있다. 클레임은 총 3가지로 나누어지며, JSON형태로 다수의 정보를 넣을 수 있다. </p>
<pre><code class="language-js">{
  &quot;sub&quot;: &quot;1234567890&quot;,
  &quot;name&quot;: &quot;John Doe&quot;,
  &quot;iat&quot;: 1516239022
}</code></pre>
<p>위와 같은 JSON 객체를 문자열로 직렬화하고 Base64 URL-Safe로 인코딩하면 다음과 같이 페이로드를 생성된다.</p>
<pre><code class="language-js">Base64URLSafe(&#39;{&quot;sub&quot;: &quot;1234567890&quot;,&quot;name&quot;: &quot;John Doe&quot;,&quot;iat&quot;:&quot;1516239022&quot;}&#39;) =&gt; eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ</code></pre>
<h4 id="등록된-클레임registered-claim">등록된 클레임(Registered Claim)</h4>
<p>토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터들로 선택적으로 작성이 가능하면 사용할 것을 권장한다. 또 간결하게 하기위해 key는 모두 길이 3의 String이다. </p>
<ul>
<li><p>iss: 토큰 발급자(issuer)</p>
</li>
<li><p>sub: 토큰 제목(subject)</p>
</li>
<li><p>aud: 토큰 대상자(audience)</p>
</li>
<li><p>exp: 토큰 만료 시간(expiration), NumericDate 형식으로 되어 있어야 함 ex) 1480849147370</p>
</li>
<li><p>nbf: 토큰 활성 날짜(not before), 이 날이 지나기 전의 토큰은 활성화되지 않음</p>
</li>
<li><p>iat: 토큰 발급 시간(issued at), 토큰 발급 이후의 경과 시간을 알 수 있음</p>
</li>
<li><p>jti: JWT 토큰 식별자(JWT ID), 중복 방지를 위해 사용하며, 일회용 토큰(Access Token) 등에 사용</p>
</li>
</ul>
<h4 id="공개-클레임public-claim">공개 클레임(Public Claim)</h4>
<p>사용자 정의 클레임으로 공개용 정보를 위해 사용된다. 충돌 방지를 위해 URL포멧을 이용한다.</p>
<h4 id="비공개-클레임private-claim">비공개 클레임(Private Claim)</h4>
<p>사용자 정의 클레임으로 서버와 클라이언트 사이에 임의로 지정한 정보를 저장한다. </p>
<h3 id="3-verify-signature서명">3. Verify Signature(서명)</h3>
<p>서명은 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드이다. 위에서 만든 헤더와 페이로드의 값을 각각 BASE64로 인코딩하고 이 값을 비밀 키를 이용해 헤더에서 정의한 알고리즘으로 해싱을 하고 다시 BASE64로 인코딩하여 생성한다.</p>
<h4 id="참고">참고</h4>
<p><a href="https://meetup.toast.com/posts/239">JWT를 소개합니다.</a><code>https://meetup.toast.com/posts/239</code></p>
<p><a href="https://velopert.com/2389">[JWT] JSON Web Token 소개 및 구조</a><code>https://velopert.com/2389</code></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[javascript_Redux]]></title>
            <link>https://velog.io/@denmark-choco/javascriptRedux</link>
            <guid>https://velog.io/@denmark-choco/javascriptRedux</guid>
            <pubDate>Sun, 30 Aug 2020 20:27:44 GMT</pubDate>
            <description><![CDATA[<h1 id="🔍-redux">🔍 Redux</h1>
<p>리덕스는 상태관리를 쉽게 만들어주는 것이다. </p>
<p>상태관리를 위해 사용하지만 react가 아닌 vanilla javascript나 vue에서도 사용이 가능하다.</p>
<p>리덕스를 사용하는 이유는 state를 예측가능하게 만들어주고 유지보수가 쉬우며 디버깅에도 유리하다.</p>
<h2 id="용어">용어</h2>
<p><img src="https://images.velog.io/images/denmark-choco/post/e7c5cad1-114a-4ebe-8ba5-f8255fff576f/%E1%84%83%E1%85%B5%E1%84%85%E1%85%A5%E1%86%A8%E1%84%89%E1%85%B3flow.png" alt=""></p>
<ul>
<li><p>Store : 상태가 관리되는 오직 하나의 공간(Store)이다.</p>
</li>
<li><p>Action(javascript Object) : reducer에서 새로운 state을 만들때 사용된다.</p>
</li>
<li><p>Reducer : 변화를 일으키는 함수이며 순수한 함수이다. 이전 state와 action을 합쳐서 새로운 state를 return한다.</p>
</li>
<li><p>state : 저장되는 data이며 읽기전용이다.</p>
</li>
</ul>
<h3 id="store생성">Store생성</h3>
<p>먼저 state를 저장할 공간인 store을 createStore를 이용해서 생성한다. 아래의 코드처럼 createStore는 reducer라는 함수를 인자로 받는 함수이다. 이제 state를 저장하는 공간은 생성이 된 것이다. </p>
<pre><code class="language-js">import { createStore } from &quot;redux&quot;;

const store = createStore(reducer);
// createStore는 reducer라는 함수를 인자로 받는 함수이다.

console.log(store.getState());</code></pre>
<ul>
<li><p>subscribe : store의 함수들 중 subscribe는 우리에게 store안에 있는 변화들을 알 수 있게 해준다. 이 subscribe함수는 store에 변화가 있을때마다 감지해서 불려진다.</p>
</li>
<li><p>getState : store의 함수들 중 getState는 state값을 가져올때 사용한다.</p>
</li>
</ul>
<h3 id="reducer">Reducer</h3>
<p>reducer함수에서 return되는 값이 data가 되고 이 data를 가져오기 위해서는 createStore를 담은 변수 store에 getState함수를 실행하면 된다. 그리고 reducer함수는 store에 저장되는 data를 modify하는 함수이다. </p>
<pre><code class="language-js">import { createStore } from &quot;redux&quot;;

const reducer = (state) = {
    //modify state
  return state;
};

const store = createStore(reducer);</code></pre>
<p>reducer에서 state의 data를 return할 때 중요한 점은 이전의 state에 변화를 주지 않고 새로운 state를 return 해야한다는 것이다.</p>
<h3 id="action">Action</h3>
<p>reducer함수에서 data의 값을 변하게하는것이 action이다. reducer에서 두번째 parameter이다. </p>
<p>그럼 action을 어떻게 reducer에 전달할까?</p>
<p>dispatch함수를 이용해서 action을 보낼 수 있다. 그리고 dispatch의 인자는 꼭 object이여야하며 키는 type가 있어야한다.</p>
<pre><code class="language-js">const reducer = (state = 0, action) =&gt; {
  switch (action.type) {
    case ADD:
      return count++;
    case MINUS:
      return count--;
    default:
      return count;
  }
};

const store = createStore(reducer);

store.dispatch({ type : ADD, text : text });</code></pre>
<h3 id="reference">Reference</h3>
<ul>
<li><p><a href="https://velopert.com/3528">리덕스 왜 쓸까?</a>
<code>https://velopert.com/3528</code></p>
</li>
<li><p><a href="https://medium.com/@ca3rot/%EC%95%84%EB%A7%88-%EC%9D%B4%EA%B2%8C-%EC%A0%9C%EC%9D%BC-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EC%89%AC%EC%9A%B8%EA%B1%B8%EC%9A%94-react-redux-%ED%94%8C%EB%A1%9C%EC%9A%B0%EC%9D%98-%EC%9D%B4%ED%95%B4-1585e911a0a6">React + Redux 플로우의 이해</a>
<code>https://medium.com/@ca3rot/%EC%95%84%EB%A7%88-%EC%9D%B4%EA%B2%8C-%EC%A0%9C%EC%9D%BC-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EC%89%AC%EC%9A%B8%EA%B1%B8%EC%9A%94-react-redux-%ED%94%8C%EB%A1%9C%EC%9A%B0%EC%9D%98-%EC%9D%B4%ED%95%B4-1585e911a0a6</code></p>
</li>
</ul>
<ul>
<li><a href="https://velopert.com/3533">리덕스</a>
<code>https://velopert.com/3533</code></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[스트리밍 페이지 기능 구현을 위한 공부노트]]></title>
            <link>https://velog.io/@denmark-choco/%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D-%ED%8E%98%EC%9D%B4%EC%A7%80-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%EC%9D%84-%EC%9C%84%ED%95%9C-%EA%B3%B5%EB%B6%80%EB%85%B8%ED%8A%B8</link>
            <guid>https://velog.io/@denmark-choco/%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D-%ED%8E%98%EC%9D%B4%EC%A7%80-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%EC%9D%84-%EC%9C%84%ED%95%9C-%EA%B3%B5%EB%B6%80%EB%85%B8%ED%8A%B8</guid>
            <pubDate>Wed, 26 Aug 2020 15:04:09 GMT</pubDate>
            <description><![CDATA[<h1 id="http-live-streaminghls이란"><a href="https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008332-CH1-SW1">HTTP Live Streaming</a>(HLS)이란?</h1>
<p><img src="https://images.velog.io/images/denmark-choco/post/4ae044a5-6b24-4681-bcaa-eaecf73c2cd3/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-26%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.08.47.png" alt=""></p>
<p><a href="https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008332-CH1-SW1">이미지 출처</a>
<code>https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008332-CH1-SW1</code></p>
<p>HLS은 애플디바이스에서 사용하는 표준 HTTP 기반 스트리밍 프로토콜이다. 공식문서에서 HLS을 이용하는 이유는 아래와 같다.</p>
<ul>
<li><p>iPhone, iPod touch, iPad 또는 Apple TV로 오디오 또는 비디오 스트리밍</p>
</li>
<li><p>특별한 서버 소프트웨어없이 라이브 이벤트 스트리밍</p>
</li>
<li><p>암호화 및 인증을 사용하여 주문형 비디오 전송</p>
</li>
</ul>
<p>HLS은 비디오와 오디오를 실시간으로 인코딩해 많은 사용자에게 동시에 보내야하는 라이브 방송과 촬영과 편집을 거쳐 동영상 파일을 제작한 다음 사용자의 요구가 있을 때 동영상을 재생하는 사전 녹화된 콘텐츠를 모두 지원한다. </p>
<p>HLS는 기존 라이브 스트리밍 방식과 차이는 크게 두가지이다. 하나는 동영상 정보를 전달하는 방식이고, 다른 하나는 HLS에서 만든 스트림 세그먼트(stream segment)이다. HLS에서 서버는 HTTP로 요청을 받아서 플레이어에 응답을 주는 역할만 한다. 요청받은 파일을 어떠한 변형도 하지 않고 응답으로 보내기만 한다. 스트림 세그먼터(Stream Segmenter)는 일정한 시간 간격마다 입력받은 미디어 데이터를 분할해 파일을 만들고, 그 분할한 파일에 접근할 수 있는 메타데이터(m3u8)를 생성하는 일을 한다. </p>
<p>HLS을 사용하는 이유는 대규모 서비스를 위해 부하 분산을 고려할 때 기존 하이브 그트리밀 방식은 매우 복잡한 구조를 사용했지만 HLS는 일반 웹 서비스의 구조와 같은 방식을 사용하기 때문에 전체적으로 단순해졌다.</p>
<p>HLS의 특징 중에 하나는 사용자의 네트워크 속도에 따라 적합한 콘텐츠를 선택하여 재생할 수 있는 ABS를 지원하는 것이다. </p>
<h1 id="adaptive-bitrate-streamingabs">Adaptive Bitrate Streaming(ABS)</h1>
<p>ABS을 적용하면 사용자의 네트워크 환경이 변화해도 끊기지 않고 동영상을 볼 수 있다. 사용자가 wi-fi를 이용하다가 휴대전화망 환경으로 이동하면 사용가능한 네트워크 대역폭이 감소되어 버퍼링이 발생하더나 화면이 제대로 표시되지 않는 문제가 발생한다. 하지만 ABS이 적용되어 있다면 화면의 품질이나 해상도 등은 나빠지지만 끊어지지 않는다.</p>
<p><img src="https://images.velog.io/images/denmark-choco/post/d631a050-ee65-4a6f-86f6-dc2a9e662c37/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-26%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.52.11.png" alt=""></p>
<p><a href="https://d2.naver.com/helloworld/7122">이미지출처</a>
<code>https://d2.naver.com/helloworld/7122</code></p>
<h1 id="wowza">Wowza</h1>
<p>Wowza Streaming Engine은 어디서나 고품질의 비디오와 오디오를 어떤 기기로든지 안정적으로 스트리밍하게 해 주는 강력한 맞춤형 미디어 서버 소프트웨어이다. </p>
<h2 id="reference">Reference</h2>
<p><a href="https://d2.naver.com/helloworld/7122">HTTP Live Streaming</a></p>
<p><a href="https://m.blog.naver.com/woliver/221833439445">라이브스트리밍을 위한 완벽 가이드</a></p>
<p><a href="https://idchowto.com/?p=2553">HLS (HTTP Live Streaming) 과 ABS (Adaptive Bitrate Streaming)</a></p>
<p><a href="https://idchowto.com/?p=9178">가변 비트레이트 스트리밍 (ABS), HTTP 라이브 스트리밍 (HLS)</a></p>
<p><a href="https://www.slideshare.net/dasomim1/wowza-64081237">Wowza설치및사용법</a></p>
<p><a href="https://idchowto.com/?p=22427">Wowza Streaming Engine 4.x &amp; JW Player 7.x 을 이용한 가변 비트레이트 구축 환경 테스트</a></p>
<p><a href="https://idchowto.com/?p=15364">wowza 테스트 페이지</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Final Project_기업협업(왓츠굿)]]></title>
            <link>https://velog.io/@denmark-choco/Final-Project%EA%B8%B0%EC%97%85%ED%98%91%EC%97%85%EC%99%93%EC%B8%A0%EA%B5%BF</link>
            <guid>https://velog.io/@denmark-choco/Final-Project%EA%B8%B0%EC%97%85%ED%98%91%EC%97%85%EC%99%93%EC%B8%A0%EA%B5%BF</guid>
            <pubDate>Tue, 25 Aug 2020 12:09:07 GMT</pubDate>
            <description><![CDATA[<h1 id="👩💻-final-project">👩‍💻 Final Project</h1>
<p>8월 24일 동기들과 Final Project 아이디어 공유시간을 가지고 기업협업 프로젝트 아이디어 피칭시간을 가졌다. 마지막 프로젝트에서 기업협업을 꼭 하고 싶다고 생각을 하고 있어서 기업협업 프로젝트 아이디어를 집중해서 듣고 왓프굿이라는 기업에 지원을 했다. 기업협업은 인기가 많은 경우 랜덤으로 결정되기 때문에 지원을 했지만 참여를 못 할수도 있어 떨리는 마음으로 기다렸는데 이번에 참여를 할 수 있게 되었다. </p>
<p>기업협업이 결정되고 팀원들도 결정되었다. 페어를 하면서 좋은 피드백을 받았던 재영님과 처음으로 만난 동훈님, 이전에 어려운 서버에서 페어를 진행해서 같이 힘들었던 태하님과 프로젝트를 진행하게 되었다. 팀원들의 첫 느낌은 다들 긴장을 했던거 같았다.</p>
<p>왓츠굿의 아이디어는 넷플릭스 파티처럼 스트리밍영상을 지인들과 함께 시청하면서 실시간 채팅을 할 수 있는 웹페이지를 구현하는 것이다. 기업측에서는 로고와 아이디어를 제공해주셨고 매주 미팅을 가지고 코드리뷰를 해주시기로 했다.</p>
<p><img src="https://images.velog.io/images/denmark-choco/post/75f721b4-0a93-4353-a884-578125d2530f/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-08-25%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%209.01.54.png" alt=""></p>
<h2 id="sr">SR</h2>
<p><img src="https://images.velog.io/images/denmark-choco/post/f651c5f6-e628-4a97-a497-fb45000653f6/_2020-08-26_17-28-44.png" alt=""></p>
<h3 id="1-서비스기획">1. 서비스기획</h3>
<ul>
<li>전체 흐름도<blockquote>
<p><img src="https://images.velog.io/images/denmark-choco/post/9485e770-ff76-45f3-baa2-29d659ddab2d/_2020-08-26_14-56-15.png" alt=""></p>
</blockquote>
</li>
</ul>
<h4 id="1-로그인-화면">1) 로그인 화면</h4>
<ul>
<li>소셜 로그인</li>
</ul>
<h4 id="2-메인화면">2) 메인화면</h4>
<ul>
<li>영상목록</li>
<li>모달창 : 영상설명 ( 데이터 받아서 렌더링)</li>
<li>모달창 : 혼자보기 버튼 , 같이보기 버튼 (영상개설시 혼자시청인지 다수와 시청을 하는지 정하고 개설될 수 있도록 설정)</li>
</ul>
<h4 id="3-스트리밍-화면">3) 스트리밍 화면</h4>
<ul>
<li>영상링크공유 : 아이콘 클릭 시 자동 복사</li>
<li>플레이한 영상기록 (채팅방 없이 혼자 볼 때)</li>
<li>인터넷 환경에 따라 해상도 자동 변환</li>
<li>다양한 디바이스에서 동작컨트롤바 제어 시 전체 채팅방 사용자와 재생 지점, 기능 동기화</li>
<li>컨트롤바 이동 시 메타 이미지</li>
<li>영상컨트롤 권한 : 호스트 (advanced : 모든 참여자)</li>
</ul>
<h4 id="4-채팅방">4) 채팅방</h4>
<ul>
<li>채팅방 바로 보이지 않고 선택지 만들기 + 트위치</li>
<li>채팅방에 아무도 없으면 방 삭제</li>
<li>채팅  : 입장기록, 영상 컨트롤 기록 , 이전 채팅 내용 다 보이기</li>
<li>채팅프로필변경 (선택사항)</li>
<li>채팅 입장, 퇴장 시 알림</li>
</ul>
<hr>
<h3 id="2-기능-리스트업">2. 기능 리스트업</h3>
<h4 id="bare-minimum-requirements">Bare Minimum Requirements</h4>
<ul>
<li><p>Google Login 기능</p>
<p>  <a href="https://velog.io/@dodose/%EC%BD%94%EB%93%9C%EC%8A%A4%ED%85%8C%EC%9D%B4%EC%B8%A0-First-Project-%ED%9B%84%EA%B8%B0">구글 로그인</a></p>
</li>
<li><p>Video 목록 화면</p>
<ol>
<li>API 에서 받은 영화 정보 렌더링을 한다. <ul>
<li>장르 별로 구분해서 렌더링 한다.</li>
<li>영화 썸네일을 렌더링한다.</li>
</ul>
</li>
</ol>
</li>
<li><p>Video 모달창</p>
</li>
<li><p>스트리밍</p>
</li>
<li><p>채팅</p>
</li>
<li><p>반응형으로 렌더링한다.</p>
</li>
</ul>
<h4 id="advanced">Advanced</h4>
<ol>
<li>채팅 프로필 변경</li>
<li>채팅 이모지 적용 </li>
<li>채팅 삭제 기능</li>
<li>채팅 금지 기능 </li>
<li>강퇴 기능 </li>
<li>혼자보기 기록 저장 및 이어보기 기능 </li>
<li>방장을 표시한다. </li>
<li>컨트롤 바 이동시 메타이미지 확인 기능</li>
</ol>
<h4 id="nightmare">Nightmare</h4>
<ol>
<li>거울모드(좌우반전) </li>
<li>구간 반복 </li>
<li>자신의 얼굴 보여주기 </li>
<li>테블릿 모드</li>
</ol>
<hr>
<h3 id="3-와이어프레임">3. 와이어프레임</h3>
<ul>
<li><p>Login</p>
<blockquote>
<p><img src="https://images.velog.io/images/denmark-choco/post/726d3ce8-4d3e-40ad-be2d-e92eadc6aa0e/Untitled.png" alt=""></p>
</blockquote>
</li>
<li><p>ListPage</p>
<blockquote>
<p><img src="https://images.velog.io/images/denmark-choco/post/5fb5c0e3-b952-47c5-82b7-5464f63704f7/Untitled%20(1).png" alt=""></p>
</blockquote>
</li>
<li><p>StreamingPage</p>
<blockquote>
<p><img src="https://images.velog.io/images/denmark-choco/post/637d65c3-ad54-4ef2-b748-3ee74aff263a/_2020-08-28__1.25.24.png" alt=""></p>
</blockquote>
</li>
<li><p>modal</p>
<blockquote>
<p><img src="https://images.velog.io/images/denmark-choco/post/020cd0a7-6866-49fb-a97e-be6d9909c6bb/Untitled%20(2).png" alt=""></p>
</blockquote>
</li>
</ul>
<hr>
<h3 id="4-스키마">4. 스키마</h3>
<p><img src="https://images.velog.io/images/denmark-choco/post/fce815a3-8e67-4ad1-95d0-fb132a9278df/Copy_of_Meecky.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2020 Dev-Matching: 웹 프론트엔드 개발자(하반기) 후기]]></title>
            <link>https://velog.io/@denmark-choco/2020-Dev-Matching-%EC%9B%B9-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%ED%95%98%EB%B0%98%EA%B8%B0-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@denmark-choco/2020-Dev-Matching-%EC%9B%B9-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%ED%95%98%EB%B0%98%EA%B8%B0-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Sat, 22 Aug 2020 12:14:13 GMT</pubDate>
            <description><![CDATA[<h1 id="첫-코딩test">첫 코딩Test</h1>
<p>프로젝트가 끝이나고 원티드나 프로그래머스를 눈팅하던 중 테스트가 있다는 것을 알고 마감 전날에 신청을 했다. 면접전에 경험을 한번 해보는 것도 좋을 거 같다고 생각해서 금요일에 신청을 하고 오늘 오후 1시 15분부터 4시 15분까지 웹 프론트엔드 과제 테스트를 시작했다.</p>
<p>문제는 javascript로 react나 다른 라이브러리를 사용하지 않고 ES6문법을 이용해서 해결하도록 했고 api에서 원하는 데이터를 받아서 이벤트를 실행시키는 필수 문제가 있고 사용자편의를 위한 기능이 추가문제로 구성되어 있었다. 코드는 이해하는데 어렵지 않았지만 문제를 푸는 것은 역시 어려움이 많았다. 어려운 문제인것보다 한번도 기능을 구현해보지 않았던 거라 구글링하는데 많은 시간이 소요됐다. 필수문제중 1개는 input창에 단어를 입력하면 검색어추천 목록이 input창 아래에 render되게 하는 기능이었다. 실제 웹에도 많이 적용하고 익숙하게 사용하는 기능이었다. 구현을 어느정도 했지만 속도가 느리고 어떤 경우에는 안되다가 또 새로고침하면 작동하다가 했으며 class문법으로 전환을 하지 못했다.</p>
<p>이렇게 3시간이 지나가고 제출을 하고 나니 기분이 좋았다. 해결하지 못한 문제도 많고 구글링하는데 많은 시간을 소요했지만 재미있는 시간이었다. 제출하면 문제를 다시 볼 수 없을거같아서 제출전에 미리 문제들을 복사해두었다. 나중에 시간을 내서 다시 만들어보고 다음 프로젝트에 기능을 구현하면 좋을 거 같다. </p>
<h2 id="etc">Etc</h2>
<p>오늘 블로그에 신기한 댓글이 달렸다. 어제 작성한 블로그에서 블로그를 방문해 응원댓글을 남겨주신 분이 <a href="http://daily-devblog.com/">데일리블로그</a>에서 내 글을 확인하고 가끔 눈팅을 해주신다고 했다. 데일리 블로그를 알아보니 전날에 작성된 IT 기술블로거들의 글을 정리해서 오전 9시에 메일로 보내준다고 한다. 말그대로 기술블로그 구독서비스이다. 들어가보니 내글이 진짜 리스트에 있었다. 꼭 네이버나 카카오 메인에 내글이 실린것처럼 기분이 좋았다. 누가 나의 글을 구독해서 읽는다는게 신기하고 기분이 좋았다. 물론 나의 글을 보려고 한다기보다 기술블로그들 중 1개이지만 기분이 너무 좋아서 캡쳐를 했다. 글을 꾸준히 자주 올려야겠다. </p>
<p><img src="https://images.velog.io/images/denmark-choco/post/7a16af23-2efc-465d-8489-8309b78a4938/KakaoTalk_Photo_2020-08-22-17-02-27.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>