<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>alexYooDev.log</title>
        <link>https://velog.io/</link>
        <description>사용자의 편의를 더 생각하고 편안한 UI/UX 개발을 꿈꾸는 프론트엔드 개발자 지망생입니다.</description>
        <lastBuildDate>Tue, 21 Jun 2022 07:31:14 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>alexYooDev.log</title>
            <url>https://images.velog.io/images/juanito_y247/profile/9c084f77-5044-4c57-9007-de1f204f7cec/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. alexYooDev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/juanito_y247" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[CS] 프로세스와 스레드]]></title>
            <link>https://velog.io/@juanito_y247/CS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@juanito_y247/CS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Tue, 21 Jun 2022 07:31:14 GMT</pubDate>
            <description><![CDATA[<h2 id="프로세스와-스레드">프로세스와 스레드</h2>
<p>기술 면접 대비 자료를 보던 중, 프로세스와 스레드에 관한 내용을 공부하던 중, 프로세스와 스레드에 대해서는 그간 공부하면서 많이 접하고 들었었지만 막상 기억속에서 잘 인출해내지 못하는 느낌을 받아 글로 정리하려고 한다.</p>
<p>이번 포스팅을 기회로 프로세스와 스레드 두 개념의 내용에 대해 좀 더 명확히 짚고 넘어가는 것을 이번 글의 목표로 하고 있다.</p>
<h3 id="프로세스란">프로세스란?</h3>
<p>프로세스와 스레드에 대한 내용을 정리하기 앞서, 흔히 말하는 컴퓨터의 프로그램에 대해 정리할 필요가 있다.</p>
<p>프로그램은, 컴퓨터 내에 파일이 저장 장치에 저장되어 있으나, 메모리에 올라가지 않은 정적인 상태를 말한다.</p>
<p>여기서 메모리에 올라가지 않았다는 것은, 아직 운영체제가 프로그램에 독립적인 메모리 공간을 할당해주지 않았다는 것을 의미한다. 모든 프로그램은 운영체제가 실행되기 위한 메모리 공간이 할당되어야 실행될 수 있다.</p>
<p>정적인 상태라는 것은, 실행되지 않은 상태를 의미한다.</p>
<p>따라서, 간단히 말해 프로그램은 아직 실행되지 않고 있는 파일 혹은 코드를 의미한다.</p>
<p>프로그램을 실행하게 되면, 파일 혹은 코드는 컴퓨터의 메모리에 올라가게 되고, 동적인 상태가 된다. 이렇게 실행되고 있는 상태의 프로그램을 프로세스라고 한다.</p>
<p>프로세스의 정의는 실행되고 있는 컴퓨터 프로그램이자, 스케줄링 단계의 작업이다.</p>
<h3 id="스레드란">스레드란?</h3>
<p>스레드의 등장 이전에는 프로그램을 실행할 때, 시작부터 끝까지 프로세스 하나만을 사용하여 진행했다. 그러나 점차 프로그램이 복잡해지고 프로세스 하나만을 사용해서 프로그램을 실행하기 힘들게 되자, 프로그램이 한 가지 이상의 작업을 할 수 있어야 하는 필요가 생기게 되었다.</p>
<p>이로 인해 프로세스 보다 더 작은 실행 단위의 개념이 필요하게 되었고, 이것이 바로 스레드이다.</p>
<p>스레드는 프로세스와 달리 스레드 간 메모리를 공유하며 작동한다. 다시 말해, 프로세스의 자원을 공유하면서 프로세스 실행 흐름의 일부가 되는 것이다.</p>
<p>프로그램이 코드 덩어리라면, 스레드는 코드 내에 선언된 함수라고 볼 수 있다.</p>
<h3 id="프로세스와-스레드의-작동-방식">프로세스와 스레드의 작동 방식</h3>
<h4 id="프로세스의-작동-방식">프로세스의 작동 방식</h4>
<p>운영체제는 프로세스가 메모리에 올라갈 때 프로세스마다 각각 독립된 메모리 영역을 Code, Data, Stack, Heap 의 형식으로 할당한다.</p>
<p>각각의 독립된 메모리 영역을 할당하기 때문에, 프로세는 다른 프로세스의 변수나 자료에 접근할 수 없다.</p>
<h4 id="스레드의-작동-방식">스레드의 작동 방식</h4>
<p>이와 달리 스레드는 같은 프로세스 내의 메모리를 서로 공유할 수 있다.</p>
<p>프로세스가 할당받은 메모리 영역 내에서 Stack 형식으로 할당된 메모리 영역을 따로 할당받고, 나머지 Code, Data, Heap 형식으로 할당된 메모리 영역은 공유한다.</p>
<p>따라서 각각의 스레드는 별도의 스택을 가지고 있으나, 힙 메모리의 경우 서로 공유하여 읽고 쓸 수 있는 것이 가능한 것이다.</p>
<h3 id="프로세스와-스레드의-차이">프로세스와 스레드의 차이</h3>
<p>먼저 스레드는 프로세스 안에 포함되는 개념이다. </p>
<p>프로세스는 컴퓨터의 메로리에 올라가 동적으로 실행되는 상태의 프로그램을 말하고
스레드는 프로세스를 구성하는 더 작은 실행 단위를 말한다.</p>
<p>프로세스는 메모리에 올라갈 때, 운영체제로부터 독자적인 시스템 자원을 할당받지만,
스레드는 프로세스 내부에서 다른 메모리 영역을 같은 프로세스 내 다른 스레드와 공유한다.</p>
<h2 id="싱글-스레드와-멀티-스레드">싱글 스레드와 멀티 스레드</h2>
<p>프로그래밍을 배우면서 종종 싱글 스레드와 멀티 스레드 같은 용어를 접할 기회가 많다. 나와 같은 경우엔, 주로 자바스크립트를 사용하고 공부하면서 &#39;자바스크립트는 싱글스레드 언어&#39; 라는 이야기를 많이 들었다. </p>
<p>싱글스레드 언어가 &#39;하나의 스레드 만을 사용한다. 따라서, 한번에 하나의 작업만을 수행할 수 있다&#39;라는 것은 자바스크립트와 익숙해지며 어렴풋이 알고 있다. 하지만 싱글 스레드에 대한 더 깊은 정보, 혹은 이와 반대되는 개념인 멀티스레드에 대해 알 필요를 느껴서 이에 대해 자료를 찾아보며 정리를 하게 되었다.</p>
<h3 id="싱글-스레드">싱글 스레드</h3>
<p>이름이 의미하는 바와 같이 하나의 프로세스에서 하나의 스레드만을 실행하는 것이다.
싱글 스레드는 하나의 레지스터와 스택으로 표현한다.</p>
<h4 id="장점">장점</h4>
<p>싱글 스레드의 장점은 자원 접근에 대한 동기화를 신경쓰지 않아도 된다는 점이 있다.</p>
<p>자원 접근에 대한 동기화란, 한 프로세스 내 여러 개의 스레드가 공유된 자원에 대해 각 스레드의 접근을 통제하는 작업을 말한다.</p>
<p>이 작업은 프로그래머에게 많은 노력을 요구하는 등 많은 비용을 발생시킨다.</p>
<p>싱글 스레드 모델에서는 이러한 자원 접근 통제 및 동기화에 대한 작업이 필요하지 않다.</p>
<p>또한, 싱글스레드 모델에서는 작업전환 작업을 요구하지 않는다. </p>
<p>작업전환 작업은, 여러 개의 프로세스가 하나의 프로세서를 공유할 때 발생하는 작업으로 많은 비용을 필요로 한다.</p>
<h4 id="단점">단점</h4>
<p>싱글 스레드 모델은 여러 개의 CPU를 활용하지 못한다는 단점이 있다.</p>
<p>싱글 스레드에서 프로세서를 최대한 활용하게 하려면 cluster 모듈을 사용하거나, 외부에서 여러 개의 프로그램 인스턴스를 실행시키는 방법을 사용해야 한다.</p>
<p>두 개의 작업을 하나의 스레드로 처리하는 경우와 비교할 때,
두 개의 스레드로 두 개의 작업을 처리하는 경우, 짧은 시간 동안 2개의 스레드가 번갈아가면서 작업을 수행한다. 이는 신속하게 이루어지기 때문에 동시에 두 작업이 처리되는 것 처럼 보인다.</p>
<p>이러한 멀티 스레드 작업은 스레드 간의 작업전환에 시간이 걸리기 때문에, 싱글 스레드 모델로 작업하는 것 보다 시간 비용이 더 걸릴 수도 있다.</p>
<p>이 때문에 단순히 CPU만을 사용하는 계산의 경우, 오히려 싱글스레드로 프로그래밍하는 것이 효율적일 수 있다.</p>
<h3 id="멀티-스레드">멀티 스레드</h3>
<p>프로그램을 다수의 실행 단위로 나누어 실행하는 모델이다.</p>
<p>멀티 스레드 모델에서는 프로세스 내에서 자원을 공유하여 자원의 생성과 관리의 중복을 최소화 할 수 있다.</p>
<p>서버가 많은 요청을 효율적으로 수행할 수 있는 환경을 제공한다.</p>
<p>각각의 스레드가 고유의 레지스터와 스택으로 표현된다.</p>
<h4 id="장점-1">장점</h4>
<p>새로운 프로세스를생성하는 것 보다 기존 프로세스에서 스레드를 생성하는 것이 빠르기 때문에 효율적이다.</p>
<p>또 프로세스의 자원과 상태를 공유하여 효율적으로 운영이 가능하다.</p>
<p>프로세스의 작업전환보다 스레드의 작업전환이 빠르다.</p>
<h4 id="단점-1">단점</h4>
<p>하나의 스레드만을 실행할 경우, 싱글 스레드 모델보다 실행 시간이 지연될 수 있다.</p>
<p>멀티 스레드 작업을 위해 운영체제의 지원이 필요하며, 스레드 스케줄링을 신경써야 하는 단점이 있다.</p>
<hr>
<p>프로세스와 스레드부터 시작해서 싱글스레드와 멀티스레드 모델까지 정리를 해보았다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[기술면접 스터디 4주차 ]]></title>
            <link>https://velog.io/@juanito_y247/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-4%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@juanito_y247/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-4%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Tue, 31 May 2022 12:15:31 GMT</pubDate>
            <description><![CDATA[<h2 id="함수와-일급-객체">함수와 일급 객체</h2>
<h3 id="일급-객체란">일급 객체란?</h3>
<p>일급 객체는 다음의 조건을 만족한다.</p>
<ol>
<li>이름이 없는 리터럴로 생성할 수 있다.</li>
<li>변수나 자료구조(객체, 배열)에 저장할 수 있다.</li>
<li>함수의 매개변수에 전달할 수 있다.</li>
<li>함수의 반환 값으로 사용할 수 있다.</li>
</ol>
<pre><code>// 무명의 리터럴로 저장할 수 있고 변수에 저장할 수 있음
const increase = function (num) {
    return ++num;
}

const decrease = function (num) {
    return --num;
}

// 매개변수에 전달할 수 있음.
function makeCounter (predicate) {
    let num = 0;

    // 함수의 반환값으로 사용
    return function() {
        num = predicate(num);
        return num;
    }
 }</code></pre><h3 id="자바스크립트에서-함수가-일급-객체라면-일급-객체로-할-수-있는-것은">자바스크립트에서 함수가 일급 객체라면, 일급 객체로 할 수 있는 것은?</h3>
<p>일급 객체로서 함수가 가지는 가장 큰 특징은 일반 객체와 같이 함수의 매개변수에 전달될 수 있으며 함ㅅ의 반환 값으로 사용할 수 있다는 것. =&gt; 함수형 프로그래밍을 가능하게 한다.</p>
<h3 id="함수형-프로그래밍이란">함수형 프로그래밍이란?</h3>
<p>외부 상태를 변경하지 않고 외부 상태에 의존하지 않는 함수를 순수함수라고 함. 순수 함수를 통해 사이드 이펙트를 최대한 억제하여 오류를 피하고 프로그램의 안정성을 높이려는 프로그래밍 패러다임을 함수형 프로그래밍이라고 함.</p>
<h3 id="순수-함수란-일반-함수와의-차이점">순수 함수란? 일반 함수와의 차이점?</h3>
<ol>
<li>순수 함수: 어떤 외수 상태에 의존하지도 않고 변경하지도 않는 함수 =&gt; 사이드 이펙트가 없느 함수</li>
<li>비순수 함수: 외부 상태에 의존하거나 외부 상태를 변경할 수도 있는 함수</li>
</ol>
<h2 id="프로토타입">프로토타입</h2>
<h3 id="객체지향-프로그래밍이란">객체지향 프로그래밍이란?</h3>
<p>객체지향 프로그래밍은 프로그램을 명령어 또는 함수의 목록으로 보는 전통적인 명령형 프로그래밍의 절차지향적 관점에서 벗어나 여러 개의 독립적 단위 즉 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임이다.</p>
<h3 id="객체지향-프로그래밍의-특징이란">객체지향 프로그래밍의 특징이란?</h3>
<ol>
<li>추상화</li>
</ol>
<ul>
<li>객체를 구성할 수 있는 다양한 속성 중에서 프로그램에 필요한 속성만 간추려 내어 표현하는 것</li>
</ul>
<ol start="2">
<li>캡슐화</li>
</ol>
<ul>
<li>데이터 구조와 데이터를 다루는 방법들을 목적에 따라 결합시켜 묶는 것</li>
<li>데이터를 외부가 아닌 함수를 통해서 접근하게 하는 방식</li>
</ul>
<ol start="3">
<li>상속</li>
</ol>
<ul>
<li>상위 개념의 특징을 하위 개념이 물려받는 것</li>
</ul>
<ol start="4">
<li>다형성</li>
</ol>
<ul>
<li>부모클래스에서 물려받은 가상함수를 자식클래스 내에서 오버라이딩(재정의)되어 사용되는 것</li>
</ul>
<h3 id="자바스크립트는-객체지향-프로그래밍인가">자바스크립트는 객체지향 프로그래밍인가?</h3>
<p>자바스크립트는 객체지향 프로그래밍 뿐 아니라 명령형, 함수형 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어. 객체지향 프로그래밍에서 프로토타입 기반의 객체지향 프로그래밍 언어이다.</p>
<h3 id="프로토타입이란">프로토타입이란?</h3>
<p>자바스크립트에서 객체를 만들기 위해서 객체 자신을 만드는 데 사용되는 원형인 프로토타입 객체를 사용하여 객체를 생성 =&gt; 이때 만들어진 객체 안에 <code>__proto__</code> 속성이 자산울 만들어낸 원형을 의미하는 프로토타입 객체를 참조하는 링크가 숨겨져 있음. 이 숨겨진 링크를 프로토타입이라고 한다.</p>
<h2 id="strict-mode">strict mode</h2>
<h3 id="strict-mode란">strict mode란?</h3>
<p>오타나 문법 지식의 미비로 인한 실수를 줄여 안정적인 코드를 생산하기 위해 ES6에 추가된 모드.
strict mode는 자바스크립트 언어의 문법을 좀 더 엄격히 적용하여 오류를 발생시킬 가능성이 높거나 자바스크립트 엔진의 최적화 작업에 문제를 일으킬 수 있는 코드에 대해 명시적인 에러를 발생시킨다.</p>
<h3 id="strict-mode를-통해-예방할-수-있는-것">strict mode를 통해 예방할 수 있는 것</h3>
<ol>
<li>암묵적 전역</li>
<li>변수, 함수, 매개변수의 삭제</li>
<li>매개변수 이름의 중복</li>
</ol>
<h2 id="빌트인-객체">빌트인 객체</h2>
<h3 id="빌트인-객체란-종류는">빌트인 객체란? 종류는?</h3>
<p>개발자가 모든 기능을 구현하지 않고, 편하게 개발할 수 있도록 자바스크립트에서 기본적으로 제공하는 객체
자바스크립트에서 객체는 크게 3개의 객체로 분류할 수 있음</p>
<ol>
<li>표준 빌트인 객체</li>
</ol>
<ul>
<li>자바스크립트에서 기본적으로 제공하는 ECMAScript 사양에 정의된 표준 객체. 애플리케이션 전역의 공통 기능을 제공</li>
<li>전역 객체의 프로퍼티로써 제공됨. 따라서 별도의 선언없이 전역 변수처럼 언제나 참조 가능.</li>
<li>new 연산자를 사용하여 표준 빌트인 객체와 결합하여 선언하면, 생성된 인스턴스로 하여금 해당 함수에 내장된 프로토 타입 메서드를 이용할 수 있음.</li>
</ul>
<ol start="2">
<li>호스트 객체</li>
</ol>
<ul>
<li>ECMAScript 사양에 정의되어 있지 않지만 자바스크립트 실행 환경(브라우저 혹은 Node.js)에서 추가로 제공하는 객체</li>
<li>브라우저 환경: DOM, BOM, Canvas, XMLHttpRequest, fetch, Web Storage, Web Component와 같은 클라이언트 사이드 Web API를 호스트 객체로 제공</li>
</ul>
<ol start="3">
<li>사용자 정의 객체</li>
</ol>
<ul>
<li>표준 빌트인 객체와 호스트 객체처럼 기본 제공되는 객체가 아닌 사용자가 직접 정의한 객체</li>
</ul>
<h3 id="래퍼-객체란">래퍼 객체란?</h3>
<p>래퍼 객체는 원시 타입을 마치 객체 타입처럼 사용하는 과정 속에서 생기는 임시 객체. 원시 타입인 Number, String, Boolean으로 특정된다.</p>
<p>이는 원시값인 문자열, 숫자, 불리언 값의 경우 이들 원시값에 대해 마치 객체처럼 닷(.)노테이션 표기법으로 접근하면 자바스크립트 엔지이 일시적으로 원시값을 연관된 객체로 변환해주기 때문이다.</p>
<p>즉, 원시값을 객체처럼 사용하면 자바스크립트 엔진은 암묵적으로 연관된 객체를 생성하여 생성된 객체로 프로퍼티에 접근하거나 메서드를 호출하고 다시 원시값으로 되돌린다.</p>
<h2 id="this">this</h2>
<h3 id="this란">this란?</h3>
<ul>
<li>this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수이다.</li>
<li>this를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있다.</li>
<li>this는 자바스크립트 엔진에 의해 암묵적으로 생성되며, 코드 어디서든 참조할 수 있다.</li>
<li>단, this가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.</li>
</ul>
<h3 id="this-바인딩이란">this 바인딩이란?</h3>
<p>바인딩이란 식별자와 값을 연결하는 과정을 의미. 
예를 들어, 변수 선언은 변수 이름(식별자)과 확보된 메모리 공강의 주소를 바인딩하는 작업.
this 바인딩은 this(키워드로 분류되나 식별자 역할)와 this가 가리키는 객체를 바인딩하는 것</p>
<h3 id="this가-바인딩되는-객체의-차이">this가 바인딩되는 객체의 차이</h3>
<ul>
<li>일반 함수 호출 : 전역 객체(window/global) 바인딩</li>
<li>콜백 함수 호출 : 전역 객체(window/global) 바인딩</li>
<li>내부 함수 호출 : 전역 객체(window/global) 바인딩</li>
<li>메서드 호출 : 메서드를 호출한 객체</li>
<li>생성자 함수 호출 : 생성자 함수가 생성할 인스턴스</li>
<li>Function.prototype.apply/call/bind 메서드에 의한 간접 호출: 메서드에 첫번째 인수로 전달한 객체</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[기술 면접 스터디 3회차]]></title>
            <link>https://velog.io/@juanito_y247/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-3%ED%9A%8C%EC%B0%A8</link>
            <guid>https://velog.io/@juanito_y247/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-3%ED%9A%8C%EC%B0%A8</guid>
            <pubDate>Wed, 25 May 2022 05:58:27 GMT</pubDate>
            <description><![CDATA[<h3 id="객체-리터럴">객체 리터럴</h3>
<h4 id="자바스크립트에서-객체란">자바스크립트에서 객체란?</h4>
<p>자바스크립트는 객체 기반의 프로그래밍 언어. 자바스크립트를 구성하는 거의 모든 것이 객체. 원시값을 제외한 함수, 배열, 객체는 모두 객체이다. 원시 타입은 단 하나의 값만을 나타내지만 객체 타입은 다양한 타입의 값을 하나의 단위로 묶어서 구성된 복합적인 자료구조이다. 원시값은 변경 불가능한 값이지만 객체 타입의 값은 변경이 가능하다.</p>
<p>객체는 0개 이상의 프로퍼티로 구성된 집합, 프로퍼티의 키와 값으로 구성된다.</p>
<h4 id="함수와-메서드의-차이점">함수와 메서드의 차이점</h4>
<p>자바스크립트에서 사용할 수 있는 모든 값은 프로퍼티 값이 될 수 있음. 함수는 일급 객체이기 때문에 값처럼 할당될 수 있으므로 프로퍼티 값이 함수일 경우, 메서드로 불린다. 객체 내부에 객체의 프로퍼티로서 참조되고 조작할 수 있는 함수를 메서드라고 한다 =&gt; 메서드는 객체에 묶여 있는 함수</p>
<h3 id="자바스크립트에서-객체를-생성하는-방법">자바스크립트에서 객체를 생성하는 방법</h3>
<p>자바스크립트는 &#39;프로토타입 기반 객체지향 언어&#39; &#39;클래스 기반 객체지향 언어와 달리 다양한 객체 생성 방법을 지원한다.</p>
<ol>
<li>객체 리터럴:<code>{}</code> 형태의 리터럴로 객체를 생성한다.</li>
<li>Object 생성자 함수: Object 생성자 함수로 인스턴스 객체를 생성할 수 있다.</li>
<li>생성자 함수: 임의의 생성자 함수를 통해 인스턴스 객체를 만들 수 있다.</li>
<li>Object.create 메서드를 사용해서 객체를 생성할 수 있다.</li>
<li>ES6 부터는 class를 활용하여 인스턴스 객체를 생성할 수 있다.</li>
</ol>
<h3 id="전역-객체란">전역 객체란?</h3>
<ul>
<li>전역 객체는 코드가 실행 (런타임) 전 단계에서 자바스크립트에 의해 생성되는 특수 객체</li>
<li>클라이언트 사이드 환경 (브라우저)에서는 window, 서버 사이드 (Node.js)에서는 global 객체이다.</li>
<li>전역 객체는 표준 빌트인 객체(Object, String, Number, Function, Array) 등 들과 환경에 따른 호스트 객체, 그리고 var 키워드로 선언한 전역 변수와 전역 함수를 프로퍼티로 갖는다.</li>
</ul>
<h2 id="원시값과-객체-비교">원시값과 객체 비교</h2>
<h3 id="동적-타이핑을-지원하는-자바스크립트에서-데이터의-타입을-2가지로-나누는-이유">동적 타이핑을 지원하는 자바스크립트에서 데이터의 타입을 2가지로 나누는 이유?</h3>
<ol>
<li>원시 타입의 값, 원시 값은 변경이 불가능 (immutable value) 인 특성을 지니고, 객체 타입의 값은 변경 가능한 속성(mutable value)을 지님</li>
<li>원시 값을 변수에 할당하면 변수는 (2진수로 변환 된) 실제 값이 저장. 객체를 변수에 할당하면 변수에는 참조 값 (메모리 주소)가 저장되는 속성으로 나뉨</li>
<li>원시값을 갖는 변수를 다른 변수에 할당하면 원본의 원시값이 복사되어 전달 (값에 의한 전달). 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조값이 복사되어 전달(참조에 의한 전달) 되어 서로 다른 속성 지님</li>
</ol>
<h3 id="값에-의한-전달이란">값에 의한 전달이란?</h3>
<p>변수에 원시값을 갖는 변수를 할당하면 할당 받는 변수에는 할당하는 변수의 원시값이 복사되어 전달된다. 값은 독립적으로 다른 메모리 공간에 저장되어 각각 변경되어도 서로 영향을 미치지 않는다. =&gt; 값에 의한 전달</p>
<h3 id="참조에-의한-전달이란">참조에 의한 전달이란?</h3>
<p>객체의 프로퍼티 개수는 정해져 있지 않아 동적으로 추가할 수 있고 삭제할 수 있다. 프로퍼티 값에도 제약이 없다. 객체는 원시값과 같이 확보해야 할 메모리 공간의 크기를 사전에 정해 둘수 없다. 위와 같은 객체의 가변성의 성질 때문에 객체를 할당한 변수가 기억하는 메모리 주소를 통해 대신 참조값에 접근하는 방식을 쓸 수 있다.
객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조값이 복사되어 전달된다. 참조값은 같은 메모리 주소를 가리키는 주소 값이므로, 한 변수의 객체를 변경하면 원본 객체 또한 변경된다. =&gt; 참조에 의한 전달</p>
<h2 id="함수">함수</h2>
<h3 id="자바스크립트에서-함수를-정의하는-방법">자바스크립트에서 함수를 정의하는 방법?</h3>
<ol>
<li>함수 선언식 (function 키워드를 통해 바로 선언)</li>
<li>함수 표현식 (function 키워드로 생성한 함수를 변수에 저장)</li>
<li>Function 생성자 함수 (new 키워드를 통해 생성자함수를 호출한 값을 변수에 저장)</li>
<li>화살표 함수 (ES6 문법)</li>
</ol>
<h3 id="함수-선언문과-함수-표현식의-차이점">함수 선언문과 함수 표현식의 차이점?</h3>
<p>코드가 한 줄씩 순차적으로 실행되는 런타임에는 이미 함수 객체가 생성되어 있고, 함수 이름과 동일한 식별자에 할당까지 완료된 상태.
함수 선언문의 코드가 평가되고 실행되기 이전에 함수를 참조할 수 있고, 호출할 수 있음
함수 호이스팅: 함수의 선언문이 코드의 선단에 끌어 올려진 것처럼 동작하는 자바스크립트의 특이 동작</p>
<p>이에 반해 함수 표현식은, var 키워드로 생성한 변수에 할당됨. undefined로 초기화 되고 함수 선언문을 통해 암묵적으로 생성된 식별자는 함수 객체로 초기화 된다.
var 키워드를 사용한 변수 선언문은 이전에 변수를 참조하면 변수 호이스팅에 의해 undefined로 평가되지만, 함수 선언문으로 정의한 함수를 함수 선언문 이전에 호출하면 함수 호이스팅에 의해 호출이 가능하다.</p>
<h3 id="즉시-실행-함수란">즉시 실행 함수란?</h3>
<ol>
<li>함수 정의와 동시에 즉시 호출되는 함수를 뜻한다. 즉시 실행 함수는 단 한번만 호출되고 다시 호출할 수 없다.</li>
<li>즉시 실행 함수는 함수 이름이 없는 익명 함수를 사용하는 것이 일반적. 함수 이름이 있는 기명도 사용할 수 있지만, 어차피 다시 호출할 수 없기 때문에 무용</li>
<li>즉시 실행함수는 그룹 연산자로 감싸야한다. (함수의 정의가 선언문 형식에 맞지 않기 때문 =&gt; 먼저 함수 리터럴을 평가해서 함수 객체를 생성하기 위함이다.)</li>
</ol>
<h2 id="스코프">스코프</h2>
<h3 id="스코프란">스코프란?</h3>
<p>유효범위라는 뜻을 식별자가 유효한 범위를 뜻한다.
자바스크립트 엔진은 스코프를 통해 어떤 변수를 참조해야 하는지 결정하기 때문에, 스코프는 자바스크립트 엔진이 식별자를 검색할 때 사용하는 규칙이라 할 수 있다.</p>
<h3 id="스코프의-종류">스코프의 종류?</h3>
<p>스코프는 크게 전역 스코프와 지역 스코프로 구분된다.
스코프는 상대적인 개념으로 전역이란 코드의 가장 바깥 영역을 의미. 전역 스코프에 변수를 선언하면 변수는 전역 스코프를 갖는 전역 변수가 된다. 전역 변수는 어디서든 참조할 수 있다.</p>
<p>지역이란 함수 몸체 내부를 말한다. 지역은 지역 스코프를 만들고, 지역 스코프에 변수를 선언 하면 지역 스코플를 갖는 지역 변수가 된다. 지역 변수는 자신의 스코프와 하위 ㅅ지역 스코프에서 접근할 수 있다.</p>
<h3 id="렉시컬-스코프란">렉시컬 스코프란?</h3>
<p>함수를 어디서 호출했는 지가 아닌 어디서 정의했는지에 따라 함수의 상위 스코프를 결정하는 것이 정적 스코프 = 렉시컬 스코프이다.</p>
<h3 id="전역-변수로-변수를-선언하면-생기는-문제점">전역 변수로 변수를 선언하면 생기는 문제점</h3>
<ol>
<li>암묵적 결합</li>
</ol>
<ul>
<li>전역 변수를 선언한 의도는 코드 어디서든 참조하고 할당할 수 있는 변수를 사용하겠다는 것임. 이는 모든 코드가 전역 변수를 참조하고 변경할 수 있는 암묵적 결합을 허용하는 것으로, 변수의 유효 범위가 클수록 코드의 가독성은 나빠지고 의도치 않게 상태가 변경될 수 있는 위험성도 높아진다.</li>
</ul>
<ol start="2">
<li>변수의 긴 생명주기</li>
</ol>
<ul>
<li>전역 변수의 생명주기는 길다. 따라서 메모리 리소스도 오랜 기간 소비하게 됨. 전역 변수는 상태를 변경할 수 있는 기간도 길고 기회도 많음. 변수 이름이 중복된다면 의도치 않은 재할당이 이루어지기도 하는 문제가 있음</li>
</ul>
<ol start="3">
<li>스코프 체인 상에서 종점에 존재</li>
</ol>
<ul>
<li>전역 변수는 스코프 제인 상에서 종점에 존재. 이는 변수를 검색할 때 전역 변수가 가장 마지막에 검색된다는 것을 뜻한다. 전역 변수의 검색 속도가 가장 느리게 됨. 검색 속도의 차이는 크지 않아도 분명히 존재</li>
</ul>
<ol start="4">
<li>네임스페이스 오염</li>
</ol>
<ul>
<li>자바스크립트의 문제는 하나의 파일이 분리되어 있다고 해도 하나의 전역 스코프를 공유한다는 것이다. 다른 파일 내에 동일한 이름으로 명명된 전역 변수나 전역 함수가 같은 스코프 내에 존재할 경우에 예상치 못한 결과를 가져올 수 있다.</li>
</ul>
<h2 id="생성자-함수에-의한-객체-생성">생성자 함수에 의한 객체 생성</h2>
<h3 id="생성자-함수란">생성자 함수란?</h3>
<p>생성자 함수는 new 연산자와 함께 호출되어 객체를 생성하는 함수를 의미한다. 생성자 함수에 의해 생성된 객체는 인스턴스라고 한다.</p>
<p>자바스크립트는 Object, String, Number, Boolean 등등 여러 내장 생성자 함수를 제공한다.</p>
<p>생성자 함수는 객체를 생성하기 위해 사용되지만, 반드시 Object 생성자 함수를 사용해 객체를 생성해야 하는 것은 아님 =&gt; 객체 리터럴을 통해서도 객체를 생성할 수 있기 때문</p>
<h3 id="객체-리터럴로-만들-때와의-차이점-생성자-함수를-사용하는-이유">객체 리터럴로 만들 때와의 차이점? 생성자 함수를 사용하는 이유</h3>
<p>객체 리터럴에 의한 객체 생성 방식은 단 하나의 객체만을 생성하기 때문에 같은 프로퍼티를 갖는 여러 개의 객체를 생성해야 하는 경우 비효율적이다.
생성자 함수를 통해 객체를 생성한다면, 객체를 생성하기 위한 템플릿처럼 프로퍼티 구조가 동일한 객체 여러 개를 간편하게 생성할 수 있다.</p>
<h3 id="생성자-함수가-객체를-생성하는-과정">생성자 함수가 객체를 생성하는 과정?</h3>
<p>생성자 함수를 생성하는 과정은 </p>
<ol>
<li>생성자 함수 선언 
<code>function Circle(radius) {}</code></li>
<li>인스턴스 생성 <pre><code>const circle = new Circle(5);</code></pre></li>
<li>인스턴스 초기화 <pre><code class="language-this.radius"> this.getDiameter = function() {
     return 2 * this.radius;
 }</code></pre>
</li>
<li>인스턴스 반환 의 과정을 거친다
인스턴스를 생성할 때, 생성자 함수를 호출할 때 넣은 인수를 this 바인딩을 통해 프로퍼티에 할당 =&gt; 인스턴스 반환</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[기술 면접 스터디 2회차]]></title>
            <link>https://velog.io/@juanito_y247/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-2%ED%9A%8C%EC%B0%A8</link>
            <guid>https://velog.io/@juanito_y247/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%84%B0%EB%94%94-2%ED%9A%8C%EC%B0%A8</guid>
            <pubDate>Tue, 17 May 2022 07:37:31 GMT</pubDate>
            <description><![CDATA[<p>1회차 면접 스터디 후, 배운 것을 설명하는 것이 쉽지 않은 일이라는 것을 깨달았다. 그동안 자바스크립트로 웹 서비스 개발 프로젝트도 진행하며 나름 잘 다룰 수 있다고 생각했지만 최근 들어 자바스크립트 이론 및 문법 공부를 다시 하면서 자바스크립트가 어떻게 동작하는 지에 대한 지식은 많이 모자랐고 배울 것이 아직도 많다는 것을 느끼게 되었다.</p>
<p>2회차 부터는 일주일의 시간이 주어지니, 범위를 넓혀 2개 주제에서 5개로 하였다. </p>
<h3 id="데이터-타입">데이터 타입</h3>
<ul>
<li>데이터 타입의 종류는 어떤 것들이 있나?</li>
</ul>
<p>자바스크립트의 데이터 타입에는 크게 원시 타입과 객체 타입 (레퍼런스 타입)이 있다. </p>
<h4 id="원시-타입">원시 타입</h4>
<ol>
<li>숫자 타입 : 자바스크립트에서는 정수 타입과 실수 타입으로 구분되어 있지 않은 number 타입이 존재한다. 숫자타입은 기본적으로 실수 타입이다.</li>
<li>문자열 타입: 여러 문자로 이루어진 문자열의 타입이다. 홀따옴표, 쌍따옴표, 백틱으로 표현할 수 있다.</li>
<li>불리언 타입: 논리형 타입으로 true(참) false(거짓)이 있다.</li>
<li>undefined 타입: 아무 값도 할당되지 않은 변수, 선언만 된 변수에 암묵적으로 할당되는 값이며 말 그대로 타입이 정의 되지 않은 값이다.</li>
<li>null 타입: 값이 없다는 것을 의도적으로 명시할 때 사용하는 값인 null의 타입이다.</li>
<li>symbol 타입: ES6에서 추가된 새로운 타입으로 원시 타입이다.</li>
</ol>
<h4 id="객체-타입">객체 타입</h4>
<p>기본적으로 위의 원시 타입을 제외한 객체, 함수, 배열은 객체 타입을 갖는다. 자바스크립트에서 함수, 배열은 객체이다.</p>
<h4 id="심벌-타입이란">심벌 타입이란?</h4>
<p>심벌 타입은 변경이 불가능한 원시타입이다. 다른 값과 중복되지 않은 유일무의한 값으로 주로 이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티 키를 만들기 위해 활용된다.</p>
<h4 id="데이터-타입이-필요한-이유">데이터 타입이 필요한 이유?</h4>
<ol>
<li><p>값을 저장할 때 확보해야 하는 메모리 공간의 크기를 결정하기 위해서</p>
<blockquote>
<p>데이터는 메모리에 저장되고 이를 참조해서 사용할 수 있어야 함. 컴퓨터에 주어진 메모리는 한정적이며 특정 데ㅣ터를 저장하려면 메모리의 공간이 얼마나 필요한 지 파악하는 것이 중요하기 때문이다
메모리의 공간에 값을 저장할 때에는 2진수의 형태로 저장되는 데, 데이터 타입은 얼마만큼의 데이터 공간을 확보해야 하는 지 명시해주는 역할을 하는 것이다.</p>
</blockquote>
</li>
<li><p>값을 참조할 때 한번에 읽어 들여야 할 메모리 공간의 크기를 결정해야 하기 위해</p>
<blockquote>
<p>변수를 선언 &amp; 초기화 하면서 메모리 공간에 저장이 되면, 해당 변수에 접근할 때 그 값이 저장된 메모리 공간을 찾아간다. 이때 값을 참조한다고 하는데, 참조하기 위해서는 한번에 읽어들여야 할 메모리의 크기를 알아야 함.
각 타입 마다 저장되는 비트 단위가 정해져 있으므로, 각 타입에 맞는 단위가 아니라면 값을 제대로 얻을 수 없다.</p>
</blockquote>
</li>
<li><p>메모리에서 읽어 들인 2진수를 어떻게 해석할 지 결정하기 위해서 이다.</p>
<blockquote>
<p>메모리 상에 값은 2진수 형태로 저장된다. 때문에 0과 1로 이루어진 이진수 값을 어떻게 해석하느냐에 따라 값이 달리질 수 있다. 이를 해석하는 방법으로 데이터 타입이 사용된다.</p>
</blockquote>
</li>
</ol>
<h4 id="정적-타이핑이란">정적 타이핑이란?</h4>
<p>C 나 java와 같은 언어에서는 데이터 타입을 명시적으로 지정한다. 이를 정적 타이핑이라고 하며 변수를 선언함과 동시에 타입이 지정된다. 정적 타입 언어의 타입은 이후 변경할 수 없고, 타입에 맞는 값만을 담을 수 있다. 정적으로 타입을 지정한 값에 대한 타입 체크는 컴파일 시점에서 수행된다. 타입이 값과 일치 하지 않다면 에러를 발생시키고 실행을 막는다. 메모리 상의 이진수의 값을 잘못 해석하거나, 메모리 공간의 잘못된 접근, 틀린 크기의 메모리 공간 할당 등의 문제를 막기 위해서 이다.</p>
<h4 id="동적-타이핑이란">동적 타이핑이란?</h4>
<p>자바스크립트는 정적 타입 언어와 달리, 변수를 선언할 때 타입이 지정되지 않는다. 자바스크립트의 변수는 선언이 아닌 할당되는 값에 따라 타입이 결정된다. 그리고 어떠한 값이 재할당되는 지에 따라 타입은 언제든지 동적으로 변할 수 있다. 이러한 자바스크립트의 타입 지정 특징을 동적 타이핑이라고 하며 이러한 타입 지정 메커니즘을 가진 언어를 동적 타입 언어라고한다. (자바스크립트, 파이썬, php가 이에 해당)</p>
<h3 id="타입변환과-단축-평가">타입변환과 단축 평가</h3>
<h4 id="명시적-타입-변환이란">명시적 타입 변환이란?</h4>
<p>자바스크립트의 모든 값은 타입이 있고, 값의 타입은 개발자의 의도에 따라 다른 타입으로 재지정 될 수 있다. 이렇게 개발자의 의도에 따라 값의 타입을 변환하는 것을 명시적 타입 변환 혹은 타입 캐스팅이라고 한다.</p>
<h4 id="명시적-타입-변환-함수의-예">명시적 타입 변환 함수의 예?</h4>
<p>문자열이 아닌 값 =&gt; 문자열 타입을 변환</p>
<ol>
<li>String 생성자 함수에 값을 인자로 전달하고 new 연산자 없이 호출</li>
<li>Object.prototype.toString 메서드를 사용</li>
<li>문자열 연결 연산자 즉 문자가 아닌 타입의 값과 문자열 타입의 값을 더하기 연산 하는 것</li>
</ol>
<p>숫자 타입이 아닌 값을 숫자타입으로 변환</p>
<ol>
<li>Number 생성자 함수에 값을 인자로 전달하고 new 연산자 없이 호출</li>
<li>parseInt, parseFloat 함수를 사용하는 방법</li>
<li><ul>
<li>단항 산술 연산자를 사용</li>
</ul>
</li>
<li><ul>
<li>산술 연산자를 사용</li>
</ul>
</li>
</ol>
<p>불리언 타입이 아닌 값을 불리언 타입으로 변환</p>
<ol>
<li>Boolean 생성자 함수를 new 연산자 없이 호출</li>
<li>! 부정 논리 연산자를 두번 사용하는 방법</li>
</ol>
<h4 id="암묵적-타입-변환이란">암묵적 타입 변환이란?</h4>
<p>개발자의 의도와 달리 표현식을 평가하는 도중 자바스크립트에 의해 값에 따라 암묵적으로 타입이 자동 변환되는 것이며, 암묵적 타입 변환 혹은 강제 타입 변환이라고도 불린다.</p>
<h4 id="truthy-혹은-falsy-한-값은-무엇인가">truthy 혹은 falsy 한 값은 무엇인가?</h4>
<p>자바스크립트 엔진은 불리언 타입이 아닌 값을 truthy한 값 falsy한 값으로 구분한다.제어문의 조건식과 같이 불리언 값으로 평가되어야 할 문맥에서 truthy 값은 true로 falsy 값은 false로 암묵적 타입 변환됨</p>
<h3 id="배열">배열</h3>
<h4 id="자바스크립트의-배열은-자료구조의-배열과-같나">자바스크립트의 배열은 자료구조의 배열과 같나?</h4>
<p>자료구조에서의 배열은 동일한 크기의 메모리 공간이 틈없이 연속적으로 나열된 자료구조, 배열의 요소는 하나의 데이터 타입으로 통일되어 있으며, 서로 연속적으로 인접해있음 (밀집 배열)</p>
<p>자바스크립트의 배열은 이와 달리, 배열요소를 위한 각각의 메모리 공간은 동일한 크기를 갖지 않으며 연속적으로 이어져 있지 않음 (다른 타입의 값으로 구성될 수 있고, 중간에 값이 없을 수 있음)
이와 같이 배열의 요소가 연속적으로 이어져 있지 않는 배열을 희소(sparse array)라고 함</p>
<p>따라서 자바스크립트이의 배열은 자료구조의 배열과 달리 배열의 동작과 유사하게 동작하는 객체이다</p>
<h4 id="배열-메서드의-종류">배열 메서드의 종류</h4>
<p>배열의 메서드는 두가지 종류로 나뉜다.</p>
<ul>
<li>원본 배열을 변경하는 메서드</li>
<li>원본 배열을 변경하지 않고 새로운 배열을 생성하여 반환하는 메서드</li>
</ul>
<p>주로 ES5 부터 도입된 메열 메서드는 원본 배열을 변경하지 않고, 이전에 도입된 메서드는 배열을 직접 변경
원본 배열을 직접 변경하는 메서드는 메서드 몸체 외부의 상태를 변경하는 등 사이드 이펙트가 발생하기 때문에 사용할 떄 주의가 필요하며, 사이드 이펙트를 피하기 위해 가급적 원본 배열을 변경하지 않는 것이 좋다.</p>
<p>Array.isArray()
Array.prototype.push -&gt; 원본 배열을 변경 
Array.prototype.pop -&gt; 원본 배열을 변경
Array.prototype.unshift -&gt; 원본 배열을 변경한다
Array.prototype.concat 
Array.prototype.splice -&gt; 원본 배열 변경
Array.prototype.slice 
Array.prototype.join -&gt; 원본 배열을 변경
Array.prototype.reverse -&gt; 원본 배열을 변경
Array.prototype.fill -&gt; 원본 배열을 변경
Array.prototype.includes </p>
<h4 id="고차-함수란">고차 함수란?</h4>
<p>고차함수는 함수를 인자로 전달 받거나 함수를 반환하는 함수
자바스크립트의 함수는 일급 객체로, 값처럼 인수로 전달할 수 있고 반환될 수 있음
고차 함수는 외부의 상태 변경이나 가변 데이터를 피하고 불변성을 지향하는 함수 프로그래밍에 기반을 두고 있음</p>
<ul>
<li>함수형 프로그래밍은 순수 함수와 보조 함수의 조합을 통해 로직 내에 존재하는 조건문과 반복문을 제거 =&gt; 복잡성을 해결하고 변수의 사용을 억제하여 상태 변경을 피하려는 프로그래밍 패러다임.
함수형 프로그래밍은 순수함수 (입력으로 들어온 동일한 값에는 항상 같은 아웃풋을 반환)을 통해 부수효과를 최대한 억제하고 오류를 피하고 프로그래밍의 안정성을 꾀한다.</li>
</ul>
<p>대부분의 고차함수들을 매개변수로 콜백 함수를 받아 사용되어 원본 배열을 바탕으로 새로운 결과를 창조하는 데 사용</p>
<p>고차 함수 기반 배열 메서드 
Array.prototype.sort
Array.prototype.forEach
Array.prototype.map
Array.prototype.filter
Array.prototype.reduce
Array.prototype.some
Array.prototype.every
Array.prototype.find</p>
<h4 id="foreach-메서드와-map-메서드의-차이점">forEach 메서드와 map 메서드의 차이점</h4>
<ul>
<li>forEach 메서드는 호출한 배열의 각 요소에 대해 매개변수로 전달한 콜백 함수내에 정의된 로직을 실행한다.</li>
<li>map 메서드는 호출한 배열의 각 요소에 대해 매개변수로 전달한 콜백 함수 내에 정의 된 로직을 실행하여 새로운 배열을 생성한다.</li>
</ul>
<p>forEach는 반환값이 없고 map은 새로이 생성된 배열을 반환.
map 메서드를 호출한 배열과 새로 생성된 배열은 1대1로 매핑됨
forEach와 map 메서드의 콜백함수는 호출한 배열의 각 요소값, 각 인덱스, this를 순차적으로 받는다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Query - Devtools]]></title>
            <link>https://velog.io/@juanito_y247/React-Query-Devtools</link>
            <guid>https://velog.io/@juanito_y247/React-Query-Devtools</guid>
            <pubDate>Tue, 01 Feb 2022 16:03:38 GMT</pubDate>
            <description><![CDATA[<h1 id="react-query-devtools">React Query Devtools</h1>
<p>이번에는 React Query 라이브러리에서 제공하는 강력한 도구인 React Query Devtools에 대해 알아보았다.</p>
<p>먼저 React Query Devtools를 사용하려면 ReactQueryDevtools 모듈을 불러와야 한다.</p>
<pre><code class="language-js">import &#39;./App.css&#39;;
import { Routes, Route, Link } from &#39;react-router-dom&#39;;
import { QueryClient, QueryClientProvider } from &#39;react-query&#39;;
import { ReactQueryDevtools } from &#39;react-query/devtools&#39;;
import { HomePage } from &#39;./components/Home.page&#39;;
import { RQSuperHeroesPage } from &#39;./components/RQSuperHeroes.page&#39;;
import { SuperHeroesPage } from &#39;./components/SuperHeroes.page&#39;;

const queryClient = new QueryClient();

function App() {
  return (
    &lt;QueryClientProvider client={queryClient}&gt;
      &lt;nav&gt;
        &lt;ul&gt;
          &lt;li&gt;
            &lt;Link to=&#39;/&#39;&gt;Home&lt;/Link&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;Link to=&#39;/super-heroes&#39;&gt;Traditional Super Heroes&lt;/Link&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;Link to=&#39;/rq-super-heroes&#39;&gt;RQ Super Heroes&lt;/Link&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/nav&gt;
      &lt;Routes&gt;
        &lt;Route path=&#39;/&#39; element={&lt;HomePage /&gt;} /&gt;
        &lt;Route path=&#39;/super-heroes&#39; element={&lt;SuperHeroesPage /&gt;} /&gt;
        &lt;Route path=&#39;/rq-super-heroes&#39; element={&lt;RQSuperHeroesPage /&gt;} /&gt;
      &lt;/Routes&gt;
      &lt;ReactQueryDevtools initialIsOpen={false} position=&#39;bottom-right&#39; /&gt;
    &lt;/QueryClientProvider&gt;
  );
}

export default App;
</code></pre>
<p>위와 같이 import를 하고, QueryClientProvider Components가 닫히기전 하단 부분에 호출을 하고, 최초에는 닫혀있도록 initialIsOpen 속성을 false로 두고, position은 bottom-right로 설정한다.</p>
<p>그 후 실행을 한다면 다음과 같은 화면이 보일 것이다.</p>
<p><img src="https://images.velog.io/images/juanito_y247/post/ab55975b-82f0-49b4-9290-70f65339c2b4/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.30.25(2).png" alt="react query devtools live"></p>
<p>위와 같이 꽃모양의 버튼이 생성된다. 해당 버튼을 클릭하면</p>
<p><img src="https://images.velog.io/images/juanito_y247/post/d7abffd9-2aff-4d26-a150-491c914b8484/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.33.33(2).png" alt="react query devtools live2"></p>
<p>위와 같이 React Query에서 제공하는 개발자 도구를 열 수 있다. 개발자 도구 안에는 </p>
<ul>
<li>fresh</li>
<li>fetching</li>
<li>stale</li>
<li>inactive    </li>
</ul>
<p>와 같은 Data Fetching State를 확인할 수 있다.</p>
<p>[&quot;super-heroes&quot;] 리스트를 클릭하면, fetch한 API에 대한 정보를 받아올 수 있다.
<img src="https://images.velog.io/images/juanito_y247/post/19473da4-b4b7-4115-bddf-e1676ba8bfdc/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-02%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.57.07(2).png" alt="react query devtools live3"></p>
<p>오른쪽 란에서 Observer는 해당 API call를 요청하는 observer의 수를 나타내며, 이 경우엔 RQ super heroes page 내의 useQuery call을 나타낸다. Last Updated에서 마지막으로 query를 불러온 시간을 확인할 수도 있다.</p>
<p>Actions 버튼은 query와 관련된 action을 해볼 수도 있다.</p>
<p>Data Explorer 탭에서는 chrome devtool의 network 탭에서 확인할 수 있었던 정보를 따로 확인할 수도 있다.</p>
<p>Query Explort 에서는 query의 상태 또한 확인할 수 있다.</p>
<p>위에서 기술한 React Query Devtools에서 제공하는 정보를 잘 활용하면, Data Fetching 작업을 더 수월하게 수행할 수 있는 것이 유용하다고 볼수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Query 사용하기]]></title>
            <link>https://velog.io/@juanito_y247/React-Query-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@juanito_y247/React-Query-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 01 Feb 2022 15:27:09 GMT</pubDate>
            <description><![CDATA[<p>새로운 기술을 도입하기 전에는, 이 기술이 어떤 문제를 해결하려고 하는 지에 대해 먼저 파악하는 것이 중요하다는 멘토님의 말씀을 따라 먼저 React Query를 사용하지 않은 기존의 Data Fetching 방식으로 연습을 진행했다.</p>
<pre><code class="language-json">/* db.json */
{
  &quot;superheroes&quot;: [
    {
      &quot;id&quot;: 1,
      &quot;name&quot;: &quot;Batman&quot;,
      &quot;alterEgo&quot;: &quot;Bruce Wayne&quot;
    },
    {
      &quot;id&quot;: 2,
      &quot;name&quot;: &quot;Superman&quot;,
      &quot;alterEgo&quot;: &quot;Clark Kent&quot;
    },
    {
      &quot;id&quot;: 3,
      &quot;name&quot;: &quot;Wonder Woman&quot;,
      &quot;alterEgo&quot;: &quot;Princess Diana&quot;
    }
  ]
}
</code></pre>
<p>해당 JSON 데이터는 json-server 라이브러리를 통해 서버화한 파일이다. 로컬에서 임의로 만든 파일이지만, 서버로 내보내어 비동기 요청을 보낼 수 있게 하였다. 해당 작업은, package.json의 scripts 란에 </p>
<pre><code class="language-shell">&quot;serve-json&quot;: &quot;json-server --watch db.json --port 4000&quot;</code></pre>
<p>를 추가하여 명령어로 4000번 포트로 돌리면 해당 서버가 돌아갈 수 있도록 하였다.</p>
<pre><code class="language-js">import axios from &#39;axios&#39;;
/* 
단순히 서버에서 데이터를 요청하고 저장하는 것임에도
두가지 훅을 받아와 사용해야 한다.
*/
import { useEffect, useState } from &#39;react&#39;;

export const SuperHeroesPage = () =&gt; {
  const [isLoading, setIsLoading] = useState(true);
  const [data, setData] = useState([]);

  useEffect(() =&gt; {
    const fetchSuperHeroes = async () =&gt; {
      try {
        const response = await axios.get(&#39;http://localhost:4000/superheroes&#39;);
        const data = await response.data;
        setData(data);
        setIsLoading(false);
      } catch (error) {
        setError(error.message);
        setIsLoading(false);
      }
    };
    fetchSuperHeroes();
  }, []);

  /* isLoading 중이라면, 서버 데이터를 사용하는 로직 대신, Loading... 메시지를 보여준다. */
  if (isLoading) {
    return &lt;h2&gt;Loading...&lt;/h2&gt;;
  }

  /* 에러가 발생하면, 상태값에 저장한 에러메시지를 보여준다. */
  if (error) {
       return &lt;h2&gt;{error}&lt;/h2&gt;
  }
  return (
    &lt;div&gt;
      &lt;h2&gt;Super Heroes Page&lt;/h2&gt;
      {data.map((hero) =&gt; (
        &lt;div key={hero.name}&gt;{hero.name}&lt;/div&gt;
      ))}
    &lt;/div&gt;
  );
};

</code></pre>
<p>재래적인 방식의 data fetching 로직이다.</p>
<p>단점은 아래와 같다.</p>
<ul>
<li>단순히 서버에서 데이터를 받아오는 것임에도 불구하고 많은 코드를 작성해야 한다.</li>
<li>useEffect 훅으로 데이터를 비동기적을 요청하고, useState 훅으로 data fetching 중 loading 상태, 그리고 결과 데이터를 저장 및 관리해야 하니, 복잡한 게 눈에 띈다.</li>
<li>또한, 데이터를 받아오는 도중 상태를 나타내기 위한 isLoading state 또한 useState로 따로 선언해야 하니 번거롭다.</li>
</ul>
<p>아래는 이번에 학습한 React Query 훅을 사용해 Data Fetching 작업을 해보았다.</p>
<pre><code class="language-js">import axios from &#39;axios&#39;;
import { useQuery } from &#39;react-query&#39;;

export const RQSuperHeroesPage = () =&gt; {
  /* 

  */
  const { data, isLoading, isError, error } = useQuery(&#39;super-heroes&#39;, () =&gt; {
    return axios.get(&#39;http://localhost:4000/superheroes&#39;);
  });

  if (isLoading) {
    return &lt;h2&gt;Loading...&lt;/h2&gt;;
  }
  /* 에러가 발생하면 에러메시지를 보여주지만,
   React Query 라이브러리가 자동으로 다시 fetching을 시도하기 때문에 로딩 상태가 더 길게 지속된다.
  */
  if (isError) {
    return &lt;h2&gt;{error.message}&lt;/h2&gt;;
  }

  return (
    &lt;div&gt;
      &lt;h2&gt;RQ Super Heroes Page&lt;/h2&gt;
      {data?.data.map((hero) =&gt; (
        &lt;div key={hero.name}&gt;{hero.name}&lt;/div&gt;
      ))}
    &lt;/div&gt;
  );
};
</code></pre>
<ul>
<li>useQuery 훅을 사용하니, data fetching을 하기 위한 코드가 대폭 줄었다.</li>
<li>.then() 혹은 await을 수반하는 복잡한 Promise 정제 작업 또한 사라졌다.</li>
<li>useQuery 훅의 리턴값에는 loading state 혹은 error state 또한 포함되므로, 값은 distructuring을 통해 따로 뽑아 사용할 수 있으니, 훨씬 편리하며 정확하다.</li>
<li>fetching이 실패하면, 자동으로 React Query 라이브러리가 재시도한다.</li>
</ul>
<p>더 놀라운 점은, 기존의 useEffect 훅을 사용한 비동기 호출과 비교해서, React Query가 query cache 기능을 추가로 제공하기 때문에, 같은 데이터를 여러번 호출할 때에도 이미 캐싱된 데이터를 보여준다. </p>
<p>기본적으로 React Query로 수행한 모든 query fetching의 결과는, 5분간 cache를 지속하기 때문에 이러한 결과가 나오는 것이다.
(5분 이후에는 query cache는 가비지 컬렉팅 된다. 따라서 다시 loading state는 true로 바뀐다.)</p>
<ul>
<li>5분의 default setting된 시간을 임의로 바꾸려면, useQuery 훅의 세번째 인자로 {cacheTime: 5000(밀리초)}를 넣어 변경할 수 있다. </li>
</ul>
<p>따라서 로딩 페이지가 한번 API콜을 수행한 이후에는 보여지지 않아 성능의 향상을 보여준다.</p>
<p><strong>해당 작업이 이루어지는 과정은 다음과 같다.</strong></p>
<blockquote>
<p>useQuery문이 인자로 넣어준 super-heroes key를 통해 최초로 실행되면 isLoading state가 true로 설정되며, 요청이 데이터를 받아오기 위해 보내진다. </p>
</blockquote>
<p>요청이 완료되면, key로 설정한 &quot;super-heroes&quot;와 fetchSuperHeroes 함수를 unique identifier로 활용하여 cache 된다.</p>
<blockquote>
</blockquote>
<p>  이후에 다시 같은 query call을 하면, react query는 cache 상에 해당 uniquer identifier가 존재하는 지 확인하고
  존재한다면, isLoading state를 true로 설정하지 않고 해당 cache 된 데이터를 보여준다.</p>
<p>그러나, cache 된 데이터가 최신 데이터가 아닐 가능성도 있으므로, 같은 query 요청에 대해 React Query는 background refetch가 trigger되면서 새로 갱신된 데이터가 UI 화면 상에 업데이트도 해준다..!</p>
<p>cache 된 데이터가 재차 요청한 데이터와 동일하다면 UI 화면 상의 데이터는 그대로 유지된다.</p>
<p>여기서, background refetching이 실행될 때 사용되는 flag state는 isFetching이다.</p>
<p>이와 같은 작업이 수행되면서, DB 상의 데이터가 변경되면 기존 client단에서는 isLoading state는 false로 유지하되 isFetching이 true로 바뀌어 cache된 데이터를 UI 화면 상에 보여주다가, isFetching 값이 false가 되면 새로 업데이트된 데이터를 Loading 화면없이 업데이트 하여 보여주는 것이 가능하게 되는 것이다.</p>
<p>결과적으로 페이지 유저는 최초의 페이지 로딩을 제외하면, query call이 성공적으로 마무리 될 경우, 다시 로딩 페이지를 볼 일이 없어지는 것이다.</p>
<pre><code class="language-js">
/* 
인라인으로 작성했던 비동기 요청 함수를 다음과 같이 빼줄 수도 있다.
더 직관적인 코딩이 가능하다.
*/
const fetchSuperHeroes = () =&gt; {
  return axios.get(&#39;http://localhost:4000/superheroes&#39;);
};

export const RQSuperHeroesPage = () =&gt; {

  const { data, isLoading, isError, error, isFetching } = useQuery(
    &#39;super-heroes&#39;,
    fetchSuperHeroes
  );</code></pre>
<p>다음 포스트에서는 React Query에서 제공하는 강력한 툴인 React Query DevTools 에 대해 다루어 보겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트 준비: React Query]]></title>
            <link>https://velog.io/@juanito_y247/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A4%80%EB%B9%84-React-Query</link>
            <guid>https://velog.io/@juanito_y247/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A4%80%EB%B9%84-React-Query</guid>
            <pubDate>Tue, 01 Feb 2022 14:02:00 GMT</pubDate>
            <description><![CDATA[<p>프로젝트를 1주 앞둔 현재, 지난 프로젝트에서 발생한 문제를 사전에 예방하고 더 나은 프로젝트 경험을 가져가려고 준비하고 있다.</p>
<p>지난 프로젝트에서 크게 변수로 작용한 것 중 하나가 비동기 로직 문제였다. 나는 서버에서 받아오는 데이터를 요청하는 비동기 로직을, 해당 데이터가 필요한 컴포넌트 내에서 바로 호출해서 상태값으로 저장했다.</p>
<p>그러나, 한 구간에서 비동기 요청을 너무 많이 사용했고, 서버에서 받아와 저장한 상태값이 서로 연관성을 크게 가졌기 때문에, 여러 문제가 발생했다.</p>
<blockquote>
<ul>
<li>첫째로, 비동기 요청을 통해 가져온 데이터 결과를 상태값으로 저장하고, 다음 비동기 POST 요청에서 params로 넘겨야 했는데, 해당 값이 저장되기 전에 다음 요청 로직이 실행 되어서 빈 값을 대신 넣어 보내는 문제가 발생했다.</li>
</ul>
</blockquote>
<ul>
<li>각 페이지 컴포넌트 마다, 서버에서 받아온 데이터를 저장한 상태값을 저장했기 때문에 해당 값이 어디에 있는지 나중에 파악하기 힘든 문제도 발생했다.</li>
<li>마지막으로, 해당 값은 서버에서 받아온 후, 최신 값인지 보장하기 힘들었고, 데이터를 받아오는 도중인지 확인하기 위한 loading state, 에러 발생을 확인하기 위한 error state를 따로 useState 훅으로 관리해서 복잡성이 높아졌다.</li>
</ul>
<p>위와 같은 문제는 특히 개발 이후에, 디버깅 및 유지 보수를 하는 과정에서 골칫덩어리로 다가왔고, 다음 프로젝트에서 같은 문제를 만나지 않기 위해 이에 대한 해결책을 찾아야 했다. </p>
<p>그렇게 찾은 해결책 중 하나가 React Query 라이브러리였다. 아래의 내용부터는 React Query가 무엇인지, 그리고 왜 필요한 지에 대해 정리하였다.</p>
<h2 id="react-query는-무엇인가">React Query는 무엇인가?</h2>
<p>React Query는 간단하게 말해서 data fetching을 위한 React 라이브러리라고 할 수 있다.</p>
<h2 id="왜-react-query는-등장했는가">왜 React Query는 등장했는가?</h2>
<ol>
<li>React Query가 UI 라이브러리인 만큼, Data Fetching을 위한 정해진 패턴 혹은 가이드라인이 따로 없었다.</li>
<li>기본적으로 useEffect 훅 안에 비동기 데이터 요청 함수를 작성하여 데이터를 불러오고, useState 훅을 통해 컴포넌트의 상태값을 저장하는 방식을 썼다 (loading, error, 결과 데이터등이 저장하는 값이다)</li>
<li>받아온 데이터가 앱 전역에서 필요하다면, 상태 관리 라이브러리를 따로 사용하였다. (Context, Redux 등)</li>
<li>그러나, 위의 상태관리 라이브러리는 client state를 관리하는 데에는 적합했지만 (화면 상에 변화를 담당하는 state)</li>
<li>server state를 관리하는 데에는 적합하지 않았다. (비동기적으로 받아오는 서버 데이터)</li>
</ol>
<h2 id="client-state-vs-server-state">Client State vs Server State</h2>
<h3 id="client-state">Client State</h3>
<ul>
<li>앱의 메모리 상에서 존재하며, 동기적으로 접근 혹은 수정이 가능한 state</li>
</ul>
<h3 id="server-state">Server State</h3>
<ul>
<li>클라이언트 밖에 존재하며, 받아오거나 수정 시에는 비동기 API 통신이 필요한 state (항상 최신 값을 보장해야 한다.)</li>
<li>따라서 외부와 공유되는 상태값이다. 그러므로, 모르는 사이 타인에 의해 변경될 수도 있다.</li>
<li>외부에 리모트 하게 존재하는 데이터와 최신화되지 않을 가능성 또한 있다.</li>
<li>데이터를 캐싱해야 하거나, 같은 데이터를 얻기 위해 여러번 요청을 하거나, 오래된 데이터를 새로 업데이트, 혹은 성능 최적화를 하려면 여러 문제가 따랐다.</li>
</ul>
<p>⇒ 위와 같은 server state를 쉽게 관리하기 위해, React Query 라이브러리가 등장하였다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS in JS의 장점 (feat. styled-components)]]></title>
            <link>https://velog.io/@juanito_y247/CSS-in-JS%EC%9D%98-%EC%9E%A5%EC%A0%90-feat.-styled-components</link>
            <guid>https://velog.io/@juanito_y247/CSS-in-JS%EC%9D%98-%EC%9E%A5%EC%A0%90-feat.-styled-components</guid>
            <pubDate>Sun, 26 Dec 2021 16:54:36 GMT</pubDate>
            <description><![CDATA[<h1 id="css-in-js">CSS in JS</h1>
<h3 id="js-파일이-css-요소를-생성하는-방식의-스타일링-방법론은-다음과-같은-장점을-가진다">JS 파일이 CSS 요소를 생성하는 방식의 스타일링 방법론은 다음과 같은 장점을 가진다.</h3>
<ul>
<li>파일을 분리하지 않고 스타일링을 적용함으로써, 더 빠른 성능 효율성을 가진다. JS 파일만 다운로드하면, css 스타일링 또한 같이 받아오기 때문이다.</li>
<li>css 스타일의 속성이 관련있는 컴포넌트에만 영향을 미치도록 스코프를 한정할 수 있다.
같은 css 파일이 다른 html 요소에 원하지 않는 영향을 주는 것을 막을 수 있다. (이는 css 파일의 선택자가 share-naming이라는 특성을 가지고 있기 때문이다.)</li>
<li>기존의 scss 문법에서 특정 css 요소가 어느 부모로 부터 nested 되었는지 파악하지 않아도, 바로 해당 컴포넌트를 cmd + click하여 스타일을 특정하여 찾을 수 있다.</li>
</ul>
<h3 id="새로운-기술을-적용할-때에는-그-기술이-해결할-수-있는-문제점에-먼저-포커스를-맞추어라">새로운 기술을 적용할 때에는, 그 기술이 해결할 수 있는 문제점에 먼저 포커스를 맞추어라</h3>
<p>신기술이라고 모두 다 좋은 점만을 가지고 있지 않다. 모든 기술에는 장점과 단점이 극명하게 있는 편이다. 새로운 기술을 맞이 했을 때에는 바로 호불호를 속단하지 않고 이 기술이 가진 장점과 단점에 더 집중하는 태도가 더 좋다. 만약 신기술이 현재 풀어야 하는 문제에 더 복잡성을 더한다면 다른 기술을 활용하는 것이 좋고, 반대라면 그 신기술을 적용하는 것이 문제를 해결할 키가 될 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐰엘리스 AI 트랙 TIL: 데이터와 정보]]></title>
            <link>https://velog.io/@juanito_y247/%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%99%80-%EC%A0%95%EB%B3%B4</link>
            <guid>https://velog.io/@juanito_y247/%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%99%80-%EC%A0%95%EB%B3%B4</guid>
            <pubDate>Tue, 07 Dec 2021 23:27:43 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터란">데이터란?</h1>
<h3 id="데이터--현실-세계의-일들을-관찰하고-측정해서-얻은-값">데이터 : 현실 세계의 일들을 관찰하고 측정해서 얻은 값</h3>
<ul>
<li>가공하기 전의 단순한 사실이다<h3 id="정보--데이터를-처리해서-얻는-의미-있는-값">정보 : 데이터를 처리해서 얻는 의미 있는 값</h3>
</li>
<li>데이터를 가공하여 의사결정을 위해 활용할 수 있는 것이다.</li>
</ul>
<h1 id="그렇다면-데이터-분석이란">그렇다면 데이터 분석이란?</h1>
<p><strong>데이터</strong>를 활용하여 원하는 <strong>정보</strong>를 얻어내기 위한 일련의 과정이다.</p>
<h2 id="데이터-분석-프로젝트의-전체-프로세스는">데이터 분석 프로젝트의 전체 프로세스는</h2>
<blockquote>
<ol>
<li>먼저, 문제 정의를 내린다.</li>
<li>가설을 설정한다.</li>
<li>데이터를 준비한다.</li>
<li>데이터를 분석한다.</li>
<li>도출된 결과를 정리한다.</li>
</ol>
</blockquote>
<h1 id="jupyter-notebook">Jupyter Notebook</h1>
<p>프로젝트 수행을 위해서는 환경을 준비해야 하는 데, 데이터 분석 프로젝트를 진행하려면 강력한 환경인 Jupyter Notebook을 준비해야 한다.</p>
<h2 id="jupyter-notebook이란">Jupyter Notebook이란?</h2>
<p>웹 브라우저에서 코드를 작성하고 실행해볼 수 있는 오픈소스 소프트웨어이다.</p>
<ul>
<li><strong>셀 단위</strong>코드 실행이 가능하여, 데이터 분석, 머신러닝 등의 프로그램 구현이 용이하다.</li>
</ul>
<h3 id="셀이란">셀이란?</h3>
<p>셀(Cell)은 기본 입력 단위이다. 다양한 입력 모드와 종류를 지닌다.</p>
<h3 id="셀모드">셀모드</h3>
<p>Jupyter Notebook에는 <strong>입력</strong>모드와 <strong>명령</strong>모드가 존재한다.
<strong>기본 입력 모드</strong>로 시작, 이후 <strong>esc키</strong>를 통해 <strong>명령 모드 전환</strong>이 가능하다.</p>
<h3 id="셀의-종류">셀의 종류</h3>
<p><strong>마크다운셀</strong>: 이미지, 영상, 설명, 그래프를 추가할 수 있다.
<strong>코드셀</strong>: 프로그래밍 언어 코드를 입력할 수 있다.</p>
<h4 id="마크다운이란">마크다운이란?</h4>
<p>깔끔한 문서를 편리하게 만들 수 있게 도와주는 언어이다.
대부분의 개발과 관련된 문서는 마크다운으로 작성되어 있다.</p>
<h4 id="마크다운-문서-정리">마크다운 문서 정리</h4>
<p>깔끔한 문서 정리를 위한 다양한 문법이 존재한다.
이를 통해 <strong>Jupyter Notebook</strong>을 깔끔하게 설명을 정리할 수 있을 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐰엘리스 AI 트랙:  직업심리검사 프론트엔드 개인 프로젝트 후기]]></title>
            <link>https://velog.io/@juanito_y247/%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-1%EC%B0%A8-%EA%B0%9C%EC%9D%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@juanito_y247/%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-1%EC%B0%A8-%EA%B0%9C%EC%9D%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Wed, 01 Dec 2021 15:55:27 GMT</pubDate>
            <description><![CDATA[<h1 id="프로젝트를-마치고-나서">프로젝트를 마치고 나서</h1>
<blockquote>
<p>사실 개인 프로젝트가 발표까지 끝난지는 사흘이 지났다. 나는 마지막에 너무 무리를 했고, 슬럼프 혹은 번아웃을 맞이하지 않기 위해 끝나고 그 동안 정신건강 관리와 피로회복에 전념했기 때문에 의도치 않게 늦은 프로젝트 마무리 회고를 해본다.</p>
</blockquote>
<p>시작에 앞서 간단히 정리한 감성은, 이번 프로젝트를 통해 내 기본기가 얼마나 허술한 지 느낄 수 있어서 반성을 많이 한 기간이기도 했지만, 이를 반대로 이야기 한다면 3개월의 기간을 모두 통틀어 실력에 있어 가장 많은 성장을 본 기간이기도 했다.</p>
<p>React 라이브러리를 활용하여 제대로 된 프로젝트를 진행한 것은 이번이 처음이었고, 이번 기회를 통해 나는 React에 대한 이해도를 조금 더 높일 수 있었다. React를 주력으로 한 프론트엔드 개발자가 되는 것을 목표로 하는 나로써는 최선의 결과인 것 같다.</p>
<p>이번 프로젝트에서는 React의 기본 문법과 활용법을 이해하고 최대한 근본에 집중하고 싶었기 때문에 최대한 서드파티 라이브러리는 배제하였다. 예를 들어 전역적인 상태관리 부분에서 나는 Redux가 아닌 Context API 기술을 활용하였고, 스타일링 또한 Bootstrap이 아닌 css module을 통해 결과물을 만들었다. 기본기가 탄탄해야지만 위의 기술들에도 더 큰 감사를 느끼며, 더 효과적으로 활용할 수 있을 것만 같았다.</p>
<p>이번 프로젝트는 다른 의미로도 내게 의미가 깊다. 나는 내가 지금까지 생각하고 있는 마인드, 개발의 철학을 가시화하여 최대한 많은 인원에게 보여주고 싶었다. 그동안은 말과 글로써만 나의 생각을 전달하였지만, 이번은 타인이나 내 자신이나 그것을 눈으로 직접 확인할 수 있는 좋은 기회라고 생각했기 때문이다.</p>
<h2 id="개인-프로젝트-개시-주-nov-16th--nov-20th">개인 프로젝트 개시 주 (Nov 16th ~ Nov 20th)</h2>
<img src="https://images.velog.io/images/juanito_y247/post/4a7a4315-c97e-4815-9131-789b2b54efc0/20211128_120959.jpg" height="100px" width="100%" >
<img src="https://images.velog.io/images/juanito_y247/post/8ebf3b19-86fc-45b4-9f17-fb534e704e4c/20211128_121007.jpg" height="100px" width="100%" >

<h3 id="첫-주의-요구사항-분석-기록들">첫 주의 요구사항 분석 기록들</h3>
<ul>
<li><p>첫 주는 먼저 이 프로젝트에서 요구하는 기능 구현사항 그리고 와이어 프레임을 분석하는 데에 시간을 많이 들였다. 과거의 프로젝트 경험과 시행착오를 떠올려 보았을 때,  개발을 시작하기 전에 나만의 체계를 미리 잡고 시작하는 것은 나중의 시간을 절약하는 길이라고 판단했었기 때문이다.</p>
</li>
<li><p>나는 제시된 기능 구현사항 리스트를 보면서, React의 어떤 기술을 활용하여야 목표 페이지의 기능을 구현할 수 있을지 고민하며 노트를 정리했고, 물론 훗날 이 작업은 개발 작업 기간 내내 많은 도움이 되었다. </p>
</li>
<li><p>다음으로 와이퍼 프레임은 이미 제시된 예시가 있었으나, 나는 적어도 이 부분에 있어서는 나만의 철학을 담고 싶었다. 프론트엔드 분야의 개발자가 되기로 마음먹은 이유 또한 명시적이고 기분좋은 UI/UX를 구축하여 사용자의 만족도가 높은 서비스를 만드는 데에 기여하고 싶은 마음이 컸기 때문이다.</p>
</li>
<li><p>그 다음 스텝으로 나는 파악하고 정리한 기능 구현사항과 페이지 디자인을 토대로 두고, 그동안 시간에 쫒겨 스스로 정립하지 못한 React의 기본 문법과 활용법을 숙지하기 위해 Udemy 사이트의 강의를 여럿 보며 개념을 정리하였다. 프로젝트를 자기 자신의 힘으로 진행해야 했기 때문에 부담이 되어 본 것도 있지만, 내가 독자적으로 이해한 바를 가지고 코드를 쓰기 시작한다면, React를 잘 활용하지 못하고 이상한 방법으로 작성할 것 같았다. 그것은 너무나도 싫은 결과였다.</p>
</li>
</ul>
<h3 id="중간-점검">중간 점검</h3>
<blockquote>
<p>중간 점검에 있어 결론부터 말하자면, 나는 시간관리에 완벽한 실패를 했다. 다른 레이서와의 개발 진도 간격은 좁힐 수 없이 커졌고 나는 이에 상당한 압박감을 느꼈다. 내가 선택하여 준비기간을 길게 가진 것도 있지만, 그렇게 정당화하기엔 내 실력이 내 자신이 인정하기엔 터무니없이 부족한 점이 탄로났기 때문이다.</p>
</blockquote>
<p>나는 객관적으로 이 프로젝트의 중간 결과에 대해 생각하기 시작했다. 과연 이제는 무엇을 해야 되는 것인가. 고민하는 시간은 최대한 짧게, 그러나 최대한 깊게 하고 싶었다. 나는 결국 기능 구현을 일단 시작하고 이후 필요한 지식이 생기면 블로그나 공식 자료를 참고하는, 예전식으로 실제 작업에 착수하기 시작했다.</p>
<h2 id="개인-프로젝트-마무리-주-nov-21st--nov-28th">개인 프로젝트 마무리 주 (Nov 21st ~ Nov 28th)</h2>
<p>이번에는 막판 스퍼트를 올릴 필요가 있었다. 디자인 지향점은 중간에도 계속 변경되어 혼란스러울 지경이었고, 기능 구현은 생각하는 대로 제대로 된 진척이 없었다. 최대한 스스로의 힘으로 문제를 해결하려 했으나, 결국 나는 지금은 체면을 따질 때가 아니라 도움을 청해야 할 때라고 생각하여 레이서 커뮤니티에 적극적으로 내 상태와 받고 싶은 도움 사항을 공유하였다. 생각한 것보다 많은 분들이 적극적으로 도움을 주셨다. </p>
<h3 id="마지막-주에-진행한-대표-구현-사항">마지막 주에 진행한 대표 구현 사항</h3>
<ol>
<li><p>react-router-dom의 Route와 Link를 통해 컴포넌트 간의 연결관계를 만들어 주었다.</p>
</li>
<li><p>axios 라이브러리를 사용하여 직업 가치관 검사의 문제들을 커리어넷에서 get 요청으로 화면에 불러왔다.</p>
</li>
<li><p>Context API 기술을 활용하여 앱 내에서 전역적으로 관리해야 할 상태값들을 관리하였다 (test-context, user-context..) 를 만들었다.</p>
</li>
<li><p>각 문제들을 5개 씩 화면에 투사하기 위해 페이지네이션 기능 구현을 하였는데, 상태값으로 버튼을 누를 때마다 페이지 수를 높이거나 낮출 수 있게 했다.</p>
</li>
<li><p>각 화면에 출력할 컴포넌트들은 무조건 Card라는 컨테이너에 담아 보여줄 수 있게 하였다. 잘 정제된 UI는 사용자의 서비스 파악을 용이하게 한다.</p>
</li>
<li><p>React의 특장점을 극한으로 끌어올리기 위해, 컴포넌트는 모듈화를 시켜 최대한 많은 분리를 진행했다. 거기에 보여지는 부분을 담당하는 Presentational 컴포넌트(ui)와 동작 로직을 담는 Container 컴포넌트로 나누어 관리하였다.</p>
</li>
<li><p>모든 문제를 체크하지 않으면 비활성화 되는 버튼과 프로그래스바를 구현하는 데에 꽤 많은 노력을 들였다. 답은 결국 각각 localStorage와 문제의 답의 값을 담는 상태값을 조정하여야 했다.</p>
</li>
<li><p>post 요청으로 보내는 값에 따른 결과를 가져오는 get 요청 부분은 늪과 같았다. 난생 처음보는 API 형식으로 인해 적지 않은 당황과 개고생을 했다. 이 부분을 해결하려고 이틀의 시간을 꼬박 투자한 것 같다.</p>
</li>
<li><p>많은 이들의 도움을 받아 결국 대체적인 기능 구현은 끝냈지만, 마이너한 버그(프로그래스바, 다음 버튼, etc..) 들이 남아있었고 이 부분을 잡는데에도 상당한 시간이 들어갔다.</p>
</li>
<li><p>깃을 활용하는 데에 실패하여, 파일을 압축하여 배포하는 데에 성공하였다. 물론 스스로 못했고 다른 동료의 도움을 받았다.</p>
</li>
</ol>
<p>위의 일련의 작업들을 달성하는 데에 장장 5일, 마지막 3일은 72시간 동안 4시간의 수면시간만 가지고 작업을 진행했다. 후반으로 갈 수록 과연 내가 기간 내에 완성할 수 있을까라는 불안감이 엄습하였고, 몇번이나 좌절을 맛보았다. 간단한 프로젝트라고 생각했던 것이 큰 착각이었던 것이다.</p>
<p>그래서 나는 마지막에 내 모든 것, 체력이든 자존감과 같은 멘탈이든, 말 그대로 모든 것을 던져넣지 않을 수 없었다. 그렇게 해서라도 내가 만족할 수 있는 결과를 끌어내는 노력을 하지 않는다면 나는 최악의 거짓말쟁이이고, 앞으로 계속 자신에게 실망할 것만 같았다.</p>
<h2 id="결과물-발표">결과물 발표</h2>
<img src="https://images.velog.io/images/juanito_y247/post/142c49ae-5f64-44f2-a475-137351ee16b6/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-02%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.56.07.png" height="100px" width="100%" >
<img src="https://images.velog.io/images/juanito_y247/post/96f24ed7-273f-481b-95f3-fd39125fc0ce/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-02%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.56.26.png" height="100px" width="100%" >
<img src="https://images.velog.io/images/juanito_y247/post/b38af21c-252b-4392-acc4-db5693b80b1a/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-02%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.56.39.png" height="100px" width="100%" >

<img src="https://images.velog.io/images/juanito_y247/post/43bea9f0-0959-4ce1-8181-80a0e0987f62/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-02%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.57.16.png" height="100px" width="100%" >
<img src="https://images.velog.io/images/juanito_y247/post/cff1d8df-904d-465d-9eb0-55e3ceccd252/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-02%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.57.27.png" height="100px" width="100%" >

<p><a href="http://elice-kdt-3rd-vm-085.koreacentral.cloudapp.azure.com/">내 프로젝트 링크: 커리어 밸런스 게임!</a></p>
<p>실제 발표에서는 막힘은 없었지만, 시간관리에 실패했다. 내가 하고 싶은 말, 내가 보여주고 싶은 것을 모두 표현하기에는 5분이라는 시간은 내게 터무니없이 짧게 느껴졌다. 발표를 하고 나서는 최대한 많은 질문과 피드백을 받고 싶었지만 아쉽게도 아무런 피드백을 받지 못했다.</p>
<p>내 발표 이후에는 그래도 발표에 참석한 모든 분들의 시연 화면과 코드를 토대로 내가 궁금한 사항을 최대한 많이 질문하였다. 나는 동료에게서 배우는 것이 최선이다. 많은 분들이 생각보다 세부적인 부분들을 고려하여 프로젝트를 진행하셨고, 특히 콘솔과 주석의 활용, 클린코딩에 대해 많은 점을 배울 수 있었다.</p>
<h2 id="느낀-점">느낀 점</h2>
<p>그렇다. 내가 가지고 있던 개발 가치관이라는 것은 결국 누구든 당연하게 생각할 수 있었다. 나는 이로서 기본은 할 수 있는 것이라고 판단하고 앞으로의 발전을 도모하며 자잘한 레이아웃 업데이트와 로직 수정을 종료 후 진행했다.</p>
<p>최대한 많은 사람들에게 앱을 소개하면서, 사용감을 옆에서 지켜보고 불편한 점은 없는 지 물어봤다. 몇몇 피드백을 토대로 개선한 점은:</p>
<ul>
<li><p>테스트 시간이 생각보다 길어 당황하는 경우가 있어 예시 페이지에 소요시간을 썼다.</p>
</li>
<li><p>예시 페이지에서 예시를 누르지 않아 모달창을 보는 경우가 대부분이라 각 예시에 번호를 달았다. </p>
</li>
<li><p>테스트 완료 페이지가 마지막 페이지인줄 알고 멈추시길래, 결과페이지로 이동하는 버튼을 더 명시적으로 바꾸었다.</p>
</li>
<li><p>마지막 결과페이지는 더 가운데로 시야 포커스를 주기 위해 다시 카드 틀로 감싸 가운데로 모아 정렬했다.</p>
</li>
</ul>
<p>더 매력있고 발전성 있는 개발자가 되려면 적어도 만들어 놓은 결과물에 대한 애착이 있어야 하고 내가 만든 창작물에 있어서 책임을 질 줄 알아야 한다. 사실 이것은 인간관계나 어떤 다른 분야의 모든 일에 있어서 동일하게 적용되는 점 같다. 나는 내가 이 인생에서 선택한 모든 것에 대해 책임감을 가질 줄 알아야 하는 것 같다.</p>
<blockquote>
<p>이번 프로젝트는 아쉽게도 반쪽짜리 프로젝트이다. 내가 보여주고 싶은 전부를 보여주지 못했고, 생각보다 많은 사람들을 귀찮게 하며 진행해버렸다. </p>
</blockquote>
<p>나는 이번 기회를 통해 파악한 내 부족한 기본기와 프로그래밍에 대한 이해를 넓혀갈 필요가 있어져서, 정규 과정 외에 다른 코스를 병행하여 듣고 있다.</p>
<p>이번 프로젝트에 있어 크루셜한 도움을 준 고마운 이들이 존재한다.
나는 이번 개인프로젝트를 무사히 마치는 데에 도움을 준 이들:</p>
<ul>
<li>박X백 동료 레이서</li>
<li>남X범 동료 레이서</li>
<li>최X호 동료 레이서</li>
<li>김X연 동료 레이서</li>
<li>양X광 동료 레이서</li>
<li>김X원 동료 레이서</li>
<li>곽X영 동료 레이서</li>
<li>조X흠 동료 레이서</li>
</ul>
<p>위 여덟 분에게 감사와 영광을 돌리며 이번 회고를 마치려 한다.
다음은 React 혹은 데이터     분석 파트에 대한 TIL을 재개한다.</p>
<blockquote>
<p>Peace And Love 🤟</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[19_Nov: 개발 회고 [ 찾는 길이 없으면 만들겠다 ]]]></title>
            <link>https://velog.io/@juanito_y247/19Nov-%EA%B0%9C%EB%B0%9C-%ED%9A%8C%EA%B3%A0-%EC%B0%BE%EB%8A%94-%EA%B8%B8%EC%9D%B4-%EC%97%86%EC%9C%BC%EB%A9%B4-%EB%A7%8C%EB%93%A4%EA%B2%A0%EB%8B%A4</link>
            <guid>https://velog.io/@juanito_y247/19Nov-%EA%B0%9C%EB%B0%9C-%ED%9A%8C%EA%B3%A0-%EC%B0%BE%EB%8A%94-%EA%B8%B8%EC%9D%B4-%EC%97%86%EC%9C%BC%EB%A9%B4-%EB%A7%8C%EB%93%A4%EA%B2%A0%EB%8B%A4</guid>
            <pubDate>Tue, 23 Nov 2021 08:33:06 GMT</pubDate>
            <description><![CDATA[<h1 id="3일차-웹-프론트엔드-개인-프로젝트">3일차 웹 프론트엔드 개인 프로젝트</h1>
<h2 id="last-24-hrs">Last 24 Hrs</h2>
<p>아직도 리액트 훅 및 기본 개념에 대한 강의를 듣는 중이었다. 그러나 강의를 들을수록 미리 숙지해 둔 기능구현 목록의 기능들을 어떤 기술을 사용하여 구현할 수 있는 지 그림이 보인다는 것은 큰 수확이었다. 그러한 부분을 만날 때 마다 나는 주석으로 기록해두었다. 예를 들어, 사용자 정보를 받는 시작페이지에서 나는 useState를 사용하여 입력내용을 저장하려고 했지만, 그것은 state를 잘못 다루는 용법인 것을 깨달았다. 화면에 보이는 상태값 정보를 단순히 읽어서 저장할 때는 (특히 form 태그의 submit액션이 있을 경우) 상태값을 변경할 때 사용하는 useState가 아닌 useRef를 사용해야 한다는 것이다.</p>
<p>나는 이렇게 기술을 활용한 기능 구현의 퍼즐을 하나씩 맞추어가는 방식으로 개발을 진행하고 있다. 물론 남들처럼 미리 대부분의 작업을 끝내고 디버깅 / 테스트 / 보수를 하는 것이 더 유리할 수도 있지만, 이번 프로젝트의 형태를 보며 판단되기를 본 의도는 기술을 혼자 사용하고 다시 재정립하면서 나의 것으로 만드는 것이 아닌가하는 게 내 생각이다. 지금까지 한 작업은 다음과 같다.</p>
<h2 id="진행-사항">진행 사항</h2>
<ul>
<li>useRef를 활용한 form 태그 submit 액션 시, 사용자 정보 입력값 저장</li>
<li>useContext를 활용하여 전역 distributing이 필요한 상태값 관리 및 저장, 변경</li>
<li>axios 서드파티 라이브러리를 통해 공공데이터 API 통신으로 필요 데이터 받아오기 및 출력 (데이터 형태 확인)</li>
</ul>
<h2 id="next-24-hrs">Next 24 Hrs</h2>
<p>이젠 또 다른 강의와 블로그를 병행하면서 참고하여 기능 구현을 차근차근 진행해야 할 차례인 것 같다. 이미 사전 준비 작업에 3일의 시간을 투자했으니, 나머지 2/3의 기간 중 1/3 + a는 기능 구현에 투자하고 남은 1/3은 디버깅 및 리펙토링 작업에 할애할 계획을 가지고 있다. 계획은 언제나 유동적으로 변할 수 있으니, 매일 아침 지난 날 해놓은 작업을 복기하고 앞을로 할 수 있는 가능한 작업을 추려 실행에 옮기는 식으로 flexible하게 가져가고 싶다.</p>
<h2 id="느낀점">느낀점</h2>
<p>이번 개인프로젝트 덕에 리액트의 기본 개념과 기술에 대해 더 상세한 학습을 할 수 있어서 좋았다. 이제 학습의 성과를 개발 과정에 녹여내는 일만 남았다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[18_Nov: 🐰엘리스 AI 트랙: 개인 프로젝트 개발 회고 [급할 수록 되돌아 가라]]]></title>
            <link>https://velog.io/@juanito_y247/18Nov-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-%EA%B0%9C%EC%9D%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B0%9C%EB%B0%9C-%ED%9A%8C%EA%B3%A0-%EA%B8%89%ED%95%A0-%EC%88%98%EB%A1%9D-%EB%90%98%EB%8F%8C%EC%95%84-%EA%B0%80%EB%9D%BC</link>
            <guid>https://velog.io/@juanito_y247/18Nov-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-%EA%B0%9C%EC%9D%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B0%9C%EB%B0%9C-%ED%9A%8C%EA%B3%A0-%EA%B8%89%ED%95%A0-%EC%88%98%EB%A1%9D-%EB%90%98%EB%8F%8C%EC%95%84-%EA%B0%80%EB%9D%BC</guid>
            <pubDate>Thu, 18 Nov 2021 16:25:41 GMT</pubDate>
            <description><![CDATA[<h1 id="2일-차-웹-프론트엔드-개발-개인-프로젝트">2일 차 웹 프론트엔드 개발 개인 프로젝트</h1>
<h2 id="last-24-hrs">Last 24 Hrs</h2>
<p>깃허브만 연동하여 깃 형상관리 작업을 해오다가 깃랩을 처음으로 연동하여 작업을 하려는데, authentication 문제가 발생했다. local 환경에 저장된 credential 정보가 깃랩 내의 정보와 일치하지 않는다는 것이었다. 혼자 구글링을 통해 해결을 해보려다가, git rm 명령어를 잘못 사용하는 바람에 이틀동안 작업했던 사항들이 몽땅 날아가 버렸다.</p>
<p>그래도 불행 중 다행인 것은 어제 제출용으로 백업해 둔 zip파일이 있었기 때문에 아예 처음부터 진행하는 빅오 노테이션은 오시지 않았다. 기술을 사용하여 기능 구현을 할 때에는 먼저 이 기능을 가능케 하기 위해 필요한 기술이 무엇인지, 이 기술이 개발된 주요 원인과 주요 역할을 파악하는 것이 중요하다고 생각한다. 이 점을 생각해서 개발을 진행하게 되면, 이후 프로젝트 발표 시에도 막힘없는 코드 설명을 할 수 있을 수도 있기 때문이다.</p>
<p>따라서 오늘은 리액트 강의를 보면서 다시 한번 리액트의 훅과 스테이트, 비동기 통신에 대한 개념을 다시 정리하는 데에 대부분의 시간을 할애하였다. 실제로 코드를 치며 프로젝트 구현 작업은 거의 진행하지 않았다. 어차피 더 좋은 기법을 알게되면 다시 뒤집어 엎을 것이 불보듯 뻔하기에, 프로젝트 관련 작업은 노트에 잊지 않도록 참고할 사항을 체크해 둔 것이 전부이다.</p>
<h2 id="진행사항">진행사항</h2>
<ul>
<li><p>컴포넌트 구조 나누기 (layout/ui, Form, Main Components) !! 되도록이면 재사용 가능한 단위로 기능 분리</p>
</li>
<li><p>git 활용 연습</p>
</li>
<li><p>리액트 강의를 리뷰 (Hook, Component, Props, State, Async) 후 배운 내용 프로젝트 기능 구현에 바로 적용하며 진행</p>
</li>
<li><p>시작페이지 기능 구현 (유저의 데이터 저장, 조건 분기하기)</p>
</li>
</ul>
<h2 id="next-24-hrs">Next 24 Hrs</h2>
<p>다음 날도 오늘과 큰 차이는 없겠지만, 벌써 기간이 1/3 정도 넘게 경과한 상태이니 개발 작업도 슬슬 병행하면서 진행해야 할 것 같다. 내일 목표로 하는 것은 이것이다.</p>
<ul>
<li><p>어떻게 하면 페이지의 리렌더링이 일어나지 않게 하면서 심리검사 항목 화면을 전환 할 수 있을 지에 대한 기술적 고민 및 파악</p>
</li>
<li><p>스테이트를 전역으로 관리하여 (최대한 리덕스를 사용하지 않는 방법으로) 효과적으로 해당 스테이트를 필요로 하는 컴포넌트에 전달할 수 있을 지에 대한 기술적 고민</p>
</li>
<li><p>마지막 페이지의 경우, 어떠한 방식으로 테스트 결과를 보여줄 수 있을 지에 대한 구상</p>
</li>
<li><p>나만의 개발 철학 (사용자의 서비스 이용 어려움을 극소화한 서비스, 유쾌하고 직관적인 UI)을 어떤 식으로 반영할 것인가에 대한 고민</p>
</li>
<li><p>이 코드를 동료가 리뷰한다고 가정했을 때, 과연 직관적이고 communicatable한 클린코드라고 할 수 있을까에 대한 고민 </p>
</li>
</ul>
<p>=&gt; 먼저 서비스의 얼굴인 시작페이지와 핵심 부분인 문제 페이지 구현을 위의 사항을 염두에 두고 제작 개시한다.</p>
<p>위의 내용을 고려해 슬슬 실제 개발 작업을 진행할 예정이다. </p>
<h2 id="느낀-점">느낀 점</h2>
<p>강의를 초기에 보면 좋은 점은, 좋은 코드 컨벤션과 올바른 기술 활용법에 미리 익숙해진 채 프로젝트 준비를 할 수 있다는 것이다. </p>
<p>이번 프로젝트에서는 되도록 리덕스를 사용하지 않을 것이다. 아직 나는 리덕스를 잘 활용할 만큼 많은 이해를 하고 있지도, 제대로 다시 배울 만큼의 시간적 여유도 없다. </p>
<p>그렇다면 상태값 관리를 어떻게 전역적으로 할 것인가라는 의문이 생길 수 있지만, 다행히도 리덕스 없이, 순수히 리액트에서 제공하는 기술로도 그 목표를 이룰 방법이 존재한다.</p>
<p>개발을 진행하다보면, 더 나은 방법 더 아름다운 코딩의 경우의 수는 무수히 존재한다. 내가 하던 식대로 무턱대고 하기 보다는 철저한 사전 준비를 통한다면 결국 지금까지의 시간은 헛되이 소비된 것은 아닐 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[17_Nov : 🐰엘리스 AI 트랙: 개인프로젝트 개발 회고]]></title>
            <link>https://velog.io/@juanito_y247/17Nov-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-%EA%B0%9C%EC%9D%B8%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B0%9C%EB%B0%9C-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@juanito_y247/17Nov-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-%EA%B0%9C%EC%9D%B8%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B0%9C%EB%B0%9C-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Wed, 17 Nov 2021 04:43:16 GMT</pubDate>
            <description><![CDATA[<h1 id="직업심리검사-서비스-개인-프로젝트-1일-차">직업심리검사 서비스 개인 프로젝트 1일 차</h1>
<p>어제부터 프론트엔드 웹 개발 개인 프로젝트를 시작했다. 10시 부터 11시 반까지 간략하게 진행한 프로젝트 안내와 깃랩 사용법에 대한 안내를 듣고, 바로 프로젝트를 시작한다는 점은 바로 바다에 던져진 느낌이었다. 사실 미니 프로젝트 스터디를 진행하면서, 어느정도 막막한 느낌은 없다고 느꼈지만.. 먼저 제공된 와이어프레임을 따라 화면 구조 설계를 진행하면서 얕게 아는 지식을 신뢰하는 것이 얼마나 위태로운 것인지 깨닫는 하루가 되었다.</p>
<h2 id="프로젝트-형태-설계하기">프로젝트 형태 설계하기</h2>
<p>먼저 시작한 작업은 제공된 기능 구현사항과 공공데이터의 구조를 파악하는 것이었다. 나는 이미 JAVA Spring 기반으로 웹 프로젝트를 진행해 본 경험이 있고, 프로젝트의 구조 파악이 잘 안되어 있는 상태와 탄탄하지 않은 설계가 얼마나 프로젝트 후반에 악영향을 미치는 지 깨달은 바가 있다. 2주가 안되는 기간은 물론 심리적 압박을 느낄 만하지만, 부담감을 느끼지 않고 내 페이스대로 하는 개발 프로젝트가 결국은 시간을 세이브하고 완성도 높은 서비스를 만든다는 믿음이 있다.</p>
<p>어제 하루, 진행 순서는 다음과 같다.</p>
<ul>
<li>공공데이터 이용 신청을 하고, 데이터 구조 파악</li>
<li>와이어 프레임 분석 후, 구현에 사용할 가능성있는 리액트 문법 생각해보기</li>
<li>요구사항을 분석하고, 와이어 프레임 구조&amp;기능과 함께 노트에 정리</li>
<li>VS CODE 상에서 React Components, Styled-Components를 통해 전체적인 서비스의 외관 형태 잡기</li>
<li>엘리스 및 외부 React 강의를 듣고, 2달동안 배운 프론트엔드 기술 다시 리마인드</li>
</ul>
<h2 id="느낀점">느낀점</h2>
<p>프로젝트 연습을 했어도, 프로젝트에서 요구하는 기능 구현사항이 내가 연습한 부분과 일치하리라는 법은 없다. 나는 이번 개인 프로젝트를 앞으로의 개발인생을 위해 스스로 답을 찾기도 하고 동료와 코치님들에게 질문하는 것을 주저하지 않는 자세를 갖추기 위한 연습 스테이지라고 생각하고 있다.</p>
<p>물론 엘리스 과정에 지원하기 전부터 프로젝트는 나에게 있어 가장 중요한 부분이었고, 최선을 다하겠지만 결과에 상관없이 과정을 통해 나의 좋은 개발 습관을 정립하는 시간이 되는 것에 더 노력하는 2주간이 되는 것을 중점으로 보낼 계획이다.</p>
<p>내가 목표로 하는 스타트업에서 근무하고 있는 친구가 해준 조언이 하나 있다. 개발에 있어서 실제로 코드를 입력하는 작업은 그렇게 많은 비중을 차지하지 않는다는 것이 하나이고, 서비스에 대한 고민을 수반한 설계, 보수가 중요하다는 점이 또 한가지였다. </p>
<p>이번 프로젝트를 포함한 남은 과정에서의 나의 목표는 엘리스 AI 트랙에서 최고가 되는 것이 아니다. 나의 목표는 과정에 있어서 기본기와 자세를 갖추는 데에 더 집중하고, 앞으로 개발업계의 풍랑에도 견딜 수 있는 뿌리를 더 견고하게 하는 데에 있다. 나는 이번 프로젝트에서 내가 가진 철학과 믿음을 보여주는 데에 더 집중하고 싶다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[03_Oct_2021 🐰 엘리스 AI 트랙 TIL: Flask를 통한 서비스 다루기]]></title>
            <link>https://velog.io/@juanito_y247/03Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-Flask%EB%A5%BC-%ED%86%B5%ED%95%9C-%EC%84%9C%EB%B9%84%EC%8A%A4-%EB%8B%A4%EB%A3%A8%EA%B8%B0</link>
            <guid>https://velog.io/@juanito_y247/03Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-Flask%EB%A5%BC-%ED%86%B5%ED%95%9C-%EC%84%9C%EB%B9%84%EC%8A%A4-%EB%8B%A4%EB%A3%A8%EA%B8%B0</guid>
            <pubDate>Sat, 06 Nov 2021 05:01:30 GMT</pubDate>
            <description><![CDATA[<h1 id="blueprint와-jinja-template">Blueprint와 Jinja Template</h1>
<h3 id="blueprint">Blueprint</h3>
<p>API들을 분류하고 관리한다.
Flask의 기능이 점점 늘어날수록, 자연스럽게 코드의 양이 증가한다.
이때, Blueprint를 사용해서 길어진 코드를 모듈화해주어 수정 개발과 유지보수에 용이하게 코드를 관리할 수 있게 해준다.</p>
<h4 id="blueprint를-사용하지-않았을-때의-예">Blueprint를 사용하지 않았을 때의 예</h4>
<pre><code class="language-py">from flask import Flask, jsonify
app = Flask(__name__)

@app.route(&#39;/&#39;, methods=[&#39;GET&#39;])
def home_route():
    return jsonify(&#39;home&#39;)

@app.route(&#39;/first&#39;, methods=[&#39;GET&#39;])
def first_route():
    return jsonify(&#39;first page&#39;)
...
if __name__ == &#39;__main__&#39;:
    app.run(debug=True)</code></pre>
<ul>
<li>app.route의 개수가 API의 개수 (굉장히 많아진다)</li>
</ul>
<h4 id="blueprint를-사용했을-때의-예">Blueprint를 사용했을 때의 예</h4>
<p>app.py</p>
<pre><code class="language-py">from flask import Flask
from first_api import bp

app = Flask(__name__)
app.register_blueprint(bp)

if __name__ == &#39;__main__&#39;:
    app.run(debug==True)</code></pre>
<pre><code class="language-py">from flask import Blueprint, jsonify
bp = Blueprint(&#39;bp&#39;, __name__)

@bp.route(&#39;/first&#39;, methods=[&#39;GET&#39;])
def first_route():
    return jsonify(&#39;first page&#39;)

@bp.route(&#39;/second&#39;, methods=[&#39;GET&#39;])
def second_route():
    return jsonify(&#39;second page&#39;)</code></pre>
<ul>
<li>app.py는 오로지 서버를 실행한다.</li>
<li>blueprint는 flask 서버와 연동, blueprint를 사용한 객체로 바로 라우팅 가능.</li>
<li>파일을 여러 개 효과적으로 개발할 수 있게 하여 유지보수적인 측면에서 이점을 가진다.</li>
<li>Flask의 요청으로 URL을 생성 할 때 화면을 출력하는 함수를 Blueprint와 연결하는 방식으로 사용한다.</li>
<li>API들을 따로 모아서 파이썬 파일들을 구성</li>
</ul>
<h2 id="jinja2란">Jinja2란?</h2>
<p>Jinja2는 Python에서 가장 많이 사용되는 템플릿이다. 서버에서 받아온 <strong>데이터를 효과적으로 보여주고</strong> <strong>비교적 간략한 표현</strong>으로 <strong>데이터를 가공</strong>할 수 있다.</p>
<ul>
<li>render_template를 사용해서 템플릿에 데이터를 같이 보여준다.</li>
<li>HTML 내에서 파이썬 문법처럼 데이터를 불러내어 나타낼 수 있다.</li>
</ul>
<h4 id="jinja2-template에서-데이터-넘겨주기---단일변수">Jinja2 Template에서 데이터 넘겨주기 - 단일변수</h4>
<p>app.py</p>
<pre><code class="language-py">@app.route(&#39;/&#39;)
def alex():
    return render_template(&#39;index.html&#39;, data=&#39;alex&#39;)</code></pre>
<pre><code>&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt; jinja example&lt;/title&gt;
        &lt;body&gt;
            {{ data }}
        &lt;/body&gt;
    &lt;/head&gt;
&lt;/html&gt;</code></pre><h4 id="jinja2-template에서-데이터-넘겨주기---list">Jinja2 Template에서 데이터 넘겨주기 - list</h4>
<p>app.py</p>
<pre><code class="language-py">@app.route(&#39;/&#39;)
def alex():
    my_list = [1,2,3,4,5]
    return render_template(&#39;index.html&#39;, data=my_list)</code></pre>
<p>index.html</p>
<pre><code>&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;jinja example&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        {{ data }}
        {% for d in data %}
            {{ d }}
        {% endfor %}
    &lt;/body&gt;
&lt;/html&gt;</code></pre><h4 id="jinja2-template에서-데이터-넘겨주기---dictionary">Jinja2 Template에서 데이터 넘겨주기 - dictionary</h4>
<p>app.py</p>
<pre><code class="language-py">@app.route(&#39;/&#39;)
def alex():
    my_data = {&#39;name&#39;:&#39;alex&#39;}
    return render_template(&#39;index.html&#39;, data=my_data)</code></pre>
<p>index.html</p>
<pre><code>&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;jinja example&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        {{ data.get(&#39;name&#39;) }}
    &lt;/body&gt;
&lt;/html&gt;</code></pre><h1 id="게시판을-위한-crud-설계-및-제작">게시판을 위한 CRUD 설계 및 제작</h1>
<h3 id="api-동작-원리">API 동작 원리</h3>
<p>클라이언트는 HTTP request를 API 주소로 보내는 데, API 서버의 기능으로 어떤 응답을 들려줄 지 파악하고, 서버는 page나 JSON의 형태로 응답을 돌려준다.</p>
<p>클라이언트가 요청하는 모든 작업은 개인의 컴퓨터(브라우저)에서 이루어진다. 요청이 서버로 전달 될 때에는 HTTP request 형태로 넘어간다. 중간의 API 주소들은 서버에 매핑되어 있다.[@app.route()] 즉, 서버 안에서 API의 주소를 확인하고, 해당 기능을 수행하고 리턴 값을 돌려주는 것이 응답의 과정이다.</p>
<h3 id="crud란">CRUD란?</h3>
<blockquote>
<ul>
<li>Create : 데이터의 생성</li>
</ul>
</blockquote>
<ul>
<li>Read : 데이터의 조회</li>
<li>Update : 데이터의 수정<blockquote>
<ul>
<li>Delete : 데이터의 삭제</li>
</ul>
</blockquote>
</li>
</ul>
<p>를 뜻한다. 여기서 또 분류를 하자면, CREATE와 READ를 묶고, Update와 Delete를 함께 묶을 수 있다. <strong>데이터를 다루는 기준</strong>으로 묶은 것이다.</p>
<p><strong>Create</strong>는 <strong>데이터를 저장하는 연산</strong>이다.
<strong>Read</strong>는 <strong>데이터를 읽어오는 연산</strong>이다. (<strong>전체 혹은 하나</strong>를 읽을 수 있다.)
<strong>Update와 Delete</strong>는 <strong>본질적으로 저장하는 연산</strong>이나, <strong>읽기 작업에 큰 비중을 가진 저장</strong>이다. (데이터를 먼저 읽어오고, <strong>읽어온 데이터에 수정/삭제 연산</strong>을 한다.)</p>
<h3 id="crud---api---db-명령어-대응">CRUD - API - DB 명령어 대응</h3>
<table>
<thead>
<tr>
<th>CRUD</th>
<th>HTTP Method</th>
<th>DB 명령어</th>
</tr>
</thead>
<tbody><tr>
<td>Create</td>
<td>POST</td>
<td>INSERT</td>
</tr>
<tr>
<td>Read</td>
<td>GET</td>
<td>SELECT</td>
</tr>
<tr>
<td>Update</td>
<td>PUT, PATCH, (POST)</td>
<td>UPDATE</td>
</tr>
<tr>
<td>Delete</td>
<td>DELETE</td>
<td>DELETE</td>
</tr>
</tbody></table>
<h1 id="authentication이란">Authentication이란?</h1>
<h3 id="authentication-vs-authorization">Authentication vs Authorization</h3>
<ul>
<li>Authentication(인증)은 사용자가 어떠한 정보를 가지고 있는 사용자인지 알려주는 것을 의미한다 (ex. log-in, 2FA, OTP, SMS, PIN)</li>
<li>Authorization(권한)은 사용자가 어떠한 역할을 서버에서 할 수 있는 가를 뜻한다. 즉, 인증이 이루어진 후에 부여되는 것이다. (ex. 뱅킹 -&gt; 예금, 송금, 인출 || 배달 -&gt; 주문, 결제 || Mail -&gt; 쓰기, 읽기, 삭제 || SNS -&gt; &#39;내가 쓴 글 수정&#39;)</li>
</ul>
<h3 id="authentication">Authentication</h3>
<p>사용자가 누구인지 확인하는 절차이며, 대표적인 예로 회원가입하고 로그인 하는 과정이 있다.</p>
<ol>
<li>회원가입 -&gt; 내 정보를 서버로 전송한다. create로 계정을 만들 때, 패스워드의 경우 암호화를 거쳐 저장된다.</li>
<li>로그인 -&gt; IP/PW를 입력하여 서버에 전송한다. 데이터베이스의 정보를 읽어, 전송한 정보랑 같은 것이 있는지 확인한다. 일치하면 로그인이 이루어진다. (session, JWT[token])</li>
<li>로그아웃 -&gt; 세션의 연결을 끊는다.</li>
</ol>
<h1 id="로그인-기능-구현">로그인 기능 구현</h1>
<h2 id="http의-한계점을-극복하기-위한-데이터">HTTP의 한계점을 극복하기 위한 데이터</h2>
<p>클라이언트와 서버간의 통신에서 (요청/응답 == HTTP 통신의 한 사이클) 서버는 클라이언트의 접속 여부를 알 수 없다. HTTP는 상태 값을 저장하고 있지 않기 때문이다. 이러한 것을 저장하기 위해 쿠키로 저장하여 전송하는 것이고, 세션으로 식별하여 서버에서 관리하는 것이다. </p>
<h3 id="쿠키">쿠키</h3>
<p><strong>클라이언트에 저장</strong>되는 <strong>키/값이 들어 있는 데이터</strong>이다.</p>
<ul>
<li>사용자가 따로 요청하지 않아도, <strong>Request 시에 자동으로 서버에 전송</strong>한다.</li>
<li>이때 쿠키는 클라이언트의 브라우저에 저장이 된다.</li>
</ul>
<h3 id="세션">세션</h3>
<p>쿠키를 기반으로 하지만 <strong>서버 측에서 관리하는 데이터</strong>이다.
<strong>클라이언트에 고유 ID를 부여</strong>하고 클라이언트에 알맞는 서비스를 제공한다. <strong>서버에서 관리</strong>하기 때문에 <strong>보안이 쿠키보다 우수</strong>하다.</p>
<p>공통점: 사용자의 정보를 담고 있다.
차이점: 세션은 서버에서 관리하며, 쿠키는 클라이언트에서 관리한다.</p>
<p>로그인의 경우 세션에서 사용. 서버에서 관리.</p>
<pre><code class="language-py">user_id = request.form[&#39;user_id&#39;]
user_pw = request.form[&#39;user_pw&#39;]
user = {&#39;user_id&#39;: &#39;elice&#39;, &#39;user_pw&#39;: &#39;1234&#39;}
if user is not None:
    if user_id == user[&#39;user_id&#39;] and user_pw == user[&#39;user_pw&#39;]:
            session[&#39;login&#39;] = user.id
            return jsonify({&#39;result&#39;:&#39;success&#39;})
       else:
            return jsonify({&#39;result&#39;:&#39;fail&#39;})</code></pre>
<ul>
<li>request로 받아온 로그인 정보(user_id, user_pw)를 변수에 저장한다.</li>
<li>데이터베이스에 user_id와 같은 데이터가 있는지 찾아온다.</li>
<li>입력된 user_pw와 저장된 패스워드가 같은지 체크한다.</li>
</ul>
<pre><code class="language-py">session[&#39;login&#39;] = None</code></pre>
<ul>
<li>로그아웃을 할 때는 정보를 받을 필요가 없다.</li>
<li>현재 저장된 session의 데이터를 비워 주면 기능이 완료된다.</li>
</ul>
<h1 id="로깅">로깅</h1>
<p>프로그램이 작동할 때 발생하는 이벤트를 추적하는 행위이다.</p>
<p><strong>이벤트: 프로그램의 기능, 동작</strong></p>
<p>프로그램의 문제들을 파악하고 유지보수 하는 데 사용되며, 로깅을 통해 발생한 에러를 추적할 수 있다.</p>
<h3 id="로깅---level">로깅 - level</h3>
<p><strong>DEBUG &lt; INFO &lt; WARNING &lt; ERROR &lt; CRITICAL</strong> : 오른쪽으로 갈수록 심각도가 높다.
기본 로거 레벨 세팅은 WARNING이기 때에 설정 없이 INFO, DEBUG를 출력할 수 없습니다.
(높은 순으로 설정되있을 수록 하위 레벨은 무시한다.)</p>
<ul>
<li>DEBUG: 상세한 정보</li>
<li>INFO: 일반적인 정보</li>
<li>WARNING: 예상치 못하거나 가까운 미래에 발생할 문제</li>
<li>ERROR: 에러 로그. 심각한 문제</li>
<li>CRITICAL: 프로그램 자체가 실행되지 않을 수 있는 문제</li>
</ul>
<pre><code class="language-py">import logging

if __name__ == &#39;__main__&#39;:
    logger.info(&#39;hello elice!&#39;)</code></pre>
<p>파이썬 디폴트 로깅 모듈을 사용한다.</p>
<pre><code class="language-py">import logging

if __name__ == &#39;__main__&#39;:

    logger = logging.getLogger()
    logger.setlevel(logging.DEBUG)
    logger.info(&#39;hello elice!&#39;)
   #레벨을 수동으로 설정하고 출력하면 정상적으로 출력이 된다.</code></pre>
<h3 id="flask에서-로깅">Flask에서 로깅</h3>
<p>에러가 발생했을 때 Flask의 logger를 사용하여 에러를 확인 가능하다.</p>
<pre><code class="language-py">from flask import Flask
app = Flask(__name__)

if __name__ == &#39;__main__&#39;:
    app.logger.info(&#39;test&#39;)
    app.logger.debug(&#39;debug test&#39;)
    app.logger.error(&#39;error test&#39;)
    app.run()</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[03_Nov_2021 🐰 엘리스 AI 트랙 TIL: Flask 기초]]></title>
            <link>https://velog.io/@juanito_y247/03Nov2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-Flask-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@juanito_y247/03Nov2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-Flask-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Wed, 03 Nov 2021 14:40:53 GMT</pubDate>
            <description><![CDATA[<h1 id="웹-서버의-동작-과정-이해하기">웹 서버의 동작 과정 이해하기</h1>
<p>우리가 흔히 정보들을 접하고 사용하는 많은 서비스는 &#39;웹 서버&#39;를 통해 우리에게 제공되고 있다.</p>
<h2 id="웹-서버의-동작-과정">웹 서버의 동작 과정</h2>
<p><strong>클라이언트란?</strong> 사용자/ 사용자 컴퓨터 / 인터넷 브라우저를 의미한다. <strong>데이터를 서버에 요청</strong>한다.
<strong>서버란?</strong> 클라이언트로부터 <strong>받은 요청을 처리해주고 응답으로 데이터를 돌려주는 곳</strong>을 의미한다.</p>
<p><img src="https://images.velog.io/images/juanito_y247/post/5d165251-2894-4545-8a7e-7679df1080eb/download.png" alt=""></p>
<p>웹 서버의 동작: 클라이언트가 서버로 요청을 하고, 요청을 받은 서버는 요청에 해당하는 데이터를 응답으로 돌려준다.</p>
<p>서버의 응답으로 클라이언트가 받는 응답인 데이터는 HTML, JSON, XML 등 다양한 형태가 될 수 있다.</p>
<h3 id="요청과-응답">요청과 응답</h3>
<p>클라이언트와 서버 간 정보 교환에서는 <strong>미리 약속한 규칙</strong>을 통해야 한다.
클라이언트는 <strong>규칙에 따라 요청</strong>을 하고, 서버 또한 <strong>정해진 형태의 데이터로 응답</strong>을 한다.</p>
<h3 id="정해진-형식-데이터의-통로-api">정해진 형식, 데이터의 통로: API</h3>
<p>웹사이트의 접속 주소는 미리 약속된 주소라고 할 수 있다. 예를 들어 구글의 url 주소 (https:// <a href="http://www.naver.com)%EA%B0%80">www.naver.com)가</a> 있다. 해당 페이지의 url 주소를 주소창에 입력하면, 약속된 방법으로 요청한 후 해당하는 페이지를 보게 되는 것이다. </p>
<p>이렇게 정해진 방식으로 데이터의 통로 역할을 하는 것이 바로 API라고 할 수 있다.</p>
<h1 id="flask-framework란">Flask Framework란?</h1>
<h2 id="framework란">Framework란?</h2>
<p>하나의 결과물을 만들기 위해서 제공하는 웹 개발 &#39;틀&#39;이다.
미리 작성되어 있는 함수(라이브러리)와 그 이상의 기능을 제공한다.</p>
<h3 id="flask">Flask</h3>
<p>Python을 사용해서 웹 서버를 만들 수 잇게 도와주는 Web Framework이다</p>
<p>Python 기반의 Framework로는 여러가지가 있는데</p>
<ul>
<li><p>다량의 기능을 미리 제공하는 Django (사용할 수 있는 기능이 많음)</p>
</li>
<li><p>기본적인 기능만 제공하는 MicroFramework: Flask, Pyramid, Bottle (개발이 자유롭다)</p>
</li>
</ul>
<p>가 있는데, 각각의 Framework 마다 장/단점이 있다.</p>
<h3 id="flask의-장점">Flask의 장점</h3>
<ul>
<li>나만의 서버를 쉽게 작성할 수 있다. ex) python, html, css, js 활용</li>
<li>간단한 코드로 빠르게 실행 할 수 있다. ex) app.run()</li>
<li>원하는 기능을 유연하게 확장하기 편리하다. e.g.) micro framework</li>
</ul>
<h1 id="flask로-웹-서버-만들기">Flask로 웹 서버 만들기</h1>
<p>웹 서버를 만드는 방법은 복잡할 것 같지만 Flask Framework를 사용해서
간단한 코드만으로 서버를 만들 수 있다.</p>
<h2 id="flask-simple-web-server-만들기">Flask Simple Web Server 만들기</h2>
<pre><code class="language-py">from flask import Flask
app = Flask(__name__)

@app.route(&#39;/&#39;)
def alex():
  return &#39;hello alex&#39;

if __name__ == &#39;__main__&quot;:
  app.run() </code></pre>
<ul>
<li>Flask 패키지에서 Flask를 import한다.</li>
<li>@app.route()는 서버에 접속 할 수 있는 url을 만들어 준다.</li>
<li>@app.route(&#39;/&#39;) 아래의 def elice()라는 함수는 app.route()의 url에서 실행할 함수이다.</li>
<li>if <code>__name__</code> == &#39;<code>__main__</code>&#39;은, 파일 &gt;이름이 main일 때만 app.run()이 실행되도록 한다.</li>
</ul>
<h1 id="url을-연결하고-데이터를-화면에-나타내기">URL을 연결하고 데이터를 화면에 나타내기</h1>
<p>app.route()는 url을 만들어준다. app.route()와 이어져 있는 함수를 사용해서 HTML과 JSON 형식의 데이터를 전달해보자.</p>
<h3 id="json-형식의-데이터-나타내기">JSON 형식의 데이터 나타내기</h3>
<pre><code class="language-py">from flask import Flask, jsonify
app = Flask(__name__)

@app.route(&#39;/&#39;)
def alex_json():
  my_data = {&#39;name&#39;:&#39;elice&#39;}
  return jsonify(my_data)

if __name__ = &#39;__main__&#39;:
  app.run()</code></pre>
<ul>
<li>Flask 패키지에서 Flask와 jsonify를 import한다.</li>
<li>jsonify라는 함수는 jsonify() 안에 있는 내용을 화면에 전달한다.</li>
<li>@app.route(&#39;/&#39;) 아래의 def elice_json() 함수는 app.route()의 url에서 실행할 함수이고, {&#39;name&#39;:&#39;elice&#39;}라는 데이터를 화면에 전달 해준다.</li>
</ul>
<h3 id="html-형식의-데이터-나타내기---파일-준비하기">HTML 형식의 데이터 나타내기 - 파일 준비하기</h3>
<ul>
<li>html을 화면에 전달기 위해서는 html 파일이 필요하다.</li>
<li>html 파일은 <strong>templates라는 폴더 아래에 위치</strong>시킨다.</li>
<li>templates 폴더에 html파일을 넣으면 <strong>Flask가 자동으로 찾아서 연결</strong>한다.</li>
</ul>
<pre><code>&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;나의 첫 html&lt;/html&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;h4&gt;html파일 띄우기&lt;/h4&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre><pre><code class="language-py">from flask import Flask, render_template
app = Flask(__name__)

@app.route(&#39;/&#39;)
def elice_html():
  return render_template(&#39;index.html&#39;)

if __name__ == &#39;__main__&#39;:
  app.run()</code></pre>
<ul>
<li>Flask 패키지에서 Flask와 render_template를 import 합니다.</li>
<li>render_template 라는 함수는 templates라는 폴더 안의 html파일을 불러와 주는 역할을 한다.</li>
<li>templates 폴더 내의 html 파일의 이름과 render_template()안의 이름이 같아야 화면에 잘 전달할 수 있다.</li>
<li>템플릿 폴더 내의 html을 render_template에 넣어서 elice_html 함수의 return에 넣어준다.</li>
</ul>
<h3 id="여러가지-url-연결하기">여러가지 url 연결하기</h3>
<pre><code class="language-py">@app.route(&#39;url&#39;)</code></pre>
<ul>
<li>url 주소를 route()의 인자로 넣어준다.</li>
<li>1개의 @app.route는 1개의 함수와 연결될 수 있다.</li>
<li>@app.route를 여러 개 사용해서 다양한 url을 만들 수 있다.</li>
<li><em>주의*</em> 한번 선언한 함수의 이름은 다시 사용할 수 없다.</li>
</ul>
<h1 id="rest-api란">REST API란?</h1>
<p><strong>HTTP URL을 통해 데이터의 자원을 표현</strong>하고, <strong>HTTP Method를 통해서 데이터를 다루는 방법</strong>을 의미한다.
Database, 이미지, 텍스트 등의 <strong>다양한 데이터에 적용</strong>할 수 있다.</p>
<h2 id="rest-api의-개념">REST API의 개념</h2>
<ul>
<li><strong>HTTP URI (Uniform Resource Identifier)를 통해 자원을 명시</strong>하고, <strong>HTTP Method(POST, GET, PUT, DELELTE)</strong>를 통해 해단 자원에 대한 <strong>CRUD를 적용</strong>하는 것</li>
<li>다양한 클라잉언트가 생겨남에 따라서 REST API가 필요하다 (다양한 곳에서의 통신 위해)</li>
<li>REST API는 메시지가 의도하는 바를 URL에서 나타내므로, 쉽게 기능을 파악할 수 있다.</li>
<li>HTTP 표준 프로토콜에 따르는 플랫폼에서 사용 가능하다.</li>
<li>서버와 클라이언트의 구분을 명확하게 할 수 있다.</li>
<li>REST API의 표준이 존재하지 않는 단점이 있다.</li>
</ul>
<h1 id="http-method-사용하기">HTTP Method 사용하기</h1>
<h2 id="http-method의-개념---getpost">HTTP Method의 개념 - GET/POST</h2>
<p>GET과 POST는 HTTP Method 중 하나이다.  <strong>GET은 데이터를 URL 뒤에 ?와 함께 사용</strong>하고 <strong>POST는 특정 양식에 데이터를 넣어 전송</strong>하는 방법이다.</p>
<h3 id="get-방식의-예시">GET 방식의 예시</h3>
<p><strong>http://사이트의 주소?데이터=123</strong></p>
<ul>
<li><strong>url 뒤에 물음표를 붙여서 데이터를 서버에 전송</strong>한다.</li>
</ul>
<h3 id="post-방식의-예시">POST 방식의 예시</h3>
<p>http://사이트의 주소
일정한 양식에 담아 데이터를 숨겨서 서버에 전송한다. (url이 같아도 내용은 다를 수 있음)</p>
<h3 id="코드-예">코드 예</h3>
<pre><code class="language-py">@app.route(&#39;url1&#39;, methods=[&quot;GET&quot;]
@app.route(&#39;url2&#39;, methods=[&quot;POST&quot;]
@app.route(&#39;url3&#39;, methods=[&quot;GET&quot;, &quot;POST&quot;]</code></pre>
<ul>
<li>app.route()에 methods라믄 옵션을 추가해서 해당하는 HTTP Method만 사용할 수 있도록 적용할 수 있다.</li>
<li>url1, url2는 각각 GET,POST 메서드만 사용가능</li>
<li>url3는 GET,POST 모두 사용이 가능하다.</li>
</ul>
<h4 id="get-요청만-사용">GET 요청만 사용</h4>
<pre><code class="language-py">from flask import *
app = Flask(__name__)

@app.route(&#39;/&#39;, methods=[&#39;GET&#39;]) # url 뒤에 ?name=alex를 넣어 get 요청을 한다.
def alex():
    name = request.args.get[&#39;name&#39;]
    result = &#39;hello. &#39; + name
    return result
if __name__ == &#39;__main__&#39;:
    app.run()</code></pre>
<h4 id="post-요청만-사용">POST 요청만 사용</h4>
<blockquote>
<p>index.html</p>
</blockquote>
<pre><code>&lt;html&gt;
&lt;body&gt;
    &lt;form action=&#39;/login&#39; method=&#39;post&#39;&gt;
        &lt;p&gt;
        아이디: &lt;input type=&#39;text&#39; name=&#39;id&#39;&gt;
        &lt;/p&gt;
        &lt;p&gt;
        비밀번호: &lt;input type=&#39;password&#39; name=&#39;pwd&#39;&gt;
        &lt;/p&gt;
        &lt;button type=&#39;submit&#39;&gt;
    &lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><blockquote>
</blockquote>
<blockquote>
<p>app.py</p>
</blockquote>
<pre><code class="language-py">from flask import *
app = Flask(__name__)
&gt;
@app.route(&#39;/&#39;, methods=[&#39;GET&#39;])
def alex():
    return render_template(&#39;index.html&#39;)
&gt;
@app.route(&#39;/login&#39;, methods=[&#39;POST&#39;])
def alex_post():
    id = request.form[&#39;id&#39;]
    pwd = request.form[&#39;pwd&#39;]
    if id == &#39;alex&#39; and pwd =&#39;1234&#39;:
        return &#39;Hi! Alex!&#39;
    else:
        return &#39;ERROR&#39;
 &gt;
 if __name__ == &#39;__main__&#39;:
     app.run()</code></pre>
<blockquote>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[30_Oct_2021 🐰 엘리스 AI 트랙 TIL: 재귀호출을 이용한 문제 해결]]></title>
            <link>https://velog.io/@juanito_y247/30Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-%EC%9E%AC%EA%B7%80%ED%98%B8%EC%B6%9C%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@juanito_y247/30Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-%EC%9E%AC%EA%B7%80%ED%98%B8%EC%B6%9C%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Mon, 01 Nov 2021 08:03:25 GMT</pubDate>
            <description><![CDATA[<h1 id="재귀함수">재귀함수</h1>
<h3 id="재귀함수를-디자인-하기-위한-3-단계">재귀함수를 디자인 하기 위한 3 단계</h3>
<p>1) 함수의 정의를 명확히 한다
2) 기저 조건에서 함수가 제대로 동작하게 작성한다
3) 함수가 제대로 동작한다고 가정하고 함수를 완성한다.</p>
<p>어떤 문제든 제일 첫 번째로 시도해야 할 방법은 무조건 완전탐색이다.</p>
<p>그러나 완전탐색의 경우, 탐색범위가 커질수록 불리하다는 단점을 가지고있다.</p>
<p>데이터가 이미 정렬된 상태라면 <strong>이진탐색</strong>을 활용할 수 있다.</p>
<ul>
<li>중간값을 기준으로 찾고자 하는 값과의 크기 비교를 한다.
찾는 값을 탐색할 때 까지 범위를 지수로그 만큼 줄여나가므로 최악의 시간 복잡도는 O(logN)이다.<h1 id="분할정복법">분할정복법</h1>
문제를 소문제로 분할하여 각각의 소문제를 해결하는 방식이며, 소문제의 해결 결과를 이용해 전체 문제를 해결하는 방법이다.</li>
</ul>
<p>분할정복법에서는 수학적 문제 해결 능력이 가장 중요하고, 잠시 키보드에서 손을 치우고 노트와 펜을 잡아야 한다.</p>
<h3 id="합병-정렬">합병 정렬</h3>
<p>분할정복법으로 해결할 수 있는 대표적인 문제 예시이다.</p>
<p>정렬되지 않은 배열 arr이 있다고 하자</p>
<pre><code class="language-py">arr = [3,5,7,2,5,9,13,11,24,11,24,11,23,1,4,5,3,2]</code></pre>
<p>먼저 이 리스트를 2 분할한다.</p>
<pre><code class="language-py">arr1 = [2,3,5,5,7,9,11,13]
arr2 = [1,2,3,4,5,11,23,24]
#왼쪽과 오른쪽으로 나눈 리스트는 정렬되어 있다.</code></pre>
<p>이 두 배열을 다시 합치면 정렬된 전체 배열을 만들 수 있을 것이다.
합치기 위해서는 각 리스트의 0번째 인덱스를 비교한다.</p>
<p>두 인덱스 값을 비교하여 더 작은 값을 빼서 새로 만든 빈 전체 배열에 넣어준다.</p>
<h4 id="합병정렬의-시간복잡도">합병정렬의 시간복잡도</h4>
<p>n개의 요소를 정렬하는 데 드는 시간은 = T(n)이다.
여기서 T(n)은 둘로 나눈 두 배열 T(N/2) + T(N/2) 를 정렬하는 총 시간이다.</p>
<p>여기에 왼쪽 배열과 오른쪽 배열의 요소를 하나하나 전부 비교하기 때문에 
T(N) = T(N/2) + T(N/2) + O(N) 이다. N이 1이 될때까지 2로 나누는 시간은 logN이다. </p>
<p>이것을 다시 합치는 데에 O(N)의 시간이 소요되고, 해당 작업을 logN 번 수행하기 때문에 총 정렬시간은 O(NlogN)이 된다.</p>
<pre><code class="language-py">arr = [2,1,-2,5,-10,3,2,5,-3,7,9,-10]</code></pre>
<p>리스트를 둘로 나눠서 연속부분 최대합을 찾아보면, [2,1,-2,5] = 6, [2,5,-3,7,9] = 20이 나온다. 또한 전체 배열에서의 연속최대합을 찾아보면, [3,2,5] = 10이다.</p>
<p>여기서 자른 지점을 포함하는 연속부분최대합은, 자른 지점을 기준으로 왼쪽과 오른쪽을 독립적으로 생각하는 것이다. 위의 배열에서 자른 지점의 기준이 되는 요소는 3(왼쪽) 2(오른쪽)이다.</p>
<p>이제 각 요소를 포함하는 기준으로 각 연속부분 최대합을 구하면,
왼쪽 배열 기준 [3] = 3 이 가장 크고, 오른쪽 배열 기준 [2,5,-3,7,9] = 20으로 가장 크다.</p>
<h1 id="탐욕법-greedy">탐욕법 (Greedy)</h1>
<p>순간의 최적의 선택이 궁극적으로 최적의 선택이다. 단순한 방법도 문제 풀이에는 충분하다. </p>
<p>완전탐색을 사용하면, 범위가 커질수록 경우의 수가 어마어마하게 커지기 때문에 시간효율성을 보장하기 힘들다. 따라서, 이와 같은 경우 탐욕법을 이용하며 효과적으로 문제를 해결할 수 있다.</p>
<h1 id="요약">요약</h1>
<p>그러나, 탐욕법은 순간의 최선의 선택을 하는 가설을 파악하기 어려우며, 문제를 해결한 다는 것을 증명하기 어렵기 때문이다.</p>
<h1 id="분할정복-알고리즘-요약">분할정복 알고리즘 요약</h1>
<h3 id="분할정복법은-어렵다">분할정복법은 어렵다.</h3>
<p>분할정복법으로 해결할 수 있는 대표적인 예제로는:
합병정렬, 퀵정렬, 거듭제곱 구하기, 연속 부분 최대합, 가장 가까운 두 점 찾기, 히스토그램등이 있었다.</p>
<p>이 문제에서 발견할 수 있었던 점은, 문제를 어떻게 나누고, 작은 문제를 어떻게 해결해야 하며, 해결한 작은 문제를 또 어떻게 합쳐서 결과를 남길 것인가에 대한 문제였다.</p>
<p>이를 훈련하기 위해서는 관련 문제들을 많이 풀어보는 것이 중요하다.</p>
<h3 id="코딩-능력과-문제-해결-능력은-다르다">코딩 능력과 문제 해결 능력은 다르다</h3>
<p>코딩과 문제 해결 능력은 구별되어야 하며, 알고리즘 문제를 풀 때에는 키보드가 아닌 스스로의 논리를 가지고 노트와 펜으로 풀이를 떠올려야 할 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[27_Oct_2021 🐰 엘리스 AI 트랙 TIL: SQL과 함수]]></title>
            <link>https://velog.io/@juanito_y247/27Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-SQL%EA%B3%BC-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@juanito_y247/27Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-SQL%EA%B3%BC-%ED%95%A8%EC%88%98</guid>
            <pubDate>Sun, 31 Oct 2021 00:35:45 GMT</pubDate>
            <description><![CDATA[<h1 id="함수">함수</h1>
<ol>
<li>데이터의 값을 계산하거나 조작하는 함수</li>
<li>행의 그룹을 계산하거나 요약하는 그룹함수</li>
<li>열의 데이터 타입을 변환하는 함수로 종류가 나뉜다.</li>
</ol>
<h1 id="count">COUNT</h1>
<p>검색한 결과의 데이터의 개수를 가져오는 내장함수. 
NULL인 데이터는 제외</p>
<ol>
<li>SUM &amp; AVG</li>
<li>MAX &amp; MIN</li>
</ol>
<pre><code>SELECT COUNT(id) FROM book;
#book 테이블 안에 있는 id 컬럼의 개수를 검색한다.

SELECT COUNT(*) FROM book;
#모든 데이터 검색</code></pre><h1 id="limit">LIMIT</h1>
<p>테이블에서 출력하고자 하는 데이터의 개수를 제한하는 명령어</p>
<blockquote>
<p>기업에서 다루는 데이터는 그 수가 방대하기 때문에, 가져오고 싶은 만큼 데이터의 수를 제한하여 추출하는 과정이 필요하기 때문이다.</p>
</blockquote>
<pre><code>-- book 테이블에서 데이터를 5개만 가져오기
SELECT * FROM book LIMIT 5;

-- 2번째 데이터부터 5개를 가져오기
SELECT * FROM book LIMIT 1, 5;</code></pre><p>첫 번째 컬럼의 시작은 0이므로, 레인지를 지정하지 않으면 첫 번째 컬럼부터 가져온다.</p>
<h1 id="sum--avg">SUM &amp; AVG</h1>
<h3 id="sum-summation-총합">SUM (Summation: 총합)</h3>
<p>지정한 컬럼들의 값을 모두 더하여 총점을 구해주는 내장함수이다.</p>
<pre><code>SELECT SUM(math) FROM grade;
#수학점수의 총합을 구함</code></pre><h3 id="avg-average-평균">AVG (Average: 평균)</h3>
<p>지정한 컬럼들의 평균값을 구해주는 내장함수이다.</p>
<pre><code>SELECT AVG(korean) FROM grade;
#국어점수의 총 평균을 구해준다.</code></pre><h1 id="max--min">MAX &amp; MIN</h1>
<h3 id="max">MAX</h3>
<p>테이블에 존재하는 데이터에서 최대값을 가져오는 내장함수
숫자형(1,2,3..) 문자형(a,b,c 혹은 ㄱ,ㄴ,ㄷ, 혹은 특수문자도) 가능</p>
<pre><code>SELECT MAX(korean) FROM grade;
</code></pre><h3 id="min">MIN</h3>
<p>테이블에 존재하는 데이터에서 최솟값을 가져오는 함수
숫자형(1,2,3..) 문자형(a,b,c 혹은 ㄱ,ㄴ,ㄷ, 혹은 특수문자도) 가능</p>
<pre><code>SELECT MIN(english) FROM grade;</code></pre><p>원하는 데이터의 최솟값을 구한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[30_Oct_2021 🐰 엘리스 AI 트랙 TIL:
서브쿼리]]></title>
            <link>https://velog.io/@juanito_y247/30Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%AC</link>
            <guid>https://velog.io/@juanito_y247/30Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%AC</guid>
            <pubDate>Sun, 31 Oct 2021 00:35:18 GMT</pubDate>
            <description><![CDATA[<h1 id="서브쿼리">서브쿼리</h1>
<p>하나의 쿼리 안에 포함된 또 하나의 쿼리
메인 쿼리가 서브쿼리를 포함하는 종속적인 관계이다.</p>
<ul>
<li>복잡한 논리로 데이터를 추출해야 할 때 사용한다.
e.g.) 연봉이 X원인 남자가 읽는 책은 무엇인지 찾고 싶은데, 매년 책을 읽는 지 혹은 올해만 읽는지 확인.</li>
</ul>
<h2 id="서브쿼리의-특징">서브쿼리의 특징</h2>
<ul>
<li>알려지지 않은 기준을 이용한 검색에 유용하다 (연봉이 상위 1%인 사람)</li>
<li>메인 쿼리가 실행되기 이전에 한 번만 실행 (서브쿼리 -&gt; 메인쿼리 순으로 실행)</li>
<li>한 문장에서 여러 번 사용 가능</li>
</ul>
<pre><code>SELECT *
FROM employee
WHERE salary &gt;
(SELECT salary FROM employee WHERE name = &#39;elice&#39;);</code></pre><p>사원 elice의 salary를 알지 못해도 검색이 가능하다.</p>
<h3 id="서브쿼리-주의사항">서브쿼리 주의사항</h3>
<ol>
<li>서브쿼리는 괄호와 함께 사용한다.</li>
<li>서브쿼리 안에서 ORDER BY 절은 사용할 수 없다.</li>
<li>서브쿼리는 연산자의 오른쪽에 사용되어야 한다.</li>
<li>서브쿼리는 오로지 SELECT문으로만 작성할 수 있다.</li>
</ol>
<h1 id="반환에-따른-분류">반환에 따른 분류</h1>
<h3 id="단일-행-서브쿼리">단일 행 서브쿼리</h3>
<p>결과가 한 행만 나오는 서브쿼리로, 서브쿼리 결과를 1개의 값만 반환하고 결과를 메인쿼리로 전달하는 쿼리</p>
<pre><code>SELECT * FROM employee
WHERE salary
(SELECT salary FROM employee WHERE 사원번호 = 1);</code></pre><h3 id="다중-행-서브쿼리">다중 행 서브쿼리</h3>
<p>서브쿼리의 결과를 2개 이상 반환하고, 결과를 메인쿼리로 전달하는 쿼리</p>
<pre><code>SELECT * 
FROM employee
WHERE salary IN 
(SELECT MAX(salary) FROM employee GROUP BY deptno);</code></pre><p>IN 다중 행 연산자를 사용한다.</p>
<h3 id="다중-행-연산자">다중 행 연산자</h3>
<table>
<thead>
<tr>
<th>기호</th>
<th>뜻</th>
</tr>
</thead>
<tbody><tr>
<td>IN</td>
<td>하나라도 만족하면 반환</td>
</tr>
<tr>
<td>ANY</td>
<td>하나라도 만족하면 반환, 비교 연산 가능</td>
</tr>
<tr>
<td>ALL</td>
<td>모두 만족하면 반환, 비교 연산 가능</td>
</tr>
</tbody></table>
<pre><code>1 in (1,2,3,4) = 참
10 &lt; any (1,2,3,4) = 최대값 찾기 : 4 =&gt; 거짓
99 &gt;= all (99,100,101) 최대값 찾기 : 101 =&gt; 거짓</code></pre><h1 id="위치에-따른-분류">위치에 따른 분류</h1>
<h3 id="스칼라-서브쿼리">스칼라 서브쿼리</h3>
<p>SELECT(쿼리의 머리부분)절에서 사용하는 서브쿼리, 스칼라 서브쿼리는 오로지 한 행만 반환하며 마치 JOIN을 사용한 것과 같은 결과를 나타낸다.</p>
<p><strong>스칼라 서브쿼리를 쓰는 이유</strong>: 적은 데이터라면 JOIN 연산과 큰 차이가 없을 수 있지만, 데이터의 규모가 클 경우, 계산 속도가 빠르게 데이터가 추출된다.</p>
<pre><code>SELELCT student.name, (
    SELECT  math
    FROM middle_test as m
    WHERE m.student_id = student.student_id
) AS middle_avg
FROM students;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[29_Oct_2021 🐰 엘리스 AI 트랙 TIL: 정규화(Normalization)와 View]]></title>
            <link>https://velog.io/@juanito_y247/29Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-%EC%A0%95%EA%B7%9C%ED%99%94Normalization</link>
            <guid>https://velog.io/@juanito_y247/29Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-%EC%A0%95%EA%B7%9C%ED%99%94Normalization</guid>
            <pubDate>Sat, 30 Oct 2021 23:53:38 GMT</pubDate>
            <description><![CDATA[<h1 id="정규화란">정규화란?</h1>
<p>테이블 간 데이터 조작(삽입, 수정, 삭제)시 발생할 수 있는 <strong>이상 현상을 줄이기 위해 하는 작업</strong>이다.</p>
<p>정규화 단계로는 1<del>5차 정규화와 BCNF까지 다양한 종류가 있지만, **1</del>3차 정규화까지 진행하면 대부분의 이상현상을 없앨 수 있다**.</p>
<h1 id="1차-정규화1nf">1차 정규화(1NF)</h1>
<p>각 속성마다 값이 1개씩 존재하도록 하는 과정이며, <strong>원자화</strong>라고도 한다.
=&gt; 각 속성 안에는 <strong>단일의 원자화된 데이터</strong>만을 넣는 것을 원칙으로 한다.</p>
<h1 id="2차-정규화">2차 정규화</h1>
<p><strong>복합키로 구성 되어있을 때 고려</strong>해야 하며, <strong>모든 속성이 완전 함수 종속</strong>이 되도록 하는 작업이다.</p>
<h3 id="완전-함수-종속">완전 함수 종속</h3>
<p>예를 들어, A,B,C,D 가 있을 때 B가 A에 의해 종속되는 경우, B는 다른 내용(C,D)에 의해 종속이 되지 않는 경우를 말한다.</p>
<p>같은 대상의 데이터가 일치하지 않는 현상을 피하기 위해, <strong>해당 데이터 관련 속성을 분리시켜 종속성을 제거</strong>해야 한다.</p>
<p>해당 데이터를 수정할 경우, <strong>분리한 테이블에서 수정</strong>이 되므로, 변경사항이 참조하는 테이블에도 적용되는 것을 확인할 수 있다.</p>
<h1 id="3차-정규화">3차 정규화</h1>
<p>테이블 내에서 이행적 요소를 제거하는 작업이다.</p>
<h3 id="이행적인-요소">이행적인 요소?</h3>
<p>ex) 데이터를 특정 짓는 id는 동일하지만 관련 데이터가 다른 현상을 예로 들 수 있다.</p>
<p>데이터 정보는 모두 PK인 ID에 영향을 받는다. 따라서 이를 분리시켜 이행적 요소를 제거해야 한다.</p>
<p>3차 정규화를 거치고 데이터를 수정하면, 또 다시 분리된 해당 데이터의 값이 정상적으로 수정되어 반영되는 것을 확인할 수 있다.</p>
<hr>
<h1 id="view란">View란?</h1>
<p>하나 이상의 테이블에서 여러 정로를 토대로 만들어지는 가상의 테이블을 말한다.</p>
<p>기존의 데이터 테이블에는 불필요한 정보도 들어있으므로, 필요한 정보만 추출하여 가상의 테이블(view)을 생성한다. -&gt; 보안성과 속도를 높인다.</p>
<blockquote>
<pre><code>CREATE VIEW &#39;테이블 명&#39; AS
SELECT 가져오는 속성 명, 속성 명2, ...
FROM 가져올 속성이 있는 테이블
(WHERE 절로 조건을 사용할 수 있다)</code></pre></blockquote>
<h1 id="여러-테이블에서-view-활용">여러 테이블에서 View 활용</h1>
<p>다수의 인원이 데이터 관리를 하게 될 경우, 데이터 테이블의 권한을 확장하게 되면 불필요한 정보를 제공되면서 개인정보 노출의 위험성이 증가하는 등 문제가 생기게 된다.</p>
<p>이때 View를 생성해서 데이터를 제공하면 필요한 정보만 선택해 가상의 테이블 형태로 제공하면, 불필요한 정보의 공유를 막고 고객 정보를 제외하여 제공 할 수 있다.</p>
<blockquote>
<pre><code>CREATE VIEW &#39;테이블 명&#39; AS
SELECT 가져오는 속성 명, 속성 명2, ...
FROM 가져올 속성이 있는 테이블, 테이블2...
(WHERE 절로 조건을 사용할 수 있다)</code></pre></blockquote>
<h1 id="view-삭제">View 삭제</h1>
<p>View는 실제 존재하지 않는 가상의 테이블이기에, 해당 view를 수정,삭제하더라도 원본 테이블에는 영향을 미치지 않는다.</p>
<blockquote>
<pre><code>DROP VIEW 삭제하는 View 명</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[29_Oct_2021 🐰 엘리스 AI 트랙 TIL: 프로젝트로 배우는 데이터베이스]]></title>
            <link>https://velog.io/@juanito_y247/29Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@juanito_y247/29Oct2021-%EC%97%98%EB%A6%AC%EC%8A%A4-AI-%ED%8A%B8%EB%9E%99-TIL-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Sat, 30 Oct 2021 16:27:26 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터베이스란">데이터베이스란?</h1>
<p>공유하여 사용할 목적으로 체계화하여 관리하는 데이터들의 집합이다.</p>
<h2 id="데이터베이스의-분류">데이터베이스의 분류</h2>
<h4 id="관계형-데이터베이스rdb">관계형 데이터베이스(RDB)</h4>
<p>EX) MariaDB, 엑셀 형태</p>
<ul>
<li>각 테이블 간의 관계가 존재한다</li>
<li>스키마가 존재한다.</li>
<li>구조적으로 안정적이지만 유연하지 못한 특징을 가지고 있다.</li>
</ul>
<h3 id="비관계형-데이터베이스nosql">비관계형 데이터베이스(NoSQL)</h3>
<p>EX) MongoDB (JSON 형태)</p>
<ul>
<li>각 테이블 간 관계가 없다</li>
<li>스키마 또한 존재하지 않는다</li>
<li>유연성을 가지고 있지만 구조 결정이 어렵다.</li>
</ul>
<p>상황과 조건에 따라 적절한 데이터베이스를 선택하는 것이 중요하다.</p>
<h1 id="데이터모델링이란">데이터모델링이란?</h1>
<p>효율적으로 데이터베이스를 구축하기 데이터베이스의 뼈대를 세우는 작업이다.</p>
<h2 id="데이터베이스-모델링-단계">데이터베이스 모델링 단계</h2>
<h4 id="요구-사항-정리">요구 사항 정리</h4>
<p>데이터가 어떠한 형태, 어떤 목적을 가지고 있는 지 정리하는 단계이다.</p>
<h4 id="개념적-데이터-모델-설계">개념적 데이터 모델 설계</h4>
<p><strong>핵심 개체</strong>를 찾고, 각 개체 간의 관계를 정리한다.</p>
<ul>
<li>관련성이 있는 데이터 끼리 묶고, 핵심 개체를 중심으로 관계를 형성한다.</li>
</ul>
<h4 id="논리적-데이터-모델-설계">논리적 데이터 모델 설계</h4>
<p>실제 데이터베이스로 구현하기 위한 모델링 단계이다.</p>
<ul>
<li>다른 데이터와 구분되는 유일 키 혹은 기본키 설정 등 관계형 데이터베이스를 구축하기 위한 정보를 설정한다.
ex) ERD 그림으로 데이터베이스의 관계를 그려본다.</li>
</ul>
<h4 id="물리적-데이터-모델-설계">물리적 데이터 모델 설계</h4>
<p>데이터가 어떻게 컴퓨터에 저장될 지 설계하는 단계이다.</p>
<ul>
<li>물리적 구조를 정의하고, 실제로 구현하는 단계이다.
ex) 각 데이터 테이블에 어떻게 데이터를 저장할 지 설계하고 구현.</li>
</ul>
<h1 id="코더랜드-공유-키보드-사업을-위한-데이터베이스">코더랜드 공유 키보드 사업을 위한 데이터베이스</h1>
<ul>
<li>킥보드 정보</li>
<li>대여 정보</li>
<li>고객 정보</li>
</ul>
<p>대여 정보는 킥보드 정보와 고객 정보와 연결된 관계를 같는 정보이다. 따라서 관계형 데이터베이스를 활용할 수 있다.</p>
<h3 id="공유-킥보드-운영-방침-대여-요구사항-분석">공유 킥보드 운영 방침: 대여 (요구사항 분석)</h3>
<ol>
<li>원활한 대여 관리를 위해 대여 정보는 <strong>대여한 킥보드의 ID, 대여한 고객의 ID, 대여해간 날짜</strong>로 구성된다.</li>
<li>대여한 킥보드의 ID는 <strong>실제 운영(소유)하고 있는 킥보드 ID</strong>만 입력 될 수 있다.</li>
<li>대여한 고객의 ID는 <strong>실제 가입한 고객의 ID</strong>만 입력 될 수 있다.</li>
<li>대여 일자는 년-월-일 시:분 으로 입력되며 고객은 킥보드 대여 후 1분 이내 다시 대여할 수 없다. <strong>단, 고객이 대여할 수 있는 킥보드의 대수에는 제한이 없다.</strong></li>
</ol>
<p><strong>테이블로 만든 예시</strong></p>
<table>
<thead>
<tr>
<th>구분</th>
<th>타입</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>대여일자</td>
<td>문자형</td>
<td>2020-10-01 11:00</td>
</tr>
<tr>
<td>대여한 고객 ID</td>
<td>문자형</td>
<td>elice_rabbit</td>
</tr>
<tr>
<td>대여한 킥보드 ID</td>
<td>문자형</td>
<td>E01</td>
</tr>
</tbody></table>
<h3 id="공유-킥보드-운영-방침-킥보드-요구사항-분석">공유 킥보드 운영 방침: 킥보드 (요구사항 분석)</h3>
<ol>
<li>킥보드 관리를 위해 모든 킥보드는 <strong>ID, 이미지 정보, 종류 정보, 연식 정보</strong>를 가지고 있다.</li>
<li>킥보드의 ID는 <strong>중복이 되거나 수정할 수 없다.</strong></li>
<li>킥보드의 이미지는 <strong>50자 미만의 URL로 구성</strong>되어 있으며 <strong>연식과 종류가 같은 킥보드일 경우 동일한 이미지를 활용</strong>한다.</li>
<li>킥보드의 종류는 <strong>브레이크의 위치</strong>에 따라 <strong>두 가지(뒷바퀴에 위치 - A형, 핸들에 위치 - B형)로 구분되며 중복이 가능</strong>하다.</li>
<li>킥보드의 <strong>연식</strong>은 <strong>킥보드의 생산년도로 4자리 숫자(YYYY)로 표현</strong>되며 <strong>중복이 가능</strong>하다.</li>
</ol>
<p><strong>테이블로 만든 예시</strong></p>
<table>
<thead>
<tr>
<th>구분</th>
<th>타입</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>킥보드 ID</td>
<td>문자형</td>
<td>E01</td>
</tr>
<tr>
<td>킥보드 종류</td>
<td>문자형</td>
<td>A</td>
</tr>
<tr>
<td>킥보드 이미지</td>
<td>문자형</td>
<td>https://..</td>
</tr>
<tr>
<td>킥보드 연식</td>
<td>숫자형</td>
<td>2019</td>
</tr>
</tbody></table>
<h3 id="공유-킥보드-운영-방침-킥보드-요구사항-분석-1">공유 킥보드 운영 방침: 킥보드 (요구사항 분석)</h3>
<ol>
<li>고객 관리를 위해 <strong>모든 고객</strong>은  <strong>ID, 이름, 전화번호</strong>를 가지고 있다.</li>
<li>고객ID는 <strong>영문 + 특문 + 숫자로 조합</strong>되며 <strong>길이는 15자 미만</strong>으로 구성되어 있다. 또한 <strong>ID는 중복이 되거나 수정될 수 없다.</strong></li>
<li>고객의 이름은 <strong>10자 미만의 한글</strong>로 구성되어 있으며 <strong>동명이인을 고려하여 중복이 가능</strong>하다.</li>
<li>고객의 전화번호는 15자 미만의 문자(<strong><em>-***</em></strong>-****)로 구성되어 있다.</li>
<li><strong>대여 중인 킥보드가 없어야</strong> <strong>회원 탈퇴(고객 정보 삭제)가 가능</strong>하다.</li>
</ol>
<p><strong>테이블로 만든 예시</strong></p>
<table>
<thead>
<tr>
<th>구분</th>
<th>타입</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>고객 ID</td>
<td>문자형</td>
<td>elice_rabbit</td>
</tr>
<tr>
<td>이름</td>
<td>문자형</td>
<td>엘리스 토끼</td>
</tr>
<tr>
<td>전화번호</td>
<td>문자형</td>
<td>010-1234-5678</td>
</tr>
</tbody></table>
<h1 id="데이터베이스-네이밍-규칙">데이터베이스 네이밍 규칙</h1>
<p><strong>유지보수와 의미의 명확성을 전달</strong>하기 위해 <strong>네이밍 규칙</strong>을 설정한다.</p>
<h3 id="공통-규칙">공통 규칙</h3>
<ol>
<li>줄임말 사용은 최소화한다. (단, 사용할 경우 범용적으로 사용되는 줄임말을 사용한다.)</li>
</ol>
<ul>
<li>kb_img (X) -&gt; kickboard_image(O)</li>
<li>tb_KickboardInfo(가능) info: information의 줄임말.</li>
</ul>
<h3 id="테이블-네이밍-규칙">테이블 네이밍 규칙</h3>
<ol>
<li>테이블 명을 작성할 때는 <strong>파스칼 표기법을 사용한다</strong>.</li>
</ol>
<ul>
<li>kickboard_rental (X) -&gt; KickboardRental(O)</li>
<li>customer_info (X) -&gt; CustomerInfo(O)</li>
</ul>
<ol start="2">
<li>테이블, 뷰(View)임을 한눈에 확인 할 수 있도록 테이블 명 앞에는 
&#39;tb_&#39;, &#39;v_&#39;를 붙인다.</li>
</ol>
<ul>
<li>tb_KickboardRental (킥보드 대여와 관련된 테이블)</li>
<li>v_ KickboardInfoAnalysis (뷰: 데이터 분석을 위해 필요한 정보만 모아 둔 가상 테이블)</li>
</ul>
<h3 id="속성-네이밍-규칙">속성 네이밍 규칙</h3>
<ol>
<li>속성 명을 작성할 때는 스네이크 표기법을 활용한다.</li>
</ol>
<ul>
<li>customer_id</li>
<li>customer_tel</li>
</ul>
<ol start="2">
<li>유일키, 외래키 등은 한 눈에 알아 볼 수 있도록 속성 명 앞에 &#39;pk_&#39;, &#39;fk_&#39;를 붙인다. </li>
</ol>
<ul>
<li>pk_kickboard_id</li>
<li>fk_pk_customer_id</li>
</ul>
<p><strong>대여 테이블 (논리적 모델링)</strong></p>
<table>
<thead>
<tr>
<th>구분</th>
<th>타입</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>대여일자</td>
<td>varchar(20)</td>
<td>rental_date</td>
</tr>
<tr>
<td>대여한 고객 ID</td>
<td>varchar(15)</td>
<td>customer_id</td>
</tr>
<tr>
<td>대여한 킥보드 ID</td>
<td>varchar(5)</td>
<td>kickboard_id</td>
</tr>
</tbody></table>
<ul>
<li>varchar는 문자형 타입을 의미(가변 문자열)하며 뒤에 괄호 안의 의미는 해당 문자열의 크기(byte)를 의미한다.</li>
</ul>
<p><strong>고객 테이블 (논리적 모델링)</strong></p>
<table>
<thead>
<tr>
<th>구분</th>
<th>타입</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>킥보드 ID</td>
<td>varchar(5)</td>
<td>kickboard_id</td>
</tr>
<tr>
<td>킥보드 종류</td>
<td>varchar(5)</td>
<td>customer_kind</td>
</tr>
<tr>
<td>킥보드 이미지</td>
<td>varchar(50)</td>
<td>kickboard_img</td>
</tr>
<tr>
<td>킥보드 연식</td>
<td>int</td>
<td>kickboard_year</td>
</tr>
<tr>
<td>- int는 정수형 타입을 의미하며, 괄호로 크기를 작성하지 않는다</td>
<td></td>
<td></td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th>구분</th>
<th>타입</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>고객 ID</td>
<td>varchar(15)</td>
<td>customer_id</td>
</tr>
<tr>
<td>이름</td>
<td>varchar(20)</td>
<td>customer_name</td>
</tr>
<tr>
<td>전화번호</td>
<td>varchar(15)</td>
<td>customer_tel</td>
</tr>
</tbody></table>
<ul>
<li>varchar에서 한글의 경우 한 글자 당 2byte가 필요하므로 20으로 설정한다.<h1 id="유일키란">유일키란?</h1>
<h3 id="key">key</h3>
데이터베이스에서 <strong>튜플(레코드, 행)간 구분을 위한 값(속성)</strong>이다</li>
<li><blockquote>
<p>유일키, 복합키, 외래키 등 다양한 종류가 존재한다.</p>
</blockquote>
</li>
</ul>
<h3 id="유일키primary-key">유일키(Primary key)</h3>
<p>테이블에서 <strong>튜플(레코드, 행)을 구분지어주는 고유 식별 값</strong>(속성)</p>
<ul>
<li>유일키 값은 <strong>중복 될 수 없으며, NULL 값 또한 불가능</strong>하다.</li>
</ul>
<p><strong>유일키 선정 팁</strong>
유일 키 선정시에는 중복이 되지 않는 중요 속성을 유일키로 선택한다.</p>
<p><strong>유일키의 선언</strong></p>
<blockquote>
<pre><code>CREATE TABLE &#39;테이블 명&#39; {
    &#39;속성명&#39; 타입,
    &#39;속성명2&#39; 타입,
    PRIMARY KEY(&#39;유일키로 사용할 속성명&#39;);
}</code></pre></blockquote>
<pre><code>
# 복합키(Composite Key)란?
**문제**
Primary 키 값과 동일한 값을 한번 더 테이블에 주입한다면 유일키 중복 오류가 발생한다.

이러한 문제를 해결하기 위해, **두 개 이상의 속성을 활용하여 튜플을 구분**지어주는 방법인 **복합키**를 활용해야 한다.

-&gt; 누가, 언제 킥보드를 빌려 갔는지에 대한 정보가 중요하기 때문에 대여 일자를 추가하여 **복합키를 구성한다**.
--&gt; 고객 ID가 중복 되어도 **또 다른 속성인 대여 일자가 달라 서로 다른 행으로 처리**한다.

**복합키 선언**
&gt;```
CREATE TABLE &#39;테이블 명&#39; {
    &#39;속성명&#39; 타입,
    &#39;속성명2&#39; 타입,
    ...
}
PRIMARY KEY(`복합키로 사용할 속성명1`,`복합키로 사용할 속성명2`)</code></pre><blockquote>
<p>유일키에 복수 개의 속성명을 넣어 복합키를 구성한다.</p>
</blockquote>
<h1 id="외래키란">외래키란?</h1>
<p>테이블에 존재하는 데이터를 다시 입력하려 했을 때, 실수로 다르게 추가하면 추후 데이터 관리에 문제가 발생하게 된다.</p>
<p><strong>외래키(Foreign Key)</strong>는 다른 테이블의 키와 연결을 해주는 키이며, <strong>참조의 무결성</strong>을 유지하기 위해 활용한다.</p>
<ul>
<li><strong>참조의 무결성</strong>: 외래키 값이 <strong>참조 중인 테이블의 값과 일관성을 가지는 것</strong>을 의미한다.</li>
</ul>
<p>코더랜드 킥보드 대여 데이터베이스의 경우, 고객의 ID에 대해 따로 테이블을 구성하고, <strong>고객 테이블의 &#39;고객ID&#39; 속성을 참조하는 외래키를 구성</strong>한다.</p>
<p>-&gt; 새로 추가하려는 행 중 외래키인 <strong>&#39;고객ID&#39;의 내용이 고객 테이블(기본키 참조)에 있지 않은 내용이므로 추가되지 않는다</strong>.</p>
<h3 id="외래키foreign-key-선언">외래키(Foreign Key) 선언</h3>
<blockquote>
<pre><code>CREATE TABLE &#39;테이블 명&#39; {
    &#39;속성명&#39; 타입,
    &#39;속성명2&#39; 타입,
    ...
    FOREIGN KEY (&#39;외래키로 사용할 속성 명&#39;) 
    REFERENCES &#39;참조하는 속성이 있는 테이블&#39; (&#39;참조할 속성명&#39;)
}</code></pre></blockquote>
]]></description>
        </item>
    </channel>
</rss>