<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>_coyg_.log</title>
        <link>https://velog.io/</link>
        <description>COYG🔴⚪</description>
        <lastBuildDate>Wed, 24 Jan 2024 07:26:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>_coyg_.log</title>
            <url>https://velog.velcdn.com/images/_coyg_/profile/9f91436c-37bd-48a1-801f-153365601747/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. _coyg_.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/_coyg_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[패스트캠퍼스] React 강의 학습후기]]></title>
            <link>https://velog.io/@_coyg_/%ED%8C%A8%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%8D%BC%EC%8A%A4-React-%EA%B0%95%EC%9D%98-%ED%95%99%EC%8A%B5%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@_coyg_/%ED%8C%A8%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%8D%BC%EC%8A%A4-React-%EA%B0%95%EC%9D%98-%ED%95%99%EC%8A%B5%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Wed, 24 Jan 2024 07:26:04 GMT</pubDate>
            <description><![CDATA[<h1 id="part-1">Part 1</h1>
<h2 id="개요">개요</h2>
<h3 id="프론트엔드-구성요소">프론트엔드 구성요소</h3>
<h4 id="html">HTML</h4>
<p>HyperText Markup Language.
웹 페이지의 전체적인 구조(리스트, 버튼, 텍스트 등)를 만드는 언어이다.</p>
<h4 id="css">CSS</h4>
<p>Cascading Style Sheets.
HTML에서 정의된 요소들의 스타일(폰트, 모양, 위치 등)을 지정하는 언어이다.</p>
<h4 id="js">JS</h4>
<p>JavaScript.
HTML+CSS에서 정의된 요소들의 동적 처리를 담당하는 언어이다.</p>
<h3 id="웹">웹</h3>
<h4 id="웹-애플리케이션의-동작-원리">웹 애플리케이션의 동작 원리</h4>
<ol>
<li>(클라이언트 - 주로 브라우저) 서버로 특정 주소에 대한 요청을 보낸다.</li>
<li>(서버) 받은 요청에 대한 응답(HTML 먼저)을 클라이언트로 보내준다.</li>
<li>(클라이언트) HTML 응답을 받으면 그 페이지의 추가정보(CSS, JS)를 요청한다.</li>
<li>(서버) 나머지 추가정보들을 응답으로 보내준다.</li>
</ol>
<h4 id="브라우저-구조">브라우저 구조</h4>
<ol>
<li>창 (window) - 프로그램 자체에 해당하는 영역</li>
<li>탭 (tab) - 창 내에서 여러 페이지를 띄울 수 있게 해주는 영역</li>
<li>주소창 (address bar) - 말 그대로 주소를 입력하는 영역</li>
<li>뷰포트 (viewport) - 탭 내에서 웹 페이지가 렌더링되는 전체 영역</li>
</ol>
<h4 id="웹에서의-이미지">웹에서의 이미지</h4>
<p>웹에서 이미지를 표현할 때 크게 두 가지 방식을 사용한다.</p>
<ol>
<li><p>비트맵</p>
<ul>
<li>픽셀로 이루어진 그리드 형태 이미지</li>
<li>각 픽셀은 특정 색상을 가짐</li>
<li>해상도에 따라 선명도가 결정됨. 픽셀마다 색상 정보를 담기 때문에 파일 크기가 크고, 이미지를 확대하면 픽셀이 보이거나 흐리게 보일 수 있음</li>
<li>대표적인 이미지 형식: JPEG, PNG, BMP 등</li>
</ul>
</li>
<li><p>벡터</p>
<ul>
<li>수학적인 모양과 경로로 나타내는 이미지</li>
<li>선, 곡선, 다각형 등의 기하학적 요소로 이루어져있음</li>
<li>이미지를 확대해도 선명도가 유지되고, 파일 크기가 작음</li>
<li>대표적인 이미지 형식: SVG</li>
</ul>
</li>
</ol>
<h3 id="html-1">HTML</h3>
<h4 id="doctype">DOCTYPE</h4>
<p>DOCTYPE(DTD): Document Type Definition.
현재 문서/파일이 어떤 HTML 버전을 사용하는지 명시하는 키워드.</p>
<h4 id="tags">tags</h4>
<ol>
<li>html: HTML 문서의 범위(처음과 끝)를 나타내는 태그</li>
<li>head: HTML 문서의 정보를 나타내는 태그<ul>
<li>meta: 아래 정보 외의 나머지 정보를 제공하는 태그<ul>
<li>charset: 문자를 어떻게 인코딩할 지 지정</li>
</ul>
</li>
<li>title: 페이지의 제목을 지정하는 태그</li>
<li>link: 외부 파일(대부분 css)을 불러오는 태그</li>
<li>script: 외부 js 파일을 불러오는 태그</li>
<li>style: css 스타일을 html 파일 내에서 지정할 수 있게 해주는 태그</li>
</ul>
</li>
<li>body: HTML 문서의 구조를 나타내는 태그</li>
</ol>
<h2 id="html-2">HTML</h2>
<p>HTML은 요소로 이루어진 문서이다.
요소(element): 앞뒤에 태그로 감싸진 하나의 개체.</p>
<h3 id="태그">태그</h3>
<h4 id="빈-태그">빈 태그</h4>
<p>기본 index.html 파일에 <code>meta</code> 태그의 경우 닫히는 태그가 존재하지 않는데, 이를 빈(empty) 태그라고 한다.
빈 태그는 닫히는 꺽쇠 전에 &#39;/&#39;를 붙여주어도 되고 안 붙여줘도 되는데 되도록이면 붙여주는게 좋다.</p>
<h4 id="속성">속성</h4>
<p>열리는 태그에 요소의 속성을 지정해줄 수 있다.
<code>&lt;script src=&quot;script.js&quot;&gt;&lt;/script&gt;</code>
위와 같은 식으로 원하는 속성(src)에 값(script.js)을 지정해줄 수 있다.</p>
<p>대부분의 빈 태그들은 별도의 설정 없이는 사용할 수 없기 때문에 태그마다 필수적으로 설정해줘야 하는 속성들이 존재한다.</p>
<h3 id="inline-vs-block">Inline vs. block</h3>
<h4 id="inline">Inline</h4>
<ul>
<li>좌에서 우로(수평) 쌓인다.</li>
<li>세로/가로 사이즈가 내용에 맞춰 최대한 줄어든다.</li>
<li>style 속성으로 사이즈를 명시해도 적용되지 않는다.</li>
<li>내/외부 여백은 가로 여백만 적용된다.</li>
<li>자식 요소로 블록 요소를 가질 수 없다.</li>
</ul>
<h4 id="block">Block</h4>
<ul>
<li>위에서 아래로(수직) 쌓인다.</li>
<li>부모 요소에 따라 길이는 최대한 늘어나고 높이는 최대한 줄어든다.</li>
<li>style 속성으로 사이즈를 원하는만큼 수정할 수 있다.</li>
<li>내/외부 여백 모두 적용된다.</li>
<li>자식 요소로 블록/인라인 요소를 가질 수 있다.</li>
</ul>
<h3 id="핵심-요소">핵심 요소</h3>
<p><code>div</code>: (block) Division. 구분을 위해 사용되는 요소.
<code>h1</code>: (block) Heading. 해당 범위의 제목을 의미하며, h 뒤의 숫자(1~6)에 따라 중요도(크기) 설정 가능.
<code>p</code>: (block) Paragraph. 문장 구분을 위해 사용되는 요소.
<code>img</code>: (inline) Image. 이미지를 삽입하는 요소. 속성으로는 src(이미지 경로)와 alt(이미지 로드 실패 시 대체 텍스트)가 있음.
<code>ul</code>: (block) Unordered list. 순서가 필요없는 집합을 의미하는 요소. 하위 요소(항목)로 li 요소를 1개 이상 가짐.
<code>a</code>: (Inline) Anchor. 특정 페이지로 이동하는 하이퍼링크를 지정하기 위해 사용되는 요소. 속성으로 href(하이퍼링크 레퍼런스-실제 주소)와 target(링크 이동 시 열릴 탭)을 가짐.
<code>span</code>: (Inline) 구분을 위해 사용되는 요소.
<code>br</code>: (Inline) Break. 줄 바꿈을 위해 사용되는 요소.
<code>input</code>: (Inline &amp; Block) 글자 요소이지만 상자 요소의 특징도 사용할 수 있음. 수평으로 쌓이지만 가로/세로 사이즈와 여백을 지정할 수 있음. 속성으로는 type(입력받을 데이터 타입), value(디폴트로 보여지는 값), placeholder(입력값에 대한 힌트), disabled(입력할 수 없음)가 있음.
<code>label</code>: (Inline) input 요소와 텍스트를 묶을 때 사용됨.
<code>table</code>: (Block) 행(tr)과 열(td)로 이루어진 집합.</p>
<h3 id="전역-속성">전역 속성</h3>
<p>모든 태그에 지정할 수 있는 속성.</p>
<p>title: 요소에 제목을 지정 (해당 요소에 커서를 올려놔야 보이는 제목)
style: 요소에 스타일을 입힘
class: 요소에 이름을 지정 (중복 가능)
id: 요소에 이름을 지정 (중복 안됨)
data-<em>name</em>: 요소에 변수명과 값을 지정하면 js에서 그 변수에 접근 가능 (querySelectorAll을 통해 해당 요소의 태그에 해당하는 요소들을 전부 가져와서, 각 요소의 dataset에서 <em>name</em>에 해당하는 변수에 접근이 가능함)</p>
<h2 id="css-1">CSS</h2>
<h3 id="기본-문법">기본 문법</h3>
<pre><code class="language-css">div {           /* 선택자: 스타일을 적용할 대상 */
  color: red;   /* 색상: 빨강 */
  margin: 20px; /* 외부 여백: 20픽셀 */
}</code></pre>
<h3 id="선언-방식">선언 방식</h3>
<h4 id="내장-방식">내장 방식</h4>
<p>HTML 파일의 <code>head</code> 영역에 <code>style</code> 태그로 작성하는 방법.
장점: HTML에서 바로 스타일 적용 가능
단점: 스타일 정보가 많아지면 가독성 저하 및 처리가 복잡함</p>
<h4 id="인라인-방식">인라인 방식</h4>
<p>HTML 파일의 요소에 style 속성으로 선언하는 방법.
단점: 우선순위 문제 때문에 코드의 유지보수가 어려움</p>
<h4 id="링크-방식">링크 방식</h4>
<p>HTML 파일의 <code>head</code> 영역에 <code>link</code> 태그로 외부 CSS 파일을 참조해오는 방법. (병렬)</p>
<h4 id="import-방식">import 방식</h4>
<p><code>@import url(&quot;경로&quot;)</code>
CSS 파일에서 외부 CSS 파일을 참조해오는 방법. (직렬)</p>
<h3 id="선택자">선택자</h3>
<h4 id="기본-선택자">기본 선택자</h4>
<ol>
<li>전체 선택자(*): 모든 요소를 선택함</li>
<li>태그 선택자(태그 이름): 지정한 태그의 요소를 모두 선택함</li>
<li>클래스 선택자(.클래스 이름): 지정한 클래스 속성값의 요소를 모두 선택함</li>
<li>아이디 선택자(#아이디 이름): 저정한 아이디 속성값의 요소를 한 개 선택함</li>
</ol>
<h4 id="복합-선택자">복합 선택자</h4>
<p>기본 선택자들을 조합해서 사용하는 선택자.</p>
<ol>
<li>일치 선택자(예: tag.class): <code>tag</code> 태그이면서 class 클래스인 모든 요소를 선택함</li>
<li>자식 선택자(예: tag &gt; .class): <code>tag</code> 태그의 자식 중 class 클래스인 모든 요소를 선택함</li>
<li>하위 선택자(예: tag .class): <code>tag</code> 태그의 후손 중 class 클래스인 모든 요소를 선택함</li>
<li>인접 형제 선택자(예: .class + tag): class 클래스의 형제 중 <code>tag</code> 태그인 요소 중 바로 다음 요소를 선택함</li>
<li>일반 형제 선택자(예: .class ~ tag): class 클래스의 형제 중 <code>tag</code> 태그인 요소 중 다음 요소를 모두 선택함</li>
</ol>
<h4 id="가상-클래스-선택자">가상 클래스 선택자</h4>
<p>대상 요소에 대해 어떠한 행동을 했을 때 동작하는 개념.
기본 선택자 끝에 &#39;:&#39;를 붙여서 가상 클래스 선택자를 지정할 수 있다.</p>
<ol>
<li>hover: 마우스의 커서가 해당 요소에 올라가 있을 때 스타일이 적용됨</li>
<li>active: 마우스로 해당 요소를 클릭하고 있을 때 스타일이 적용됨</li>
<li>focus: 해당 요소가 선택됐을 때 스타일이 적용됨 (input 등 입력을 받을 수 있는 요소 한정. 그 외 요소들은 tabindex 속성으로 focus를 가능하게 할 수 있다)</li>
<li>first-child(.class tag:first-child): class 클래스를 가진 요소의 자식 요소 중 <code>tag</code> 태그인 자식 중 첫째를 선택함</li>
<li>last-child: 위의 반대</li>
<li>nth-child(2)(.class *:nth-child(2)): class 클래스를 가진 요소의 하위 요소 전체 중 2번 째 자식을 선택함 (숫자에 n이 붙으면 2의 배수 번째에 해당하는 요소들을 선택함; 2n+1 등도 가능함; n+2 같은 경우에는 2번째 이상 요소들을 전부 선택함)</li>
<li>부정 선택자(.class *:not(span)): class 클래스를 가진 요소의 자식 중 <code>span</code> 태그 요소가 아닌 요소들을 전부 선택함</li>
</ol>
<h4 id="가상-요소-선택자">가상 요소 선택자</h4>
<p>가상의 인라인 요소를 만들어 실제로 삽입할 수 있음.</p>
<ol>
<li>before(.class::before { content: &quot;앞!&quot;; }): class 클래스를 가진 요소의 내부 앞에 &quot;앞!&quot;을 삽입</li>
<li>after: 위의 반대</li>
</ol>
<p>before, after 가상 요소 선택자의 경우 content라는 속성은 무조건 있어야 한다(빈 문자열이라도).
인라인 요소 삽입이기 때문에 사이즈, 여백 등을 지정해줄 수 없지만 display라는 속성에 값을 block으로 지정해주면 가능해진다.</p>
<h4 id="속성-선택자">속성 선택자</h4>
<ol>
<li>속성 선택자([type]): type이라는 속성을 가진 요소를 전부 선택함</li>
<li>속성-값 선택자([type=&quot;password&quot;]): type이라는 속성과 그 값에 해당하는 요소를 전부 선택함</li>
</ol>
<h3 id="스타일-상속">스타일 상속</h3>
<h4 id="강제-상속">강제 상속</h4>
<p>본래는 부모 요소의 글자나 문자와 관련된 스타일은 웬만하면 상속이 된다. </p>
<p>일반 상속이 되지 않는 속성들에 한해서 강제 상속을 할 수 있다.</p>
<p>부모 요소에 존재하는 스타일 속성에 대해서 같은 속성을 자식 요소에 정의하고 값에 inherit을 지정하면 부모 요소의 스타일 속성과 같은 값이 들어간다.</p>
<h3 id="선택자-우선순위">선택자 우선순위</h3>
<p>우선순위 및 점수</p>
<p>!important(99999999) &gt; 인라인 선언(1000) &gt; id 선택자(100) &gt; class 선택자(10) &gt; tag/요소 선택자(1) &gt; 전체 선택자(0)</p>
<p><code>body</code>는 상속 x</p>
<p>!important는 지정하기 원하는 속성의 값 뒤에 붙이는 값이다.</p>
<p>복합 선택자들의 경우 사용되는 모든 기본 선택자들의 점수를 합산해서 비교하는 것이 편하다.</p>
<h3 id="속성-1">속성</h3>
<h4 id="widthheight">width/height</h4>
<ul>
<li>width, height: 기본값으로 auto(inline 요소의 경우 둘다 최소; block 요소는 width 최대, height 최소)</li>
<li>max-width, max-height: 최대 픽셀 제한 (none: 제한 없음)</li>
<li>min-width, min-height: 최소 픽셀 제한 (0: 제한 없음)</li>
</ul>
<h4 id="단위">단위</h4>
<ul>
<li>em: 요소의 폰트 사이즈 (예: font-size: 16; width: 20em == 16*20px)</li>
<li>rem: 루트 요소(html)의 폰트 사이즈</li>
<li>vw/vh: 뷰포트 기준 길이/높이 퍼센티지</li>
</ul>
<h4 id="여백">여백</h4>
<ul>
<li><p>margin: 요소의 외부 여백을 지정 (auto: 가운데 정렬)</p>
<pre><code class="language-css">margin: 10px; /* 상하좌우 외부 여백 10px */
margin: 10px 20px; /* 상하 좌우 */
margin: 10px 20px 30px; /* 상 좌우 하 */
margin: 10px 20px 30px 40px; /* 상 우 하 좌 (시계 방향) */
margin-top(bottom/left/right): 10px;</code></pre>
<p>음수값도 사용 가능. 외부 여백 축소.</p>
</li>
<li><p>padding: 요소의 내부 여백을 지정 (auto: 가운데 정렬) margin과 마찬가지 방식으로 지정할 수 있음.</p>
</li>
</ul>
<h1 id="part-4">Part 4</h1>
<h2 id="리액트">리액트</h2>
<h4 id="용어">용어</h4>
<p>리액트: 사용자 인터페이스를 구현하기 위한 효율적인 선언적 자바스크립트 라이브러리.
프레임워크: 특정 앱/서비스를 만들기 위해 필요한 모든 것을 포함.
라이브러리: 특정 기능의 모듈화.</p>
<p>프레임워크는 필요에 따라 많은 라이브러리를 포함할 수 있다.</p>
<p>리액트 컴포넌트: 리액트 앱의 가장 작은 구성 요소.
예) 인스타그램의 컴포넌트로는 포스트, 검색창, 스토리, 프로필 등등이 있다.</p>
<ol>
<li>클래스형 컴포넌트 (hooks 발표 이전)</li>
<li>함수형 컴포넌트 (hooks 발표 이후)</li>
</ol>
<h3 id="jsx">JSX</h3>
<p>Javascript Syntax Extension.
주로 리액트에서 UI를 나타기 위해 사용함.
JSX는 자바스크립트와 HTML 구조를 같이 사용할 수 있다.
<code>const hello = &lt;h1&gt;Hello World!&lt;/h1&gt;;</code>
바벨을 통해 jsx를 기존의 UI 렌더링 방식인 React API 방식으로 변환할 수 있다.</p>
<h3 id="props">Props</h3>
<p>Properties.
부모 컴포넌트에서 자녀 컴포넌트로 데이터를 전달하는 방법.
자녀 컴포넌트에서는 값을 변경할 수 없고 부모 컴포넌트에서 state를 변경하므로써 가능하다.</p>
<h3 id="state">State</h3>
<p>State는 데이터를 포함하는 객체이며, 데이터에 변화가 있을 때 화면이 다시 렌더링 된다.
State는 컴포넌트 내에서 관리된다.</p>
<p>자녀 컴포넌트로 데이터를 보내는 props와 달리 state는 해당 컴포넌트 내부에서 데이터를 넘겨줄 때 사용되며 값의 변경이 가능하다.</p>
<h1 id="part-9">Part 9</h1>
<h2 id="redux">Redux</h2>
<p>State 관리를 도와주는 라이브러리.
리덕스 데이터 흐름은 일방향이다. action -&gt; reducer -&gt; redux store.</p>
<p>Action: 자바스크립트 객체. 어떤 작업을 수행하는지 유형을 지정하는 <strong>type</strong> 속성이 있으며 <strong>payload</strong> 속성을 통해 일부 데이터를 저장소에 보낼 수 있다.
Reducer: state의 변경 사항을 결정하고 변경된 state를 반환하는 함수.
Redux store: action을 통해 저장소의 데이터 state을 변경할 수 있다.</p>
<h3 id="redux-provider">Redux Provider</h3>
<p>Provider 컴포넌트는 하위 컴포넌트들에서 store에 접근하게 할 수 있는 컴포넌트이다.
보통 앱의 최상위 수준에서 이 컴포넌트를 렌더링한다.</p>
<h4 id="useselector-usedispatch">useSelector, useDispatch</h4>
<p><strong>Provider</strong>로 둘러쌓인 곳에서 store에 접근하는 방법.</p>
<p>useSelector: 값을 가져오는 훅
useDispatch: action을 보내는 훅</p>
<h3 id="redux-middleware">Redux middleware</h3>
<p>리덕스의 데이터 흐름에서 reducer에 도달하기 전에 위치하는 중간자이다.
주로 로깅, 충돌 보고, 비동기 API와의 통신 등에 사용된다.</p>
<h3 id="redux-thunk">Redux thunk</h3>
<p>리덕스를 사용하는 앱에서 비동기 작업을 처리할 때 주로 사용된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[02 Modules & NPM]]></title>
            <link>https://velog.io/@_coyg_/02-Modules-NPM</link>
            <guid>https://velog.io/@_coyg_/02-Modules-NPM</guid>
            <pubDate>Mon, 22 Jan 2024 15:15:47 GMT</pubDate>
            <description><![CDATA[<h1 id="modules">Modules</h1>
<p>필요한 함수들의 집합.</p>
<h2 id="core-modules">Core modules</h2>
<p>http, url, querystring, path, fs, util 등 기본적으로 Node.js에서 제공되는 모듈들.</p>
<h2 id="local-modules">Local modules</h2>
<p>필요에 따라 직접 생성하는 모듈.</p>
<pre><code class="language-javascript">const log = {
  info: function (info) {
    console.log(&quot;Info &quot; + info);
  },
  warning: function (warning) {
    console.log(&quot;Warning &quot; + warning);
  },
  error: function (error) {
    console.log(&quot;Error &quot; + error);
  },
};

module.exports = log;</code></pre>
<p>이런 식으로 모듈을 생성할 수 있고, 다른 파일에서 위 객체를 불러오고 싶을 때 <code>const module = require(&quot;./log.js&quot;);</code> 처럼 불러올 수 있다.</p>
<h3 id="모듈의-장점">모듈의 장점</h3>
<ol>
<li>재사용성 - 반복되는 함수들을 모듈화하여 편하게 관리할 수 있다.</li>
<li>관계성 - 관련 있는 변수/함수끼리 모듈로 묶어서 관리할 수 있다.</li>
<li>캡슐화 - 보안 상 필요한 정보(변수/함수)만 가져와서 쓸 수 있다.</li>
</ol>
<h3 id="exports">exports</h3>
<pre><code class="language-javascript">module.exports = log;
module.exports.A = 1;
module.exports.encrypt = function encrypt(data) { return &quot;data&quot;; }
exports.encrypt = function encrypt(data) { return &quot;data&quot;; }</code></pre>
<p>하지만 맨 아래에서 모듈을 exports 하는 것이 가장 좋다.</p>
<h2 id="commonjs-vs-ecmascriopt">CommonJS vs ECMAScriopt</h2>
<h3 id="commonjs-module">CommonJS module</h3>
<p>Node.js의 기본 모듈로 사용된다.
<code>module.exports</code>-<code>require</code></p>
<h3 id="ecmascript-module">ECMAScript module</h3>
<p>CommonJS와 다른 문법을 사용한다.
<code>export</code>-<code>import</code></p>
<p>ES 모듈은 자바스크립트의 표준이고 CommonJS는 Node.js의 기본값이다.</p>
<p>ES 모듈을 사용하려면 파일 확장자를 mjs로 바꿔줘야 한다.</p>
<h2 id="indexjs">index.js?</h2>
<p>모듈을 불러오는 과정에서 관련 있는 모듈을 한 디렉토리 안에 넣어놓고 그 디렉토리의 index.js 파일에서 모든 모듈을 묶어서 내보내는 경우가 많은데, 이는 모듈 로딩 시스템을 복잡하게 할 수 있기 때문에 index.js를 활용하여 모듈을 묶어서 내보내는 것은 지양해야 한다고 한다.</p>
<h1 id="npm-node-package-manager">NPM (Node Package Manager)</h1>
<ol>
<li>오픈 소스 Node.js 프로젝트 게시를 위한 온라인 리포지토리.</li>
<li>패키치 설치, 버전 관리 및 종속성 관리를 지원하는 해당 저장소와 상호작용하기 위한 cli 유틸리티.</li>
</ol>
<p><code>npm init -y</code> 명령어를 입력하면 프로젝트가 생성되고 package.json 파일이 생성된다.
<code>npm install [package_name]</code> 명령어는 원하는 패키지를 설치한다.</p>
<p>install을 통해 패키지를 설치하면 프로젝트의 루트 디렉토리에 node_modules 디렉토리가 생긴다. 여기에는 앞서 설치한 패키지(모듈)와 그 패키지(모듈)가 의존하고 있는 모든 모듈이 포함되어있다.</p>
<p>예를 들어 <code>axios</code> 모듈을 설치했다면 <code>axios</code>가 의존하는 모든 모듈이 설치가 되는 것이다.
<code>axios</code>는 <code>follow-redirects</code>, <code>form-data</code>, <code>proxy-from-env</code>에 의존하고, 이 세 가지 모듈도 의존하는 모듈이 있다면 전부 node_modules 디렉토리에 설치된다.</p>
<h2 id="semantic-versioning">Semantic versioning</h2>
<p>package.json 파일을 보면 dependencies에서 설치된 모듈을 확인할 수 있는데, 모듈마다 3개의 숫자(n.n.n)로 이루어진 버전이 있다.</p>
<p>예시)</p>
<pre><code class="language-json">&quot;follow-redirects&quot;: &quot;^1.15.0</code></pre>
<p>1(MAJOR).15(MINOR).0(PATCH)</p>
<p>MAJOR - 호환되지 않는 API 변경 시 (이전 버전과 호환 x)
MINOR - 이전 버전과 호환 가능; 기능 추가
PATCH - 이전 버전과 호환 가능; 버그 수정</p>
<p>앞에 붙는 기호:
<del>(틸드): PATCH 까지만 설치/업데이트 (</del>1.0.5는 1.0.5 ~ 1.1 범위 내에서 설치/업데이트)
^(캐럿): MINOR 까지만 설치/업데이트 (^1.0.5는 1.0.5 ~ 2.0 범위 내에서 설치/업데이트) (예외: 1.0.0 미만의 경우 지정한 버전 자릿수 내에서 업데이트)</p>
<h2 id="package-lockjson">package-lock.json</h2>
<p>여러 명이서 작업을 할 때에 캐럿이나 틸드로 버전을 표시하면 패키지를 설치/업데이트한 시점에 따라 버전이 다 다를 수 있는데, package-lock.json 파일은 현 시점 기준 정확한 버전 정보를 담고 있다. 따라서 버전 충돌을 해결할 수 있다.</p>
<h2 id="npm-audit">npm audit</h2>
<p>현재 프로젝트에 구성된 종속성에 대한 설명을 기본 레지스트리에 제출하고 알려진 취약성에 대한 보고서를 요청한다.
어떤 모듈에서 어떤 취약점이 발생했는 지 알려준다. fix 인수가 제공되면 수정사항이 패키지 트리에 적용된다.</p>
<h2 id="npm-install--g">npm install -g</h2>
<p>위 명령어로 패키지를 설치하면 현재 프로젝트에만 설치되는 것이 아닌 로컬(컴퓨터) 환경의 전역에 설치가 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Programming Language, Scripting Language]]></title>
            <link>https://velog.io/@_coyg_/Programming-Language-Scripting-Language</link>
            <guid>https://velog.io/@_coyg_/Programming-Language-Scripting-Language</guid>
            <pubDate>Tue, 01 Aug 2023 03:33:06 GMT</pubDate>
            <description><![CDATA[<h1 id="programming-language">Programming Language</h1>
<ul>
<li>컴퓨터와 소통하기 위한 명령어의 집합으로 이루어진 컴퓨터 언어.</li>
<li>대부분의 프로그래밍 언어는 컴파일 과정을 거침.</li>
<li>컴파일 시 실행파일이 생기고 바로 실행 가능.</li>
<li>컴파일 과정 때문에 시간이 조금 걸림.</li>
<li>소스 코드 전체를 기계어로 변환 후 실행 파일을 생성하는 방식.</li>
<li>컴파일 시 오류를 미리 확인할 수 있어서 실행 시 발생할 수 있는 오류를 줄일 수 있음.</li>
</ul>
<h1 id="scripting-language">Scripting Language</h1>
<ul>
<li>런타임 환경을 위한 프로그래밍 언어.</li>
<li>소스 코드 전체가 아닌 한 줄씩 읽어서 즉시 실행하는 방식.</li>
<li>컴파일 단계가 없어서 빠르게 프로그램을 작성하고 실행할 수 있음.</li>
<li>실행 시에 오류가 발견되며 디버깅/테스트가 비교적 간단함.</li>
<li>문법이 쉬우며 운영체제 상관 없이 사용 가능.</li>
</ul>
<p><a href="https://www.interviewbit.com/blog/scripting-language-vs-programming-language/">Scripting Language Vs Programming Language: What&#39;s The Difference?</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Web Server, Web Application Server]]></title>
            <link>https://velog.io/@_coyg_/Web-Server-Web-Application-Server</link>
            <guid>https://velog.io/@_coyg_/Web-Server-Web-Application-Server</guid>
            <pubDate>Tue, 01 Aug 2023 03:01:25 GMT</pubDate>
            <description><![CDATA[<h1 id="web-server">Web Server</h1>
<ul>
<li>클라이언트로부터 HTTP 요청을 받아 정적인 컨텐츠(HTML, CSS, JPEG)를 제공한다.</li>
<li>동적인 컨텐츠를 처리하기보다는 <strong>정적인 컨텐츠를 빠르게 전달</strong>하는 게 주 목적이다.</li>
<li>클라이언트로부터 동적 컨텐츠를 요청받았다면 요청을 WAS에 보내고, WAS에서 처리한 결과를 받아 클라이언트에게 제공한다.</li>
</ul>
<h1 id="web-application-server">Web Application Server</h1>
<ul>
<li>aka 웹 컨테이너, 서블릿 컨테이너</li>
<li>클라이언트로부터 HTTP 요청을 받아 처리하고, 동적인 웹 페이지를 생성하여 클라이언트에게 제공한다.</li>
<li><strong>동적인 데이터 위주</strong>로 처리한다.</li>
<li><strong>DB와 상호작용</strong>이 필요한 경우 사용한다.</li>
<li>WAS도 웹 서버의 역할인 정적 컨텐츠 처리가 가능하지만 별도의 웹 서버 없이 WAS만 사용한다면 서버에 부하가 걸리고 성능이 저하될 수 있기 때문에 웹 서버+WAS를 사용하는 것이 좋다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Closure]]></title>
            <link>https://velog.io/@_coyg_/Closure</link>
            <guid>https://velog.io/@_coyg_/Closure</guid>
            <pubDate>Wed, 26 Jul 2023 04:02:05 GMT</pubDate>
            <description><![CDATA[<h1 id="closure">Closure</h1>
<ul>
<li>클로저는 함수가 선언될 때 자신의 주변 환경(Lexical Environment)을 기억하여, 함수 내부에서 자유 변수(free variables)에 접근할 수 있게 해주는 기능.</li>
</ul>
<pre><code class="language-javascript">function outerFunction() {
  const outerVariable = &quot;I am from the outer function.&quot;;

  function innerFunction() {
    console.log(outerVariable); // outerFunction의 자유 변수에 접근
  }

  return innerFunction;
}

const closureFunction = outerFunction();
closureFunction(); // &quot;I am from the outer function.&quot; 출력</code></pre>
<h2 id="lexical-environment">Lexical Environment</h2>
<ul>
<li>스코프와 변수 식별자(identifier)를 관리하는 데 사용되는 내부 데이터 구조.</li>
<li>함수/변수가 선언되는 위치에 따라 Lexical Environment가 형성되고, 해당 스코프에서 접근 가능한 변수와 함수들의 정보를 담고 있음.</li>
<li>각 함수/블록이 실행될 때 자신의 Lexical Environment를 생성함. LE는 식별자, 해당 값, 외부 스코프에 대한 참조 등을 포함.</li>
<li>LE는 또한 스코프 체인을 형성하는 데 사용됨.</li>
<li>스코프 체인: 변수를 찾을 때 현재 실행 중인 컨텍스트부터 외부 스코프를 순차적으로 탐색하는 메커니즘.</li>
</ul>
<h3 id="예시">예시)</h3>
<ul>
<li>위의 코드에서 outerFunction 내부에서 innerFunction 호출.</li>
<li>innerFunction에서 사용되는 outerVariable은 외부 함수인 outerFunction의 LE에 있음.</li>
<li>이는 스코프 체인을 통해 innerFunction이 outerFunction의 LE에 접근하여 외부 변수에 접근할 수 있기 때문.</li>
</ul>
<h2 id="free-variable">Free Variable</h2>
<ul>
<li>함수 내에서 사용되지만 해당 함수 내에서 정의되지 않은 변수.</li>
<li>외부 스코프에서 탐색되는 변수.</li>
<li>위의 코드에서 outerVariable이 자유 변수. </li>
<li>클로저를 이용하여 innerFunction이 outerFunction의 환경을 기억하고 있기 때문에 innerFunction이 호출될 때 outerVariable에 접근할 수 있는 것.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Promise, async/await]]></title>
            <link>https://velog.io/@_coyg_/Promise-asyncawait</link>
            <guid>https://velog.io/@_coyg_/Promise-asyncawait</guid>
            <pubDate>Wed, 26 Jul 2023 03:48:08 GMT</pubDate>
            <description><![CDATA[<h1 id="promise">Promise</h1>
<ul>
<li>ES6에서 도입된 비동기 처리에 사용되는 객체.</li>
<li>전통적인 콜백 패턴이 가진 단점(콜백지옥, 오류처리)을 보완하며 비동기 처리 시점을 명확하게 표현할 수 있다는 장점이 있음.</li>
</ul>
<h2 id="promise의-4가지-상태">Promise의 4가지 상태</h2>
<ol>
<li>pending: 비동기 처리가 아직 수행되지 않은 상태 (resolve/reject가 아직 호출되지 않은 상태)</li>
<li>fulfilled: 비동기 처리가 수행된 상태 (성공) (resolve가 호출된 상태)</li>
<li>rejected: 비동기 처리가 수행된 상태 (실패) (reject가 호출된 상태)</li>
<li>settled: fulfilled | rejected</li>
</ol>
<h2 id="사용법">사용법</h2>
<pre><code class="language-javascript">// 예시)
// resolve와 reject를 둘 다 호출하는 Promise 예시
1  function fetchData(condition) {
2    return new Promise((resolve, reject) =&gt; {
3      setTimeout(() =&gt; {
4        if (condition) {
5          const data = &quot;Fetched data from server&quot;;
6          // 성공적으로 완료될 때 resolve를 호출하여 결과 값을 전달
7          resolve(data);
8        } else {
9          // 실패할 때 reject를 호출하여 에러를 전달
10         reject(new Error(&quot;Failed to fetch data from server&quot;));
11       }
12     }, 2000);
13   });
14 }
15
16 // Promise 사용 예시
17 fetchData(true)
18   .then((result) =&gt; {
19     console.log(result); // &quot;Fetched data from server&quot; (2초 후에 출력)
20   })
21   .catch((error) =&gt; {
22     console.error(error); // 실패할 경우, Error 객체 출력 (조건에 따라 출력 여부 달라짐)
23   });</code></pre>
<ul>
<li>성공 시:<ul>
<li>2초 뒤에 resolve(data)가 호출되는데, 이 data는 18번째 줄에서 then에서 받을 수 있다.</li>
<li>결과적으로 2초 뒤에 &quot;Fetched data from server&quot;가 출력된다.</li>
</ul>
</li>
<li>실패 시:<ul>
<li>2초 뒤에 reject(new Error())가 호출된다. 이 에러객체는 21번째 줄의 catch에서 받을 수 있다.</li>
<li>결과적으로 &quot;Failed to fetch data from server&quot; 오류 객체가 출력된다.</li>
</ul>
</li>
</ul>
<h3 id="then-catch">then, catch</h3>
<h4 id="then">then</h4>
<ul>
<li>then 메소드는 두 개의 콜백 함수를 인자로 전달 받음: 1) 성공 시 호출 함수, 2) 실패 시 호출 함수.<pre><code class="language-javascript">promiseAjax(wrongUrl)
.then(res =&gt; console.log(res), err =&gt; console.error(err)); // Error: 404</code></pre>
</li>
<li>Promise를 반환한다.</li>
<li>하지만 then 메소드에 두 번째 콜백 함수를 전달하면 첫 번째 콜백 함수에서 발생한 에러를 캐치하지도 못하고 코드가 복잡해지기 때문에 catch를 사용하는게 훨씬 낫다.<h4 id="catch">catch</h4>
</li>
<li>catch 메소드는 비동기 처리에서 혹은 then 메소드에서 에러가 발생하면 호출된다.</li>
<li>Promise를 반환한다.<pre><code class="language-javascript">promiseAjax(wrongUrl)
.then(res =&gt; console.log(res))
.catch(err =&gt; console.error(err)); // Error: 404</code></pre>
</li>
<li>위처럼 catch 메소드를 호출하면 내부적으로 <code>then(undefined, onRejected)</code>을 호출한다.<pre><code class="language-javascript">promiseAjax(wrongUrl)
.then(res =&gt; console.log(res))
.then(undefined, err =&gt; console.error(err)); // Error: 404</code></pre>
</li>
</ul>
<h2 id="프로미스-체이닝">프로미스 체이닝</h2>
<ul>
<li>여러 개의 비동기 작업을 순차적으로 연결하여 처리.</li>
<li>then 메소드를 통해 연결되어 결과 전달 혹은 다음 비동기 작업 실행.</li>
</ul>
<pre><code class="language-javascript">function fetchData(condition) {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      if (condition) {
        const data = &quot;Fetched data from server&quot;;
        resolve(data);
      } else {
        reject(new Error(&quot;Failed to fetch data from server&quot;));
      }
    }, 2000);
  });
}

fetchData(true)
  .then((result1) =&gt; {
    console.log(result1);
    return fetchData(false);
  })
  .then((result2) =&gt; {
    console.log(result2);
  })
  .catch((error) =&gt; {
    console.error(error);
  });</code></pre>
<ul>
<li>then이 연속으로 두 번 쓰이는데, 첫 번째 then 메소드에서 fetchData(false)가 반환되었기 때문에 두 번째 then 메소드는 실행되지 않음.</li>
</ul>
<h2 id="프로미스의-정적-메소드">프로미스의 정적 메소드</h2>
<h3 id="promiseresolve--promisereject">Promise.resolve / Promise.reject</h3>
<ul>
<li>존재하는 값을 Promise로 래핑하기 위해 사용.</li>
</ul>
<pre><code class="language-javascript">const resolvedPromise = Promise.resolve([1, 2, 3]);
resolvedPromise.then(console.log); // [ 1, 2, 3 ]

const rejectedPromise = Promise.reject(new Error(&#39;Error!&#39;));
rejectedPromise.catch(console.log); // Error: Error!

// above are same as below:

const resolvedPromise = new Promise(resolve =&gt; resolve([1, 2, 3]));
resolvedPromise.then(console.log); // [ 1, 2, 3 ]

const rejectedPromise = new Promise((resolve, reject) =&gt; reject(new Error(&#39;Error!&#39;)));
rejectedPromise.catch(console.log); // Error: Error!</code></pre>
<h3 id="promiseall">Promise.all</h3>
<ul>
<li>프로미스가 담겨 있는 배열 등의 이터러블을 인자로 전달 받은 뒤 모든 프로미스를 병렬로 처리한 후 그 처리 결과를 resolve하는 새로운 프로미스를 반환.</li>
<li>모든 프로미스의 처리가 종료될 때까지 기다린 후 모든 처리 결과를 resolve/reject 한다.</li>
<li>resolve: 각각의 프로미스가 resolve한 처리 결과를 배열에 담아 resolve하는 새로운 프로미스를 반환한다. 처리 순서가 보장된다 (첫 번째 프로미스가 가장 나중에 처리되더라도 배열에는 첫 번째 요소로 담긴다)</li>
<li>reject: 가장 먼저 실패한 프로미스가 reject한 에러를 reject하는 새로운 프로미스가 반환된다.</li>
</ul>
<pre><code class="language-javascript">Promise.all([
  new Promise(resolve =&gt; setTimeout(() =&gt; resolve(1), 3000)), // 1
  new Promise(resolve =&gt; setTimeout(() =&gt; resolve(2), 2000)), // 2
  new Promise(resolve =&gt; setTimeout(() =&gt; resolve(3), 1000))  // 3
]).then(console.log) // [ 1, 2, 3 ]
  .catch(console.log);</code></pre>
<p>첫 번째 프로미스: 3초 후에 1을 resolve하여 처리 결과 반환
두 번째 프로미스: 2초 후에 2를 resolve하여 처리 결과 반환
세 번째 프로미스: 1초 후에 3을 resolve하여 처리 결과 반환</p>
<p>즉, 3초 후에 [1, 2, 3]이 출력된다.</p>
<h3 id="promiserace">Promise.race</h3>
<ul>
<li>Promise.all과 비슷하지만 가장 먼저 처리된 프로미스가 resolve한 처리 결과를 resolve하는 새로운 프로미스를 반환한다.</li>
<li>reject는 Promise.all과 동일하다.</li>
</ul>
<h1 id="asyncawait">async/await</h1>
<ul>
<li>ES8에서 도입된 비동기 처리를 구현할 수 있는 키워드.</li>
<li>async 키워드를 함수의 앞에 붙이면 해당 함수는 항상 Promise를 반환.</li>
<li>await 키워드를 사용하여 Promise가 처리될 때까지 기다리는 것처럼 작성 가능.</li>
</ul>
<pre><code class="language-javascript">function fetchData(condition) {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      if (condition) {
        const data = &quot;Fetched data from server&quot;;
        resolve(data);
      }
      else {
        reject(new Error(&quot;Something went wrong&quot;));
      }
    }, 2000);
  });
}

async function fetchDataAsync() {
  try {
    const result = await fetchData(false);
    console.log(result);
  } catch (error) {
    console.error(error);
  }
}

fetchDataAsync();</code></pre>
<ul>
<li>await: fetchData 함수가 Promise가 처리될 때까지 기다렸다가 결과 값을 반환하게 함</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[개발 방법론]]></title>
            <link>https://velog.io/@_coyg_/%EA%B0%9C%EB%B0%9C-%EB%B0%A9%EB%B2%95%EB%A1%A0</link>
            <guid>https://velog.io/@_coyg_/%EA%B0%9C%EB%B0%9C-%EB%B0%A9%EB%B2%95%EB%A1%A0</guid>
            <pubDate>Tue, 25 Jul 2023 04:55:58 GMT</pubDate>
            <description><![CDATA[<h1 id="개발-방법론">개발 방법론?</h1>
<ul>
<li><p>소프트웨어 또는 기타 제품의 개발을 관리하기 위한 구조적, 체계적 접근 방식.</p>
</li>
<li><p>팀이 효과적/효율적으로 고품질 소프트웨어를 개발하기 위한 가이드라인, 사례 및 프로세스를 제공함.</p>
</li>
<li><p>시작부터 배포까지 개발 싸이클을 구성/계획/실행하는 데에 사용됨.</p>
</li>
<li><p>고유의 규칙, 사례, 특성 등을 가진 다양한 방법론이 존재함.</p>
</li>
</ul>
<h2 id="주요-소프트웨어-개발-방법론">주요 소프트웨어 개발 방법론</h2>
<ol>
<li><a href="https://www.tutorialspoint.com/sdlc/sdlc_waterfall_model.htm">Waterfall Model</a>: 선형-순차 수명 주기 모델.<ul>
<li>각 단계는 다음 단계가 시작되기 전에 완료되어야 하며 단계가 겹치지 않음.
<img src="https://velog.velcdn.com/images/_coyg_/post/d6dde4d9-085b-4f09-97ff-23416dcc4570/image.png" alt=""></li>
</ul>
</li>
<li><a href="https://www.tutorialspoint.com/sdlc/sdlc_agile_model.htm">Agile Model</a>: 반복적, 증분적 프로세스 모델.<ul>
<li>작은 이터레이션/스프린트를 통해 빠르게 프로토타입을 만들고 지속적인 개선을 추구함.
<img src="https://velog.velcdn.com/images/_coyg_/post/d71b07ad-8974-4bf0-8e12-0e5eed77962d/image.png" alt=""></li>
</ul>
</li>
<li><a href="https://www.tutorialspoint.com/sdlc/sdlc_spiral_model.htm">Spiral Model</a>: 반복 개발 프로세스 모델과 선형-순차 개발 모델의 조합. 위험 분석에 중점을 둠.<ul>
<li>단계마다 보다 신중한 위험 분석을 수행함.
<img src="https://velog.velcdn.com/images/_coyg_/post/65e0b821-75b7-48a3-bebf-95a03d7f0c92/image.png" alt=""></li>
</ul>
</li>
<li><a href="https://www.tutorialspoint.com/sdlc/sdlc_iterative_model.htm">Iterative Model</a>: 작은 소프트웨어 요구사항 세트의 간단한 구현으로 시작하여 전체 시스템이 구현되고 배포할 준비가 될 때까지 진화하는 버전을 반복적으로 향상시킴.<ul>
<li>애자일 모델과 다르게 각 단계는 폭포수 모델 방식으로 진행됨.
<img src="https://velog.velcdn.com/images/_coyg_/post/7b4173c3-5437-4ca5-bb24-0e0d8ae1df5b/image.png" alt=""></li>
</ul>
</li>
<li><a href="https://www.techtarget.com/searchsoftwarequality/definition/lean-programming">Lean Software Development</a>: 애자일 프레임워크 기반으로 효율성의 최적화, 낭비의 최소화를 강조하는 모델.<ul>
<li><a href="https://www.productplan.com/glossary/lean-software-development/">Lean Software Development</a></li>
</ul>
</li>
<li><a href="https://about.gitlab.com/topics/devops/">DevOps</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 보안 취약점]]></title>
            <link>https://velog.io/@_coyg_/Node.js-%EB%B3%B4%EC%95%88-%EC%B7%A8%EC%95%BD%EC%A0%90</link>
            <guid>https://velog.io/@_coyg_/Node.js-%EB%B3%B4%EC%95%88-%EC%B7%A8%EC%95%BD%EC%A0%90</guid>
            <pubDate>Tue, 25 Jul 2023 04:00:32 GMT</pubDate>
            <description><![CDATA[<h1 id="injection-attacks">Injection Attacks</h1>
<ul>
<li>공격자가 취약 애플리케이션에 악성 코드를 작성하고 애플리케이션이 이를 실행했을 때 발생함.</li>
</ul>
<h2 id="종류">종류</h2>
<ul>
<li>SQL injection</li>
<li>NoSQL injection</li>
<li>Command injection</li>
</ul>
<h2 id="문제">문제</h2>
<pre><code class="language-javascript">// SQL injection attack의 예시
const express = require(&quot;express&quot;);
const app = express();
const mysql = require(&quot;mysql&quot;);

const connection = mysql.createConnection({
  host: &quot;localhost&quot;,
  user: &quot;root&quot;,
  password: &quot;password&quot;,
  database: &quot;test&quot;,
});

app.get(&quot;/user&quot;, (req, res) =&gt; {
  const id = req.query.id;
  const query = `SELECT * FROM users WHERE id = ${id}`;
  connection.query(query, (error, results) =&gt; {
    if (error) {
      throw error;
    }
    res.send(results);
  });
});

app.listen(3000, () =&gt; {
  console.log(&quot;Example app listening on port 3000!&quot;);
});</code></pre>
<ul>
<li>req로 받은 id가 SQL 쿼리에 바로 사용이 되는데 이 때 id값으로 1 혹은 1=1 등을 주게 된다면 users 테이블의 모든 레코드를 가져오게 된다.</li>
</ul>
<h2 id="해결방법">해결방법</h2>
<pre><code class="language-javascript">app.get(&quot;/user&quot;, (req, res) =&gt; {
  const id = req.query.id;
  const query = &quot;SELECT * FROM users WHERE id = ?&quot;;
  connection.query(query, [id], (error, results) =&gt; {
    if (error) {
      throw error;
    }
    res.send(results);
  });
});

app.listen(3000, () =&gt; {
  console.log(&quot;Example app listening on port 3000!&quot;);
});</code></pre>
<ul>
<li>SQL injection 공격을 방지하기 위해서는 req로 받은 id를 쿼리에 바로 사용하는 것이 아니라 <strong><a href="https://iksflow.tistory.com/127">prepared statement</a></strong>를 사용하여 id를 쿼리에 바인딩하는 방법이 있다.</li>
</ul>
<h1 id="cross-site-scriptingxss">Cross-Site Scripting(XSS)</h1>
<ul>
<li><p>다른 사용자들이 보는 웹페이지에 악성 스크립트를 삽입하는 것.</p>
</li>
<li><p>이러한 공격으로 인해 민감한 데이터(login credentials 등)가 도난당할 수 있음. </p>
</li>
</ul>
<h2 id="문제-1">문제</h2>
<pre><code class="language-javascript">// XSS attack의 예시
const express = require(&quot;express&quot;);
const app = express();

app.get(&quot;/&quot;, (req, res) =&gt; {
  const name = req.query.name;
  res.send(`&lt;h1&gt;Hello, ${name}&lt;/h1&gt;`);
});

app.listen(3000, () =&gt; {
  console.log(&quot;Example app listening on port 3000!&quot;);
});</code></pre>
<ul>
<li>name이 HTML response에 직접적으로 포함이 되어있는데, name에 <code>&lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;</code>라는 값을 넘겼을 때 이는 악성 스크립트가 된다. </li>
</ul>
<h2 id="해결방법-1">해결방법</h2>
<ul>
<li>이러한 취약점을 방지하기 위해서는 escape-html 등의 라이브러리를 사용하면 된다.<pre><code class="language-javascript">const express = require(&quot;express&quot;);
const app = express();
const escapeHtml = require(&quot;escape-html&quot;);
</code></pre>
</li>
</ul>
<p>app.get(&quot;/&quot;, (req, res) =&gt; {
  const name = escapeHtml(req.query.name);
  res.send(<code>&lt;h1&gt;Hello, ${name}&lt;/h1&gt;</code>);
});</p>
<p>app.listen(3000, () =&gt; {
  console.log(&quot;Example app listening on port 3000!&quot;);
});</p>
<pre><code># Denial-of-Service(DoS)
* 서버에 과부하를 주어서 마비시키는 것.
  * 서버에 많은 요청을 보내거나
  * 서버에 데이터를 플러딩하는 등 다양한 방법을 통해 공격할 수 있음

* 이를 방지하기 위해서는 속도 제한을 구현하고, 적절한 오류 처리를 사용하고, 강력한 인프라를 구축해야 한다.

## 문제
```javascript
const express = require(&quot;express&quot;);
const app = express();

app.get(&quot;/&quot;, (req, res) =&gt; {
  // Do a resource-intensive operation
  while (true) {}
});

app.listen(3000, () =&gt; {
  console.log(&quot;Example app listening on port 3000!&quot;);
});</code></pre><ul>
<li>들어온 요청들에 대해 적절한 처리가 되어있지 않음 </li>
<li>대량의 요청이 들어온다면 무한 루프 때문에 마비가 될 것</li>
</ul>
<h2 id="해결방법-2">해결방법</h2>
<ul>
<li>들어온 요청에 대한 적절한 검증 및 처리</li>
<li>요청이 처리할 수 있는 자원의 제한</li>
</ul>
<pre><code class="language-javascript">const express = require(&quot;express&quot;);
const app = express();
const rateLimit = require(&quot;express-rate-limit&quot;);

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests per windowMs
  message: &quot;Too many requests, please try again later&quot;,
});

app.use(limiter);

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

app.listen(3000, () =&gt; {
  console.log(&quot;Example app listening on port 3000!&quot;);
});</code></pre>
<ul>
<li>express-rate-limit 패키지를 활용하여 최대 요청 수를 제한하는 미들웨어를 사용할 수 있다.</li>
</ul>
<h1 id="improper-authentication-and-authorization">Improper Authentication and Authorization</h1>
<ul>
<li><p>부적절한 인증 및 권한 부여로 인해 민감한 데이터에 대한 무단 액세스가 발생하여 도난이나 손상이 발생할 수 있음</p>
</li>
<li><p>이를 방지하기 위해 적절한 인증 및 권한 부여 방법을 구현해야 함</p>
<ul>
<li>보안 암호 사용</li>
<li>이중 인증 사용</li>
</ul>
</li>
</ul>
<h2 id="문제-2">문제</h2>
<pre><code class="language-javascript">const express = require(&quot;express&quot;);
const app = express();

app.get(&quot;/secret&quot;, (req, res) =&gt; {
  res.send(&quot;This is a secret page!&quot;);
});

app.listen(3000, () =&gt; {
  console.log(&quot;Example app listening on port 3000!&quot;);
});</code></pre>
<ul>
<li>/secret 엔드포인트는 보안이 적용되어있지 않아서 이 경로를 아는 누구나 접근할 수 있음</li>
</ul>
<h2 id="해결방법-3">해결방법</h2>
<ul>
<li>적절한 인증 메커니즘 구현<pre><code class="language-javascript">const express = require(&quot;express&quot;);
const app = express();
</code></pre>
</li>
</ul>
<p>const checkAuth = (req, res, next) =&gt; {
  if (!req.session.user) {
    return res.status(401).send(&quot;Unauthorized&quot;);
  }
  next();
};</p>
<p>app.get(&quot;/secret&quot;, checkAuth, (req, res) =&gt; {
  res.send(&quot;This is a secret page!&quot;);
});</p>
<p>app.listen(3000, () =&gt; {
  console.log(&quot;Example app listening on port 3000!&quot;);
});</p>
<pre><code>* checkAuth 미들웨어를 사용함으로써 /secret 엔드포인트에 접근하기 전 사용자의 인증정보를 확인한다.

# Insecure Direct Object References
* 안전하지 않은 직접 개체 참조에서 공격자는 의도된 보안 제어를 우회하여 개체에 직접 접근 및 조작을 할 수 있음

## 문제
```javascript
const express = require(&quot;express&quot;);
const app = express();

const users = [
  { id: 1, name: &quot;John Doe&quot; },
  { id: 2, name: &quot;Jane Doe&quot; },
];

app.get(&quot;/user/:id&quot;, function (req, res) {
  let user = users.find((user) =&gt; user.id == req.params.id);

  if (!user) {
    res.status(404).send(&quot;User not found&quot;);
    return;
  }

  res.send(user);
});

app.listen(3000);</code></pre><ul>
<li>users 배열에서 params로 받은 id값에 해당하는 user 정보를 추출하는데 이 때, id로 주는 값에 따라 남의 정보 또한 추출할 수 있음.</li>
</ul>
<h2 id="해결방법-4">해결방법</h2>
<ul>
<li>위의 공격과 마찬가지로 현재 사용자가 접근 권한이 있는 사용자인지 체크하는 미들웨어를 사용하여 남의 정보에 접근하는 것을 방지할 수 있음.</li>
</ul>
<p><a href="https://blog.javascripttoday.com/blog/node-js-server-vulnerabilities/">https://blog.javascripttoday.com/blog/node-js-server-vulnerabilities/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[동기 vs. 비동기]]></title>
            <link>https://velog.io/@_coyg_/%EB%8F%99%EA%B8%B0-vs.-%EB%B9%84%EB%8F%99%EA%B8%B0</link>
            <guid>https://velog.io/@_coyg_/%EB%8F%99%EA%B8%B0-vs.-%EB%B9%84%EB%8F%99%EA%B8%B0</guid>
            <pubDate>Thu, 20 Jul 2023 05:18:24 GMT</pubDate>
            <description><![CDATA[<h1 id="동기-vs-비동기">동기 vs. 비동기</h1>
<h2 id="동기적-코드-실행-방식">동기적 코드 실행 방식</h2>
<h3 id="특징">특징</h3>
<ul>
<li>작업이 순차적으로 진행됨</li>
<li>코드가 한 줄 실행되고 그 다음 줄이 실행되는 순서를 기준으로 작업이 처리됨.</li>
<li>현재 작업이 끝나야 다음 작업이 실행됨
<img src="https://velog.velcdn.com/images/_coyg_/post/f64e97b1-877a-4527-b6e4-bc5bd6aa73dc/image.png" alt=""></li>
</ul>
<p>예) 주문을 하면 음료를 받을 때까지 기다리는 방식 (뒷사람들 기다림)</p>
<pre><code class="language-javascript">console.log(&#39;First&#39;);
console.log(&#39;Second&#39;);
console.log(&#39;Third&#39;);

// OUTPUT
// First
// Second
// Third</code></pre>
<h3 id="장점">장점</h3>
<ul>
<li>순서/일관성 보장</li>
<li>간단하고 직관적인 구조</li>
<li>단순한 오류 처리</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>블로킹 현상</li>
<li>성능 저하</li>
<li>자원 낭비</li>
</ul>
<h2 id="비동기적-코드-실행-방식">비동기적 코드 실행 방식</h2>
<h3 id="특징-1">특징</h3>
<ul>
<li>작업이 순차적으로 진행되지 않고 여러 작업을 동시에 처리함</li>
<li>현재 작업을 기다리지 않고 다음 작업이 진행됨</li>
<li>비동기적 작업은 보통 이벤트 루프, 콜백 함수로 처리됨</li>
<li>주로 I/O 작업, 네트워크 요청 등 시간이 오래 걸리는 작업에 사용됨
<img src="https://velog.velcdn.com/images/_coyg_/post/5a616d28-bb73-42d4-8528-e462acbecf55/image.png" alt=""></li>
</ul>
<p>예) 주문을 하고 진동벨이 울리면 픽업하는 방식 (뒷사람들 기다림 x)</p>
<pre><code class="language-javascript">console.log(&#39;First&#39;);
// setTimeout: 비동기 함수
// 즉시 종료되며 실행 내용이 이벤트 루프로 들어감
// 이벤트 루프에 들어간 실행 내용은 2초 뒤에 실행됨
setTimeout(() =&gt; console.log(&#39;Second&#39;), 2000);
console.log(&#39;Third&#39;);

// OUTPUT
// First
// Third
// Second</code></pre>
<h3 id="장점-1">장점</h3>
<ul>
<li>응답성 향상: 블로킹 x -&gt; 작업이 완료되지 않아도 다른 작업 처리 가능</li>
<li>자원 효율: 블로킹 x -&gt; 대기 시간동안 다른 작업 처리 가능</li>
<li>병렬 처리: 블로킹 x -&gt; 동시에 여러 작업 처리 가능</li>
</ul>
<h3 id="단점-1">단점</h3>
<ul>
<li>코드 복잡성: 비동기 작업이 연속적으로 발생할 때 콜백 지옥 발생 가능</li>
<li>오류 처리: 콜백 함수 사용 시 오류 처리 복잡</li>
<li>디버깅: 순차적 x, 병렬적 o -&gt; 여러 비동기 작업 동시 실행 시 프로그램 상태 파악 어려움</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[REST API]]></title>
            <link>https://velog.io/@_coyg_/REST-API</link>
            <guid>https://velog.io/@_coyg_/REST-API</guid>
            <pubDate>Wed, 19 Jul 2023 04:43:24 GMT</pubDate>
            <description><![CDATA[<h1 id="api">API</h1>
<ul>
<li>Application Programming Interface<ul>
<li>소프트웨어 애플리케이션 간에 서로 소통하기 위한 규약/인터페이스.</li>
<li>소프트웨어 구성 요소 간의 상호작용을 도와주는 도구.</li>
<li>API를 통해 한 애플리케이션이 다른 애플리케이션의 기능과 데이터를 활용할 수 있음.</li>
</ul>
</li>
</ul>
<h1 id="rest">REST</h1>
<ul>
<li><strong>RE</strong>presentational <strong>S</strong>tate <strong>T</strong>ransfer<ul>
<li>웹 기반 애플리케이션에서 자주 사용되는 소프트웨어 아키텍처 스타일.</li>
</ul>
</li>
</ul>
<h1 id="restful-api">RESTful API</h1>
<ul>
<li>REST 원칙을 따르는 API.</li>
<li>네트워크 상에서 자원(데이터)을 표현/조작을 위한 표준화된 방법을 제공함.</li>
</ul>
<h2 id="특징">특징</h2>
<ol>
<li>Uniform Interface<ul>
<li>URI(Uniform Resource Identifier)로 지정한 자원에 대한 조작을 <strong>통일되고 한정적인 인터페이스</strong>로 수행하는 아키텍처 스타일.</li>
</ul>
</li>
<li>Stateless<ul>
<li>서버가 클라이언트의 상태를 유지하지 않음.</li>
<li>클라이언트의 각 요청은 서버에 대한 완전한 정보를 포함해야 하며, 서버는 이전 요청의 상태를 기억하지 않고(세션, 쿠키 저장 x) 독립적으로 처리함. </li>
<li>구현이 단순함.</li>
</ul>
</li>
<li>Cacheable<ul>
<li>HTTP를 사용하기 때문에 캐싱이 가능함.</li>
<li>Last-Modified 태그, E-Tag를 이용하여 캐싱을 구현할 수 있음.</li>
</ul>
</li>
<li>Self-descriptiveness<ul>
<li>REST API 메세지만 보고도 쉽게 이해할 수 있는 &#39;자체 표현 구조&#39;로 되어있음.</li>
</ul>
</li>
<li>Client-Server Structure<ul>
<li>클라이언트와 서버의 역할이 확실히 구분되기 때문에 각각에서의 개발해야 하는 내용이 명확해지고 서로간 의존성이 줄어듬.</li>
</ul>
</li>
<li>Layered Structure<ul>
<li>다중 계층으로 구성할 수 있으며 클라이언트와 서버 사이에 중간 계층을 추가하여 시스템의 유연성, 확장성을 향상시킬 수 있음.</li>
<li>보안, 로드 밸런싱, 캐싱, 인증 등 다양한 기능을 수행하는 중간 계층.</li>
</ul>
</li>
</ol>
<h2 id="rest-api-디자인-가이드">REST API 디자인 가이드</h2>
<ol>
<li>URI는 정보의 자원을 표현해야 한다.</li>
<li>자원에 대한 행위는 HTTP 메서드로 표현한다.</li>
</ol>
<h3 id="rest-api의-중심-규칙">REST API의 중심 규칙</h3>
<ol>
<li>URI는 정보의 자원을 표현해야 한다.<pre><code>좋은 예) GET /members/1
안좋은 예) GET /members/delete/1 (행위에 대한 표현 포함 x)</code></pre></li>
<li>자원에 대한 행위는 HTTP 메서드로 표현한다.<ul>
<li>POST: 자원 생성</li>
<li>GET: 자원 조회</li>
<li>PUT: 자원 수정</li>
<li>DELETE: 자원 삭제<pre><code>안좋은 예) GET /members/delete/1 (행위에 대한 표현 포함 x, 적절한 메서드 사용)
좋은 예) DELETE /members/1</code></pre></li>
</ul>
</li>
</ol>
<h3 id="uri-설계-시-주의할-점">URI 설계 시 주의할 점</h3>
<ol>
<li>&#39;/&#39;는 계층 관계를 나타내는 데 사용한다.</li>
<li>URI 마지막 문자로 &#39;/&#39;를 포함하지 않는다.<ul>
<li>혼동을 주지 않기 위해</li>
</ul>
</li>
<li>가독성을 높이기 위해 &#39;-&#39;를 사용한다.</li>
<li>밑줄(_)은 사용하지 않는다.</li>
<li>소문자만 사용한다.</li>
<li>파일 확장자는 포함시키지 않는다.</li>
</ol>
<h1 id="graphql">GraphQL</h1>
<ul>
<li>API를 위한 쿼리 언어이며 타입 시스템을 활용하여 쿼리를 실행하는 서버사이드 런타임.</li>
</ul>
<h2 id="rest와의-차이점">REST와의 차이점</h2>
<ol>
<li><p>하나의 엔드포인트(Root endpoint)를 가진다.</p>
<ul>
<li>하나의 엔드포인트를 사용하여 요청하는 쿼리에 따라 다른 응답을 반환하는 방식.</li>
<li>엔드포인트가 많을 경우 관리도 힘들고 많은 엔드포인트의 노출을 막기 위해 추가적인 처리가 필요할 수 있는데 GraphQL을 사용하여 이 문제들을 해결할 수 있다.<pre><code>// REST API
// 전체 반의 정보
example.com/class
// 1반의 정보
example.com/class/1
// 1반의 전체 학생 정보
example.com/class/1/students
// 1반의 1번 학생 정보
example.com/class/1/students/1
</code></pre></li>
</ul>
<p>// GraphQL
// 하나의 엔드포인트에 다른 쿼리를 사용해 요청
example.com/graphql
```</p>
</li>
<li><p>원하는 응답 값만 골라서 받아올 수 있다.</p>
<ul>
<li>쿼리를 작성하여 엔드포인트에서 원하는 데이터만 골라서 받아올 수 있다.<pre><code>// REST API
GET, https://swapi.dev/api/people/1
</code></pre></li>
</ul>
<p>// REST API response
{
  &quot;name&quot;: &quot;Luke Skywalker&quot;,
  &quot;height&quot;: &quot;172&quot;,
  &quot;mass&quot;: &quot;77&quot;,
  &quot;hair_color&quot;: &quot;blond&quot;,
  &quot;skin_color&quot;: &quot;fair&quot;,
  &quot;eye_color&quot;: &quot;blue&quot;,
  &quot;birth_year&quot;: &quot;19BBY&quot;,
  &quot;gender&quot;: &quot;male&quot;,
  &quot;homeworld&quot;: &quot;<a href="http://swapi.dev/api/planets/1/&quot;">http://swapi.dev/api/planets/1/&quot;</a>,
  &quot;films&quot;: [&quot;<a href="http://swapi.dev/api/films/1/&quot;">http://swapi.dev/api/films/1/&quot;</a>, &quot;<a href="http://swapi.dev/api/films/2/&quot;">http://swapi.dev/api/films/2/&quot;</a>, &quot;<a href="http://swapi.dev/api/films/3/&quot;">http://swapi.dev/api/films/3/&quot;</a>, &quot;<a href="http://swapi.dev/api/films/6/&quot;%5D">http://swapi.dev/api/films/6/&quot;]</a>,
  &quot;species&quot;: [],
  &quot;vehicles&quot;: [&quot;<a href="http://swapi.dev/api/vehicles/14/&quot;">http://swapi.dev/api/vehicles/14/&quot;</a>, &quot;<a href="http://swapi.dev/api/vehicles/30/&quot;%5D">http://swapi.dev/api/vehicles/30/&quot;]</a>,
  &quot;starships&quot;: [&quot;<a href="http://swapi.dev/api/starships/12/&quot;">http://swapi.dev/api/starships/12/&quot;</a>, &quot;<a href="http://swapi.dev/api/starships/22/&quot;%5D">http://swapi.dev/api/starships/22/&quot;]</a>,
  &quot;created&quot;: &quot;2014-12-09T13:50:51.644000Z&quot;,
  &quot;edited&quot;: &quot;2014-12-20T21:17:56.891000Z&quot;,
  &quot;url&quot;: &quot;<a href="http://swapi.dev/api/people/1/&quot;">http://swapi.dev/api/people/1/&quot;</a>
}</p>
<pre><code>* REST API로 인물의 정보를 받아오면 전체 데이터를 받아와야 한다. 만약 이름, 키, 몸무게만 필요하다고 했을 때 GraphQL API를 사용하면 다음과 같이 요청할 수 있다.</code></pre><p>// GraphQL request
query {
  person(personID: 1) {</p>
<pre><code>name
height
mass</code></pre><p>  }
}
// GraphQL response
{
  &quot;data&quot;: {</p>
<pre><code>&quot;person&quot;: {
  &quot;name&quot;: &quot;Luke Skywalker&quot;,
  &quot;height&quot;: 172,
  &quot;mass&quot;: 77
}</code></pre><p>  }
}</p>
<pre><code></code></pre></li>
</ol>
<h2 id="장점">장점</h2>
<ol>
<li>HTTP 요청 횟수를 줄일 수 있다.<ul>
<li>필요한 자원 별로 요청을 보내야 하는 RESTful API와 다르게 하나의 쿼리에 원하는 정보를 모두 담아 요청을 보낼 수 있다.</li>
</ul>
</li>
<li>HTTP 응답 사이즈를 줄일 수 있다.<ul>
<li>RESTful API는 응답 형태가 고정적이지만 GraphQL API는 원하는 데이터를 쿼리로 보내 응답 사이즈를 줄일 수 있다.</li>
</ul>
</li>
</ol>
<h2 id="단점">단점</h2>
<ol>
<li>고정된 요청/응답만 필요할 때는 쿼리로 인해 RESTful API보다 요청의 크기가 더 커질 수 있다.</li>
<li>캐싱이 복잡하다.
파일 업로드 구현 방법이 정해져있지 않아 직접 구현해야 한다.</li>
</ol>
<h1 id="reference">Reference</h1>
<p><a href="https://hahahoho5915.tistory.com/63#google_vignette">[간단정리] GraphQL이란? (REST api와 차이점)</a>
<a href="https://www.ciokorea.com/news/272631#csidxfd5b1031eeb1f37b42590e35eb1b953">REST API 대신 ‘그래프QL’ 선택 전에... 알아야 할 장단점 5가지</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[05 DB 구조와 유형]]></title>
            <link>https://velog.io/@_coyg_/05-DB-%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%9C%A0%ED%98%95</link>
            <guid>https://velog.io/@_coyg_/05-DB-%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%9C%A0%ED%98%95</guid>
            <pubDate>Sat, 01 Jul 2023 19:01:26 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터베이스">데이터베이스</h1>
<ul>
<li>체계화된 데이터의 모임.</li>
<li>효율적인 데이터 저장/검색/수정/삭제 등을 지원하며 동시에 여러 사용자가 접근할 수 있음.</li>
</ul>
<h2 id="데이터베이스-시스템">데이터베이스 시스템</h2>
<ul>
<li>DB를 관리/조작하는 데 사용되는 소프트웨어.</li>
<li>데이터의 구조화/저장/검색/수정/삭제 등을 효율적으로 수행할 수 있도록 지원함.</li>
</ul>
<h3 id="주요-구성-요소">주요 구성 요소</h3>
<ol>
<li>데이터베이스 관리 시스템(DBMS)<ul>
<li>DB를 관리하는 소프트웨어.</li>
<li>데이터의 구조, 구성, 접근 권한, 무결성 등을 관리.</li>
<li>DB에 대한 작업을 수행할 수 있는 인터페이스 제공.</li>
<li>예) Oracle, MySQL, PostgreSQL</li>
</ul>
</li>
<li>데이터베이스<ul>
<li>체계화된 데이터의 집합.
DBMS에 의해 관리/조작됨.</li>
<li>테이블(==릴레이션), 레코드(==튜플,로우), 필드(속성,컬럼) 등의 구조로 구성됨.</li>
<li>데이터의 지속성 및 일관성 보장, 동시 접근 보장</li>
</ul>
</li>
<li>데이터 모델<ul>
<li>데이터의 구조와 관계의 표현방법 정의.</li>
<li>개념적인 데이터 구조를 추상화하여 표현함.</li>
<li>주요 데이터 모델: 관계형 데이터 모델, 객체지향 데이터 모델, 계층형 데이터 모델, 네트워크 데이터 모델.</li>
</ul>
</li>
</ol>
<h2 id="dbms-언어-3종류">DBMS 언어 3종류</h2>
<ol>
<li>데이터 정의어 (Data Definition Language)<ul>
<li>데이터베이스 스키마 정의</li>
<li>데이터 구조 생성(create table)/수정(alter table)/삭제(drop table), 특정 애트리뷰트 위에 인덱스 정의 (create index)</li>
</ul>
</li>
<li>데이터 조작어 (Data Manipulation Language)<ul>
<li>데이터 조회/변경/삽입/삭제</li>
<li>select, update, insert, delete</li>
</ul>
</li>
<li>데이터 제어어 (Data Control Language)<ul>
<li>트랜잭션 명시 및 권한 부여/취소</li>
</ul>
</li>
</ol>
<h2 id="데이터베이스-유형">데이터베이스 유형</h2>
<h3 id="관계형-데이터베이스">관계형 데이터베이스</h3>
<ul>
<li>데이터를 테이블 형태로 구성.</li>
<li>테이블 간의 관계를 설정하여 데이터 저장/관리/조회.</li>
</ul>
<h4 id="특징">특징</h4>
<ul>
<li>테이블<ul>
<li>데이터가 저장되는 곳.</li>
<li>행(레코드)과 열(필드)로 구성.</li>
</ul>
</li>
<li>관계<ul>
<li>테이블 간의 관계 설정. 데이터의 무결성/일관성 유지 가능.</li>
<li>One-to-One, One-to-Many, Many-to-Many.</li>
</ul>
</li>
<li>기본 키<ul>
<li>레코드의 고유 키.</li>
<li>null 값 x</li>
<li>유일값</li>
</ul>
</li>
<li>외래 키<ul>
<li>다른 테이블과의 관계를 나타내는 필드.</li>
<li>다른 테이블의 기본 키와 매칭되어 데이터 무결성과 관계를 유지하는 데 사용됨.</li>
</ul>
</li>
</ul>
<h3 id="nosql-데이터베이스">NoSQL 데이터베이스</h3>
<p>Not Only SQL.</p>
<ul>
<li>대량의 분산 데이터 처리</li>
<li>확장성, 성능, 유연성</li>
</ul>
<h4 id="특징-1">특징</h4>
<ol>
<li>비구조적 모델<ul>
<li>테이블 x / 스키마 x. but 다양한 데이터 모델을 사용하여 데이터 저장. (예: key-value, graph db, document db 등)</li>
</ul>
</li>
<li>수평적 확장성<ul>
<li>대규모 데이터 처리에 용이</li>
<li>데이터베이스 클러스터를 구성하고 데이터를 분산하여 처리함으로써 처리량을 증가시킬 수 있음.</li>
</ul>
</li>
<li>유연한 스키마<ul>
<li>데이터를 저장할 때 사전에 스키마 정의 필요 x</li>
<li>필요에 따라 동적으로 데이터 구조 변경 가능</li>
</ul>
</li>
<li>빠른 읽기/쓰기<ul>
<li>분산 아키텍처, 메모리 기반 데이터 저장 등의 기술 덕분에 성능 개선</li>
</ul>
</li>
</ol>
<h4 id="주요-유형">주요 유형</h4>
<ol>
<li>Key-value store: 데이터가 키-값 쌍으로 저장됨.<ul>
<li>Redis, Amazon DynamoDB 등</li>
</ul>
</li>
<li>컬럼 패밀리: 테이블과 유사한 구조. 각 컬럼은 행 단위로 저장됨.<ul>
<li>Cassandra, HBase</li>
</ul>
</li>
<li>문서 데이터베이스: JSON, XML 등의 문서 형태의 데이터 저장.<ul>
<li>MongoDB, CouchDB</li>
</ul>
</li>
<li>그래프 데이터베이스: 노드와 엣지로 구성된 그래프 형태의 데이터 저장. 관계 쿼리 효율적.<ul>
<li>Neo4j, Amazon Neptune</li>
</ul>
</li>
</ol>
<h1 id="rd-vs-nosql">RD vs. NoSQL?</h1>
<h2 id="rd">RD</h2>
<h3 id="장점">장점</h3>
<ol>
<li>데이터의 일관성 보장 / ACID 트랜잭션을 지원하여 데이터의안정성 유지 가능</li>
<li>데이터 간의 관계의 명확한 정의/관리 가능 / 복잡한 쿼리 수행 가능</li>
<li>정형화된 데이터에 적합 / 정교한 데이터 구조 다루는데 유용<h3 id="단점">단점</h3>
</li>
<li>수직적 확장에 제약 -&gt; 대규모 데이터 처리의 한계</li>
<li>번거로운 스키마 변경 -&gt; 유연성 부족</li>
<li>대량의 데이터 / 유연한 데이터 모델 필요한 경우 -&gt; 성능 저하</li>
</ol>
<h2 id="nosql">NoSQL</h2>
<h3 id="장점-1">장점</h3>
<ol>
<li>수평적 확장 용이 -&gt; 대규모 데이터 처리에 적합.</li>
<li>유연한 스키마 -&gt; 동적 데이터 구조에 대응 용이.</li>
<li>빠른 읽기/쓰기 -&gt; 효과적인 분산 데이터 처리.</li>
<li>다양한 데이터 모델 제공 -&gt; 다양한 유형의 데이터 처리.</li>
</ol>
<h3 id="단점-1">단점</h3>
<ol>
<li>데이터 일관성이 상대적으로 낮음 -&gt; 일관성보다는 가용성과 성능에 초점 (BASE 원칙)</li>
<li>데이터 간의 관계 명시 x -&gt; 복잡한 쿼리 작업 어려움</li>
<li>NoSQL DB 간의 표준화된 쿼리 언어 x -&gt; 벤더마다 쿼리 언어 다름</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[04 쓰레드와 쓰레드풀]]></title>
            <link>https://velog.io/@_coyg_/04-%EC%93%B0%EB%A0%88%EB%93%9C%EC%99%80-%EC%93%B0%EB%A0%88%EB%93%9C%ED%92%80</link>
            <guid>https://velog.io/@_coyg_/04-%EC%93%B0%EB%A0%88%EB%93%9C%EC%99%80-%EC%93%B0%EB%A0%88%EB%93%9C%ED%92%80</guid>
            <pubDate>Sat, 01 Jul 2023 17:13:34 GMT</pubDate>
            <description><![CDATA[<h1 id="프로그램">프로그램</h1>
<ul>
<li>컴퓨터에서 실행 가능한 명령어의 집합.</li>
</ul>
<h1 id="프로세스">프로세스</h1>
<ul>
<li><p>컴퓨터에서 실행 중인 프로그램의 인스턴스.</p>
</li>
<li><p>단일 스레드 프로세스 - 실행 흐름이 하나 뿐인 프로세스</p>
</li>
<li><p>멀티 스레드 프로세스 - 실행 흐름이 여러 개인 프로세스</p>
</li>
</ul>
<p>프로세스로만 작업 처리 시 문제점:</p>
<ol>
<li>프로세스 생성 시 오버헤드 발생</li>
<li>문맥 교환 시 오버헤드가 큼</li>
<li>프로세스 간 통신이 어려움</li>
</ol>
<h1 id="스레드">스레드</h1>
<ul>
<li>프로세스를 구성하는 실행 흐름의 단위</li>
</ul>
<p>프로세스의 스택을 제외한 힙, 코드, 데이터 영역은 스레드끼리 공유함.
스택 영역은 각 스레드가 독립적으로 할당받음.</p>
<p>스레드가 실행되는 데 필요한 정보는 스택에 독립적으로 저장을 하지만, 동적 정보는 힙에 저장되고 모든 스레드가 이를 공유한다.</p>
<p>스레드로 작업 처리 시 장점:</p>
<ol>
<li>프로세스보다 작은 실행 단위 구현 가능</li>
<li>프로세스 생성 시 오버헤드 감소</li>
<li>자원을 공유하기 때문에 빠른 문맥교환</li>
<li>프로세스 간 통신</li>
</ol>
<h2 id="멀티-프로세스">멀티 프로세스</h2>
<p>컴퓨터에서 동시에 여러 개의 프로세스가 실행되는 방식.</p>
<ul>
<li><p>각각의 프로세스는 독립된 메모리 공간을 가지고 실행 흐름과 리소스를 독립적으로 관리함</p>
</li>
<li><p>서로 다른 작업 or 병렬(동시) 작업 처리</p>
</li>
</ul>
<h3 id="장점">장점</h3>
<ul>
<li>각각의 프로세스가 독립적으로 실행되기 때문에 서로 영향을 주지 않음 (한 프로세스에 문제가 생겨도 다른 프로세스에는 영향 x)<h3 id="단점">단점</h3>
</li>
<li>프로세스 간 문맥교환이 자주 발생하므로 성능에 영향을 줌.</li>
<li>프로세스마다 독립적인 메모리 공간이 있어야 하므로 프로세스가 많아질 수록 차지하는 메모리가 많아짐.</li>
</ul>
<h2 id="멀티-스레드">멀티 스레드</h2>
<ul>
<li>컴퓨터에서 단일 프로세스 내에서 동시에 여러 개의 스레드가 실행되는 방식.</li>
</ul>
<h3 id="장점-1">장점</h3>
<ul>
<li>스레드 간 데이터를 공유하며 통신이 원활함. -&gt; 작업의 효율성 up</li>
<li>문맥교환의 비용이 멀티 프로세스의 문맥교환보다 적음</li>
</ul>
<h3 id="주의할-점">주의할 점</h3>
<ul>
<li>교착상태: 한 스레드가 점유한 자원을 다른 스레드가 무한으로 기다리고, 반대로도 마찬가지인 상태.
<a href="https://namu.wiki/w/%EC%8B%9D%EC%82%AC%ED%95%98%EB%8A%94%20%EC%B2%A0%ED%95%99%EC%9E%90%20%EB%AC%B8%EC%A0%9C">식사하는 철학자 문제</a></li>
</ul>
<h2 id="스레드-풀">스레드 풀</h2>
<p>일정한 개수의 스레드들을 미리 생성하고 작업이 들어왔을 때 스레드 중 하나에 작업을 할당하여 처리하는 기법. </p>
<h3 id="사용하는-이유">사용하는 이유</h3>
<p>스레드 생성 및 제거에 대한 오버헤드를 줄이고 스레드를 재사용하여 처리 속도와 성능을 향상시키기 위해</p>
<h3 id="구성-요소">구성 요소</h3>
<ol>
<li>작업 큐<ul>
<li>스레드 풀이 작업을 저장하는 공간. 작업이 도착했을 때 여기에 추가되고 스레드가 작업을 수행할 때 여기에서 가져감.</li>
</ul>
</li>
<li>스레드 생성 및 제거 매커니즘<ul>
<li>몇 개의 스레드를 미리 생성할 지 등</li>
</ul>
</li>
<li>스레드 관리자<ul>
<li>스레드의 생성, 할당, 반환, 우선순위 관리 등을 수행</li>
</ul>
</li>
</ol>
<h3 id="동작">동작</h3>
<ol>
<li>초기화: 미리 정해진 개수의 스레드를 생성. 이 때 스레드들은 작업이 들어오기를 기다리는 상태.</li>
<li>작업 요청: 외부에서 작업이 도착하면 작업 큐에 추가되고 해당 작업은 스레드 풀에게 요청됨.</li>
<li>작업 할당: 작업 큐에서 작업을 꺼내어 실행 가능한 스레드에게 할당함.</li>
<li>작업 실행: 할당된 스레드는 작업을 실행하고, 완료되었을 때 다음 작업을 위해 작업 큐에서 다시 작업을 가져옴.</li>
<li>스레드 재사용: 작업이 완료된 스레드는 작업 큐로 돌아가 새로운 작업을 할당받은 준비를 함.</li>
<li>작업 완료: 모든 작업이 완료되면 스레드 풀은 종료될 수 있음. 하지만 작업 큐가 비워질 때까지 모든 스레드는 대기 상태 유지.</li>
</ol>
<h3 id="단점-1">단점</h3>
<ol>
<li>정의된 스레드보다 더 많은 양의 작업이 들어오면 다 작업 큐에 추가됨. 메모리 사용량 up</li>
<li>작업이 처리되기 위해 스레드를 기다려야하기 때문에 이에 따른 지연이 발생할 수 있음. </li>
<li>작업의 우선순위 관리 어려움</li>
<li>교착상태 발생 가능</li>
</ol>
<h2 id="동시성concurrency-vs-병렬성parallelism">동시성(Concurrency) vs. 병렬성(Parallelism)</h2>
<h3 id="동시성">동시성</h3>
<p>여러 작업이 동시에 실행되는 것처럼 &#39;보이는&#39; 개념.
실제로는 각 작업이 작은 시간 단위로 번갈아가며 실행됨.</p>
<ul>
<li>주로 단일 프로세서 환경에서 활용됨<h3 id="병렬성">병렬성</h3>
여러 작업이 실제로 동시에 실행됨.
여러 프로세서 또는 코어가 동시에 작업을 처리함.</li>
<li>주로 멀티 프로세서 환경에서 활용됨</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[자료구조 - Graph]]></title>
            <link>https://velog.io/@_coyg_/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Graph</link>
            <guid>https://velog.io/@_coyg_/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Graph</guid>
            <pubDate>Tue, 20 Jun 2023 15:21:40 GMT</pubDate>
            <description><![CDATA[<h1 id="그래프">그래프</h1>
<ul>
<li>정점(V)과 간선(E)의 집합으로 이루어진 비선형 자료구조이다.</li>
<li>정점은 노드라고도 불리고, 간선은 노드들을 연결시켜주는 선이다.</li>
</ul>
<ul>
<li>그래프의 표현식: G(E,V).</li>
</ul>
<ul>
<li>노드: 데이터를 담고 있는 객체(?)</li>
</ul>
<p>예시) 페이스북</p>
<ul>
<li>페북에는 사용자, 사진, 영상, 그룹, 페이지, 댓글 등 많은 요소가 있고, 각각의 요소는 데이터를 담고 있는 노드이다.</li>
<li>사용자가 사진을 게시하거나, 댓글을 작성하거나, 다른 사용자와 친구가 된다면 이들 노드들은 간선으로 연결이 된다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/_coyg_/post/045a287c-0e51-4067-a83d-b23b546af060/image.png" alt=""></p>
<h2 id="종류">종류</h2>
<p><strong>Directed graph(유향 그래프)</strong>: (v,u) 간선이 존재해도 반대의 (u,v) 간선은 존재하지 않을 수도 있는 그래프. 간선의 방향은 화살표로 표현.
<strong>Undirected graph(무향 그래프)</strong>: (v,u) 간선이 존재한다면 반대의 (u,v) 간선도 존재하는 그래프.</p>
<p>V = { 0, 1, 2, 3 }
E = { (0, 1), (0, 2), (0, 3), (1, 2) }
G = { V, E }</p>
<h2 id="용어">용어</h2>
<ul>
<li>Adjacency(인접): 간선으로 이어진 정점.
위 예시에서 2와 3은 인접 정점이 아니다.</li>
<li>Path(경로): 한 정점에서 다른 정점으로 가는 수열.
(0-1, 0-2)와 (0-2)는 모두 0에서 2로 가는 경로에 해당된다.</li>
<li>Closed Path(폐쇄 경로): 한 정점이 경로의 시작점이자 끝점인 경로.</li>
<li>Cycle: 경로 내에 중복된 정점(시작점,끝점 제외) 혹은 간선이 없는 경로.</li>
</ul>
<h2 id="구현-방법">구현 방법</h2>
<h3 id="인접-행렬">인접 행렬</h3>
<p>위의 그래프를 아래와 같이 2차원 배열로 구현할 수 있다.
이 2차원 배열을 <strong>인접 행렬</strong>이라고 한다.
<img src="https://velog.velcdn.com/images/_coyg_/post/c810222e-f0ab-4da6-ad21-b3b879fc430f/image.png" alt=""></p>
<p>위 그래프는 무향 그래프(쌍방)이기 때문에 (0,2)와 (2,0) 모두 표시해줘야 한다.</p>
<h4 id="장점">장점</h4>
<ul>
<li>간선 탐색이 매우 빠름
*Edge lookup(간선 탐색): 정점A와 정점B 사이의 간선 탐색<h4 id="단점">단점</h4>
</li>
<li>모든 경우의 수(위의 경우 4x4)를 미리 초기화해야 하므로 공간을 많이 차지함</li>
</ul>
<h3 id="인접-리스트">인접 리스트</h3>
<p>다른 구현 방식으로는 연결리스트의 배열이 있다.
이 연결리스트의 배열을 <strong>인접 리스트</strong>라고 한다.
<img src="https://velog.velcdn.com/images/_coyg_/post/78879d9a-f931-4e2e-b9ab-3ce53be07537/image.png" alt=""></p>
<h4 id="장점-1">장점</h4>
<ul>
<li>인접 행렬과는 다르게 필요한 값(존재하는 가선)만 저장할 수 있음.</li>
</ul>
<h2 id="연산">연산</h2>
<p>그래프의 가장 자주 쓰이는 연산은 아래와 같다.</p>
<ol>
<li>특정 요소(정점 혹은 간선)가 있는지 확인</li>
<li>그래프 탐색 (DFS, BFS)</li>
<li>요소(정점 혹은 간선) 삽입</li>
<li>한 정점에서 다른 정점으로의 경로 구하기</li>
</ol>
<h1 id="심화">심화</h1>
<h2 id="spanning-tree">Spanning Tree</h2>
<ul>
<li>신장 트리는 무향 그래프의 부분집합으로, 모든 정점들이 최소한의 간선 갯수로 연결되어있는 그래프를 뜻한다.</li>
<li>그래프의 모든 정점들에 간선이 존재한다면 신장 트리가 최소 한 개 있다는 뜻이며, 한 그래프 내에 여러 개의 신장 트리가 존재할 수 있다.</li>
<li>신장 트리에 정점이 n개가 존재한다면 간선은 n-1개 있어야 한다.
<img src="https://velog.velcdn.com/images/_coyg_/post/3ac29e66-9a1c-403a-a21e-59d75bf32f5a/image.png" alt=""></li>
</ul>
<p>예를 들면 위 그래프에서 굵은선으로 이루어진 그래프가 신장 트리 중 하나이다.</p>
<h3 id="minimum-spanning-tree">Minimum Spanning Tree</h3>
<ul>
<li>최소 신장 트리는 간선들에 가중치가 정해져있을 때 가장 작은 비용으로 이루어질 수 있는 신장 트리를 뜻한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/_coyg_/post/45370b58-3460-4675-afc2-58e5fc724e14/image.png" alt=""></p>
<ul>
<li>대표적인 알고리즘으로는 Kruskal 알고리즘, Prim 알고리즘이 존재한다.</li>
</ul>
<h2 id="최단-경로">최단 경로</h2>
<ul>
<li>최단 경로는 간선들에 가중치가 정해져있을 때 한 정점에서 다른 정점으로의 경로의 비용이 가장 작은 경로를 뜻한다.</li>
<li>주로 가중치가 있는 유향 그래프에서 나타나지만 무향 그래프에도 적용이 가능하다.</li>
</ul>
<ul>
<li><p>현실 세계에서는 지도에 최단 경로 구하기를 적용할 수 있다. 다양한 최단 경로 알고리즘으로 네비게이션 동작을 최적화할 수 있다.</p>
</li>
<li><p>2가지 대표적인 최단 경로 알고리즘으로는</p>
<ul>
<li>Dijkstra&#39;s Shortest Path Algorithm (다익스트라)</li>
<li>Bellman Ford&#39;s Shortest Algorithm (벨만 포드)</li>
</ul>
<p>가 있다.</p>
</li>
</ul>
<h1 id="사용처">사용처</h1>
<ol>
<li><p>네트워크 및 통신</p>
<ul>
<li>컴퓨터 네트워크, 인터넷, 라우팅 알고리즘 등과 같은 통신 시스템의 구조를 모델링하는 데 사용된다.</li>
<li>노드는 라우터, 서버, 컴퓨터 등의 네트워크 장치를 나타내고, 간선은 연결과 통신 경로를 나타낸다.</li>
</ul>
</li>
<li><p>소셜 네트워크 분석</p>
<ul>
<li>소셜 네트워크 분석에서 사용되어 친구 관계, 연결, 그룹 구성 등을 모델링한다.</li>
<li>사용자, 프로필 또는 개인 간의 상호 작용은 그래프의 노드와 간선으로 표현될 수 있다.</li>
</ul>
</li>
<li><p>경로 및 최적화 문제</p>
<ul>
<li>경로 찾기, 최단 경로 문제, 여행자 문제 등과 같은 경로 및 최적화 문제를 해결하는 데 사용된다.</li>
<li>최소 신장 트리, 최단 경로 알고리즘, 플로우 네트워크 등 그래프 기반의 알고리즘을 활용한다.</li>
</ul>
</li>
<li><p>데이터베이스 및 검색 엔진</p>
<ul>
<li>관계형 데이터베이스 및 검색 엔진에서 사용되어 데이터 사이의 관계와 연결성을 모델링한다.</li>
<li>그래프 데이터베이스는 복잡한 관계와 네트워크를 저장하고 조회하는 데 사용된다.</li>
</ul>
</li>
</ol>
<h1 id="알고리즘-문제">알고리즘 문제</h1>
<ol>
<li><p>최단 경로 문제 (Shortest Path Problem)</p>
<ul>
<li>두 정점 간의 최단 경로를 찾는 문제</li>
<li>대표적인 알고리즘: Dijkstra 알고리즘, Bellman-Ford 알고리즘.</li>
</ul>
</li>
<li><p>최소 신장 트리 (Minimum Spanning Tree)</p>
<ul>
<li>가중치가 있는 그래프에서 모든 정점을 연결하면서 간선의 가중치 합이 최소인 트리를 찾는 문제. </li>
<li>대표적인 알고리즘: Kruskal 알고리즘, Prim 알고리즘.</li>
</ul>
</li>
<li><p>너비 우선 탐색 (Breadth-First Search, BFS)</p>
<ul>
<li>그래프에서 한 정점으로부터 모든 정점을 탐색하는 알고리즘. </li>
<li>너비 우선 탐색은 그래프의 최단 경로 문제, 연결성 확인, 그래프 구조 분석 등에 사용.</li>
</ul>
</li>
<li><p>깊이 우선 탐색 (Depth-First Search, DFS)</p>
<ul>
<li>그래프에서 한 정점으로부터 가능한 한 깊숙이 들어가서 탐색하는 알고리즘.</li>
<li>깊이 우선 탐색은 사이클 검사, 연결 구성 요소 확인, 위상 정렬 등에 활용.</li>
</ul>
</li>
<li><p>플로이드-와샬 알고리즘 (Floyd-Warshall Algorithm)</p>
<ul>
<li>그래프에서 모든 정점 쌍 간의 최단 경로를 찾는 알고리즘.</li>
<li>음의 가중치를 허용하는 그래프에서도 적용 가능.</li>
</ul>
</li>
<li><p>위상 정렬 (Topological Sorting)</p>
<ul>
<li>방향 그래프에서 각 정점의 선행 순서를 유지하면서 정점들을 정렬하는 알고리즘. </li>
<li>주로 작업의 의존 관계를 해결하는 데 사용.</li>
</ul>
</li>
<li><p>강한 연결 요소 (Strongly Connected Components)</p>
<ul>
<li>방향 그래프에서 강하게 연결된 정점들의 최대 집합을 찾는 문제. </li>
<li>대표적인 알고리즘: Kosaraju&#39;s 알고리즘, Tarjan&#39;s 알고리즘.</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[03 프로세스]]></title>
            <link>https://velog.io/@_coyg_/03-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4</link>
            <guid>https://velog.io/@_coyg_/03-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4</guid>
            <pubDate>Sat, 17 Jun 2023 18:25:51 GMT</pubDate>
            <description><![CDATA[<h1 id="프로세스-생명-주기">프로세스 생명 주기</h1>
<h2 id="프로세스-상태">프로세스 상태</h2>
<h3 id="생성-new">생성 (New)</h3>
<ul>
<li>보조기억장치에 데이터 덩어리로 저장되어있던 프로그램이 주기억장치에 올라왔지만 아직 실행은 불가능한 상태.</li>
<li><strong><em>생성 상태에서 갈 수 있는 상태:</em></strong> 준비 상태<h3 id="준비-ready">준비 (Ready)</h3>
</li>
<li>생성된 프로세스가 실행될 수 있도록 변수 초기화 등 기초 세팅을 통해 프로세스를 준비시키는 상태.</li>
<li><strong><em>준비 상태가 될 수 있는 상태:</em></strong><ol>
<li>생성 - 프로세스가 생성됐을 때</li>
<li>수행 - 프로세스가 실제로 수행을 하다가 OS에 의해 중단이 되었을 때</li>
<li>대기 - 대기 상태에서 입출력이 완료되었을 때</li>
</ol>
</li>
<li><strong><em>준비 상태에서 갈 수 있는 상태:</em></strong> 수행 상태<h3 id="수행-running">수행 (Running)</h3>
</li>
<li>실행될 준비를 마친 프로세스들이 실제로 프로세서에 의해 실행되는 상태.</li>
<li><strong><em>수행 상태가 될 수 있는 상태:</em></strong> 준비 상태</li>
<li><strong><em>수행 상태에서 갈 수 있는 상태:</em></strong><ol>
<li>준비 - 스케쥴러(OS)에 의해 프로세스가 중단이 되었을 때</li>
<li>대기 - 입출력 이벤트를 받아야할 때</li>
<li>종료 - 프로세스가 끝났을 때<h3 id="대기-waiting">대기 (Waiting)</h3>
</li>
</ol>
</li>
<li>입출력 작업이 들어왔을 때 프로세스가 입출력장치로 넘어가 프로세서가 기다리는 상태.</li>
<li><strong><em>대기 상태가 될 수 있는 상태:</em></strong> 수행 상태</li>
<li><strong><em>대기 상태에서 갈 수 있는 상태:</em></strong> 준비 상태<h3 id="종료-terminated">종료 (Terminated)</h3>
</li>
<li>프로세스의 수행이 끝난 상태.</li>
<li><strong><em>종료 상태가 될 수 있는 상태:</em></strong> 수행 상태</li>
</ul>
<h2 id="대기-큐">대기 큐</h2>
<ol>
<li><strong>Job queue</strong> - 프로세스가 실행되려면 프로그램이 보조기억장치에서 주기억장치로 올라와야 하는데 주기억장치에 공간이 없거나 cpu가 다른 작업을 하는 중일 때 프로세스가 대기하는 큐.</li>
<li><strong>Ready queue</strong> - 프로그램이 주기억장치에 올라왔지만 바로 프로세스가 실행되지 못하는 상태일 때 프로세스가 대기하는 큐.</li>
<li><strong>Device queue</strong> - 입/출력이 필요한 프로세스가 입/출력 작업이 끝날 때까지 대기하는 큐.</li>
</ol>
<h2 id="스케줄링">스케줄링</h2>
<ol>
<li><strong>Job scheduler</strong> - job queue에 있는 프로세스들을 어떤 순서로 메모리에 올릴 지 결정. (프로그램 시작 시 / 주기억장치에 공간 없을 시)<ul>
<li>Long Term Scheduler: 긴 간격으로 동작하는 스케줄러 (자주 발생하지 않음)</li>
</ul>
</li>
<li><strong>CPU scheduler</strong> - ready queue에 있는 프로세스들을 어떤 순서로 실행할 지 결정.<ul>
<li>Short Term Scheduler: 짧은 간격으로 동작하는 스케줄러 (엄청 자주 발생함)</li>
</ul>
</li>
<li><strong>Device scheduler</strong> - device queue에 있는 프로세스들이 어떤 순서로 입/출력 장치를 이용할 지 결정.</li>
</ol>
<h2 id="주-보조-교환swapping">주-보조 교환(Swapping)</h2>
<ul>
<li>메모리 할당이 일정 기간동안 필요하지 않은 프로세스들을 잠시 보조기억장치로 내려놓고(swap out) 메모리 할당이 당장 필요한 프로세스들을 주기억장치로 올려(swap in) 실행하는 작업.</li>
</ul>
<ol>
<li>PCB(Process Control Block)에 프로세스의 정보 저장<ul>
<li>PID, 레지스터(지금까지의 작업 상태 등), 프로세스 상태, 메모리 정보, CPU 스케줄링 정보, 사용한 파일 / 입출력장치 정보 등</li>
<li>예) 프로세스A가 일정 기간동안 실행될 필요가 없을 때 프로세스A의 정보를 PCB에 저장.</li>
</ul>
</li>
<li>다음 프로세스의 정보를 PCB에서 가져오기<ul>
<li>예) 당장 실행되어야 하는 프로세스B의 정보를 PCB에서 가져오기</li>
</ul>
</li>
<li>PCB에서 가져온 정보를 바탕으로 프로세스B를 이어서 실행</li>
<li>1-3 반복</li>
</ol>
<ul>
<li>Medium Term Scheduler: 적당한 간격으로 동작하는 스케줄러</li>
</ul>
<h2 id="문맥-교환context-switching">문맥 교환(Context switching)</h2>
<ol>
<li>Context switching - 수행 상태의 프로세스를 스케줄러가 준비 상태로 내리고 다른 프로새스를 수행 상태로 올리는 작업.<ul>
<li>프로세스들의 메모리와 실행의 적절한 분배 등</li>
</ul>
</li>
<li>Scheduler - 어떤 프로세스가 어떤 순서로 수행될 지 결정하는 녀석.</li>
<li>Dispatcher - 주-보조 교환에서 설명했던 1~3번 작업을 수행하는 녀석.</li>
</ol>
<h1 id="프로세스-메모리">프로세스 메모리</h1>
<h2 id="프로세스-메모리-구조">프로세스 메모리 구조</h2>
<ol>
<li>코드 영역 - 프로그램 실행에 필요한 명령어 저장되는 공간 (말그대로 코드)</li>
<li>데이터 영역 - 프로그램 시작 시 필요한 데이터 저장되는 공간 (전역 혹은 정적 변수)</li>
<li>힙 영역 - 직접 할당 가능한 공간 (malloc, new)</li>
<li>스택 영역 - 데이터가 일시적으로 저장되는 공간 (매개변수, 지역변수)</li>
</ol>
<ul>
<li><p>정적 데이터 영역: 코드, 데이터</p>
</li>
<li><p>동적 데이터 영역: 힙, 스택</p>
</li>
<li><p>힙 영역과 스택 영역은 동적(크기가 고정되어있지 않음)이기 때문에 힙 영역은 데이터 영역 위에서 위로, 스택 영역은 메모리 영역의 맨 위에서 아래로 쌓인다.</p>
</li>
</ul>
<h2 id="커널">커널</h2>
<ul>
<li><p>운영체제에서 핵심적인 기능을 수행하는 인터페이스.</p>
</li>
<li><p>하드웨어와 프로세스들 사이에서 다양한 작업 수행:</p>
<ol>
<li>메모리 관리</li>
<li>프로세스 관리</li>
<li>입출력 관리</li>
<li>파일 시스템 관리</li>
</ol>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[59. NestJS Typeorm Migration (항해 74일차)]]></title>
            <link>https://velog.io/@_coyg_/59.-NestJS-Typeorm-Migration-%ED%95%AD%ED%95%B4-74%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@_coyg_/59.-NestJS-Typeorm-Migration-%ED%95%AD%ED%95%B4-74%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 15 Jun 2023 03:48:22 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p>현재 진행 중인 프로젝트에서 데이터베이스의 stores라는 테이블에 새로운 컬럼을 추가해야 하는 일이 생겼다.
pgadmin4에서 쿼리문으로 &#39;ALTER TABLE stores ADD COLUMN coordinates geometry(Point, 4326) default NULL&#39; 이런 식으로 컬럼을 생성했다.</p>
<p>그런 다음에 stores 테이블에 기존에 있던 Ma, La 값을 가지고 coordinates의 값을 업데이트 해주었다.</p>
<p>처음에는 잘 되다가 중간에 갑자기 서버가 끊기면서 해당 컬럼이 존재하지 않는다는 오류가 떴다. 그리고 실제로 pgadmin4에 봤더니 컬럼이 삭제되어있었다.</p>
<h1 id="references">REFERENCES</h1>
<ul>
<li><a href="https://orkhan.gitbook.io/typeorm/docs/migrations">TypeORM Migrations 공식 문서</a></li>
<li><a href="https://orkhan.gitbook.io/typeorm/docs/data-source">TypeORM DataSource 문서</a></li>
<li><a href="https://stackoverflow.com/questions/71803499/typeorm-when-trying-to-run-migrations-missing-required-argument-datasource">stackoverflow: Missing required argument: dataSource</a></li>
<li><a href="https://wanago.io/2022/07/25/api-nestjs-database-migrations-typeorm/">Database migrations with TypeORM 강좌</a></li>
</ul>
<h1 id="시도">시도</h1>
<p>아직까지도 정확한 이유는 모르지만 어쨌든 migration으로 스키마의 변경 사항을 버전 관리도 하고 데이터베이스의 변경을 추적하고, 자동으로 적용할 수 있다는 이점 덕에 더 안전한 관리가 가능하다고 생각이 들어서 migration을 만들어보기로 했다.</p>
<p>위의 reference들을 따라하면서 진행했다.</p>
<h2 id="migration-생성">migration 생성</h2>
<p><code>npx typeorm migration:create ./src/migrations/addColumn</code></p>
<ul>
<li>src/migrations 폴더에 {TIMESTAMP}-addColumn.ts 이라는 파일이 생김</li>
</ul>
<pre><code class="language-tsx">// {TIMESTAMP}-addColumn.ts

import { MigrationInterface, QueryRunner } from &#39;typeorm&#39;;

export class AddColumn1686766534159 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise&lt;void&gt; {}

  public async down(queryRunner: QueryRunner): Promise&lt;void&gt; {}
}</code></pre>
<ul>
<li>up: 마이그레이션을 run 시 수행하고자 하는 query문 작성</li>
<li>down: 마이그레이션 revert 시 수행하고자 하는 query문 작성</li>
<li>예시</li>
</ul>
<pre><code class="language-tsx">// 1686766534159-addColumn.ts

import { MigrationInterface, QueryRunner } from &#39;typeorm&#39;;

export class AddColumn1686766534159 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise&lt;void&gt; {
    await queryRunner.query(
      `ALTER TABLE &quot;stores&quot; ADD COLUMN &quot;coordinates&quot; geometry(Point, 4326) DEFAULT NULL`,
    );
  }

  public async down(queryRunner: QueryRunner): Promise&lt;void&gt; {
    await queryRunner.query(`ALTER TABLE &quot;stores&quot; DROP COLUMN &quot;coordinates&quot;`);
  }
}</code></pre>
<ul>
<li>해당 entity에도 column을 추가해야 함.</li>
</ul>
<pre><code class="language-tsx">// stores.entity.ts

import { Users } from &#39;../auth/users.entity&#39;;
import { Reviews } from &#39;../reviews/reviews.entity&#39;;
import { Tables } from &#39;../tables/tables.entity&#39;;
import { Waitings } from &#39;../waitings/waitings.entity&#39;;
import {
  BaseEntity,
  Column,
  CreateDateColumn,
  Entity,
  OneToMany,
  OneToOne,
  Point,
  PrimaryGeneratedColumn,
  UpdateDateColumn,
} from &#39;typeorm&#39;;

@Entity()
export class Stores extends BaseEntity {
  @PrimaryGeneratedColumn()
  storeId: number;

  @Column()
  storeName: string;

  @Column()
  description: string;

  @Column()
  category: string;

  @Column()
  maxWaitingCnt: number;

  @Column()
  currentWaitingCnt: number;

  @Column(&#39;numeric&#39;)
  La: number;

  @Column(&#39;numeric&#39;)
  Ma: number;

  @Column()
  address: string;

  @Column({ nullable: true })
  distance: number;

  @Column({ nullable: true })
  oldAddress: string;

  @Column({ default: 60 })
  cycleTime: number;

  @Column()
  tableForTwo: number;

  @Column()
  tableForFour: number;

  @Column({ type: &#39;float&#39;, default: 0 })
  rating: number;

  // 얘다
  @Column(&#39;geometry&#39;, {
    spatialFeatureType: &#39;Point&#39;,
    srid: 4326,
    nullable: true,
  })
  coordinates: Point;

  @CreateDateColumn({ type: &#39;timestamp&#39;, default: () =&gt; &#39;CURRENT_TIMESTAMP&#39; })
  createdAt: Date;

  @UpdateDateColumn({ type: &#39;timestamp&#39;, default: () =&gt; &#39;CURRENT_TIMESTAMP&#39; })
  updatedAt: Date;

  @OneToMany(() =&gt; Waitings, (waiting) =&gt; waiting.store)
  waitings: Waitings[];

  @OneToMany(() =&gt; Reviews, (review) =&gt; review.store)
  reviews: Reviews[];

  @OneToOne(() =&gt; Tables, (table) =&gt; table.store)
  tables: Tables;

  @OneToOne(() =&gt; Users, (user) =&gt; user.store)
  user: Users;
}</code></pre>
<h2 id="migration-실행">migration 실행</h2>
<ul>
<li>실행을 위해 DataSource 인스턴스가 있어야 한다.</li>
</ul>
<pre><code class="language-tsx">// typeOrm.config.ts

import { Stores } from &#39;./src/stores/stores.entity&#39;;
import { ConfigService } from &#39;@nestjs/config&#39;;
import { config } from &#39;dotenv&#39;;
import { DataSource } from &#39;typeorm&#39;;
import { AddColumn1686766534159 } from &#39;./src/migrations/1686766534159-addColumn&#39;;
import { Waitings } from &#39;./src/waitings/waitings.entity&#39;;
import { Reviews } from &#39;./src/reviews/reviews.entity&#39;;
import { Tables } from &#39;./src/tables/tables.entity&#39;;
import { Users } from &#39;./src/auth/users.entity&#39;;

config();
const configService = new ConfigService();

export const dataSource = new DataSource({
  type: &#39;postgres&#39;,
  host: configService.get(&#39;POSTGRES_HOST&#39;),
  port: 5432,
  username: configService.get(&#39;POSTGRES_USERNAME&#39;),
  password: configService.get(&#39;POSTGRES_PASSWORD&#39;),
  database: &#39;temp&#39;,
  entities: [Stores, Waitings, Reviews, Tables, Users],
  migrations: [AddColumn1686766534159],
  // migrationsTableName: &#39;custom_migration_table&#39;,
});

dataSource
  .initialize()
  .then(() =&gt; {
    console.log(&#39;Data Source has been initialized!&#39;);
  })
  .catch((error) =&gt; {
    console.error(&#39;Error during Data Source initialization&#39;, error);
  });</code></pre>
<ul>
<li><p>import 할 때 경로의 앞에 꼭 “./”을 붙여줘야 한다. 그러지 않으면 module을 못 찾는다.</p>
</li>
<li><p>package.json의 scripts에는 아래 내용을 추가해야 한다.</p>
</li>
</ul>
<pre><code class="language-json">&quot;typeorm&quot;: &quot;ts-node ./node_modules/typeorm/cli&quot;,
&quot;typeorm:run-migrations&quot;: &quot;npm run typeorm migration:run -- -d ./typeOrm.config.ts&quot;,
&quot;typeorm:generate-migration&quot;: &quot;npm run typeorm -- -d ./typeOrm.config.ts migration:generate ./migrations/$npm_config_name&quot;,
&quot;typeorm:create-migration&quot;: &quot;npm run typeorm -- migration:create ./migrations/$npm_config_name&quot;,
&quot;typeorm:revert-migration&quot;: &quot;npm run typeorm -- -d ./typeOrm.config.ts migration:revert&quot;</code></pre>
<ul>
<li>migration 실행: <code>npm run typeorm:run-migrations</code><ul>
<li>위 명령어를 실행하면 루트 디렉토리의 typeOrm.config.ts 파일을 찾아서 migrations 배열에 들어있는 migration들을 실행하게 된다.</li>
</ul>
</li>
</ul>
<h2 id="새로운-migration을-생성하고-실행했을-때-적용이-안되는-이유">새로운 migration을 생성하고 실행했을 때 적용이 안되는 이유?</h2>
<ul>
<li>migration revert는 가장 최근에 생성된? migration들만 down이 된다.<ol>
<li>typeOrm.config.ts의 migrations 배열에 AddColumn1686766534159만 있을 때 run을 하면 AddColumn1686766534159가 migrations db에 추가된다.</li>
<li>typeOrm.config.ts의 migrations 배열에 AddColumnToTables1686791275164를 추가하고 run하면 AddColumn1686766534159는 이미 run되어있기 때문에 AddColumnToTables1686791275164만 run되고 migrations db에 추가된다.</li>
<li>revert를 했을 때 가장 최근에 run된 AddColumnToTables1686791275164가 삭제된다.</li>
<li>또 한 번 revert를 해야 AddColumn1686766534159도 삭제된다.</li>
</ol>
</li>
<li>migrations 배열에 처음부터 2개가 있다면 run을 했을 때 둘 다 migrations db에 추가되고 revert를 했을 때 둘 다 삭제된다.</li>
</ul>
<h1 id="해결">해결</h1>
<p>위 과정들을 거치고 나서 원하던 작업(stores 테이블에 새로 추가된 coordinates 값 업데이트)을 수행하니까 중간에 끊기지 않고 잘 수행이 된다.</p>
<p>원하는 51만여개의 row에 coordinates 컬럼의 값이 잘 업데이트 되었다.</p>
<h1 id="알게-된-점">알게 된 점</h1>
<p>귀찮더라도... pgadmin4에서 쿼리로 컬럼 생성하는거보다 어렵더라도.. 잘 모르겠더라도.. 안전하고 더 체계적이고 유용한 마이그레이션을 통해 데이터베이스를 관리하는 것이 좋다..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[알고리즘 - Dynamic Programming (동적 계획법)]]></title>
            <link>https://velog.io/@_coyg_/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Dynamic-Programming-%EB%8F%99%EC%A0%81-%EA%B3%84%ED%9A%8D%EB%B2%95</link>
            <guid>https://velog.io/@_coyg_/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Dynamic-Programming-%EB%8F%99%EC%A0%81-%EA%B3%84%ED%9A%8D%EB%B2%95</guid>
            <pubDate>Wed, 07 Jun 2023 16:01:51 GMT</pubDate>
            <description><![CDATA[<ul>
<li>최적화 문제를 해결하기 위한 알고리즘 설계 기법</li>
<li>문제를 여러 하위 문제로 나누어 해결하고, 중복되는 하위 문제들을 한 번만 계산하여 중복 계산을 피하는 방법을 사용한다.<ul>
<li>큰 규모의 문제를 해결할 때 용이</li>
</ul>
</li>
</ul>
<h1 id="핵심-아이디어">핵심 아이디어</h1>
<ul>
<li>작은 크기의 하위 문제들을 해결한 결과를 저장해두었다가, 이를 이용하여 더 큰 크기의 문제들을 해결하는 것.</li>
<li>하위 문제들을 푸는 과정에서 발생하는 중복 계산을 피할 수 있다 =&gt; 시간 복잡도 GOOD</li>
</ul>
<h1 id="충족-요건">충족 요건</h1>
<ol>
<li>최적 부분 구조(Optimal Substructure): 큰 문제의 최적해는 작은 문제의 최적해로부터 구할 수 있어야 함.</li>
<li>중복되는 하위 문제(Overlapping Subproblems): 문제를 반복적으로 해결하는 과정에서 동일한 작은 문제가 여러 번 발생해야 함.</li>
</ol>
<h1 id="접근법">접근법</h1>
<h2 id="상향식-접근법-top-down">상향식 접근법 (Top-Down)</h2>
<p>큰 문제를 작은 하위 문제로 쪼개면서 문제를 해결하는 방식.</p>
<p>재귀 함수 혹은 메모이제이션을 통해 구현된다.</p>
<h3 id="메모이제이션">메모이제이션</h3>
<p>계산한 값을 저장해두었다가 필요할 때 재사용하는 기법 -&gt; 동일한 하위 문제의 반복적인 호출 x.</p>
<h2 id="하향식-접근법-bottom-up">하향식 접근법 (Bottom-Up)</h2>
<p>작은 하위 문제부터 시작하여 점진적으로 큰 문제를 해결하는 방식.</p>
<p>작은 문제들의 해를 계산하여 더 큰 문제들의 해를 구하는 방식.</p>
<p>반복문.</p>
<h1 id="어떤-문제에-적용할-수-있나">어떤 문제에 적용할 수 있나?</h1>
<ol>
<li>중복 계산이 발생하는 문제<ul>
<li>동일한 계산이 반복적으로 수행되는 문제 (예: 피보나치: <code>f(n-1) + f(n + 2)</code> )</li>
</ul>
</li>
<li>작은 부분 문제로 분할될 수 있는 문제<ul>
<li>큰 문제를 작은 부분 문제를 나눌 수 있는 문제 (예: 피보나치: <code>f(n-1) + f(n-2)</code> )</li>
</ul>
</li>
<li>부분 문제의 최적해가 전체 문제의 최적해에 영양을 미치는 문제<ul>
<li>부분 문제의 해답을 이용하여 전체 문제의 최적해를 구할 수 있는 문제 (예: 배낭 문제)</li>
</ul>
</li>
</ol>
<p>위와 같은 특징을 가진 문제인지 먼저 살펴봐야한다.</p>
<p>문제를 작은 부분 문제로 분할하고, 부분 문제의 해답을 메모이제이션하거나 재귀적으로 계산하여 저장하는 방식으로 구현해야 한다.</p>
<p>기존의 중복 계산을 피하고 문제를 효율적으로 해결할 수 있다.</p>
<h1 id="대표적인-적용-문제">대표적인 적용 문제</h1>
<h2 id="피보나치-수열">피보나치 수열</h2>
<pre><code class="language-javascript">// 0 1 1 2 3 5 8 13 21 34 55 89 144 . . .

function fibo1(n) {
  if (n === 1 || n === 2) {
    return 1;
  } else {
    return fibo1(n - 1) + fibo1(n - 2);
  }
}

function fibo2(n) {
  const fiboArray = [0, 1, 1];

  for (let i = 3; i &lt;= n; i++) {
    fiboArray[i] = fiboArray[i - 1] + fiboArray[i - 2];
  }

  return fiboArray[n];
}

let fiboMemo = {};

function fibo3(n) {
  if (n === 1 || n === 2) {
    return 1;
  }
  if (fiboMemo[n]) {
    return fiboMemo[n];
  }

  fiboMemo[n] = fibo3(n - 1) + fibo3(n - 2);

  return fiboMemo[n];
}



// fibo 함수의 실행 시간 측정
performance.mark(&quot;startFibo&quot;);
console.log(fibo1(20));
performance.mark(&quot;endFibo&quot;);
performance.measure(&quot;executionTimeFibo&quot;, &quot;startFibo&quot;, &quot;endFibo&quot;);
const measureFibo = performance.getEntriesByName(&quot;executionTimeFibo&quot;)[0];
console.log(`fibo Execution time: ${measureFibo.duration}ms`);

// fibo2 함수의 실행 시간 측정
performance.mark(&quot;startFibo2&quot;);
console.log(fibo2(20));
performance.mark(&quot;endFibo2&quot;);
performance.measure(&quot;executionTimeFibo2&quot;, &quot;startFibo2&quot;, &quot;endFibo2&quot;);
const measureFibo2 = performance.getEntriesByName(&quot;executionTimeFibo2&quot;)[0];
console.log(`fibo2 Execution time: ${measureFibo2.duration}ms`);

// fibo3 함수의 실행 시간 측정
performance.mark(&quot;startFibo3&quot;);
console.log(fibo3(20));
performance.mark(&quot;endFibo3&quot;);
performance.measure(&quot;executionTimeFibo3&quot;, &quot;startFibo3&quot;, &quot;endFibo3&quot;);
const measureFibo3 = performance.getEntriesByName(&quot;executionTimeFibo3&quot;)[0];
console.log(`fibo3 Execution time: ${measureFibo2.duration}ms`);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[57. Artillery(2) (항해 65일차)]]></title>
            <link>https://velog.io/@_coyg_/57.-Artillery2-%ED%95%AD%ED%95%B4-65%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@_coyg_/57.-Artillery2-%ED%95%AD%ED%95%B4-65%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 06 Jun 2023 02:47:27 GMT</pubDate>
            <description><![CDATA[<h2 id="설치">설치</h2>
<pre><code class="language-bash">// 전역 설치
npm install -g artillery@latest

// 프로젝트 설치
npm install -D artillery@latest</code></pre>
<h2 id="테스트-한번-작성해보자">테스트 한번 작성해보자</h2>
<p>온라인 쇼핑몰의 백엔드에서 동작하는 한 API의 성능을 테스트 한다고 가정해보자.</p>
<p>보통 온라인 쇼핑몰은 블랙프라이데이나 사이버먼데이와 같은 행사기간에 트래픽이 급증하는 현상이 발생한다.</p>
<p>백엔드가 위와 같은 대용량 트래픽을 무리 없이 처리할 수 있는지 확인할 수 있는 매우 좋은 방법은 사용자들이 실제로 어떤 행동을 할지 시뮬레이션을 해보는 것이다.</p>
<p>온라인 쇼핑몰에서 상품을 구매하려 할 때 사용자는 다음과 같은 행동들을 할 것이다.</p>
<ul>
<li>상품 키워드 검색</li>
<li>상품 클릭</li>
<li>상품 정보 읽기</li>
<li>장바구니 추가</li>
</ul>
<p>위의 동작들이 동시에 100명에 의해서 실행되도 잘 작동하는지 확인하고자 한다.</p>
<h2 id="구성">구성</h2>
<h3 id="대상-url">대상 URL</h3>
<p>테스트하고자 하는 URL.</p>
<pre><code class="language-yaml">config:
  target: &quot;https://example.com/api&quot;</code></pre>
<h3 id="로드-단계">로드 단계</h3>
<p>각 단계마다 몇 명의 가상의 사용자를 생성할지, 얼마나 자주 요청을 보낼지 등을 정의하면 된다.</p>
<pre><code class="language-yaml">config:
  target: &quot;https://example.com/api&quot;
  phases:
    - duration: 60
      arrivalRate: 5
      name: Warm up
    - duration: 120
      arrivalRate: 5
      rampTo: 50
      name: Ramp up load
    - duration: 600
      arrivalRate: 50
      name: Sustained load</code></pre>
<p>첫번째 단계: 백엔드를 웜업하는 (느린 증가)단계이다. 60초마다 5명의 가상 사용자를 백엔드로 보냄.
두번째 단계: 120초 동안 5명의 가상 사용자로 시작해서 매 초마다 수를 증가시켜 단계가 끝나는 피크에는 50명의 사용자를 보냄.
세번째 단계: 600초 동안 매 초마다 50명의 가상 사용자를 유지하는 지속적인 스파이크를 시뮬레이션.</p>
<h3 id="외부파일에서-데이터-주입">외부파일에서 데이터 주입</h3>
<p>상품 검색은 성능 테스트에서 확인할 섹션 중 하나다. 제품 검색과 같은 동적 콘텐츠에 접근할 때 시스템이 어떻게 처리하는지 확인하는 것이 좋다.</p>
<p>artillery에서는 외부 csv파일을 불러와서 시나리오의 변수로 주입시킬 수 있다.</p>
<pre><code class="language-txt">// keywords.csv
computer
video game
vacuum cleaner
toys
hair dryer</code></pre>
<p>위와 같은 파일이 있을 때</p>
<pre><code class="language-yaml">config:
  ...
  ...
  payload:
    path: &quot;keywords.csv&quot;
    fields:
      - &quot;keyword&quot;</code></pre>
<p>payload 키로 불러올 수 있다.</p>
<ul>
<li>path: csv파일의 경로</li>
<li>fields: 테스트 시나리오에서 사용하고자 하는 변수 이름 (파일의 한 줄에 값이 여러 개가 존재한다면 <code>fields</code>의 value값도 여러 개 선언할 수 있다)</li>
</ul>
<h2 id="시나리오">시나리오</h2>
<p>위에서는 테스트에 필요한 구성을 설정했다면 이제 실제로 가상의 사용자들이 어떤 과정을 거치면 좋을지 시나리오를 구상해볼 것이다.</p>
<p>각 가상 사용자들에 대해서 다양한 시나리오를 정의할 수 있고 각 시나리오는 한개 이상의 동작을 수행한다.</p>
<h3 id="시나리오와-흐름-추가">시나리오와 흐름 추가</h3>
<p>테스트 스크립트에 scenarios를 추가해아한다.</p>
<pre><code class="language-yaml">scenarios:
  - name: &quot;Search and buy&quot;
    flow:
      - post:
          url: &quot;/search&quot;
          json:
            kw: &quot;{{ keyword }}&quot;</code></pre>
<ul>
<li>가상 사용자마다 기본 URL에 대한 <code>POST /search</code> 요청을 생성한다.</li>
<li>요청 바디에는 <code>kw</code>(JSON 객체)가 있어야 하고 config.payload의 키워드 중 하나로 설정한다.<ul>
<li>예를 들어 가상의 사용자 A는 <code>{ &quot;kw&quot;: &quot;toys&quot; }</code>를 요청으로 보내고, 가상의 사용자 B는 <code>{ &quot;kw&quot;: &quot;computer&quot; }</code>를 요청으로 보낸다.</li>
</ul>
</li>
</ul>
<h3 id="응답받은-변수-사용">응답받은 변수 사용</h3>
<p>다음으로는 백엔드로부터 반환받은 결과값의 상세정보를 조회하는 것이다.</p>
<pre><code class="language-yaml">scenarios:
  .
  .
    - post:
      .
      .
      capture:
        - json: &quot;$.results[0].id&quot;
        as: &quot;productId&quot;</code></pre>
<ul>
<li><code>POST /search</code> 요청을 보내면 백엔드는 키워드가 포함된 객체들을 배열로 반환해준다. 첫 번째 결과물의 ID만 필요하다고 했을 때 capture옵션을 사용하여 <code>id</code> 프로퍼티를 <code>productId</code>에 저장할 수 있다.</li>
</ul>
<p>저장된 <code>productId</code>는<code>GET /product/:productId/details</code> 요청 등에 사용할 수 있다.</p>
<pre><code class="language-yaml">scenarios:
  .
  .
    - post:
      .
      .
    - get:
      url: &quot;/product/{{ productId }}/details&quot;</code></pre>
<h3 id="테스트-일시정지">테스트 일시정지</h3>
<p>가상의 사용자가 요청을 보낸 뒤 사이트에 머무르는 것을 시뮬레이션할 수 있다.</p>
<pre><code class="language-yaml">.
.
- get:
  url: &quot;/product/{{ productId }}/details&quot;
- think: 5</code></pre>
<ul>
<li>위의 <code>think: 5</code>는 가장 최근 요청인 get 요청을 보낸 뒤 5초 동안 테스트가 일시정지된다.</li>
</ul>
<h3 id="시나리오-이어서">시나리오 이어서..</h3>
<p>상품을 장바구니에 추가하는 시나리오를 생각해보자. 이 동작을 수행하는 요청은 <code>POST /cart</code>이다. 요청 바디로 <code>productId</code>가 필요하다.</p>
<pre><code class="language-yaml">.
  .
    .
      - post:
          url: &quot;/cart&quot;
          json:
            productId: &quot;{{ productId }}&quot;</code></pre>
<p>여기서 사용되는 <code>productId</code>는 <code>POST /search</code> 요청 때 캡쳐해둔 <code>productId</code>이다.</p>
<h1 id="성능-테스트-실행">성능 테스트 실행</h1>
<pre><code class="language-yaml"># search-and-add-to-cart.yml
config:
  target: &quot;https://example.com/api&quot;
  phases:
    - duration: 60
      arrivalRate: 5
      name: Warm up
    - duration: 120
      arrivalRate: 5
      rampTo: 50
      name: Ramp up load
    - duration: 600
      arrivalRate: 50
      name: Sustained load
  payload:
    path: &quot;keywords.csv&quot;
    fields:
      - &quot;keyword&quot;

scenarios:
  - name: &quot;Search and buy&quot;
    flow:
      - post:
          url: &quot;/search&quot;
          json:
            kw: &quot;{{ keyword }}&quot;
          capture:
            - json: &quot;$.results[0].id&quot;
              as: &quot;productId&quot;
      - get:
          url: &quot;/product/{{ productId }}/details&quot;
      - think: 5
      - post:
          url: &quot;/cart&quot;
          json:
            productId: &quot;{{ productId }}&quot;</code></pre>
<p>위의 파일이 최종 테스트 스크립트이다.</p>
<p>테스트 실행 방법:<code>artillery run search-and-add-to-cart.yml</code></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[56. Artillery(1) (항해 64일차)]]></title>
            <link>https://velog.io/@_coyg_/56.-Artillery1-%ED%95%AD%ED%95%B4-64%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@_coyg_/56.-Artillery1-%ED%95%AD%ED%95%B4-64%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 05 Jun 2023 12:47:37 GMT</pubDate>
            <description><![CDATA[<h1 id="artillery">Artillery</h1>
<ul>
<li>성능 테스트 툴킷. </li>
</ul>
<h2 id="성능-테스트">성능 테스트?</h2>
<p>Artillery는 두 가지 성능 테스트를 수행할 수 있다.</p>
<ol>
<li><p>부하 테스트(시스템에 부하를 가하는 테스트)</p>
<ul>
<li>로드(부하) 테스트: 예상되는 사용 패턴과 부하 조건을 기반으로 시스템이 얼마나 잘 작동하는지 테스트.<ul>
<li>응답시간, 처리량, 자원사용량 등 측정, 시스템의 성능 한계/저하 발생 지점 식별.</li>
<li>정상적인 운영 상황에서의 성능 확인</li>
</ul>
</li>
<li>스트레스 테스트: 예상되는 부하 이상의 작업 처리 시 성능&amp;안전성 평가.<ul>
<li>최대 부하를 넘어서는 트래픽/동점자 수 가정.</li>
<li>과부하 상황에서 응답시간, 에러율, 처리량 등 측정, 시스템의 신뢰성 &amp; 견딜 수 있는 부하 확인.</li>
</ul>
</li>
<li>soak(평균|지속 부하) 테스트: 오랜 기간 동안 지속적인 부하를 가하여 성능과 안정성을 테스트.<ul>
<li>지속적인 부하에 대해 얼마나 안정적으로 작동하는지</li>
<li>장시간 동안의 운영 중에 발생할 수 있는 문제/성능저하 확인 (안정성, 리소스/메모리 누수 등)</li>
</ul>
</li>
</ul>
</li>
<li><p>지속적인 기능 테스트(시스템이 의도대로 작동하는 지 테스트)</p>
</li>
</ol>
<h2 id="뭘-테스트할-수-있는지">뭘 테스트할 수 있는지?</h2>
<ul>
<li>주로 백엔드.. API, 채팅, 게임, 데이터베이스, 메시지 브로커 등등 네트워크를 통해 통신할 수 있는 모든 시스템/서비스.</li>
<li>다양한 프로토콜 지원: HTTP, 웹 소켓, 소켓io 등</li>
</ul>
<h2 id="일반적인-사용-시나리오">일반적인 사용 시나리오</h2>
<ol>
<li>일시적인 부하 테스트를 수행하여 개별 API나 마이크로서비스의 성능 특성 탐색. 필요한 경우 성능 최적화 수행.</li>
<li>새로운 서비스의 출시 전 대규모 부하 테스트 수행 / 대규모 트래픽의 처리를 위한 애플리케이션과 인프라 준비.</li>
<li>Running tests against staging/feature environments as part of a CI/CD pipeline to catch performance regressions early, and to verify SLOs</li>
<li>Adding synthetic traffic in production to maintain a margin of safety against traffic spikes</li>
<li>Running synthetic monitoring against key APIs from multiple geographical locations to verify that key transactions &amp; flows work as expected, and alert if anything breaks</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[55. WIL-07 (항해 64일차)]]></title>
            <link>https://velog.io/@_coyg_/55.-WIL-07-%ED%95%AD%ED%95%B4-64%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@_coyg_/55.-WIL-07-%ED%95%AD%ED%95%B4-64%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 05 Jun 2023 01:13:02 GMT</pubDate>
            <description><![CDATA[<p>지난 4주 동안 TIL, WIL을 작성하지 않았다.</p>
<p>오늘부터라도 다시 시작해보려 한다..</p>
<p>4주 전부터 WIL 회고의 주제는 &#39;협업을 하며 느낀 점 (스스로 아쉬웠던 점 / 보완하고 싶은 점)&#39;이다.</p>
<p>그 동안 꾸준히 기록을 해왔던 것이 아니라 잊은 점도 있겠지만 최대한 기억나는대로 써보려 한다.</p>
<h3 id="협업을-하며-느낀-점">협업을 하며 느낀 점</h3>
<ul>
<li>이런 프로젝트가 처음이어서 역할 분담이 제대로 되었는 지 의문이다 (내가 맡은 부분은 금방 끝나서 다른 팀원들에 비해 붕 뜨는 시간이 있었다..고나 할까..)</li>
<li>위 항목과 이어서, 시간이 뜬다면 뭐든 내가 찾아서 더 연구해보고 개선했어야 했는데 그 부분에서 많이 부족했던 것 같다.</li>
<li>의견이 다른 것도 이해하고 그 의견차이로 갈등?이 생길 수 있다는 것도 이해한다. (물론 우리 팀은 다들 사람이 좋아서 갈등이 생긴 것 같지는 않다). 하지만 프로젝트와 디테일에 대해 모두가 같은 이해를 하고 있는지 파악하는 것은 또 다른 일인 것 같다. 예를 들어, 어떤 한 로직에 대해 A와 B가 이해한게 서로 완전 다른데 그걸 파악하는게 쉽지 않은 것 같다.</li>
<li>시간이 많이 오래 걸리더라도 프로젝트의 아주 사소한 부분까지도 모든 팀원이 완벽하게 같은 이해를 하고 넘어가는 게 좋을 것 같다는 생각이 들었다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[01 CPU와 메모리]]></title>
            <link>https://velog.io/@_coyg_/01-CPU%EC%99%80-%EB%A9%94%EB%AA%A8%EB%A6%AC</link>
            <guid>https://velog.io/@_coyg_/01-CPU%EC%99%80-%EB%A9%94%EB%AA%A8%EB%A6%AC</guid>
            <pubDate>Sun, 04 Jun 2023 11:24:35 GMT</pubDate>
            <description><![CDATA[<h1 id="cpu">CPU</h1>
<h2 id="구성">구성</h2>
<ol>
<li>ALU (Arithmetic Logic Unit): 산술논리 연산장치.<ul>
<li>비교, 판단, 연산 담당</li>
</ul>
</li>
<li>CU (Control Unit): 제어부.<ul>
<li>명령어의 해석과 올바른 실행을 위해 제어하는 장치.</li>
<li>1) 명령어들이 순서대로 호출되고, 2) 해독하고, 3) 제어 신호를 발생시켜 컴퓨터의 각 장치를 동작하도록 제어하는 장치.</li>
<li>내부 버스: 기억, 연산, 제어 기능을 실현하기 위해 CPU와 주기억장치, 입출력장치, 외부기억장치 등의 제어부 사이를 연결하는 통로.</li>
</ul>
</li>
<li>레지스터: 처리할 명령어 저장.<ul>
<li>연산에 필요한 데이터를 저장하고 빠른 속도로 접근할 수 있는 저장공간.</li>
<li>특수 목적 레지스터:
1) 메모리 주소 레지스터 (MAR): 읽고 쓰기 위한 주기억장치(RAM)의 주소 저장.
2) 프로그램 카운터 (PC): 다음에 수행할 명령어의 주소 저장.
3) 명령어 레지스터 (IR): 현재 실행 중인 명령어 저장.
4) 메모리 버퍼 레지스터 (MBR): 주기억장치에서 읽어온/저장할 데이터 임시 저장.
5) 누산기 (AC): 연산 결과 임시 저장.</li>
</ul>
</li>
<li>캐시 메모리(L1): 처리 속도를 높여주는 역할.<ul>
<li>속도가 빠른 장치와 느린 장치 사이에서 속도차에 따른 병목 현상을 줄이기 위한 범용 메모리.<ul>
<li>(8차선 도로에서 2차선으로 줄어드는 것을 순차적으로 8, 6, 4, 2차선 등 순서대로 감소시키는 것과 비슷)</li>
</ul>
</li>
<li>L1은 CPU에 내장되어있고 데이터 사용/참조에 가장 먼저 사용됨.</li>
<li>여기서 찾지 못하면 L2로 넘어감.</li>
</ul>
</li>
</ol>
<h2 id="동작">동작</h2>
<ol>
<li>명령어 인출 - 수행할 명령어 정보 가져오기</li>
<li>명령어 해독 - opcode라고 하는 명령어 코드를 인출하고 필요한 레지스터 준비</li>
<li>실행 - 해독된 명령어 수행</li>
<li>반영 - 수행 결과를 반영 (출력/저장)</li>
</ol>
<h1 id="메모리">메모리</h1>
<h2 id="캐시-메모리-l2-l3">캐시 메모리 (L2, L3)</h2>
<ul>
<li>휘발성 메모리.</li>
<li>조회가 가장 빠름.</li>
<li>CPU와 주기억장치 사이에 있음.</li>
<li>CPU가 메모리를 읽는 과정에서 자주 조회하는 정보를 캐시 메모리에 저장함으로써 재사용 시 나타날 정보의 거리를 줄임.</li>
<li>가장 먼저 L1에서 찾다가 없으면 L2, L3에서 찾게 됨.</li>
</ul>
<h2 id="주기억장치-ram">주기억장치 (RAM)</h2>
<ul>
<li>CPU가 현재 처리중인 데이터나 명령을 일시적으로 저장.</li>
<li>휘발성 메모리.</li>
<li>보조기억장치(HDD, SSD)보다 접근 속도가 빠름.</li>
<li>모든 프로그램은 실행되기 위해 메모리의 일부를 사용.
1) DRAM (Dynamic RAM)<ul>
<li>전원이 계속 공급되더라도 주기적으로 재충전해야 함.</li>
<li>대용량 기억장치에 사용됨.</li>
<li>흔히 말하는 RAM에 해당.
2) SRAM (Static RAM): 캐시 / 레지스트리.</li>
<li>전원이 공급되는 동안 기록된 내용은 지워지지 않음. 재충전 x</li>
<li>접근 속도가 빠름 but 비쌈. 주로 캐시메모리/레지스터로 사용됨.</li>
</ul>
</li>
</ul>
<h2 id="보조기억장치">보조기억장치</h2>
<ul>
<li>비휘발성 메모리.</li>
<li>설치하는 프로그램, 파일 등 저장.</li>
</ul>
<h1 id="cpu와-메모리">CPU와 메모리</h1>
<h2 id="동작-1">동작</h2>
<ol>
<li>주기억장치: 입력장치에서 입력받은 데이터 / 보조기억장치에 저장된 프로그램 명령어 조회.</li>
<li>중앙처리장치: 프로그램 실행을 위해 주기억장치에 저장된 프로그램 명령어와 데이터를 읽어와 처리 후 결과를 다시 주기억장치에 저장.</li>
<li>주기억장치: 처리 결과를 보조기억장치에 저장 / 출력장치에 전달.</li>
<li>제어장치: 1~3번 과정에서 명령어가 순서대로 잘 실행되도록 각 장치 제어.</li>
</ol>
<h2 id="구조">구조</h2>
<p><img src="https://velog.velcdn.com/images/_coyg_/post/6bf2519a-8616-4330-abb0-9ea9d0adcd38/image.png" alt=""></p>
<h3 id="폰노이만-구조">폰노이만 구조</h3>
<ul>
<li>CPU가 연산하는 데이터들이 보조기억장치에서 <strong>하나의 메모리</strong>에 올라감 (데이터와 명령어 동시 접근 불가능)</li>
<li>제어장치는 ALU한테 데이터의 위치를 알려줌.</li>
<li>메모리가 구분되어있지 않고 하나의 버스를 가지므로 병목현상 발생.</li>
</ul>
<h3 id="하버드-구조">하버드 구조</h3>
<ul>
<li>메모리의 구분: 명령어 메모리 &amp; 데이터 메모리 (데이터와 명령어 동시 접근 가능)</li>
<li>명령어 메모리는 프로그램이 사용할 명령어를 모아두고 명령어에 대한 정보를 제어장치로 전달함.</li>
<li>ALU는 데이터와 명령어를 읽어서 연산 수행.</li>
<li>메모리가 역할 별로 나누어져있기 때문에 속도가 빠름.</li>
<li>하지만 구성이 많아서 비싸고 복잡하기 때문에 고장 확률 O.</li>
</ul>
<h3 id="현대-cpu-구조">현대 CPU 구조</h3>
<ul>
<li>CPU 외부(주기억장치): 폰노이만 구조.<ul>
<li>하나의 메모리, 하나의 버스.</li>
</ul>
</li>
<li>CPU 내부: 하버드 구조.<ul>
<li>RAM과 CPU 사이에 캐시 메모리를 둬서 속도 차이 줄임.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>