<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>3hee_11.log</title>
        <link>https://velog.io/</link>
        <description>배운 것을 기억하기 위해 기록합니다 😎</description>
        <lastBuildDate>Thu, 22 Dec 2022 15:13:19 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>3hee_11.log</title>
            <url>https://velog.velcdn.com/images/3hee_11/profile/ab8c991c-3659-42c1-9902-d2ea5cbb709f/image.jfif</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 3hee_11.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/3hee_11" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Typescript] tsconfig.json 설정하기]]></title>
            <link>https://velog.io/@3hee_11/Typescript-tsconfig.json-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@3hee_11/Typescript-tsconfig.json-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 22 Dec 2022 15:13:19 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<ul>
<li><code>npm init -y</code> : package.json 초기화</li>
<li><code>npm install -D typescript</code>: typescript 설치<blockquote>
</blockquote>
💡 -D 붙이면 타입스크립트가 devDependencies에 설치됨</li>
</ul>
<h3 id="✅-tsconfigjson-생성">✅ tsconfig.json 생성</h3>
<p>tsconfig.json은 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>타입스크립트 컴파일러 설정 파일</span>이다. node.js는 타입스크립트를 이해하지 못하기 때문에 자바스크립트 코드로 컴파일하는 작업이 필요하다.</p>
<pre><code class="language-ts">{
    // 어디에 타입스크립트 파일이 위치하는지
    &quot;include&quot;: [&quot;src&quot;],
    &quot;compilerOptions&quot;: {
        // 자바스크립트 파일이 생성될 디렉토리 지정
        &quot;outDir&quot;: &quot;build&quot;,
        // 자바스크립트 몇버전으로 컴파일할지 지정
        &quot;target&quot;: &quot;ES6&quot;
        // 어떤 환경에서 코드를 실행하는 지 지정
        &quot;lib&quot;: [&quot;ES6&quot;, &quot;DOM&quot;],
        //
        &quot;strict&quot;: true
    }
}</code></pre>
<h3 id="✅-ts에서-js로-만들어진-패키지를-설치했을-때-ts에-패키지의-타입을-정의하는-방법">✅ TS에서 JS로 만들어진 패키지를 설치했을 때 TS에 패키지의 타입을 정의하는 방법</h3>
<h4 id="📄-mypackagedts-생성">📄 myPackage.d.ts 생성</h4>
<p>d.ts 파일은 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>자바스크립트로 만들어진 패키지나 라이브러리를 타입스크립트에게 어떤 타입인지 설명</span>한다.</p>
<p>임의로 다른 파일에서 아래 코드와 같은 함수를 만들고(설치한 모듈이라고 가정) <code>index.ts</code>로 불러오면 사진과 같은 경고 메세지가 뜬다.</p>
<pre><code class="language-js">export function init(config){
    return true;
}

export function exit(code){
    return code + 1;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/67664d6a-80f0-4cd3-940c-6ebbcc11bdae/image.png" alt=""></p>
<p>타입스크립트에게 새로 만든 함수의 타입을 알려주기 위해 <code>myPackage.d.ts 파일</code>을 생성해서 아래처럼 작성한다( d.ts의 정의 파일에서 구현이 아닌 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>호출 시그니처, 즉 타입만</span> 써주면 된다 )</p>
<pre><code class="language-ts">interface Config {
    url: string;
}

declare module &quot;myPackage&quot; {
    function init(config: Config): boolean;
}</code></pre>
<p>경고 메세지가 사라지고 잘 불러와지는 걸 볼 수 있다.
<img src="https://velog.velcdn.com/images/3hee_11/post/11ce8160-4271-4787-aead-246f9b330c8e/image.png" alt=""></p>
<h3 id="✅-프로젝트-안에-js와-ts-파일이-같이-들어있는-경우">✅ 프로젝트 안에 JS와 TS 파일이 같이 들어있는 경우</h3>
<p>경로를 <code>&quot;./myPackage&quot;</code>로 변경</p>
<pre><code class="language-js">// index.ts
import {init, exit} from &quot;./myPackage&quot;;</code></pre>
<p><code>tsconfig.json</code> 파일에 <code>allowJs:true</code> 추가</p>
<pre><code class="language-js">{
    // 어디에 타입스크립트 파일이 위치하는지
    &quot;include&quot;: [&quot;src&quot;, &quot;myPackage.js&quot;],
    &quot;compilerOptions&quot;: {
        // 자바스크립트 파일이 생성될 디렉토리 지정
        &quot;outDir&quot;: &quot;build&quot;,
        // 자바스크립트 몇버전으로 컴파일할지 지정
        &quot;target&quot;: &quot;ES6&quot;,
        // 어떤 환경에서 코드를 실행하는 지 지정
        &quot;lib&quot;: [&quot;ES6&quot;, &quot;DOM&quot;],
        &quot;strict&quot;: true,
        // 타입스크립트 안에서 자바스크립트 허용
        &quot;allowJs&quot;: true
    }
}</code></pre>
<h4 id="🤔-js에서도-타입-검사를-하고-싶다면">🤔 JS에서도 타입 검사를 하고 싶다면?</h4>
<blockquote>
<p><strong>💡 // @ts-check</strong>
@ts-check를 .js 파일의 첫 번째 줄에 추가하면 자바스크립트도 타입 검사할 수 있다.</p>
</blockquote>
<p><strong>💡 // JSDoc</strong>
코멘트로 이루어진 문법으로 함수 바로 위에 코멘트를 적으면 된다. 타입스크립트는 이 코멘트를 읽을 수 있다.</p>
<pre><code class="language-js">// @ts-check
/**
 * Initializes the project
 * @param {object} config 
 * @param {boolean} config.debug
 * @param {string} config.url
 * @returns {boolean}
 */
export function init(config){
    return true;
}

/**
 * Exit the program
 * @param {number} code 
 * @returns {number}
 */
export function exit(code){
    return code + 1;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Typescript] 클래스와 인터페이스]]></title>
            <link>https://velog.io/@3hee_11/Typescript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@3hee_11/Typescript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Wed, 21 Dec 2022 14:56:33 GMT</pubDate>
            <description><![CDATA[<h2 id="클래스">클래스</h2>
<pre><code class="language-ts">class Car {
    constructor(public color:string){
        // 이 부분은 생략이 가능하다. 
        // 파라미터들을 써주기만 하면 TS가 알아서 constructor 함수를 만들어준다.
        this.color = color;
    }

    start(){
        console.log(&quot;start&quot;);
    }
}

const bmw = new Car(&quot;red&quot;);
bmw.start();</code></pre>
<h3 id="접근제한자">접근제한자</h3>
<ul>
<li><code>public</code> - 자식 클래스, 클래스 인스턴스 모두 접근가능(default)</li>
<li><code>private</code> - 해당 클래스 내부에서만 접근 가능(private 키워드 대신 # 사용 가능) </li>
<li><em>🚨 상속한 클래스에서도 접근할 수 없으므로 주의! 🚨*</em></li>
<li><code>protected</code> - 자식 클래스에서 접근 가능</li>
</ul>
<table>
<thead>
<tr>
<th>구분</th>
<th>선언한 클래스 내</th>
<th>상속받은 클래스 내</th>
<th>인스턴스</th>
</tr>
</thead>
<tbody><tr>
<td>private</td>
<td>⭕</td>
<td>❌</td>
<td>❌</td>
</tr>
<tr>
<td>protected</td>
<td>⭕</td>
<td>⭕</td>
<td>❌</td>
</tr>
<tr>
<td>public</td>
<td>⭕</td>
<td>⭕</td>
<td>⭕</td>
</tr>
</tbody></table>
<h3 id="static">static</h3>
<p><code>static</code> 을 사용하면 정적 멤버 변수, 메서드를 만들 수 있다. <code>클래스.</code> 으로 접근이 가능하다.</p>
<pre><code class="language-jsx">class Car {
    // color: string;
    static wheels = 4;
    constructor(public color:string){
        this.color = color;
    }
    start(){
        console.log(&quot;start&quot;);
        console.log(Car.wheels);
    }
}

const bmw = new Car(&quot;red&quot;);</code></pre>
<h3 id="readonly">readonly</h3>
<p><code>readonly</code> 키워드를 클래스 속성 이름 앞에 추가하면 읽기 전용 속성이 되어 속성을 수정할 수 없다. </p>
<pre><code class="language-ts">class Word {
    constructor(
        public readonly term :string,
        public readonly def :string
    ){}
}</code></pre>
<h3 id="추상-클래스">추상 클래스</h3>
<ul>
<li><p>추상 클래스는 클래스 앞에 <code>abstarct</code> 키워드를 사용한다.  추상 클래스는 <strong>new를 이용해서 객체를 만들 수 없고 상속을 할 때만 사용</strong>할 수 있다. 
👉 <code>오로지 상속만을 위한 것</code></p>
</li>
<li><p>추상 클래스는 공통된 속성과 메소드를 갖도록 해주는 <code>청사진</code>을 만들기 위해 사용한다.</p>
</li>
<li><p>추상 클래스 안에는 <code>추상 메서드</code>를 구현할 수 있다. 추상 메서드 안에 내용은 추상 메서드가 아닌 상속받은 쪽에서 구현 해야한다.</p>
</li>
</ul>
<h3 id="예제">예제</h3>
<pre><code class="language-ts">type Words = {
    // property에 대해 모르고 타입만 알 때 유용
    [key:string]: string
}

class Dict {
    private words: Words

    constructor(){
        // 수동으로 초기화
        this.words = {}
    }

      // 클래스를 타입으로 쓸 수 있다!
    add(word:Word){
        // 사전에 단어가 존재하지 않으면 추가
        if(!this.words[word.term]){
            this.words[word.term] = word.def;
        }
    }

    def(term:string){
        return this.words[term];
    }
}

class Word {
    constructor(
        public term :string,
        public def :string
    ){}
}

const dict = new Dict();
const kimchi = new Word(&quot;kimchi&quot;, &quot;한국의 음식&quot;);

dict.add(kimchi);
dict.def(&quot;kimchi&quot;);</code></pre>
<h2 id="인터페이스">인터페이스</h2>
<h3 id="타입">타입</h3>
<p>타입은 객체를 설명하는데도 쓸 수 있고 타입 alias를 만드는데도 사용할 수 있고 특정 값을 가지도록 제한할 수도 있다. 
👉 <strong>타입은 인터페이스에 비해 더 다양하게 활용할 수 있다.</strong></p>
<p>아래처럼 <code>연산자</code>를 이용해서 타입이 특정값을 가지게 할 수 있다.</p>
<pre><code class="language-ts">type Team = &quot;red&quot; | &quot;blue&quot; | &quot;yellow&quot;;
type Health = 1 | 5 | 10

type Player = {
    nickname:string,
    team:Team,
    health: Health
}

const nico:Player = {
    nickname: &quot;yuni&quot;,
    team: &quot;red&quot;,
    health: 5
}</code></pre>
<h3 id="인터페이스-1">인터페이스</h3>
<p>인터페이스는 타입과 달리 객체의 모양을 특정해주는 용도로만 사용한다.</p>
<pre><code class="language-ts">type Team = &quot;red&quot; | &quot;blue&quot; | &quot;yellow&quot;;
type Health = 1 | 5 | 10

interface Player {
    nickname:string,
    team:Team,
    health: Health
}

const nico:Player = {
    nickname: &quot;yuni&quot;,
    team: &quot;red&quot;,
    health: 5
}</code></pre>
<p><code>extends</code> 키워드를 이용해 인터페이스를 다른 인터페이스에 상속할 수 있다.</p>
<pre><code class="language-ts">interface User{
    name:string
}

interface Player extends User {

}

const yuni:Player = {
    name: &quot;yuni&quot;
}

// 타입으로도 아래와 같이 작성하면 위 코드와 동일하게 사용할 수 있다.
type User = {
    name:string
}

type Player = User &amp; {

}

const yuni:Player = {
    name: &quot;yuni&quot;
}</code></pre>
<blockquote>
<p>🤔 <strong>인터페이스와 타입의 차이점</strong></p>
</blockquote>
<p>✔ <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>확장하는 방법(상속)</span> : 인터페이스는 extends, 타입은 &amp;</p>
<blockquote>
</blockquote>
<p>✔ <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>선언적 확장</span> : type은 새로운 속성을 추가하기 위해서 다시 같은 이름으로 선언할 수 없지만, interface는 아래 코드처럼 항상 선언적 확장이 가능하다.</p>
<pre><code class="language-ts">interface User {
  name: string
}
interface User {
  lastName: string
}
interface User {
  health: number
}</code></pre>
<p>✔ <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>interface는 객체에만 사용이 가능하다.</span></p>
<blockquote>
</blockquote>
<p><code>implements</code>를 사용해서 인터페이스의 속성과 메소드를 클래스에서 구현하도록 할 수 있다.</p>
<pre><code class="language-ts">interface User {
    firstName:string,
    lastName:string
    sayHi(name:string):string
    fullName():string
}

interface Human {
    health:number,
}

class Player implements User, Human {
    constructor(
        public firstName:string,
        public lastName:string,
        public health:number,
    ){}

    fullName(){
        return `${this.firstName} ${this.lastName}`;
    }

    sayHi(name:string){
        return `Hello ${name} My name is ${this.fullName()}`;
    }
}</code></pre>
<p>인터페이스는 타입스크립트에서만 존재하기 때문에 추상 클래스를 상속하는 것보다 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>코드가 가볍다.<span></p>
<h3 id="참고">참고</h3>
<p><a href="https://bny9164.tistory.com/48">typescript type과 interface의 차이</a></p>
<h2 id="다형성">다형성</h2>
<pre><code class="language-ts">interface SStorage&lt;T&gt; {
    [key:string]: T
}

class LocalStorage&lt;T&gt; {
      // 제네릭을 전달할 수 있다.
    private storage: SStorage&lt;T&gt; = {}

    set(key:string, value:T){
        this.storage[key] = value;
    }

    remove(key:string){
        delete this.storage[key];
    }

    get(key:string): T {
        return this.storage[key];
    }

    clear(){
        this.storage = {};
    }
}

const stringStorage = new LocalStorage&lt;string&gt;();

stringStorage.get(&quot;cat&quot;);  </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Proxy 설정하기]]></title>
            <link>https://velog.io/@3hee_11/Proxy-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@3hee_11/Proxy-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 13 Oct 2022 02:18:49 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>CORS란?</strong>
교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다.</p>
</blockquote>
<blockquote>
<p><strong>출처란?</strong>
웹 콘텐츠의 출처(origin)는 접근할 때 사용하는 URL의 스킴(프로토콜), 호스트(도메인), 포트로 정의된다. 두 객체의 스킴, 호스트, 포트가 모두 일치하는 경우 같은 출처를 가졌다고 말한다. 일부 작업은 동일 출처 콘텐츠로 제한되나 CORS를 통해 제한을 해제할 수 있다.</p>
</blockquote>
<h3 id="cors-정책이-필요한-이유">CORS 정책이 필요한 이유</h3>
<p>실제 서비스가 사용되는 앱을 운영 중이라면 클라이언트 뒤의 서버와 연결되어 있는 DB에는 라이브 데이터가 쌓일 것이다. 이런 라이브 데이터는 민감한 데이터들 위주이기 때문에 보안이 중요하다. 만약 서비스 및 프로젝트가 모든 출처의 접근을 허락한다면 보안성이 낮아지고 해킹의 위험에 노출될 수 있다.</p>
<p>따라서 모든 도메인을 허용하지않고 특정 도메인을 허용하도록 구현해야한다. 프론트엔드 개발자가 백엔드 개발자에게 프론트엔드 개발 서버 도메인을 허용해달라고 요청해야하고 백엔드 개발자는 응답 헤더에 필요한 값들을 담아서 전달해줘야한다.</p>
<h3 id="proxy">Proxy</h3>
<p>그러나 위의 과정없이 React 라이브러리 혹은 Webpack Dev Server에서 제공하는 proxy 기능을 사용하면 CORS 정책을 우회할 수 있다. 이는 별도의 응답 헤더를 받을 필요없이 브라우저는 React 앱으로 데이터를 요청하고 해당 요청을 백엔드로 전달하게된다. 여기서 React 앱이 서버로부터 받은 응답 데이터를 다시 브라우저로 전달하는 방법을 쓰기 때문에 출처가 같아져 브라우저는 CORS 정책을 위반한지 모르게된다.</p>
<h3 id="proxy-사용법">Proxy 사용법</h3>
<h4 id="webpack-dev-server-proxy">webpack dev server proxy</h4>
<p>webpack dev server의 proxy를 사용하게 되면 브라우저 API를 요청할 때 백엔드 서버에 직접적으로 요청을 하지 않고 현재 개발서버의 주소로 우회 요청을 하게 된다. 그러면 웹팩 개발 서버에서 해당 요청을 받아 그대로 백엔드 서버로 전달하고 백엔드 서버에서 응답한 내용을 다시 브라우저로 반환한다.</p>
<p>웹팩 개발서버의 proxy 설정은 원래 웹팩 설정을 통해서 적용을 하지만 CRA 를 통해 만든 리액트 프로젝트에서는 package.json 에서 <code>proxy</code> 값을 설정하여 쉽게 적용할 수 있도록 구성이 되어 있다.</p>
<pre><code class="language-js">...
&quot;browserslist&quot;: {
    &quot;production&quot;: [
      &quot;&gt;0.2%&quot;,
      &quot;not dead&quot;,
      &quot;not op_mini all&quot;
    ],
    &quot;development&quot;: [
      &quot;last 1 chrome version&quot;,
      &quot;last 1 firefox version&quot;,
      &quot;last 1 safari version&quot;
    ]
  },
    &quot;proxy&quot; : &quot;우회할 API 주소&quot;
}</code></pre>
<p>그리고 기존의 fetch 혹은 axios를 통해 요청하던 부분에서 도메인 부분을 제거한다.</p>
<pre><code class="language-js">export async function getAllfetch() {

    const response = await fetch(&#39;우회할 api주소/params&#39;);
    .then(() =&gt; {
            ...
        })
}

export async function getAllfetch() {

    const response = await fetch(&#39;/params&#39;);
    .then(() =&gt; {
            ...
        })
}</code></pre>
<h4 id="react-proxy-사용법">React Proxy 사용법</h4>
<p>webpack dev server 에서 제공하는 proxy는 전역적인 설정이기 때문에 종종 해당 방법이 충분히 적용되지 않는 경우가 생기기도 한다. 그래서 수동으로 proxy를 적용해줘야 하는 경우가 있는데 이때는 http-proxy-middleware 라이브러리를 사용한다.</p>
<ul>
<li>http-proxy-middleware 라이브러리 설치
<code>npm install http-proxy-middleware --save</code></li>
<li>React App의 src 파일 안에서 setupProxy.js 파일을 생성하고 안에서 설치한 라이브러리 파일을 불러온 다음 아래와 같이 작성한다.<pre><code class="language-js">const { createProxyMiddleware } = require(&#39;http-proxy-middleware&#39;);
</code></pre>
</li>
</ul>
<p>module.exports = function(app) {
  app.use(
    &#39;/api&#39;, //proxy가 필요한 path prameter 입력합
    createProxyMiddleware({
      target: &#39;<a href="http://localhost:5000&#39;">http://localhost:5000&#39;</a>, //타겟이 되는 api url 입력
      changeOrigin: true, //대상 서버 구성에 따라 호스트 헤더가 변경되도록 설정하는 부분
    })
  );
};</p>
<pre><code>- 기존의 fetch 혹은 axios를 통해 요청하던 부분에서 도메인 부분을 제거한다.

```js
export async function getAllfetch() {

    const response = await fetch(&#39;우회할 api주소/params&#39;);
    .then(() =&gt; {
            ...
        })
}

export async function getAllfetch() {

    const response = await fetch(&#39;/params&#39;);
    .then(() =&gt; {
            ...
        })
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[CI/CD] CI/CD&Github Action]]></title>
            <link>https://velog.io/@3hee_11/CICD</link>
            <guid>https://velog.io/@3hee_11/CICD</guid>
            <pubDate>Wed, 12 Oct 2022 14:44:56 GMT</pubDate>
            <description><![CDATA[<h2 id="cicd">CI/CD</h2>
<h3 id="cicontinuous-integration">CI(Continuous Integration)</h3>
<p><code>CI</code>는 개발자를 위한 자동화 프로세스인 지속적인 통합을 의미하며 <code>Code-Build-Test</code>단계가 있다. 지속적 통합으로 머지 전 빌드 오류나 테스트 오류를 확인하여 보안 이슈, 에러 등을 쉽게 파악할 수 있어 해당 이슈를 빠르게 개선할 수 있다.</p>
<ul>
<li><strong>Code</strong> : 개발자가 코드를 원격 코드 저장소에 push하는 단계</li>
<li><strong>Build</strong> : 원격 코드 저장소로부터 코드를 가져와 유닛 테스트 후 빌드하는 단계</li>
<li><strong>Test</strong> : 코드 빌드의 결과물이 다른 컴포넌트와 잘 통합되는 지 확인하는 과정</li>
</ul>
<h3 id="cdcontinuous-delivery">CD(Continuous Delivery)</h3>
<p><code>CD</code>는 지속적인 서비스 제공 및/또는 지속적인 배포(Continuous Deployment)를 의미하며 이 두 용어는 상호 교환적으로 사용된다. </p>
<p>지속적인 배포의 경우 코드 변경 사항의 병합부터 프로덕션에 적합한 빌드 제공에 이르는 모든 단계로 테스트 자동화와 코드 릴리스 자동화가 포함된다.</p>
<ul>
<li><strong>Release</strong> : 배포 가능한 소프트웨어 패키지를 작성</li>
<li><strong>Deploy</strong> : 프로비저닝을 실행하고 서비스를 사용자에게 노출(실질적인 배포)</li>
<li><strong>Operate</strong> : 서비스 현황을 파악하고 생길 수 있는 문제를 감지</li>
</ul>
<h3 id="cicd의-영역">CI/CD의 영역</h3>
<p>CI/CD는 지속적 통합 및 지속적 제공의 구축 사례만을 지칭할 때도 있고 지속적 통합, 지속적 제공, 지속적 배포라는 3가지 구축 사례 모두를 의미할 때도 있다. 좀 더 복잡하게 설명하면 지속적인 서비스 제공은 때로 지속적인 배포의 과정까지 포함하는 방식으로 사용되기도 한다.</p>
<p>결과적으로 CI/CD는 파이프라인으로 표현되는 실제 프로세스를 의미하고 애플리케이션 개발에 지속적인 자동화 및 지속적인 모니터링을 추가하는 것을 의미한다. 이 용어는 사례별로 CI/CD 파이프라인에 구현된 자동화 수준 정도에 따라 그 의미가 달라진다.</p>
<h3 id="배포-자동화">배포 자동화</h3>
<p>배포 자동화란 한번의 클릭 혹은 명령어 입력을 통해 전체 배포 과정을 자동으로 진행하는 것을 뜻한다. </p>
<blockquote>
<p><strong>배포 자동화의 필요성</strong></p>
</blockquote>
<ul>
<li>수동적이고 반복적인 배포 과정을 자동화함으로써 시간이 절약됨</li>
<li>휴먼 에러(수동 배포 과정 중 생기는 에러)를 방지할 수 있음</li>
</ul>
<h3 id="cicd-파이프라인">CI/CD 파이프라인</h3>
<p>배포에서 파이프라인이란 소스 코드의 관리부터 실제 서비스로의 배포 과정을 연결하는 구조를 뜻한다. 파이프라인은 전체 배포 과정을 여러 단계로 분리한다. 각 단계는 파이프라인 안에서 순차적으로 실행되며 각 단계마다 주어진 작업들을 수행한다.</p>
<blockquote>
<p><strong>파이프라인에서 대표적으로 쓰이는 단계</strong></p>
</blockquote>
<ul>
<li><strong>Source</strong>: Source 단계에서는 원격 저장소에 관리되고 있는 소스 코드에 변경 사항이 일어날 경우 이를 감지하고 다음 단계로 전달하는 작업을 수행한다.</li>
<li><strong>Build</strong>: Build 단계에서는 Source 단계에서 전달받은 코드를 컴파일, 빌드, 테스트하여 가공한다. 또한 Build 단계를 거쳐 생성된 결과물을 다음 단계로 전달하는 작업을 수행한다.</li>
<li><strong>Deploy</strong>: Deploy 단계에서는 Build 단계로부터 전달받은 결과물을 실제 서비스에 반영하는 작업을 수행한다.</li>
</ul>
<h3 id="cicd-파이프라인-구성-요소-및-장점">CI/CD 파이프라인 구성 요소 및 장점</h3>
<ul>
<li>빌드 (소프트웨어 컴파일)</li>
<li>테스트 (호환성 및 오류 검사)</li>
<li>릴리스 (버전 제어 저장소의 애플리케이션 업데이트)</li>
<li>배포 (개발에서 프로덕션 환경으로의 변환)</li>
<li>규정 준수 및 유효성 검사</li>
</ul>
<h2 id="github-action">Github Action</h2>
<h3 id="github-action이란">Github Action이란?</h3>
<p>GitHub Actions는 Github가 공식적으로 제공하는 빌드, 테스트 및 배포 파이프라인을 자동화할 수 있는 CI/CD 플랫폼이다. </p>
<p>레포지토리에서 Pull Request나 push같은 이벤트를 트리거로 GitHub 작업 워크플로를 구성할 수 있다. 워크플로는 하나 이상의 작업이 실행되는 자동화 프로세스로 각 작업은 자체 가상 머신 또는 컨테이너 내부에서 실행된다.</p>
<p>워크플로는 .yml (혹은 .yaml ) 파일에 의해 구성되며 테스트, 배포 등 기능에 따라 여러개의 워크플로도 만들 수 있다. 생성된 워크플로는 .github/workflows 디렉토리 이하에 위치한다.</p>
<p><strong><a href="http://fe-23-kyh1685.s3-website.ap-northeast-2.amazonaws.com/">배포 링크</a></strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[최적화] Lighthouse]]></title>
            <link>https://velog.io/@3hee_11/%EC%B5%9C%EC%A0%81%ED%99%94-Lighthouse</link>
            <guid>https://velog.io/@3hee_11/%EC%B5%9C%EC%A0%81%ED%99%94-Lighthouse</guid>
            <pubDate>Fri, 07 Oct 2022 07:55:22 GMT</pubDate>
            <description><![CDATA[<p>구글에서 개발한 성능 측정 도구인 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>Lighthouse</span>를 사용해 Velog의 성능 검사를 해봤다.</p>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/7c6921b7-0209-45c9-b3ec-12d15fd1c6f6/image.png" alt=""></p>
<h3 id="lighthouse-분석-결과-항목">Lighthouse 분석 결과 항목</h3>
<h4 id="✅-performance">✅ Performance</h4>
<p>Performance 항목에서는 웹 성능을 측정한다. 화면에 콘텐츠가 표시되는데 시간이 얼마나 걸리는지, 표시된 후 사용자와 상호작용하기 까진 얼마나 걸리는지, 화면에 불안정한 요소는 없는지 등을 확인한다.</p>
<h4 id="✅-accessibility">✅ Accessibility</h4>
<p>Accessibility 항목에서는 웹 페이지가 웹 접근성을 잘 갖추고 있는지 확인한다. 대체 텍스트를 잘 작성했는지, 배경색과 콘텐츠 색상의 대비가 충분한지, 적절한 WAI-ARIA 속성을 사용했는지 등을 확인한다.</p>
<h4 id="✅-best-practices">✅ Best Practices</h4>
<p>Best Practices 항목에서는 웹 페이지가 웹 표준 모범 사례를 잘 따르고 있는지 확인한다. HTTPS 프로토콜을 사용하는지, 사용자가 확인할 확률은 높지 않지만 콘솔 창에 오류가 표시 되지는 않는지 등을 확인한다.</p>
<h4 id="✅-seo">✅ SEO</h4>
<p>SEO 항목에서는 웹 페이지가 검색 엔진 최적화가 잘 되어있는지 확인한다. 애플리케이션의 robots.txt가 유효한지, <code>&lt;meta&gt;</code> 요소는 잘 작성되어 있는지, 텍스트 크기가 읽기에 무리가 없는지 등을 확인한다.</p>
<h4 id="✅-pwa-progressive-web-app">✅ PWA (Progressive Web App)</h4>
<p>PWA 항목에서는 해당 웹 사이트가 모바일 애플리케이션으로서도 잘 작동하는지 확인한다. 앱 아이콘을 제공하는지, 스플래시 화면이 있는지, 화면 크기에 맞게 콘텐츠를 적절하게 배치했는지 등을 점수가 아닌 체크리스트로 확인한다.</p>
<h3 id="개선-방향">개선 방향</h3>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/ef3d37a5-9975-47a5-9b4c-e64042aac5f4/image.png" alt=""></p>
<h4 id="✅-properly-size-images적절한-크기의-이미지">✅ Properly size images(적절한 크기의 이미지)</h4>
<p>Lighthouse는 렌더링된 이미지의 크기와 실제 이미지의 크기를 비교하는데, 여기서 렌더링된 이미지의 크기보다 실제 이미지가 크면 바이트가 낭비되고 페이지 로드 시간이 느려진다.</p>
<p>적절한 크기의 이미지를 제공하기 위한 <strong>첫번째 방법은 반응형 이미지 사용이다.</strong> 반응형 이미지를 사용하면 각 이미지의 여러 버전을 생성한 다음 미디어 쿼리, 뷰포트 크기 등을 사용하여 HTML 또는 CSS에서 사용할 버전을 지정할 수 있다. <strong>두번째 방법은 이미지 CDN 사용이다.</strong> 이미지 변환을 위한 웹서비스 API와 같은 이미지 CDN을 사용해서 적절한 크기의 이미지를 제공할 수 있다. <strong>마지막 방법은 SVG와 같은 벡터 기반 이미지 형식을 사용</strong>하는 것이다. SVG 이미지는 한정된 양의 코드를 사용해 어떤 크기로든 확장할 수 있다. </p>
<h4 id="✅-serve-images-in-next-gen-formats최신-형식의-이미지-제공">✅ Serve images in next-gen formats(최신 형식의 이미지 제공)</h4>
<p>PNG 대신 WebP를 사용하면 용량이 26&amp; 감소하고 JPEG의 경우 25~35% 더 감소된다. AVIF는 JPEG와 비교했을 때 무려 용량의 50%가 감소되며 WebP와 비교했을 땐 20% 감소된다. 이처럼 PNG, JPEG 대신 WebP와 AVIF를 사용하여 이미지의 용량을 줄이고 성능을 개선할 수 있다.</p>
<h4 id="✅-use-video-formats-for-animated-content애니메이션-콘텐츠에-비디오-형식-사용">✅ Use video formats for animated content(애니메이션 콘텐츠에 비디오 형식 사용)</h4>
<p>용량이 큰 GIF는 애니메이션 콘텐츠를 전달하는데 비효율적이다. 따라서 GIF를 동영상으로 변환하면 사용자의 대역폭을 크게 절약할 수 있다. 네트워크 바이트를 절약하기 위해 GIF 대신 MPEG4, WebM을 사용해야한다.</p>
<h4 id="✅-efficiently-encode-images이미지를-효율적으로-인코딩">✅ Efficiently encode images(이미지를 효율적으로 인코딩)</h4>
<p>Lighthous는 JPEG 또는 BMP 이미지를 수집하고 각 이미지의 압축 수준을 85로 설정한 다음 원본 버전을 압축 버전과 비교한다. 절감 효과가 4KiB 이상인 경우 Lighthouse는 이미지를 최적화 가능한 것으로 본다.</p>
<h4 id="✅-reduce-unused-javascript사용하지-않는-자바스크립트-제거">✅ Reduce unused JavaScript(사용하지 않는 자바스크립트 제거)</h4>
<p>Lighthouse는 사용되지 않는 코드가 20KB이상인 모든 Javascript 파일을 최적화 대상으로 본다. 사용하지 않는 Javascript 파일은 페이지의 로드 속도를 늦출 수 있으므로 제거하는 것이 좋다.</p>
<h4 id="✅-minify-javascript자바스크립트-축소">✅ Minify JavaScript(자바스크립트 축소)</h4>
<p>Javascript 파일을 축소하면 페이로드 크기와 스크립트 구문 분석 시간을 줄일 수 있다. Lighthouse 보고서의 기회 섹션에서는 축소되지 않은 모든 Javascript 파일이 나열되며 축소됐을 때 절약할 수 있는 키비바이트가 표시된다.</p>
<p>여기서 축소는 파일 내부에 필요하지 않은 공백과 코드를 제거하는 프로세스이다. Javascript 압축 도구인 Terser를 이용해서 압축할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[최적화] 캐시 관리]]></title>
            <link>https://velog.io/@3hee_11/%EC%B5%9C%EC%A0%81%ED%99%94-%EC%BA%90%EC%8B%9C-%EA%B4%80%EB%A6%AC</link>
            <guid>https://velog.io/@3hee_11/%EC%B5%9C%EC%A0%81%ED%99%94-%EC%BA%90%EC%8B%9C-%EA%B4%80%EB%A6%AC</guid>
            <pubDate>Fri, 07 Oct 2022 05:21:27 GMT</pubDate>
            <description><![CDATA[<p><em>김영한 강사님의 모든 개발자를 위한 HTTP 웹 기본 지식 강의를 참고했습니다.</em></p>
<h2 id="캐시란">캐시란?</h2>
<p>캐시는 다운로드 받은 데이터나 값을 미리 복사해놓은 임시 저장소를 뜻한다. 데이터에 접근하는 시간이 오래 걸리는 경우나 값을 다시 계산하는 시간을 절약하고 싶은 경우에 사용한다. </p>
<blockquote>
<p><strong>💡 브라우저 캐시 활용시 효과</strong></p>
</blockquote>
<ul>
<li>캐시가 유효한 시간동안 네트워크 리소스를 아낄 수 있다.</li>
<li>파일을 다시 받아올 필요가 없기 때문에 브라우저 로딩이 빠르다.</li>
<li>로딩이 빨라진 만큼 빠른 사용자 경험을 제공한다.</li>
</ul>
<h2 id="캐시-기본-동작">캐시 기본 동작</h2>
<h3 id="🚨-캐시-없을-때">🚨 캐시 없을 때</h3>
<ul>
<li>데이터에 변경이 없어도 매번 네트워크를 통해서 다운로드 해야 함
👉 인터넷 네트워크는 매우 느리고 비쌈
👉 브라우저 로딩 속도 느림</li>
</ul>
<h3 id="💡-캐시-있을-때">💡 캐시 있을 때</h3>
<ul>
<li>캐시 가능 시간동안 네트워크를 사용하지 않아도 됨
👉 비싼 네트워크 사용량을 줄일 수 있음
👉 브라우저 로딩 속도가 매우 빠름</li>
</ul>
<h3 id="캐시-동작-과정">캐시 동작 과정</h3>
<ul>
<li>클라이언트가 이미지(예시)를 요청했을 때, 서버는 응답으로 이미지와 함께 캐시 유효 시간을 응답으로 줌</li>
<li>클라이언트는 응답 결과를 브라우저 캐시에 저장</li>
<li>똑같은 이미지를 재요청할 때, 클라이언트는 우선 브라우저 캐시의 캐시 유효 시간을 보고 유효하면 캐시에서 조회함</li>
<li>만약 유효 시간이 초과됐다면 서버를 통해 데이터를 다시 조회하고 캐시를 갱신</li>
</ul>
<h2 id="검증-헤더와-조건부-요청">검증 헤더와 조건부 요청</h2>
<h3 id="🤔-캐시-만료후에도-서버에서-데이터를-변경하지-않았다면">🤔 캐시 만료후에도 서버에서 데이터를 변경하지 않았다면?</h3>
<ul>
<li>데이터를 전송하는 대신에 저장해 두었던 캐시를 재사용 할 수 있음</li>
<li>대신 <strong>클라이언트와 서버의 데이터가 같은지 확인</strong> 해야함</li>
</ul>
<h3 id="캐시-시간-초과">캐시 시간 초과</h3>
<ul>
<li>클라이언트가 데이터를 요청하고 서버가 응답할 때, 캐시 유효 시간 외에 최종 수정 시간(Last-Modified)도 함께 보낸다.</li>
<li>클라이언트는 응답 결과를 브라우저에 캐시에 저장한다.</li>
<li>클라이언트가 똑같은 데이터를 다시 요청할 때, 만약 캐시 유효 시간이 초과되었다면 캐시에서 최종 수정 시간을 꺼내서 요청에 if-modified-since에 넣어 보낸다.</li>
<li>만약 서버가 가진 최종 수정일과 요청으로 보낸 수정일이 동일하다면 304 Not Modified로 바디없이 응답한다.</li>
<li>클라이언트는 서버가 보낸 헤더 정보로 캐시 정보를 갱신하고 브라우저 캐시의 데이터를 재사용한다.</li>
</ul>
<h3 id="📌-정리">📌 정리</h3>
<ul>
<li>캐시 유효 시간이 초과해도 서버의 데이터가 갱신되지 않으면 304 Not Modified + 헤더 메타 정보만 응답(바디X)</li>
<li>클라이언트는 서버가 보낸 응답 헤더 정보로 캐시의 메타 정보를 갱신</li>
<li>클라이언트는 캐시에 저장되어 있는 데이터 재활용</li>
<li>결과적으로 네트워크 다운로드가 발생하지만 용량이 적은 헤더 정보만 다운로드</li>
</ul>
<h3 id="검증-헤더">검증 헤더</h3>
<ul>
<li>캐시 데이터와 서버 데이터가 같은지 검증하는 데이터
예) Last-Modified , ETag</li>
</ul>
<h3 id="조건부-요청-헤더">조건부 요청 헤더</h3>
<ul>
<li>검증 헤더로 조건에 따른 분기
예) If-Modified-Since: Last-Modified, If-None-Match: ETag 사용</li>
<li>조건이 만족하면 200 OK, 만족하지 않으면 304 Not Modified</li>
</ul>
<h3 id="🚨-last-modified-if-modified-since-단점">🚨 Last-Modified, If-Modified-Since 단점</h3>
<ul>
<li>1초 미만 단위로 캐시 조정이 불가능하며 날짜 기반의 로직임</li>
<li>데이터를 수정해서 날짜는 다르지만 수정 결과가 똑같은 경우 판별이 안됨</li>
<li>주석처럼 크게 영향이 없는 변경일 경우 캐시를 유지하고 싶을 때도 변경됨</li>
</ul>
<h3 id="💡-etag-if-none-match">💡 ETag, If-None-Match</h3>
<ul>
<li><strong>ETag(Entity Tag)</strong> : 캐시용 데이터에 임의의 고유한 버전 이름을 달아둠
예) ETag: &quot;v1.0&quot;, ETag: &quot;a2jiodwjekjl3&quot;</li>
<li>데이터가 변경되면 이 이름을 바꾸어서 변경함(Hash를 다시 생성)
예) ETag: &quot;aaaaa&quot; -&gt; ETag: &quot;bbbbb&quot;</li>
<li>** ETag만 보내서 같으면 유지, 다르면 다시 받음**
👉 캐시 제어 로직을 서버에서 완전히 관리</li>
</ul>
<h2 id="캐시와-조건부-요청-헤더">캐시와 조건부 요청 헤더</h2>
<h3 id="cache-control-캐시-제어">Cache-Control: 캐시 제어</h3>
<ul>
<li>Cache-Control : max-age<ul>
<li>캐시 유효 시간, 초 단위</li>
</ul>
</li>
<li>Cache-Control : no-cache<ul>
<li>데이터는 캐시해도 되지만, 항상 원(origin) 서버에 검증하고 사용</li>
</ul>
</li>
<li>Cache-Control : no-store<ul>
<li>데이터에 민감한 정보가 있으므로 저장하면 안됨
👉 메모리에서 사용하고 최대한 빨리 삭제</li>
</ul>
</li>
</ul>
<h3 id="pragma-캐시-제어하위-호환">Pragma: 캐시 제어(하위 호환)</h3>
<ul>
<li>Pragma: no-cache<ul>
<li>HTTP 1.0 하위 호환</li>
</ul>
</li>
</ul>
<h3 id="expires-캐시-유효-기간하위-호환">Expires: 캐시 유효 기간(하위 호환)</h3>
<ul>
<li>캐시 만료일을 정확한 날짜로 지정(HTTP 1.0 부터 사용)</li>
<li>현재는 Cache-Control: max-age 권장
👉 Cache-Control: max-age와 함께 사용하면 Expires는 무시</li>
</ul>
<h3 id="프록시-캐시">프록시 캐시</h3>
<h3 id="cache-control">Cache-Control</h3>
<ul>
<li>Cache-Control: public<ul>
<li>응답이 public 캐시에 저장되어도 됨</li>
</ul>
</li>
<li>Cache-Control: private<ul>
<li>응답을 private 캐시에 저장해야 함(기본값)</li>
</ul>
</li>
<li>Cache-Control: s-maxage<ul>
<li>프록시 캐시에만 적용되는 max-age</li>
</ul>
</li>
<li>Age: 60 (HTTP 헤더)<ul>
<li>오리진 서버에서 응답 후 프록시 캐시 내에 머문 시간(초)</li>
</ul>
</li>
</ul>
<h3 id="캐시-무효화">캐시 무효화</h3>
<h3 id="cache-control-1">Cache-Control</h3>
<ul>
<li>Cache-Control: no-cache</li>
<li>Cache-Control: no-store</li>
<li>Cache-Control: must-revalidate<ul>
<li>캐시 만료후 최초 조회시 원 서버에 검증해야함</li>
<li>원 서버 접근 실패시 반드시 오류가 발생해야함 - 504(Gateway Timeout)</li>
<li>must-revalidate는 캐시 유효 시간이라면 캐시를 사용함</li>
</ul>
</li>
<li>Pragma: no-cache</li>
</ul>
<blockquote>
<p><strong>🤔 no-cache과 must-revalidate의 차이점</strong></p>
</blockquote>
<ul>
<li>no-cache는 원서버에 접근할 수 없는 경우, 서버 설정에 따라서 캐시 데이터를 반환할 수 있음(Error or 200 OK)</li>
<li>must-revalidate는 원 서버에 접근할 수 없는 경우, 항상 오류가 발생해야 함(504 Gateway Timeout)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[최적화] 최적화 기법]]></title>
            <link>https://velog.io/@3hee_11/%EC%B5%9C%EC%A0%81%ED%99%94-%EC%B5%9C%EC%A0%81%ED%99%94-%EA%B8%B0%EB%B2%95</link>
            <guid>https://velog.io/@3hee_11/%EC%B5%9C%EC%A0%81%ED%99%94-%EC%B5%9C%EC%A0%81%ED%99%94-%EA%B8%B0%EB%B2%95</guid>
            <pubDate>Fri, 07 Oct 2022 05:18:18 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>📌 최적화란?</strong>
컴퓨터 공학에서의 최적화는 적은 리소스를 소모하면서 가능한 빠르게 원하는 결과를 얻을 수 있도록 하는 것을 의미한다. 웹 개발에서의 최적화는 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>주어진 조건 아래에서 최대한 빠르게 화면을 표시</span>하도록 만드는 것이다.</p>
</blockquote>
<p><strong>🧐 최적화의 필요성 및 효과</strong></p>
<ul>
<li>이탈률 감소</li>
<li>전환율 증가</li>
<li>수익 증대</li>
<li>사용자 경험 향상</li>
</ul>
<h2 id="최적화-기법">최적화 기법</h2>
<h3 id="📌-html-css-코드-최적화하기">📌 HTML, CSS 코드 최적화하기</h3>
<h4 id="html-최적화-방법">HTML 최적화 방법</h4>
<ul>
<li><strong><span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>DOM 트리 가볍게 만들기</span></strong><ul>
<li>불필요하게 깊이를 증가시키는 요소 삭제</li>
</ul>
</li>
<li><strong><span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>인라인 스타일 사용하지 않기</span></strong><ul>
<li>인라인 스타일은 개별 요소에 스타일 속성을 작성해주는 것이기 때문에 클래스로 묶어서 한번에 작성해도 될 스타일 속성을 중복으로 작성하게 되는 경우가 생긴다.</li>
<li>CSS 파일을 따로 작성하면 한 번의 리플로우만 발생하는 것과 달리 <strong>인라인 스타일은 리플로우를 계속해서 발생</strong>시켜 렌더링 완료 시점을 늦춘다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>💡 <strong>참고</strong>
styled components는 인라인 스타일에 포함되지 않는다. styled components는 javascript 파일 내에 작성되지만 렌더링 시 class를 부여해서 css를 적용하기 때문이다.</p>
</blockquote>
<h4 id="css-최적화-방법">CSS 최적화 방법</h4>
<ul>
<li><strong><span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>사용하지 않는 CSS 제거</span></strong></li>
<li><strong><span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>간결한 셀렉터 사용</span></strong></li>
</ul>
<h3 id="📌-리소스-로딩-최적화하기">📌 리소스 로딩 최적화하기</h3>
<h4 id="css-파일-불러오기">CSS 파일 불러오기</h4>
<p>화면을 렌더링할 때 DOM트리는 HTML 코드를 한줄씩 읽으면서 순차적으로 구성할 수 있지만, <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>CSSOM 트리는 CSS 코드를 모두 해석해야 구성할 수 있다.</span> 따라서 CSSOM 트리를 빠르게 구성할 수 있도록 <strong>HTML 문서 최상단(head 요소 안)에 배치</strong>하는 것이 좋다.</p>
<h4 id="js-파일-불러오기">JS 파일 불러오기</h4>
<p>Javascript는 DOM트리와 CSSOM트리를 동적으로 변경할 수 있다. <strong>HTML 코드 파싱 중에 <code>&lt;script&gt;</code> 요소를 만나는 순간 해당 스크립트가 실행되며 <code>&lt;script&gt;</code> 요소 이전에 생성된 DOM까지만 접근할 수 있다.</strong>  따라서 <code>&lt;script&gt;</code> 요소를 중간에 넣는다면 해당 요소 이후에 생성될 DOM을 수정하는 코드가 있는 경우 화면에 의도한 대로 표시되지 않는다. 또 <strong>스크립트 실행이 완료될 때까지 DOM트리 생성이 중단되고 중단된 시간만큼 렌더링 완료 시간이 늦춰진다.</strong> 이러한 이유로 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>Javascript 파일은 DOM트리 생성이 완료되는 시점인 HTML 문서 최하단(body 요소 바로 위)에 배치</span>하는게 좋다. </p>
<h3 id="📌-브라우저-이미지-최적화하기">📌 브라우저 이미지 최적화하기</h3>
<p>페에지 대부분의 용량은 이미지 파일과 미디어 파일이 차지한다. 따라서 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>이미지의 용량을 줄이거나 요청의 수를 줄이는 것</span>을 우선적으로 고려하면 사용자 경험을 빠르게 개선할 수 있다.</p>
<h4 id="이미지-스프라이트">이미지 스프라이트</h4>
<p>이미지 스프라이트 기법은 여러 개의 이미지를 모아 하나의 스프라이트 이미지로 만들고 CSS의 <code>width</code>, <code>height</code>,<code>background-position</code> 속성을 사용해 이미지의 일정 부분만 클래스 등으로 구분하여 사용하는 방법이다.
<img src="https://velog.velcdn.com/images/3hee_11/post/9fab1f45-6341-4409-a10d-9697caf51e57/image.png" alt="">
이 기법을 사용하면 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>한번의 요청으로 개별 이미지를 사용할 수 있기 때문에 네트워크 로딩 시간을 줄일 수 있다.</span> 또한 많은 이미지 파일을 개별로 관리할 필요없이 스프라이트 이미지 파일만 관리하면 되므로 관리가 용이하다.</p>
<h4 id="아이콘-폰트-사용하기">아이콘 폰트 사용하기</h4>
<p>아이콘을 이미지 대신 아이콘 폰트를 사용하여 용량을 줄일 수 있다. 대표적으로 Font Awesome이 있다. Font Awesome의 사용법은 두가지가 있다.</p>
<ul>
<li><strong><span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>CDN 사용하기</span></strong> : Font Awesome에서 발급한 키트를 <code>head</code> 요소에 넣고 사용하고 싶은 아이콘을 찾아서 복사하고 붙여넣는다.</li>
<li><strong><span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>Font Awesome 모듈 설치하기</span></strong> : Font Awesome을 다른 라이브러리처럼 설치해서 사용할 수도 있다. 리액트에서 사용할 경우 아래와 같은 패키지들을 설치하면 된다. 설치 후에는 사용하고 싶은 아이콘을 불러와서 사용한다. 아이콘의 이름은 camelCase로 작성해야한다.<pre><code class="language-js">// 핵심 패키지 설치
npm i --save @fortawesome/fontawesome-svg-core
</code></pre>
</li>
</ul>
<p>// 아이콘 패키지 설치 (해당 코드는 무료 아이콘들입니다. 유료 아이콘을 사용할 경우 추가로 설치가 필요합니다.)
npm i --save @fortawesome/free-solid-svg-icons
npm i --save @fortawesome/free-regular-svg-icons
npm i --save @fortawesome/free-brands-svg-icons</p>
<p>// Font Awesome React 구성 요소 설치
npm i --save @fortawesome/react-fontawesome@latest</p>
<p>// 사용할 때 코드
import { FontAwesomeIcon } from &quot;@fontawesome/react-fontawesome&quot;
import { faReact } form &quot;@fontawesome/free-brands-svg-icons&quot;</p>
<p>const el = <FontAwesome icon={faReact} /></p>
<pre><code>
#### WebP 또는 AVIF 이미지 포맷 사용하기
WebP는 PNG와 비교해 26% 용량이 감소되며 JPEG와 비교했을 땐 25-35% 더 감소된다. AVIF는 JPEG와 비교했을 때 무려 용량의 50%가 감소되며 WebP와 비교했을 땐 20% 감소된다.

하지만 WebP와 AVIF 모두 비교적 최근에 등장한 이미지 포맷이기 때문에 다른 포맷처럼 모든 브라우저에서 호환되지 않는다는 단점이 있다. 이런 단점은 HTML의 ```&lt;picture&gt;``` 태그를 이용하면 각 브라우저의 호환에 맞도록 분기를 대체할 수 있다.

다음과 같이 작성하면 만약 접속한 브라우저에서 ```&lt;source&gt;``` 태그 내의 srcset에 정의한 WebP 포맷을 지원하지 않는다면 해당 ```&lt;source&gt;``` 태그는 무시한다.

```html
// img 요소의 다중 이미지 리소스를 위한 컨테이너를 정의할 때 사용
&lt;picture&gt;
  &lt;source srcset=&quot;logo.webp&quot; type=&quot;image/webp&quot;&gt;
  &lt;img src=&quot;logo.png&quot; alt=&quot;logo&quot;&gt;
&lt;/picture&gt;</code></pre><h3 id="📌-cdn-사용하기">📌 CDN 사용하기</h3>
<p>CDN은 네트워크 지연(유저와 호스팅 서버 간의 물리적 거리의 한계)을 해결하고자 세계 곳곳에 분포한 분산된 서버에 콘텐츠를 저장한다. 간단히 말해 CDN은 유저가 가까운 곳에 위치한 데이터 센터(서버)의 데이터를 가져온다. 이렇게 하면 데이터가 전달되기 위해 거쳐야하는 서버의 수가 줄기 때문에 로딩 속도가 빨라진다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 번들링과 웹팩]]></title>
            <link>https://velog.io/@3hee_11/React-%EB%B2%88%EB%93%A4%EB%A7%81%EA%B3%BC-%EC%9B%B9%ED%8C%A9</link>
            <guid>https://velog.io/@3hee_11/React-%EB%B2%88%EB%93%A4%EB%A7%81%EA%B3%BC-%EC%9B%B9%ED%8C%A9</guid>
            <pubDate>Mon, 26 Sep 2022 05:09:30 GMT</pubDate>
            <description><![CDATA[<h2 id="번들링">번들링</h2>
<h3 id="번들링이란">번들링이란?</h3>
<p>번들링이란 여러 제품이나, 코드, 프로그램을 묶어서 패키지로 제공하는 행위를 의미한다. 현대 웹 개발에서 프론트엔드 개발자에게 번들은 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>사용자에게 웹 애플리케이션을 제공하기 위한 파일 묶음</span>이다.</p>
<p>사용자가 브라우저를 열고 주소를 입력하면 해당 주소에서 프론트엔드 개발자가 번들링한 여러 파일을 받는다. 이 파일을 브라우저가 실행하여 웹 애플리케이션을 사용자에게 제공하게 된다.</p>
<blockquote>
<p>🧐 <strong>꼭 번들링을 해줘야 하나요?</strong>
HTML, CSS, JS 파일을 그대로 보낼 수도 있지만 그런 경우 아래와 같은 어려움이 있을 수 있다.</p>
</blockquote>
<ul>
<li>두 개의 JS 파일에서 같은 변수를 사용하고 있을 경우 변수 간 충돌</li>
<li>한 번만 불러오면 되는 프레임워크 코드가 8MB라서 인터넷 속도가 느린 환경에서 사용자가 불편을</li>
<li>번들 파일 사이즈를 줄이기 위해서 파일의 공백을 모두 지웠는데 가독성이 떨어져 코딩하기 어려워서 결국 공백을 되돌려서 코딩</li>
<li>배포 코드가 너무 읽기 쉬워 개발을 할 줄 아는 사용자가 프론트엔드 애플리케이션을 임의로 조작하여 피해 발생<blockquote>
</blockquote>
📌 <strong>소프트웨어를 잘 만들어도 사용자에게 배포하기 위해 번들링이 꼭 필요하다.</strong></li>
</ul>
<h2 id="웹팩">웹팩</h2>
<h3 id="웹팩이란">웹팩이란?</h3>
<p><span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>웹팩이란 여러 개의 파일을 <strong>하나의 파일로 합쳐주는 모듈 번들러</strong>를 의미한다.</span> 모듈 번들러란 HTML, CSS, JavaScript 등의 자원을 전부 각각의 모듈로 보고 이를 조합해 하나의 묶음으로 번들링(빌드)하는 도구이다.</p>
<p>웹팩에서의 모듈은 JavaScript의 모듈에만 국한되지 않는다. HTML, CSS 혹은 .jpg나 .png 같은 이미지 파일들도 전부 포함한 포괄적인 개념이다. 따라서 웹팩은 주요 구성 요소인 로더를 통해 다양한 파일의 번들링이 가능하다.</p>
<h3 id="모듈-번들러의-등장">모듈 번들러의 등장</h3>
<p>모던 웹으로 발전하면서 JavaScript 코드의 양이 증가하고 대규모의 의존성 트리를 가지고 있는 대형 웹 애플리케이션이 등장하면서 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>세분화된 모듈 파일이 증가</span>했다. 이 모듈 단위의 파일들을 호출을 해 브라우저에 띄우려면 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>각 변수들의 스코프 문제</span>를 해결해야 하고 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>각 자원을 호출할 때에 생겨나는 네트워크 쪽의 코스트</span>도 신경써야했다.</p>
<p>이런 복잡성에 대응하기 위해 하나의 시작점(React App의 index.js 등)으로부터 의존성을 가지는 모듈을 모두 추적하여 하나의 결과물을 만들어내는 모듈 번들러가 등장하게 되었다.</p>
<h3 id="빌드와-번들링">빌드와 번들링</h3>
<p><span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>빌드는 개발이 완료된 앱을 배포하기 위해 하나의 폴더로 구성하여 준비하는 작업을 말한다.</span> React 앱을 기준으로 설명하면 <code>npm run build</code>를 실행하면 React build 작업이 진행되고 index.html 파일에 압축되어 배포에 최적화된 상태를 제공해준다.</p>
<p>번들링은 파일을 묶는 작업을 말하며 여기서 파일은 의존적 관계에 있는 파일들(import, export) 혹은 내부적으로 포함 되어 있는 모듈을 의미한다. 정확히 말하면 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>모듈 간의 의존성 관계를 파악해 그룹화 하는 작업</span>이라고 볼 수 있다.</p>
<h3 id="웹팩의-필요성">웹팩의 필요성</h3>
<p>웹팩이 필요한 가장 큰 이유는 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>웹 애플리케이션의 <strong>빠른 로딩 속도</strong>와 <strong>높은 성능</strong>을 위해서</span>이다. 웹페이지를 구성하는 코드의 양이 많은 것을 무겁다라고 표현하는데 이것이 무거울수록 웹 페이지의 로딩 속도와 성능은 저하된다. </p>
<p>로딩이 오래 걸릴수록 유저가 이탈할 확률이 높아지기 때문에 로딩 속도를 개선할 방법이 필요했고 그 중 대표적인 방법이 브라우저에서 서버로 요청하는 파일의 숫자를 줄이는 것이었다. 웹팩이 없다면 각 자원들을 일일히 서버에 요청해야 하지만 웹팩이 있다면 같은 타입의 파일들은 묶어서 요청 및 응답을 받을 수 있기 때문에 네트워크 코스트가 훨씬 적어졌다.</p>
<p>또한 Webpack loader를 사용하면 일부 브라우저에서 지원하지 않는 ES6의 문법들을 ES5로 번환해주는 babel-loader를 사용할 수 있게 된다. Vue인 경우는 vue-loader를 scss 파일 같은 경우는 css 파일로 변환해주는 scss-loader 등의 loader도 사용할 수 있기 때문에 개발자가 원하는 방식을 선택해 개발할 수 있다.</p>
<p>Webpack4 버전 이상부터는 Develoment, Production 두 가지 모드를 지원한다. Production 모드로 번들링을 진행할 경우 코드 난독화, 압축, 최적화(Tree Shaking) 작업을 지원한다. 한마디로 상용화 된 프로그램을 사용자가 느끼기에 더욱 쾌적한 환경 및 보안까지 신경쓰면서 노출시킬 수 있다는 점에서 웹팩의 필요성은 굉장히 높은 편이라고 할 수 있다.</p>
<h2 id="웹팩-핵심-개념">웹팩 핵심 개념</h2>
<h3 id="target">Target</h3>
<p>웹팩은 다양한 환경과 target(기본값은 web)을 컴파일한다.  이 부분에는 web 외에도 다양한 환경을 컴파일 할 수 있는데 esX를 넣으면 지정된 ECMAScript 버전으로 컴파일할 수 있다.</p>
<pre><code class="language-js">module.exports = {
  target: [&quot;web&quot;, &quot;es5&quot;],
};</code></pre>
<h3 id="entry">Entry</h3>
<p>Entry 속성은 Entry point라고도 하며 웹팩이 내부의 디펜던시 그래프를 생성하기 위해 사용해야 하는 모듈이다. 웹팩은 이 Entry point를 기반으로 직간접적으로 의존하는 다른 모듈과 라이브러리를 찾아낼 수 있다.</p>
<pre><code class="language-js">//기본 값
module.exports = {
    ...
  entry: &quot;./src/index.js&quot;,
};

//지정 값
module.exports = {
    ...
  entry: &quot;./src/script.js&quot;,
};</code></pre>
<h3 id="output">Output</h3>
<p>Output 속성은 생성된 번들을 내보낼 위치와 이 파일의 이름을 지정하는 방법을 웹팩에 알려주는 역할이다. 기본 출력 파일의 경우에는 <code>./dist/main.js</code>로, 생성된 기타 파일의 경우에는 <code>./dist</code> 폴더로 설정된다.</p>
<pre><code class="language-js">const path = require(&#39;path&#39;);

module.exports = {
    ...
  output: {
    // path 속성을 사용할 때는 path 모듈을 사용해야한다.
    path: path.resolve(__dirname, &quot;docs&quot;), // 절대 경로로 설정을 해야 합니다. 
    filename: &quot;app.bundle.js&quot;,
    clean: true
  },
};</code></pre>
<h3 id="loader">Loader</h3>
<p>웹팩은 기본적으로 Javascript와 JSON 파일만 이해한다. 하지만 loader을 사용하면 웹팩이 다른 유형의 파일을 처리하거나 유효한 모듈로 변환해 애플리케이션에 사용하거나 디펜던시 그래프에 추가할 수 있다. </p>
<ul>
<li><code>test</code> : 변환이 필요한 파일들 식별하기 위한 속성(<strong>필수</strong>)</li>
<li><code>use</code> : 변환을 수행하는데 사용되는 로더를 가리키는 속성(<strong>필수</strong>)</li>
<li><code>exclude</code> : 바벨로 컴파일하지 않을 파일이나 폴더를 지정(반드시 컴파일해야 할 파일이나 폴더는 <code>include</code>로 지정 가능)</li>
</ul>
<p>🚨 <strong>속성을 넣기 위해서는 <code>module.rules</code> 아래에 정의해야 한다</strong> 🚨</p>
<pre><code class="language-js">module.exports = {
    ...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, &quot;css-loader&quot;],
        exclude: /node_modules/,
      },
    ],
  },
};</code></pre>
<h3 id="plugins">Plugins</h3>
<p>Plugins를 사용하면 번들을 최적화하거나 에셋을 관리하고 환경변수 주입 등의 광범위한 작업을 수행할 수 있다.</p>
<pre><code class="language-js">const webpack = require(&#39;webpack&#39;);
const HtmlWebpackPlugin = require(&quot;html-webpack-plugin&quot;);
const MiniCssExtractPlugin = require(&quot;mini-css-extract-plugin&quot;);

module.exports = {
  ...
  plugins: [
    // 생성된 모든 번들을 자동으로 삽입하여 애플리케이션용 HTML 파일을 생성
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, &quot;src&quot;, &quot;index.html&quot;),
    }),
    // CSS를 별도의 파일로 추출해 CSS를 포함하는 JS 파일 당 CSS 파일을 작성해주게 지원
    new MiniCssExtractPlugin(),
  ],
};</code></pre>
<p>플러그인을 사용하기 위해서는 require()를 통해 먼저 요청해야한다. 그리고 plugins 배열에 사용하고자 하는 플러그인을 추가해야 한다. 대부분의 플러그인은 사용자가 옵션을 통해 지정할 수 있다. 다른 목적으로 플러그인을 여러 번 사용하도록 설정할 수 있기 때문에 new 연산자를 사용해 호출하여 플러그인의 인스턴스를 만들어줘야 한다.</p>
<h3 id="optimization">Optimization</h3>
<p>웹팩은 버전4부터 선택한 항목에 따라 최적화를 진행한다. 최적화하기 위해 다양한 옵션이 지원되는데 대표적으로 <code>minimize</code>와 <code>minimizer</code>를 사용한다.</p>
<ul>
<li><code>minimize</code> : TerserPlugin 또는 optimization.minimize에 명시된 plugins로 bundle 파일을 최소화(압축)시키는 작업 여부를 결정</li>
<li><code>minimizer</code> : defualt minimizer을 커스텀된 TerserPlugin 인스턴스를 제공해서 재정의할 수 있습니다.</li>
</ul>
<pre><code class="language-js">module.exports = {
  ...
  optimization: {
    minimizer: [
      // mini-css-extract-plugin 에 관련된 번들을 최소화
      new CssMinimizerPlugin(),
    ]
  }
};</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자료구조] Stack과 Queue]]></title>
            <link>https://velog.io/@3hee_11/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Stack%EA%B3%BC-Queue</link>
            <guid>https://velog.io/@3hee_11/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Stack%EA%B3%BC-Queue</guid>
            <pubDate>Tue, 20 Sep 2022 12:34:55 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/3hee_11/post/d179d6cc-3371-4129-b6ce-00b7c126a725/image.png" alt=""></p>
<blockquote>
<p><strong>자료구조란?</strong>
자료구조는 여러 데이터의 묶음을 저장하고 사용하는 방법을 정의한 것이다. 데이터를 체계적으로 정리하여 저장하는 것이 데이터를 사용할 때 유리하므로 자료구조를 잘 활용하는 것이 좋다.</p>
</blockquote>
<p>자료 구조를 눈으로 볼 수 있는 사이트
<a href="https://visualgo.net/en">VisuAlgo</a>
<a href="https://www.cs.usfca.edu/~galles/visualization/Algorithms.html">Data Structure Visualizations</a></p>
<h2 id="stack">Stack</h2>
<h3 id="stack이란">Stack이란?</h3>
<p>Stack은 데이터를 순서대로 쌓는 자료구조이다. 일상 생활에서 예를 들면 끝이 막혀있는 골목에 차들이 들어오는 걸 생각하면 된다. 끝이 막혀있으니 차는 계속 쌓일 것이고 여기서 탈출하려면 맨 마지막에 들어온 차부터 빠져나와야 한다. 여기서 골목은 Stack, 자동차는 데이터로 비유할 수 있다. </p>
<h3 id="stack의-특징">Stack의 특징</h3>
<ul>
<li>LIFO(Last In First Out, 후입선출)
👉 이러한 특성으로 인해 스택은 조회가 필요하지않으므로 데이터를 저장하고 검색하는 프로세스가 빠르며 최상위 블록에서 데이터를 저장하고 검색하면 된다는 장점이 있다.</li>
<li>데이터는 하나씩 넣고 뺄 수 있다.</li>
<li>하나의 입출력 방향을 가지고 있다.</li>
<li>저장되는 데이터는 유한하고 정적이어야 한다.</li>
<li>스택의 크기는 제한되어 있다.</li>
</ul>
<h3 id="stack-예시">Stack 예시</h3>
<p>컴퓨터에서 Stack이 대표적으로 사용되는 곳은 브라우저의 앞으로 가기, 뒤로 가기 기능이다. </p>
<ul>
<li>새로운 페이지로 접속할 때 현재 페이지를 Prev Stack에 보관한다.</li>
<li>뒤로 가기 버튼을 눌러 이전 페이지로 돌아갈 때에는 현재 페이지를 Next Stack에 보관하고 Prev Stack에 가장 나중에 보관된 페이지를 현재 페이지로 가져온다.</li>
<li>앞으로 가기 버튼을 눌러 앞서 방문한 페이지로 이동을 원할 때에는 Next Stack의 가장 마지막으로 보관된 페이지를 가져온다.</li>
<li>마지막으로 현재 페이지를 Prev Stack에 보관한다.</li>
</ul>
<h2 id="queue">Queue</h2>
<h3 id="queue란">Queue란?</h3>
<p>큐는 줄을 서서 기다리다, 대기 행렬이라는 뜻을 가지고 있다. 일상 생활에서 예를 들면 고속도로를 지나는 차의 모습을 생각하면 된다. 가장 먼저 톨게이트에 진입한 차가 가장 먼저 톨게이트를 통과한다. 여기서 고속도로의 톨게이트를 Queue, 자동차는 데이터에 비유할 수 있다. </p>
<h3 id="queue의-특징">Queue의 특징</h3>
<ul>
<li>FIFO(First In First Out, 선입선출)</li>
<li>데이터는 하나씩 넣고 뺄 수 있다.</li>
<li>두 개의 입출력 방향을 가지고 있다.
데이터를 넣는 것을 <code>enqueue</code>, 꺼내는 것을 <code>dequeue</code>라고 한다.</li>
</ul>
<h4 id="enqueue-기능">Enqueue 기능</h4>
<p>Enqueue는 큐 자료구조에 데이터를 넣는 기능을 수행한다. 앞서 비유한 톨게이트에 자동차들이 줄을 서있다면 톨게이트 맨앞에 있는 자동차를 front라 하고 마지막에 있는 자동차를 rear라고 부른다.</p>
<p>1번 자동차가 Enqueue되면 front와 rear 모두 1번 자동차를 가리킨다.
<img src="https://velog.velcdn.com/images/3hee_11/post/47405292-1d11-4032-a336-49df2e2029b6/image.png" alt=""></p>
<p>다음으로 2번 자동차가 Enqueue되면 front는 고정이고 rear만 나중에 들어온 2번 자동차를 가리킨다. 
<img src="https://velog.velcdn.com/images/3hee_11/post/d1d48e25-bb0e-45d0-8fce-f844ee40103c/image.png" alt=""></p>
<p>이런 식으로 rear 인덱스가 점점 증가된다.
<img src="https://velog.velcdn.com/images/3hee_11/post/0f1a0b20-6369-49b0-b995-ea8d4e8610f3/image.png" alt=""></p>
<h4 id="dequeue-기능">Dequeue 기능</h4>
<p>Dequeue는 반대로 Queue에서 데이터를 내보내는 기능을 수행한다. 보통은 Dequeue 기능을 수행하고 front의 인덱스를 증가시키는데 이렇게 되면 rear이 배열의 마지막 인덱스를 가리키게 되면서 앞에 남아있는 (삽입 중간에 Dequeue되어 비어있는 공간) 공간을 활용할 수 없게 된다. 이 방식을 해결하기 위해서 아래 그림처럼 Dequeue를 할때 front를 고정시킨 채 뒤에 남아있는 데이터를 앞으로 한칸씩 당기거나 원형 큐를 사용한다.</p>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/0f1a0b20-6369-49b0-b995-ea8d4e8610f3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/c014a6e6-da07-4e67-8cdd-bfa4702c7735/image.png" alt=""></p>
<h3 id="queue-예시">Queue 예시</h3>
<p>컴퓨터 장치들 사이에서 데이터를 주고받을 때 각 장치 사이에 존재하는 속도의 차이나 시간 차이를 극복하기 위해 임시 기억 장치의 자료구조로 Queue를 사용한다. 이것을 통틀어 버퍼라고 한다.</p>
<p>대부분의 컴퓨터 장치에서 발생하는 이벤트는 불규칙적으로 발생한다. 이에 비해 CPU와 같이 발생한 이벤트를 처리하는 장치는 일정한 처리 속도는 갖는다. 불규칙적으로 발생한 이벤트를 규칙적으로 처리하기 위해 버퍼를 사용한다.</p>
<blockquote>
<p><strong>컴퓨터와 프린터 사이의 데이터 통신 정리</strong></p>
</blockquote>
<ul>
<li>CPU와 프린터의 속도를 비교하면 상대적으로 CPU가 데이터를 처리하는 속도가 빠르다.</li>
<li>따라서 <strong>CPU는 빠른 속도로 인쇄에 필요한 데이터를 만든 다음, 인쇄 작업 Queue에 저장하고 다른 작업을 수행</strong>한다.</li>
<li><strong>프린터는 인쇄 작업 Queue에서 데이터를 받아 일정한 속도로 인쇄</strong>한다.</li>
</ul>
<p>동영상 스트리밍을 통해 동영상을 시청할 때 다운로드된 데이터가 영상을 재생하기에 충분하지 않은 경우가 있다. 이때 동영상을 정상적으로 재생하기위해 Queue에 모아두었다가 충분한 양의 데이터가 모이면 동영상을 재생한다. </p>
<h3 id="참고">참고</h3>
<p><a href="https://lktprogrammer.tistory.com/47?category=676210">선형 큐 (Linear Queue) 자료구조</a></p>
<p><a href="https://lktprogrammer.tistory.com/59">원형 큐 (Circular Queue) 자료 구조</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🍪 Cookie에 대해 알아보자]]></title>
            <link>https://velog.io/@3hee_11/Cookie%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@3hee_11/Cookie%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Tue, 13 Sep 2022 03:05:53 GMT</pubDate>
            <description><![CDATA[<p>🚨 <strong>HTTP는 <a href="https://velog.io/@3hee_11/HTTP-HTTP-%EA%B8%B0%EB%B3%B8">무상태(Stateless) 프로토콜</a>이다.</strong> 클라이언트와 서버가 요청과 응답을 주고 받으면 연결이 끊어진다.
👉 클라이언트가 다시 요청하면 서버는 이전 요청을 기억하지 못한다.</p>
<h3 id="쿠키란">쿠키란?</h3>
<ul>
<li>서버가 웹 브라우저에 정보를 저장하고 불러올 수 있는 수단이다. 해당 도메인에 대한 쿠키가 존재하면 웹 브라우저는 도메인에게 http 요청 시 쿠키를 함께 전달한다.</li>
<li>사용자 로그인 세션 관리, 광고 정보 트래킹에 사용된다.</li>
<li>쿠키 정보는 생성된 이후 항상 서버에 전송되기 때문에 네트워크 트래픽을 더 유발한다.
👉 최소한의 정보만 사용해야 함(세션 id, 인증 토큰)
🔎 서버 전송말고 웹 브라우저 내부에 저장하고 싶다면 웹 스토리지 참고</li>
</ul>
<p>💀 <strong>주의</strong> : 보안에 민감한 데이터는 저장하면 안됨(주민번호, 신용카드 번호 등)</p>
<h3 id="쿠키-사용">쿠키 사용</h3>
<ul>
<li><strong>Set-Cookie</strong> : 서버에서 클라이언트로 쿠키 전달
예) set-cookie: sessionId=abcde1234; expires=Sat, 26-Dec-2020 00:00:00 GMT; path=/; <a href="http://domain%3D.google.com/">domain=.google.com</a>; Secure</li>
<li><strong>Cookie</strong> : 클라이언트가 서버에서 받은 쿠키를 저장하고, HTTP 요청시 서버로 전달</li>
</ul>
<p><strong>🍪 쿠키를 사용하면?</strong>
클라이언트가 요청으로 데이터를 줬을 때 <strong>서버는 쿠키 저장소에 데이터를 저장</strong>한다. 다음에 <strong>클라이언트가 요청할 때 쿠키 저장소를 조회</strong>해서 조회된 쿠키를 포함하여 요청한다.</p>
<h3 id="쿠키-옵션">쿠키 옵션</h3>
<h4 id="생명-주기">생명 주기</h4>
<ul>
<li><strong>expires</strong> : 만료일이 되면 쿠키 삭제
예) Set-Cookie: expires=Sat, 26-Dec-2020 04:39:21 GMT</li>
<li><strong>max-age</strong> : 쿠키가 유효한 시간을 초단위로 설정, 0이나 음수를 지정하면 쿠키 삭제
예) Set-Cookie: max-age=3600 (3600초)</li>
<li>세션 쿠키: <code>MaxAge</code>나 <code>Expires</code> 옵션이 없는 쿠키로 브라우저가 실행 중일 때만 사용할 수 있는 임시 쿠키. 브라우저를 종료하면 해당 쿠키 삭제</li>
<li>영속 쿠키: 브라우저 종료 여부와 상관없이 <code>MaxAge</code>나 <code>Expires</code> 옵션에 지정된 시간만큼 쿠키 사용 가능</li>
</ul>
<h4 id="도메인domain">도메인(domain)</h4>
<ul>
<li><strong>명시</strong> : 명시한 문서 기준 도메인 + 서브 도메인(도메인 앞에 있는 <code>www</code>같은 것) 포함<ul>
<li>domain=example.org를 지정해서 쿠키 생성
👉 example.org, dev.example.org도 쿠키 접근</li>
</ul>
</li>
<li><strong>생략</strong> : 현재 문서 기준 도메인만 적용<ul>
<li>example.org 에서 쿠키를 생성하고 domain 지정을 생략
👉 example.org 에서만 쿠키 접근</li>
</ul>
</li>
</ul>
<h4 id="경로path">경로(path)</h4>
<ul>
<li>적은 경로를 포함한 하위 경로 페이지(<code>/user/login</code>)만 쿠키 접근</li>
<li>일반적으로 <code>path=/</code> 루트로 지정</li>
<li>설정된 경로를 포함하는 하위 경로로 요청을 해도 쿠키를 서버에 전송할 수 있다. <code>path=/user</code>라면 <code>/user/login</code>인 경우에도 쿠키 전송 가능</li>
</ul>
<h4 id="보안">보안</h4>
<ul>
<li><strong>Secure</strong><ul>
<li>Secure이 <code>true</code>인 경우 프로토콜이 https인 경우에만 전송한다.</li>
</ul>
</li>
<li><strong>HttpOnly</strong><ul>
<li><code>true</code>인 경우 자바스크립트에서 접근 불가(document.cookie)</li>
<li>XSS 공격 방지</li>
<li>HTTP 전송에만 사용</li>
</ul>
</li>
<li><strong>SameSite</strong><ul>
<li>XSRF(or CSRF) 공격 방지</li>
<li><code>Lax</code> : Cross-Origin 요청이라면 GET 메소드에 대해서만 쿠키 전송</li>
<li><code>Strict</code> : Cross-Origin이 아닌 <code>same-site</code> 인 경우에만 쿠키 전송</li>
<li><code>None</code> : 항상 쿠키를 전송할 수 있지만 Secure 옵션이 추가로 필요함</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[네트워크] 네트워크 계층 모델]]></title>
            <link>https://velog.io/@3hee_11/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EA%B3%84%EC%B8%B5-%EB%AA%A8%EB%8D%B8</link>
            <guid>https://velog.io/@3hee_11/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EA%B3%84%EC%B8%B5-%EB%AA%A8%EB%8D%B8</guid>
            <pubDate>Thu, 08 Sep 2022 05:49:21 GMT</pubDate>
            <description><![CDATA[<h2 id="osi-7계층">OSI 7계층</h2>
<h3 id="osi-7계층-모델-왜-등장했을까">OSI 7계층 모델 왜 등장했을까?</h3>
<p>해당 계층 모델은 국제표준화 기구에서 제정한 표준 규격이다. 왜 제정했냐면 과거에는 같은 회사에서 만든 컴퓨터끼리만 통신할 수 있었기 때문에 다른 회사의 시스템이라도 네트워크 유형에 관계없이 상호 통신 가능한 규약이 필요했다. 그래서 제조사에 상관없이 사용할 수 있는 네크워크 표준 규격을 정의했다.</p>
<p>OSI 7계층 모델은 네트워크를 이루고 있는 구성요소들을 7단계로 나누고 각 계층의 표준을 정했다. OSI 7계층 모델의 목적은 표준화를 통해 포트, 프로토콜의 호환 문제를 해결하는 것이다</p>
<h3 id="osi-7계층-구조">OSI 7계층 구조</h3>
<h4 id="✅-1단계---물리계층physical-layer">✅ 1단계 - 물리계층(Physical Layer)</h4>
<p>시스템 간의 물리적인 연결과 전기 신호를 변환 및 제어하는 계층이다. 주로 전기 신호를 전달하는데 초점을 두고 들어온 전기 신호를 그대로 잘 전달하는 것이 목적이다. <code>CDMA, GSM, NICs, CSMA/CD, Fiber</code></p>
<h4 id="✅-2단계---데이터링크-계층">✅ 2단계 - 데이터링크 계층</h4>
<p>네트워크 기기 간의 데이터 전송 및 물리주소를 결정하는 계층이다. 물리 계층에서 들어온 전기 신호를 모아 알아볼 수 있는 데이터 형태로 처리한다. 이 계층에서 주소 정보를 정의하고 출발지와 도착지 주소를 확인한 후에 데이터 처리를 진행한다. <code>FDDI, Ethernet, PPP</code></p>
<h4 id="✅-3단계---네트워크-계층">✅ 3단계 - 네트워크 계층</h4>
<p>실제 네트워크 간에 데이터 라우팅을 담당한다. 이때 라우팅이란 어떤 네트워크 안에서 통신 데이터를 짜여진 알고리즘에 의해 최대한 빠르게 보낼 최적의 경로를 선택한 과정이다. <code>IP, ICMP</code></p>
<h4 id="✅-4단계---전송-계층">✅ 4단계 - 전송 계층</h4>
<p>컴퓨터간 신뢰성 있는 데이터를 서로 주고받을 수 있도록 하는 서비스를 제공하는 계층이다. 전송 계층에서는 데이터들이 실제로 정상적으로 보내지는지 확인하는 역할을 한다. 네트워크 계층에서 사용되는 패킷이 유실되거나 순서가 바뀌는 경우 이를 바로 잡아주는역할도 담당한다. <code>TCP, UDP, NETDEUI</code></p>
<h4 id="✅-5계층---세션-계층">✅ 5계층 - 세션 계층</h4>
<p>세션 연결의 설정과 해제, 세션 메시지 전송 등의 기능을 수행하는 계층이다. 즉, 컴퓨터간의 통신 방식에 대해 결정하는 계층이라고 할 수 있다. 쉽게 말해, 양 끝 단의 프로세스가 연결을 성립하도록 도와주고 작업을 마친 후에는 연결을 끊는 역할을 한다. <code>RPC, SQL, NETBOIS, Sockets</code></p>
<h4 id="✅-6계층---표현-계층">✅ 6계층 - 표현 계층</h4>
<p>응용 계층으로 전달하거나 전달받는 데이터를 인코딩 또는 디코딩하는 계층이다. <code>GIF, JPEG, MPEG, MIME, ZIP, ASCII</code></p>
<h4 id="✅-7계층---응용-계층">✅ 7계층 - 응용 계층</h4>
<p>최종적으로 사용자와의 인터페이스를 제공하는 계층으로 사용자가 실행하는 응용 프로그램(ex. Google Chrome)들이 해당 계층에 속한다. <code>HTTP, DNS, SSL, SMTP, FTP</code></p>
<h3 id="데이터-캡슐화">데이터 캡슐화</h3>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/3bd9f877-dfc3-4779-af9a-e7eb5a5a5dec/image.png" alt=""></p>
<p>OSI 7계층 모델은 송신 측의 7계층과 수신 측의 7계층을 통해 데이터를 주고받는다. 데이터를 전송하는 쪽은 데이터를 보내기 위해 상위 계층에서 하위 계층으로 데이터를 전달한다. 이때 각 계층에서 필요한 정보를 데이터에 추가하는데 이 정보를 헤더라고 하고 헤더를 붙여나가는 것을 캡슐화라고 한다.</p>
<p>마지막 물리 계층에 도달하면 송신 측의 데이터링크 계층에서 만들어진 데이터가 전기 신호로 변환되어 수신 측에 전송된다.</p>
<p>데이터를 받는 쪽은 하위 계층에서 상위 계층으로 각 계층을 통해 전달된 데이터를 받는다. 이때 상위 계층으로 데이터를 전달하면서 각 계층에서 헤더를 제거하는 것을 역캡슐화라고 한다. 역캡슐화를 통해 마지막 응용 게층에 도달하면 원본 데이터만 남게 된다.</p>
<h2 id="tcpip-4계층-모델">TCP/IP 4계층 모델</h2>
<h3 id="tcpip-4계층-구조">TCP/IP 4계층 구조</h3>
<h4 id="✅-4계층---어플리케이션-계층">✅ 4계층 - 어플리케이션 계층</h4>
<p>OSI 계층의 세션 계층, 표현 계층, 응용 계층에 해당하며 TCP/UDP 기반의 응용 프로그램을 구현할 때 사용한다.</p>
<h4 id="✅-3계층---전송-계층">✅ 3계층 - 전송 계층</h4>
<p>OSI 계층의 전송 계층에 해당하며 통신 노드간의 연결을 제어하고, 신뢰성 있는 데이터 전송을 담당한다.</p>
<h4 id="✅-2계층---인터넷-계층">✅ 2계층 - 인터넷 계층</h4>
<p>OSI 계층의 네트워크 계층에 해당하며 통신 노드 간의 IP 패킷을 전송하는 기능 및 라우팅을 담당한다.</p>
<h4 id="✅-1계층---네트워크-인터페이스-계층">✅ 1계층 - 네트워크 인터페이스 계층</h4>
<p>OSI 계층의 물리 계층과 데이터 링크 계층에 해당하며 물리적인 주소로 MAC을 사용한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[네트워크] IP, TCP, UDP]]></title>
            <link>https://velog.io/@3hee_11/IP-TCP-UDP</link>
            <guid>https://velog.io/@3hee_11/IP-TCP-UDP</guid>
            <pubDate>Thu, 08 Sep 2022 05:47:15 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/3hee_11/post/a289c1cf-c0ee-4f38-b326-ff4f5c5a1251/image.png" alt=""></p>
<h3 id="패킷교환-방식">패킷교환 방식</h3>
<p>패킷교환 방식은 패킷이라는 단위로 데이터를 잘게 나누어 전송하는 방식이다. 각 패킷에는 출발지와 목적지 정보가 있기 때문에 가장 효율적인 방식으로 이동할 수 있다. </p>
<h3 id="ip인터넷-프로토콜">IP(인터넷 프로토콜)</h3>
<p>IP는 출발지와 목적지의 정보를 IP 주소라는 특정한 숫자값으로 표기하고 패킷단위로 데이터를 전송하게 되었다. </p>
<h3 id="ip-프로토콜의-한계">IP 프로토콜의 한계</h3>
<ul>
<li>비연결성 : 패킷을 받을 대상이 없거나 서비스 불능 상태여도 패킷 전송</li>
<li>비신뢰성 : 중간에 패킷이 사라질 수도 있고 패킷의 순서도 보장할 수 없음</li>
</ul>
<h3 id="tcp">TCP</h3>
<h4 id="연결-지향---tcp-3-way-handshake가상-연결">연결 지향 - TCP 3 way handshake(가상 연결)</h4>
<ol>
<li>클라이언트는 서버에 접속을 요청하는 SYN(Synchronize) 패킷을 보낸다.</li>
<li>서버는 SYN 요청을 받고 클라이언트에게 요청을 수락한다는 ACK(Acknowledgment)와 SYN가 설정된 패킷을 발송하고 클라이언트가 다시 ACK로 응답하기를 기다린다.</li>
<li>클라이언트가 서버에게 ACK를 보내면 이후에는 연결이 성립되며 데이터를 전송할 수 있다.</li>
</ol>
<p>만약 서버가 꺼져있다면 클라이언트가 SYN을 보내고 서버에서 응답이 없기 때문에 데이터를 보내지 않는다. 현재에는 최적화가 이루어져 3번에서 클라이언트가 ACK를 보낼때 데이터를 함께 보내기도 한다.</p>
<h4 id="데이터-전달-보증">데이터 전달 보증</h4>
<p>TCP는 데이터 전송이 성공적이라면 이에 대한 응답을 돌려주기 때문에 IP 패킷의 한계인 비연결성을 보완할 수 있다.</p>
<h4 id="순서-보장">순서 보장</h4>
<p>만약 패킷이 순서대로 도착하지 않는다면 TCP 세그먼트에 있는 정보로 다시 패킷 전송을 요청할 수 있기 때문에 IP 패킷의 한계인 비신뢰성을 보완할 수 있다.</p>
<h4 id="신뢰할-수-있는-프로토콜">신뢰할 수 있는 프로토콜</h4>
<h3 id="udp사용자-데이터그램-프로토콜-user-datagram-protocol">UDP(사용자 데이터그램 프로토콜, User Datagram Protocol)</h3>
<ul>
<li>흰 도화지에 비유</li>
<li>비 연결지향</li>
<li>데이터 전달 보증 안됨</li>
<li>순서 보장 안됨</li>
<li>⭐ 단순하고 빠르기때문에 신뢰성보다 연속성이 중요한 서비스(ex. 실시간 스트리밍)에 자주 사용됨</li>
</ul>
<p>UDP는 IP 프로토콜에 PORT, 체크섬 필드 정보만 추가된 단순한 프로토콜이다. TCP보다 신뢰성은 낮지만 3 way handshake 방식을 사용하지 않아 상대적으로 속도가 빠르다. HTTP3는 UDP를 사용하며 이미 여러 기능이 구현된 TCP보다 UDP는 커스터마이징이 가능하다는 장점이 있다.</p>
<h3 id="📌-결론">📌 결론</h3>
<p>TCP가 가지고 있는 기능들을 UDP는 가지고 있지 않기 때문에 신뢰성이 낮지만 속도는 상대적으로 빠르다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹 표준과 웹 접근성]]></title>
            <link>https://velog.io/@3hee_11/%EC%9B%B9-%ED%91%9C%EC%A4%80%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@3hee_11/%EC%9B%B9-%ED%91%9C%EC%A4%80%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Mon, 05 Sep 2022 07:10:20 GMT</pubDate>
            <description><![CDATA[<h2 id="웹-표준">웹 표준</h2>
<h3 id="웹-표준이란">웹 표준이란?</h3>
<p><a href="https://www.w3.org/">W3C</a>에서 권고하는 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>웹에서 표준적으로 사용되는 기술이나 규칙</span>이다. <strong>사용자의 환경(운영체제, 브라우저)에 상관없이 웹페이지가 동일하게 보이고 잘 작동할 수 있도록</strong> 하는 웹 페이지 제작 기법을 담고있다.</p>
<blockquote>
<p><strong>🤔 웹 표준이 왜 필요한가요?</strong>
웹 표준이 없다면 익스플로러에서는 정상적으로 보이던 페이지가 다른 브라우저에서는 작동이 되지 않는 일이 생길 수 있다. 이를 막기 위해 개발자들이 브라우저마다 따로 개발을 해줄 수도 있겠지만 이는 매우 비효율적인 일이기 때문에 웹 개발의 형식을 통일시킨 웹 표준이 필요하다.</p>
</blockquote>
<h3 id="웹-표준의-장점">웹 표준의 장점</h3>
<h4 id="✅-유지보수의-용이성">✅ 유지보수의 용이성</h4>
<p>웹 표준으로 HTML, CSS, JS 등의 사용법을 정리하기 전에는 구조, 표현, 동작이 섞여있는 코드가 많았다. 그렇기 때문에 어느 한 부분을 수정하려면 코드 전체를 고쳐야할 때도 있었다. 웹 표준으로 각 영역이 분리된 후에는 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>유지보수가 용이</span>해졌고 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>코드가 경량화되면서 트래픽 비용도 감소</span>했다. </p>
<h4 id="✅-웹-호환성-확보">✅ 웹 호환성 확보</h4>
<p>웹 표준을 준수하여 웹 사이트를 만들면 브라우저의 종류나 버전, 운영 체제나 기기 종류에 상관없이 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>항상 동일한 결과가 나오도록</span> 할 수 있다.</p>
<h4 id="✅-검색-효율성-증가">✅ 검색 효율성 증가</h4>
<p>웹 표준에 맞춰 웹 사이트를 만들면 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>검색 엔진에서 더 높은 우선 순위로 노출</span>될 수 있다. 검색 엔진은 정보를 수집할 때 HTML 파일의 구조를 고려하는데 웹 표준에서 요소의 사용, 정확한 정보 작성 등의 내용도 다루고 있기 때문이다.</p>
<h4 id="✅-웹-접근성-향상">✅ 웹 접근성 향상</h4>
<p>웹 표준에 맞춰 사이트를 제작하면 브라우저나 운영체제, 기기의 종류에 상관없이 웹에 접근할 수 있다. </p>
<h3 id="semantic-html">Semantic HTML</h3>
<p><span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>Semantic HTML은 말 그대로 구조적이고 의미있는 HTML을 지향하는 것</span>이다. 그렇다면 의미있는 HTML이란 무엇일까? </p>
<p>웹 사이트가 div만으로 구성돼 있다고 가정해보자 화면을 구성하는데 문제는 없겠지만 각 요소가 어떤 역할을 하는지 알아보는 건 쉽지 않을 것이다. </p>
<p>아래와 같이 다른 종류의 요소를 사용한다면 어떨까? 각 요소의 이름만 보고도 화면에서 어떤 역할을 할지, 어떤 내용을 담게 될지 알 수 있다. 이렇게 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>요소가 어떤 내용을 담게 될지, 어떤 기능을 하게 될지 확실하게 의미를 가지고 있는 요소를 시맨틱 요소</span>라고 한다.</p>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/8b3f0f97-f05e-4839-be83-b60d9f6d7c55/image.png" alt=""></p>
<h3 id="시맨틱-html의-필요성">시맨틱 HTML의 필요성</h3>
<h4 id="✅-개발자간-소통">✅ 개발자간 소통</h4>
<p>여러 명의 개발자와 같이 협업을 한다고 가정해보자. div나 span만을 사용해 화면을 구성한다면 각 요소가 어떤 기능을 하는지 바로 파악할 수 없기 때문에 주석을 작성하거나 id, class를 사용해야한다. 시맨틱 요소를 사용한다면 이런 문제를 해결할 수 있다.</p>
<h4 id="✅-검색-효율성">✅ 검색 효율성</h4>
<p>앞서 말했듯이 검색 엔진은 HTML 코드를 보고 문서의 구조를 파악한다. 그렇기 때문에 div나 span 대신 시맨틱 요소를 사용하면 어떤 요소가 더 중요한 내용을 담고 있는지 우선 순위를 정할 수 있고 우선 순위가 높다고 판단된 페이지가 검색 결과 상단에 표시된다.</p>
<h4 id="✅-웹-접근성">✅ 웹 접근성</h4>
<p>웹 접근성은 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>나이, 성별, 사용 환경 등의 여부를 떠나 항상 동일한 수준의 정보를 제공</span>할 수 있어야 함을 뜻한다. 예시로 시각 장애인의 경우 음성으로 화면을 읽게 되는데, 이 때 HTML이 시맨틱하게 구성되어 있다면 화면의 구조에 대한 정보까지 추가로 전달할 수 있어 컨텐츠를 더 정확하게 전달할 수 있다. </p>
<h3 id="시맨틱-요소의-종류">시맨틱 요소의 종류</h3>
<ul>
<li><code>&lt;header&gt;</code> : 페이지나 해당 섹션의 가장 윗부분에 위치하며 사이트의 제목이 보통 들어간다. 선택적으로 상단바나 검색창 등이 안에 들어갈 수 있다.</li>
<li><code>&lt;nav&gt;</code> : 내비게이션의 약자로 상단바 등 사이트를 안내하는 요소에 사용된다. 보통은 안에 <code>&lt;ul&gt;</code>을 넣어 목록 형태로 사용한다.</li>
<li><code>&lt;main&gt;</code>: 문서의 주된 콘텐츠를 표시한다.</li>
<li><code>&lt;article&gt;</code> : 독립적이고 자체 포함된 콘텐츠를 지정한다.</li>
<li><code>&lt;section&gt;</code>: 문서의 독립적인 구획을 나타내며, 딱히 적합한 의미의 요소가 없을 때 사용합니다. 제목(<code>&lt;hgroup&gt;</code>)을 포함하는 경우가 많습니다.</li>
<li><code>&lt;aside&gt;</code> : 본문의 주요 부분을 표시하고 남은 부분을 설명하는 요소이다. ex) 사이드바, 광고창</li>
<li><code>&lt;footer&gt;</code> : 페이지나 해당 파트의 가장 아랫부분에 위치하며 사이트의 라이선스, 주소, 연락처 등을 넣을 때 사용한다.</li>
<li><code>&lt;hgroup&gt;</code>: 제목을 표시할 때 사용하는 요소로, <code>&lt;h1&gt;</code> ~ <code>&lt;h6&gt;</code> 요소가 <code>&lt;hgroup&gt;</code>입니다.</li>
</ul>
<blockquote>
<p>❌ <strong>자주 틀리는 마크업</strong></p>
</blockquote>
<ul>
<li>인라인 요소 안에 블록 요소 넣기 
=&gt; 인라인 요소는 항상 블록 요소 안에 들어가야한다</li>
<li><code>&lt;b&gt;</code>, <code>&lt;i&gt;</code> 요소 사용하기 
=&gt; 시맨틱하지 않고 표현을 기준으로 이름이 지어진 요소기 때문에 <code>&lt;strong&gt;</code>, <code>&lt;em&gt;</code> 요소를 사용하는 것이 좋다.</li>
<li><code>&lt;hgroup&gt;</code> 무분별하게 사용하기
=&gt; <code>&lt;hgroup&gt;</code>는 목차의 역할을 하면서 콘텐츠의 상하 관계를 표시하기 위해 사용한다. 무분별하게 사용한다면 잘못된 화면 구조 정보를 전달할 수 있다</li>
<li><code>&lt;br /&gt;</code> 연속으로 사용하기
=&gt; <code>&lt;br /&gt;</code>은 텍스트 흐름에 줄 바꿈을 해주기 위해 사용하는 요소다. 요소 사이에 간격을 만들기 위해 남발해서는 안된다.</li>
<li>인라인 스타일링 사용하기
=&gt; 웹 표준으로 HTML, CSS, JavaScript 각 영역을 분리시킨 것을 다시 합치는 것과 같다</li>
</ul>
<h3 id="크로스-브라우징">크로스 브라우징</h3>
<p>크로스 브라우징이란 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>웹 사이트에 접근하는 브라우저의 종류에 상관 없이 <strong>동등한 화면과 기능을 제공</strong>할 수 있도록 만드는 작업</span>을 의미한다.</p>
<h3 id="크로스-브라우징-워크-플로우">크로스 브라우징 워크 플로우</h3>
<h4 id="초기-기획">초기 기획</h4>
<p>초기 기획 단계에서는 어떤 웹 사이트를 만들지 결정해야 한다. 어떤 컨텐츠와 기능이 있어야 하고 디자인은 어떻게 해야하는지 결정해야 한다. 그 다음 고객층을 생각하고 고객이 사용하는 브라우저와 기기를 고민해야 한다. 그리고 결정했다면 이에 맞는 기술을 사용해 개발한다.</p>
<h4 id="개발">개발</h4>
<p>코드를 작성할 때는 작성하고 있는 코드가 브라우저에서 호환성이 어떤지 파악해야 한다. <a href="https://developer.mozilla.org/ko/">MDN</a>, <a href="https://caniuse.com/">Can I Use </a>등의 사이트에서 코드의 호환성을 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/495eeb8c-af72-47dd-a91e-9d64ff3c9826/image.png" alt=""></p>
<h4 id="테스트">테스트</h4>
<p>기능을 구현했다면 아래와 같이 기능에 대한 테스트가 필요하다. <code>TestComplete</code>, <code>Lambda Test</code>, <code>BitBar</code> 등 자동으로 크로스 브라우징 테스트를 해주는 툴들이 있다.</p>
<blockquote>
<ul>
<li>데스크톱 브라우저(롬, 엣지, 파이어폭스, 오페라, 사파리 등)에서 테스트</li>
</ul>
</blockquote>
<ul>
<li>휴대폰 및 태플릿 브라우저(삼성 인터넷, 사파리, 안드로이드 기기의 크롬 등) 테스트</li>
<li>Window, Linux, Mac 등 다양한 운영 체제 테스트</li>
</ul>
<h4 id="수정--반복">수정 &amp; 반복</h4>
<p>테스트 단계에서 버그가 발견되었다면 버그가 발생하는 위치를 특정하고 해당 브라우저에서의 해결 방법을 찾아야 한다. 섣불리 코드를 수정하면 다른 브라우저에 영향이 생길 수 있으니 조건문을 작성해 다른 코드를 실행하는 방식이 좋다.</p>
<h2 id="seo">SEO</h2>
<h3 id="seo란">SEO란?</h3>
<p>SEO(Search Engine Optimization)는 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>검색 엔진의 작동 방식에 맞게 웹 페이지를 최적화</span>해주는 작업이다. SEO를 통해 검색 엔진에서 웹 페이지를 상위에 노출되게 만들 수 있다. SEO는 크게 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>On-Page SEO</span>와 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>Off-Page SEO</span>로 나눌 수 있다.</p>
<blockquote>
<p>💡 <strong>SEO 종류</strong></p>
</blockquote>
<ul>
<li><strong>On-Page SEO</strong>
페이지 내에서 사용할 수 있는 SEO로 제목과 컨텐츠, 핵심 키워드의 배치와 효율적인 HTML 요소 사용법을 이용하는 방법이다. </li>
<li><strong>Off-Page SEO</strong>
웹 사이트 외부에서 이루어지는 SEO로 소셜 미디어 홍보나 백링크 등을 이용하는 방법이다. 웹 페이지의 내용이나 구조와는 관계가 없다. <code>ex) 광고비를 지불해 검색 결과 상위에 노출</code></li>
</ul>
<h2 id="웹-접근">웹 접근</h2>
<h3 id="웹-접근이란">웹 접근이란?</h3>
<p>웹 접근성은 장애인, 고령자 등이 웹 사이트에서 제공하는 정보에 비장애인과 동등하게 접근하고 이해할 수 있도록 보장하는 것을 뜻한다. 웹 접근성을 갖추면 웹에 접근했을 때 항상 동등한 수준의 정보를 제공받도록 보장받을 수 있다. </p>
<h3 id="웹-접근성의-효과">웹 접근성의 효과</h3>
<h4 id="사용자층-확대">사용자층 확대</h4>
<p>웹 접근성을 확보하면 장애인, 고령자 등 정보 소외 계층도 웹 사이트를 자유롭게 이용할 수 있게 되고 그만큼 사이트의 이용자를 늘릴 수 있다.</p>
<h4 id="다양한-환경-지원">다양한 환경 지원</h4>
<p>정보 소외 계층이 아니더라도 정보에 접근하기 어려운 상황이 있을 수 있다. 웹 접근성을 향상시키면 다양한 환경에서 웹 사이트를 자유롭게 사용할 수 있게 되므로 서비스의 사용 범위가 확대된다. </p>
<h4 id="사회적-이미지-향상">사회적 이미지 향상</h4>
<p>웹 접근성 확보를 통해 기업이 정보 소외 계층을 위한 사회 공헌 및 복지 향상에 힘쓰고 있음을 보여줄 수 있다. 기업의 사회적 이미지가 향상되면 그만큼 이용자 수거 증가할  가능성이 늘어나게 된다.</p>
<h3 id="웹-콘텐츠-접근성-지침">웹 콘텐츠 접근성 지침</h3>
<h4 id="✅-인식의-용이성perceivable">✅ 인식의 용이성(Perceivable)</h4>
<p>모든 콘텐츠는 사용자가 인식할 수 있어야 한다.</p>
<ul>
<li><strong>적절한 대체 텍스트</strong><ul>
<li>텍스트가 아닌 콘텐츠는 의미나 용도를 이해할 수 있도록 대체 텍스트를 제공한다.
<code>ex) &lt;img src=&quot;귀여운 강아지.jpg&quot; alt=&quot;강아지&quot; /&gt;</code></li>
<li>배경 이미지와 같이 정보를 전달할 필요가 없는 경우 alt의 값으로 빈 문자열을 넣어 스크린 리더가 인식하지 않게 한다.</li>
<li>인접한 요소에서 이미지의 정보를 얻을 수 있는 경우 대체 텍스트를 작성하지 않는다.</li>
</ul>
</li>
<li><strong>자막 제공</strong><ul>
<li>멀티미디어 콘텐츠에는 자막, 원고 또는 수화를 제공해야한다.</li>
<li>자막을 포함하는 동영상을 사용하거나 자막을 지원하는 플랫폼을 사용한다.</li>
<li>비디오 안쪽에 <code>track</code>요소를 사용해서 자막 파일을 불러온다.
<code>&lt;video&gt;&lt;track src=&quot;자막.vtt&quot; kind=&quot;captions&quot; /&gt;&lt;/video&gt;</code></li>
</ul>
</li>
<li><strong>색에 무관한 콘텐츠 인식</strong><ul>
<li>콘텐츠는 색에 관계없이 인식될 수 있어야 한다.</li>
<li>콘텐츠에 테두리를 설정하거나 레이블을 단다.</li>
</ul>
</li>
<li><strong>명확한 지시사항 제공</strong><ul>
<li>지시사항은 모양, 크기, 위치, 방향, 색, 소리 등에 관계없이 인식될 수 있어야 한다. </li>
</ul>
</li>
<li><strong>텍스트 콘텐츠 명도 대비</strong><ul>
<li>텍스트 콘텐츠와 배경 간의 명도 대비는 4.5대 1 이상이어야 한다.</li>
</ul>
</li>
<li><strong>자동 재생 금지</strong><ul>
<li>자동 재생 금지를 해야한다면 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>1. 가장 위에 위치시켜 정지할 수 있도록 구현</span> <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>2. ESC 눌러 정지</span> <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>3. 3초 내에 정지</span>와 같은 방법으로 해결할 수 있다.</li>
</ul>
</li>
<li><strong>콘텐츠 간 구분</strong></li>
</ul>
<h4 id="✅-운용의-용이성operable">✅ 운용의 용이성(Operable)</h4>
<p>사용자 인터페이스 구성요소는 조작 가능하고 내비게이션 할 수 있어야 한다.</p>
<ul>
<li><strong>키보드 사용 보장</strong></li>
<li><strong>초점 이동</strong><ul>
<li>키보드에 의한 초점은 논리적으로 이동(왼쪽에서 오른쪽으로, 위쪽에서 아래쪽으로)해야 하며 시각적으로 구별할 수 있어야 한다.</li>
</ul>
</li>
<li><strong>조작 가능</strong><ul>
<li>사용자 입력 및 컨트롤은 조작 가능하도록 제공되어야 한다.</li>
</ul>
</li>
<li><strong>응답 시간 조절</strong><ul>
<li>시간제한이 있는 콘텐츠는 응답시간을 조절할 수 있어야 한다.</li>
<li>시간 제한이 있는 콘텐츠를 넣어야 한다면 충분한 시간, 종료 안내, 조절 수단을 제공해야 한다.</li>
</ul>
</li>
<li><strong>정지 기능 제공</strong><ul>
<li>자동으로 변경되는 콘텐츠는 움직임을 제어할 수 있어야 한다.
<code>ex) 캐러셀 슬라이드, 실시간 검색어</code></li>
</ul>
</li>
<li><strong>깜빡임과 번쩍임 사용 제한</strong><ul>
<li>초당 3~50회 주기로 깜빡이거나 번쩍이는 콘텐츠를 제공하지 않아야 한다.</li>
<li>만약 제공해야 한다면 번쩍이는 콘텐츠가 화면의 10% 미만이거나, 사전에 경고하고 중단할 수 있는 수단을 제공하거나, 시간을 3초 미만으로 제한해야한다.</li>
</ul>
</li>
<li><strong>반복 영역 건너뛰기</strong><ul>
<li>가장 앞에 건너뛰기 링크 제공, 메뉴를 필요할 때만 열 수 있도록 구현 등</li>
</ul>
</li>
<li><strong>제목 제공</strong><ul>
<li>페이지, 프레임, 콘텐츠 블록에는 적절한 제목을 제공해야 한다(특수문자는 1개만 허용)</li>
</ul>
</li>
<li><strong>적절한 링크 텍스트</strong><ul>
<li>링크 텍스트는 용도나 목적을 이해할 수 있도록 제공해야 한다.</li>
<li>링크를 설명하는 대체 텍스트를 작성해야한다.</li>
</ul>
</li>
</ul>
<h4 id="✅-이해의-용이성understandable">✅ 이해의 용이성(Understandable)</h4>
<p>콘텐츠는 이해할 수 있어야 한다.</p>
<ul>
<li><strong>기본 언어 표시</strong><ul>
<li>주로 사용하는 언어를 명시한다 <code>&lt;html lang=&quot;ko&quot;&gt;</code></li>
</ul>
</li>
<li><strong>사용자 요구에 따른 실행</strong><ul>
<li>사용자가 의도하지 않은 기능(새 창 등)은 실행되지 않아야 한다.</li>
<li>페이지 접근 시 팝업이 뜨지 않게 해야 하며 모달이 있는 경우 위에 위치시켜 제어할 수 있도록 해야한다.</li>
<li>스크린 리더 사용자는 새 창이 떴을 때 인지할 수 없으므로 새창임을 알려줘야 한다.
<code>&lt;a href=&quot;...&quot;&gt;페이지&lt;span class=&quot;blind&quot;&gt;새 창&lt;/span&gt;&lt;/a&gt;</code>
<code>&lt;a href=&quot;...&quot; title=&quot;새 창&quot;&gt;페이지&lt;/a&gt;</code>
<code>&lt;a href=&quot;...&quot; target=&quot;_blank&quot;&gt;페이지&lt;/a&gt;</code></li>
</ul>
</li>
<li><strong>콘텐츠 선형 구조</strong><ul>
<li>콘텐츠는 논리적인 순서(제목 -&gt; 내용)로 제공해야한다.</li>
</ul>
</li>
<li><strong>표의 구성</strong><ul>
<li>표는 이해하기 쉽게 구성해야 한다.</li>
<li>테이블 요소 안에 <code>caption</code>으로 표 제목 제공하기</li>
<li>제목 셀과 데이터 셀잉 구분되도록 적절하게 <code>&lt;th&gt;</code> <code>&lt;td&gt;</code> 사용하기</li>
<li>표의 구조가 복잡할 경우 <code>scope</code>나 <code>id</code>와 <code>headers</code> 속성 사용하기</li>
</ul>
</li>
<li><strong>레이블 제공</strong><ul>
<li><code>&lt;input&gt;</code> 요소에 id를 설정하고 <code>&lt;label&gt;</code> 요소의 for 속성으로 연결해준다.</li>
<li><code>&lt;input&gt;</code> 안에 <code>title</code> 속성을 사용한다.</li>
<li>WAI-ARIA의 <code>aria-label</code> 속성을 사용한다.(필요한 경우가 아니라면 사용 X)</li>
</ul>
</li>
<li><strong>오류 정정</strong><ul>
<li>입력 오류를 정정할 수 있는 방법을 제공해야 한다.</li>
</ul>
</li>
</ul>
<h4 id="✅-견고성robust">✅ 견고성(Robust)</h4>
<p>웹 콘텐츠는 미래의 기술로도 접근할 수 있도록 견고하게 만들어야 한다.</p>
<ul>
<li><strong>마크업 오류 방지</strong></li>
<li><strong>웹 애플리케이션 접근성 준수</strong></li>
</ul>
<h3 id="wai-aria">WAI-ARIA</h3>
<p>WAI-ARIA는 WAI에서 발표한 RIA 환경(보통 SPA)에서의 웹 접근성 기술 규격이다. WAI-ARIA는 <span style='padding: 0.5px 2px; background-color: #e5e5e5; border-radius: 4px'>HTML 요소에 추가적으로 의미를 부여</span>한다. 따라서 <strong>보조적으로 사용</strong>하면 웹 접근성을 향상시킬 수 있다.</p>
<blockquote>
<p>💡 <strong>WAI-ARIA 사용 시 웹 접근성을 향상시킬 수 있는 경우</strong></p>
</blockquote>
<ul>
<li>시맨틱 요소만으로 의미를 전달할 수 없는 경우</li>
<li>SPA처럼 AJAX를 사용하는 경우
👉 새로고침 없이 페이지의 내용이 바뀌는 상황에서도 변경된 영역에대한 정보를 전달해줄 수 있어 동적인 콘텐츠에서도 웹 접근성을 향상시킬 수 있다.</li>
</ul>
<h4 id="역할role">역할(Role)</h4>
<p>HTML의 요소 종류와 역할이 서로 맞지 않을 때 어떤 역할을 하는 요소인지 명시해줄 때 사용할 수 있는 속성이다. <code>&lt;div role=&quot;button&quot;&gt;div이지만 button으로 사용되는 요소&lt;/div&gt;</code></p>
<p>HTML 요소로 내용을 파악할 수 있는 경우 role을 사용하지 않는 것이 좋다. 또한 시맨틱 요소의 의미를 임의로 바꾸지 않아야 한다.</p>
<h4 id="상태state">상태(State)</h4>
<p>Tab 컴포넌트의 경우 어떤 탭이 선택되어있어야 하는지 알 수 있어야 한다. 이때 사용할 수 있는 속성이 바로 <code>aria-selected</code>라는 속성이다. </p>
<pre><code class="language-js">&lt;div role=&quot;tabList&quot;&gt;
    &lt;li role=&quot;tab&quot; aria-selected=&quot;true&quot;&gt;Tab1&lt;/li&gt;    
    &lt;li role=&quot;tab&quot; aria-selected=&quot;false&quot;&gt;Tab2&lt;/li&gt;
&lt;/div&gt;</code></pre>
<p>이 외에도 아코디언이 펼쳐진 상태인지 표시해주는 <code>aria-expanded</code>와 요소가 숨긴 상태인지 표시하는 <code>aria-hidden</code>등의 속성이 있다.</p>
<h4 id="속성property">속성(Property)</h4>
<ul>
<li><strong>aria-label</strong> : 텍스트 콘텐츠 없이 이미지로만 만들어진 버튼같이 요소에 대한 정보를 얻을 수 없는 경우 <code>aria-label</code>를 사용해 라벨을 붙여줄 수 있다.</li>
<li><strong>aria-live</strong> : <code>aria-live</code>는 요소가 실시간으로 내용을 갱신하는 영역인지 표시한다. <code>ex) alert, modal, dialog, ajax를 이용</code> 속성값으로는 <code>polite</code>, <code>assertive</code>, <code>off(default)</code>가 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[UI/UX] UI, UX를 이해해보자]]></title>
            <link>https://velog.io/@3hee_11/UI-UX%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@3hee_11/UI-UX%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Tue, 23 Aug 2022 02:25:33 GMT</pubDate>
            <description><![CDATA[<h3 id="uiuser-interface-사용자-인터페이스">UI(User Interface, 사용자 인터페이스)</h3>
<p>UI는 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>사람들이 컴퓨터와 상호 작용하는 시스템</span>을 의미한다. UI라고 하면 떠오르는 화면 상의 그래픽 요소 외에도 키보드, 마우스같은 물리적 요소도 UI라고 볼 수 있다.</p>
<h4 id="guigraphical-user-interface-그래픽-사용자-인터페이스">GUI(Graphical User Interface, 그래픽 사용자 인터페이스)</h4>
<p>GUI는 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>사용자가 그래픽을 통해 컴퓨터와 정보를 교환하는 작업 환경</span>을 말한다. GUI의 예시는 우리가 보는 운영체제의 화면 혹은 애플리케이션 화면이 있다. </p>
<h3 id="uxuser-experience-사용자-경험">UX(User Experience, 사용자 경험)</h3>
<p>UX는 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>사용자가 어떤 시스템, 제품, 서비스를 직•간접적으로 이용하면서 느끼고 생각하는 경험</span>이다. 서비스 그 자체에 대한 경험은 물론이고 홍보, 접근성, 사후 처리 등 직간접적으로 관련된 모든 경험을 사용자 경험이라고 한다.</p>
<h3 id="ui와-ux의-관계">UI와 UX의 관계</h3>
<p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>UX는 UI를 포함한다.</span> 또한 좋은 UX가 좋은 UI를 의미하거나 좋은 UI가 항상 좋은 UX를 보장하지는 않는다.</p>
<p>기본 계산기 어플리케이션은 투박한 디자인이지만 계산 기능을 제대로 수행한다는 점에서 UX가 훌륭하다. 이처럼 좋은 UX가 꼭 좋은 UI를 의미하지 않는다. 반대로 세련된 디자인의 계산기가 있어도 계산 기능을 제대로 수행하지 못하면 UX가 좋지 않다. 이는 좋은 UI가 좋은 UX를 보장하지 않음을 보여준다.</p>
<h3 id="좋은-ux를-만드는-요소">좋은 UX를 만드는 요소</h3>
<p>아래 그림은 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>좋은 UX를 만들기 위해</span> 피터 모빌이 제시한 벌집 모형이다. 벌집 모형은 이외에도 그래프를 활용하여 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>UX를 얼마나 고려했는지 혹은 사용자가 얼마나 좋은 UX를 경험했는지 평가하기 위한 척도</span>로도 사용될 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/af03dbd1-4034-429c-bd0b-15f9f43ba540/image.png" alt=""></p>
<ul>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>유용성</span> : 사용 가능한 기능을 제공하고 있는가에 관한 요소</p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>사용성</span> : 사용하기 쉬운가에 관한 요소</p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>매력성</span> : 사용자들에게 매력적인가에 대한 요소</p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>신뢰성</span> : 사용자가 믿고 사용할 수 있는가에 관한 요소</p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>접근성</span>: 나이, 성별, 장애 여부를 떠나서 누구든지 접근할 수 있는가에 관한 요소</p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>검색가능성</span> : 사용자가 원하는 기능이나 정보를 쉽게 찾을 수 있는가에 관한 요소</p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>가치성</span> : 위에서 언급된 모든 요소를 총합하여 고객에게 가치를 제공하고 있는가에 관한 요소</p>
</li>
</ul>
<h3 id="user-flow">User Flow</h3>
<p>사용자 흐름(User Flow)은 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>사용자가 제품에 진입한 시점을 시작으로 취할 수 있는 모든 행동</span>을 뜻하며 아래 그림처럼 다이어그램으로 그려서 정리한다.
<img src="https://velog.velcdn.com/images/3hee_11/post/410e0e11-9ac2-47ee-a69f-739614225330/image.png" alt=""></p>
<h4 id="user-flow-다이어그램-작성법">User Flow 다이어그램 작성법</h4>
<ul>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>직사각형</span> : 사용자가 보게 될 화면 <code>ex: 회원 가입 페이지, 로그인 페이지</code></p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>다이아몬드</span> : 사용자가 취하게 될 행동 <code>ex: 로그인, 버튼 클릭, 업로드</code></p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>화살표</span> : 직사각형(화면)과 다이아몬드(행동)를 연결시켜주는 화살표</p>
</li>
</ul>
<h4 id="user-flow-다이어그램을-그리는-이유">User Flow 다이어그램을 그리는 이유</h4>
<ul>
<li>사용자 흐름 상 어색하거나 매끄럽지 않은 부분을 발견하여 수정할 수 있다.</li>
<li>있으면 좋은 기능을 발견하여 추가하거나 없어도 상관 없는 기능을 발견하고 삭제할 수 있다.
👉 사용자 흐름을 더 편리하게 다듬어 나가는 과정을 거치면서 UX를 개선할 수 있다.</li>
</ul>
<h4 id="user-flow-다이어그램-도구">User Flow 다이어그램 도구</h4>
<ul>
<li>Miro</li>
<li>FigJam</li>
</ul>
<h3 id="uiux-사용성-평가">UI/UX 사용성 평가</h3>
<p>사용성 평가 기준은 서비스중인 애플리케이션을 평가하기 위한 목적으로도 사용할 수 있지만 제품 설계 단계에서 더 완성도있는 애플리케이션을 기획하기 위해서도 사용할 수도 있다.</p>
<h4 id="제이콥-닐슨의-10가지-사용성-평가-기준jakobs-ten-usability-heuristics">제이콥 닐슨의 10가지 사용성 평가 기준(Jakob’s Ten Usability Heuristics)</h4>
<p>제이콥 닐슨의 10가지 사용성 평가 기준은 UI/UX 사용성 평가 기준 중 하나이다.</p>
<blockquote>
<p>🤔 <strong>여기서 Heuristic(휴리스틱)이란?</strong>
&#39;체험적인&#39;이라는 뜻으로 완벽한 지식 대신 직관과 경험을 활용하는 방법론을 말한다.</p>
</blockquote>
<ul>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>시스템 상태의 가시성 (Visibility of system status)</span> : 합리적인 시간 내에 적절한 피드백을 통해 사용자에게 진행 상황에 대한 정보를 항상 제공해야 한다. <code>ex : 파일을 업로드할 때 얼마나 남았는지 표시됨</code></p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>시스템과 현실 세계의 일치 (Match between system and the real world)</span> : 전문용어가 아닌 사용자에게 친숙한 단어, 구문 및 개념을 사용한다.</p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>사용자 제어 및 자유 (User control and freedom)
</span> : 현재 진행 중인 작업에서 벗어날 수 있는 방법 혹은 실수로 수행한 작업을 취소할 수 있는 방법을 제공해야 한다. <code>ex : 파일을 삭제했을 때 실행취소 버튼</code></p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>일관성 및 표준 (Consistency and standards)</p>
</span>
- 외부 일관성 : 일관적인 사용자 경험을 제공하기 위해서 플랫폼 및 업계의 관습을 따른다. ```ex : 잘 알려진 UI 디자인 패턴을 사용```
- 내부 일관성 : 사용자가 혼란스럽지 않도록 제품의 인터페이스나 정보 제공에 일관성이 있어야 한다. ```ex : 버튼의 모양, 위치, 아이콘 크기```
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>오류 방지 (Error prevention)</span> : 오류가 발생하기 쉬운 상황을 제거하여 사용자의 실수를 방지해야 한다. <code>ex : 삭제 버튼을 눌렀을 때 정말 삭제할 것인지 한번 더 확인한다.</code></p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>기억보다는 직관 (Recognition rather than recall)</span> : 사용자가 기억해야하는 정보를 줄인다. <code>ex : 최근 검색 했던 단어 목록</code></p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>사용의 유연성과 효율성 (Flexibility and efficiency of use)</span> : 초보자와 전문가 모두에게 개별 맞춤 기능을 제공한다. <code>ex : 프로그램의 단축키를 직접 설정</code></p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>미학적이고 미니멀한 디자인 (Aesthetic and minimalist design)</span> : 인터페이스에는 관련이 없거나 불필요한 정보가 포함되지 않도록 한다. <code>ex : 사용 빈도가 적은 메뉴는 필요할 때에만 볼 수 있게 숨겨놓음</code></p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>오류의 인식, 진단, 복구를 지원 (Help users recognize, diagnose, and recover from errors)</span> : 사용자가 이해할 수 있는 언어를 사용하여 문제가 무엇인지 정확하게 표시하고 해결 방법을 제안한다. <code>ex : 영문 성을 입력해야하는 폼에서는 한글이 아닌 영어를 입력해야 함을 알려준다.</code></p>
</li>
<li><p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>도움말 및 설명 문서 (Help and documentation)</span> : 추가 설명이 필요 없는 것이 가장 좋지만 상황에 따라 이해하는 데 도움이 되는 문서를 제공한다. </p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] JSON 헷갈려서 맨날 찾아보는 사람 🙋 🙋]]></title>
            <link>https://velog.io/@3hee_11/Javascript-JSON-%ED%97%B7%EA%B0%88%EB%A0%A4%EC%84%9C-%EB%A7%A8%EB%82%A0-%EC%B0%BE%EC%95%84%EB%B3%B4%EB%8A%94-%EC%82%AC%EB%9E%8C</link>
            <guid>https://velog.io/@3hee_11/Javascript-JSON-%ED%97%B7%EA%B0%88%EB%A0%A4%EC%84%9C-%EB%A7%A8%EB%82%A0-%EC%B0%BE%EC%95%84%EB%B3%B4%EB%8A%94-%EC%82%AC%EB%9E%8C</guid>
            <pubDate>Mon, 22 Aug 2022 23:28:11 GMT</pubDate>
            <description><![CDATA[<p>이전에 <a href="https://velog.io/@3hee_11/Javascript-%EA%B0%9D%EC%B2%B4#json">객체와 JSON</a>으로 JSON을 간단하게 포스팅한 적이 있지만 내용이 부족한 것 같아서 이번 챕터에서 배운 내용을 다시 정리해보려고 한다.</p>
<h3 id="json이란">JSON이란?</h3>
<p>JSON은 <strong>J</strong>ava<strong>S</strong>cript <strong>O</strong>bject <strong>N</strong>otation의 줄임말로 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>데이터 교환을 위해 만들어진 객체 형태의 포맷</span>이다. </p>
<p>네트워크를 통해 어떤 객체 내용을 다른 프로그램으로 전송한다고 가정해보자. 이 객체가 채팅 프로그램에서 쓰는 하나의 메시지라고 한다면 객체를 어떻게 전송할 수 있을까?</p>
<pre><code class="language-js">let message = {
  sender: &quot;나&quot;,
  receiver: &quot;모두에게&quot;,
  message: &quot;상쾌한 화요일 아침입니다~!&quot;,
  createdAt: &quot;2022-08-23 07:10:10&quot;
}</code></pre>
<p>이 메시지 객체가 전송이 가능하려면 메시지를 보내는 발신자와 메시지를 받는 수신자가 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>1. 같은 프로그램을 사용하거나</span>, <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>2. 문자열처럼 범용적으로 읽을 수 있는 형태</span>여야 한다.</p>
<p>그럼 객체를 toString()이나 String()으로 객체를 String 타입으로 변환해주면 되지 않나? 라는 생각이 들텐데, <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>객체는 타입 변환을 이용해 String으로 변환할 경우 객체 내용을 포함하지 않는다.</span></p>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/dd9b916d-a65b-423e-89e5-70389d584424/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/3dbb1f66-b394-4035-baee-8d83993d63d7/image.jpg" alt=""></p>
<p>객체의 내용을 문자열로 바꿔줘야 하는데 타입 변환이 안된다, 그렇다면 어떻게 해야할까?</p>
<p>👉 바로 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>객체를 JSON의 형태로 변환하거나 JSON을 객체의 형태로 변환</span>하면 된다.</p>
<h3 id="jsonstringify와-jsonparse">JSON.stringify()와 JSON.parse()</h3>
<p>이 두 가지 메서드는 앞서 말했듯이 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>객체를 JSON의 형태로 변환(JSON.stringify)</span>하거나 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>JSON을 객체의 형태로 변환(JSON.parse)</span>해주는 메서드이다.</p>
<p>위에 있는 message 객체를 JSON.stringify()를 통해 JSON으로 변환해준 다음 typeof로 타입을 확인해보면 String 타입으로 변환된 것을 확인할 수 있다. 이렇게  <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>stringify하는 과정을 <strong>직렬화(serialize)</strong>한다</span>고 한다.</p>
<pre><code class="language-js">message = JSON.stringify(message)

console.log(message) 
// `{&quot;sender&quot;:&quot;나&quot;,&quot;receiver&quot;:&quot;모두에게&quot;,&quot;message&quot;:&quot;상쾌한 화요일 아침입니다~!&quot;,&quot;createdAt&quot;:&quot;2022-08-23 07:10:10&quot;}`

console.log(typeof(message)) // `string`</code></pre>
<blockquote>
<p>💡 <strong>참고</strong>
JSON.stringify()는 객체뿐만 아니라 원시값에도 적용할 수 있다. 그러나 JSON은 속성만 담을 수 있기 때문에 메서드, 심볼, 값이 undefined인 속성은 담을 수 없다.</p>
</blockquote>
<p>네트워크를 통해 JSON 형태(문자열)로 변환한 객체를 보냈다. 그렇다면 수신자는 이 문자열 메시지를 어떻게 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>다시 객체의 형태</span>로 만들 수 있을까? 이럴 때 사용하는 메서드가 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>JSON.parse()</span>이다.</p>
<p>아래 코드를 보면 JSON.stringify()와 반대로 JSON.parse()을 사용하면 JSON 형태의 데이터가 객체로 변환되는 것을 볼 수 있다. 이 과정을 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'><strong>역직렬화(deserialize)</strong>한다</span>고 한다.</p>
<pre><code class="language-js">let packet = `{&quot;sender&quot;:&quot;나&quot;,&quot;receiver&quot;:&quot;모두에게&quot;,&quot;message&quot;:&quot;상쾌한 화요일 아침입니다~!&quot;,&quot;createdAt&quot;:&quot;2022-08-23 07:10:10&quot;}`
let obj = JSON.parse(packet)

console.log(obj)
/*{
  sender: &quot;나&quot;,
  receiver: &quot;모두에게&quot;,
  message: &quot;상쾌한 화요일 아침입니다~!&quot;,
  createdAt: &quot;2022-08-23 07:10:10&quot;
}*/

 console.log(typeof(obj))
 // `object`</code></pre>
<h3 id="json의-기본-규칙">JSON의 기본 규칙</h3>
<p>JSON은 형태가 객체와 비슷해보이지만 아래 표와 같이 미묘한 차이점이 있다. 원래 코드를 칠 때 문자열에 큰따옴표를 사용했으니까 키를 쌍따옴표로 감싸야 한다는 점과 모든 공백(=키와 값 사이, 키-값 쌍 사이 공백)은 사용할 수 없다는 점을 기억해야겠다.</p>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/542904bf-e137-4809-a594-916611bb5eaa/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] 재귀 함수가 뭔데, 그거 어떻게 하는 건데.]]></title>
            <link>https://velog.io/@3hee_11/Javascript-%EC%9E%AC%EA%B7%80-%ED%95%A8%EC%88%98%EA%B0%80-%EB%AD%94%EB%8D%B0-%EA%B7%B8%EA%B1%B0-%EC%96%B4%EB%96%BB%EA%B2%8C-%ED%95%98%EB%8A%94-%EA%B1%B4%EB%8D%B0</link>
            <guid>https://velog.io/@3hee_11/Javascript-%EC%9E%AC%EA%B7%80-%ED%95%A8%EC%88%98%EA%B0%80-%EB%AD%94%EB%8D%B0-%EA%B7%B8%EA%B1%B0-%EC%96%B4%EB%96%BB%EA%B2%8C-%ED%95%98%EB%8A%94-%EA%B1%B4%EB%8D%B0</guid>
            <pubDate>Mon, 22 Aug 2022 14:28:16 GMT</pubDate>
            <description><![CDATA[<h3 id="재귀-함수는">재귀 함수는...</h3>
<p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>재귀 함수는 자기 자신을 호출하는 함수이다.</span> 자기 자신을 호출한다는게 무슨 뜻이냐면 아래 코드처럼 함수 안에 자기 자신을 또 부르는 것이다.</p>
<pre><code class="language-js">function repeat(){
  console.log(&quot;반복된다!&quot;);
  repeat();
}</code></pre>
<p>repeat 함수를 콘솔에 출력해보면 &quot;반복된다!&quot;라는 문자열이 계속 출력되는 것을 볼 수 있다. 이는 함수 마지막에 repeat 함수를 다시 호출하기 때문이다. 
<img src="https://velog.velcdn.com/images/3hee_11/post/4bf67516-d962-4005-9fe9-d589728c6a87/image.png" alt=""></p>
<blockquote>
<p><strong>🖐 재귀 함수를 왜 알아야 하나요?</strong>
재귀 함수를 사용하면 반복적인 작업을 좀 더 간단하게 풀어낼 수 있기 때문이다. </p>
</blockquote>
<h3 id="재귀를-사용해서-문제를-풀어보자">재귀를 사용해서 문제를 풀어보자</h3>
<p>이론적으로 재귀로 문제를 해결하는 단계는 아래와 같다.</p>
<blockquote>
<ol>
<li>문제를 좀 더 작게 쪼갠다.</li>
<li>전과 같은 방식으로 문제가 더 작아질 수 없을 때까지 쪼갠다.</li>
<li>가장 작은 단위의 문제를 풀어 전체 문제를 해결한다.</li>
</ol>
</blockquote>
<p>정리하자면 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>문제를 가장 작은 단위까지 쪼개서 해결한다!</span> 이 개념을 적용해서 배열 [1,2,3,4,5]의 합을 구하는 함수를 작성해보자. </p>
<h4 id="1-문제를-좀-더-작게-쪼갠다">1. 문제를 좀 더 작게 쪼갠다.</h4>
<pre><code class="language-js">arrSum([1, 2, 3, 4, 5]) === 1 + arrSum([2, 3, 4, 5])
arrSum([2, 3, 4, 5]) === 2 + arrSum([3, 4, 5])
arrSum([3, 4, 5]) === 3 + arrSum([4, 5])
...</code></pre>
<h4 id="2-전과-같은-방식으로-문제가-더-작아질-수-없을-때까지-쪼갠다">2. 전과 같은 방식으로 문제가 더 작아질 수 없을 때까지 쪼갠다.</h4>
<pre><code class="language-js">arrSum([3, 4, 5]) === 3 + arrSum([4, 5])
arrSum([4, 5]) === 4 + arrSum([5])
arrSum([5]) === 5 + arrSum([]) // 더 이상 쪼갤 수 없음</code></pre>
<h4 id="3-가장-작은-단위의-문제를-풀어-전체-문제를-해결한다">3. 가장 작은 단위의 문제를 풀어 전체 문제를 해결한다.</h4>
<pre><code class="language-js">arrSum([5]) === 5 + arrSum([]) === 5 + 0 === 5;
arrSum([4, 5]) === 4 + arrSum([5]) === 4 + 5 === 9;
arrSum([3, 4, 5]) === 3 + arrSum([4, 5]) === 3 + 9 === 12;
arrSum([2, 3, 4, 5]) === 2 + arrSum([3, 4, 5]) === 2 + 12 === 14;
arrSum([1, 2, 3, 4, 5]) === 1 + arrSum([2, 3, 4, 5]) === 1 + 14 === 15;</code></pre>
<h4 id="👇-최종-코드">👇 최종 코드</h4>
<pre><code class="language-js">function sum(arr){
    // 빈 배열을 받았을 때 0 리턴
    // 가장 작은 문제를 해결하는 코드 &amp; 재귀를 멈추는 코드
    if(arr.length === 0){
        return 0;
    }

    // 배열의 첫 요소 + 나머지 요소가 담긴 배열을 받는 sum 함수
    // 재귀(자기 자신을 호출)를 통해 문제를 작게 쪼개나가는 코드
    return arr.shift() + sum(arr);
}</code></pre>
<h3 id="재귀-함수-언제-사용하면-좋을까">재귀 함수 언제 사용하면 좋을까?</h3>
<ul>
<li>주어진 문제를 비슷한 구조의 더 작은 문제로 나눌 수 있는 경우</li>
<li>중첩된 반복문이 많거나 반복문의 중첩 횟수를 예측하기 어려운 경우</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[HTTP/네트워크] REST API]]></title>
            <link>https://velog.io/@3hee_11/HTTP%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-Rest-API</link>
            <guid>https://velog.io/@3hee_11/HTTP%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-Rest-API</guid>
            <pubDate>Fri, 05 Aug 2022 09:14:09 GMT</pubDate>
            <description><![CDATA[<h3 id="rest-apirepresentational-state-transfer란">REST API(Representational State Transfer)란?</h3>
<p>REST API는 웹에서 사용되는 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>데이터나 자원을 HTTP URI로 표현</span>하고, <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>HTTP 프로토콜을 통해 요청과 응답을 정의</span>하는 방식이다.</p>
<h3 id="rest-api-작성-규칙">REST API 작성 규칙</h3>
<blockquote>
<p>0~3단계까지 총 4단계가 있지만 3단계까지 지키기는 어렵기 때문에 2단계까지만 적용해도 좋은 API 디자인이라고 볼 수 있다.
👉 <strong>이를 HTTP API라고 부른다.</strong></p>
</blockquote>
<h4 id="0단계---http-사용">0단계 - HTTP 사용</h4>
<p>0단계에서는 단순히 HTTP 프로토콜을 사용하기만 해도 된다. 물론 이 경우 해당 API를 REST API라고 할 수는 없으며 0단계는 REST API를 작성하기 위한 기본 단계이다.</p>
<h4 id="1단계---개별-리소스와의-통신-준수">1단계 - 개별 리소스와의 통신 준수</h4>
<p>1단계에서는 개별 리소스와의 통신을 준수해야 한다. <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>모든 자원은 개별 리소스에 맞는 엔드포인트를 사용해야하며 요청하고 받는 자원에 대한 정보를 응답으로 전달해야 한다</span>는 것이다.</p>
<p>👉 엔드포인트 작성 시 <strong>리소스에 집중해서 명사 형태의 단어</strong>로 작성해야한다. <code>ex) /doctors/허준</code>
👉 요청에 대한 정보를 응답에 넣어서 전달해야한다. <code>ex) 예약에 성공하면 성공한 내역, 실패하면 실패한 내역</code></p>
<h4 id="2단계---http-메소드-원칙-준수">2단계 - HTTP 메소드 원칙 준수</h4>
<p>2단계에서는 CRUD에 맞는 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>적절한 HTTP 메서드를 사용</span>해야 한다. <strong><a href="https://velog.io/@3hee_11/HTTP-HTTP-%EB%A9%94%EC%84%9C%EB%93%9C">[HTTP] HTTP 메서드</a></strong></p>
<h4 id="3단계---hateoas-원칙-준수">3단계 - HATEOAS 원칙 준수</h4>
<p>3단계의 요청은 2단계와 동일하지만 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>응답에 리소스의 URI를 포함한 링크 요소를 삽입</span>하여 작성해야 한다. 이때 응답에 들어가게 되는 링크 요소는 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>응답을 받은 다음에 할 수 있는 다양한 액션들을 위해 많은 하이퍼미디어 컨트롤을 포함</span>하고 있다.</p>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/3e237763-f271-46cb-ac7a-7d78957301ed/image.png" alt=""></p>
<p>예를 들어 허준이라는 의사의 예약 가능 시간을 확인한 후에는 그 시간대에 예약을 할 수 있는 링크를 삽입하거나, 특정 시간에 예약을 완료하고 나서는 그 예약을 다시 확인할 수 있도록 링크를 작성해 넣을 수도 있다. 이렇게 <strong>응답 내에 새로운 링크를 넣어 새로운 기능에 접근할 수 있도록 하는 것</strong>이 3단계의 핵심 포인트이다.</p>
<blockquote>
<p>📌 <strong>정리</strong>
REST API를 준수하기 위해서는 <strong>(1) HTTP 프로토콜을 사용</strong>하고 <strong>(2) 엔드포인트에 명사 형태의 자원을 작성</strong>하고 <strong>(3) CRUD에 따른 적절한 HTTP 메소드를 사용</strong>해야 하며 <strong>(4) 응답에 링크를 포함하여 새로운 기능에 접근</strong>할 수 있도록 해야한다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[HTTP/네트워크] 브라우저의 작동 원리]]></title>
            <link>https://velog.io/@3hee_11/HTTP%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EC%9E%91%EB%8F%99-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@3hee_11/HTTP%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EC%9E%91%EB%8F%99-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Thu, 04 Aug 2022 06:41:46 GMT</pubDate>
            <description><![CDATA[<h3 id="url과-uri">URL과 URI</h3>
<p>브라우저의 검색창을 클릭하면 나타나는 주소가 URI이다. <strong>URI는 URL을 포함하는 상위개념</strong>이다.</p>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/b4c8c162-bd79-48b5-ab5d-ddc9e72a68c4/image.png" alt=""></p>
<h4 id="url">URL</h4>
<p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>URL(Uniform Resource Locator)</span>은 네트워크 상에서 웹 페이지, 이미지, 동영상 등의 파일이 위치한 정보를 나타낸다. URL은 <code>scheme</code>, <code>hosts</code>, <code>url-path</code>로 구분할 수 있다. </p>
<ul>
<li><code>scheme</code> : 통신 방식(프로토콜)을 결정하며 일반적인 웹 브라우저에서는 http(s)를 사용한다. </li>
<li><code>hosts</code>: 웹 서버의 이름이나 도메인, IP를 사용하며 주소를 나타낸다. </li>
<li><code>url-path</code> :  웹 서버에서 지정한 루트 디렉토리부터 시작하여 웹 페이지, 이미지, 동영상 등이 위치한 경로와 파일명을 나타낸다.</li>
</ul>
<h4 id="uri">URI</h4>
<p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>URI(Uniform Resource Identifier)</span>는 일반적으로 URL의 기본 요소인 <code>scheme</code>, <code>hosts</code>, <code>url-path</code>에 더해 <code>query</code>, <code>fragment</code>를 포함한다. </p>
<ul>
<li><code>query</code> : 웹 서버에 보내는 추가적인 질문이다. </li>
<li><code>fragment</code> : 일종의 북마크 기능을 수행하며 URL에 fragment(#)와 특정 HTML 요소의 id를 전달하면 해당 요소가 있는 곳으로 스크롤을 이동할 수 있다.</li>
</ul>
<h3 id="ip와-port">IP와 PORT</h3>
<p>네트워크에 연결된 특정 PC의 주소를 나타내는 체계를 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>IP address(Internet Protocol address, IP 주소)</span>라고 한다.</p>
<h4 id="ip">IP</h4>
<p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>IP(Internet Protocol)</span>는 인터넷상에서 사용하는 주소체계를 의미한다. </p>
<blockquote>
<p>💡 <strong>기억해야하는 IP 주소</strong></p>
</blockquote>
<ul>
<li><code>localhost</code>, <code>127.0.0.1</code> : 현재 사용 중인 로컬 PC를 지칭</li>
<li><code>0.0.0.0</code>, <code>255.255.255.255</code> : broadcast address, 로컬 네트워크에 접속된 모든 장치와 소통하는 주소. 서버에서 접근 가능 IP 주소를 broadcast address 로 지정하면 모든 기기에서 서버에 접근할 수 있다.</li>
</ul>
<h4 id="port">PORT</h4>
<p>포트는 IP 주소가 가리키는 PC에 접속할 수 있는 통로(채널)를 의미한다.</p>
<blockquote>
</blockquote>
<ul>
<li>22 : SSH</li>
<li>80 : HTTP</li>
<li>443: HTTPS</li>
</ul>
<h3 id="도메인과-dns">도메인과 DNS</h3>
<h4 id="domain-name">Domain name</h4>
<p>웹 브라우저를 통해 특정 사이트에 진입을 할 때 IP 주소를 대신하여 사용한다. IP 주소를 보다 간단하게 나타낼 수 있다.</p>
<h4 id="dns">DNS</h4>
<p>브라우저의 검색창에 도메인 이름을 입력하여 해당 사이트로 이동하기 위해서는 해당 도메인 이름과 매칭된 IP 주소를 확인하는 작업이 반드시 필요하다. 네트워크에는 이것을 위한 서버가 별도로 있는데 이를 <strong>DNS(Domain Name System)</strong>라고 한다.</p>
<p>DNS는 호스트의 도메인 이름을 IP 주소로 변환하거나 반대의 경우를 수행할 수 있도록 개발된 데이터베이스 시스템이다.</p>
<h3 id="ajax">AJAX</h3>
<p><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>AJAX(Asynchronous JavaScript And XMLHttpRequest)</span>는 JavaScript, DOM, Fetch, XMLHttpRequest, HTML 등의 다양한 기술을 사용하는 웹 개발 기법이다.</p>
<p>AJAX를 구성하는 핵심 기술은 <code>JavaScript</code>와 <code>DOM</code>, 그리고 <code>Fetch</code>이다. <code>JavaScript</code>에서 <code>DOM</code>을 사용해 조작할 수 있기 때문에 <code>Fetch</code>를 통해 전체 페이지가 아닌 필요한 데이터만 가져와 DOM에 적용시켜 <strong>새로운 페이지로 이동하지 않고 기존 페이지에서 필요한 부분만 변경</strong>할 수 있다.</p>
<p>브라우저는 Fetch가 서버에 요청을 보내고 응답을 받을 때까지 모든 동작을 멈추는 것이 아니라 계속해서 페이지를 사용할 수 있게 하는 <strong>비동기적인 방식을 사용</strong>한다.</p>
<p>👉 AJAX의 가장 큰 특징은 <strong>웹 페이지에 필요한 부분에 필요한 데이터만 비동기적으로 받아와 화면에 그려낼 수 있다는 것</strong>이다.</p>
<h4 id="ajax의-장점">AJAX의 장점</h4>
<ul>
<li><p><strong>화면의 일부만 업데이트하여 렌더링</strong>
서버에서 HTML을 완성하여 보내주지 않아도 웹페이지를 만들 수 있다.</p>
</li>
<li><p><strong>표준화된 방법</strong>
이전에는 브라우저마다 다른 방식으로 AJAX를 사용했으나, XHR이 표준화되면서부터 브라우저에 상관없이 AJAX를 사용할 수 있다.  </p>
</li>
<li><p><strong>유저 중심 애플리케이션 개발</strong>
AJAX를 사용하면 필요한 일부분만 렌더링하기 때문에 빠르고 더 많은 상호작용이 가능한 애플리케이션을 만들 수 있다.</p>
</li>
<li><p><strong>더 작은 대역폭</strong>
이전에는 서버로부터 완성된 HTML 파일을 받아와야 했기 때문에 한 번에 보내야 하는 데이터의 크기가 컸지만 AJAX에서는 필요한 데이터를 텍스트 형태(JSON, XML 등)로 보내면 되기 때문에 비교적 데이터의 크기가 작다.</p>
</li>
</ul>
<h4 id="ajax의-단점">AJAX의 단점</h4>
<ul>
<li><p><strong>Search Engine Optimization(SEO)에 불리</strong>
AJAX 방식의 웹 앱은 한 번 받은 HTML을 렌더링 한 후 서버에서 비동기적으로 필요한 데이터를 가져와 그린다. 따라서, 처음 받는 HTML 파일에는 데이터를 채우기 위한 틀만 작성되어 있는 경우가 많다. 검색 사이트에서는 전 세계 사이트를 돌아다니며 각 사이트의 모든 정보를 긁어와 사용자에게 검색 결과로 보여준다. AJAX 방식의 웹 애플리케이션의 HTML 파일은 뼈대만 있고 데이터는 없기 때문에 사이트의 정보를 긁어가기 어렵다.</p>
</li>
<li><p><strong>뒤로가기 버튼 문제</strong>
AJAX에서는 이전 상태를 기억하지 않기 때문에 뒤로가기 버튼을 누르면 이전 상태로 돌아가지 않는다. 따라서 뒤로가기 등의 기능을 구현하기 위해서는 별도로 History API를 사용해야 한다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[HTTP/네트워크] 웹 애플리케이션 아키텍처]]></title>
            <link>https://velog.io/@3hee_11/HTTP%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%9B%B9-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98</link>
            <guid>https://velog.io/@3hee_11/HTTP%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%9B%B9-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98</guid>
            <pubDate>Thu, 04 Aug 2022 05:29:36 GMT</pubDate>
            <description><![CDATA[<h3 id="클라이언트---서버-아키텍처">클라이언트 - 서버 아키텍처</h3>
<p>리소스를 사용하는 앱을 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>클라이언트</span> 리소스를 제공(serve)하는 곳을 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>서버</span>라고 부르며 <strong>클라이언트와 서버는 요청과 응답을 주고받는다.</strong></p>
<ul>
<li><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>2티어 아키텍처</span> : 상품 정보같은 리소스가 존재하는 곳과 리소스를 사용하는 앱를 분리시킨 것(= 클라이언트-서버 아키텍처)</li>
<li><span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>3티어 아키텍처</span> : 2티어 아키텍처에 데이터베이스가 추가된 형태</li>
</ul>
<h3 id="클라이언트와-서버의-종류">클라이언트와 서버의 종류</h3>
<h4 id="✔-클라이언트">✔ 클라이언트</h4>
<p>클라이언트는 보통 플랫폼에 따라 구분된다. </p>
<ul>
<li>브라우저를 통해 주로 이용하는 웹 플랫폼에서의 클라이언트(웹사이트 또는 웹 앱라고 부름)</li>
<li>iOS나 안드로이드와 같은 스마트폰/태블릿 플랫폼</li>
<li>윈도우와 같은 데스크탑 플랫폼에서 이용하는 앱</li>
</ul>
<h4 id="✔-서버">✔ 서버</h4>
<p>서버는 무엇을 하느냐에 따라 종류가 달라진다. </p>
<ul>
<li>파일 서버는 파일을 제공하는 앱</li>
<li>웹 서버는 웹사이트에서 필요로 하는 정보들을 제공하는 앱</li>
<li>메일 서버는 메일을 주고받을 수 있도록 도와주는 앱</li>
</ul>
<p><em>데이터베이스도 데이터 제공자로서 일하므로 일종의 서버라고 볼 수 있다.</em></p>
<h3 id="클라이언트---서버-통신">클라이언트 - 서버 통신</h3>
<p>클라이언트와 서버 간의 통신을 알기위해 프로토콜에 대한 이해가 필요하다. <strong>프로토콜은 통신 규약, 즉  서버와 클라이언트가 원활하게 메세지를 주고받기 위한 규칙이다.</strong></p>
<p>웹 애플리케이션 아키텍처에서는 클라이언트와 서버가 서로 HTTP라는 프로토콜을 이용해서 서로 메세지를 주고 받는다. HTTP를 이용해 주고받는 메시지는 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>HTTP 메시지</span>라고 부른다.</p>
<h4 id="주요-프로토콜">주요 프로토콜</h4>
<p><img src="https://velog.velcdn.com/images/3hee_11/post/25325f5b-6a23-43e9-9943-9aeabf2bdf89/image.png" alt=""></p>
<h3 id="api">API</h3>
<p>커피 주문에 비유하자면 메뉴를 주문할 때 알아서 맛있는거 주세요!라는 요청은 컴퓨터에서 허용하지 않는다. 정확한 메뉴를 요청해야한다. 어떻게 해야 서버에 있는 사용 가능한 리소스 즉 메뉴를 파악할 수 있을까? 여기서 필요한게 바로 <strong>API(Application Programming Interface)</strong>이다.</p>
<p>서버는 클라이언트에게 리소스를 잘 활용할 수 있도록 인터페이스를 제공해 줘야하고 이것을 <span style='padding: 2px; background-color: #e5e5e5; border-radius: 4px'>API</span>라고 부른다. 위에 상황에 비유하자면 메뉴판이라고 볼 수 있다.</p>
<p>보통 인터넷에 있는 데이터를 요청할 때는 HTTP라는 프로토콜을 사용하며 주소(URL, URI)를 통해 접근할 수 있다. 주소 안에는 클라이언트에서 요청과 함께 값을 보내기 위해 <strong>파라미터를 사용</strong>한다. 이 때 ?(물음표)와 &amp;(앰퍼샌드)기호를 사용한다.</p>
<p>HTTP 요청에는 <strong>메서드</strong>라는 것이 존재하며 CRUD 각각의 행동과 일치하는 종류가 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] React State와 Props를 이용한 Twittler 정리]]></title>
            <link>https://velog.io/@3hee_11/React-React-State%EC%99%80-Props%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Twittler-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@3hee_11/React-React-State%EC%99%80-Props%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Twittler-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 03 Aug 2022 16:06:50 GMT</pubDate>
            <description><![CDATA[<p><code>React Router DOM</code>을 설치 후 import 구문을 이용하여 <code>BrowserRouter</code>, <code>Routes</code>, <code>Route</code>, <code>Link</code> 컴포넌트를 불러온다.</p>
<pre><code class="language-js">import { BrowserRouter, Routes, Route, Link } from &#39;react-router-dom&#39;;</code></pre>
<blockquote>
<p><strong>🤔 import할 때 왜 어떤 건 중괄호를 사용하고 어떤 건 사용하지 않을까?</strong> <strong><a href="https://codingmania.tistory.com/333">출처</a></strong>
해당 컴포넌트에서 <code>export</code>할 때, <code>export</code> 뒤에 <code>default</code> 키워드를 붙여주면 다른 컴포넌트에서 import할 때 괄호를 써주지 않아도 된다. 또 변수명도 import한 컴포넌트에서 마음대로 지정할 수 있다.</p>
</blockquote>
<p>라우터 역할을 하는 <code>BrowserRouter</code> 컴포넌트를 작성하고, 그 안에 경로를 매칭해주는 <code>Routes</code> 와 <code>Route</code>, 그리고 경로를 변경하는 역할을 하는 Link를 작성한다.</p>
<pre><code class="language-js">&lt;BrowserRouter&gt;
    &lt;div className=&quot;App&quot;&gt;
      &lt;main&gt;
        &lt;section className=&quot;sidebar&quot;&gt;
            // &lt;Link&gt;의 to 속성을 활용하여 &lt;Route&gt; 컴포넌트에 설정해 준 path 주소를 연결한다.
              &lt;Link to=&quot;/&quot;&gt;&lt;i className=&quot;far fa-comment-dots&quot;&gt;&lt;/i&gt;&lt;/Link&gt;
              &lt;Link to=&quot;/about&quot;&gt;&lt;i className=&quot;far fa-question-circle&quot;&gt;&lt;/i&gt;&lt;/Link&gt;
              &lt;Link to=&quot;/mypage&quot;&gt;&lt;i className=&quot;far fa-user&quot;&gt;&lt;/i&gt;&lt;/Link&gt;  
        &lt;/section&gt;
        &lt;section className=&quot;features&quot;&gt;
          &lt;Routes&gt;
              // path로 경로를 설정해서 해당 경로로 접근하면 element에 작성한 컴포넌트로 연결해준다.
            &lt;Route path=&#39;/&#39; element={&lt;Tweets/&gt;}&gt;&lt;/Route&gt;
            &lt;Route path=&#39;/about&#39; element={&lt;About /&gt;}&gt;&lt;/Route&gt;
            &lt;Route path=&#39;/mypage&#39; element={&lt;MyPage /&gt;}&gt;&lt;/Route&gt;
          &lt;/Routes&gt;
        &lt;/section&gt;
      &lt;/main&gt;
    &lt;/div&gt;
&lt;/BrowserRouter&gt;</code></pre>
<p>트윗을 작성하기 위해 <code>useState</code>로 사용자 이름과 메세지가 변경될 때마다 관리한다.</p>
<pre><code class="language-js">// useState 호출해서 state의 변수, 갱신 함수, 초기값을 지정한다.
 const [username, setUsername] = useState(&quot;&quot;);

const handleChangeUser = (event) =&gt; {
      // event를 호출한 요소의 값을 가져온다.
    setUsername(event.target.value);
};

// input의 value가 변경될 때마다 호출될 함수를 지정한다.
&lt;input
    type=&quot;text&quot;
    placeholder=&quot;your username here..&quot;
    className=&quot;tweetForm__input--username&quot;
    onChange={handleChangeUser}
    value={username}
&gt;&lt;/input&gt;</code></pre>
<p>트윗 전송 버튼을 클릭했을 때 트윗 목록에 작성한 트윗을 추가하기위해 트윗들을 state로 관리한다. </p>
<pre><code class="language-js">const [tweets, setTweets] = useState(dummyTweets);

const handleButtonClick = (event) =&gt; {
      // 새로 추가할 트윗을 객체로 선언하고 작성했던 내용들을 할당한다.
    const tweet = {id: ~, username: ~};

      // 갱신 함수에 새 배열을 선언하고 새로 추가할 트윗과 기존 트윗을 spread 문법으로 펼쳐서 할당한다.
    setTweets([tweet, ...tweets]);
      // let new

    // 트윗 전송 후 사용자 이름과 메세지를 비우기 위함
    setUsername(&quot;&quot;);
    setMsg(&quot;&quot;);
};</code></pre>
<blockquote>
<p><strong>🤔 아래 코드처럼 unshift()를 써서 새 트윗을 기존 트윗에 추가해주면 안되나요?</strong></p>
</blockquote>
<pre><code class="language-js">tweets.unshift(tweet);
setTweets(tweets);</code></pre>
<p>unshift()는 원본 배열을 변경하는 것이기 때문에 기존에 저장된 tweets와 현재 갱신 함수에 전달 인자인 tweets는 주소가 같다. <strong>set 갱신함수는 같은 주소값이면 갱신을 하지 않기 때문에 리렌더링이 안된다!</strong></p>
<blockquote>
</blockquote>
<p>🖐 <strong>저는 unshift()를 사용하고 싶은데요</strong></p>
<pre><code class="language-js">const newTweets = tweets.slice();
newTweets.unshift(tweet);
setTweets(newTweets);</code></pre>
<p>unshift()를 사용하고 싶다면 위 코드처럼 tweets를 복사해 새 배열을 만들고(주소값이 달라짐) unshift()를 사용하면 된다</p>
<p>트윗들을 나열하기 위해 map을 사용해 tweets에서 꺼낸 각 tweet들을 Tweet 컴포넌트에 props으로 전달한다. </p>
<pre><code class="language-js">&lt;ul className=&quot;tweets&quot;&gt;
    {
        tweets.map(tweet =&gt; {
            return &lt;Tweet tweet={tweet} key={tweet.id}&gt;&lt;/Tweet&gt;
        })
    }
&lt;/ul&gt;</code></pre>
<p>Tweet 컴포넌트에서는 객체인 props를 전달받아 렌더링한다.</p>
<pre><code class="language-js">const Tweet = ({ tweet }) =&gt; {
  return (
    &lt;li className=&quot;tweet&quot; id={tweet.id}&gt;
      &lt;div className=&quot;tweet__profile&quot;&gt;
        &lt;img src={tweet.picture} /&gt;
      &lt;/div&gt;
      &lt;div className=&quot;tweet__content&quot;&gt;
        &lt;div className=&quot;tweet__userInfo&quot;&gt;
          &lt;div className=&quot;tweet__userInfo--wrapper&quot;&gt;
            &lt;span className=&quot;tweet__username&quot;&gt;
            {tweet.username}
            &lt;/span&gt;
            &lt;span className=&quot;tweet__createdAt&quot;&gt;
            {parsedDate}
            &lt;/span&gt;
          &lt;/div&gt;
        &lt;div className=&quot;tweet__message&quot;&gt;
          {tweet.content}
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/li&gt;
  );
};</code></pre>
]]></description>
        </item>
    </channel>
</rss>