<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>nada_1221.log</title>
        <link>https://velog.io/</link>
        <description>FE_개발자_지망생</description>
        <lastBuildDate>Thu, 05 Jan 2023 14:34:49 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>nada_1221.log</title>
            <url>https://velog.velcdn.com/images/nada_1221/profile/7c4fa7fc-21ca-4a38-b955-0d3b1568b0c8/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. nada_1221.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/nada_1221" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[vue.js]]></title>
            <link>https://velog.io/@nada_1221/vue.js</link>
            <guid>https://velog.io/@nada_1221/vue.js</guid>
            <pubDate>Thu, 05 Jan 2023 14:34:49 GMT</pubDate>
            <description><![CDATA[<p>vue.js 
JavaScript 프레임 워크로 대화형이자 반응형인 웹 프론트엔드를 구축합니다.
웹 프론트엔드란,
브라우저에서 실행되는 웹 어플리케이션을 말하며, 사용자가 더 쉽게 사용할 수 잇는 어플리케이션을 의미합니다.</p>
<p>우선 JavaScript는 브라우저에서 사용하는 프로그래밍 언어입니다.
사용자가 페이지를 로드한 후 브라우저에서 실행됩니다.
사용자 화면에 보이는 모습을 조작할 수 있도록 해줍니다.
서버에서 새로운 페이지를 가져오지 않은 채로 말입니다.
이는 풍부한 사용자 경험을 제공합니다.</p>
<p>Vue.js가 JS로만 쓰이는 것은 아닙니다. JS 프레임워크죠.
프레임 워크란 JS를 비롯한 모든 프로그래밍 언어에서 서드 파티 라이브러리를 말합니다. 다른 누군가 작성한 코드로 특정 유틸리티 기능과 메서드, 도구 등을 이용하므로 내가 직접 코드를 작성할 필요가 없습니다.</p>
<p>중요한건 다른 일반 라이브러리와 달리 프레임 워크는 추가 기능을 제공할 뿐만 아니라 규칙을 제공합니다.
어플리케이션 구축 시 따라야 할 접근 방식을 안내합니다.
어플리케이션 코드의 작성법에 대한 명확한 구조와 아이디어를 제공합니다.
유틸리티 기능과 규칙을 제공하는 것 입니다.</p>
<p>그렇다면 왜 Vue.js 를 사용할까요? 
이를 사용해서 대화형이고 반응형인 웹 프론트엔드를 구축할 수 있기 때문입니다.</p>
<p>반응형이란 앱이 사용자의 작업에 즉각 응답한다는 뜻입니다.
사용자가 화면에 뭔가를 입력하면 이에 따라 앱이 반응하도록 만드는 것입니다.</p>
<p>서버 사이드 프레임워크가 아닙니다.
PHP or Node와 함께 사용하지 않습니다.
조합해서 사용할 수 있긴 하지만 코드 작성에 도움이 되진 않습니다.
Vue는 브라우저 사이드 JS 이기 때문입니다.
HTML&amp; CSS, JS 그리고 브라우저의 Vue.js를 사용해 사용자가 보는 것을 제어하고 사용자 인터페이스를 웹에서 제공합니다.</p>
<p>Vue.js는 프레임워크로 브라우저에서 실행되는 JS 기반 사용자 인터페이스를 구축하는데 도움을 줍니다.
서버와 통신 할 수 있는 웹 어플리케이션을 위해서요.
하지만 이에 도움이 되는건 브라우저 사이드 코드입니다.</p>
<p>왜 Vue.js를 사용하는 걸까요?
반응형 웹 프론트를 왜 구축하는 걸까요?
전통적인 웹페이지에서는 항상 응답을 기다려야 했습니다.
이때 JS가 속도 개선에 도움을 줍니다.
브라우저에서 모던 웹 어플리케이션을 제공해줍니다. JS는 로드된 페이지에서 브라우저 내에 실행된다는 게 장점입니다.
브라우저에서 실행하는 언어가 있다는 뜻인데 페이지를 변경하는데 사용됩니다. 화면 뒤에서 새 HTML을 가져오지 않고 문서 객체 모델DOM이라고 부르는 페이지의 HTML구조를 JS로 조작합니다.
모던 JS 기반 웹 애플리케이션에서는 새 HTML 페이지를 얻고자 요청을 보내는 대신 단 한 번만 실행하고 이후 화면 뒤에서 데이터만 교환합니다.
클라이언트 사이드 JS와 Vue 와 같은 프레임워크를 사용하여 화면을 업데이트 합니다.
Vue.js 를 사용하는 이유는 JS가 완벽하지 않기 때문입니다.
따라야 하는 명확한 규칙이 있고, </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BE]인증보안]]></title>
            <link>https://velog.io/@nada_1221/BE%EC%9D%B8%EC%A6%9D%EB%B3%B4%EC%95%88</link>
            <guid>https://velog.io/@nada_1221/BE%EC%9D%B8%EC%A6%9D%EB%B3%B4%EC%95%88</guid>
            <pubDate>Tue, 13 Sep 2022 04:17:02 GMT</pubDate>
            <description><![CDATA[<h2 id="cookie">Cookie</h2>
<hr>
<p>서버에서 클라이언트에 영속성있는 데이터를 저장하는 방법</p>
<blockquote>
<p><code>영속성</code> : 데이터를 생성한 프로그램의 실행이 종료되더라도 사라지지 않는 데이터의 특성을 의미.</p>
</blockquote>
<p>서버가 원한다면 서버는 클라이언트의 쿠키를 이용하여 데이터를 가져올 수 있다.</p>
<p>쿠키를 이용하는 것은 단순히 서버에서 클라이언트에 쿠키를 전송하는 것만 의미하지 않고 클라이언트에서 서버로 쿠키를 다시 전송하는 것도 포함된다.</p>
<p>쿠키의 특징</p>
<h3 id="서버가-클라이언트에-특정한-데이터를-저장할-수-있다">서버가 클라이언트에 특정한 데이터를 저장할 수 있다.</h3>
<p>데이터를 저장한 이후 아무 때나 데이터를 가져올 수는 없다. 데이터를 저장한 이후 특정한 조건들이 만족되어야 다시 가져올 수 있기 때문이다.</p>
<pre><code class="language-js">//쿠키 옵션
&#39;Set-Cookie&#39;:[
  &#39;cookie=yummy&#39;,
  &#39;Secure=Secure; Secure&#39;,
  &#39;HttpOnly=HttpOnly; HttpOnly&#39;,
  &#39;Path=Path; Path=/cooke&#39;,
  &#39;Domain=Domain; Domain=nadavelog.com&#39;
]</code></pre>
<h3 id="1-domain">1. Domain</h3>
<p>쿠키 옵션에서 도메인은 포트 및 서브 도메인 정보, 세부 경로를 포함하지 않는다.</p>
<p>ex) <code>http://www.localhost.com:3000/users/login</code> 이라 하면 여기에서 Domain 은 <code>localhost.com</code>이 된다.</p>
<p>쿠키 옵션에서 도메인 정보가 존재한다면 클라이언트에서는 쿠키의 도메인 옵션과 서버의 도메인이 일치해야만 쿠키를 전송 할 수 있다. 이를 통해 <code>naver.com</code>에서 받은 쿠키를 <code>google.com</code>에 전송하는 일을 막을 수 있다.</p>
<h3 id="2-path">2. Path</h3>
<p><code>Path</code>는 세부 경로로써 서버가 라우팅할 때 사용하는 경로를 의미한다.
ex)<code>http://www.localhost.com:3000/users/login</code> 이라 하면 여기에서 <code>Path</code>, 즉 세부 경로는 <code>/users/login</code>이 된다. 이를 명시하지 않으면 기본적으로 <code>/</code> 으로 설정되어 있다.</p>
<p><code>Pah</code>옵션의 특징은 설정된 경로를 포함하는 하위 경로로 요청을 하더라도 쿠키를 서버에 전송할 수 있다.</p>
<h3 id="3-maxage-or-expires">3. MaxAge or Expires</h3>
<p>쿠키가 유효한 기간을 정하는 옵션.
<code>MaxAge</code>는 쿠키가 유효한 시간을 초 단위로 설정하는 옵션. 
<code>Expires</code>은 <code>MaxAge</code>와 비슷하지만 언제까지 쿠키가 유효한지 지정할 수 있다. 이때 옵션의 값은 클라이언트의 시간을 기준으로 한다. 이후 지정된 시간, 날짜를 초과하게 되면 쿠키는 자동으로 파괴된다.</p>
<p>쿠키는 위 옵션의 여부에 따라 세션 쿠키<code>Session Cookie</code>와 영속성 쿠키<code>Persistent Cookie</code>로 나눠진다.</p>
<p><strong>세션 쿠키</strong> : <code>MaxAge</code> or <code>Expires</code> 옵션이 없는 쿠키. 브라우저가 실행 중일 때 사용할 수 있는 임시 쿠키. 브라우저를 종료하면 쿠키는 삭제된다.</p>
<p><strong>영속성 쿠키</strong> : 브라우저의 종료 여부와 상관없이 <code>MaxAge</code>or<code>Expires</code>에 지정된 유효시간만큼 사용가능한 쿠키</p>
<h3 id="4-secure">4. Secure</h3>
<p>사용하는 프로토콜에 따른 쿠키의 전송 여부를 결정하는 옵션.
만약 <code>Secure</code>옵션이 <code>true</code>로 설정된 경우 HTTPS를 이용하는 경우에만 쿠키를 전송할 수 있다.</p>
<h3 id="5-httponly">5. HttpOnly</h3>
<p>자바스크립트에서 브라우저의 쿠키에 접근 여부를 결정한다. 해당 옵션이 <code>true</code>로 설정된 경우, 자바스크립트로 쿠키에 접근이 불가하다.</p>
<p>명시되지 않은 경우 기본으로 <code>false</code>로 지정되어 있다.
이 경우 <code>document.cookie</code>를 이용해 자바스크립트에서 쿠키접근이 가능하므로 XSS 공격에 취약해진다.</p>
<h3 id="6-samesite">6. SameSite</h3>
<p>Cross-Origin 요청을 받은 경우 요청에서 사용한 메소드와 해당 옵션(e.g. <code>GET</code> , <code>POST</code> ,<code>PUT</code> , <code>PATCH</code> ...)의 조합을 기준으로 서버의 쿠키 전송 여부를 결정하게 된다. 사용 가능한 옵션은 다음과 같다.</p>
<ul>
<li><code>Lax</code> : Cross-Origin 요청이라면 <code>GET</code> 메소드에 대해서만 쿠키를 전송할 수 있다.</li>
<li><code>Strict</code> : 단어 그대로 가장 엄격한 옵션으로, Cross-Origin 이 아닌 <code>same-site</code>인 경우에만 쿠키를 전송 할 수 있다.</li>
<li><code>None</code> : Cross-Origin에 대해 가장 관대한 옵션으로 항상 쿠키를 보내줄 수 있다. 다만 쿠키 옵션 중 <code>Secure</code>옵션이 필요하다.</li>
</ul>
<p>이 때 <code>same-site</code>는 요청을 보낸 Origin과 서버의 도메인, 프로토콜, 포트가 같은 경우를 말한다. 이중 하나라도 다르다면 Cross-origin으로 구분된다.</p>
<p>서버에서 이러한 옵션들을 지정한 다음 서버에서 클라이언트로 쿠키를 처음 전송하게 된다면 헤더에 <code>Set-Cookie</code>라는 프로퍼티로 쿠키를 담아 전송한다.</p>
<p>이후 클라이언트에서 서버에게 쿠키를 전송해야 한다면 클라이언트는 헤더에 <code>Cookie</code>라는 프로퍼티에 쿠키를 담아 서버에 쿠키를 전송하게 된다.</p>
<h3 id="쿠키를-이용한-상태-유지">쿠키를 이용한 상태 유지</h3>
<hr>
<p>쿠키의 특성을 이용하여 서버는 클라이언트에 인증정보를 담은 쿠키를 전송하고, 클라이언트는 전달받은 쿠키를 서버에 요청과 같이 전송하여 <code>Stateless</code>한 인터넷 연결을 <code>Stateful</code>하게 유지할 수 있다.</p>
<p><strong>하지만 기본적으로 쿠키는 오랜 시간 동안 유지될 수 있고, HttpOnly 옵션을 사용하지 않았따면 자바스크립트를 이용해서 쿠키에 접근할 수 있기 때문에 쿠키에 민감한 정보를 담는 것은 위험하다.</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹 표준& 접근성 [2]]]></title>
            <link>https://velog.io/@nada_1221/%EC%9B%B9-%ED%91%9C%EC%A4%80-%EC%A0%91%EA%B7%BC%EC%84%B1-2</link>
            <guid>https://velog.io/@nada_1221/%EC%9B%B9-%ED%91%9C%EC%A4%80-%EC%A0%91%EA%B7%BC%EC%84%B1-2</guid>
            <pubDate>Mon, 12 Sep 2022 05:49:04 GMT</pubDate>
            <description><![CDATA[<h2 id="seo">SEO</h2>
<hr>
<p>개발자가 아무리 열심히 웹페이지를 만들어도, 검색했을 때 검색 결과 상위에 없거나 뒤 페이지로 밀려난다면 아무도 찾지 않는 웹 페이지가 되어버린다.</p>
<p>이런 사태를 방지하기 위해서는 검색 엔진의 작동 방식에 맞게 웹 페이지를 최적화해주는 작업, SEO<code>Search Engine Optimization</code> <code>검색 엔진 최적화</code> 가 필요하다. SEO를 통해 검색 엔진에서 웹 페이지를 보다 더 상위에 노출될 수 있게끔 만들 수 있다.</p>
<p>SEO는 크게 On-Page SEO 와 Off-Page SEO 두가지로 나뉜다.</p>
<ul>
<li>On-Page SEO : 페이지 내부에서 진행할 수 있는 SEO 제목, 콘텐츠, 핵심 키워드 배치, 효율적인 HTML 요소 사용법 등을 이용하는 방법</li>
<li>Off-Page SEO : 웹 사이트 외부에서 이루어지는 SEO, 소셜 미디어 홍보, 백링크등을 이용하는 방법, 웹 페이지 내용이나 구조와는 관계 X</li>
</ul>
<p>On-Page SEO 예시의 일례로 여러 개의 <code>&lt;meta&gt;</code>요소와 <code>&lt;title&gt;</code>요소에 검색 키워드를 적용시킨다. 등이 있다.</p>
<h3 id="seo에-미치는-요소">SEO에 미치는 요소</h3>
<hr>
<h3 id="1-title-요소">1. <code>&lt;title&gt;</code> 요소</h3>
<p><code>&lt;title&gt;</code> 요소는 검색 결과창에서 제목에 해당하는 요소로,<code>&lt;head&gt;</code> 요소의 자식 요소로 작성한다.</p>
<ul>
<li><code>&lt;title&gt;</code> 요소에 어떤 내용을 적는가에 따라 검색 후 유입까지 유도할 수 있다.<ul>
<li>제목으로 사이트를 파악하기 어려워지면 유입률이 떨어진다.</li>
</ul>
</li>
<li><code>&lt;title&gt;</code> 요소에 핵심 키워드가 포함되면 상위에 노출될 확률이 높아진다.<ul>
<li>같은 키워드를 반복시 불이익을 받을 수 있으니 핵심 키워드는 한 번만 포함시켜주자.</li>
</ul>
</li>
</ul>
<h3 id="2-meta-요소">2. <code>&lt;meta&gt;</code> 요소</h3>
<p><code>&lt;meta&gt;</code> 요소는 메타 데이터를 담는 요소
<code>&lt;meta&gt;</code> 요소도 <code>&lt;head&gt;</code> 요소의 자식요소로 작성해주는 것이 일반적
<code>&lt;meta&gt;</code> 요소 안에 들어있는 내용은 웹페이지가 어떤 데이터를 달고 있는지를 설명하는 메타 데이터임을 알 수 있다. 또한 <code>&lt;meta&gt;</code> 요소에 들어가는 내용은 검색 결과창에서만 확인 할 수 잇는 것이 아닌 소셜 미디어나 채팅 앱에서 링크를 공유했을 때 뜨는 링크 미리보기와 관련 정보도 이 <code>&lt;meta&gt;</code> 요소에 들어가 있는 내용이다.</p>
<p><code>&lt;meta&gt;</code> 요소의 각각의 목적은 다르다.
첫 번째 경우에는 <code>name</code>속성을 사용하며, SEO를 위해서 사용하는 것이 목적이다.
두 번째 경우는 <code>property</code>속성을 사용하며, 다른 사람에게 공유하기 위한 것이 목적.
특히 <code>property</code>속성을 사용하는 경우는 <strong>오픈 그래프<code>Open Graph</code></strong> 라고 하며, 페이스북에서 게시물을 공유하기 위한 목적으로 만들었으며, 속성값 앞에는 오픈 그래프를 뜻하는 &quot;og&quot;가 붙는다.</p>
<h4 id="seo를-위한-meta-요소">SEO를 위한 meta 요소</h4>
<pre><code class="language-js">&lt;meta name=&#39;속성값&#39; content=&#39;내용&#39; /&gt;</code></pre>
<table>
<thead>
<tr>
<th align="center">name 속성값</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">description</td>
<td align="center">콘텐츠에 대한 간략한 설명. 검색결과에서 제목 밑에 뜨는 내용을 생각하면 된다.</td>
</tr>
<tr>
<td align="center">keywords</td>
<td align="center">웹 페이지의 관련 키워드들을 나열할 때 사용</td>
</tr>
<tr>
<td align="center">author</td>
<td align="center">콘텐츠의 제작자를 표시한다.</td>
</tr>
</tbody></table>
<h4 id="오픈-그래프">오픈 그래프</h4>
<pre><code class="language-js">&lt;meta property =&#39;속성값&#39; content=&#39;내용&#39;/&gt;</code></pre>
<table>
<thead>
<tr>
<th align="center">property 속성값</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">og:url</td>
<td align="center">페이지의 표준 URL</td>
</tr>
<tr>
<td align="center">og:site_name</td>
<td align="center">사이트의 이름</td>
</tr>
<tr>
<td align="center">og:title</td>
<td align="center">콘탠츠의 제목</td>
</tr>
<tr>
<td align="center">og:description</td>
<td align="center">콘텐츠에 대한 간략한 설명. 검색 결과에서 제목 밑에 뜨는 내용을 생각하면 된다.</td>
</tr>
<tr>
<td align="center">og:image</td>
<td align="center">미리보기로 표시될 이미지</td>
</tr>
<tr>
<td align="center">og:type</td>
<td align="center">콘텐츠의 미디어 유형. 기본 값은 website로, videio, music등의 유형을 표시할 수 있다.</td>
</tr>
<tr>
<td align="center">og:locale</td>
<td align="center">리소스의 언어로, 기본 값은 en_US 한국은 ko_KR이다.</td>
</tr>
</tbody></table>
<h3 id="3-hgroup-요소">3. <code>&lt;hgroup&gt;</code> 요소</h3>
<p><code>&lt;hgroup&gt;</code> 요소는 콘텐츠의 제목을 표시하는 용도인 만큼 핵심 키워드를 포함하고 잇을 가능성이 높다. 따라서 검색 엔진도 <code>&lt;hgroup&gt;</code> 요소의 내용을 중요하게 취급한다.
but 똑같은 키워드만 반복 === 역효과. 
비슷한 키워드로 대체해서 사용 or 핵심 키워드&amp; 관련 키워드 포함시키는 것이 좋다.</p>
<h3 id="4-콘텐츠">4. 콘텐츠</h3>
<h4 id="개성있는-브랜딩">개성있는 브랜딩</h4>
<p>아이디어나 이름이 겹치지 않는다면, 관련 키워드를 검색했을 때 해당 웹 사이트가 상위권에 뜰 가능성이 매우 높다. 꼭 이름이나 서비스 종류가 이니더라도 웹사이트만의 독특한 이벤트나 콘텐츠를 만들어내는 것도 훌륭한 방법</p>
<h4 id="복붙-금지">복붙 금지</h4>
<p>타 사이트의 글을 그대로 복사해서 사용하면 검색 엔진은 중복 문서로 판정 아예 검색 결과에서 생랼해버리기도 한다. 
타 사이트의 글을 이용하고 싶다면, 일부만 가져오면서 링크를 첨부하여 출처를 표기하는 것이 좋다.</p>
<h4 id="간결한-제목과-설명글">간결한 제목과 설명글</h4>
<p>웹사이트와 관련있는 키워드라고 해도, 같은 키워드를 너무 많이 반복해서 작성해도 좋지 않다. 최악의 경우 스팸 요소가 있는 사이트로 분류될 가능성도 있으니 조심하자.</p>
<h4 id="최대한-글자로-작성하기">최대한 글자로 작성하기</h4>
<p>적절한 이미지의 사용은 콘텐츠의 품질을 높여준다. 하지만 글자로 적어도 될 내용을 굳이 이미지로 만들어서 작성하는 것은 SEO에는 도움이 되지 않는다. </p>
<p>꼭 이미지를 넣어야 한다면 <code>alt</code> 속성을 사용하여 해당 이미지에 대한 설명을 텍스트로 작성하는 것이 좋다.</p>
<pre><code class="language-js">// O
&lt;img src=&#39;nada.img&#39; alt=&#39;nada_blog_logo&#39; /&gt;
//X
&lt;img src=&#39;nada.img&#39; alt=&#39;나다 블로그 로고, 클립, 소스, 메뉴 네브바 등&#39; /&gt;
</code></pre>
<h2 id="웹-접근성">웹 접근성</h2>
<hr>
<h3 id="웹-접근성이란">웹 접근성이란?</h3>
<p>일반적으로 장애인, 고령자 등이 웹 사이트에서 제공하는 정보에 비장애인과 동등하게 접근하고 이해할 수 있또록 보장하는 것을 뜻한다. 또한 비장애인도 정보 접근에 제한을 받는 불편함을 겪을 수 있다.</p>
<p>궁극적인 목적으로 어떤 상황이든, 어떤 사람이든 정보를 제공받지 모하는 경우가 없도록 하는 것이다.</p>
<h3 id="웹-접근성-실태">웹 접근성 실태</h3>
<p>우리나라의 웹 접근성 수준은 높은 정보화 수준에도 불구하고 높지 않다. 
일례로 시력이 안 좋은 경우 화면의 텍스트를 음성으로 읽어주는 스크린 리더를 사용하는 경우가 많다. 하지만 이미지에 들어있는 글자의 경우는 스크린 리더가 인식할 수 없어 음성으로 읽어줄 수 없다.
국내 온라인 쇼핑몰 사이트를 보면 상품의 상세정보가 이미지로 올라와있는 경우가 많고, 텍스트로 표시된 정보는 굉장히 제한적인 것을 볼 수 있다.
해외 쇼핑몰 사이트 같은 경우 상품의 기본 정보가 모두 텍스트로 작성되어 있다. 또한 페이지에 첨부되어 있는 모든 이미지에 이미지를 설명하는 텍스트가 함께 작성되어 있다. </p>
<p>국내에서는 대부분의 경우 웹 접근성에 대한 인식이 낮은 편이고, 잘 지켜지지 않는 경우가 많다.
웹 접근성을 갖추기 위해 노력하면 정보의 평등에 다가갈 수 있는 것은 물론이고, 그 외에도 여러 가지 효과를 기대할 수 있다.</p>
<h3 id="웹-접근성을-갖추면-얻을-수-있는-효과">웹 접근성을 갖추면 얻을 수 있는 효과</h3>
<ol>
<li>사용자층 확대</li>
</ol>
<p>웹 접근성을 확보하면 장애인, 고령자 등 정보 소외 계층도 웹 사이트를 자유롭게 이용할 수 있게 된다. 
그만큼 이용자를 늘릴 수 있고, 새로운 고객층을 확보할 수 있게 된다.</p>
<ol start="2">
<li>다양한 환경 지원</li>
</ol>
<p>웹 접근성을 향상시키면 다양한 환경, 다양한 기기에서의 웹 사이트를 자유롭게 사용할 수 있게 되므로 서비스의 사용 범위가 확대된다. 자연스럽게 서비스 이용자 수 증가를 기대할 수 있다.</p>
<ol start="3">
<li>사회적 이미지 향상</li>
</ol>
<p>기업의 사회적 책임에 대한 중요성이 점점 증가하고 있는 상황에서, 웹 접근성 확보를 통해 기업이 정보 소외계층을 위한 사회 공헌 및 복지 향상에 힘쓰고 잇음을 보여줄 수 있다. 그만큼 이용자 수 증가는 물론 충성 고객을 확보할 수 있는 가능성이 늘어나게 된다.</p>
<h2 id="wai-aria">WAI-ARIA</h2>
<hr>
<ul>
<li>WAI <code>Web Accessibility Initiative</code> : 웹 표준을 정하는 W3C에서 웹 접근성을 담당하는 기관</li>
<li>ARIA <code>Accessible Rich Internet Applications</code> : 장애가 있는 사람들이 웹 콘텐츠와 웹 응용 프로그램에 더 쉽게 액세스할 수 있도록 하는 기술<ul>
<li>RIA <code>Rich Internet Applications</code> : 따르 프로그램을 설치하지 않아도 웹 브라우저를 통해 사용할 수 있는 편리성 + 프로그램을 직접 설치해서 사용하는 것처럼 빠른 반응의 사용자 인터페이스를 동시에 가지는 웹 애플리케이션. SPA 를 의미하는 경우가 많다.</li>
</ul>
</li>
</ul>
<p>정리하자면, WAI-ARIA는 WAI에서 발표한 RIA 환경에서의 웹 접근성 기술 규격이다. </p>
<h3 id="wai-aria의-필요성">WAI-ARIA의 필요성</h3>
<hr>
<p>WAI-ARIA는 HTML 요소에 추가적으로 의미를 부여할 수 있게 해준다. </p>
<ol>
<li>시멘틱 요소만으로 의미를 충분히 부여할 수 없는 상황에 WAI-ARIA를 사용하면 HTML요소에 추가적인 의미를 부여하여 더 원활하게 페이지를 탐색할 수 있게 도와준다.  <ul>
<li><code>시맨틱 요소만으로 의미를 충분히 부여할 수 없는 상황</code> 이라는 것은 시맨틱 요소만으로 충분한 상황에서는 사용하지 않아야 한다는 의미. WAI-ARIA는 보조적인 역할로만 사용해야 한다.</li>
</ul>
</li>
<li>SPA처럼 AJAX를 사용하는 상황, 즉 새로고침 없이 페이지의 내용이 바뀌는 상황에서도 변경된 영역에 대한 정보를 전달해줄 수 있어 동적인 콘텐츠엣도 웹 접근성을 향상시킬 수 있다.</li>
</ol>
<h3 id="wai-aria-사용법">WAI-ARIA 사용법</h3>
<hr>
<p>WAI-ARIA는 HTML 태그 내부에 속성을 추가함으로서 의미를 부여해줄 수 있다.
WAI-ARIA의 속성에는 크게 세가지 분류가 있다.</p>
<ul>
<li>역할 role : HTML 요소의 역할을 정의하는 속성</li>
<li>상태 state : 요소의 현재 상태를 나타내는 속성</li>
<li>속성 property : 요소의 특징을 정의하는 속성 attribute</li>
</ul>
<ol>
<li><p>역할 role
HTML의 요소 종류와 역할이 서로 맞지 않을 때, 어떤 역할을 하는 요소인지 명시해줄 때 사용할 수 있는 속성.
예를 들어, 버튼으로 사용되는 요소를 만들었는데 <code>&lt;div&gt;</code>요소를 사용했다면, 이 요소가 버튼 역할을 하고 있음을 다음과 같이 표시해줄 수 있다.</p>
<pre><code class="language-js">&lt;div role=&#39;button&#39;&gt;div이지만 button으로 사용되는 요소&lt;/div&gt;</code></pre>
<p>주의할 점은, HTML요소로 충분히 파악할 수 있는 내용을 또 설명해줄 필요는 없다.
또한, 시멘틱 요소 본연의 의미를 임의로 바꾸지 않아야 한다.</p>
</li>
<li><p>상태 state</p>
</li>
</ol>
<ul>
<li>aria-selected</li>
</ul>
<p>탭 컴포넌트에서 필요한 정보가 역할 뿐인가? 어떤 탭이 선택되어 있는지도 알 수 있어야 하지 않을까?
이럴 때 사용하는 속성이 바로 여러 개의 선택 가능한 요소 중에서 선택 상태인 요소를 표시할 수 있는 <code>aria-selected</code>라는 속성이다.</p>
<pre><code class="language-js">&lt;div role=&#39;tablist&#39;&gt;
  &lt;li role =&#39;tab&#39; aria-selected=&#39;true&#39;&gt;Tab1&lt;/li&gt;
  &lt;li role =&#39;tab&#39; aria-selected=&#39;false&#39;&gt;Tab2&lt;/li&gt;
  &lt;li role =&#39;tab&#39; aria-selected=&#39;false&#39;&gt;Tab3&lt;/li&gt;
&lt;/div&gt;

&lt;div role=&#39;tabpanel&#39;&gt;Tab menu ONE&lt;/div&gt;
&lt;div role=&#39;tabpanel&#39;&gt;Tab menu Two&lt;/div&gt;
&lt;div role=&#39;tabpanel&#39;&gt;Tab menu THREE&lt;/div&gt;</code></pre>
<p>이제 3개의 탭 중에서 첫 번째 탭이 선택된 상태임을 알 수 있게 됐다.
이 외에도 아코디언 UI가 펼쳐진 상태인지 표시해주는 <code>aria-expanded</code>,요소가 숨긴 상태인지를 표시하는 <code>aria-hidden</code>등의 속성이 있다.</p>
<ol start="3">
<li>속성 property</li>
</ol>
<ul>
<li>aria-label</li>
</ul>
<p>이따금 요소에 대한 정보를 전혀 얻을 수 없는 경우가 발생하기도 한다.
텍스트 콘텐츠 없이 이미지로만 만들어진 버튼이 대표적인 예시이다.</p>
<pre><code class="language-js">&lt;button aria-label=&#39;닫기&#39;&gt;&lt;img src=&#39;close.png&#39; /&gt;&lt;/button&gt;
&lt;button aria-label=&#39;검색&#39;&gt;&lt;img src=&#39;sersh.jpeg&#39; /&gt;&lt;/button&gt;</code></pre>
<ul>
<li>aria-live</li>
</ul>
<p><code>aria-live</code>속성은 해당 요소가 실시간으로 내용을 갱신하는 영역인지 표시한다.
즉, 브라우징 도중에 내용을 띄우는 <code>alert</code> ,<code>modal</code> , <code>off(defalt)</code> 가 있다.</p>
<ol>
<li><code>polite</code> : 스크린 리더가 현재 읽고있는 내용을 모두 읽고나서 갱신된 내용을 사용자에게 전달한다.</li>
<li><code>assertive</code> : 스크린 리더가 현재 읽고있는 내용을 중단하고 갱신된 내용을 바로 사용자에게 전달한다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹 표준& 접근성]]></title>
            <link>https://velog.io/@nada_1221/%EC%9B%B9-%ED%91%9C%EC%A4%80-%EC%A0%91%EA%B7%BC%EC%84%B1</link>
            <guid>https://velog.io/@nada_1221/%EC%9B%B9-%ED%91%9C%EC%A4%80-%EC%A0%91%EA%B7%BC%EC%84%B1</guid>
            <pubDate>Sat, 10 Sep 2022 09:17:28 GMT</pubDate>
            <description><![CDATA[<h2 id="웹-표준">웹 표준</h2>
<hr>
<p><code>웹</code>이란 무엇인가?</p>
<blockquote>
<p>인터넷은 웹 기반으로 작동한다 O or X ?</p>
</blockquote>
<p>정답은 X, 인터넷이 웹보다 좀 더 포괄적인 개념이기 때문.</p>
<p>인터넷은 <code>전 세계적으로 연결되어 있는 컴퓨터 네트워크 통신망</code>을 의미하며, 웹 뿐만 아니라 온라인 게임, 모바일 앱, 이메일 등 네트워크를 사용하는 다양한 서비스들을 모두 포함한다.</p>
<p>웹과 인터넷을 혼동하지 말자.</p>
<p>그렇다면 웹은 무엇을 의미할까?
웹은 <code>공간</code>으로 정의할 수 있다. 
우리가 쉽게 접하는 웹툰의 어원 역시 World Wide Web + Cartoon을 합친 것이다. 인터넷만 연결되어 있다면 웹이라는 공간 안에서 만화를 자유롭게 보고 댓글도 달 수 있다.</p>
<p>웹을 정상적으로 구동시키기 위해서는 개발자들이 각 브라우저마다 따로 개발을 해줘야만 했던 시대가 있었다. 이런 수고를 없애고 웹 개발의 형식을 통일시킨 것이 바로 <code>웹 표준</code>이다.</p>
<h3 id="웹-표준-2">웹 표준 #2</h3>
<hr>
<p>웹 표준이란 W3C에서 권고하는 <code>웹에서 표준적으로 사용되는 기술이나 규칙</code>으로, 사용자가 어떤 운영체제나 브라우저를 사용하더라도 웹 페이지가 동일하게 보이고 정상적으로 작동할 수 있도록 하는 웹 페이지 제작 기법을 담고있다.</p>
<p>웹 개발에 사용되는 언어인 HTML,CSS,JS등의 기술을 다룬다. 이 세 기술은 화면의 구조,표현,동작을 각각 담당한다.</p>
<h3 id="웹-표준의-장점">웹 표준의 장점</h3>
<hr>
<ol>
<li><p>유지 보수의 용이
각 영역이 분리되면서 유지 보수가 용이해졌고, 코드가 경량화되면서 트래픽 비용이 감소하는 효과도 생김.</p>
</li>
<li><p>웹 호환성 확보
웹 표준을 준수하여 웹 사이트를 제작하면 웹 브라우저의 종류나 버전, 운영 체제나 사용 기기 종류에 상관없이 항상 동일한 결과가 나오도록 할 수 있다.</p>
</li>
<li><p>검색 효율성 증대
웹 표준에 맞춰 웹 사이트를 작성하는 것 만으로도 검색 엔진에서 더 높은 우선 순위로 노출될 수 있다. 적절한 HTML 요소의 사용, 웹 페이지에 대한 정확한 정보 작성 등 검색 효율성과 관련된 내용도 웹 표준에서 다루고 있기 때문.</p>
</li>
<li><p>웹 접근성 향상</p>
</li>
</ol>
<h2 id="semantic-html">Semantic HTML</h2>
<hr>
<p>시맨틱 HTMl은 합성어이며, 각 단어의 의미는 다음과 같다.</p>
<ul>
<li>semantic : 의미의, 의미가 있는</li>
<li>HTML : 화면의 구조를 만드는 마크업 언어</li>
</ul>
<p>HTML이 의미를 갖는다는 것은 어떤 의미일까?
HTML을 사용하는 두 가지 방식을 보고 비교하여 이해해보자.</p>
<h3 id="1-div와-span으로-화면-구성하기">1. <code>&lt;div&gt;</code>와 <code>&lt;span&gt;</code>으로 화면 구성하기</h3>
<p><img src="https://ask4helps.com/wp-content/uploads/2020/01/diffrence-div-span.jpg" alt="">
예시의 HTML 구조만 보고 각 요소들이 어떤 역할을 할지 알아낼 수 있을까? </p>
<p>추측은 가능하지만 확신을 할 수 는 없다. 어떤 내용이 들어갈지 명시되어 있지 않기 때문.</p>
<h3 id="2-시맨틱-요소로-화면-구성하기">2. 시맨틱 요소로 화면 구성하기</h3>
<p><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zSrkp3lE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1636103034458/R43hLkp7H.jpeg" alt=""></p>
<p>요소가 어떤 내용을 담게 될지, 어떤 기능을 하게 될지 확실하게 의미를 가지고잇는 요소를 시맨틱 요소라고 한다. 
그리고 시맨틱 요소를 적절하게 사용하여 구성한 HTML을 시맨틱 HTML이라고 한다.</p>
<h3 id="시맨틱-html의-필요성">시맨틱 HTML의 필요성</h3>
<hr>
<ol>
<li><p>개발자간 소통
수많은 귀찮은 과정을 시맨틱한 요소를 사용하기만 해도 없앨 수 있다. 적어도 각 요소의 기능을 정의하느라 쏟아야 하는 시간은 들지 않을 것.</p>
</li>
<li><p>검색 효율성
시맨틱 요소를 사용하면, 어떤 요소에 더 중요한 내용이 들어있을지 우선 순의를 정할 수 있고, 우선 순위가 높다고 파악된 페이지를 검색 결과 상단에 표시하게 된다.</p>
</li>
<li><p>웹 접근성
조건을 떠나 항상 동일한 수준의 정보를 제공할 수 있어야 함을 뜻한다. 시맨틱 요소만 잘 사용해도 웹 접근성을 향상시킬 수 있다.</p>
</li>
</ol>
<h3 id="시맨틱-요소의-종류">시맨틱 요소의 종류</h3>
<hr>
<table>
<thead>
<tr>
<th align="center">요소 종류</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>&lt;header&gt;</code></td>
<td align="center">페이지나 요소의 최상단에 위치하는 머릿말 역할의 요소</td>
</tr>
<tr>
<td align="center"><code>&lt;nav&gt;</code></td>
<td align="center">메뉴, 목차 등에 사용되는 요소</td>
</tr>
<tr>
<td align="center"><code>&lt;aside&gt;</code></td>
<td align="center">문서와 연관은 있지만, 직접적인 연관은 없는 내용을 담는 요소</td>
</tr>
<tr>
<td align="center"><code>&lt;main&gt;</code></td>
<td align="center">이름 그대로 문서의 메인이 되는 주요 콘텐츠를 담는 요소</td>
</tr>
<tr>
<td align="center"><code>&lt;article&gt;</code></td>
<td align="center">게시글, 뉴스 기사 등 독립적으로 구분해 재사용할 수 있는 부분을 의미하는 요소. 각각의 아티클을 구분하기 위한 수단이 필요하며, 보통 제목(<code>&lt;hgroup&gt;</code>)을 포함하는 방법을 사용한다.</td>
</tr>
<tr>
<td align="center"><code>&lt;section&gt;</code></td>
<td align="center">문서의 독립적인 구획을 나타내며, 딱히 적합한 의미의 요소가 없을 때 사용한다. 제목(<code>&lt;hgroup&gt;</code>)을 포함하는 경우가 많다.</td>
</tr>
<tr>
<td align="center"><code>&lt;hgroup&gt;</code></td>
<td align="center">제목을 표시할 때 사용하는 요소로, <code>&lt;h1&gt;</code>~<code>&lt;h6&gt;</code>요소가<code>hgroup</code>이다.</td>
</tr>
<tr>
<td align="center"><code>&lt;footer&gt;</code></td>
<td align="center">페이지나 요소의 최하단에 위치하는 꼬릿말 역할의 요소</td>
</tr>
</tbody></table>
<h2 id="크로스-브라우징">크로스 브라우징</h2>
<hr>
<p>웹 사이트에 접근하는 브라우저의 종류에 상관 없이 동등한 화면과 기능을 제공할 수 있도록 만드는 작업을 의미.
여기서 중요한 포인트는 <code>동일한</code>이 아니라 <code>동등한</code>이라는 표현을 쓴다는 것이다.
크로스 브라우징은 모든 브라우저에서 완전히 똑같은 화면이 보이도록 만드는 것이 아니다. 
모든 브라우저에서 동등한 수준의 정보와 기능을 제공하는 것이다.</p>
<h3 id="크로스-브라우징-워크-플로우">크로스 브라우징 워크 플로우</h3>
<hr>
<ol>
<li><p>초기 기획
어떤 웹 사이트를 만들 것인지 정확하게 결정해야 한다.
어떤 콘텐츠와 기능이 있어야 하는지, 디자인은 어떻게 할지 등의 사항을 결정해야 한다.
그 다음 사이트의 고객이 누구일지 생각해야 한다.
타겟 고객이 주로 사용하게 될 브라우저와 기기를 파악했다면, 여기에 맞는 기술을 사용해서 개발할 수 있또록 기획해야 한다.</p>
</li>
<li><p>개발
코드를 작성할 때 사용하는 코드가 각 브라우저에서의 호환성이 어떤지 파악하고 사용해야 한다. 
코드를 작성하다보면 크로스 브라우징이 힘든 상황을 만나게 될 수도 있는데, 이럴 경우 대체 수단을 마련해야 한다. </p>
</li>
<li><p>테스트/ 발견
각 기능을 구현한 후에는 그 기능에 대한 테스트가 필요하다.</p>
</li>
</ol>
<ul>
<li>안정적인 데스크톱 브라우저에서 테스트를 진행한다
(ex. 크롬, 엣지, 파이어폭스 ...)</li>
<li>휴대폰 및 태블릿 브라우저에서 테스트를 진행한다.
(ex. 삼성 인터넷, 사파리, 크롬 ...)</li>
<li>Window, Linux, Mac등 다양한 운영 체제에서도 테스트를 진행한다.</li>
</ul>
<p>직접 테스트도 가능하지만, 자동으로 테스트를 진행해주는 도구를 이용하는 것도 방법이다.
<code>TestComplete</code>, <code>LambdaTest</code>, <code>BitBar</code> 등의 크로스 브라우징 테스트 툴이 있다.</p>
<ol start="4">
<li>수정/ 반복
테스트 단계에서 버그가 발견되었다면 수정이 필요하다. 버그가 발생하는 위치를 최대한 좁혀서 특정하고, 버그가 발생하는 특정 브라우저에서의 해결 방법을 정해야 한다. 섣불리 코드를 수정했다가는 다른 브라우저에서 버그가 발생할 수 있으므로, 조건문을 작성해 다른 코드를 실행하게 하는 방식으로 고쳐나가는 것이 좋다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React]상태 관리]]></title>
            <link>https://velog.io/@nada_1221/React%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC</link>
            <guid>https://velog.io/@nada_1221/React%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC</guid>
            <pubDate>Wed, 31 Aug 2022 15:44:53 GMT</pubDate>
            <description><![CDATA[<h2 id="상태-관리">상태 관리</h2>
<hr>
<p>프론트엔드 개발에서의 상태 관리.
React가 상태 관리를 위한 라이브러리는 아니다.
그러나 상태 관리의 주요 원칙을 배우고 이를 따라간다면, 컴포넌트 간 서로 느슨하게 결합된<code>loose coupled</code>, 구조적으로 아름다운 코드를 작성할 수 있다.</p>
<p>상태란 무엇인가? 
<code>UI에 동적으로 표현될 데이터</code></p>
<p>Side Effect란 무엇인가? 
<code>함수(또는 컴포넌트)의 입력 외에도 함수의 결과에 영향을 미치는 요인</code>
<code>대표적인 예: 네트워크 요청 (백엔드API요청)</code></p>
<p>React의 주요 개발 원칙 중 하나는 UI를 페이지 단위가 아닌 컴포넌트 단위로 보는 것이다.</p>
<blockquote>
<p><a href="https://ko.reactjs.org/docs/thinking-in-react.html">리엑트로 사고하기</a> &lt;-- 읽고가자</p>
</blockquote>
<p>상태를 구분하는 데에는 절대적인 기준이나 법칙이 있는 것은 아니지만, 로컬 or 전역 상태로 나눠서 접근해보자.</p>
<p>로컬 상태는 특정 컴포넌트 안에서만 관리되는 상태이며, 전역 상태는 프로덕트 전체 혹은 여러가지 컴포넌트가 동시에 관리하는 상태를 말한다.</p>
<p>로컬 상태를 구분하는 것은 쉽다. 보통 컴포넌트 내에서만 영향을 끼치는 상태는 로컬 상태이다.</p>
<p>다른 컴포넌트와 데이터를 공유하지 않는 폼<code>form</code> 데이터는 대부분 로컬 상태이다.</p>
<p><code>input box</code>,<code>select box</code> 등과 같이 입력 값을 받는 경우가 이에 해당한다.</p>
<p>전역 상태는 다른 컴포넌트와 상태를 공유하고 영향을 끼치는 상태이다.</p>
<p>서로 다른 컴포넌트가 사용하는 상태의 종류가 다르면, 꼭 전역 상태일 필요는 없다. 출처<code>source</code>가 달라도 된다. </p>
<pre><code class="language-js">Component A = wish list
Component B = profile data
/** Ok 상태의 종류(wish list &amp; profile data) 가 다름**/</code></pre>
<p>그러나, 서로 다른 컴포넌트가 동일한 상태를 다룬다면, 이 출처는 오직 한 곳이어야 한다. 만일 사본이 있을 경우, 두 데이터는 서로 동기화<code>sync</code>하는 과정이 필요한데, 이는 문제를 어렵게 만든다. </p>
<pre><code class="language-js">Component A = wish list
Component B = wish list copy
/** 서로 동일한 상태(wish list)를 다루는데 
서로 다른 출처(Component A &amp; B)로 부터 가져오는 것은 피해야 한다.  **/</code></pre>
<p>한 곳에서만 상태를 저장하고 접근해라. 여기서 <code>하나의 출처</code>는 다른 말로 이야기하면 <code>전역 공간</code>이라고 볼 수 있다.</p>
<p>데이터 무결성을 위해, 동일한 데이터는 항상 같은 곳에서 데이터를 가지고 오도록 하자. 신뢰할 수 있는 단일 출처<code>Single source of truth</code> 원칙은 프론트엔드 뿐만 아니라 다양한 곳에서 언급되는 원칙이다.</p>
<p>전역으로 상태를 관리해야 하는 경우는 어떤 것이 있을까?</p>
<p>네이버를 비롯한 여러 사이트에서 다크 모드 기능을 이용해 본 적이 있을 것이다. 이 경우 모든 페이지, 모든 컴포넌트에 다크 모드가 적용이 되어야 하기 때문에 이러한 테마 설정을 전역으로 관리할 수도 있다.</p>
<p>그리고 국제화 <code>Globalization</code> 설정도 마찬가지다.</p>
<p>사용자가 사용하는 브라우저나, 운영체제가 특정 언어를 사용하고 있음을 알아내서, UI에 필요한 텍스트 리소스를 따로 저장한 후, 전역 상태로 관리하기도 한다.</p>
<p>이 기능의 경우에도 모든 컴포넌트에서 사용자 언어로 표현이 되어야 하기 때문에 전역에서 상태 관리가 필요하다.</p>
<p>상태관리를 도와주는 각종 툴이 있다.
현업에서 쓰일 가능성이 매우 높으므로 상태 관리 라이브러리가 어떤 문제를 해결해주는 지만 알아보자.</p>
<ul>
<li>React Context</li>
<li>Redux</li>
<li>MobX</li>
</ul>
<ol>
<li>전역 상태를 위한 저장소를 제공한다.</li>
<li>프로퍼티 내려꽂기 <code>props drilling</code> 문제를 해결한다.</li>
</ol>
<p>상태관리 툴이 반드시 필요할까? 그것은 아니다. 상태 관리 툴이 없어도 충분히 규모 있는 애플리케이션을 만들 수 있다.</p>
<h2 id="props-drilling이란">Props Drilling이란</h2>
<hr>
<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAC0CAMAAAB4+cOfAAABDlBMVEX///8isUz2/Pjv+vIApSBrxYLR6dUAqTDp9Ov8/v3j9OdZwHOW0aGDypHQ69YArDi+4cQAohKLzpotsVBkwnuy37zH58643r8Ur0UArD7e8eJ9yI0AqCf//fCi4tAAtGooqC5huFPh+//v8NBuvVd00bDu/v+k2bCVyn2KxnBVyJouri206OD///j1/v/n7cc7tlvH7+i52qGp0YoXt3bv89sAoi8aqhs8uGljxZJItESD1biCx3lbvWcZs1fN8Omo1JlXwohhvGZNt1LX6cQ0vYVFvW5it0JZszJ/wmPN4rOz2qmF07LY68xAwIO97OSk4dN607SSy4qF0qdhyqNKxZQAqkue0Zj39du55NGQ1cAqAAAGxUlEQVR4nO2dC1PaShSAD0kQgmhAXgnyELBErTxEQUErWl8tltZaa+X//5G7u4FeiNk71zBOMtnzzaiJZGcO32w2YTknC4AgCIIgCIIgLpCXQfI6+nckVVBcU9jwOvp3JGXKUZfIq4EWk3HfNo1inEExHMQRIxHU/99WGDGN45N0Wu9zjy1mF62JI+bjPnn3hQfaddg/VOnvptQEaPWaC23FEgODUzhLfTofwkX40x6ctVOXTfgcPtFPG1d6uz7fViwx18mD6xMVdm5g5wjgsAxQeYKtJ7juNVu6qD1m0G63bydkK5s5O4KdPYC7y1zmrAzEWE2piiuGnUoA3Ug/MRXzpZ/LJSZMTBLFHN4AdCwxX38TT+vCizl+YH9HxuS+UIZdKkX5Ni6cQvKBinlJ9sUcfCE/fd/jeEbOQyxGNov38SF5QYLGShPklYUbGXHEvBEUwwHFcEAxHFAMh2CLyblvGw60GP5keMRC0Mnw9SyP9bQeCoX0MP+IbN7r6L1hk4kJcq9wCYrhgGI4oBgOKIYDiuGAYjisoRgn4hu3IcrqRtzrUPxFyAhZGG2vQ/EXuZkYLeF1KP5C0qdiUl5H4jdMq8sY2GHsTLuM12H4jzg1Y+A16RWyRsUEOWXVLeQOT8cO40AsEtJiXgfhS1aNsNch+JN1Jep1CD7lDSmcQWNlGYI8AKUiSxDkKYlUBlSXBPwrWvzu2hkUwwHFcLCJkZuc45wQR8yFng71mzC6ZHtXD8WrA7ox+k5/pYb2tsKIOTyvA+we0RxfSkwqKj/oRqdMfm3rT/a2oogpJqmG7lqzc3Sf/gaQGxYLP6Ab3jwjYrr62Kja2ooipqVN03w7kVL0+AGUEhFTLJRiFSLm4jd8KdnaiiJmZMzEkFNp+ydsETEH9DSiP1v71hk1jyhiar3pucLEfLDEHP5mYmqRdioVOVhsK4qYxkdaSjBK1ufF0G0iZnePvLRtG35FEUPOJTLWDp5mPYaMMckfL8pBcVBuJPdh7lybIowYGKdvb8kIOzYB7icQHzbiQ7j+tJoxu3F649fYWLyVEUfMG0ExHFAMBxTDAcVwCLYYM+aWaKCfHxNSkjwiGiXCfT2prHkd/TsicVGnWZvqfxzidfTegOmsHFAMBxTDAcVwQDEcUAwHFMMBiyycUNPpNkvzbacx3WyB21nKvJ72OhR/kdVmRRbrXofiM1LTDrPqdSB+I2MVWWgrXgfiO6wug2Vcr2B1OcYSM3xBRdWxKscZUw8ZptdB+BFZCxmy10H4kk0NPxA4Ek0JOqsLy5VRBNmaXFimliDrdfjvh6wk1l1jBFlMconLTrDFLFFzhGI4oBgOKIaDOGLG7VTosgrdNMvOvPgGjywZnOx3wwR7ZrgwYlrKhOgw6rUeE7MyhMoHutFNVmu9qtQdnC42FkYM09B4HNZ6ifCvJozXofITGn/C8UK1RlN8aZb4PKKIaRxbT9+HWuRSqjzRR+8TMdt9+SxCxEyy9yFbxZIoYqyyHKBFBXWaHb67B5XTlwIZcxQixjTjbdsgI4qYaY9RmZiLqZjWc9MSQ06la1vKvChirCKK4vH+vJia8a+YVk9QMV2lBOpOWWViWMVJ5af6sQQ7RExvKOevBB186Q1LO9SvQ3ezDte/4P4U/pTovc2vzXp3MxzezNgmYMQR80ZQDAcUwwHFcAi2GJzBc0RWNC46w+AfUAiwGDWX4JFlX13rce4BiZygj/ZiYoJ8urgFxXBAMRxQDAcUwwHFcEAxHFCME5KZsW7w1kzMDJ8nX5iuS6BrQS4idkF4VmShYX7iArMiCx2rcmycWF1GE/STIh+ry2CHeQ0rstDwcv0Ktl4OFp84kML7O2doKZfXMfgSycBqJWc2NK8j8CviLpWTXV2GAHvLaXHXrBWCLEZ33zamBFmM4b5tHsU4g2I4CCRGTZiZOoBspYbkJTXP1m9g+3nTPscpjpju1mX2QnuYPTV9UJpm/tL9w+dMovJ9IQlPHDF3NJ11pDQ7RxBlCui6BCDLRMw1W5TgeKGYQBgxLwp7yrwEnfN2+rlKewwR83j+WS/DV/YcdWnBhDBi/iZ+d86bcHdqPWW+pdfhsAz2whOKgGLm1yW4YWOM0GJeFFpdUow3HRZs+ErXJaCPnp9DGDGwTd/9xfNCjxnRK1IZWpEqLU9ZKD8RR0xx8D33aBywy/PdB0jSy3Vj0P8Toeuf6KY52FtoK44YgHEmQW7pJJlcpCWINulVu5Gb0H2QMxlbHZdIYt4EiuGAYjigGA4ohkOwZ/C0jTW3hIM855sNL0OAxSAIgiAIgiAIgiBIgPkHvDPjbwN91WwAAAAASUVORK5CYII=" alt="">
<code>Props Drilling</code>은 상위 컴포넌트의 state를 props를 통해 전달하고자 하는 컴포넌트로 전달하기 위해 그 사이는 props 전달하는 용도로만 쓰이는 컴포넌트 들을 거치면서 데이터를 전달하는 현상을 의미한다.</p>
<h3 id="props-drilling의-문제점">Props Drilling의 문제점</h3>
<p>Props의 전달 횟수가 5회 이내로 많지 않다면 큰 문제가 되지 않는다. 하지만 규모가 커지고 구조가 복잡해지면서 Props의 전달 과정이 늘어난다면 아래와 같은 문제가 발생한다.</p>
<ul>
<li>코드의 가독성이 매우 나빠지게 된다.</li>
<li>코드의 유지보수 또한 힘들어진다.</li>
<li>state 변경시 Props 전달 과정에서 불필요하게 관여된 컴포넌트들 또한 리렌더링이 발생한다.
따라서, 웹성능에 악영향을 줄 수 있다.</li>
</ul>
<h3 id="해결-방법">해결 방법</h3>
<hr>
<p>과도한 <code>Props Drilling</code>을 방지하기 위한 방법으로는 컴포넌트와 관련있는 state는 될 수 있으면 가까이 유지하는 방법과 상태관리 라이브러리릇 ㅏ용하는 방법이 있다. 상태관리 라이브러리를 사용하게 되면 전역으로 관리하는 저장소에서 직접 state를 꺼내쓸 수 있기 때문에 <code>Props Drilling</code>을 방지하기에 매우 효과적이다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React]Custom component]]></title>
            <link>https://velog.io/@nada_1221/ReactCustom-component</link>
            <guid>https://velog.io/@nada_1221/ReactCustom-component</guid>
            <pubDate>Fri, 26 Aug 2022 07:47:10 GMT</pubDate>
            <description><![CDATA[<h2 id="cdd">CDD</h2>
<hr>
<h3 id="component-driven-development">Component-Driven Development</h3>
<p>프로잭트 중 이전에 요청 받았던 버튼을 똑같이 사용하도록 요청받았다.</p>
<p>여러 프로젝트 혹은 여러 팀 간에 같은 UI 컴포넌트를 공유한다면,
디자인과 개발 단계에서부터 재사용할 수 있는 UI 컴포넌트를 미리 디자인하고 개발하면 이런 고민을 해결할 수 있다.</p>
<p>이 고민을 해결하기 위해 등장한 개발 방법이 바로 Component Driven Development(CDD) 이다.
레고처럼 조립해 나갈 수 있는 부품 단위로 UI 컴포넌트를 반들어 나가는 개발을 진행할 수 있다.</p>
<h2 id="css-in-js">CSS in JS</h2>
<hr>
<p><img src="https://cdn-images-1.medium.com/max/1000/1*yBxZo9LNEjRaL7eKUBqRSA.png" alt="">
인터넷이 만들어진 이후 기술의 발달과 함께 사용자들은 다양한 환경(디바이스)에서 인터넷을 사용하기 시작했다.</p>
<p>이에따라 개발자들의 CSS 작성 방식도 꾸준히 진화해 오고 있다.</p>
<p>CSS 작업을 효율적으로 하기 위해 구조화된 CSS의 필요성이 대두되었고, CSS를 구조화하는 방법에 대한 연구가 필요해졌다.</p>
<p>CSS 전처리기 <code>CSS Preprocessor</code> 라는 개념이 등장했다.
CSS가 구조적으로 작성될 수 있도록 도움을 주는 도구이다.</p>
<p>여러가지 요인으로 CSS 문서는 양이 많아지고 이로 인해 이후 유지관리에 많은 영향을 끼친다. 
이런 CSS의 문제점들을 프로그래밍 개념( 변수, 함수, 상속 등)을 활용하여 해결해 나갈 수 있다.</p>
<p>하지만 CSS 전처리기 자체만으로는 웹 서버가 인지하지 못하기 때문에 CSS 전처리기에 맞는 Compiler를 사용해야 하고 컴파일을 하게 되면 실제로 우리가 사용하는 CSS 문서로 변환이 된다.</p>
<p>이를 통해 CSS 파일들을 잘 구조화할 수 있게 되었고, 최소한 CSS 파일을 몇 개의 작은 파일로 분리할 수 있는 방법이 생겼다.</p>
<h3 id="sass">SASS</h3>
<pre><code class="language-js">/** CSS **/
.alert(
  border: 1px solid color;
)
.button(
  color : color
)
/** --&gt; SASS **/
$base-color: color
.alert(
  border: 1px solid $border-dark
)
.button(
  color: $border-dark
)</code></pre>
<p>CSS 전처리기 중에서 가장 유명한 SASS 는 Syntactically Awesome Style Sheets의 약자로 CSS를 확장해 주는 스크립팅 언어이다.</p>
<p>즉, CSS를 만들어주는 언어로서 자바스크립트처럼 특정 속성의 값을 변수로 선언하여 필요한 곳에 선언된 변수를 적용할 수도 있고, 반복되는 코드를 한 번의 선언으로 여러 곳에서 재사용할 수 있도록 해주는 등의 기능을 가졌다.</p>
<p>하지만 얼마 지나지 않아서 SASS가 &#39;CSS의 구조화&#39;를 해결해 주는 것의 장점보다 다른 문제들을 더 많이 만들어낸다는 것이 밝혀진다.</p>
<p>결국 전처리기가 내부에서 어떤 작업을 하는지 모른채로 스타일이 겹치는 문제를 해결하기 위해 단순히 계층 구조를 만들어 내는 것에 의지하게 되었고, 그 결과 컴파일 된 CSS의 용량은 어마어마하게 커지게 되었다.</p>
<h3 id="css-방법론의-대두">CSS 방법론의 대두</h3>
<hr>
<p>CSS 전처리기의 문제를 보완하기 위해 BEM, OOCSS, SMACSS 같은 CSS 방법론이 대두 되었다. 각각의 장단점이 있으나 결국 세 방법론 모두 같은 지향점을 가지고 있다.</p>
<ul>
<li>코드의 재사용</li>
<li>코드의 간결화 (유지보수 용이)</li>
<li>코드의 확장성 </li>
<li>코드의 예측성 (클래스 명으로 의미 예측)</li>
</ul>
<h3 id="--bem">- BEM</h3>
<hr>
<p><strong>Block, Element, Modifier로 구분하여 클래스명을 작성하는 방법</strong>
<img src="https://keepinguptodate.com/pages/2020/05/05-bem-naming-structure.svg" alt=""></p>
<ul>
<li>Block : 전체를 감싸고 있는 블럭 요소</li>
<li>Element : 블럭이 포함하고 있는 한 조각</li>
<li>Modifier : 블럭 또는 요소의 속성</li>
</ul>
<p>대표적인 CSS 방법론으로는 BEM이 있다.
BEM이란 Block, Element, Modifier로 구분하여 클래스명을 작성하는 방법이며, Block, Element, Modifier 각각은 --dhk __ 로 구분한다.
클래스명은 BEM 방식의 이름을 여러 번 반복하여 재사용할 수 있도록 하며 HTML/CSS/SASS 파일에서도 더 일관된 코딩 구조를 만들어 준다.</p>
<p>하지만 이러한 방법론들에서도 문제점이 발생하기 시작한다.
클래스명 선택자가 장황해지고, 마크업이 불필요하게 커지며, 재사용하려고 할 때마다 모든 UI 컴포넌트를 명시적으로 확장해야만 했다.</p>
<p><code>Encapsulation : 객체의 속성과 행위를 하나로 묶고 실제 구현 내용 일부를 외부에 감추어 은닉하는 개념</code></p>
<p>이 없다는 것이 문제점. 이로 인해 개발자들이 유일한 클래스명을 선택하는 것에 의존할 수 밖에 없었다.</p>
<h3 id="css--in--js의-등장--styled-component">CSS- in- JS의 등장 -Styled-Component</h3>
<hr>
<p>애플리케이션으로 개발 방향이 진화하면서 컴포넌트 단위의 개발은 캡슐화의 중요성을 불러왔다. 
CSS를 컴포넌트 영역으로 불러들이기 위해서 CSS - in -JS가 탄생해서 이 문제를 정확하게 해결했다.</p>
<p>CSS-in-JS에는 대표적으로 Styled-Component가 있다.</p>
<p>기능적<code>Functional</code> 혹은 상태를 가진 컴포넌트들로부터 UI를 완전히 분리해 사용할 수 있는 아주 단순한 패턴을 제공한다. </p>
<table>
<thead>
<tr>
<th align="center"></th>
<th align="center">특징</th>
<th align="center">장점</th>
<th align="center">단점</th>
</tr>
</thead>
<tbody><tr>
<td align="center">CSS</td>
<td align="center">기본적인 스타일링 방법</td>
<td align="center">-</td>
<td align="center">일관된 패턴을 갖기 어려움 <br>!important의 남용</td>
</tr>
<tr>
<td align="center">SASS<br>(preprocessor)</td>
<td align="center">프로그래밍 방법론을 도입하며,<br> 컴파일된 CSS를 만들어내는 전처리기</td>
<td align="center">변수/함수/상속 개념을 활용하여 <br>재사용 가능 <br>CSS의 구조화</td>
<td align="center">전처리 과정이 필요,<br> 디버깅의 어려움이 있음<br> 컴파일한 CSS파일이 거대해짐</td>
</tr>
<tr>
<td align="center">BEM</td>
<td align="center">CSS 클래스명 작성에<br> 일관된 패턴을 강제하는 방법론</td>
<td align="center">네이밍으로 문제 해결,<br>전처리 과정 불필요</td>
<td align="center">선택자의 이름이 장황하고,<br>클래스 목록이 너무 많아짐</td>
</tr>
<tr>
<td align="center">Styled-Componet<br>(CSS-in-JS)</td>
<td align="center">컴포넌트 기반으로<br> CSS를 작성할수 있게 도와주는<br> 라이브러리</td>
<td align="center">CSS를 컴포넌트 안으로 캡슐화,<br>네이밍이나 최적화를 신경 쓸 필요가 없음</td>
<td align="center">빠른 페이지 로드에 불리함</td>
</tr>
</tbody></table>
<h2 id="styled-components">Styled Components</h2>
<hr>
<p>Styled Components는 앞서 배운 CSS in JS라는 개념이 대두되면서 나온 라이브러리.</p>
<p>기존에 HTML,CSS,JS 로 쪼개서 개발하던 방법에서, React 등의 라이브러리의 등장으로 컴포넌트 단위 개발이 주류가 되었지만, CSS는 그렇지 못했단 점에서 출발한 개념.</p>
<p>CSS in JS 라이브러리를 사용하면 CSS도 쉽게 JS 안에 넣어줄 수 있으므로, HTML + JS + CSS까지 묶어서 하나의 JS 파일 안에서 컴포넌트 단위로 개발할 수 있게 된다. </p>
<p>이런 CSS in JS 라이브러리 중에서 현재 가장 인기 있는 라이브러리가 바로 Styled Components이다.</p>
<h3 id="1-컴포넌트-만들기">1. 컴포넌트 만들기</h3>
<hr>
<p>Styled Components로 컴포넌트를 만드는 방법은 다음과 같다.</p>
<pre><code class="language-js">const 컴포넌트이름 = styled.태그종류`
    CSS속성1 : 속성값;
    CSS속성2 : 속성값;
`</code></pre>
<p>Styled Components는 ES6의 Templet Literals 문법을 사용한다. 즉, <code>&#39;</code> 이 아니라 백틱(<code>`</code>) 을 사용한다.</p>
<pre><code class="language-js">import styled from &quot;styled-components&quot;;
//import 를 꼭 해주자.

//Styled Components로 컴포넌트를 만들고
const 컴포넌트이름 = styled.태그종류`
    CSS속성1 : 속성값;
    CSS속성2 : 속성값;
`

export default function App(){
 // React 컴포넌트를 사용하듯이 사용하면 된다.
  return &lt;컴포넌트이름&gt; 내용 &lt;/컴포넌트이름&gt;;
}
</code></pre>
<h3 id="2-컴포넌트를-재활용해서-새로운-컴포넌트-만들기">2. 컴포넌트를 재활용해서 새로운 컴포넌트 만들기</h3>
<hr>
<pre><code class="language-js">const 컴포넌트이름 = styled(재활용할 컴포넌트)`
    추가할 CSS속성1:속성값;
    추가할 CSS속성2:속성값;
`</code></pre>
<p>이미 만들어진 컴포넌트를 재활용해서 새로운 컴포넌트를 만들 수도 있다. 컴포넌트를 선언하고 <code>styled()</code>에 재활용할 컴포넌트를 전달해준 다음, 추가하고 싶은 스타일 속성을 작성해주면 된다.</p>
<pre><code class="language-js">import styled from &quot;styled-components&quot;;
//import 를 꼭 해주자.

//Styled Components로 컴포넌트를 만들고
const 컴포넌트이름1 = styled.태그종류`
    CSS속성1 : 속성값;
    CSS속성2 : 속성값;
`

//만들어진 컴포넌트를 재활용해 컴포넌트를 만들 수 있다
const 컴포넌트이름2 = styled(컴포넌트이름1)`
    추가할 CSS속성1:속성값;
    추가할 CSS속성2:속성값;
`
//재활용한 컴포넌트를 재활용할 수도 있다.
const 컴포넌트이름3 = styled(컴포넌트이름2)`
    추가할 CSS속성1:속성값;
    추가할 CSS속성2:속성값;
`

export default function App() {
  return (
    &lt;&gt;
      &lt;컴포넌트이름&gt; 내용 &lt;/컴포넌트이름&gt;
      &lt;br /&gt;
      &lt;컴포넌트이름2&gt; 내용 &lt;/컴포넌트이름2&gt;
      &lt;br /&gt;
      &lt;컴포넌트이름3&gt; 내용 &lt;/컴포넌트이름3&gt;
    &lt;/&gt;
  );
}</code></pre>
<h3 id="3-props-활용하기">3. Props 활용하기</h3>
<hr>
<p>Styled Component로 만든 컴포넌트도 React 컴포넌트처럼 props를 내려줄 수 있다. 내려준 props 값에 따라서 컴포넌트를 렌더링하는 것도 가능하다.</p>
<pre><code class="language-js">const 컴포넌트이름 = styled.태그종류`
    css속성:${(props)=&gt; 함수 코드}
`</code></pre>
<p>Styled Components는 템플릿 리터럴 문법( <code>${ }</code> )을 사용하여 JavaScript 코드를 사용할 수 있다. props를 받아오려면 props를 인자로 받는 함수를 만들어 사용하면 된다.</p>
<h4 id="1-props로-조건부-렌더링하기">1) Props로 조건부 렌더링하기</h4>
<pre><code class="language-js">const 컴포넌트이름 = styled.태그종류`
    background:${(props)=&gt; props.blue?&quot;blue&quot;:&quot;white&quot;}
`</code></pre>
<p>삼항연산자를 활용해 컴포넌트에 blue라는 props가 있는지 확인하고, 있으면 배경색으로 blue를 없으면 white를 지정해주는 예시코드.</p>
<h4 id="2-props-값으로-렌더링하기">2) Props 값으로 렌더링하기</h4>
<p>props 값을 통째로 활용해서 컴포넌트 렌더링에 활용할 수 있다.</p>
<pre><code class="language-js">const 컴포넌트이름 = styled.태그종류`
    background:${(props)=&gt; props.color?props.color:&quot;white&quot;}
`;
&lt;styled.태그종류&gt;내용1&lt;/stlyed.태그종류&gt;
&lt;styled.태그종류 color=&quot;red&quot;&gt;내용2&lt;/stlyed.태그종류&gt;
&lt;styled.태그종류 color=&#39;yellow&#39;&gt;내용3&lt;/stlyed.태그종류&gt;</code></pre>
<p>똑같이 상항연산자를 사용하고 있지만, 이번에는 <code>props.color</code>가 없다면 <code>white</code>를, 있다면 <code>props.color</code>의 값을 그대로 가져와서 스타일 속성 값으로 리턴해준다. </p>
<pre><code class="language-js">const 컴포넌트이름 = styled.태그종류`
    background:${(props)=&gt; props.color||&quot;white&quot;}
`;
&lt;styled.태그종류&gt;내용1&lt;/stlyed.태그종류&gt;
&lt;styled.태그종류 color=&quot;red&quot;&gt;내용2&lt;/stlyed.태그종류&gt;
&lt;styled.태그종류 color=&#39;yellow&#39;&gt;내용3&lt;/stlyed.태그종류&gt;</code></pre>
<p>꼭 삼항연산자만 사용해야하는 것은 아니다. JS 코드라면 무엇이든 사용할 수 있으므로 원하는 값을 사용할 수 있도록 함수코드를 만들어서 사용하면 된다.</p>
<h4 id="전역-스타일-설정하기">전역 스타일 설정하기</h4>
<hr>
<p>스타일을 컴포넌트로 만들 수 있다는 것은 좋지만, 전역에 스타일을 설정하고 싶을 땐 어떻게 하면 좋을까?</p>
<p>우선 전역 스타일을 설정하기 위해 Style Components에서 <code>createGlobalStyle</code> 함수를 불러온다.</p>
<pre><code class="language-js">import { createGlobalStyle } from &quot;styled-components&quot;;</code></pre>
<p>그 다음 이 함수를 사용해 CSS 파일에서 작성하듯 설정해주고 싶은 스타일을 작성한다.</p>
<pre><code class="language-js">const GlobalStyle = createGlobalStyle`
    button{
        padding : 2rem;
        margin : 1.5rem;
        border-radius : 30px;
    }
`</code></pre>
<p>이렇게 만들어진 <code>&lt;GlobalStyle&gt;</code> 컴포넌트를 최상위 컴포넌트에서 사용해주면 전역에 <code>&lt;GlobalStyle&gt;</code> 컴포넌트의 스타일이 적용된다.</p>
<pre><code class="language-js">function App(){
  return(
    &lt;&gt;
        &lt;GlobalStyle /&gt;
        &lt;input&gt;전역 스타일 적용하기&lt;/input&gt;
    &lt;/&gt;
  )
}</code></pre>
<h2 id="컴포넌트-ui-개발을-위한-storybook">컴포넌트 UI 개발을 위한 Storybook</h2>
<hr>
<p>Component Driven Development 가 트렌드로 자리 잡게 되면서 이를 지원하는 도구 중 하나인 컴포넌트 탐색기<code>Component Explorer</code>가 등장했다. Component Explorer에는 많은 UI 개발 도구가 다양하게 있는데 그 중 하나가 Storybook이다.</p>
<h3 id="what-is-storybook">what is Storybook?</h3>
<p>Component Dreven Development를 하기 위한 도구. 
각각의 컴포넌트들을 따로 볼 수 있게 구성해주어 한 번에 하나의 컴포넌트에서 작업할 수 있다. 복잡한 개발 스택을 시작하거나, 특정 데이터를 데이터 베이스로 강제 이동하거나, 애플리케이션을 탐샐할 필요 없이 전체 UI를 한눈에 보고 개발할 수 있다.</p>
<h3 id="why-used-storybook-or-ui-development-tool">why used Storybook or UI development tool?</h3>
<p>Storybook은 기본적으로 독립적인 개발 환경에서 실행된다. 개발자는 애플리케이션의 다양한 상황에 구애받지 않고 UI 컴포넌트를 집중적으로 개발 할 수 있다.</p>
<p>지원하는 기능</p>
<ul>
<li>UI 컴포넌트들을 카탈로그화하기</li>
<li>컴포넌트 변화를 Stories로 저장하기</li>
<li>핫 모듈 재 로딩과 같은 개발 툴 경험을 제공</li>
<li>리액트를 포함한 다양한 뷰 레이어 지원</li>
</ul>
<h2 id="useref">useRef</h2>
<hr>
<p>React만 가지고 거의 대부분의 프론트엔드 요구사항을 구현할 수 있었다. 
DOM 지식이 필요없다고 생각할 수도 있다.
하지만 리엑트로 모든 개발 요구사항을 충족할 수는 없다.
아래와 같이 DOM 엘리먼트의 주소값을 활용해야 하는 경우 특히 그렇다</p>
<ul>
<li>focus</li>
<li>text selection</li>
<li>media playback</li>
<li>에니메이션 적용</li>
<li>j3.js, greensock 등 DOM 기반 라이브러리 활용</li>
</ul>
<p>리엑트는 이런 예외적인 상황에서 <code>useRef</code>로 DOM Node, element, React 컴포넌트 주소값을 참조할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[UI/UX 분석 및 개선]]></title>
            <link>https://velog.io/@nada_1221/UIUX-jp57syu3</link>
            <guid>https://velog.io/@nada_1221/UIUX-jp57syu3</guid>
            <pubDate>Thu, 25 Aug 2022 02:39:11 GMT</pubDate>
            <description><![CDATA[<p>UI분석</p>
<ul>
<li>사용중인 UI 디자인 패턴<ul>
<li>모달 (자세히 보기)</li>
<li>탭 (Navbar)</li>
<li>아코디언(help 한정)</li>
</ul>
</li>
</ul>
<p>UX분석</p>
<ul>
<li>피터모빌의 UX 7요소 충족 여부</li>
</ul>
<ol>
<li><p>유용성 - 8점
해당 사이트에 해당 전문가가 사용할 시 유용성이 높을 것이라고 판단.
특정한 유저를 대상으로 사이트를 만들었다고 판단하여 유용성에 8점을 할당함</p>
</li>
<li><p>사용성 - 6.5점
구독제를 통한 이용권 제공하고 있다. 
하지만 특정한 유저를 대상으로 사이트를 만들었기 때문에 유용성에서는 높은 점수를 줄만 했지만, 사용성에 관해서는 자세한 내용의 설명이 없었기에 중간 점수를 주었다. </p>
</li>
<li><p>매력성 - 9점
사이트의 첫 인상부터 매력적으로 다가온다. 
OZZ라는 플랫폼을 모르고 들어오더라도 궁금증이 생길법한 사이트로 디자인 됐다고 본다.  </p>
</li>
<li><p>신뢰성 - 4.5점
그러나 신뢰성 면에서는 의아함이 느껴지긴 한다. 해당 사이트에 구독료를 지불하고 기능을 제공받는데 해당 기능을 어떻게 제공받을 건지에 대한 내용의 설명은 부실하고 그저 이거 저거 해준다고만 적혀있어서 신뢰성에 의심이 생겼다.</p>
</li>
<li><p>접근성 - 7점
네비게이션 바 부터 비율대비 폰트사이즈 등 여러가지로 접근성에 대한 신경을 쓴 것이 보인다. 다만 사이트 자체적으로 무엇인가 제공하는 느낌을 받기는 힘들었다.</p>
</li>
<li><p>검색 가능성 - 8점
네비게이션 바 그리고 탭 등을 이용해서 사용자들이 원하는 기능이나 정보를 찾을 수 있게 해놓은 점은 좋았다. 또한 콘텐츠를 직관적으로 배치하여 찾고자하는 내용에 스크롤을 하여 갈 수 있어 검색 가능성에 높은 점수를 줬다.</p>
</li>
<li><p>가치성 - 5점
사실 이 부분에 대해서는 해당 전문가가 판단해야할 문제이지 않을까 생각했다.
일반적으로 모든 대중들이 사용하는 사이트가 아니라는 점 그리고 특정 전문가가 아니라는 점을 생각해 중립적인 마음을 담아 5점을 줬다.</p>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/nada_1221/post/8138cffb-5359-4930-817a-d8faecfeae8a/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준]Node.js_1000번|1001번|10998번|1008번]]></title>
            <link>https://velog.io/@nada_1221/%EB%B0%B1%EC%A4%80Node.js1000%EB%B2%881001%EB%B2%8810998%EB%B2%881008%EB%B2%88</link>
            <guid>https://velog.io/@nada_1221/%EB%B0%B1%EC%A4%80Node.js1000%EB%B2%881001%EB%B2%8810998%EB%B2%881008%EB%B2%88</guid>
            <pubDate>Wed, 24 Aug 2022 14:37:02 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/nada_1221/post/8b941544-f7e3-4951-bd15-1a68f226f1fb/image.png" alt="">
<img src="https://velog.velcdn.com/images/nada_1221/post/fdc07441-d21b-42ed-89b9-afdbeca01596/image.png" alt=""></p>
<p>이제부터 백준 알고리즘의 빡침 포인트 <code>fs</code> 모듈이 나온다. 
<code>fs</code>모듈에 관해서 다루는 글은 다루지 않을 생각이니, 만약 필요하다면 <a href="https://velog.io/@wiostz98kr/%EB%B0%B1%EC%A4%80-Node.js-fs%EB%AA%A8%EB%93%88%EB%A1%9C-%EC%9E%85%EB%A0%A5%EA%B0%92-%EB%B0%9B%EA%B8%B0">여기</a> 에서 확인해보시길.</p>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;/dev/stdin&quot;)
    .toString()
    .split(&quot; &quot;)

let A = Number(input[0]);
let B = Number(input[1]);

console.log(A+B)
console.log(A-B)
console.log(A*B)
console.log(A/B)</code></pre>
<p>아직도 저놈의 <code>let input = fs.readFileSync(&quot;/dev/stdin&quot;)</code> 뒤에 붙는
<code>.toString()</code>,<code>.split(&quot; &quot;)</code> 외에 더 들어갈 애들 때문에 골머리가 아프다...</p>
<p>해당 내용에 관련된 유튜브 강의를 들어야 할 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준]Node.js_10718번]]></title>
            <link>https://velog.io/@nada_1221/%EB%B0%B1%EC%A4%80Node.js10718%EB%B2%88</link>
            <guid>https://velog.io/@nada_1221/%EB%B0%B1%EC%A4%80Node.js10718%EB%B2%88</guid>
            <pubDate>Wed, 24 Aug 2022 14:25:30 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/nada_1221/post/90d569ac-e69a-4172-a4d9-17a996d4eed1/image.png" alt=""></p>
<p><del>대한민국 육군 병장 전역자로서 대흉근이 웅장해지는 문제</del></p>
<pre><code class="language-js">console.log(`강한친구 대한육군`)
console.log(`강한친구 대한육군`)</code></pre>
<p>만능 콘솔닷로그 를 두 줄에 걸쳐서 적으면 된다.
쉽다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준]Node.js_2557번]]></title>
            <link>https://velog.io/@nada_1221/%EB%B0%B1%EC%A4%80Node.js2557%EB%B2%88</link>
            <guid>https://velog.io/@nada_1221/%EB%B0%B1%EC%A4%80Node.js2557%EB%B2%88</guid>
            <pubDate>Wed, 24 Aug 2022 14:19:51 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가기에-앞서">들어가기에 앞서</h2>
<hr>
<p>드디어 나도 백준 알고리즘에 발을 들였다.</p>
<p>코딩 배운지 2달만에 나름의 쾌거다.</p>
<p>원래는 한달차 즈음에 도전해볼 생각으로 들어갔다가 단순한 이 2557번 문제조차 풀지 못해 좌절한 적이 있다.</p>
<p>그 때는 백준 알고리즘의 문제 풀이에 대해 이해하지 못한 상태로 그저</p>
<pre><code class="language-js">return &#39;Hello World!&#39; </code></pre>
<p>를 적고 있었으니 당연히 풀 수 없었고 다른 문제들을 보고 기가 죽어 그대로 나왔다.</p>
<p>그런데 이번에 40기 디코방에서 운 좋게도 알고리즘 소모임을 갖게 되어 최소한의 지식을 겸비할 수 있게 됐다.</p>
<p>그 지식을 기반으로 차근차근 알고리즘 문제를 풀어나갈 생각이다.</p>
<hr>
<h2 id="백준-알고리즘-2557번">백준 알고리즘 2557번</h2>
<p><img src="https://velog.velcdn.com/images/nada_1221/post/1e1ea610-4cc2-492a-ac17-37fdab503a1c/image.png" alt=""></p>
<hr>
<p>백준 알고리즘의 세계로의 입성을 환영하는 문제라고 생각한다.</p>
<pre><code class="language-js">console.log(&#39;Hello World!&#39;)</code></pre>
<p>백준은 <code>return</code> 이 아니라 <code>console.log()</code> 로 답을 제출해야 했다.
(<del>뻘하게 <code>return</code>만 적던 과거의 나... 많이 발전했다. XD</del>)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[UI/UX]]></title>
            <link>https://velog.io/@nada_1221/UIUX</link>
            <guid>https://velog.io/@nada_1221/UIUX</guid>
            <pubDate>Tue, 23 Aug 2022 13:50:10 GMT</pubDate>
            <description><![CDATA[<h2 id="ui">UI</h2>
<hr>
<p>UI <code>User Interface</code> 사용자 인터페이스는 사람들이 컴퓨터와 상호 작용하는 시스템을 의미한다.</p>
<h3 id="gui">GUI</h3>
<p><code>Graphical User Interface</code> 그래픽 사용자 인터페이스는 사용자가 그래픽을 통해 컴퓨터와 정보를 교환하는 작업 환경을 말한다.
프론트엔드 개발자로서의 UI는 대부분 이 GUI를 의미한다. </p>
<h2 id="ux">UX</h2>
<hr>
<p>UX <code>User Experience</code> 사용자 경험의 사전적 의미는 사용자가 어떤 시스템, 제품, 서비스를 직/간접적으로 이용하면서 느끼고 생각하는 총체적 경험.</p>
<p>UX에 영향을 주는 많은 요소 중에 프론트엔드 개발자에게 가장 중요한 요소는 바로 UI이다. 
좋은 프론트엔드 개발자라면 제품이나 서비스의 UI가 사용자로 하여금 가능하면 좋은 UX를 가질 수 있도록, 최소한 나쁜 경험은 하지 않도록 해야 한다.</p>
<h2 id="ui와-ux의-관계">UI와 UX의 관계</h2>
<hr>
<p>UX는 UI를 포함한다. 또한 좋은 UX가 좋은 UI를 의미하거나, 좋은 UI가 항상 좋은 UX를 보장하지는 않는다.</p>
<p>나쁜 UI는 보통 나쁜 UX를 유발한다.</p>
<p>UI와 UX는 서로 다르지만 떼려야 뗄 수 없는 관계이며, 서로를 보완하는 역할을 한다. UX가 좋지 않은 곳을 찾아냄으로서 UI 개선점을 찾아낼 수 있고, UI를 개선함으로서 UX가 좋아지기도 한다. 이렇게 UX와 UI는 서로를 계속해서 발전시킬 수 있다.</p>
<h2 id="ui-디자인-개요">UI 디자인 개요</h2>
<hr>
<p>UI 디자인 패턴은 프로그래밍 시 자주 반복되어 나타나는 문제점을 해결하고자, 과거의 다른 사람이 해결한 결과물을 재사용하기 좋은 형태로 만든 패턴을 말한다.</p>
<p>자주 쓰이는 UI 디자인 패턴을 익혀두면 UI를 디자인하기 보다 쉬워지고, 프론트엔드 개발자, 디자이너, PM과의 의사소통도 원할해져 협업 효율도 높아진다. </p>
<h3 id="모달-modal">모달 Modal</h3>
<hr>
<p><img src="https://i0.wp.com/codemyui.com/wp-content/uploads/2018/09/Button-into-Modal-Form-Animation-1.gif?w=880&ssl=1" alt="">
모달은 기존에 이용하던 화면 위에 오버레이 되는 창을 뜻한다. 
닫기 버튼, 혹은 모달 범위 밖을 클릭하면 모달이 닫히는 것이 일반적이며, 모달을 닫기 전에는 기존 화면과 상호작용 할 수 없다.</p>
<p>팝업은 브라우저에 의해 강제로 막힐 수 있지만, 모달은 브라우저 설정에 영향을 받지 않는다.</p>
<h3 id="토글-toggle">토글 Toggle</h3>
<hr>
<p><img src="https://i.pinimg.com/originals/f8/b6/5a/f8b65a79475ddaac8e9f4dcf2efa030f.gif" alt=""></p>
<p>토글은 On/Off를 설정할 때 사용하는 스위치 버튼. 
색상, 스위치의 위치, 그림자 등의 시각적 효과를 주어 사용자가 토글의 상태를 직관적으로 알 수 있게 만들어야 한다.</p>
<h3 id="탭-tab">탭 Tab</h3>
<hr>
<p><img src="https://miro.medium.com/max/1400/1*0nOpxIXG4asiLd5ixBxEQA.gif" alt="">
탭은 콘텐츠를 분리해서 보여주고 싶을 때 사용하는 UI 디자인 패턴. </p>
<p>탭을 사용하려면 각 섹션의 이름이 너무 길지 않아야 하고, 섹션의 구분이 명확해야 하며, 현재 어떤 섹션을 보고 있는지 표시해줘야 한다.</p>
<h3 id="태그-tag">태그 Tag</h3>
<hr>
<p><img src="https://aws1.discourse-cdn.com/business7/uploads/streamlit/original/2X/0/08995330ceee1a2514beed81641b63d464b56c24.png" alt="">
태그는 콘텐츠를 설명하는 키워드를 사용해서 라벨을 붙이는 역할을 한다. </p>
<p>태그로 사용될 키워드는 사용자가 직접 작성하게 만들 수도 있고, 개발자가 종류를 아예 정해놓을 수도 있다. 어떤 방식을 선택하든 태그의 추가와 제거는 자유롭게 할 수 있어야 한다.</p>
<h3 id="자동완성-autocomplete">자동완성 Autocomplete</h3>
<hr>
<p><img src="https://coralogix.com/wp-content/uploads/2020/06/auto1.gif" alt="">
자동완성은 사용자가 정보를 직접 입력하는 시간을 줄여주고, 정보를 검색할 때 많이 사용한다.</p>
<p>자동 완성 항복은 너무 많은 항목이 나오지 않도록 개수를 제한하는 것이 좋으며, 키보드 방향 키나 클릭 등으로 접근하여 사용할 수 있는 것이 좋다.</p>
<h3 id="드롭다운-dropdown">드롭다운 Dropdown</h3>
<hr>
<p><img src="https://cdn.dribbble.com/users/410036/screenshots/3545208/dropdownabout.gif" alt="">
드롭다운이 펼쳐지는 방식보다 중요한 것은 사용자가 자신이 선택한 항목을 정확하게 알 수 있게 만드는 것이다.</p>
<h3 id="아코디언-accordion">아코디언 Accordion</h3>
<hr>
<p><img src="https://i.pinimg.com/originals/62/f1/da/62f1da32967de421a054c9fe5b98b0cf.gif" alt="">
같은 분류의 아코디언을 여러 개 연속해서 배치한다.
트리 구조의 콘텐츠를 렌더링할 때 사용하거나. 메뉴바로 사용할 수도 있다.</p>
<p>기본적으로는 화면을 깔끔하게 구성하기 위해서 사용하며, 트리 구조나 메뉴바로 사용할 경우에는 상하 관계를 표현하기 위해서 사용하는 경우가 많고, 콘텐츠를 담는 용도로 사용할 때는 핵심 내용을 먼저 전달하려는 목적을 가질 때가 많다.</p>
<h3 id="캐러셀-carousel">캐러셀 Carousel</h3>
<hr>
<p><img src="https://i.pinimg.com/originals/f9/37/00/f937006d6b93105ac124e47171335c51.gif" alt="">
캐러셀은 자동으로 돌아가거나, 사용자가 옆으로 넘겨야만 넘어가거나, 아니면 둘 중 선택할 수 있도록 만들 수 있다.</p>
<p>캐러셀을 사용자가 넘겨야만 넘어가도록 만드는 경우, 콘텐츠가 넘어갈 수 있음을 직관적으로 알 수 있어야 한다. 따라서 다음 콘텐츠의 일부를 옆에 배치하거나, 콘텐츠를 넘길 수 있는 버튼을 배치하기도 한다.</p>
<h3 id="페이지네이션-pagination">페이지네이션 Pagination</h3>
<hr>
<p><img src="https://i.pinimg.com/originals/c0/d4/cd/c0d4cd329a94ffb5c401b135f3374dbd.gif" alt="">
페이지네이션은 한 페이지에 띄우기에 정보가 너무 많은 경우, 책 페이지를 넘기듯이 번호를 붙여 페이지를 구분해주는 것을 말한다. </p>
<p>사용자가 원하는 페이지로 바로바로 접근할 수 있다는 장점이 있지만, 페이지를 넘기기 위해서는 잠시 멈춰야 하기 때문에 매끄러운 사용자 경험과는 거리가 멀 수 있다는 단점도 있다.</p>
<h3 id="무한-스크롤-infinite-scroll--continuous-scroll">무한 스크롤 Infinite Scroll / Continuous Scroll</h3>
<hr>
<p><img src="https://cdn.dribbble.com/users/1277312/screenshots/7527535/media/f1cfe93f2aff7d75ddf10d0dfba80268.gif" alt="">
페이지네이션과 마찬가지로 한 번에 띄우기엔 정보가 너무 많을 때 사용하는 UI 디자인 패턴.</p>
<p>페이지네이션과 같이 잠시 멈춰서 페이지를 선택할 필요가 없기 때문에 보다 더 매끄러운 사용자 경험을 제공한다. 하지만 콘텐츠의 끝이 어딘지 알 수 없다는 점, 지나친 콘텐츠를 찾기 힘들다는 점 등의 단점도 있다. </p>
<p>보통 페이지의 맨 아래에 도달하면 추가 콘텐츠를 로드해오는 방식으로 만든다. 처음부터 모든 콘텐츠를 로드해온 후 조금씩 보여주는 방식으로 구현하는 것은 진정한 의미의 무한스크롤이라고 할 수 없으므로 주의하자.</p>
<h3 id="gnb-global-navigation-bar-lnb-local-navigation-bar">GNB (Global Navigation Bar), LNB (Local Navigation Bar)</h3>
<hr>
<p><img src="https://images.surferseo.art/99f0d937-0d6a-4bc8-8477-63ab3326f2e7.jpeg" alt="">
GNB는 어느 페이지에 들어가든 사용할 수 있는 최사우이 메뉴, LNB는 GNB에 종속되는 서브 메뉴 혹은 특정 페이지에서만 볼 수 있는 메뉴를 뜻한다.</p>
<p>GNB는 어느 페이지에 있든 사용할 수 있도록 항상 동일한 위치에 있어야 한다. </p>
<p><a href="https://ui-patterns.com/patterns">참고사이트</a></p>
<h2 id="ui-layout">UI Layout</h2>
<h3 id="그리드-시스템-grid-system">그리드 시스템 Grid System</h3>
<hr>
<p>grid는 수직, 수평으로 분할된 격자 무늬를 뜻하며, 말 그대로 화면을 격자로 나눈 다음 그 격자에 맞춰 콘텐츠를 배치하는 방법이다.</p>
<p>웹 디자인 분야에서는 화면을 세로로 몇 개의 영역으로 나눌 것인가에 초점을 맞춘 컬럼 그리드 시스템(Column Grid System)을 사용하며, Margin, Column,Gutter라는 세 가지 요소로 구성 된다.</p>
<p><img src="https://s3.ap-northeast-2.amazonaws.com/urclass-images/An8ohaLMsaxRQp-NCGPZY-1655905645893.gif" alt=""></p>
<h3 id="1margin">1.Margin</h3>
<p>Margin은 화면 양쪽의 여백을 의미 한다. 너비를 <code>px</code>같은 절대 단위를 사용해서 고정 값으로 사용해도 되고, <code>vw</code>,<code>%</code>같은 상대 단위를 사용하여 유동성을 주어도 좋다.</p>
<h3 id="2-column">2. Column</h3>
<p>column은 콘텐츠가 위치하게 될, 세로로 나누어진 영역. 컬럼 개수를 임의로 나눌 수도 있겠지만, 표준적으로 휴대폰에서 4개, 태브릿에서 8개, PC에서는 12개의 컬럼으로 나눈다.</p>
<p>Column은 상대 단위를 사용하여 콘텐츠가 창 크기에 맞춰서 크기가 변하도록 설정하는 것이 좋다. 기기마다 화면의 크기가 조금씩 다르고, 브라우저의 크기를 사용자가 마음대로 바꿀 수도 있기 때문이다.</p>
<h3 id="3gutter">3.Gutter</h3>
<p>Gutter는 Column 사이의 공간으로, 콘텐츠를 구분하는데 도움을 준다. Gutter의 간격이 좁을 수록 콘텐츠들이 연관성이 있어 보이고, 넓을수록 각 콘텐츠가 독립적인 느낌을 준다.</p>
<p>다만 너무 좁거나. 너무 넓게 설정하지 않도록 주의해야 한다. 너무 좁으면 콘텐츠를 구분하기 힘들어지고 답답한 느낌을 준다. 그렇다고 너무 넓으면 콘텐츠가 따로 노는 느낌을 주면서 UI가 어수선해지기 때문이다. </p>
<p>그러므로 Gutter는 아무리 넓어도 컬럼 너비보다는 작게 설정하자.</p>
<h3 id="컬럼-그리드-시스템-예시">컬럼 그리드 시스템 예시</h3>
<hr>
<h3 id="네이버">네이버</h3>
<p><img src="https://s3.ap-northeast-2.amazonaws.com/urclass-images/jLI_jlit6JTiNXtLERs9i-1655905696805.gif" alt="">
네이버의 메인 페이지이다. 화면이 12개의 컬럼으로 나누어져 있고, 컬럼에 맞춰서 콘텐츠가 배열되어 있다.</p>
<p>컬럼 그리드 시스템을 활용할 때 화면 가로 길이에 따라서 컬럼 개수가 달라지도록 코드를 작성하면, 다양한 디바이스와 다양한 환경에 유연하게 대응하는 UI를 만들 수 있으며, 이를 반응형 웹이라고 부른다. </p>
<h2 id="ux-design">UX Design</h2>
<hr>
<h3 id="좋은-ux를-만드는-요소">좋은 UX를 만드는 요소</h3>
<p><img src="https://popupsmart.com/encyclopedia/images/u/s/e/r/-/user-experience-honeycomb-0201bdf6.png" alt="">
좋은 UX를 만들려면 무엇을 고려해야 할까? 
피터 모빌의 벌집 모형은 이 질문에 대한 답을 준다.</p>
<h3 id="1-유용성-useful--사용-가능한가">1. 유용성 Useful : 사용 가능한가?</h3>
<hr>
<p>유용성은 제품이나 서비스가 목적에 맞는, 사용 가능한 기능을 제공하고 있는가에 관한 요소이다.
그리고 꼭 목적에 맞지 않더라도, 비실용적이라도 추가적인 기능을 제공하는지도 관련이 있다. </p>
<h3 id="2-사용성-usable--사용하기-쉬운가">2. 사용성 Usable : 사용하기 쉬운가?</h3>
<hr>
<p>사용성은 제품이 본연의 기능을 제공하는 것을 넘어서 사용하기 쉬운가에 관한 요소이다. 기능이 아무리 잘 작동하더라도 사용자가 사용하기 어렵다면 좋은 UX를 제공하기 어렵다.
가능한 단순하면서 직관적이고 사용하기 쉬운 제품이나 서비스를 만들어야 한다. 이 요소는 UI 디자인 패턴과도 연관이 깊다. 자주 쓰이는 패턴들은 사용자들에게도 친숙할 가능성이 높아 사용성을 높여준다.</p>
<h3 id="3-매력성-desirable--매력적인가">3. 매력성 Desirable : 매력적인가?</h3>
<hr>
<p>매력성은 말 그대로 제품이 사용자들에게 매력적인가에 대한 요소이다. 단순히 디자인이 보기에 좋은지부터 시작해서, 이미지, 브랜딩 등의 여러 요소들이 사용자에게 긍정적인 감정을 불러일으킬 수 있는지, 사용자들이 해당 제품이나 서비스를 이용하고 싶어하는지가 중요하다.</p>
<h3 id="4-신뢰성-credible--신뢰할-수-있는가">4. 신뢰성 Credible : 신뢰할 수 있는가?</h3>
<hr>
<p>신뢰성은 사용자가 제품이나 서비스를 믿고 사용할 수 있는가에 관한 요소이다. 사용자의 신뢰성을 떨어뜨리는 일이 없어야 하며 장기적으로는 믿을 수 있는 브랜드 이미지를 구축하는 것이 좋다.</p>
<h3 id="5-접근성-accessible--접근하기-쉬운가">5. 접근성 Accessible : 접근하기 쉬운가?</h3>
<hr>
<p>접근성은 나이, 성별, 장애 여부를 떠나서 누구든지 제품이나 서비스에 접근할 수 있는가에 관한 요소이다. </p>
<h3 id="6-검색-가능성-findable--찾기-쉬운가">6. 검색 가능성 Findable : 찾기 쉬운가?</h3>
<hr>
<p>검색 가능성은 사용자가 원하는 기능이나 정보를 쉽게 찾을 수 있는가에 관한 요소이다. 웹 사이트의 경우 사용자가 특정 페이지에 접근하려고 할 때 찾기 힘들다면 좋은 UX를 주기 어렵다. </p>
<h3 id="7-가치성-valualbe--가치를-제공하는가">7. 가치성 Valualbe : 가치를 제공하는가?</h3>
<hr>
<p>가치성은 위에서 언급된 모든 요소들을 총합하여 고객에게 가치를 제공하고 있는가에 관한 요소이다. 사용자 마다 가치판단기준과 그 정도는 다 다르다. 특정 제품이 접근성에 모든 노력을 기울였다고 해도, 사용자가 접근성을 전혀 중요하게 생가하지 않는다면 가치를 제공하지 못할 수도 있다. 따라서 가능한 모든 요소를 고르게 고려하는 것이 좋고, 제품 사용자들이 공통적으로 중요하게 생각하는 요소를 찾아냈다면 그 요소에 집중하는 것도 UX를 효율적으로 개선하는 전략이 될 수 있다.</p>
<h2 id="user-flow">User Flow</h2>
<hr>
<p>사용자 흐름<code>user flow</code>은 사용자가 제품에 진입한 시점을 시작으로 취할 수 있는 모든 행동을 뜻하며,
<img src="https://miro.medium.com/max/1200/1*pce79LRCOOWTJYHbn9rd4w.png" alt="">
이미지 처럼 다이어그램을 그려서 정리한다.</p>
<h3 id="user-flow-다이어그램-작성법">User Flow 다이어그램 작성법</h3>
<hr>
<p>사용자 흐름을 다이어그램으로 작성할 때, 기본적으로 세가지 요소를 사용한다.</p>
<ol>
<li>직사각형 : 사용자가 보게 될 화면</li>
<li>다이아몬드 : 사용자가 취하게 될 행동</li>
<li>화살표 : 직사각형과 다이아몬드를 연결시켜주는 화살표</li>
</ol>
<p>이 외의 요소를 필요에 따라 추가하여도 좋지만, 이 세가지 요소는 거의 필수적으로 사용하게 된다. </p>
<h3 id="user-flow-다이어그램을-그리면-좋은-이유">User Flow 다이어그램을 그리면 좋은 이유</h3>
<hr>
<p>사용자 흐름 다이어 그램을 그려보면 다음과 같은 장점이 있다.</p>
<ol>
<li>사용자 흐름 상 어색하거나 매끄럽지 않은 부분을 발견하여 수정할 수 있다.</li>
<li>있으면 좋은 기능을 발견하여 추가하거나 없어도 상관 없는 기능을 발견하고 삭제할 수 있다.</li>
</ol>
<p>필수로 그려야 하는 것은 아니지만, 좋은 UX를 디자인하고 싶다면 기획 단계에서 한번 쯤은 그려보는 것이 좋다.</p>
<h3 id="user-flow-다이어그램-도구">User Flow 다이어그램 도구</h3>
<hr>
<ul>
<li><a href="https://miro.com/">Miro</a></li>
<li><a href="https://www.figma.com/figjam/">FigJam</a></li>
</ul>
<h2 id="uiux-사용성-평가">UI/UX 사용성 평가</h2>
<hr>
<h3 id="제이콥-닐슨의-10가지-사용성-평가-기준">제이콥 닐슨의 10가지 사용성 평가 기준</h3>
<p><code>Jakob&#39;s Ten Usability Heuristics</code></p>
<hr>
<ul>
<li>Heuristic이란? 
&#39;체험적인&#39;이라는 뜻으로, 완벽한 지식 대신 직관과 경험을 활용하는 방법론을 말한다.</li>
</ul>
<ol>
<li>시스템 상태의 가시설 <code>Visibility of system status</code></li>
</ol>
<ul>
<li>합리적인 시간 내에 적절한 피드백을 통해 사용자에게 진행 상황에 대한 정보를 항상 제공해야 한다.<ul>
<li>피드백이 존재하는가?</li>
<li>피드백이 즉시 제공되는가?</li>
<li>피드백이 명확한가?<ol start="2">
<li>시스템과 현실 세계의 일치 <code>Match between system and the real world</code></li>
</ol>
<ul>
<li>내부 전문용어가 아닌 사용자에게 친숙한 단어, 구문 및 개념을 사용한다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<ol start="3">
<li>사용자 제어 및 자유 <code>User control and freedom</code></li>
</ol>
<ul>
<li>사용자는 종종 실수를 한다. 현재 진행 중인 작업에서 벗어날 수 있는 방법, 혹은 실수로 수행한 작업을 취소할 수 있는 방법을 명확하게 제공해야 한다.</li>
</ul>
<ol start="4">
<li>일관성 및 표준 <code>Consistency and standards</code></li>
</ol>
<ul>
<li>외부 일관성 : 일관적인 사용자 경험을 제공하기 위해서 플랫폼 및 업계의 관습을 따라라.<ul>
<li>사용자에게 익숙한 UI를 제공해라. 잘 알려진 UI 디자인 패턴을 사용하는 것이 좋다.</li>
</ul>
</li>
<li>내부 일관성 : 사용자가 혼란스럽지 않도록 제품의 인터페이스나 정보 제공에 일관성이 있어야 한다.<ul>
<li>ex) 한 제품 내에서 같은 인터페이스를 유지한다(버튼의 모양, 위치, 아이콘의 크기 등)</li>
</ul>
</li>
</ul>
<ol start="5">
<li>오류 방지 <code>Error prevention</code></li>
</ol>
<ul>
<li>오류가 발생하기 쉬운 상황을 제거하여 사용자의 실수를 방지해야 한다.<ul>
<li>예시) 삭제 버튼을 눌렀을 때, 정말로 삭제할 것인지를 이용자의 의사를 확인하기 위해 다시 물어본다.</li>
</ul>
</li>
</ul>
<ol start="6">
<li>기억보다는 직관 <code>Recognition rather than recall</code></li>
</ol>
<ul>
<li>사용자가 기억해야 하는 정보를 줄인다.<ul>
<li>예시) 최근 검색했던 단어 목록을 확인할 수 있다.</li>
</ul>
</li>
</ul>
<ol start="7">
<li>사용의 유연성과 효율성 <code>Flexibility and efficiency of use</code></li>
</ol>
<ul>
<li>초보자와 전문가 모두에게 개별 맞춤 기능을 제공하도록 한다.<ul>
<li>예시) 프로그램의 단축키를 직접 설정하여 사용할 수 있다.
8, 미학적이고 미니멀한 디자인 <code>Aesthetic and minimalist design</code></li>
</ul>
</li>
<li>인터페이스에는 관련이 없거나 불필요한 정보가 포함되지 않도록 한다. 콘텐츠와 기능의 우선순위를 정하고 우선 순위가 높은 것을 잘 제공하고 있는지 확인하자.<ul>
<li>예시) 사용 빈도가 적은 메뉴를 다 보여줄 필요는 없다. 필요할 때에만 볼 수 있게 숨겨놓는 것도 좋은 방법이다.</li>
</ul>
</li>
</ul>
<ol start="9">
<li>오류의 인식, 진단, 복구를 지원 <code>Help users recognize</code>,<code>diagnose</code>, and <code>recover from errors</code></li>
</ol>
<ul>
<li>사용자가 이해할 수 있는 언어를 사용하여 문제가 무엇인지 정확하게 표시하고, 해결 방법을 제안해야 한다.<ul>
<li>예시) 영문 성<code>Family Name</code>을 입력해야 하는 폼에서는 한글이 아닌 영어를 입력해야 함을 정확하게 알려준다.</li>
</ul>
</li>
</ul>
<ol start="10">
<li>도움말 및 설명 문서 <code>Help and documentation</code></li>
</ol>
<ul>
<li>추가 설명이 필요 없는 것이 가장 좋지만, 상황에 따라 이해하는 데 도움이 되는 문서를 제공해야 한다. <ul>
<li>예시) 간단한 안내를 통해 검색에 도움을 준다.</li>
</ul>
</li>
</ul>
<h3 id="사용성-평가-기준-활용하기">사용성 평가 기준 활용하기</h3>
<hr>
<p>사용성 평가 기준은 제품 설계 단계에서 더 완성도 있는 애플리케이션을 기획하기 위해서 사용할 수 있다. 지속적으로 확인해주면 사용성과 효율성을 크게 높일 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JSON.stringify]]></title>
            <link>https://velog.io/@nada_1221/JSON.stringify</link>
            <guid>https://velog.io/@nada_1221/JSON.stringify</guid>
            <pubDate>Mon, 22 Aug 2022 14:36:14 GMT</pubDate>
            <description><![CDATA[<h2 id="json의-탄생배경">JSON의 탄생배경</h2>
<hr>
<p>JSON은 JavaScript Object Notation의 줄임말로, 데이터 교환을 위해 만들어진 객체 형태의 포맷이다. 
네트워크를 통해, 어떤 객체 내용을 다른 프로그램에게 전송한다고 가정하자. 이 객체의 내용을 일종의 메신저 혹은 채팅 프로그램에서 쓰는 하나의 메시지라고 한다면, 다음 객체를 어떻게 전송할 수 있을까?</p>
<pre><code class="language-js">const message = {
  sender: &quot;nada&quot;,
  receiver: &quot;neoda&quot;,
  message: &quot;I will be back&quot;,
  createdAt: &quot;2022-08-22 10:11:12&quot;
}</code></pre>
<p>메시지 객체가 전송 가능하려면, 메시지를 보내는 발신자와 메시지를 받는 수신자가 같은 프로그램을 사용하거나, 무자열 처럼 범용적으로 읽을 수 있는 형태여야 한다.</p>
<blockquote>
<p>전송 가능한 조건(transferable condition)</p>
</blockquote>
<ul>
<li>수신자와 발신자가 같은 프로그램을 사용한다.</li>
<li>또는, 문자열처럼 범용적으로 읽을 수 있어야 한다.</li>
</ul>
<p>객체는 타입 변환을 이용해 String 으로 변환할 경우 객체 내용을 포함하지 않는다. JS에서 객체를 문자열로 변환하기 위해서 메서드 <code>message.toString()</code>이나 형변환<code>String(message)</code>을 시도하면, <code>[object object]</code>라는 결과를 리턴한다.</p>
<p>이 문제를 해결하는 방법은 객체를 JSON의 형태로 변환하거나 JSON을 객체의 형태로 변환하는 방법이다. 
이를 위한 메서드는 다음과 같다</p>
<ul>
<li><code>JSON.stringify</code>: 객체를 JSON으로 변환</li>
<li><code>JSON.parse</code>:JSON을 객체로 변환한다.</li>
</ul>
<pre><code class="language-js">let transferableMessage = JSON.stringify(message)

console.log(transferableMessage)
//{&quot;sender&quot;:&quot;nada&quot;,&quot;receiver&quot;:&quot;neoda&quot;,&quot;message&quot;:&quot;I will be back&quot;,&quot;createdAt&quot;:&quot;2022-08-22 10:11:12&quot;}
console.log(typeof(transferableMessage))
//string</code></pre>
<blockquote>
<p>stringify하는 이 과정을 직렬화<code>serialize</code>한다고 한다.</p>
</blockquote>
<p>JSON으로 변환된 객체의 타입은 문자열이다. 발신자는 객체를 직렬화한 문자열을 누군가에게 객체의 내용을 보낼 수 있다. 그렇다면 수신자는 이 문자열 메시지를 어떻게 다시 객체의 형태로 만들 수 있을까? <code>JSON.stringify</code>와 정반대의 작업을 수행하는 메서드 <code>JSON.parse</code>를 사용할 수 있다.</p>
<pre><code class="language-js">let packet = {&quot;sender&quot;:&quot;nada&quot;,&quot;receiver&quot;:&quot;neoda&quot;,&quot;message&quot;:&quot;I will be back&quot;,&quot;createdAt&quot;:&quot;2022-08-22 10:11:12&quot;}
let obj = JSON.parse(packet)

console.log(obj)
//{
//  sender: &quot;nada&quot;,
//  receiver: &quot;neoda&quot;,
//  message: &quot;I will be back&quot;,
//  createdAt: &quot;2022-08-22 10:11:12&quot;
//}
console.log(typeof(obj))
// &#39;object&#39;</code></pre>
<blockquote>
<p>JSON.parse를 적용하는 이 과정을 역직렬화(deserialize)한다고 한다.</p>
</blockquote>
<h2 id="json의-기본-규칙">JSON의 기본 규칙</h2>
<hr>
<p>JSON은 얼핏 보기에 자바스크립트의 객체와 별반 다를 바가 없어 보이지만, 자바스크립트의 객체와는 미묘하게 다른 규칙이 있다.</p>
<table>
<thead>
<tr>
<th align="center"></th>
<th align="center">자바스크립트 객체</th>
<th align="center">JSON</th>
</tr>
</thead>
<tbody><tr>
<td align="center">키</td>
<td align="center">키는 따옴표 없이 쓸 수 있음 <code>{key:&quot;property}</code></td>
<td align="center">반드시 쌍따옴표를 붙여야 함 <code>{&quot;key&quot;:&quot;property&quot;}</code></td>
</tr>
<tr>
<td align="center">문자열 값</td>
<td align="center">작은따옴표도 사용 가능 <code>{&quot;key&quot;:&#39;property&#39;}</code></td>
<td align="center">반드시 큰따옴표로 감싸야 함 <code>&#39;{&quot;key&quot;:&quot;property&quot;}&#39;</code></td>
</tr>
<tr>
<td align="center">키와 값 사이 공백</td>
<td align="center">사용 가능 <code>{&quot;key&quot;:&#39;property&#39;}</code></td>
<td align="center">사용 불가능 <code>&#39;{&quot;key&quot;:&quot;property&quot;}&#39;</code></td>
</tr>
<tr>
<td align="center">키-값 쌍 사이 공백</td>
<td align="center">사용 가능 <code>{&quot;key&quot;:&#39;proterty&#39;,num:1}</code></td>
<td align="center">사용 불가능 <code>&#39;{&quot;key&quot;:&quot;property&quot;,&quot;num&quot;:1}&#39;</code></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자료구조/알고리즘] 재귀]]></title>
            <link>https://velog.io/@nada_1221/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9E%AC%EA%B7%80</link>
            <guid>https://velog.io/@nada_1221/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9E%AC%EA%B7%80</guid>
            <pubDate>Fri, 19 Aug 2022 02:15:20 GMT</pubDate>
            <description><![CDATA[<h2 id="재귀의-개념">재귀의 개념</h2>
<hr>
<p>재귀란 무엇일까? 표준국어대사전에서는 다음과 같이 정의하고 있다.</p>
<blockquote>
<p>재귀再歸 : 원래의 자리로 되돌아가거나 되돌아 옴.</p>
</blockquote>
<p>재귀의 시각적 예시를 든다면 계속해서 원래의 상태로 돌아오는 아래 이미지와 같을 것이다.
<img src="https://velog.velcdn.com/images/nada_1221/post/9f3c35a9-2b23-4fe6-bfbc-473ef3c6cd5a/image.gif" alt=""></p>
<p>재귀 함수란, 자기 자신을 호출하는 함수를 재귀 함수라고 한다. 
재귀 함수를 잘 활용하면 반복적인 작업을 해야하는 문제를 좀 더 간결한 코드로 풀어낼 수 있다.</p>
<h2 id="재귀로-문제-해결하기">재귀로 문제 해결하기</h2>
<hr>
<p>Q. 자연수로 이루어진 리스트<code>배열</code>을 입력받고, 리스트의 합을 리턴하는 함수 <code>arrSum</code> 을 작성해보자.</p>
<p>이론적으로 재귀로 문제를 해결하는 단계는 다음과 같다.</p>
<blockquote>
<ol>
<li>문제를 좀 더 작게 쪼갠다.</li>
<li>1번과 같은 방식으로, 문제가 더는 작아지지 않을 때까지, 가장 작은 단위로 문제를 쪼갠다.</li>
<li>가장 작은 단위의 문제를 풂으로써 전체 문제를 해결한다.</li>
</ol>
</blockquote>
<p>이 단계를 적용해서 <code>arrSum</code> 함수를 작성해보자.
배열은 [11,12,13,14,15] 로 하자.</p>
<h3 id="1-문제-작게-쪼개기">1. 문제 작게 쪼개기</h3>
<p>어떻게 하면 과정을 작게 쪼갤 수 있을까?
단순하게 생각해보면, 모든 배열의 합을 구하는 것 보다 가장 적은 수의 배열 값의 합을 구하는 것이 작은 문제일 것이다.</p>
<p>위 방식을 코드로 표현하자면</p>
<pre><code class="language-js">arrSum([11,12,13,14,15]) === 11 + arrSum([12,13,14,15])
// ...
arrSum([13,14,15]) === 13 + arrSum([14, 15])</code></pre>
<h3 id="2-문제를-가장-작은-단위로-쪼개기">2. 문제를 가장 작은 단위로 쪼개기</h3>
<p>위에서 쪼갠 방식을 반복해서 하다보면 더이상 쪼갤 수 없는 상태에 도달하게 된다.</p>
<pre><code class="language-js">arrSum([15]) === 15+ arrSum([])</code></pre>
<p>빈 배열을 받게 되면서 더이상 쪼갤 수 없게 되었다.
비로써 문제를 가장 작은 단위까지 쪼갰다고 할 수 있겠다.</p>
<h3 id="3-문제-해결하기">3. 문제 해결하기</h3>
<p>문제가 더 쪼개지지 않는다면 가장 작은 단위의 문제를 해결하자.</p>
<pre><code class="language-js">arrSum([]) === 0
arrSum([15]) === 15 + arrSum([]) === 15+0 === 15;
//...
arrSum([11,12,13,14,15]) === 11 + arrSum([12,13,14,15]) === 11 + 54 === 65</code></pre>
<p>위 단계를 반영해서 <code>arrSum</code>함수를 완성해보면 다음과 같다.</p>
<pre><code class="language-js">function arrSum(arr){
  //빈 배열을 받았을 때 0을 리턴하는 조건문
  //--&gt; 가장 작은 문제를 해결하는 코드 &amp; 재귀를 멈추는 코드
  if(arr.length === 0){
    return 0
  }

  // 배열의 첫 요소 + 나머지 요소가 담긴 배열을 받는 arrSum 함수 
  // --&gt; 재귀(자신을 호출)를 통해 문제를 작개 쪼개나가는 코드
  return arr.shift() + arrSum(arr)
}</code></pre>
<p>arrSum 함수는 계속 쪼개지다가 결국 쪼갤 수 없는 <code>arrSum([])</code> 까지 함수가 호출된다.
<code>arrSum([])</code>은 조건문에 의해 더이상 자기자신을 호출하지 않고, 숫자 0을 리턴하면서 종료된다. 
그 결과 중첩되어있던 함수들도 연쇄적으로 숫자를 리턴하고, 최종적으로는 배열의 모든 요소의 합을 리턴하면서 문제가 해결된다.</p>
<h2 id="재귀는-언제-사용하는-게-좋은가">재귀는 언제 사용하는 게 좋은가?</h2>
<hr>
<p>재귀는 다음과 같은 상황에서 매우 적합하다</p>
<blockquote>
<ol>
<li>주어진 문제를 비슷한 구조의 더 작은 구조의 더작은 문제로 나눌 수 있는 경우</li>
<li>중첩된 반복문이 많거나 반복문의 중첩 횟수(number of loops)를 예측하기 어려운 경우</li>
</ol>
</blockquote>
<pre><code class="language-js">for (let i = 0; i &lt; n; i++) {
    for (let j = 0; j &lt; n; j++) {
        for (let k = 0; k &lt; n; k++) {
            for (let l = 0; l &lt; n; l++) {
                for (let m = 0; m &lt; n; m++) {
                    for (let n = 0; n &lt; n; n++) {
                        for (let o = 0; o &lt; n; o++) {
                            for (let p = 0; p &lt; n; p++) {
                                // do something
                                someFunc(i, j, k, l, m, n, o, p);
                           }
                        }
                    }
                }
            }
        }
    }
 }</code></pre>
<p>모든 재귀 함수는 반복문으로 표현할 수 있다. 
그러나 재귀를 적용할 수 있는 대부분의 경우에는, 재귀를 적용하는 코드가 더욱 간결하고 이해하기 쉽다.</p>
<hr>
<h2 id="재귀의-활용">재귀의 활용</h2>
<h3 id="재귀적으로-사고하기">재귀적으로 사고하기.</h3>
<hr>
<h3 id="1-재귀-함수의-입력값과-출력값-정의하기">1. 재귀 함수의 입력값과 출력값 정의하기.</h3>
<p>재귀적으로 사고하는 데 가장 먼저 해야 할 일은 문제를 가장 추상적으로 또는, 가장 단순하게 정의하는 것이다. 
이 것은 그 출발점이며, 도달하고자 하는 목표를 정의하는 데 도움이 된다.</p>
<p>함수 <code>arrSum</code>의 경우 <code>number</code>타입을 요소로 갖는 배열을 입력받고, <code>number</code>타입을 리턴한다. 이를 더 간단하게 표기하면 다음과 같다</p>
<ul>
<li><p><code>arrSum: [number] =&gt; numer</code> &lt;- 입출력값 정의</p>
<h3 id="2-문제를-쪼개고-경우의-수를-나누기">2. 문제를 쪼개고 경우의 수를 나누기</h3>
<p>다음으로는 주어진 문제를 어떻게 쪼갤 것인지 고민하자.
문제를 쪼갤 기준을 정하고, 정한 기준에 따라 문제를 더 큰 경우와 작은 경우로 구분할 수 있는지 확인하자.
일반적으로, 입력값을 이 기준으로 정한다.
이때 중요한 관점은 <strong>입력값이나 문제의 순서와 크기</strong>이다.
주어진 입력값 또는 문제 상황을 크기로 구분할 수 있거나, 순서를 명확하게 정할 수 있다면 문제를 구분하는데 도움이 된다. </p>
<p>문제에서 주어진 입력값에 따라, 경우의 수를 나눈다. 일반적으로 문제를 더 이상 쪼갤 수 없는 경우와 그렇지 않은 경우로 나눈다.</p>
</li>
<li><p>함수 <code>arrSum</code>은 입력값이 빈 배열인 경우와 그렇지 않은 경우로 나눌 수 있다. 각각의 경우는 다른 방식으로 처리해야 한다.</p>
<ul>
<li><code>arrSum: [number] =&gt; number</code></li>
<li><code>arrSum([ ])</code> &lt;- 입력값이 빈 배열인 경우</li>
<li><code>arrSum([요소,요소2,...요소n])</code>&lt;- 그렇지 않은 경우</li>
</ul>
</li>
</ul>
<h3 id="3-단순한-문제-해결하기">3. 단순한 문제 해결하기</h3>
<p>재귀의 기초(base case) = 문제를 구분한 다음 가장 해결하기 쉬운 문제부터 해결한다.
재귀의 기초는 나중에 재귀 함수를 구현할 때, 재귀의 탈출조건(재귀 호출이 멈추는 조건)을 구성한다.</p>
<p>탈출조건이 없는 경우 재귀 함수는 끝없이 자기 자신을 호출하게 된다. 그렇다고 문제를 덜 쪼갠 상태에서 탈출 조건을 세우는 경우에는 해결할 수 없게 된다. 그만큼 쪼갠다음 해결하는 것이 중요하다.</p>
<ul>
<li><code>arrSum: [number] =&gt; number</code></li>
<li><code>arrSum([ ]) === 0</code>&lt;- 입력값이 빈 배열인 경우 : 해결</li>
<li><code>arrSum([요소,요소2,...요소n])</code></li>
</ul>
<h3 id="4-복잡한-문제-해결하기">4. 복잡한 문제 해결하기</h3>
<ul>
<li>길이가 1 이상인 배열이 함수 <code>arrSum</code>에 입력된 경우, 입력된 배열을 배열의 첫 요소와 나머지 요소를 입력값으로 갖는 문제로 쪼개고, 둘을 더한다.</li>
<li><code>arrSum: [number] =&gt; number</code></li>
<li><code>arrSum([ ]) === 0</code></li>
<li><code>arrSum([요소,요소2,...요소n])=== 요소1 + arrSum([요소2,...요소n])</code>&lt;- 그렇지 않은 경우: 해결</li>
<li>배열을 첫 요소와 더 작은 문제로 쪼개는 방법만 안다면, 함수 <code>arrSum</code>을 재귀적으로 구현할 수 있다.</li>
</ul>
<h3 id="5-코드로-구현하지">5. 코드로 구현하지</h3>
<pre><code class="language-js">function arrSum(arr) {
  // base case : 문제를 더 이상 쪼갤 수 없는 경우 (재귀의 기초)
  if (arr의 길이가 0인 경우) {
    return 0;
  }

  // recursive case : 그렇지 않은 경우
  return 요소1 + arrSum([요소2, ... , 요소n]);
}</code></pre>
<p>아래는 일반적인 재귀함수 템플릿.</p>
<pre><code class="language-js">function recursive(input1, input2, ...) {
  // base case : 문제를 더 이상 쪼갤 수 없는 경우
  if (문제를 더 이상 쪼갤 수 없을 경우) {
    return 단순한 문제의 해답;
  }

  // recursive case : 그렇지 않은 경우
  return 더 작은 문제로 새롭게 정의된 문제
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드스테이츠 FE Section2 회고록]]></title>
            <link>https://velog.io/@nada_1221/Section2winteriscoming</link>
            <guid>https://velog.io/@nada_1221/Section2winteriscoming</guid>
            <pubDate>Thu, 18 Aug 2022 07:22:57 GMT</pubDate>
            <description><![CDATA[<h1 id="섹션-2-회고록">섹션 2 회고록</h1>
<h2 id="goodbye-section-2">Goodbye Section 2!</h2>
<hr>
<p><img src="https://c.tenor.com/Ag_9v0a2TCgAAAAC/korean-clapping.gif" alt="https://c.tenor.com/Ag_9v0a2TCgAAAAC/korean-clapping.gif"></p>
<p>음 이번에도 길고 길었던 섹션2가 끝났다. </p>
<p>이번에도 섹션이 끝나면 어떠한 감정이 있을거라 생각했다.</p>
<p>이번에도 물론 뿌듯함은 있었다. </p>
<p>서버도 건드려보고 리엑트도 건드려보고 여러가지를 건드려봤다.</p>
<p>그런데 그동안 내가 뭘 했는지 정리도 안되는 데 시간은 지나갔다. </p>
<p>눈을 떴다 감으면 하루가 지나가 있고, 그렇게 일주일이 지나가고, 그렇게 섹션이 끝났다.</p>
<p><img src="https://c.tenor.com/g0DOGYraig8AAAAM/wow-um.gif" alt="…um?"></p>
<p>…um?</p>
<p><del>(리액트 감이 올만하니 회고..? 이게 맞나…?)</del></p>
<p>그래도 지나가는 시간을 잡을 수는 없으니 앞으로 를 더 철저히 준비해야 될 것이다.</p>
<p>아 그리고 섹션 2도 어려웠는데 섹션 3는 더 어렵다고 한다.  : ) </p>
<p>하나 알게된 사실이 있다면 섹션2 나 섹션 3 나 지금 배우고 있는 섹션이 가장 쉬운 것이고, 앞으로 내가 배우게 될 섹션 들은 지금보다 더 어려울 것이라는 것.</p>
<p>즉 오늘이 가장 쉬운 날이고 내일이 가장 어려운 날이자 가장 쉬운 날이 될 것이라는것.</p>
<p>배운다는게 그런 것 같다. 배우지 않으면 어려운게 당연하고 배우면 쉬워진다. </p>
<p>그런 고로 앞으로의 배움에 더 진지하게 임하고자 이번엔 <strong>목표가 아닌 나 자신</strong>에 대해 다시 한번 체크해보려고 한다. </p>
<hr>
<h2 id="0-슬럼프">0. 슬럼프</h2>
<p>코드 스테이츠에 멋들어지게 발을 들인지 벌써 2달이 되어간다.</p>
<p>그렇게 들어온 코드 스테이츠 FE 과정을 해나가면서 솔직히 말해서 버거웠다.</p>
<p>배우는 내용들이 엄청나게 버겁거나 하는 수준은 아니었지만 하루하루 새로운 것을 배우는 것이 버거웠다. </p>
<p>하나를 다 알기도 전에 다른 하나를 배워야 했다. </p>
<p>하루 이틀은 상관없지만 벌써 적어도 40일 가까이 그렇게 지식을 쌓고있다. </p>
<p>그러다보니 머리속에서 지식들이 뒤죽박죽 섞이기도 하고 또 생각했던 코드가 사용된 곳에서는 엉뚱한 결과가 나오는 경우도 있었다. </p>
<p><img src="https://cdn.jjalbot.com/2018/12/r1Hy3a4zlN/20171231_5a4883966822f.gif" alt="https://cdn.jjalbot.com/2018/12/r1Hy3a4zlN/20171231_5a4883966822f.gif"></p>
<p>그렇게 슬럼프가 찾아왔다.</p>
<p>코드를 적는 것에 대한 부담감이 생겼다. </p>
<p>“틀리면 어떡하나?” 의 문제가 아닌 <strong>코드 자체를 적기가 싫었다.</strong> </p>
<p>어차피 틀릴 것이라고 생각했으니까.</p>
<p>어차피 내 코드는 틀릴 것이고 결국 나는 시간만 허비할 것이라는 생각 때문이었다.</p>
<p>물론 지금 돌아보면 생각 자체가 틀렸고 그렇게 생각하면 안 됐었다. </p>
<p>이미 바닥을 쳤던 자존감은 돌아올 생각을 안했다.</p>
<p>하지만 바닥을 찍는 다는 의미를 조금 다르게 생각해보면 발을 디딜곳까지 내려온 것이고 발을 디딜 수 있다면 다시 박차오를 수 있다는 생각을 했다.</p>
<p>물론 그런 생각을 하게 된 계기가 있었다.</p>
<p>이제부터 그 계기와 함께 조금 더 글을 써보려고 한다.</p>
<hr>
<h2 id="1-나에-대해-돌아보다">1. 나에 대해 돌아보다.</h2>
<p>우선 거창할 것은 없었다. </p>
<p>그저 아무렇게나 적어본 코플릿 내용이 정답 이었던 적이 있었다.</p>
<p>정말 의아했다. 왜 이게 맞는지도 알겠고, 왜 이걸 썼는지도 알겠는데 믿기지 않았다.</p>
<p><img src="https://t1.daumcdn.net/cfile/tistory/99EC91435E06FCAC28" alt=""></p>
<p>그래서 생각했다. </p>
<p>“<strong>생각보다 나는 그래도 아는게 있는지도 모르겠다”</strong> 고.</p>
<p>그 날, 그 일을 계기로 나는 나 자신에 대해 좀 돌아봤다.</p>
<p>돌아 본 리스트는 별거 아닌 단순한 내용이었다.</p>
<ul>
<li>나는 코딩을 얼마나 배웠을까?</li>
<li>내가 하는 코드가 맞을까?</li>
<li>나는 어떻게 해야할까?</li>
<li>나를 믿어야 하는가?</li>
</ul>
<p>리스트들을 적어보니 정말 아무것도 아닌 내용들이다.</p>
<p>하지만 다르게 말하면 정말 아무것도 아닌 내용들이 쌓여 나는 슬럼프를 겪었다.</p>
<p>사람을 무너뜨리는 것은 거창한 것이 아니라 저런 사소한 것들 일 수도 있다.</p>
<p>아무튼 저 리스트 들에 대한 대답을 간단하게 요약해보자면</p>
<blockquote>
<p>나는 코딩을 제대로 배운지 2달도 안된 코린이다. 그렇기 때문에 내가 하는 코드가 맞을 확률보다 틀릴 확률이 높다. <strong>당연한 것이다.</strong> 그렇다면 나는 어떻게 해야 할까?? 배운지 얼마 안된 사람이 모든 것을 척척 한다는 것이 가능한 것은 천재 뿐이다. 나는 나를 안다. <strong>나는 천재가 아니다.</strong> 그렇기 때문에 틀릴 수 있고 틀려야 한다. <strong>틀린 곳에서 부터 답을 찾아가는 것이 코딩</strong> 이라고 생각하기 때문이다.</p>
</blockquote>
<p>가장 중요한 대답은 바로 나를 믿어야 하는가? 에 대한 대답이라고 생각한다.</p>
<p>하지만 이 대답은 맨 마지막 단락으로 미루고 싶다. 이 대답은 이 글에 대한 마침이자 나에 대한 고찰 이기 때문이다. </p>
<hr>
<h2 id="2-앞으로-나아갈-마음의-준비">2. 앞으로 나아갈 마음의 준비</h2>
<p>이제 나에게 남은 일은 슬럼프가 오더라도 이겨낼 수 있도록 마음에 무장을 하는 일이다.</p>
<p>사소한 무엇인가가 또 쌓여서 무너질 지도 모른다. 아마 계속해서 무너질 거고 그때마다 일어날 것이란 걸 안다. 그렇기에 더더욱 마음에 대한 무장을 해야 한다 생각한다.</p>
<p>위에서 <strong>나는 어떻게 해야 할까?</strong> 라는 질문이 있었다. </p>
<p>그에 대한 대답으로 나는 틀릴 수 있고 틀려야 한다고 적었다.</p>
<p>사실 저 대답은 반은 맞고 반은 틀리다고 생각한다.</p>
<p>정확하게 적을 수 있는 코드는 당연히 정확하게 적으면 좋다.</p>
<p>여기서 내가 더 첨언하고 싶은 내용은 바로</p>
<blockquote>
<p><strong>모르겠으면 일단 그냥 적어라.</strong></p>
</blockquote>
<p>모르겠으면 일단 적고 틀리라는 말이었다.</p>
<p>내 안좋은 습관 중에 하나라고 생각하는 것은 생각을 할 때 손을 멈춘다는 것이다.</p>
<p>이 습관이 정말 안좋다고 생각하게 된 계기는 바로 직전 페어 님 덕분이었다.</p>
<p>그 페어 분은 모든 것을 console.log()로 찍어봤다. </p>
<p>정말 사소한 것들 까지 다 찍어보고 답을 찾아냈다.</p>
<p>나는 그 부분이 정말 신기했고 따라해보며 왜 해야하는지에 대해서도 알게됐다.</p>
<p>찍어보지 않으면 모를 것들이 너무 많았다. </p>
<p>한가지 예로 들자면 id 값이 들어올 때 ‘42’ 로 들어오면 이 id 의 type 은 무엇일까?  </p>
<p>나는 너무나 안일 하게도 Number 라고 가정하고 문제를 풀었으나 절대 풀리지 않았다. </p>
<p>결국 console.log(typeof id) 를 쳐보고 나서야 id 의 type 이 String 이라는 것을 알았다. </p>
<p>정말 단순한 예시 이지만 위에 말 처럼 모르겠으면 일단 적어보라는 말에 완벽한 예시라고 생각한다.</p>
<p>모를 수도 있고 틀릴 수도 있다. 앞으로 내가 개발자가 되어도 계속 틀릴 것이다. </p>
<p>틀릴 때마다 무너지지 않도록 스스로를 무장하도록 하자.</p>
<p><img src="https://i.gifer.com/origin/4b/4bf848cb05f34ec1abb2725a8e70904a.gif" alt="https://i.gifer.com/origin/4b/4bf848cb05f34ec1abb2725a8e70904a.gif"></p>
<p><strong>모르겠으면 일단 그냥 적고 틀리자. 틀린 곳부터 풀어 나가서 정답으로 가면 될 것이다.</strong></p>
<hr>
<h2 id="3-나를-믿어야-하는가">3. 나를 믿어야 하는가?</h2>
<blockquote>
<p>결론 부터 말하자면 Yes 믿어야 한다. 세상에서 내가 나를 믿어주지 않으면 누가 나를 믿어주겠는가?</p>
</blockquote>
<p><strong>라는 같잖은 말을 할 생각은 없다.</strong></p>
<p>나를 믿으면 안된다. <strong>그게 개발자라면 말이다.</strong></p>
<p><strong>내 코드가 틀릴 수 있고 언젠가 고쳐야 할 코드라고 생각해야한다.</strong></p>
<p><del>물론 내가 개발자가 아니기 때문에 전문가적인 의견은 아니다.</del></p>
<p>다만 ‘개발자인 나’ 가 아닌 <strong>말 그대로 ‘나 자신&#39; 은 믿어줘야 한다.</strong></p>
<p>나는 잘 하고 있다. 내가 하는 일들은 잘 되어 가고있다 믿어주면서 끌고 나가야한다.</p>
<p>사람은 의기가 떨어지면 지친다고 생각한다. 나는 잘하고있다고 꾸준히 생각하고 믿어주면 지쳐가는 텀 이 조금은 더 천천히 찾아올 것이라고 믿는다.</p>
<p>그렇기 때문에 나는 두 가지를 분리해서 믿어주기로 했다.</p>
<p>‘<strong>개발자가 되기 위한 나’는 언제나 의심하지만, 반대로 ‘일상 속의 나’는 언제나 믿음을 주기로 말이다.</strong></p>
<hr>
<h2 id="마치며">마치며…</h2>
<p>사실 기존의 KRT 회고로 적어야 했지만 이미 섹션 1 때 목표를 상기하고 열심히 이뤄가고 있었기 때문에 아직 한달도 채 되지 않은 이 시점에서 다시 적고 싶지 않았다.</p>
<p>그래서 섹션 2에서 숱한 좌절을 겪으며 조금이나마 성장한 나 자신을 돌아본 기억을 되살려 동기 분들에게 말하며 같이 생각해보고 싶었다.</p>
<p>아마 우리는 앞으로도 많은 시간을 같이 좌절해가며 성장 해 갈 것이다.</p>
<p>그 동안(혹은 당장) 나 처럼 슬럼프에 빠지거나 혹은 빠져있는 동기가 있다면, </p>
<p>그리고 그 동기에게 내가 쓴 이 회고글이 조금이라도 도움이 될 수 있었으면 좋겠다.</p>
<p>아무튼 FE_40 기 동기 여러분들 이 더운 계절을 보내고 추워질 계절이 올 때까지 다같이 힘내봅시다 = )</p>
<p><img src="https://c.tenor.com/vLCmZWrhX3cAAAAC/got-game-of-thrones.gif" alt="Game of thrones (왕좌의 게임) 재밌습니다 안보신분들 보세요 ㅎㅎ "></p>
<p>Game of thrones (왕좌의 게임) 재밌습니다 안보신분들 보세요 ㅎㅎ</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Web Server]Express]]></title>
            <link>https://velog.io/@nada_1221/Web-ServerExpress</link>
            <guid>https://velog.io/@nada_1221/Web-ServerExpress</guid>
            <pubDate>Sun, 14 Aug 2022 05:33:22 GMT</pubDate>
            <description><![CDATA[<h2 id="refactor-express-개요">Refactor Express 개요</h2>
<p><img src="https://codingthesmartway.com/wp-content/uploads/2019/01/mern_logo.png" alt="">
MERN stack은 JavaScript 생태계에서 인기 있는 프레임워크인 MongoDB,Express,React,Node.js를 지칭하는 말이다. 이 중에서 Express는 Node.js 환경에서 웹 서버, 또는 API 서버를 제작하기 위해 사용되는 인기 잇는 프레임워크이다.</p>
<p>Express로 구현한 서버가 Node.js HTTP모듈로 작성한 서버와 다른 점은 다음과 같다.</p>
<ol>
<li>미들웨어를 추가할 수 있다.</li>
<li><a href="https://expressjs.com/ko/guide/routing.html">라우터</a>를 제공한다.</li>
</ol>
<p>리펙토링을 진행해보자. 그 전에.</p>
<h3 id="간단한-웹-서버-만들기">간단한 웹 서버 만들기</h3>
<p>Express 공식 문서의 <a href="https://expressjs.com/ko/starter/hello-world.html">시작하기 - Hello world 예제</a>를 참고해보자.</p>
<pre><code class="language-js">const express = require(&#39;express&#39;)
const app = express()
const port = 3000

app.get(&#39;/&#39;, (req,res) =&gt;{
  res.send(&#39;Hello World&#39;)
})

app.listen(port, ()=&gt;{
  console.log(`Example app listening on port${port}`)
})</code></pre>
<h3 id="라우팅-메서드와-url에-따라-분기routing하기">라우팅: 메서드와 url에 따라 분기(Routing)하기</h3>
<p>Express 공식 문서의 <a href="https://expressjs.com/ko/starter/basic-routing.html">시작하기 - 기본 라우팅</a>을 참고해보자.</p>
<p>메서드와 url(<code>/lower</code>,<code>/upper</code> 등)로 분기점을 만드는 것을 라우팅이라고 한다.</p>
<p>클라이언트는 특정한 HTTP요청 메서드(GET,POST 등)와 함께 서버의 특정 URI(또는 경로)로 HTTP 요청을 보낸다. 라우팅은 클라이언트의 요청에 해당하는 Endpoint에 따라 서버가 응답하는 방법을 결정하는 것이다.</p>
<p>추가적인 라이브러리를 사용하지 않고, 순수한 Node.js로 코드를 작성하면, 다음과 같이 작성할 수 있다.</p>
<pre><code class="language-js">const requestHandler = (req, res) =&gt; {
  if(req.url === &#39;/lower&#39;) {
    if (req.method === &#39;GET&#39;) {
      res.end(data)
    } else if (req.method === &#39;POST&#39;) {
      req.on(&#39;data&#39;, (req, res) =&gt; {
        // do something ...
      })
    }
  }
}</code></pre>
<p>반면에 Express는 프레임워크 자체에서 라우터 기능을 제공한다. Express의 라우터를 활용하면 아래와 같이 직관적인 코드를 작성할 수 있다.</p>
<pre><code class="language-js">const router = express.Router()

router.get(&#39;/lower&#39;,(req,res) =&gt;{
  res.send(data);
})

router.post(&#39;/lower&#39;,(req,res)=&gt;{
  // do something
})</code></pre>
<h2 id="middleware">Middleware</h2>
<hr>
<p><img src="https://i.morioh.com/200522/661f29bd.jpg" alt="">
자동차 공장에서는 컨베이어 벨트 위에 올려진 자동차의 뼈대에, 각 공정마다 부품을 추가한다. 모든 부품이 추가되면 완성된 자동차가, 어딘가 문제가 있다면 불량품이 결과물로 나오게 된다. <strong>미들웨어<code>Middleware</code></strong> 는자동차 공장의 공정과 비슷하다. 컨베이어 벨트 위에 올라가 있는 요청(Request)에 필요한 기능을 더하거나, 문제가 발견된 불량품을 밖으로 걷어내는 역할을 한다. 미들웨어는 express의 가장 큰 장점이라고 할 수 있다.</p>
<h3 id="자주-사용하는-미들-웨어">자주 사용하는 미들 웨어</h3>
<hr>
<p>미들웨어를 사용하는 상황은 다음과 같다,</p>
<p>1.POST 요청 등에 포함된 body(payload)를 구조화할 때 (쉽게 얻어내고자 할 때)
2. 모든 요청/응답에 CORS 헤더를 붙여야 할 때.
3. 모든 요청에 대해 url이나 메서드를 확인할 때
4. 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때</p>
<p>미들웨어를 이용하면 Node.js만으로 구현한 서버에서는 번거로울 수 있는 작업을 보다 쉽게 적용할 수 있다.
3번과 4번은 직접 만들어볼 예정이므로, Express로 구현한 서버에서 흔하게 사용하는 미들웨어인 1번과 2번의 경우를 살펴보자</p>
<h3 id="case-1-post-요청-등에-포함된-bodypayload-구조화-할-때">case 1: POST 요청 등에 포함된 body(payload) 구조화 할 때</h3>
<p>Node.js로 HTTP body(payload)를 받을 때에는 Buffer를 조합해서 다소 복잡한 방식으로 body를 얻을 수 있다. 
네트워크 상의 chunk를 합치고, buffer를 문자열로 변환하는 작업이 필요하다.</p>
<pre><code class="language-js">let body = [];
request.on(&#39;data&#39;,(chunk)=&gt;{
  body.push(chunk);
}).on(&#39;end&#39;,()=&gt;{
  body = Buffer.concat(body).toString();
  //body 변수에는 문자열 형태로 payload가 담겨져 있다.
});

/* what is chunk, buffer, payload? */</code></pre>
<p>Express v4.16.0부터는 body-parser를 따로 설치하지 않고, Express 내장 미들웨어인 express.json()을 사용한다.</p>
<pre><code class="language-js">const jsonParser= express.json();

// ...생략
app.post(&#39;/api/users&#39;,jsonParse,function(req,res){

})</code></pre>
<blockquote>
<p>Mini-Node Server 리팩토링을 진행하다 express.json() 미들웨어 사용에 어러가 났다면?
<a href="https://expressjs.com/ko/4x/api.html#express.json">express.json([options])</a>의 options에 해답이 있다.</p>
</blockquote>
<pre><code class="language-js">const jsonParser = express.json({strict: false});

// ...생략
app.post(&#39;/api/users&#39;,jsonParse,function(req,res){

})</code></pre>
<p><strong>options</strong> 에 <strong>{strict:false}</strong> 추가했다. 어떤 의미인지 설명할 수 있어야 한다.</p>
<h3 id="case-2-모든-요청-응답에-cors-헤더를-붙일-때">case 2: 모든 요청/ 응답에 CORS 헤더를 붙일 때</h3>
<p>Node.js HTTP모듈을 이용한 코드에 CORS헤더를 붙이려면, 응답 객체의 <code>writeHead</code>메서드를 이용할 수 있다. Node.js에서는 이 메서드 등을 이용하여 라우팅마다 헤더를 매번 넣어주어야 한다. 그뿐만 아니라. <code>OPTIONS</code> 메서드에 대한 라우팅도 따로 구현해야 한다.</p>
<pre><code class="language-js">const defaultCorsHeader = {
  &#39;Access-Control-Allow-Origin&#39;:&#39;*&#39;,
  &#39;Access-Control-Allow-Methods&#39;:&#39;GET,POST,PUT,DELETE,OPTIONS&#39;,
  &#39;Access-Control-Allow-Headers&#39;:&#39;Content-Type,Accept&#39;,
  &#39;Access-Control-MAX-Age&#39;:10
};
//...생략
if (req.method === &#39;OPTIONS&#39;)
  res.writeHead(201,defaultCorsHeader);
res.end()
}</code></pre>
<p><a href="http://expressjs.com/en/resources/middleware/cors.html">cors 미들웨어</a>를 사용하면 이 과정을 간단하게 처리할 수 있다.</p>
<pre><code class="language-js">npm install cors</code></pre>
<pre><code class="language-js">// 모든 요청에 대해 CORS 허용
const cors = require(&#39;cors&#39;);

//...생략
app.use(cors());

// 특정 요청에 대해 CORS 허용
const cors = require(&#39;cors&#39;)

//...생략
app.get(&#39;products/:id&#39;,cors().function(req,res,next){
  res.json({msg:&#39;This is CORS-enabled for a SIngle Route&#39;})        
})</code></pre>
<h3 id="case-3-모든-요청에-대해-url이나-메서드를-확인할-때">case 3: 모든 요청에 대해 url이나 메서드를 확인할 때</h3>
<p>미들웨어는 말 그대로 프로세스 중간에 관여하여 특정 역할을 수행한다. 수많은 미들웨어가 있지만, 가장 단순한 미들웨어 로거(logger)를 예로 들겠다. 로거는 디버깅이나, 서버 관리에 도움이 되기 위해 <code>console.log</code>로 적절한 데이터나 정보를 출력한다. 데이터가 여러 미들웨어를 거치는 동안 응답할 결과를 만들어야 한다면, 미들웨어 사이사이에 로거를 삽입하여 현재 데이터를 확인하거나, 디버깅에 사용할 수 있다. 이런 미들웨어는 일반적으로 다음과 같은 구성을 가진다.
<img src="https://s3.ap-northeast-2.amazonaws.com/urclass-images/auEpUwrE7-1600964704103.png" alt="">
위 그림은 ㄷndpoint가 <code>/</code>이면서, 클라이언트로부터 <code>GET</code>요청을 받았을 때 적요되는 미들웨어이다.
파라미터의 순서에 유의해야 한다. <code>req</code>,<code>res</code>는 우리가 잘 아는 요청, 응답이고 <code>next</code>는 다음 미들웨어를 실행하는 역할을 한다.</p>
<p>만약 특정 endtpoint가 아니라, 모든 요청에 동일한 미들웨어를 적용하려면 어떻게 해야 할까?
메서드<a href="http://expressjs.com/ko/api.html#app.use">app.use</a>를 사용하면 된다. 아래 코드를 직접 실행해 보자. 모든 요청에 대해<code>LOGGED</code>가 출력되는 걸 확인할 수 있다.</p>
<pre><code class="language-js">const express = require(&#39;express&#39;);
const app = express();

const myLogger = function(req,res,next){
  console.log(&#39;LOGGED&#39;);
  next();
};

app.use(myLogger);

app.get(&#39;/&#39;,function(req,res){
  res.send(&#39;Hello World&#39;);
});

app.listen(3000);</code></pre>
<h3 id="case-4-요청-헤더에-사용자-인증-정보가-담겨있는지-확인할-때">case 4: 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때</h3>
<p>다음은 HTTP 요청에서 토큰이 있는지를 판단하여, 이미 로그인한 사용자일 경우 성공, 아닐 경우 에러를 보내는 미들웨어 예제이다.</p>
<blockquote>
<p>토큰(Token):주로 사용자 인증에 사용하며, Section3 인증(Authentication) 유닛에서 다룬다.</p>
</blockquote>
<pre><code class="language-js">app.use((req,res,next)=&gt;{
  //토큰이 있는지 확인, 없으면 받아줄 수 없음
  if(req.headers.token){
    req.isLoggedIn= true;
    next();
  }else{
    res.status(400).send(&#39;invalid user&#39;)
  }
})</code></pre>
<p>로그인 없이 웹사이트에 접근을 시도했을 때, 로그인 창으로 되돌려 보내는 경우를 경험해 본 적이 있을 것이다.
서버에서는 요청에 포함된 데이터를 통해 미들웨어가 요구하는 조건에 맞지 않으면, 불량품으로 판단하고 돌려보내도록 구현할 수 있다.</p>
<h2 id="refactor-express-start">Refactor Express start</h2>
<hr>
<h4 id="refactor-before">Refactor before</h4>
<pre><code class="language-jsx">const server = http.createServer((req, res) =&gt; {
  if (req.method === &#39;POST&#39;) {
    if (req.url === &#39;/lower&#39;) {
      let data = &#39;&#39;;
      req.on(&#39;data&#39;, chunk =&gt; {
        data = data + chunk;
      });
      req.on(&#39;end&#39;, () =&gt; {
        data = data.toLowerCase();
        res.writeHead(201, defaultCorsHeader);
        res.end(data);
      });
    } else if (req.url === &#39;/upper&#39;) {
      let data = &#39;&#39;;
      req.on(&#39;data&#39;, chunk =&gt; {
        data = data + chunk;
      });
      req.on(&#39;end&#39;, () =&gt; {
        data = data.toUpperCase();
        res.writeHead(201, defaultCorsHeader);
        res.end(data);
      });
    } else {
      res.writeHead(404, defaultCorsHeader);
      res.end();
    }
  }
  if (req.method === &#39;OPTIONS&#39;) {
    res.writeHead(200, defaultCorsHeader);
    res.end();
  }
});

server.listen(PORT, ip, () =&gt; {
  console.log(`http server listen on ${ip}:${PORT}`);
});

const defaultCorsHeader = {
  &#39;Access-Control-Allow-Origin&#39;: &#39;*&#39;,
  &#39;Access-Control-Allow-Methods&#39;: &#39;GET, POST, PUT, DELETE, OPTIONS&#39;,
  &#39;Access-Control-Allow-Headers&#39;: &#39;Content-Type, Accept&#39;,
  &#39;Access-Control-Max-Age&#39;: 10
};</code></pre>
<h4 id="refactor-affter">Refactor affter</h4>
<p>```jsx
const express = require(&#39;express&#39;);
const app = express();
const cors = require(&#39;cors&#39;);</p>
<p>app.use(cors());
// app.use(express.static(&#39;client&#39;));
app.use(express.json({ strict: false }));
//배열과 개체만 허용하거나 사용하지 않도록 설정합니다. 비활성화되면 모든 것을 JSON.parse수락합니다.
//기본 값 = true;</p>
<p>// GET
app.get(&#39;/&#39;, (req, res) =&gt; {
  res.send(&#39;Hello world!&#39;);
})</p>
<p>// POST
app.post(&#39;/upper&#39;, (req, res) =&gt; {
  //console.log(req.body);
  res.json(req.body.toUpperCase());
  // let result = req.body;
  // result = result.toUpperCase();
  // console.log(result);
  // res.json(result);
})</p>
<p>app.post(&#39;/lower&#39;, (req, res) =&gt; {
  //console.log(req.body);
  res.json(req.body.toLowerCase());
  // let result = req.body;
  // result = result.toLowerCase();
  // // console.log(result);
  // res.json(result);
})</p>
<p>app.listen(PORT, ip, () =&gt; {
  console.log(<code>http server listen on ${ip}:${PORT}</code>);
});</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Web Server] CORS]]></title>
            <link>https://velog.io/@nada_1221/Web-Server-CORS</link>
            <guid>https://velog.io/@nada_1221/Web-Server-CORS</guid>
            <pubDate>Sun, 14 Aug 2022 04:17:22 GMT</pubDate>
            <description><![CDATA[<h2 id="sop">SOP</h2>
<hr>
<p>SOP는 <code>Same-Origin Policy</code>의 줄임말로, 동일 출처 정책을 뜻한다.</p>
<p>한 마디로 <code>같은 출처의 리소스만 공유가 가능하다</code> 라는 정책을 뜻한다.</p>
<p>여기서 말하는 출처<code>Origin</code>는 다음과 같다.</p>
<p><img src="https://s3.ap-northeast-2.amazonaws.com/urclass-images/3GBKU8dBwEv5lGTqIpsdm-1654737466758.png" alt="">
출처는 프로토콜, 호스트, 포트의 조합으로 되어있다. 이 중 하나라도 다르면 동일한 출처로 보지 않는다.</p>
<p>예시를 들어 이해해 보자.</p>
<ul>
<li><code>https://www.codestates.com</code> vs <code>http://www.codestates.com</code> </li>
<li><blockquote>
<p>두 URI는 <strong>프로토콜</strong>이 다르기 때문에 동일 출처가 아니다. (https / http)</p>
</blockquote>
</li>
<li><code>https://urclass.codestates.com</code> vs <code>https://codestates.com</code></li>
<li><blockquote>
<p>두 URI는 <strong>호스트</strong>가 다르기 때문에 동일 출처가 아니다.(urclass.codestates.com / codestates.com)</p>
</blockquote>
</li>
<li><code>http://codestates.com:81</code> vs <code>http://codestates.com</code><ul>
<li>http 프로토콜의 기본 포트는 80이다. 따라서 <code>http://codestates.com</code>는 <code>http://codestates.com:80</code> 과 동일하다.</li>
<li><blockquote>
<p>두 URI는 <strong>포트</strong>가 다르기 때문에 동일 출처가 아니다(:81/:80)</p>
</blockquote>
</li>
</ul>
</li>
<li><code>https://codestates.com:443</code> vs <code>https://codestates.com</code><ul>
<li>https 프로토콜의 기본 포트는 443이다. 따라서 두 URI는 프로토콜,호스트,포트 모두 같은 동일 출처이다.</li>
</ul>
</li>
</ul>
<p>그렇다면 SOP는 왜 생겨나게 되었는가?
동일 출처 정책은 잠재적으로 해로울 수 있는 문서를 분리함으로써 <strong>공격 받을 수 있는 경로를 줄여준다.</strong>
SOP를 통해 해킹등의 위협에서 보다 더 안전해질 수 있다는 것이다. 왜 그런지 알아보기 위해 동일 출처 정책이 없는 상황을 가정해 보자.</p>
<p>우리가 네이버 같은 웹 페이지에 로그인해서 서비스를 이용하고 있다고 해보자. 서비스 이용중이 아니더라도 로그아웃을 깜빡했거나, 자동 로그인 기능으로 인해 브라우저에 로그인 정보가 남아있을 수도 있을 것이다. </p>
<p>그 상태에서 우리의 로그인 정보를 노리는 코드가 있는 다른 사이트에 방문하게 된다면? 해커는 우리의 로그인 정보를 이용해서 네이버에서 사용할 수 있는 모든 기능을 이용할 수 있게된다. 나도 모르는 사이에 내 계정으로 해커 갖은 행위를 할 수 있는 것이다.</p>
<p>SOP가 있다면? SOP는 애초에 다른 사이트와의 리소스 공유를 제한하기 때문에 로그인 정보가 타 사이트의 코드에 의해서 새어나가는 것을 방지할 수 있다. 이러한 보안상 이점 때문에 SOP는 모든 브라우저에서 기본적으로 사용하고 있는 정책이다.</p>
<p>그런데, 다른 출처의 리소스를 사용하게 될 일은 너무나도 많다. 개발중인 웹 사이트에서 네이버 지도 api를 사용하고 싶다면? github 정보를 받아와서 사용하고 싶다면? 모두 다른 출처의 리소스를 사용해야하는 일이다. 어떻게 하면 다른 출처의 리소스를 받아올 수 있을까?</p>
<h2 id="cors">CORS</h2>
<hr>
<p>위 문제 상황에서 필요한 것이 바로 CORS이다. CORS는 <code>Cross-Origin Resource Sharing</code>의 줄임말로 <strong>교차 출처 리소스 공유</strong>를 뜻한다. 
MDN에서는 CORS를 다음과 같이 정의하고 있다.</p>
<blockquote>
<p><strong>교차 출처 리소스 공유</strong>(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 <strong>다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여</strong>하도록 브라우저에 알려주는 체제입니다.</p>
</blockquote>
<p>즉, 브라우저는 SOP에 의해 기본적으로 다른 출처의 리소스 공유를 막지만, CORS를 사용하면 접근 권한을 얻을 수 있게 되는 것이다. 
<img src="https://s3.ap-northeast-2.amazonaws.com/urclass-images/WOPcppPfHOgJqLWPcVdY3-1654737520932.png" alt="">
해당 에러를 쉽게 풀어쓰면 다음과 같을 것이다.</p>
<blockquote>
<p>다른 출처의 리소스를 가져오려고 했지만 <strong>SOP</strong> 때문에 접근이 불가능합니다.
CORS 설정을 통해 서버의 응답 헤더에 ‘Access-<strong>Control-Allow-Origin’을 작성하면 접근 권한을 얻을 수 있습니다.</strong></p>
</blockquote>
<p>즉, 이 에러는 CORS 때문이 아니라, <strong>SOP 때문</strong>이다. CORS는 오히려 이 에러를 해결해줄 수 있는 방안이었던 것이다. </p>
<h2 id="cors-동작-방식">CORS 동작 방식</h2>
<hr>
<p>CORS의 동작 방식에는 크게 세 가지가 있다.</p>
<ol>
<li>프리플라이트 요청 (Preflight Request)
실제 요청을 보내기 전, OPTIONS 메서드로 사전 요청을 보내 해당 출처 리소스에 접근 권한이 있는지부터 확인하는 것을 프리플라이트 요청이라고 한다.
<img src="https://s3.ap-northeast-2.amazonaws.com/urclass-images/962M9O76gH6gVxkQmXArv-1655259376584.png" alt="">
위 이미지의 흐름과 같이, 브라우저는 서버에 실제 요청을 보내기 전에 프리플라이트 요청을 보내고, 응답 헤더의 <code>Access-Control-Allow-Origin</code>으로 요청을 보낸 출처가 돌아오면 실제 요청을 보내게 된다.
<img src="https://s3.ap-northeast-2.amazonaws.com/urclass-images/tq2s-1QfE_a1hE60oytOb-1655259979648.png" alt="">
만약 요청을 보낸 출처가 접근 권한이 없다면 브라우저에서 CORS 에러를 띄우게 되고, 실제 요청은 전달되지 않는다.<br/>
프리플라이트 요청은 왜 필요한 것인가? </li>
</ol>
<ul>
<li>실제 요청을 보내기 전에 미리 권한 확인을 할 수 있기 때문에, 실제 요청을 처음부터 통째로 보내는 것보다 리소스 측면에서 효율적이다.</li>
<li>CORS에 대비가 되어있지 않은 서버를 보호할 수 있다. CORS 이전에 만들어진 서버들은 SOP 요청만 들어오는 상황을 고려하고 만들어졌다. 따라서 다른 출처에서 들어오는 요청에 대한 대비가 되어있지 않다.<br/>
![](https://s3.ap-northeast-2.amazonaws.com/urclass-images/Bnf8ikYSnPt9cnlkRnNyj-1655260062333.png)
이런 서버에 바로 요청을 보내면, 응답을 보내기 전에 우선 요청을 처리하게 된다. 브라우저는 응답을 받은 후에야 CORS권한이 없다는 것을 인지하지만, 브라우저가 에러를 띄운 후에는 이미 요청이 수행된 상태가 된다.  만약에 들어온 요청이 DELETE나 PUT처럼 서버의 정보를 삭제하거나 수정하는 요청이었다면? 생각해도 아찔하다.
<br/>
하지만 CORS에 대비가 되어 있지 않은 서버라도 프리플라이트 요청을 먼저 보내게 되면, 프리플라이트 요청에서 CORS 에러를 띄우게 된다. 예시와 같이 실행되선 안 되는 Cross-Origin 요청이 실행되는 것을 방지할 수 있는 것이다. 이런 이유로 프리플라이트 요청이 CORS의 기본 사양으로 들어가게 되었다.
</li>
</ul>
<ol start="2">
<li>단순 요청 (Simple Request)
단순 요청은 특정 조건이 만족되면 프리플라이트 요청을 생략하고 요청을 보내는 것을 말한다.
<img src="https://s3.ap-northeast-2.amazonaws.com/urclass-images/obZ8akdCdULqKKBYAOJd6-1655260484881.png" alt="">
조건은 다음과 같다. 하지만 이 조건들을 모두 만족시키기는 어려우므로, 일단 참고만 하자.</li>
</ol>
<ul>
<li><code>GET</code>,<code>HEAD</code>,<code>POST</code>요청 중 하나여야 한다.</li>
<li>자동으로 설정되는 헤더 외에, <code>Accept</code>,<code>Accept-Language</code>,<code>Content-Language</code>,<code>Content-Type</code>헤더의 값만 수동으로 설정할 수 있다.<ul>
<li><code>Content-Type</code>헤더에는 <code>application/x-www-form-urlencoded</code>,<code>multipart/form-data</code>,<code>text/plain</code>값만 허용된다.</li>
</ul>
</li>
</ul>
<ol start="3">
<li>인증정보를 포함한 요청 (Credentialed Request)
요청 헤더에 인증 정보를 담아 보내는 요청이다. 출처가 다를 경우에는 별도의 설정을 하지 않으며 쿠키를 보낼 수 없다. 민감한 정보이기 때문에, 이 경우에는 <strong>프론트, 서버 양측 모두 CORS 설정이 필요</strong>하다.</li>
</ol>
<ul>
<li><strong>프론트</strong> 측에서는 요청 헤더에 <code>withCredentials:true</code>를 넣어줘야 한다.</li>
<li><strong>서버</strong> 측에서는 응답 헤더에 <code>Access-Control-Allow-Credentials : true</code>를 넣어줘야 한다.</li>
<li>서버 측에서 <code>Access-Control-Allow-Origin</code>을 설정할 때, 모든 출처를 허용한다는 뜻의 와일드카드( * )로 설정하면 에러가 발생한다. 인증 정보를 다루는 만큼 출처를 정확하게 설정해주어야 한다.</li>
</ul>
<h3 id="cors-설정-방법">CORS 설정 방법</h3>
<hr>
<ol>
<li>Node.js server
Node.js로 간단한 HTTP 서버를 만들 경우, 다음과 같이 응답 헤더를 설정해줄 수 있다.<pre><code class="language-js">const http = require(&#39;http&#39;);
</code></pre>
</li>
</ol>
<p>const server = http.createServer((request, response) =&gt; {
// 모든 도메인
  response.setHeader(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;);</p>
<p>// 특정 도메인
  response.setHeader(&quot;Access-Control-Allow-Origin&quot;, &quot;<a href="https://codestates.com&quot;">https://codestates.com&quot;</a>);</p>
<p>// 인증 정보를 포함한 요청을 받을 경우
  response.setHeader(&quot;Access-Control-Allow-Credentials&quot;, &quot;true&quot;);
})</p>
<pre><code>
2. Express 서버
Express 프레임워크를 사용해서 서버를 만드는 경우에는, CORS 미들웨어를 사용해서 보다 더 간단하게 CORS 설정을 해줄 수 있다.
```js
const cors = require(&quot;cors&quot;);
const app = express();

//모든 도메인
app.use(cors());

//특정 도메인
const options = {
  origin: &quot;https://codestates.com&quot;, // 접근 권한을 부여하는 도메인
  credentials: true, // 응답 헤더에 Access-Control-Allow-Credentials 추가
  optionsSuccessStatus: 200, // 응답 상태 200으로 설정
};

app.use(cors(options));

//특정 요청
app.get(&quot;/example/:id&quot;, cors(), function (req, res, next) {
  res.json({ msg: &quot;example&quot; });
});</code></pre><p>이 외 다양한 개발 환경에서도, 헤더의 값을 설정하는 방법만 알면 CORS 설정을 해줄 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Client Ajax request [Test]]]></title>
            <link>https://velog.io/@nada_1221/React-Client-Ajax-request-Test</link>
            <guid>https://velog.io/@nada_1221/React-Client-Ajax-request-Test</guid>
            <pubDate>Wed, 10 Aug 2022 15:09:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/nada_1221/post/f28cef9f-3416-4212-92b4-223d7cfc9aed/image.png" alt=""></p>
<h2 id="-항공권-목록-필터링"># 항공권 목록 필터링</h2>
<hr>
<ul>
<li><p>Main.js</p>
<pre><code class="language-jsx">export default function Main() {
// 항공편 검색 조건을 담고 있는 상태
const [condition, setCondition] = useState({
  departure: &#39;ICN&#39;,
});
const [flightList, setFlightList] = useState(getFlight);
const [isLoading,setIsLoading] = useState(true);
// 주어진 검색 키워드에 따라 condition 상태를 변경시켜주는 함수
const search = ({ departure, destination }) =&gt; {
  if (
    condition.departure !== departure ||
    condition.destination !== destination
  ) {
    // console.log(&#39;condition 상태를 변경시킵니다&#39;);

    // TODO: search 함수가 전달 받아온 &#39;항공편 검색 조건&#39; 인자를 condition 상태에 적절하게 담아보세요.
    setCondition({departure,destination})
  }
};</code></pre>
</li>
<li><p>Search.js</p>
</li>
</ul>
<pre><code class="language-js">
function Search({onSearch}) {
  const [textDestination, setTextDestination] = useState(&#39;&#39;);

  const handleChange = (e) =&gt; {
    setTextDestination(e.target.value.toUpperCase());
  };

  const handleKeyPress = (e) =&gt; {
    if (e.type === &#39;keypress&#39; &amp;&amp; e.code === &#39;Enter&#39;) {
      handleSearchClick();
    }
  };

  const handleSearchClick = () =&gt; {
    // console.log(&#39;검색 버튼을 누르거나, 엔터를 치면 search 함수가 실행됩니다&#39;);
    onSearch({departure : &quot;ICN&quot;,destination : textDestination})
    // TODO: 지시에 따라 상위 컴포넌트에서 props를 받아서 실행시켜 보세요.
    //
  };</code></pre>
<h2 id="-ajax-요청"># AJAX 요청</h2>
<hr>
<ul>
<li>Main.Js</li>
</ul>
<pre><code class="language-jsx"> const [flightList, setFlightList] = useState();
const [isLoading,setIsLoading] = useState(true);

/* 생략 */

useEffect(() =&gt; {
 setIsLoading(true);
 getFlight(condition)
 .then(data =&gt;{
   setFlightList(data);
   setIsLoading(false);
  })
}, [condition])

/*다른 풀이법 (async-await)*/

  useEffect(async() =&gt;{
    setloading(true)
    setFlightList(await getFlight(condition))
    setloading(false)
  }, [condition])

/* 생략 */

{isLoading 
  ? &lt;LoadingIndicator /&gt; 
  : &lt;FlightList list={flightList} /&gt;
}
</code></pre>
<ul>
<li>FlightDataApi.js<pre><code class="language-jsx"></code></pre>
</li>
</ul>
<p>/* 생략 */</p>
<p>export function getFlight(filterBy = {}) {
  // HINT: 가장 마지막 테스트를 통과하기 위해, fetch를 이용합니다. 아래 구현은 완전히 삭제되어도 상관없습니다.
  // TODO: 아래 구현을 REST API 호출로 대체하세요.
  let filtered = Boolean(filterBy.destination); //false
  return(
    filtered 
    ? fetch(<code>http://ec2-13-124-90-231.ap-northeast-2.compute.amazonaws.com:81/flight?departure=ICN&amp;destination=${filterBy.destination}</code>)
  .then((res) =&gt; res.json())
    :fetch(<code>http://ec2-13-124-90-231.ap-northeast-2.compute.amazonaws.com:81/flight</code>)
    .then((res) =&gt; res.json())
    )
/* 다른 풀이 방법 */</p>
<p>  let queryString = &#39;&#39;;
  if (filterBy.departure) {
    queryString = queryString + <code>departure=${filterBy.departure}&amp;</code>;
  }
  if (filterBy.destination) {
    queryString = queryString + <code>destination=${filterBy.destination}</code>;
  }</p>
<p>  let endpoint = <code>http://ec2-13-124-90-231.ap-northeast-2.compute.amazonaws.com:81/flight?${queryString}</code>;</p>
<p>  return fetch(endpoint).then((resp) =&gt; resp.json());</p>
<p>  ```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[모던 자바스크립트 1일차]]></title>
            <link>https://velog.io/@nada_1221/%EB%AA%A8%EB%8D%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-1%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@nada_1221/%EB%AA%A8%EB%8D%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-1%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 09 Aug 2022 16:57:47 GMT</pubDate>
            <description><![CDATA[<h2 id="프로그래밍이란">프로그래밍이란?</h2>
<hr>
<blockquote>
<p>대부분의 문제는 복잡하며 명확하지 않을 수도 있다. 따라서 문제(요구사랑)를 명확히 이해하는 것이 우선 되어야 하며 복잡함을 단순하게 분해<code>decomposition</code>하고 자료를 정리하고 구분<code>modeling</code>해야 하며 순서에 맞게 행위를 배열해야 한다.
(...중략) 컴퓨터와 사람은 사고, 인지의 방식이 다르다. 따라서 컴퓨터의 관점에서 문제를 사고<code>computational thinking</code>해야 한다. 여기에는 논리적, 수학적 사고가 필요하며, 해결 과제를 작은 단위로 분해하고 패턴화해서 추출하며, 프로그래밍 내에서 사용될 모든 개념은 평가 가능하도록 정의해야 한다.</p>
</blockquote>
<p>코플릿을 풀면서 매번 느끼는 일이지만 문제를 쪼개는 것은 중요하다.
단순한 문제라도 최대한 쪼갤 수 있을 때 까지 쪼개면 문제 풀이가 수월하다는 것을 안다. 하지만 문제점은 쪼갤 대로 쪼갰다고 생각하고 문제 풀이에 들어가고 레퍼런스를 확인하면 더 쪼갤 수 있다는 것. 그리고 방향성이 맞지 않을 때도 있었다. 그럴 땐 내 능력의 한계를 느낄 수 밖에 없다.</p>
<p>아마 발전하려면 문제를 더 쪼개고 쪼개는 연습을 해야할 것 같다.</p>
<h3 id="12-프로그래밍-언어">1.2 프로그래밍 언어</h3>
<hr>
<blockquote>
<p>(...생략) 프로그래밍은 프로그래밍 언어를 사용해 컴퓨터에게 실행을 요구하는 일종의 커뮤니케이션이다. 프로그래밍 언어는 구문<code>syntax</code> 과 의미<code>semantics</code>의 조합으로 표현된다.</p>
</blockquote>
<h3 id="13-구문과-의미">1.3 구문과 의미</h3>
<hr>
<blockquote>
<p>프로그래밍 학습은 일반적으로 프로그래밍 언어의 문법을 배우는 것부터 시작한다. (...중략) 문법을 잘 안다고 해서 언어를 잘한다고 말할 수는 없다. 언어를 잘하려면 화자의 말이나 문장을 정확히 이해한 후, 문맥에 따른 적절한 어휘 선택, 그리고 순차적으로 결론을 향해 나아가는 문장 구성이 필요하다. 즉, 문법에 맞는 문장을 구성하는 것은 물론 의미를 가지고 있어야 언어의 역할을 충실히 수행할 수 있다.(...중략) 결국 문제 해결 능력을 통해 만들어낸 해결 방안은 프로그래밍 언어의 문법을 사용해 표현한다. 즉, 작성된 코드는 해결 방안의 구체적 구현물이다. 그리고 이것은 프로그래밍 언어의 문법에 부합하는 것은 물론이고 수행하고자 하는 바를 정확히 수행하는 것, 즉 요구사항이 실현(문제가 해결) 되어야 의미가 있다. </p>
</blockquote>
<p>어떤 언어를 배우더라도 문법을 잘한다고 그 언어를 잘한다고 할 수는 없다는 말에 공감한다. 가장 기초가 되는 단어를 알아야 하고, 단어와 문법을 통해 화자가 말하는 바를 잘 알아듣고 파악해야 한다. 프로그래밍으로 연관 지으면 주어지는 요소 (단어) 를 알아야 하고, 요소와 해당 문법을 조합하여 문제 풀이에 잘 연관지어 문제를 해결해야 한다. 그렇기에 기초가 가장 중요하다고 생각하며 이 책을 차근차근 읽어나가려고 하는 이유가 바로 그 기초 때문이다.</p>
<blockquote>
<p>(...생략) 대부분의 프로그래밍 언어는 <code>변수와 값</code>, <code>키워드</code>, <code>연산자</code>, <code>표현식과 문</code>, <code>조건문</code>과 <code>반복문</code>에 의한 <code>흐름제어</code>, <code>함수</code>, 그리고 자료구조인 <code>객체</code>, <code>배열</code>등과 같은 문법을 제공한다. 프로그래밍 언어가 제공하는 문법을 적절히 사용하여 변수를 통해 값을 저장하고 참조하며 연산자로 값을 연산, 평가하고 조건문과 반복문에 의한 흐름제어로 코드의 실행순서를 제어하고 함수로 재사용 가능한 문의 집합을 만들며 객체, 배열 등으로 자료를 구조화한다. <strong>결국 프로그래밍은 요구사항의 집합을 분석해서 적절한 자료구조와 함수의 집합으로 변환한 후, 그 흐름을 제어하는 것이다.</strong></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Client Ajax request [2]]]></title>
            <link>https://velog.io/@nada_1221/React-Client-Ajax-request-2</link>
            <guid>https://velog.io/@nada_1221/React-Client-Ajax-request-2</guid>
            <pubDate>Tue, 09 Aug 2022 14:26:50 GMT</pubDate>
            <description><![CDATA[<h2 id="effect-hook">Effect Hook</h2>
<hr>
<h3 id="side-effect부수-효과">Side Effect(부수 효과)</h3>
<p>함수 내에서 어떤 구현이 함수 외부에 영향을 끼치는 경우 해당 함수는 Side Effect가 있다고 이야기 한다. 
React에서는 컴포넌트 내에서 fetch를 사용해 API 정보를 가져오거나 이벤트를 활용해 DOM 직접 조작할 때 Side Effect가 발생했다고 말한다.</p>
<p>다음은, 전역 변수 foo 를 bar라는 함수가 수정하는 예제이다.</p>
<pre><code class="language-js">let foo = &#39;hello&#39;;

function bar(){
  foo = &#39;world&#39;;
}

var(); // bar는 Side Effect를 발생시킨다.</code></pre>
<h3 id="pure-function-순수-함수">Pure Function (순수 함수)</h3>
<hr>
<p>순수 함수란, 오직 함수의 입력만이 함수의 결과에 영향을 주는 함수를 의미한다. 함수의 입력이 아닌 다른 값이 함수의 결과에 영향을 미치는 경우, 순수 함수라고 부를 수 없다. 또한 순수 함수는, 입력으로 전달된 값을 수정하지 않는다.</p>
<pre><code class="language-js">function upper(str){
  return str.toUpperCase(); / toUpperCase 메소드는 원본을 수정하지 않는다 (Immutable)
}

upper(&#39;hell&#39;)//&#39;HELLO&#39;</code></pre>
<p>순수 함수에는 네트워크 요청과 같은 Side Effect가 없다. 순수 함수으 ㅣ특징 중 하나는, 어떠한 전달 인자가 주어질 경우, 항상 똑같은 값이 리턴됨을 보장한다. 그래서 예측 가능한 함수이기도 하다.</p>
<p>Q.</p>
<ul>
<li><code>Math.random()</code>은 순수 함수가 아니다. 왜일까?</li>
<li>어떤 함수가 fetch API를 이용해 AJAX 요청을 한다고 가정해 보자. 이 함수는 순수 함수가 아니다. 왜일까?</li>
</ul>
<h3 id="react의-함수-컴포넌트">React의 함수 컴포넌트</h3>
<hr>
<p>우리가 앞서 배운 React의 함수 컴포넌트는, props가 입력으로, JSX Element가 출력으로 나간다. 여기에는 그 어떤 side Efeect도 없으며, 순수 함수로 작동한다.</p>
<pre><code class="language-jsx">function SingleTweet({writer, body, createdAt}){
  return &lt;div&gt;
    &lt;div&gt;{writer}&lt;/div&gt;
    &lt;div&gt;{createdAt}&lt;/div&gt;
    &lt;div&gt;{body}&lt;/div&gt;
  &lt;/div&gt;
}</code></pre>
<p>하지만 보통 React 애플리케이션을 작성할 때에는, AJAX 요청이 필요하거나, LocalStorage 또는 타이머와 같은 React와 상관없는 API를 사용하는 경우가 발생할 수 있다. 이는 React의 입장에서는 전부 Side Effect이다. React는 Side Effect를 다루기 위한 Hook인 Effect Hook을 제공한다.</p>
<h3 id="react-컴포넌트에서의-side-effect">React 컴포넌트에서의 Side Effect</h3>
<ul>
<li>타이머 사용(setTimeout)</li>
<li>데이터 가져오기(fetch API, localStorage)</li>
</ul>
<h2 id="effect-hook-1">Effect Hook</h2>
<hr>
<p>여기 명언을 보여주는 간단한 애플리케이션이 있다. 먼저 <a href="https://lj4p9.csb.app/">이 링크를 열어서</a> 버튼을 클릭할 때마다 브라우저 상단의 타이틀이 어떻게 변경되는지 확인해보자.</p>
<p><code>useEffect</code>는 컴포넌트 내에서 Side effect를 실행할 수 있게 하는 Hook이다. 이 컴포넌트에서 실행하는 Side effect는 <strong>브라우저 API를 이용하여, 타이틀을 변경하는 것</strong> 이다. 다음 코드를 확인해 보자.</p>
<h3 id="api">API</h3>
<blockquote>
<p>useEffect(함수)</p>
</blockquote>
<p><code>useEffect</code>의 첫 번째 인자는 함수이다. 해당 함수 내에서 side effect를 실행하면 된다. 이 함수는 다음과 같은 조건에서 실행된다.</p>
<p><strong>언제 실행되나?</strong>
<img src="https://s3.ap-northeast-2.amazonaws.com/urclass-images/271i3wYsF-1620491345655.png" alt=""></p>
<ul>
<li>컴포넌트 생성 후 처음 화면에 렌더링(표시)</li>
<li>컴포넌트에 새로운 props가 전달되며 렌더링</li>
<li>컴포넌트에 상태(state)가 바뀌며 렌더링</li>
</ul>
<pre><code class="language-jsx">// ex)
useEffect(() =&gt;{
console.log(몇 번 호출 될까요?)
}) // &lt;-- 컴포넌트가 처음 생성되거나, props가 업데이트 되거나, state가 업데이트 될 때마다 실행된다. 

useEffect(() =&gt;{
console.log(몇 번 호출 될까요?)
},[]) // &lt;-- 컴포넌트가 처음 생성될 때만 함수가 실행된다. 즉 최초 1회만 호출한다.

useEffect(() =&gt;{
console.log(몇 번 호출 될까요?)
},[dep]) // &lt;-- `dep`이 업데이트 될 때마다 실행된다.</code></pre>
<p>이와 같이 매번 새롭게 컴포넌트가 렌더링 될 때 Effect Hook이 실행된다.</p>
<h3 id="hook을-쓸-때-주의할-점">Hook을 쓸 때 주의할 점</h3>
<ul>
<li>최상위에서만 Hook을 호출한다.</li>
<li>React 함수 내에서 Hook을 호출한다.</li>
</ul>
<h3 id="조건부-effect-발생dependency-array">조건부 effect 발생(Dependency array)</h3>
<hr>
<p><code>useEffect</code>의 두 번째 인자는 배열이다. 이 배열은 조건을 담고 있다. 여기서 조건은 boolean 형태의 표현식이 아닌, 어떤 값의 변경이 일어날 때를 의미한다. 따라서, 해당 배열엔 어떤 값의 목록이 들어간다. 이 배열을 특별히 종속성 배열이라고 부른다.</p>
<p><a href="https://oute9.csb.app/">이 예제를 열어보고</a>, 개발자 콘솔의 값을 확인해보자. 여기에는 다음과 같은 세 상태가 존재한다.</p>
<ul>
<li>명언 목록 (proverbs)</li>
<li>필터링할 문자열 (effect)</li>
<li>카운트 (count)</li>
</ul>
<p>이 예제는, <code>filter</code>가 변할 때에만, effect 함수가 실행된다. 개발자 콘솔을 통해 확인할 수 있다.</p>
<p>한편, 카운트를 올리는 버튼은 컴포넌트의 상태가 바뀌고 업데이트되지만, 아무리 버튼을 눌러도 effect함수는 실행되지 않는다. 왜냐하면, 종속성 배열에는 <code>filter</code>만 존재하고, <code>count</code>는 존재하지 않기 때문이다.</p>
<p>Q.</p>
<ul>
<li>카운트 버튼을 눌렀을 때에도 effect 함수를 실행시키려면 어떻게 해야 하나?</li>
</ul>
<h3 id="api-1">API</h3>
<blockquote>
<p><code>useEffect(함수,[종속성1, 종속성2, ...])</code></p>
</blockquote>
<p><code>useEffect</code>의 두 번째 인자는 종속성 배열이다. 배열 내의 종속성1, 또는 종속성2의 값이 변할 때, 첫 번째 인자의 함수가 실행된다. 배열 내의 어떤 값이 변할 때에만, (effect가 발생하는) 함수가 실행된다.</p>
<h3 id="단-한번만-실행되는-effect-함수">단 한번만 실행되는 Effect 함수</h3>
<hr>
<p>만일 종속성 목록에 아무런 종속성도 없다면 어떤 일이 발생할까? 달리 말해, 두 번째 배열을 빈 배열<code>[]</code>로 둘 경우에는 무슨 일이 발생할까? 두 번째 인자를 아예 안 넘기는 것과 어떻게 다를까?</p>
<blockquote>
<ol>
<li>빈 배열 넣기
<code>useEffect(함수,[])</code></li>
<li><strong>아무 것도 넣지 않기(기본 형태)</strong>
<code>useEffect(함수)</code></li>
</ol>
</blockquote>
<p>(2번) 기본 형태의 <code>useEffect</code>는 컴포넌트가 처음 생성되거나, props가 업데이트되거나, 상태(state)가 업데이트 될 때 effect 함수가 실행됨을 앞서 배웠다.</p>
<p>반면에 (1번) 빈 배열을 useEffect의 두 번째 인자로 사용하면, 이 때는 <strong>컴포넌트가 처음 생성될 때만</strong> effect 함수가 실행된다. 이것이 언제 필요할까? 대표적으로 처음 단 한번, 외부 API를 통해 리소스를 받아오고 더 이상 API 호출이 필요하지 않을 때에 사용할 수 있다.</p>
<h3 id="data-fetching-필터링-예제-다시-보기">Data Fetching: 필터링 예제 다시 보기</h3>
<hr>
<p>목록 내 필터링을 구현하기 위해서는 다음과 같은 두 가지 접근이 있을 수 있다.</p>
<ol>
<li>컴포넌트 내에서 필터링: 전체 목록 데이터를 불러오고, 목록을 검색어로 filter하는 방법</li>
<li>컴포넌트 외부에서 필터링: 컴포넌트 외부로 API 요청을 할 때, 필터링 한 결과를 받아오는 방법 (보통, 서버에 매번 검색어와 함께 요청하는 경우가 이에 해당한다.)</li>
</ol>
<h3 id="1-컴포넌트-내에서-필터링">1. 컴포넌트 내에서 필터링</h3>
<p>처음 단 한 번, 외부 API로부터 명언 목록을 받아오고, filter 함수를 이용한다.
!codesandbox[filter-by-client-vyzdc?fontsize=14&amp;hidenavigation=1&amp;theme=dark]</p>
<h3 id="2-컴포넌트-외부에서-필터링">2. 컴포넌트 외부에서 필터링</h3>
<p>검색어가 바뀔 때마다, 외부 API를 호출한다. (앞선 조건부 실행 콘텐츠에서 봤던 예제와 동일하다.)
!codesandbox[useeffect-2-oute9?fontsize=14&amp;hidenavigation=1&amp;theme=dark]</p>
<h3 id="두-방식의-차이점">두 방식의 차이점</h3>
<p>각각의 장단점은 무엇인가? 지금은 <code>storageUtil.js</code>를 이용해 외부 API를 직접 구현했지만(LocalStorage API를 이용), 이는 서버 요청으로 대체 할 수 있다. 만일 서버에서 수십만 개의 명언을 제공한다고 가정해보자. 다음의 표는 HTTP를 이용한 서버 요청을 가정할 때, 두 방식으 ㅣ차이점을 설명하고 있다.</p>
<table>
<thead>
<tr>
<th align="center"></th>
<th align="center">장점</th>
<th align="center">단점</th>
</tr>
</thead>
<tbody><tr>
<td align="center">컴포넌트 내부에서 처리</td>
<td align="center">HTTP 요청의 빈도를 줄일 수 있다.</td>
<td align="center">브라우저(클라이언트)의 메모리 상에 많은 데이터를 갖게 되므로, 클라이언트의 부담이 늘어난다.</td>
</tr>
<tr>
<td align="center">컴포넌트 외부에서 처리</td>
<td align="center">클라이언트가 필터링 구현을 생각하지 않아도 된다.</td>
<td align="center">빈번한 HTTP 요청이 일어나게 되며, 서버가 필터링을 처리하므로 서버가 부담을 가져간다.</td>
</tr>
</tbody></table>
<h2 id="ajax-요청을-보내자">AJAX 요청을 보내자!</h2>
<hr>
<p>임의로 구현한 <code>storageUtil.js</code>대신,fetch API를 써서, 서버에 요청한다면 코드는 어떻게 될까? 명언을 제공하는 API의 엔드포인트가 <code>http://서버주소/proverbs</code>라고 가정해보자.</p>
<pre><code class="language-jsx">useEffect(() =&gt;{
  fetch(`http://서버주소/proverbs?q=${filter}`)
  .then(resp =&gt; resp.json())
  .then(result =&gt;{
    setProverbs(result);
  });
}, [filter]);</code></pre>
<h2 id="ajax-요청이-매우-느릴-경우">AJAX 요청이 매우 느릴 경우?</h2>
<p>모든 네트워크 요청이 항상 즉각적인 응답을 가져다주는 것은 아니다. 외부 API접속이 느릴 경우를 고려하여, 로딩화면의 구현은 필수적이다.</p>
<p>[그림] loading indicator &amp; placeholder
<img src="https://miro.medium.com/max/882/1*8NJgObmgEVhNWVt3poeTaA.gif" alt="">
<img src="https://raw.githubusercontent.com/zalog/placeholder-loading/master/docs/imgs/placeholder-loading-demo-2.gif" alt=""></p>
<p>기본적으로, Loading indicator의 구현은 어떻게 처리할 수 있을까? 여기에도 <strong>상태 처리</strong>가 필요하다.</p>
<pre><code class="language-jsx">const [isLoading, setIsLoading] = useState(true);
//생략, LoadingIndicator 컴포넌트는 별도로 구현했음을 가정한다.
return {isLoading ? &lt;loadingIndicator /&gt; :&lt;div&gt;로딩 완료 화면&lt;/div&gt;}</code></pre>
<p>fetch 요청의 전후로 <code>setIsLoading</code>을 설정해 주어 보다 나은 UX를 구현할 수 있다.</p>
<pre><code class="language-jsx">usEffect (()=&gt;{
  setIsLoading(true);
  fetch(`http://서버주소/proverbs?q=${filter}`)
    .then(resp =&gt; resp.json())
    .then(result =&gt; {
    setProverbs(result);
      setIsLoading(false);
    });
},[filter]);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Client Ajax request [1]]]></title>
            <link>https://velog.io/@nada_1221/React-Client-Ajax-request</link>
            <guid>https://velog.io/@nada_1221/React-Client-Ajax-request</guid>
            <pubDate>Tue, 09 Aug 2022 13:34:57 GMT</pubDate>
            <description><![CDATA[<h2 id="react-데이터-흐름">React 데이터 흐름</h2>
<hr>
<p>리액트는 데이터가 부모 컴포넌트에서 자식 컴포넌트로 단방향(Top to Bottom)으로 흐른다. </p>
<p>만약, 자식 컴포넌트의 어떤 이벤트에 의해 부모 컴포넌트의 상태가 바뀐다면, 역방향으로 데이터가 흐르고 이는 리액트의 단방향 흐름 원칙에 위배되는 것인가?</p>
<p>리액트에서는 단방향 흐름의 원칙을 지키면서, 자식 컴포넌트에서 부모 컴포넌트로 데이터를 보내기 위한 방법(Bottom to Top)으로 상태 끌어올리기라는 방법을 제시한다.</p>
<p>그 방법은 부모 컴포넌트의 상태 변화함수를 자식 컴포넌트에 인자로 전달하고 자식 컴포넌트에서 그 함수를 실행시켜 부모 컴포넌트의 상태를 변화시키는 것이다.</p>
<hr>
<p>Ex)
!codesandbox[simple-lifting-state-up-hooks-forked-tcl83?fontsize=14&amp;hidenavigation=1&amp;theme=dark]</p>
<ul>
<li><code>ChildComponent onBtnClick = {handleChange}</code>
부모 컴포넌트에서 자식 컴포넌트로 props를 전달하는데, 키는 onBtnClick, 값은 상태변화 함수이다. (단방향 데이터 흐름 충족)</li>
<li><code>function ChildComponent({onBtnClick}){}</code>
자식 컴포넌트의 인자로 상태변화 함수가 전달되었다.</li>
<li><code>return &lt;button onCLick = {handleClick}&gt;값 변경&lt;/button&gt;</code>
버튼이 클릭됐을 때 handleClick 함수가 동작하는데, 해당 함수는 인자로 전달받은 함수를 작동시키는 함수이다.</li>
</ul>
<p>따라서, 정리해보자면, 자식 컴포넌트에서 버튼을 클릭하면 이벤트 핸들러(handleClick)가 실행되는데, 그 핸들러는 자식 컴포넌트가 인자로 입력받은 함수 (콜백함수, 부모 컴포넌트의 상태변화 함수)를 동작시키고, 그 결과 부모 컴포넌트의 상태가 업데이트 된다.</p>
<hr>
<p>Ex 2)
!codesandbox[twittler-react-lifting-state-up-hooks-forked-iq58g?fontsize=14&amp;hidenavigation=1&amp;theme=dark]</p>
<ul>
<li><code>데이터 흐름</code>
상위 컴포넌트(Twittler)는 상태(tweets)를 갖고, 하위 컴포넌트(NewTweetForm)에서 글을 작성하고 새글쓰기 버튼을 클릭하면 상위 컴포넌트의 상태인 tweets가 업데이트 된다.</li>
<li><code>&lt;NewTweetForm onButtonClick = {addNewTweet} /&gt;</code>
단방향 데이터 흐름의 원칙을 지키고 상태를 끌어올리기 위해 상태변경함수가 하위 컴포넌트에 props로 전달된다.</li>
<li><code>const addNewTweet = (newTweet) =&gt; {strTweets([...tweets,newTweet])}</code>
addNewTweet 함수는 인자로 새로 생성된 트윗을 입력받아 spread syntax를 사용해 하나의 배열에 기존 트윗들과 함께 담아준다.</li>
</ul>
<hr>
<p>Bareminimum Test 복습</p>
<p><strong>Main.js</strong></p>
<pre><code class="language-jsx">
/* ...생략 */

export default function Main() {
  // 항공편 검색 조건을 담고 있는 상태
  const [condition, setCondition] = useState({
    departure: &#39;ICN&#39;,
  });
  const [flightList, setFlightList] = useState(json);

  // 주어진 검색 키워드에 따라 condition 상태를 변경시켜주는 함수
  const search = ({ departure, destination }) =&gt; {
    if (
      condition.departure !== departure ||
      condition.destination !== destination
    ) {
      console.log(&#39;condition 상태를 변경시킵니다&#39;);

      // TODO: search 함수가 전달 받아온 &#39;항공편 검색 조건&#39; 인자를 condition 상태에 적절하게 담아보세요.
      setCondition({departure,destination})
        //1. 상태변경 함수인 search에 condition 변경 함수인 setCondition 을 이용해 값을 바꿔준다.
    }
  };

/* ...생략 */

        &lt;main&gt;
        &lt;h1&gt;
          여행가고 싶을 땐, States Airline
        &lt;/h1&gt;
        &lt;Search onSearch={search}/&gt; 
// 2 Search 컴포넌트에는 상태 변경 함수 `search`가 `onSearch` props로 전달되어야 한다
        &lt;div className=&quot;table&quot;&gt;
          &lt;div className=&quot;row-header&quot;&gt;

/* ...생략 */</code></pre>
<p><strong>Search.js</strong></p>
<pre><code class="language-jsx">
/* ...생략 */

function Search({onSearch}) { 
// 3 onSearch props를 받아온다
  const [textDestination, setTextDestination] = useState(&#39;&#39;)

/* ...생략 */

  const handleSearchClick = () =&gt; {
    console.log(&#39;검색 버튼을 누르거나, 엔터를 치면 search 함수가 실행됩니다&#39;)

  // 4 상태 변경 함수 `search`는 Search 컴포넌트의 `검색` 버튼 클릭 시 실행되어야 합니다 
  // 검색 버튼을 클릭했을때 onChange는 handleChange값이 변경된다고 아래에 적혀있다
  // handleChange는 도착지 값이 변경되는 것을 알려주고 있고 
  // 출발지는 고정하고 도착지의 값을 textDestination으로 변경해주면 된다 
  // 서치 함수에서 setCondition({departure, destination}) 객체형태로 값을 받아오는걸 알 수 있으니
  // 똑같이 값을 넣어줘야 한다
    onSearch({departure : &quot;ICN&quot;, destination : textDestination})
  }</code></pre>
]]></description>
        </item>
    </channel>
</rss>