<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jeff_gan.log</title>
        <link>https://velog.io/</link>
        <description>Fast is better than good</description>
        <lastBuildDate>Tue, 30 Nov 2021 06:22:08 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jeff_gan.log</title>
            <url>https://images.velog.io/images/jeff_gan/profile/1786ebcd-0599-4558-9e57-0a020676c71f/썬글라스.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jeff_gan.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jeff_gan" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Cookie]]></title>
            <link>https://velog.io/@jeff_gan/Cookie</link>
            <guid>https://velog.io/@jeff_gan/Cookie</guid>
            <pubDate>Tue, 30 Nov 2021 06:22:08 GMT</pubDate>
            <description><![CDATA[<h1 id="cookie">Cookie</h1>
<h2 id="what-is-cookie">What is Cookie</h2>
<p>쿠키는 브라우저에 저장되는 작은 크기의 문자열로, <a href="https://datatracker.ietf.org/doc/html/rfc6265">HTTP 프로토콜의 일부입니다</a></p>
<p>쿠키는 주로 웹서버에 의해 만들어집니다. 서버가 HTTP 응답 헤더의 <code>Set-Cookie</code>에 내용을 넣어 전달하면, 브라우저는 이 내용을 자체적으로 브라우저에 저장합니다 (쿠키).</p>
<p>브라우저는 사용자가 쿠키를 생성하도록 한 동일 서버에 접속할 때마다 쿠키의 내용을 <code>Cookie</code> 요청 헤더에 넣어서 함께 전달합니다</p>
<p>쿠키는 클라이언트 식별과 같은 인증에 많이 사용됩니다.</p>
<ul>
<li>사용자가 로그인하면 서버는 HTTP 응답 헤더의 <code>Set-Cookie</code>에 담긴 “세션 식별자(session identifier)” 정보를 사용해 쿠키를 설정합니다.</li>
<li>사용자가 동일 도메인에 접속하려고 하면 브라우저는 HTTP Cookie 헤더에 인증 정보가 담긴 고윳값(세션 식별자)을 함께 실어 서버에 요청을 보냅니다.</li>
<li>서버는 브라우저가 보낸 요청 헤더의 세션 식별자를 읽어 사용자를 식별합니다.</li>
</ul>
<h2 id="documentcookie로-살펴보기">document.cookie로 살펴보기</h2>
<p><strong>document.cookie로 확인한 daum.net의 쿠키</strong></p>
<pre><code class="language-javascript">&gt; document.cookie
&#39;webid=d3fdabd053b311ea9f33000af759d210; webid_ts=1582257785973; dtck_first=20210511; SLEVEL=1; HM_CU=5DrWr6DnRlF; __T_=1; chanelApiType=default; webid_sync=1638236159761&#39;</code></pre>
<p>document.cookie 프로퍼티를 이용하면 자바스크립트로 쿠키를 확인할 수 있습니다.
name=value 쌍으로 구성되고, 각 쌍은 <code>;</code>로 구분되는걸 알 수 있습니다.
httpOnly로 설정되지 않은 쿠키들을 확인할 수 있습니다</p>
<p><strong>document.cookie로 쿠키 쓰기</strong></p>
<pre><code class="language-javascript">&gt; document.cookie
&#39;webid=d3fdabd053b311ea9f33000af759d210; webid_ts=1582257785973; dtck_first=20210511; SLEVEL=1; HM_CU=5DrWr6DnRlF; __T_=1; chanelApiType=default; webid_sync=1638245518265&#39;

&gt; document.cookie = &#39;user=John&#39;;
&#39;webid=d3fdabd053b311ea9f33000af759d210; webid_ts=1582257785973; dtck_first=20210511; SLEVEL=1; HM_CU=5DrWr6DnRlF; __T_=1; chanelApiType=default; webid_sync=1638245518265; user=John&#39;

&gt;
// 특수 값(공백)은 인코딩 처리해 줘야 합니다.
let name = &quot;my name&quot;;
let value = &quot;John Smith&quot;

// 인코딩 처리를 해, 쿠키를 my%20name=John%20Smith 로 변경하였습니다.
document.cookie = encodeURIComponent(name) + &#39;=&#39; + encodeURIComponent(value);</code></pre>
<p>document.cookie에 값을 쓸 때는 data property가 아닌 accessor property 입니다.
document.cookie= 연산은 모든 쿠키를 덮어쓰지 않고, 명시된 쿠키인 user의 값만 갱신합니다.</p>
<h2 id="cookie의-한계">cookie의 한계</h2>
<p><code>encodeURIComponent</code> 로 인코딩 이후 <code>name=value</code> 쌍은 4KB를 넘을 수 없습니다.
도메인 하나당 저장할 수 있는 쿠키의 개수는 20여 개 정도로 한정되어 있습니다.</p>
<h2 id="개발자도구에서-살펴보기">개발자도구에서 살펴보기</h2>
<p><strong>개발자도구에서 확인한 daum.net의 쿠키</strong>
<img src="https://images.velog.io/images/jeff_gan/post/a8ce4f8a-0cb9-43cb-b352-4949a465129c/image.png" alt="">
<strong>쿠키 옵션</strong>
옵션은 <code>key=value</code> 뒤에 나열하고 <code>;</code>로 구분합니다.</p>
<pre><code class="language-javascript">document.cookie = &quot;user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT&quot;</code></pre>
<p>Domain</p>
<ul>
<li><p>쿠키에 접근 가능한 도메인 지정</p>
</li>
<li><p><code>domain</code>옵션에 아무 값이 없는 경우, 쿠키를 설정한 도메인에서만 쿠키에 접근할 수 있습니다 (subdomain도 불가)</p>
</li>
<li><p><code>domain</code>옵션에 루트 도메인을 명시적으로 설정하는 경우 서브 도메인에서도 쿠키에 접근할 수 있습니다</p>
<pre><code class="language-javascript">// site.com에서
// 서브 도메인(*.site.com) 어디서든 쿠키에 접속하게 설정할 수 있습니다.
document.cookie = &quot;user=John; domain=site.com&quot;

// 이렇게 설정하면

// forum.site.com와 같은 서브도메인에서도 쿠키 정보를 얻을 수 있습니다.
alert(document.cookie); // user=John 쿠키를 확인할 수 있습니다.</code></pre>
<ul>
<li>구식 브라우저 지원을 위해서는 <code>domain=.site.com</code> 식으로 작성합니다</li>
</ul>
</li>
</ul>
<p>Path</p>
<ul>
<li>설정한 경로의 하위 경로에 있는 페이지만 쿠키에 접근 가능합니다. (보통 루트로 설정)</li>
</ul>
<p>Expires / Max-Age</p>
<ul>
<li><p><code>Expires</code>나 <code>Max-Age</code>가 지정되어 있지 않으면 브라우저가 닫힐 때 쿠키도 함께 삭제됩니다(세션 쿠키)</p>
</li>
<li><p>Max-Age와 Expires 모두 있는 경우 Max-Age가 적용됩니다(Expires 무시)</p>
</li>
<li><p>Expires(유효 일자)</p>
<ul>
<li>브라우저는 설정된 유효 일자까지 쿠키를 유지하다가, 해당 일자가 도달하면 쿠키를 자동으로 삭제합니다</li>
<li>GMT 포맷으로 설정해야 합니다. <code>date.toUTCString</code> 사용<pre><code class="language-javascript">// 지금으로부터 하루 후
let date = new Date(Date.now() + 86400e3);
date = date.toUTCString();
document.cookie = &quot;user=John; expires=&quot; + date;</code></pre>
</li>
</ul>
</li>
<li><p>Max-Age(만료 기간)</p>
<ul>
<li>현재부터 설정하고자 하는 만료일시까지의 시간을 초로 환산한 값을 설정합니다</li>
<li>0이나 음수값을 설정하면 쿠키값이 바로 삭제됩니다.<pre><code class="language-javascript">// 1시간 뒤에 쿠키가 삭제됩니다.
document.cookie = &quot;user=John; max-age=3600&quot;;
</code></pre>
</li>
</ul>
<p>// 만료 기간을 0으로 지정하여 쿠키를 바로 삭제함
document.cookie = &quot;user=John; max-age=0&quot;;</p>
<pre><code></code></pre></li>
</ul>
<p>HttpOnly</p>
<ul>
<li>웹서버에서 <code>Set-Cookie</code> 헤더를 이용해 쿠키를 설정할 때 지정할 수 있습니다.</li>
<li>해당 옵션 설정 시, 자바스크립트 같은 클라이언트 측 스크립트가 쿠키를 사용할 수 없게 합니다(document.cookie 로 못봄)</li>
<li>XSS(Cross-Site Scripting) 같은 공격을 방어할 수 있습니다.</li>
</ul>
<p>Secure</p>
<ul>
<li>이 옵션 설정 시 HTTPS로 통신하는 경우에만 쿠키가 전송됩니다.</li>
<li>쿠키는 기본적으로 도메인만 확인하고 프로토콜을 따지지 않습니다.</li>
<li>secure 옵션이 설정된 경우 프로토콜도 확인합니다.<pre><code class="language-javascript">// (https:// 로 통신하고 있다고 가정 중)
// 설정한 쿠키는 HTTPS 통신시에만 접근할 수 있음
document.cookie = &quot;user=John; secure&quot;;</code></pre>
</li>
</ul>
<p>SameSite</p>
<ul>
<li>XSRF(Cross-Site Request Forgery) 공격을 막기 위해 만들어진 옵션입니다</li>
<li>XSRF : 크로스 사이트 요청 위조<ul>
<li><img src="https://images.velog.io/images/jeff_gan/post/f416294c-44ce-4ec8-9860-4386b55ba9f9/image.png" alt=""></li>
<li>실제 은행에서는 <code>back.com</code>을 사용하는 모든 폼에 <code>XSRF 보호 토큰</code>과 같은 특수 필드를 넣어서 막지만, 구현에 시간이 걸립니다</li>
</ul>
</li>
<li>SameSite 옵션<ul>
<li><code>samesite=strict</code> (samesite 옵션만 써줘도 동일)<ul>
<li>제 3의 도메인(사이트 외부)에서 요청이 이뤄질 때 쿠키를 전송하지 않습니다</li>
</ul>
</li>
<li><code>samesite=lax</code><ul>
<li><code>strict</code>와 마찬가지로 <code>lax</code>도 사이트 외부에서 요청을 보낼 때 브라우저가 쿠키를 보내는 걸 막아줍니다.</li>
<li>예외사항 (다음 두 조건을 동시에 만족하는 경우)인 경우는 쿠키를 전송합니다.<ul>
<li>&#39;안전한&#39; HTTP 메서드인 경우(GET방식)</li>
<li>작업이 최상위 레벨 탐색에서 이루어질 때 (브라우저 주소창에서 URL을 변경하는 경우)</li>
</ul>
</li>
<li>조건을 충족하지 못하는 경우<ul>
<li>AJAX는 탐색 행위가 아니므로 충족하지 못합니다.</li>
<li>iframe안에서 탐색은 최상위 레벨이 아니므로 충족하지 못합니다.</li>
</ul>
</li>
<li>조건을 충족하는 경우<ul>
<li>특정 URL로 이동 : <code>samesite=lax</code>옵션이 설정되어 있으면 쿠키가 서버로 전송됩니다</li>
<li>노트에 저장된 링크를 여는 것도 특정 URL로 이동하는 행위이므로 충족합니다</li>
</ul>
</li>
</ul>
</li>
<li><a href="https://caniuse.com/?search=samesite">다만 <code>samesite</code>는 오래된 브라우저에서는 지원하지 않습니다(2017년 전)</a></li>
</ul>
</li>
</ul>
<p><a href="https://developer.chrome.com/blog/first-party-sets-sameparty/#how-do-first-party-sets-affect-cookies">SameParty</a></p>
<h2 id="추가사항">추가사항</h2>
<p>브라우저에 따라 서드 파티 쿠키를 허용하지 않을 수 있습니다. Safari는 기본적으로 서드 파티 쿠키를 금지합니다.
사용자가 EU 국가 거주자인 경우 GDPR을 준수해야 합니다. 따라서, 사용자 추적 시 반드시 동의를 얻어야 합니다.</p>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://ko.javascript.info/cookie">https://ko.javascript.info/cookie</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies">https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[CORS]]></title>
            <link>https://velog.io/@jeff_gan/CORS</link>
            <guid>https://velog.io/@jeff_gan/CORS</guid>
            <pubDate>Mon, 29 Nov 2021 10:15:51 GMT</pubDate>
            <description><![CDATA[<h1 id="cors-정리">CORS 정리</h1>
<h2 id="배경">배경</h2>
<h3 id="origin">Origin</h3>
<p>protocol + host + port 가 동일한 url의 경우 같은 origin(출처)라고 합니다</p>
<pre><code>[다른 출처 #1, 프로토콜이 다름]
https://naver.com
http://naver.com

[다른 출처 #2, 호스트가 다름(실제로는 동일하지만 브라우저에서 string 비교할 때 다르게 인식)]
http://localhost:8081
http://127.0.0.1:8081

[다른 출처 #3, port가 다름]
localhost:8080
localhost:8081


[같은 출처, path만 다름]
http://naver.com
http://naver.com/login</code></pre><h3 id="sop-same-origin-policy">SOP (Same Origin Policy)</h3>
<p>동일 출처의 리소스로만 상호작용을 제한하는 브라우저의 보안 정책입니다.
악의적일 수 있는 문서를 분리함으로 공격 경로를 줄여줍니다.</p>
<pre><code>example
1. 페이스북에 로그인 후 인증토큰을 받아옵니다
2. 메일에서 악의적인 페이지(hack.com)에 접속하게 되었습니다
3. 악의적인 페이지에서 인증토큰을 이용해 페이스북에 포스트를 올리는 요청을 보냅니다
4. 이때 SOP 정책이 없는 경우 이슈가 발생합니다</code></pre><blockquote>
<p>IE의 경우는 SOP에 몇가지 예외사항이 있습니다.</p>
</blockquote>
<ol>
<li>양쪽 도메인 모두 신뢰할 수 있는 사이트(높은 단계의 보안 수준)인 경우 SOP를 적용하지 않습니다</li>
<li>SOP 검사에 포트를 포함하지 않습니다</li>
</ol>
<h3 id="cors-cross-origin-resource-sharing">CORS (Cross Origin Resource Sharing)</h3>
<p>페이지를 만들다 보면 다른 출처의 자원이 필요한 경우가 생깁니다. 하지만 브라우저에서는 SOP로 인해 다른 출처의 자원과 상호작용이 제한됩니다.
CORS는 HTTP 헤더를 사용해 한 출처에서 실행중인 웹 어플리케이션이 다른 출처의 자원에 접근할 수 있는 권한을 부여하도록 브라우저에게 알려주는 mechanism 입니다.</p>
<blockquote>
<p>서버 데이터에 부수 효과(side effect)를 일으킬 수 있는 HTTP 요청 메서드(GET을 제외한 HTTP 메서드)에 대해, CORS 명세는 <strong>브라우저</strong>가 요청을 OPTIONS 메서드로 &quot;프리플라이트&quot;(preflight, 사전 전달)하여 지원하는 메서드를 요청하고, 서버의 &quot;허가&quot;가 떨어지면 실제 요청을 보내도록 요구하고 있습니다.</p>
</blockquote>
<h2 id="접근-제어-시나리오-예제">접근 제어 시나리오 예제</h2>
<h3 id="단순-요청-simple-request">단순 요청 (simple request)</h3>
<p>simple request의 경우는 CORS preflight를 트리거하지 않습니다(ex. 별도의 side effect가 없는 get 요청).
<strong>simple request는 다음 조건을 모두 충족해야 합니다</strong></p>
<ul>
<li>Method<ul>
<li>GET, POST, HEAD 중 하나</li>
</ul>
</li>
<li>아래의 Header만 설정됨<ul>
<li><a href="https://fetch.spec.whatwg.org/#forbidden-header-name">user agent가 자동으로 설정한 헤더</a>(Connection, User-Agent, ...)</li>
<li>Accept (클라가 이해가능한 컨텐츠 타입 나열)</li>
<li>Accept-Language (클라가 이해, 지역 설정 중 선호되는 언어)</li>
<li>Content-Language (청중을 위한 언어)</li>
<li>Content-Type<ul>
<li>application/x-www-form-urlencoded</li>
<li>multipart/form-data</li>
<li>text/plain</li>
</ul>
</li>
<li><em>실제 서비스에서 위 조건을 만족하기는 어렵습니다 (ex. Authorization 헤더 등 사용)</em></li>
</ul>
</li>
</ul>
<p><img src="https://images.velog.io/images/jeff_gan/post/912dfeb9-6d25-4a93-b5ca-a507104cb04a/image.png" alt=""></p>
<p>Simple Request 헤더</p>
<pre><code>GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example</code></pre><ul>
<li>CORS 요청을 보내는 경우 브라우저는 항상 <code>Origin</code> 헤더를 request에 추가합니다</li>
<li>Origin 헤더엔 요청이 이뤄지는 페이지 경로(/page)가 아닌 오리진(도메인·프로토콜·포트) 정보가 담기게 됩니다.</li>
</ul>
<p>Simple Response 헤더</p>
<pre><code>HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[…XML Data…]</code></pre><ul>
<li>서버는 요청 헤더에 있는 Origin를 검사하고, 요청을 받아들이기로 동의한 상태라면 특별한 헤더 Access-Control-Allow-Origin를 응답에 추가합니다</li>
<li>크로스 오리진 요청이 이뤄진 경우, 자바스크립트는 기본적으로 ‘안전한’ 응답 헤더로 분류되는 헤더에만 접속할 수 있습니다.</li>
<li>안전한 응답 헤더 리스트<ul>
<li><code>Cache-Control</code>, <code>Content-Language</code>, <code>Content-Type</code>, <code>Expires</code>, <code>Last-Modified</code>, <code>Pragma</code></li>
<li>이 외의 응답 헤더에 접근하면 에러가 발생합니다.</li>
<li>자바스크립트를 사용해 안전하지 않은 응답 헤더에 접근하려면 서버에서 <code>Access-Control-Expose-Headers</code>라는 헤더를 보내줘야만 합니다</li>
</ul>
</li>
</ul>
<h3 id="프리플라이트-요청-preflight-request">프리플라이트 요청 (preflight request)</h3>
<p>CORS가 허용되는지 먼저 preflight 요청을 통해 체크합니다
<img src="https://images.velog.io/images/jeff_gan/post/7991751c-f56b-4c16-90e0-4e71f773da6f/image.png" alt=""></p>
<ul>
<li>CORS 요청을 보내는 경우 브라우저는 항상 <code>Origin</code> 헤더를 request에 추가합니다</li>
<li></li>
</ul>
<h3 id="인증정보를-포함한-요청-credentialed-requests">인증정보를 포함한 요청 (credentialed requests)</h3>
<p>자바스크립트로 크로스 오리진 요청을 보내는 경우, 기본적으로 쿠키나 HTTP 인증 같은 자격 증명(credential)이 함께 전송되지 않습니다.
서버에서 이를 허용하고 싶으면, 자격증명이 달린 헤더를 명시적으로 허용하겠다는 세팅이 서버에 필요합니다.
자격증명을 함께 전송하는 방법</p>
<ul>
<li>fetch의 경우 <code>credentials: include</code></li>
<li>axios의 경우 <code>withCredentials: true,</code></li>
</ul>
<p>자격 증명 정보가 담긴 요청을 서버에서 받아들이기로 동의했다면 서버는 응답에 Access-Control-Allow-Origin 헤더와 함께 Access-Control-Allow-Credentials: true 헤더를 추가해서 보냅니다.
자격 증명이 함께 전송되는 요청을 보낼 땐 Access-Control-Allow-Origin에 *을 쓸 수 없습니다.</p>
<h2 id="cors-해결-방법">CORS 해결 방법</h2>
<h3 id="프론트-프록시-서버-설정">프론트 프록시 서버 설정</h3>
<ul>
<li>nginx 서버 배포해서 사용</li>
<li>웹팩 devServer 사용시 webpack proxy 사용</li>
<li>다른사람이 만든 프록시 서버 이용(<a href="https://cors-anywhere.herokuapp.com">https://cors-anywhere.herokuapp.com</a>)</li>
</ul>
<h3 id="서버-응답-시-직접-헤더에-설정">서버 응답 시 직접 헤더에 설정</h3>
<ul>
<li>서버분들에게 요청</li>
<li>springboot에서 @CrossOrigin 설정 등 ,,</li>
</ul>
<h2 id="참고">참고</h2>
<p><a href="https://ko.javascript.info/fetch-crossorigin">https://ko.javascript.info/fetch-crossorigin</a>
<a href="https://ui.toast.com/weekly-pick/ko_2021110">https://ui.toast.com/weekly-pick/ko_2021110</a>
<a href="https://developer.mozilla.org/ko/docs/Web/HTTP/CORS">https://developer.mozilla.org/ko/docs/Web/HTTP/CORS</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[접근성 QA 회고]]></title>
            <link>https://velog.io/@jeff_gan/%EC%A0%91%EA%B7%BC%EC%84%B1-QA-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@jeff_gan/%EC%A0%91%EA%B7%BC%EC%84%B1-QA-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Thu, 25 Nov 2021 14:20:29 GMT</pubDate>
            <description><![CDATA[<h1 id="웹-접근성web-accessibility">웹 접근성(Web Accessibility)</h1>
<p>웹 사이트에서 제공하는 정보를 차별 및 제한 없이 동등하게 이용할 수 있도록 보장하는 것</p>
<ul>
<li>장애인 및 고령자 등을 포함한 모든 사람</li>
<li>다양한 플랫폼 및 장치, 웹 브라우저 등의 모든 환경</li>
</ul>
<h2 id="접근성-qa-이슈-종류">접근성 QA 이슈 종류</h2>
<p>이번 프로젝트 접근성 QA 종류는 다음과 같이 분류할 수 있다</p>
<ol>
<li>초점 표시 안됨 or 표시 위치 부적절</li>
<li>대체 텍스트, 음성 출력, 알림 미흡</li>
</ol>
<h3 id="1-초점-표시-안됨-or-표시-위치-부적절">1. 초점 표시 안됨 or 표시 위치 부적절</h3>
<ul>
<li>기존 프로젝트에서는 outline:none이 설정되어 있어 focus되었을 때 초점이 시각적으로 표현되지 않음<ul>
<li>outline:focus-visible 가상클래스를 사용해 탭키로 초점 접근시 시각적으로 표현</li>
</ul>
</li>
<li>팝업 활성화 시 첫 초점이 안내문구가 아닌 &#39;확인 버튼&#39;에 접근되어 시각장애인 사용자가 메시지 인식이 어려움<ul>
<li>팝업 활성화 시, 초점이 팝업의 첫 요소(안내문구)로 이동되도록 제어(tabindex, useEffect 등 사용)</li>
</ul>
</li>
</ul>
<h3 id="2-대체-텍스트-음성-출력-알림-미흡">2. 대체 텍스트, 음성 출력, 알림 미흡</h3>
<p>대체 텍스트는 <code>.screen_out</code> 클래스를 사용해서 작성</p>
<pre><code class="language-css">.screen_out {
  overflow: hidden;
  position: absolute;
  width: 0;
  height: 0;
  line-height: 0;
  text-indent: -9999px;
}</code></pre>
<p><strong>WAI-ARIA</strong></p>
<ul>
<li>aria : Accessible Rich Internet Application</li>
<li>WAI : Web Accessibility Initiative의 약자로 W3C에서 웹 접근성을 담당하는 조직</li>
<li>WAI-ARIA : ARIA를 위한 접근성 권고안으로 마크업에 역할(role), 속성(property), 상태(state) 정보를 추가하여 스크린리더 및 보조 기기 등에서 접근성 및 상호 운용성을 향상시키고 보다 나은 사용자 경험(User Experience)을 제공</li>
</ul>
<p><strong>WAI-ARIA 3가지 기능</strong>
역할(role)</p>
<ul>
<li>특정 element에 역할을 부여하여 사용자에게 정보 제공. 동적으로 변경할 수 없음<pre><code class="language-html">&lt;!-- 접혀진 상태 --&gt;
&lt;div role=&quot;button&quot; ...&gt;
 &lt;span class=&quot;screen_out&quot;&gt;다운받기&lt;/span&gt;
. . .
&lt;/div&gt;</code></pre>
</li>
<li>QA중 사용된 role<ul>
<li>role=button : 초점이 하나로 제공됨</li>
<li>role=log : 스크린리더가 자동으로 음성 출력</li>
</ul>
</li>
</ul>
<p>속성(property)</p>
<ul>
<li>element가 기본적으로 갖고 있는 특징이나 상황</li>
<li>&#39;aria-*&#39; 접두어를 가진다</li>
<li>어플리케이션 실행중에 바뀌는 경우는 드물다<pre><code class="language-html">&lt;p class=&quot;info_tip&quot; aria-live=&quot;assertive&quot;&gt;
 &lt;span&gt;TIP&lt;/span&gt;
  카카오메일이 있다면 메일 아이디만 입력해 보세요.
&lt;/p&gt;</code></pre>
</li>
<li>QA중 사용된 property<ul>
<li>aria-live : 실시간의 내용을 갱신하는 영역. assertive를 값으로 사용하면 보조기기 작업을 중단하고 갱신 내용을 즉시 사용자에게 전달</li>
<li>aria-label : 현재 element의 레이블 정의</li>
<li>aria-describedby : id를 참조해서 설명을 컨트롤과 직접 연관시키도록 한다</li>
</ul>
</li>
</ul>
<p>상태(state)</p>
<ul>
<li>element가 기본적으로 갖고 있는 특징이나 상황</li>
<li>&#39;aria-*&#39; 접두어를 가진다</li>
<li>어플리케이션 실행중에 자주 바뀐다<pre><code class="language-html">&lt;!--접혀진 상태이며 새로운 메시지가 있을 때--&gt;
&lt;button aria-expanded=&quot;false&quot;&gt;
&lt;span class=&quot;screen_out&quot;&gt;새 메시지&lt;/span&gt;&lt;span class=&quot;screen_out&quot;&gt;톡으로 상담&lt;/span&gt;
&lt;button&gt;
</code></pre>
</li>
</ul>
<!--펼쳐진 상태-->
<button aria-expanded="true">
  <span class="screen_out">톡으로 상담</span>
<button>
```
- QA 중 사용된 state
  - aria-expanded : 접힘 / 펼침 상태
  - aria-hidden : 스크린리더 가상 커서에서 탐색되지 않음
  - aria-disabled : 활성 / 비활성 상태


]]></description>
        </item>
        <item>
            <title><![CDATA[How to deal with complexity]]></title>
            <link>https://velog.io/@jeff_gan/How-to-deal-with-complexity</link>
            <guid>https://velog.io/@jeff_gan/How-to-deal-with-complexity</guid>
            <pubDate>Sun, 12 Sep 2021 06:41:29 GMT</pubDate>
            <description><![CDATA[<p>공학에서 복잡한 것(Complexity)들을 다루는 방법은 추상화(Abstraction)이다.</p>
<h2 id="회로-예시">회로 예시</h2>
<p>AND, OR, NOT Gate의 상위, 하위 추상화 레벨을 생각해보자.</p>
<pre><code>- (C, C++, Java, ...)High Level Language
- Machine instruction level
- (반가산기, 전가산기, ..) Funtional level 
- (AND, OR, NOT) Gate level
- Transistor level
- Semi-Conductor Physics level
- 원자물리학(Atomic Physics) level</code></pre><p>우리가 Java같은 HLL를 사용할 수 있는 것은, 그 아래 수많은 추상화 레벨들의 연구의 지원이 있기 때문이다.</p>
<h2 id="interface">Interface</h2>
<p>우리가 컴퓨터를 사용할 때, 컴퓨터의 구현(implementation)할 줄 몰라도 컴퓨터의 Interface만 알면 사용할 수 있다. Interface란 일종의 product의 사용설명서이다.</p>
<h2 id="computer-science의-three-major-interfaces">Computer Science의 Three Major Interfaces</h2>
<img src="https://images.velog.io/images/jeff_gan/post/f030b5fa-da3e-48fd-ab14-1501232687f5/image.png" width="400" >

<h3 id="1-isainstruction-set-architecture">1. ISA(Instruction Set Architecture)</h3>
<p>Hardware에서 Software에게 제공하는 Interface.</p>
<h3 id="2-hllhigh-level-language">2. HLL(High Level Language)</h3>
<p>각 언어(C, Java, ...) 컴파일러가 개발자들에게 제공하는 Interface</p>
<h3 id="3-apiapplication-programming-interface">3. API(Application Programming Interface)</h3>
<p>OS(Kernel)가 Machine을 사용할 수 있는 API를 제공한다. 유틸리티 프로그램을 제작시 위 API를 통해 Machine의 CPU, Memory, I/O를 사용할 수 있다.
<img src="https://images.velog.io/images/jeff_gan/post/59dc00dd-8cc4-40db-937c-8c350c86fc58/image.png" width="400" ></p>
<h2 id="실전---프로그램-개발에서의-abstraction">실전 - 프로그램 개발에서의 abstraction</h2>
<ul>
<li>React의 Component</li>
<li>npm module</li>
<li>정확한 변수, 함수 네이밍 (내부 구현을 들어보지 않아도 동작을 파악할 수 있는)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[개발자는 비즈니스 문제를 해결하는 사람]]></title>
            <link>https://velog.io/@jeff_gan/%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94-%EB%B9%84%EC%A6%88%EB%8B%88%EC%8A%A4-%EB%AC%B8%EC%A0%9C%EB%A5%BC-%ED%95%B4%EA%B2%B0%ED%95%98%EB%8A%94-%EC%82%AC%EB%9E%8C</link>
            <guid>https://velog.io/@jeff_gan/%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94-%EB%B9%84%EC%A6%88%EB%8B%88%EC%8A%A4-%EB%AC%B8%EC%A0%9C%EB%A5%BC-%ED%95%B4%EA%B2%B0%ED%95%98%EB%8A%94-%EC%82%AC%EB%9E%8C</guid>
            <pubDate>Mon, 06 Sep 2021 14:36:38 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>feat. 배달의민족 CEO 인터뷰 영상
<em>1. 풀고자 하는 문제를 정확히 이해하는 것에 대부분의 시간 투자가 필요.</em>
<em>2. 때로는 문제를 해결하는 가장 좋은 방법은 정책을 바꾸고 코딩을 하지 않는 것.</em>
<em>3. 코드를 만줄 짠것보다, 내가 짠 코드로 만든 비즈니스 가치가 중요.</em></p>
</blockquote>
<p>다른 좋은 이야기도 많았지만, 가장 기억에 남는 3가지를 꼽아봤다.</p>
<p>시간이 지나면서 일을 잘하기 위해서 중요하다고 생각한 것들이 바뀌는 걸 느끼고 있다.
입사 초반에는 최근 유행하는 프레임워크, 아키텍처 등 소위 &#39;도구&#39;에 집중을 했다(react, redux, redux-saga, typescript 등등,,).</p>
<p>개발자가 단순히 코드를 작성하는 사람이 아닌 문제를 해결한다는 사람이다. 문제를 해결하기 위해선 자연스럽게 <code>문제를 정확히 이해하는 것</code>이 우선되어야 한다. 그리고 문제해결을 위해 <code>기획, 디자이너와 커뮤니케이션</code>을 진행하면서 현재 상황에 맞는 방향을 함께 찾는다. 여기서 개발자는 문제해결 방법을 찾으면서 동시에 <code>프로젝트 아키텍처</code>를 잘 사수해야 한다(<em>아키텍처를 위해 투쟁하는 것은 개발자의 책무 중 하나이다</em>). 
<br/><br/></p>
<p><strong>영상 리뷰와는 다소 방향이 틀릴 수 있지만, 최근 일을 잘하기 위해서 중요하다고 생각하는 것들에 대한 간단한 정리.</strong></p>
<h3 id="1-fast-is-better-than-good">1. Fast is better than good</h3>
<p>직역하자면 빠른 것이 좋은 것보다 낫다. 문제가 전혀 없는 완벽한 프로덕트는 없다. 시간이 흐르면서 어제는 맞았지만 오늘은 틀린 상황이 나올 수 있다. 주워진 자원, 환경 속에 맞는 프로덕트를 빠르게 만들어야 시장 반응에 맞춰가면서 개선할 수 있다.</p>
<h3 id="2-결국-중요한-것은-사람-마음가짐">2. 결국 중요한 것은 사람, 마음가짐</h3>
<p>진부한 내용이다. 어른들이 항상 이야기하는 마음가짐이다. 특히 스타트업에서는 구성원들이 같이 한 곳을 바라보면서 나가야 괴로운 <strong>데스벨리</strong>를 이겨낼 가능성이 높아진다. 스타트업을 선택할 때, 또는 인원을 뽑을 때 중요한 것은 기술스택, 복지가 아니라 방향, 목적, 마음가짐이라 생각한다. 본인도 현재는 스타트업이 아닌 일반 IT 회사에 근무중이지만, 추후 스타트업으로 이직을 할 경우 첫번째로 살펴볼 항목이다.</p>
<p>지금 중요하다고 생각하지만 또 1년 뒤에는 생각이 바뀔 수 있는 내용,, 여러 상황들을 겪으면서 생각이 정립되고 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[적절한 난이도의 중요성]]></title>
            <link>https://velog.io/@jeff_gan/%EC%A0%81%EC%A0%88%ED%95%9C-%EB%82%9C%EC%9D%B4%EB%8F%84%EC%9D%98-%EC%A4%91%EC%9A%94%EC%84%B1</link>
            <guid>https://velog.io/@jeff_gan/%EC%A0%81%EC%A0%88%ED%95%9C-%EB%82%9C%EC%9D%B4%EB%8F%84%EC%9D%98-%EC%A4%91%EC%9A%94%EC%84%B1</guid>
            <pubDate>Sun, 05 Sep 2021 15:00:20 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>feat. 함께자라기</p>
</blockquote>
<h2 id="입력가설---stephen-krashen">입력가설 - Stephen Krashen</h2>
<p>현재 언어 학습자의 언어 수준을 i라고 할 때, 딱 한 단계 높은 i+1 수준의 입력이 주어질 때에만 언어 능력이 유의미하게 진전한다는 이론</p>
<h2 id="적절한-난이도를-위한-전략">적절한 난이도를 위한 전략</h2>
<p><img src="https://images.velog.io/images/jeff_gan/post/109fab0b-f878-4a28-89cf-6a7fcd804c4f/graph.png" alt=""></p>
<h4 id="지루함을-느끼는-경우">지루함을 느끼는 경우</h4>
<p>a1. 실력 낮추기 : 키보드로만 개발. 컴파일 주기 늘리기.
a2. 난이도 높이기 : 익숙한 작업을 새로운 언어로 진행. 업무기간 줄이기. 100rps시스템 -&gt; 1000rps 시스템. 테스트</p>
<h4 id="불안함을-느끼는-경우">불안함을 느끼는 경우</h4>
<p>b1. 난이도 낮추기 : 최소 기능 제품(MVP). 쉬운 언어로 난이도 낮추기
b2. 실력 높이기 : 뛰어난 전문가의 도움(짝 프로그래밍, 튜토리얼 진행), 도구의 도움. 비슷한 경험 바탕으로 문제해결</p>
<p>우리는 C 영역에 있을 때 몰입할 수 있다.</p>
<h2 id="실전대입">실전대입</h2>
<h3 id="문제는-한번에-하나씩-해결한다">문제는 한번에 하나씩 해결한다</h3>
<p>커다란 문제를 만나는 경우, 불안함을 느끼게 된다. 이 때 문제를 피쳐리스트로 잘게 쪼개서 (난이도 낮추기) 한번에 하나씩 처리하는 경우 몰입 상태를 유지할 수 있다.</p>
<h3 id="어깨에-힘을-빼고-주변을-살핀다">어깨에 힘을 빼고, 주변을 살핀다</h3>
<p>힘을 뺀다는 뜻은, 해당 일과 관련된 모든 정보를 받아들이겠다는 의미다. 비슷한 문제를 해결한 동료의 코드, 문서를 참고하고 문제해결과 관련있는 도구의 도움을 받는다.(실력 높이기)</p>
]]></description>
        </item>
    </channel>
</rss>