<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>brian_kim.log</title>
        <link>https://velog.io/</link>
        <description>만물에 관심이 많은 잡학지식사전이자, 새로운 도전을 꿈꾸는 주니어 개발자 / 잡학지식에서 벗어나서 전문성을 가진 엔지니어로 거듭나자!</description>
        <lastBuildDate>Thu, 05 May 2022 04:05:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>brian_kim.log</title>
            <url>https://images.velog.io/images/brian_kim/profile/079c8d2d-ef72-4073-bd52-17946ccc5d89/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. brian_kim.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/brian_kim" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[2022.5.5(목) 회고]]></title>
            <link>https://velog.io/@brian_kim/2022.5.5%EB%AA%A9-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@brian_kim/2022.5.5%EB%AA%A9-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Thu, 05 May 2022 04:05:02 GMT</pubDate>
            <description><![CDATA[<h3 id="뒤를-돌아보는-시간">뒤를 돌아보는 시간</h3>
<p>이렇게 글을 적게 되는게 얼마 만인지 놀라울 따름이다. 매번 시간이 없어서, 여유가 없어서라는 핑계를 대가며 글을 적는 것은 잠시 미루어두곤 했다. 지금부터 5년전이었나? 군대 전역하고 1년 정도 후이니, 아마 그때쯤이었을 것이다. 여름 방학에 여느 건축학과 학생들은 열심히 유럽 건축 여행기를 찾아보며 여행 루트를 짜고 있을 때, 나는 침대에 엎드려 노트북에 열심히 부자가 되는 법을 찾아보고 있던 때였다. 누구나 그렇지 않을까? 쉽게 돈을 버는 방법, 남들처럼 쿨(?)하게 사는 방법에 대해 관심이 많았던 철부지 대학생이었다. 당시 학교 커뮤니티 페이지에 올라온 글을 보고, 처음으로 취직이 아닌 창업이라는 말도 안되는 길을 걷게 되었다. 그만큼 나는 충동적인 사람이었다. 하고 싶은 건 해야만 했고, 
해보지 못하면 직성이 풀리지 않는 그런 사람.</p>
<blockquote>
<p>우리는 이렇게 작은 아이디어로 이렇게 상도 많이 받았고, 
이만큼 대단한 꿈을 꾸고 있습니다. 
우리와 함께 해줄 사람을 찾습니다.</p>
</blockquote>
<p>엄청 간단한 설명과 조금은 조잡하게 끼워 맞춰진 카드 이미지에는 그런 말들이 적혀 있었다. 보고 있노라면 나도 모르게 이미지를 줄이고, 폰트크기를 바꾸고 조금 촌스러운 폰트는 로보토 같은 깔끔한 폰트로 변경하고.. 원색으로 꾸며진 이미지는 파스텔톤의 정갈한 이미지로 변경하면 좋겠다는 생각을 하면서 나도 모르게 사진갤러리에 저장했었다. 그 이후로는 수업이 귀에 들어오지 않아, 수업만 들어가면 다른 생각만 하며 교수님 이야기는 흘려 들었던 것 같다.(사실 그걸 떠나서 애당초 건축으로부터는 관심이 떠난 후여서 그랬는지도 모른다.) 그 이미지를 하루종일 보면서 밤낮없이 사흘을 해당 아이템을 요목조목 뜯어보며 생각한 끝에 내린 결론은.. 사실 그렇게 긍정적인 판단은 아니었다. 청년 5명에, 하드웨어 프로덕트를 만들어 홈 트레이닝 시장에 들어가겠다. 디자인 아이디어 상품이라 킥 기능만 살리면 정말 작은 시장성은 있어보였지만, 사실 하드웨어 시장바닥에서 살아남기라는 것 자체가 말도 안된다고 생각했다. 첨단 기술도 없고, 이미 가진 네이밍 밸류가 있는 것도 아니며, 지금 있는 시장의 파이를 쪼개기에도 영향력이 한참 부족해보였다.당시 아이템의 대부분 아이디어는 2015년 6월에 한국 최초 출시한 스마트 워치에서 대부분 대체가 가능했기 때문이었다. 근데도 하겠다고 뛰어든 건 뭐랄까.. 미래에 대한 불안감? 현재 아무것도 하지 않는 본인에 대한 실망을 채우려는 얄팍한 시도였는지도 모른다.</p>
<h3 id="나-창업하려구">나 창업하려구!</h3>
<p>당시에 학교에서 마주치는 사람들한테 게임 매크로마냥 내뱉던 대답이었다. 엊그제까지 꿈인 적도 없었으면서 정말 얄팍하게 내 현재에 대한 변명거리 쯤으로 삼으려고 그랬었는지도 모르겠다. 남들은 건축 디자인을 공부하겠다고, 연 몇천만원이 넘는 유학비를 감당하며 졸업후에 유럽 전문 예술학교를 또 다니겠다고 하는데, 나는 그렇게 할 자신이 없었다. 아니 그렇게 하고싶을 만큼 열정이 충분하지 않았다. 학교에 재학중이던 때에 르 꼬르뷔제부터 스티븐 홀, 안도 타다오 같은 유명 거장 건축가를 이야기하며, Fancy한 예술가적 분위기를 좋아하는 학생들이 많았던 것 같은데 도저히 이해도 안될 뿐더러 일단 재미가 없었다. 내가 거장도 아닌데, 거장처럼 행동할 것도 없었고 거장이 되고 싶은 생각도 없었고, 이래저래 분위기가 맞지 않았다.</p>
<blockquote>
<p>개방감, 위요감, 공간감, 공간과의 관계성</p>
</blockquote>
<p>건축을 하다보면 저런 단어들을 자주 마주하게 되는데, 사실 와닿지도 않았다. 물론 좋은 공간이라는 것은 분명히 있다. 여기저기 돌아다니다보면 나도 모르게 편안함을 느끼고 계속 있고 싶어지는 곳들이 분명 있기 때문이다. 그렇기 때문에 유현준 씨같은 사람들이 미디어에 나와, 우리나라의 공간들은 문제가 많다며 지적하는 것이 아닐까 싶긴하다. 그럼에도 불구하고 휴학 포함 7년을 건축분야를 굴러본 내게 남은 것은 글쎄.. 수치를 잘 가늠하는 정도의 감각, 그리고 일반인보다는 조금 나은 스케치 능력. 발표를 자주하다보니 발표 능력 정도가 되시겠다. 어찌됐던 맞지 않는 분야는 털어버려야 직성이 풀리기에 3학년이 되던 5년차에 자퇴를 생각했지만 그것도 쉽진 않았다. 그렇다고 내가 지금 당장 뭘 어떻게 하려는 대안도 없이 뛰쳐나가는 건 답이 없었으니까. 그래서 나름대로 목적있(어보이)는 방황을 시작했다. 남들이 나한테 이렇게 물을 때 이렇게 답했다.</p>
<blockquote>
<p>그래서 넌 졸업하고 뭘하려고? 나 창업하려구!</p>
</blockquote>
<h3 id="기회는-언제나-찾아온다">기회는 언제나 찾아온다.</h3>
<p>긴 인생도 아니고, 겨우 1회 차에 30년 차쯤 되니까 인생에도 나름대로 운명이나 기회라는 것들이 있다는 것을 믿게 되었다. 대부분의 RPG 게임에서는 만렙이 99가 디폴트 값이다. 사람이 보통 최대로 사는 나이가 100살 정도라고 하니, 인생을 압축해서 즐길 수 있게끔 그렇게 레벨링 시스템이 짜여진 것이 아닌가 싶다. RPG 게임도 레벨 30정도에 들어서면서부터는 어느정도 시스템에 익숙해지게 된다. 접속하자마자 내가 사냥해야하는 곳이 맵의 어느지점쯤인지 알게 되고, 한번 사냥해야할 때 어떤 스킬셋이 유리한지 알게되고 어떤 방향으로 키워나가야 할지 조금은 눈에 보이기 시작한다. 물론 고수들의 공략을 확인하지 않으면, 내 선택이 최선인지 알 수는 없지만 나름대로 이런 저런 선택을 하면서 조금씩 강해지기 시작한다. 인생도 마찬가지인 것 같다. 30살쯤 되고 나니, 내가 뭘 해야할지 정도는 감이 잡힌다. 내가 더 공부해야할 것들이 무엇이며 어떤 것들을 공부해야 그 쪽으로 나아갈지 어두운 밤처럼 느껴지고 깜깜해도 무드등이 켜진 것 정도의 밝기의 앞길은 읽어볼 수 있다. </p>
<blockquote>
<p>당시에 다양한 기회들이 나를 덮쳐왔다.</p>
</blockquote>
<p>나는 연애를 쉬어본 적이 없는데(순전히 내 의견이지만, 연애만큼 새로운 것을 시작하게끔 계기를 만들어주는 것은 없다고 생각한다. 사랑의 힘은 강력하다.), 당시 여자친구는 처음으로 다른 분야의 사람이었다. 건축학과 특성상 작업 반경을 벗어나는 관계를 만드는 것 자체가 굉장히 어려웠는데 당시에 데이팅 앱이 유행하기 시작한 시초였는데, 이를 통해서 당시 여자친구를 만나게 되었다. 여자친구는 컴퓨터 공학과 산업 공학을 복수전공하고 본인 분야에 대해서 열심히 공부하고 최선을 다하던 친구였다. 우연찮은 계기로 알고리즘 문제를 푸는 것을 보게되었고 나도 관심이 가게 되었다. 내가 건축 분야를 혐오했던 이유 중에 하나는 논리를 감성으로 풀어나간다는 점이었다. 내가 생각하는 논리는 충분한 증거와 원칙을 가지고 결과로의 정당성을 얻어내는 과정이라고 한다면, 건축의 논리라는 것은 그 증거와 원칙이 디자인의 느낌과 감각에 있었기 때문이다. 내가 마주하게 되었던 프로그래밍은 좀 달랐다. 조금은 수학과 비슷하면서도, 충분한 증거와 원칙이라는 것이 감각이 아닌 절대적인 것이었기 때문이다. 글로 표현하는 것이 서툴러 이상한 표현일 수도 있지만 당시 내 느낌은 그랬다.당시 여자친구가 풀어내는 알고리즘들을 보고, 신선한 충격을 받았다. 이런 걸 공부하는 분야가 있다고? 왜 이걸 이제야 알았을까? 거기에서 온 느낌은 말로 표현할 수 없을만큼 충격적이고 신선했다. 어쨌든 나는 그런 기회를 받아드리기로 했고, 이윽고 결정했다. 이게 뭔지는 모르겠지만, 재미있으니까 공부해야겠다.</p>
<h3 id="학점도-내려놓은-인생">학점도 내려놓은 인생</h3>
<p>결국에는 겉으로는 창업을 외치며, 평소에는 프로그래밍을 공부하고, 학교에서는 엎드리는 이상한 사람이 되었다. 태어나서 단 한번도 책상에서 잠들어본 적 없는 내가.. 이렇게 되버리다니! 나름대로 웃기면서도 정말 즐거운 나날들이었던 것 같다. 아침 저녁으로 창업지원단에서 마련해준 사무실로 출퇴근하면서, 시간이 나면 프로그래밍 책을 읽고, 나름대로 돈을 벌겠다고 시간이 날 땐 과외를 하고, 막상 열심히 다녀야할 대학교에서는 피곤해져서 잠들어버리는.. 신기한 시간들이었다. 당연한 결과였겠지만, 이때부터는 학점을 B에만 맞추자고 생각했던 것 같다. 무슨 이유에서인지는 모르겠으나, 나는 당시에 건축 분야로는 절대 안가게 될거라고 스스로 생각했던 것 같다. 이제는 스스로 결정할 수 있다. 결정하겠다라는 생각을 처음으로 해본 것 같다. 이때부터 조금은 입체적으로 생각할 수 있는 사람이 되었다. 내가 결정하는 것들이 단순히 잘 살기 위함이 아니라, 한번 사는 인생 이것저것 다해보자는 결심을 처음으로 하게 되었다.</p>
<p>뭐 당연한 말이지만, 3학년 이후로 학점이야기..는 별로 하고 싶지 않다. 1,2학년 때는 나름대로 학점에 A도 많고 4점대도 받아본 나름대로 장학생이었던 것 같은데, 대학생이라는 평가잣대에서 3학년 이후의 모습은 사실 너무 막나가는게 아닌가 싶은 생각이 들 정도였다. 동기들한테 듣던 얘기로는 쟤 진짜 저러다가 어쩔려고 그러는지? 인생 너무 막산다라는 이야기도 들리기도 했으니 뭐.. 결론적으로 5년 쯤 뒤에 와서 돌아보니, 내 결정을 놀라워하는 사람도 많고 실제로 부럽다고 하는 사람들도 많으니 그렇게 틀리지는 않은 결정이었던 것 같다.</p>
<h3 id="그래서-지금-삶은-어떤가">그래서 지금 삶은 어떤가</h3>
<p>사실 이런 글을 몇 년전부터 써내려왔으면 좋았겠다라는 생각이 든다. 인생에 남는 것은 &quot;사진&quot;이라는 말도 있지만, 사실 글만큼 생각을 잘 표현하는 매체는 없다. 내가 1살 때부터 만들어온 역사들은 당시의 사진에는 충분히 나와있지만, 내가 했던 생각과 이야기들은 따로 적혀있는 것이 별로 없다. 일기장이 있으면 그 글들을 읽으며 되짚어 가보며 당시의 생각을 회고하기 쉬운데, 지금은 당시의 느낌들을 골똘히 생각해봐야 조금은 따라갈 수 있기 때문이다. 어찌됐던 지금은 충분히 만족하는 삶을 살고 있다. 제작년 말에 졸업을 하며 졸업작품 상도 수상하고 나름대로는 분야에서 큰 회사에도 가서 다녀봤지만, 지금 인생만큼 행복하지 않았다. 스물 다섯에 했던 고민들이 얼추 맞아떨어지는 중이라 스스로에게도 꽤 대견하기도 하고 나름 굉장하다고 생각하기도 한다. </p>
<p>학교를 졸업하던 시기와 맞물려 현실적인 이유로 졸업을 생각하게 되어서 창업팀에서도 나오게 되었고, 이 덕분에 널널해진 시간으로 졸업작품에 매진할 수 있었다. 원래 같으면 7일중 순수 작업시간이 12시간을 채 넘지 못했기 때문에 늘 작업물이 시원찮았었다. 마음에 들지 않았으나, 이미 분야에 대한 정은 다 떨어진 후라 크게 심적으로 힘들지는 않았다. 늘 그렇듯이 담담하게 받아들였던 것 같다. 결론적으로는 졸업 시기에 시간이 많아지게 되서 프로그래밍 공부도 놓치지 않고 열심히 할 수 있었으며, (당시에는 임베디드 분야를 생각하며 공부했다.) 졸업작품도 코로나와 맞물려 직접 건축모형을 만들지도 않아도 되어서 손재주가 나쁜 나로서는 엄청 큰 메리트를 얻었다. 덕분에 드론이라는 매개체와 연결한 산업클러스터라는 나름 신선한 주제로 작업물을 풀어갈 수 있었다. 그래서 3년간 바닥을 기었던 내 성적을 보란듯이 비웃으며 총 10학점 수업인 졸업 설계에서 A+라는 학점과 수상이라는 신기록으로 졸업할 수 있었던 것 같다. 나는 졸업 이후에 일도 하면서 또 추가적으로 공부를 하면서 내가 생각하는 미래에 부합하는 회사들에 지원했고, 그 중 가장 가고싶었던 도메인에 입사해서 8개월을 이어가고 있다. 원래는 웹개발 보다는 임베디드 쪽을 생각하며 공부했지만 공부하던 중에 알게된 여러 생각들이 다시 내 마음을 바꿔 웹 백엔드라는 분야에서 일을 하고 있다.</p>
<p>급하게 마무리 지어야할 것 같은데, 오늘은 5월 5일이기때문에 놀러가야한다.
놀고와서 또 시간이 날 때 글을 마무리 지어야 겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NestJS] Providers]]></title>
            <link>https://velog.io/@brian_kim/NestJS-Providers-otzwoex5</link>
            <guid>https://velog.io/@brian_kim/NestJS-Providers-otzwoex5</guid>
            <pubDate>Sun, 10 Oct 2021 09:04:38 GMT</pubDate>
            <description><![CDATA[<h1 id="providers">Providers</h1>
<p>프로바이더는 Nest의 기본이 되는 개념이다. 이해가 쉽지 않아서 공식문서를 보며 정리하고 있는 중이다. 대부분의 기본 Nest 클래스는 서비스, 리포지토리, 팩토리, 헬퍼등 프로바이더로 분류된다. 이렇게 구분하는 방식 자체가 프로바이더(Provider)인 것 같다. </p>
<p>기본적으로 프로바이더의 중심 컨셉은 종속성으로 <strong>주입</strong>할 수 있다는 것이다. 주입할 수 있다는 이야기는 <code>@Injectable()</code> 데코레이터가 붙어있다는 것이다. 전체 애플리케이션의 중심에 있는 <code>AppService</code>에 붙은 <code>@Injectable()</code>은 Provider화 하기 위한 하나의 방식이다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/ce117bc9-0cdc-43dd-bb32-76b4c9353592/image.png" alt=""></p>
<blockquote>
<p>이를 통해 NestApp 내부의 객체는 <strong>서로 다양한 관계</strong>를 만들 수 있으며 객체의 인스턴스를 &quot;<strong>연결</strong>&quot;하는 기능은 대부분 Nest 런타임 시스템에 의해 짜여져서 애플리케이션으로서 작동한다는 이야기다.</p>
</blockquote>
<h2 id="예제로-살펴보는-providers">예제로 살펴보는 Providers</h2>
<h3 id="srcuseruserservicets">src/user/user.service.ts</h3>
<pre><code class="language-ts">import { Injectable } from &#39;@nestjs/common&#39;;
import { UserDto } from &#39;./dto/user.dto&#39;;
@Injectable()
export class UserService {
  private users: UserDto[] = [
    new UserDto(&#39;kim1&#39;, &#39;브라이언 김&#39;),
    new UserDto(&#39;park1&#39;, &#39;존 박&#39;),
  ];
  findAll() : Promise&lt;UserDto[]&gt; {
    return new Promise((resolve) =&gt;
      setTimeout(
        () =&gt; resolve(this.users),
        100,
      ),
    );
  }
  findOne(id: string) : UserDto | object {
    const foundOne = this.users.filter(user =&gt; user.userId === id);
    return foundOne.length ? foundOne[0] : { msg: &#39;nothing&#39; };
  }
  saveUser(userDto: UserDto) : void {
    this.users = [...this.users, userDto];
  }
}</code></pre>
<p>3 line에서 <code>@Injectable()</code>을 선언해서, 이 싱글톤 객체(서비스)의 Dependency가 생성된다. Controller에서 사용할 로직은 Service 영역에서 사용할 수 있도록 짜여져 있고, 선언된 각 <code>Method( ex) findOne, saveUser)</code>들은 데이터를 조작하고 생성하고 조회하거나 삭제하는(CRUD)의 역할을 담당한다.</p>
<p>위와 같이 서비스 싱글톤 객체를 만들면, 메모리에 떠있기만 한다. 객체가 살아나긴 했는데 어떻게 쓸 수 있게 되는지 알아보자. 따라서 Controller의 소스를 만들어보자!</p>
<h3 id="srcuserusercontrollerts">src/user/user.controller.ts</h3>
<pre><code class="language-ts">import { Body, Controller, Get, Param, Post, Res } from &#39;@nestjs/common&#39;;
import { UserDto } from &#39;./dto/user.dto&#39;;
import { UserService } from &#39;./user.service&#39;;
@Controller(&#39;user&#39;)
export class UserController {

  // 의존성(Dependency) 주입
  **constructor(private userService: UserService) {
    this.userService = userService;
  }**
  @Get(&#39;list&#39;)
  findAll(): Promise&lt;UserDto[]&gt; {
    return this.userService.findAll();
  }
  @Get(&#39;:userId&#39;)
  findOne(@Param(&#39;userId&#39;) id: string): any | object {
    return this.userService.findOne(id);
  }
  @Post()
  saveUser(@Body() userDto: UserDto): string {
    this.userService.saveUser(userDto);
    return Object.assign({
      data: { ...userDto },
      statusCode: 201,
      statusMsg: `saved successfully`,
    });
  }
}</code></pre>
<p>위의 Controller 코드를 통해서 살펴보자. Controller에는 생성자가 존재하고 해당 생성자에는 <code>UserService</code>라는 타입의 <strong>userService argument</strong>를 받아 UserController 내부의 멤버 변수에 주입한다. </p>
<blockquote>
<p>생성자를 통해서, 객체 생성될 때 Provider을 넣어주는 것을 아마 <strong>주입</strong>이라고 표현하는 것 같다. <code>@Injectable()</code>은 결국 <strong>주입</strong>될 수 있도록 의존성(Dependency)를 만들어주는 것이다.</p>
</blockquote>
<p>코드만 떼어서 살펴보면 아래와 같다. 결국은 이렇게 하게되면 UserService라는 싱글톤 객체를 Controller에 넣어주게되서, 내부 메서드를 사용할 수 있게 된다. 넣어줄 수 있는 객체 자체를 <code>Providers</code>이라고 부른다. 넣어지는 것을 <code>의존성 주입(Dependency Injection, DI)</code>이라고 부른다.</p>
<pre><code class="language-ts">constructor(private userService: UserService) {
    this.userService = userService;
  }</code></pre>
<h2 id="ioc와-di">IOC와 DI</h2>
<h3 id="iocinversioin-of-control-제어-역전">IOC(Inversioin Of Control, 제어 역전)</h3>
<p>메소드나 객체의 호출 작업을 개발자가 따로 코드를 작성해서 이루어지는 것이 아니라 Nest의 경우 Application 내부의 독자적인 제어(외부)에서 결정되는 것을 의미한다. 기존 프로그래밍 언어에서 객체나 인스턴스는 new와 같은 생성 지시어를 이용해서 메모리를 할당받는 식으로 직접 수행했다. 하지만 IOC의 개념이 도입된 NestJS에서는 세부적인 설정만을 명시하고 Nest가 인스턴스 lifeCycle을 제어하도록 위임한다는 뜻이다.</p>
<blockquote>
<p>정말 쉽게 말해서, 내가 직접 Service 인스턴스나, Controller 인스턴스 혹은 Module 인스턴스같은 것들을 직접 필요에따라 인스턴스를 생성하고 삭제할 필요가 없어지는 것을 의미한다. 어떤 기능을 하는지, 어떻게 주입되는지에 대한 적절한 설정만 해두면 Application이 Runtime에 직접 이를 조정하고 제어한다.</p>
</blockquote>
<h3 id="didependency-injection-의존성-주입">DI(Dependency Injection, 의존성 주입)</h3>
<p>의존성 주입이라는 것은 <strong>의존</strong>적인 객체(<code>Controller</code> 객체에 <code>Service</code>객체를 넣어서, <code>Controller</code>에서 <code>Service</code>의 메서드를 <code>call</code>할 수 있도록 넣어서 사용)를 직접 생성하지 않고 외부에서 결정한 뒤 연결하는 것을 의미한다. DI를 내포한 코딩(<code>@Injectable()</code>)을 통해서 객체 지향성을 보장하며, 모듈간의 결합도를 낮추고, IOC의 구현에 적합한 플랫폼 부품(<code>Provider</code>)를 작성할 수 있게 된다.</p>
<blockquote>
<p>윗 글을 정리해보자면 DI에 의해 주입된 의존성 명시에 의해 NestJS는 IOC를 지원하고 수행한다. 의존성을 가지고 주입될 수 있도록 의존 관계를 명시하고, 의존관계에 묶인 함수, 클래스, API등을 묶어서 처리할 수 있도록 해주므로 서비스의 동작을 추상적으로 연결하는 것을 쉽게 만들어 준다.고 이해했다.</p>
</blockquote>
<blockquote>
<p>스프링에서 중심개념이 튀어나왔기 때문에 스프링 개념으로 설명을 해야한다. 간단히 요약해보자면, <code>provide</code>는 <strong>key</strong>, 아래있는 <code>use...</code>로 쓴 것이 <strong>value</strong>로 Nest Application 내부의 <code>IoC Container</code>에 등록된 뒤, <strong>DI</strong>를 진행(resolve)할 수 있다.</p>
</blockquote>
<h2 id="provider의-실행-과정">Provider의 실행 과정</h2>
<ol>
<li><code>@Injectable()</code> 데코레이터를 발견하면 해당 클래스를 <code>Nest IOC 컨테이너</code>가 관리할 수 있는 <code>클래스로 선언</code>한다.</li>
<li><code>Controller</code>에서 해당 <code>Provider Token</code>에 대한 의존성을 생성자 주입(DI)과 함께 생성한다.</li>
<li>Module에서 <code>Provider Token</code>을 해당 <code>Provider</code>의 클래스와 연결한다.</li>
</ol>
<pre><code class="language-ts">// 코드 작성시
@Module({
      controllers: [UsersController],
      providers: [UsersService],
})

// 실제 컴파일될 때 코드
@Module({
  controllers: [UsersController],
  providers: [
        {    
          provide: UsersService,
          useClass: UsersService,
        },
        ];
})</code></pre>
<p>위와 같은 종속성 처리는 부트스트랩(<code>main.ts &gt; bootstrap();</code>)에 의해 발생한다.</p>
<h2 id="custom-provider-살펴보기">Custom Provider 살펴보기</h2>
<p>NestJS의 Provider에서 좀 어렵기도하고 흥미롭기도 한 부분이 <code>Custom Provider</code> 이부분이다. 원하는 목적과 최적화 성능에 맞춰 개발자가 <code>Custom Provider</code>를 정의하고 사용할 수 있는데 예시 코드를 작성하며 이해해 보았다.</p>
<h3 id="usevalue">useValue</h3>
<p>모형 객체에 <code>실제 구현을 대체</code>하는데 용이하다.</p>
<pre><code class="language-ts">import { connection ] from &#39;./connection&#39;; // 외부 파일의 객체
@Module({
   providers: [
        {
        provide: UsersService,      //사용할 provide 
        useValue: ${대체할 Provider},//실제 provide
        },
    ],
})
export class AppModule {}</code></pre>
<p>혹은 <code>문자열 값 토큰</code>을 외부 파일에서 가져온 다른 <code>객체와 연결</code>하는 기능을 제공할 수도 있다.</p>
<pre><code class="language-ts">import { connection } from &#39;./connection&#39;; //외부 파일의 connection 객체

@Module({
    provide: &#39;CONNECTION&#39;, // 문자열 토큰
    useValue: connection, //해당 토큰과 연결할 외부 파일 객체
    },
  ],
});
export class AppModule{ }        </code></pre>
<p>위의 패턴을 사용해 문자열 형태의 Token으로 객체를 연결하고 싶다면, 종속성을 클래스 이름으로 선언해야 한다.</p>
<pre><code class="language-ts">@Injectable()
export class UsersRepository {
      constructor(@Inject(&#39;CONNECTION&#39;) connection: Connection) {}
}</code></pre>
<h3 id="useclass">useClass</h3>
<p><strong>동적</strong>으로 해결해야 할 필요가 있는 클래스를 결정할 때 쓸 수 있다. 
(ex 추상 or 기본 클래스를 환경에 따라 다르게 넣어주고자 하는 다양한 상황에서)</p>
<pre><code class="language-ts">const configServiceProvider = {
      provider: ConfigService,
      useClass:
          process.env.NODE_ENV === &#39;development&#39; // 환경에 따라 서비스를 정해 연결
              ? DevelopmentConfigService,
              : ProductionConfigService,
    };

  @Module({
      providers: [configServiceProvider],
  })

  export class AppModule {}</code></pre>
<h3 id="usefactory">useFactory</h3>
<p><strong>동적인 Provider 생성</strong>이 가능하다. 실제 Provider는 정의한 <strong>Factory Function</strong>의 return값으로 제공된다. <strong>Factory</strong>의 작업에 다른 Provider를 주입하는 것도 가능하다.
(하지만 이 부분은 주의할 점이 있음, 하단 메커니즘에 표시)</p>
<pre><code class="language-ts">const connectionFactory = {
  provide: &#39;CONNECTION&#39;,
  useFactory: (optionsProvider: OptionsProvider) =&gt; {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider], // 팩토리에 optionProvider를 주입하기 위해 필요
};

@Module({
  providers: [connectionFactory],
})
export class AppModule {}</code></pre>
<p>동적으로 Provider를 생성한다는 말에서 &#39;동적&#39;이라는 말은 <code>Factory Function</code>에서 처리된 결과로 반환받은 <code>Provider</code> 클래스를 주입받는 것과 동일하다. useFactory는 개발할 때 사용하는데, 위의 예시코드처럼 Database Config Service를 Database Service에 항상 주입해놓지 않고 필요시에만 저렇게 Factory를 통해 주입할 수 있다.</p>
<p>이렇게 사용하면 Production/dev 환경을 분리하거나 Database를 변경하면서 사용해야할 때 쉽게 Service를 적용할 수 있도록 config(환경)과 database service(비즈니스 로직)이 분리될 수 있어서 유용하다.</p>
<h3 id="useexisting">useExisting</h3>
<p>기존의 <code>Provider</code>에 대한 별칭 설정이 가능하다. 동일한 <code>Provider</code>에 대한 접근하는 방법이 별칭까지 두가지로 늘어난다.(ex 클래스 기반 <code>Provider</code>와 문자열 토큰 기반 <code>Provider</code>를 별칭을 통해서 분리 시킴, <code>alias</code> 개념임)</p>
<pre><code class="language-ts">@Injectable() //클래스 기반 Provider
class LoggerService {
     // 비즈니스 로직
}

const loggerAliasProvider = { //문자열 토큰 기반 Provider, 별칭 생성
      provide: &#39;AliasedLoggerService&#39;,
      useExisting: LoggerService, //종속성 설정
};

@Module({
  providers: [LoggerService, loggerAliasProvider],
})
export class AppModule {}</code></pre>
<h3 id="custom-provider-export">Custom Provider Export</h3>
<p>다른 <code>Provider</code>와 동일하게 사용자 지정 Provider 또한 선언된 <code>모듈 내부로 범위가 지정</code>된다. 다른 모듈에 표시하기 위해서는 Export를 통해 내보내기를 수행해야한다. 문자열 토큰을 내보낼수도 있으며, 전체 Provider 객체를 내보낼 수도 있음!</p>
<p><strong>export with Token</strong></p>
<pre><code class="language-ts">const connectionFactory = {
  provide: &#39;CONNECTION&#39;,
  useFactory: (optionsProvider: OptionsProvider) =&gt; {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};

@Module({
  providers: [connectionFactory],
  exports: [&#39;CONNECTION&#39;], // 지정한 토큰만을 export
})
export class AppModule {}</code></pre>
<p><strong>export with the full provider object</strong></p>
<pre><code class="language-ts">const connectionFactory = {
  provide: &#39;CONNECTION&#39;,
  useFactory: (optionsProvider: OptionsProvider) =&gt; {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};

@Module({
  providers: [connectionFactory],
  exports: [connectionFactory], // 전체 Provider 객체를 export
})
export class AppModule {}</code></pre>
<h1 id="마치며">마치며</h1>
<p>대충 이정도면 <code>Providers</code>라는 개념을 이해하기는 쉬울 것 같다. 이전까지는 <code>Providers:[]</code>라고 적혀있으면 멘붕이 왔었는데, 이제는 좀 쉽게 이해할 수 있을 것 같다. 결국엔 내부에서 사용될 객체를 나열해서 집어넣는 것이라고 보면 되겠다. 그 집어넣는 과정에서 config(context or 환경)에 따라 다르게 집어넣거나, 집어넣는 것을 다른 이름으로 집어넣거나 하는 방식에 있어서 <code>use...</code> 어노테이션을 활용하는 것이고... 100% 이해는 안됐지만 나름 이해하려고 노력중이다..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NestJS] Testing _ 공식문서]]></title>
            <link>https://velog.io/@brian_kim/NestJS-Testing-%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C</link>
            <guid>https://velog.io/@brian_kim/NestJS-Testing-%EA%B3%B5%EC%8B%9D%EB%AC%B8%EC%84%9C</guid>
            <pubDate>Sat, 09 Oct 2021 10:11:39 GMT</pubDate>
            <description><![CDATA[<h1 id="testing">Testing</h1>
<p>테스트가 자동화되어있으면 차후에 유지관리 측면에서 혹은 문제가 발생하거나 했을 때의 개발차원의 자원이 과도하게 들어가는 것을 막을 수 있기때문에 필수적으로 취급된다. 자동화를 통해 개발중에 개별 유닛으로 테스트하거나 테스트 스위트를 쉽게 빠르고 반복할 수 있다. 이는 릴리즈의 품질과 성능 목표 충족도를 확인하는데 크게 도움이 된다. 자동화는 적용범위를 늘리고 개발자에게 더 빠른 피드백 루프를 제공한다. 자동화는 개별 개발자의 생산성도 높여주고, 소스 코드 제어 체크인, 기능 통합 및 버전 릴리즈와 같은 중요한 개발 수명주기 단계에서 테스트가 실행되도록 한다.</p>
<p>이러한 테스트는 <code>단위 테스트</code>, <code>종단간(e2e) 테스트</code>, <code>통합 테스트</code>등 다양한 유형에 걸쳐있는 경우가 많다. 단위 테스트의 경우 개별 모듈의 성능을 검사하고 체크하며, e2e테스트는 성능 한계점까지 커버리지를 확인하는 테스트고, 실제 환경과 동일하게 차용해서 확실함을 높인 테스트다. 통합 테스트의 경우 이러한 테스트를 종합적으로 테스트로 구축해서 전반적인 서비스 로직 흐름이 원활하게 돌아가는지 확인하기 위한 테스트다. 테스트가 필수적인 것은 확실히 알 수 있지만, 이를 초기 세팅하는 과정이 귀찮고 지루할 수 있다. Nest는 효과적인 테스트를 위한 다양한 툴과 모범 사례를 공유하고 있다.</p>
<h2 id="nest">Nest</h2>
<ul>
<li>구성 요소(Module)에 대한 <code>기본 단위 테스트</code> 및 <code>애플리케이션에 대한 e2e테스트</code>를 <code>자동</code>으로 구축해준다.</li>
<li>기본 도구 제공(예 : 격리 모듈/어플리케이션 로더를 빌드하는 테스터) </li>
<li><code>Jest</code> 및 <code>Supertest</code>와 통합을 즉시 제공하는 동시에 테스트 도구에 대해 독립적이다.</li>
<li>구성 요소(Module)을 쉽게 모의(Mock)하기 위해서 테스트 환경에서 Nest 종속성 주입 시스템을 사용할 수 있다.</li>
</ul>
<p>언급했듯이 Nest는 특정 도구를 강제하지 않으므로 원하는 <code>테스트 프레임워크</code>를 사용할 수 있다. 필요한 요소(예: 테스트 실행기)를 교체하기만하면 Nest의 기성 테스트의 이점을 계속 누릴 수 있다.</p>
<h2 id="installation">Installation</h2>
<pre><code class="language-bash">$ npm i --save-dev @nestjs/testing</code></pre>
<h2 id="unit-testing">Unit Testing</h2>
<p>예제를 통해서, (공식문서에는 Cats를 이용해서 만든 모듈로 존재하는데, 이를 User로 바꾼다.) 클래스 테스트를 확인해보자. 앞서 언급했듯이 기본 테스트 프레임워크로 <code>Jest</code>가 제공된다. 테스트 실행자 역할을 하며 Mock, Spy 등에 도움되는 assert 함수 및 테스트 이중 유틸이 제공된다. 기본 테스트에서 이런 클래스를 수동으로 인스턴스화해서, 컨트롤러와 서비스가 API대로 동작하는지 확인한다.</p>
<pre><code class="language-ts">users.controller.spec.ts

import { UsersController } from &#39;./users.controller&#39;;
import { UsersService } from &#39;./users.service&#39;;

describe(&#39;UsersController&#39;, () =&gt; {
  let UsersController;
  let UsersService;

  beforeEach(() =&gt; {
    UsersService = new UsersService();
    UsersController = new UsersController(UsersService);
  });

  describe(&#39;findAll&#39;, () =&gt; {
    it(&#39;should return an array of users&#39;, async () =&gt; {
      const result = [&#39;test&#39;];
      jest.spyOn(UsersService, &#39;findAll&#39;).mockImplementation(() =&gt; result);

      expect(await catsController.findAll()).toBe(result);
    });
  });
});</code></pre>
<blockquote>
<p>테스트 파일은 <code>users.controller.spec.ts</code>이나, <code>users.service.test.ts</code>와 같은 네이밍으로 파일이름을 지어야한다. </p>
</blockquote>
<p>위의 샘플코드는 사소한 것이기 때문에 실제 Nest 테스트와는 다르다. 위엔 실제로 의존성 주입도 되어있지 않다. (<code>UsersService</code>의 인스턴스를 <code>UsersController</code>에 전달한다는 점에 유의하자!) 테스트중인 클래스를 수동으로 인스턴스화하는 이러한 형식의 테스트는 프레임워크와 독립적이므로 종종 <code>격리된 테스트</code>라고 합니다. Nest기능을 보다 광범위하게 사용하는 애플리케이션을 테스트하는데 도움이 되는 기능들을 살펴보자.</p>
<h2 id="testing-utilities">Testing utilities</h2>
<p><code>@nestjs/testing</code> 패키지는 보다 강력한 테스트 프로세스를 가능하게 하는 유틸리티 세트를 제공한다. 내장된 <code>Test</code>클래스를 사용하여 이전 예제를 다시 작성해보자.</p>
<pre><code class="language-ts">users.conroller.spec.ts

import { Test } from &#39;@nestjs/testing&#39;;
import { UsersController } from &#39;./users.controller&#39;;
import { UsersService } from &#39;./users.service&#39;;

describe(&#39;UsersController&#39;, () =&gt; {
  let usersController: UsersController;
  let userService: UsersService;

  beforeEach(async () =&gt; {
    const module = await Test.createTestingModule({
        controllers: [UsersController],
        providers: [UsersService],
      }).compile();

    usersService = module.get&lt;UsersService&gt;(UsersService);
    usersController = module.get&lt;UsersController&gt;(UsersController);
  });

  describe(&#39;findAll&#39;, () =&gt; {
    it(&#39;should return an array of users&#39;, async () =&gt; {
      const result = [&#39;test&#39;];
      jest.spyOn(usersService, &#39;findAll&#39;).mockImplementation(() =&gt; result);

      expect(await usersController.findAll()).toBe(result);
    });
  });
});</code></pre>
<p><code>Test</code>클래스는 기본적으로 전체 <code>Nest runtime</code>을 Mock하는 애플리케이션 실행 컨텍스트를 제공하는 데 유용하지만, Mocking 및 재정의를 포함하여 클래스 인스턴스를 쉽게 관리할 수 있는 Hook을 제공한다. <code>Test</code> 클래스에는 모듈 메타데이터 객체를 인수로 사용하는 <code>createTestingModule()</code> 메서드가 있다. (<code>@Module()</code> 데코레이터에 전달하는 동일한 객체). 이 메서드는 몇가지 메서드를 제공하는 <code>TestingModule</code> 인스턴스를 반환한다. 단위 테스트에서 중요한 것은 <code>compile()</code>메서드다. 이 메소드는 의존성이 있는 모듈을 <code>bootstrap</code>하고(애플리케이션이 <code>NestFactory.create()</code>를 사용하여 기존 <code>main.ts</code> 파일에서 <code>bootstrap</code>되는 방식과 유사함) 테스트할 준비가 된 모듈을 반환한다.</p>
<blockquote>
<p><code>compile()</code>메서드는 비동기이므로 컴파일까지 기다려야한다. 모듈이 컴파일 되면 <code>get()</code>메서드를 사용하여 선언하는 <strong>정적</strong> 인스턴스(controller 및 provider)를 검색할 수 있습니다.</p>
</blockquote>
<p><code>TestingModule</code>은 <code>모듈 참조</code> 클래스에서 상속되므로 범위가 지정된 프로바이더(임시 또는 요청 범위)를 동적으로 확인하는 기능이다. <code>resolve()</code>메서드를 사용하여 이 작업을 수행한다.(<code>get()</code>메서드는 정적 인스턴스만 검색할 수 있다.)</p>
<pre><code class="language-ts">const moduleRef = await Test.createTestingModule({
                          controllers: [UsersController],
                          providers: [UsersService],
                    }).compile();

usersService = await moduleRef.resolve(UsersService);</code></pre>
<p><code>resolve()</code>메서드는 자체 <code>DI 컨테이너 하위 트리</code>에서 프로바이더의 고유한 인스턴스를 반환한다. 각 <strong>하위트리</strong>에는 고유한 <strong>컨텍스트 식별자</strong>가 있다. 따라서 이 메서드를 두번 이상 호출하고 인스턴스 참조를 비교하면 같지 않음을 알 수 있다. </p>
<p>프로바이더의 프로덕션 버전을 사용하는 대신 테스트 목적으로 <strong>Custum Provider</strong>로 재정의할 수 있다. 예를 들어 DB에 연결하는 대신 데이터베이스 서비스를 Mock할 수 있다. 다음 섹션에서 재정의를 다루겠지만, 단위 테스트에서 사용할 수 있다.</p>
<h2 id="end-to-end-testing">End-to-end testing</h2>
<p>개별 모듈 및 클래스에 초점을 맞춘 단위 테스트와 달리 <code>엔드-투-엔드(e2e)테스트</code>는 최종 사용자가 프로덕션 레벨에서 가질 수 있는 수준보다 <strong>훨씬 더 디테일하고 총체적인 수준</strong>에서의 <strong>클래스 및 모듈 테스트</strong>다. system, application의 scale이 커질수록 각 API 엔드 포인트의 end-2-end 동작을 수동으로 테스트하기 어렵다. 자동화된 e2e 테스트는 시스템 전반적인 동작이 정확하고 프로젝트 요구사항을 충족하는지 확인하는데 도움된다. e2e 테스트를 수행하기 위해 방금 단위 테스트에서 다룬 것과 유사하게 사용한다. Nest를 사용하면 <code>supertest</code> 라이브러리를 사용해서 HTTP 요청을 쉽게 시뮬레이션 할 수 있다.</p>
<h3 id="userse2e-spects">users.e2e-spec.ts</h3>
<pre><code class="language-ts">import * as request from &#39;supertest&#39;;
import { Test } from &#39;@nestjs/testing&#39;;
import { UsersModule } from &#39;../../src/users/users.module&#39;;
import { UsersService } from &#39;../../src/users/users.service&#39;;
import { INestApplication } from &#39;@nestjs/common&#39;;

describe(&#39;Users&#39;, () =&gt; {
  let app: INestApplication;
  let usersService = { findAll: () =&gt; [&#39;test&#39;] };

  beforeAll(async () =&gt; {
    const moduleRef = await Test.createTestingModule({
      imports: [UsersModule],
    })
      .overrideProvider(UsersService)
      .useValue(catsService)
      .compile();

    app = moduleRef.createNestApplication();
    await app.init();
  });

  it(`/GET users`, () =&gt; {
    return request(app.getHttpServer())
      .get(&#39;/users&#39;)
      .expect(200)
      .expect({
        data: catsService.findAll(),
      });
  });

  afterAll(async () =&gt; {
    await app.close();
  });
});</code></pre>
<p>이 예에서는 앞에서 설명한 몇가지 개념을 기반으로 한다. 이전에 사용한 <code>compile()</code> 메서드 외에도 이제 <code>createNestApplication()</code> 메서드를 사용하여 전체 <code>Nest 런타임 환경을 인스턴스화</code>한다. 실행중인 앱에 대한 참조를 <code>app</code>변수에 저장하여 <code>HTTP</code>요청을 시뮬레이션하는데 사용할 수 있다.</p>
<p>Supertest의 <code>request()</code> 함수를 사용하여 HTTP 테스트를 시뮬레이션한다. 이러한 HTTP 요청이 실행중인 Nest 앱으로 라우팅되기를 원하므로 <code>request()</code> 함수에 Nest의 기반이 되는 HTTP 리스터에 대한 참조를 전달한다.(이는 Express 플랫폼에서 사용할 수 있다.) 따라서 구성 <code>request(app.getHttpServer())</code>.<code>request()</code> 호출은 이제 Nest 앱에 연결되어 래핑된 HTTP 서버를 전달한다. 이 서버는 실제 HTTP 요청을 시뮬레이션하는 메소드를 노출합니다. 예를 들어, <code>request(...).get(&#39;/cats&#39;)</code>를 사용하면 네트워크를 통해 들어오는 <code>get &#39;/cats&#39;</code>와 같은 <strong>실제</strong> HTTP 요청과 동일한 Nest앱에 대한 요청이 시작된다.</p>
<p>이 예에서는 테스트할 수 있는 하드코딩된 값을 간단히 반환하는 <code>UsersService</code>의 대체(test-double) 구현도 제공한다. 이러한 대체 구현을 제공하려면 <code>overrideProvider()</code>를 사용해야 한다. 마찬가지로 Nest는 각각 <code>overrideGuard()</code>, <code>overrideInterceptor()</code>, <code>overrideFilter()</code> 및 <code>overridePipe()</code> 메서드를 사용하여 가드, 인터셉터, 필터 및 파이프를 재정의하는 메서드를 제공한다.</p>
<p>각 재정의 메서드는 커스텀 프로바이더에 대해 설명된 메서드를 미러링하는 3가지 메서드가 있는 객체를 반환한다.</p>
<ul>
<li><code>useClass</code>: 객체(프로바이더, 가드 등)을 재정의할 인스턴스를 제공하기 위해 인스턴스화될 클래스를 제공한다.</li>
<li><code>useValue</code>: 객체를 재정의할 인스턴스를 제공한다.</li>
<li><code>useFactory</code>: 객체를 재정의할 인스턴스를 반환하는 함수를 제공한다.</li>
</ul>
<p>각 재정의 메서드 유형은 차례로 <code>TestingModule</code> 인스턴스를 반환하므로 <strong>fluent style</strong>의 다른 메서드와 연결할 수 있다. 이러한 체인의 끝에 <code>compile()</code>을 사용하여 Nest가 모듈을 인스턴스화하고 초기화하도록 해야한다.</p>
<p>또한 때로는 사용자 정의 Logger를 제공하고 싶을 수도 있다. 테스트가 실행될 때(예: CI 서버에서). <code>setLogger()</code> 메소드를 사용하고 <code>LoggerService</code> 인터페이스를 충족하는 객체를 전달하여 <code>TestModuleBuilder</code>에 테스트중에 기록하는 방법을 지시한다. 기본적으로 오류로그만 콘솔에 기록된다.
컴파일된 모듈에는 다음 표에 설명된 몇가지 유용한 메서드가 있다.</p>
<h2 id="createnestapplication"><code>createNestApplication()</code></h2>
<p>주어진 모듈을 기반으로 Nest 애플리케이션(<code>INestApplication</code>인스턴스)을 만들고 반환한다. <code>init()</code> 메서드를 사용하여 애플리케이션을 수동으로 초기화해야 한다.</p>
<h2 id="createnestmicroservice"><code>createNestMicroservice()</code></h2>
<p>지정된 모듈을 기반으로 Nest 마이크로 서비스(<code>INestMicroservice</code> 인스턴스)를 만들고 반환한다. </p>
<h2 id="get"><code>get()</code></h2>
<p>애플리케이션 환경에서 사용 가능한 컨트롤러 또는 프로바이더(가드, 필터등 포함)의 정적 인스턴스를 검색한다. 모듈 참조 클래스에서 상속된다.</p>
<h2 id="resolve"><code>resolve()</code></h2>
<p>애플리케이션 환경에서 사용할 수 있는 컨트롤러 또는 프로바이더(가드,필터 등 포함)의 동적으로 생성된 범위 인스턴스(요청 또는 일시적)를 검색한다. 모듈 참조 클래스에서 상속된다.</p>
<h2 id="select"><code>select()</code></h2>
<p>모듈의 종속성 그래프를 탐색한다. 선택한 모듈에서 특정 인스턴스를 검색하는데 사용할 수 있다.(<code>get()</code>메서드에서 엄격모드(<code>strict: true</code>)와 함께 사용됨).</p>
<blockquote>
<p>e2e 테스트 파일을 <code>test</code> 디렉토리에 보관하자! 테스트 파일에는 <code>.e2e-spec</code> 접미사가 있어야 한다.</p>
</blockquote>
<h2 id="overriding-globally-registered-enhancers">Overriding globally registered enhancers</h2>
<p>전역적으로 등록된 가드(또는 파이프, 인터셉터 또는 필터)가 있는 경우 해당 인핸서를 재정의하기 위해 몇가지 단계를 더 수행해야 한다. 원래 등록을 요약하면 다음과 같다.</p>
<pre><code class="language-ts">providers: [
    {
    provide: APP_GUARD,
    useClass: JwtAuthGuard,
    },
],</code></pre>
<p><code>APP_*</code>토큰을 통해 가드를 &quot;다중&quot;프로바이더로 등록하는 것이다. 여기서 <code>JwtAuthGuard</code>를 교체하려면 등록시 이 슬롯에 있는 기존 프로바이더를 사용해야 한다.</p>
<pre><code class="language-ts">providers: [
  {
    provide: APP_GUARD,
    useExisting: JwtAuthGuard,
  },
  JwtAuthGuard,
],</code></pre>
<blockquote>
<p><code>useClass</code>를 <code>useExisting</code>으로 변경하여 Nest가 토큰 뒤에서 인스턴스화하는 대신 등록된 프로바이더를 참조하자.</p>
</blockquote>
<p>이제 <code>JwtAuthGuard</code>는 <code>TestingModule</code>을 만들 때 재정의할 수 있는 일반 프로바이더로 Nest에 표시된다.</p>
<pre><code class="language-ts">const module = await Test.createTestingModule({
      imports: [AppModule],
})
    .overrideProvider(JwtAuthGuard)
    .useClass(MockAuthGuard)
    .compile();</code></pre>
<p>이제 모든 테스트에서 모든 요청에 <code>MockAuthGuard</code>를 사용한다.</p>
<h2 id="testing-request-scoped-instances">Testing request-scoped instances</h2>
<p>요청 범위 프로바이더는 들어오는 각 요청에 대해 고유하게 생성된다. 요청이 처리를 완료한 후 인스턴스가 가비지 콜렝팅(Garbage Collecting)된다. 테스트된 요청을 위해 특별히 생성된 종속성 주입 하위 트리에 액세스할 수 없기 때문에 문제가 된다.</p>
<p>우리는(위 섹션을 기반으로)<code>resolve()</code>메서드를 사용해서 동적으로 인스턴스화된 클래스를 검색할 수 있다는 것을 알고 있다. DI 컨테이너 하위 트리의 수명주기를 제어하기 위해 고유한 컨텍스트 식별자를 전달할 수 있다. 
이를 테스트 컨텍스트에서 어떻게 사용하는가?</p>
<p>미리 컨텍스트 식별자를 생성하고 Nest가 이 특정 ID를 사용하여 들어오는 모든 요청에 대한 하위트리를 만들도록 하는 것이다. 이러한 방식으로 테스트된 요청을 위해 생성된 인스턴스를 검색할 수 있다.이를 수행하려면 <code>ContextIdFactory</code>에서 <code>jest.spyOn()</code>을 사용한다.</p>
<pre><code class="language-ts">const contextId = ContextIdFactory.create();
jest
    .spyOn(ContextIdFactory, `getByRequest`)
    .mockImplementation(()=&gt;contextId);</code></pre>
<p>이제 <code>contextId</code>를 사용하여 후속 요청에 대해 생성된 단일 DI 컨테이너 하위 트리에 엑세스할 수 있다.</p>
<pre><code class="language-ts">usersService = await module.resolve(UsersService, contextId);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NestJS] Unit test]]></title>
            <link>https://velog.io/@brian_kim/NestJS-Testing</link>
            <guid>https://velog.io/@brian_kim/NestJS-Testing</guid>
            <pubDate>Sat, 09 Oct 2021 05:51:26 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/brian_kim/post/4bdec260-6c06-4afb-9c13-3ec65eb6d4bd/image.png" alt=""></p>
<h1 id="unit-test-단위-테스트">Unit test (단위 테스트)</h1>
<p>NestJS는 내장된 종속성 주입을 사용해서 쉽게 테스트 코드를 작성할 수 있도록 도와준다! <code>종속성 주입</code>은 일반적으로 클래스가 아닌 <code>인터페이스</code>를 기반으로하지만, TypeScript에서 <code>인터페이스</code>는 런타임이 아닌 컴파일 타임에만 존재한다.(런타임에는 인터페이스는 증발함.) 그렇기 때문에 타입에 대한 100% 신뢰성을 부여하기 어렵다. NestJS에서는 클래스 기반 주입을 사용하는 것이 일반적이다.</p>
<pre><code class="language-ts">import { Test, TestingModule } from &#39;@nestjs/testing&#39;;

describe(&#39;UserService&#39;, () =&gt; {
  let userService: UserService;
  let userRepository: UserRepository;

  beforeEach(async () =&gt; {
    const module: TestingModule = await Test.createTestingModule({
      providers: [UserService, UserRepository],
    }).compile();

    userService = module.get&lt;UserService&gt;(UserService);
    userRepository = module.get&lt;UserRepository&gt;(UserRepository);
  });
}</code></pre>
<p>기존에 Express에서는 <strong>sinon</strong>과 같은 패키지를 사용해서 테스트하려는 <code>Service</code>를 모킹(Mocking)해서 사용했으며, 테스트 프레임워크를 직접 설치해서 사용했었지만 NestJS에서는 특정 도구를 강제하지는 않지만 <code>JEST</code>를 기본 테스트 프레임워크로 제공해주며 테스팅 패키지도 제공하기 때문에 개발자가 다른 도구를 찾는데 소모하는 리소스를 줄일 수 있다. </p>
<p>NestJS에서 제공하는 <code>@nestjs/testing</code>패키지를 사용하면 테스트에 사용되는 종속성만 선언해서 모듈을 만들고 해당 모듈로 <code>UserService</code>, <code>UserRepository</code>를 가져올 수 있다. 따로 단위테스트를 작성하기 위해서는 페이크 데이터를 만들어줄 필요가 있다. 기본적으로 들어갔다 나오는 결과물에 대한 것들을 지정해줘야 실제 테스팅이 이루어지기 때문이다. 물론 다른 프레임워크를 이용하면 데이터를 실제로 만들지 않아도 편리하게 할 수 있다. </p>
<h2 id="jest-mocking">Jest Mocking</h2>
<pre><code class="language-ts">const userRepositorySaveSpy = jest
        .SpyOn(userRepository, &#39;save&#39;)
        .mockResolvedValue(savedUser);</code></pre>
<p>Jest에서는 모킹(Mocking)함수를 기본적으로 제공한다. 모킹은 단위테스트를 작성할 때. 해당 코드가 의존하는 부분을 가짜로 대체해서 만드는 것을 의미한다. 일반적으로는 테스트하려는 코드가 의존하는 부분을 직접 생성하기가 너무 부담스러울때 모킹이 사용된다. 위 코드에서는 <code>SpyOn</code>으로 <code>userRepository</code>의 <code>save</code>함수를 호출하는 것을 Mock하고, 이 Mock된 함수는 <code>mockResolvedValue</code>의 결괏값을 리턴하도록 하고 있다.</p>
<blockquote>
<p>쉽게 말하면, userReposity에서 &#39;save&#39;를 call하는 것을 추적하면서, 결과값이 savedUser가 되도록하는 mocking함수라고 보면 된다.</p>
</blockquote>
<p>이런식으로 Mocking함수에 넣어줄 실제 형태를 만들어서 삽입할 수 있다.</p>
<pre><code class="language-ts">const savedUser: User = { firstName : &#39;brian&#39;, lastName: &#39;Kim&#39; };</code></pre>
<h2 id="nestjs에서-단위-테스트-작성">NestJS에서 단위 테스트 작성</h2>
<h3 id="서비스에서-사용된-updateuser-메서드">서비스에서 사용된 updateUser 메서드</h3>
<pre><code class="language-ts">async updateUser(
  id: number,
  requestDto: UserUpdateRequestDto,
): Promise&lt;User&gt; {
      const userToUpdate = await this.userRepository.findOne({where: { id: id },});

    if(!userToUpdate) {
        throw new BadRequestException(Message.NOT_FOUND_ERROR);
    }

    const { firstName, lastName, isActive);
    user.update(firstName, lastName, isActive);

    return this.userRepository.save(user);
}</code></pre>
<h3 id="유저-정보-수정--존재하지-않는-유저-정보-수정">유저 정보 수정 / 존재하지 않는 유저 정보 수정</h3>
<p>Jest를 이용해서 위의 User 정보를 수정하는 서비스의 단위 테스트를 작성해보도록 하자!
<code>UserService</code>의 <code>updateUser</code> 메서드를 테스트하려고하는데, 이 메서드에서는 두 가지를 테스트해야 한다. 유저 정보가 존재할 때는 성공적으로 수정하고 유저 정보가 존재하지 않을 경우엔 실패하는 로직에 대해서 검증이 필요하다.</p>
<pre><code class="language-ts">describe(&#39;UserService&#39;, () =&gt; {
    describe(&#39;유저 정보 수정&#39;, () =&gt; {
        if(&#39;존재하지 않는 유저 정보를 수정할 경우 NotFoundError 발생시킨다.&#39;, async () =&gt; {
            const userId: number = 1;

                const updateUserDto: UpdateUserDto = {
                      firstName: &#39;John&#39;,
                      lastName: &#39;Park&#39;
            }

                const userRepositoryFindOneSpy = jest
                    .spyOn(userRepository, &#39;findOne&#39;)
                    .mockResolvedValue(undefined);

          try {
                await userService.updateUser(userId, updateUserDto);
          } catch(e) {
                expect(e).toBeInstanceOf(NotFoundException);
                expect(e.message).toBe(Message.NOT_FOUND_ERROR);
          }

          expect(userRepositoryFindOneSpy).toHaveBeenCalledWith({
                where: {
                      id: userId,
                },
          });
        });
    });
})</code></pre>
<p>위의 단위 테스트 코드에서는 존재하지 않는 유저의 정보를 수정할 때는 <code>findOne</code> 메서드가 <code>null</code>값을 반환할 거라고 모킹해준다. <code>updateUser</code> 메서드는 가짜로 <code>null</code>의 값이 반환되는 줄 알고 <code>null</code>일 때, <code>NotFoundError</code>가 발생하는 로직을 실행하게 된다.
<code>expect(e).toBeInstanceOf(NotFoundException)</code>는 이 오류 메시지 객체가 <code>NotFoundException</code> 클래스의 인스턴스인지 확인하는 작업이며, <code>.toBe</code>로 값을 비교해서 올바르게 오류 메시지가 나왔는지 검증할 수 있다.</p>
<h3 id="유저-정보-수정--유저-정보를-성공적으로-수정">유저 정보 수정 / 유저 정보를 성공적으로 수정</h3>
<pre><code class="language-ts">describe(&#39;UserService&#39;, () =&gt; {
  describe(&#39;유저 정보 수정&#39;, () =&gt; {
    it(&#39;유저 정보를 성공적으로 수정한다.&#39;, async () =&gt; {
      const userId: number = 1;

      const updateUserDto: UpdateUserDto = {
        firstName: &#39;John&#39;, 
        lastName: &#39;Park&#39;
        isActive: false,
      };

      const existingUser = User.of({
        id: userId,
        firstName: &#39;Brian&#39;,
        lastName: &#39;Kim&#39;,
        isActive: true,
      });

      const savedUser = User.of({
        id: userId,
        ...updateUserDto,
      });

      const userRepositoryFindOneSpy = jest
        .spyOn(userRepository, &#39;findOne&#39;)
        .mockResolvedValue(existingUser);

      const userRepositorySaveSpy = jest
        .spyOn(userRepository, &#39;save&#39;)
        .mockResolvedValue(savedUser);

      const result = await userService.updateUser(userId, updateUserDto);

      expect(userRepositoryFindOneSpy).toHaveBeenCalledWith({
        where: {
          id: userId,
        },
      });
      expect(userRepositorySaveSpy).toHaveBeenCalledWith(savedUser);
      expect(result).toEqual(savedUser);
    });
  });
})</code></pre>
<p><code>updateUser</code>메서드에서 유저 정보를 찾아서 유저 정보를 정상적으로 수정했다는 로직의 테스트다. 미리 정의해놓은 <code>existingUser</code>을 반환할 거라고 모킹 해주고, 이 반환된 값을 수정해서 저장하면 <code>saveduser</code>을 반환할거라고 Mock했다. 그리고 오류가 없이 정상적으로 처리된 내용을 <code>result</code>에 값을 담고, Jest의 <code>expect</code>를 통해 검증한다. 먼저, <code>.toHaveBeenCalledWith</code>는 Mocking 함수가 특정 인수로 호출되었는지 확인하는데 사용될 수 있고, <code>.toEqual</code>로 개체의 모든 속성을 재귀적으로 비교한다.</p>
<p><code>UserService</code>의 <code>User</code>정보를 수정하는 코드의 일부분을 살펴보았다.</p>
<h2 id="마치며">마치며</h2>
<p>E2E테스트는 (End to End) 종단테스트로 환경에 의존하지만, 단위 테스트는 기본적으로 환경이랑 상관없이 빠르게 실행되어야 한다. E2@테스트에서는 보통 테스트 데이터베이스를 사용하고, 테스트의 신뢰성이 높지만 속도가 느리다는 단점이 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Nestjs] Swagger]]></title>
            <link>https://velog.io/@brian_kim/Nestjs-Swagger</link>
            <guid>https://velog.io/@brian_kim/Nestjs-Swagger</guid>
            <pubDate>Sun, 03 Oct 2021 04:07:40 GMT</pubDate>
            <description><![CDATA[<h2 id=""><img src="https://images.velog.io/images/brian_kim/post/4bdec260-6c06-4afb-9c13-3ec65eb6d4bd/image.png" alt=""></h2>
<h1 id="nestswagger">@Nest/Swagger</h1>
<p><code>Swagger</code>는 <strong>API 문서 자동화도구</strong>이다. Nest를 실질적으로 프로젝트에 적용한 적이 없었기 때문에 이전에는 DB를 기록하는 방식으로 DBdiagram이라는 웹 서비스를 이용했었다. API의 변경사항이 있을때마다 수기로 작성해서 변경시켜줘야하는 부분에서 번거로움이 많았고, 프론트엔드와 의사소통 과정중에 변동사항을 일일히 모아서 적용시켜야 했었다. Swagger라는 Nest 툴을 이용하면 이러한 API 문서를 따로 작성할 필요 없이 구현 코드를 수정하면서 API 문서를 같이 수정할 수 있다. (<del>아무래도 개발자들은 모든걸 코드로 해결하고 싶어하는 것 같다(?)</del>)</p>
<p>만약에 코드와 API 문서를 따로 관리하게 되면, <code>코드는 수정되고 API 문서는 갱신하지 않아 최신화되지 않으면 다른 팀원들에게 공유된 API 문서가 실제 코드내의 API와 다른 문제</code>가 발생할 수 있다. 그리고, <code>일일히 문서화하는 것에서 큰 실수가 발생할 수 있지만 실제 구동을 코드에 영향주지 않으면서 테스트</code>할 수 있다는 점이 크게 장점이다.</p>
<p>다른 장점으로는 Swagger로 작성된 API 페이지를 따로 생성해서 실제로 값을 요청하고 응답을 확인하는 테스트할 수 있는 인터페이스를 제공한다는 것이다. <code>/api/docs</code> 이런 페이지에서 실제로 확인할 수 있다.</p>
<hr>
<h2 id="nestjs에서-swagger-install">NestJS에서 Swagger install</h2>
<p>Swagger를 사용하는 방법은 간단하다. NestJS에서 사용할 수 있도록 모듈이 제공되고 있다. 아래의 모듈들을 설치하면 된다.</p>
<blockquote>
<h3 id="swagger-ui-express를-사용하는-경우">Swagger-ui-express를 사용하는 경우</h3>
</blockquote>
<pre><code class="language-bash">npm install --save @nestjs/swagger swagger-ui-express</code></pre>
<h3 id="nestjsfastify를-사용하는-경우">NestJS(fastify)를 사용하는 경우</h3>
<pre><code class="language-bash">npm install --save @nestjs/swagger fastify-swagger</code></pre>
<hr>
<h2 id="nestjs에서-swagger-사용하기">NestJS에서 Swagger 사용하기</h2>
<h3 id="swagger-home">swagger-home</h3>
<blockquote>
<ol>
<li><code>main.ts</code>에서 <code>SwaggerModule</code>를 사용해서 아래와 같이 초기화한다.</li>
</ol>
</blockquote>
<pre><code class="language-ts">import { NestFactory } from &#39;@nestjs/core&#39;;
import { AppModule } from &#39;src/app.module&#39;;
import { setupSwagger } from &#39;src/util/swagger&#39;;
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
    // ... 생략
  setupSwagger(app);
  await app.listen(3000);
}
void bootstrap();</code></pre>
<p>따로 <code>setupSwagger</code>를 만들 수도 있다. <code>DocumentBuilder</code>로 문서의 기본을 구성할 수 있다. 제목, 설명, 버전 등과 같은 속성을 설정할 수 있는 몇 가지 메서드를 제공한다. API 문서를 만들기 위해 <code>SwaggerModule</code>의 <code>createDocument()</code> 메서드를 사용한다.</p>
<pre><code class="language-ts">import { INestApplication } from &#39;@nestjs/common&#39;;
import { SwaggerModule, DocumentBuilder } from &#39;@nestjs/swagger&#39;;
/**
 * Swagger 세팅
 *
 * @param {INestApplication} app
 */
export function setupSwagger(app: INestApplication): void {
  const options = new DocumentBuilder()
    .setTitle(&#39;NestJS Study API Docs&#39;)
    .setDescription(&#39;NestJS Study API description&#39;)
    .setVersion(&#39;1.0.0&#39;)
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup(&#39;api-docs&#39;, app, document);
}</code></pre>
<p>아래의 코드에서 <code>setup()</code> 메서드를 통해서 <code>Swagger UI를 Mount하는 Path</code>를 설정할 수 있다. 브라우저에서 <a href="http://localhost:3000/api-docs%EB%A1%9C">http://localhost:3000/api-docs로</a> 이동하면 Swagger UI가 표시된다.</p>
<pre><code class="language-ts">SwaggerModule.setup(&#39;api-docs&#39;, app, document);</code></pre>
<p><img src="https://images.velog.io/images/brian_kim/post/dfc5fb23-6e7d-4064-a553-42c7aa423739/image.png" alt=""></p>
<hr>
<h3 id="swagger-controller">swagger-controller</h3>
<p>기초 구성은 끝났으니 이제 만들어진 API에 문서화를 해보자.
@nestjs/swagger에서 제공하는 데코레이터들을 사용하면 된다.</p>
<pre><code class="language-ts">import { ApiTags, ApiOperation, ApiResponse } from &#39;@nestjs/swagger&#39;;

@Controller(&#39;v1/users&#39;)
@ApiTags(&#39;유저 API&#39;)
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  @ApiOperation({ summary: &#39;유저 생성 API&#39;, description: &#39;유저를 생성한다.&#39; })
  @ApiCreatedResponse({ description: &#39;유저를 생성한다.&#39;, type: User })
  async create(@Body() requestDto: UserCreateRequestDto, @Res() res: Response) {
    const user: User = await this.userService.createUser(requestDto);

    return res.status(HttpStatus.CREATED).json(user);
  }
}</code></pre>
<p><code>컨트롤러(Controller)</code>에만 Swagger를 사용하고 Swagger UI를 확인해본다.
<img src="https://images.velog.io/images/brian_kim/post/ad8d113e-4279-49d8-a1e3-f59bd4e67059/image.png" alt=""></p>
<h3 id="swagger-api-test">swagger-api-test</h3>
<p>API에 대한 <code>Swagger UI</code>가 만들어졌는데, <code>Try it out</code>버튼을 클릭하면 API의 동작을 테스트할 수 있는 화면이 나온다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/d3b16961-d0f8-4d29-8808-cbff7046f752/image.png" alt=""></p>
<p><code>Execute</code> 버튼을 클릭하면 API를 호출해서 응답을 확인할 수 있다.</p>
<p><code>@ApiTags()</code>로 ‘<strong>유저 API</strong>’를 설정하였는데 해당 컨트롤러가 어떤 API 인지 설정할 수 있다. 각 API에 대한 설명으로는 <code>@ApiOperation()</code>로 설정할 수 있다. <code>@ApiCreatedResponse()</code>와 같은 <strong>API 응답에 대해서 정의</strong>할 수 있는 데코레이터를 제공한다.</p>
<p><strong>@nestjs/swagger</strong>에서 제공하는 <strong>API 응답 데코레이터</strong>들은 아래와 같다. 개별내용은 나중에 포스팅으로 정리하도록 하겠다. 현재 필요한 내용들은 위에 내용들이 대부분이지만, 추가적인 응답에 대한 정의도 내릴 수 있는 것으로 보인다. 모든 데코레이터는 <code>Api%</code>로 시작한다!</p>
<pre><code class="language-ts">@ApiOkResponse()
@ApiCreatedResponse()
@ApiAcceptedResponse()
@ApiNoContentResponse()
@ApiMovedPermanentlyResponse()
@ApiBadRequestResponse()
@ApiUnauthorizedResponse()
@ApiNotFoundResponse()
@ApiForbiddenResponse()
@ApiMethodNotAllowedResponse()
@ApiNotAcceptableResponse()
@ApiRequestTimeoutResponse()
@ApiConflictResponse()
@ApiTooManyRequestsResponse()
@ApiGoneResponse()
@ApiPayloadTooLargeResponse()
@ApiUnsupportedMediaTypeResponse()
@ApiUnprocessableEntityResponse()
@ApiInternalServerErrorResponse()
@ApiNotImplementedResponse()
@ApiBadGatewayResponse()
@ApiServiceUnavailableResponse()
@ApiGatewayTimeoutResponse()
@ApiDefaultResponse()</code></pre>
<p>유저를 생성하는 API의 코드에서는 <code>UserCreateRequestDto</code> 클래스를 사용하는데 이 클래스는 현재는 Swagger UI에서는 표시되어 있지 않다.</p>
<h3 id="swagger-dto-schema">swagger-dto-schema</h3>
<pre><code class="language-ts">import { ApiPropertyOptional } from &#39;@nestjs/swagger&#39;;

export class UserCreateRequestDto {
  @ApiProperty({ description: &#39;이름&#39; })
  firstName!: string;

  @ApiProperty({ description: &#39;성&#39; })
  lastName!: string;
}</code></pre>
<p><code>UserCreateRequestDto</code> 클래스의 속성에 <code>@ApiProperty()</code> 데코레이터를 사용해서 <code>Swagger 문서화</code>를 할 수 있다. @ApiProperty()에서 제공하는 옵션들을 활용해서 다양한 설정도 할 수 있다. 보통 DTO를 정의할 때는 <code>@Column()</code> 정의가 마무리되는 마지막에 <code>@ApiProperty()</code>를 이용해서 정의해준다. </p>
<p>그렇게 작성하고나면 API 명세와 마찬가지로 Swagger UI에서 <code>UserCreateRequestDto</code> 클래스의 <code>Schema</code>도 확인할 수 있다.</p>
<h3 id="swagger-user-schema">swagger-user-schema</h3>
<pre><code class="language-ts">import { Entity, Column, PrimaryGeneratedColumn } from &#39;typeorm&#39;;
import { ApiProperty } from &#39;@nestjs/swagger&#39;;

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  @ApiProperty({ description: &#39;id&#39; })
  id!: number;

  @Column({
    length: 50,
  })
  @ApiProperty({ description: &#39;이름&#39; })
  firstName!: string;

  @Column({
    length: 50,
  })
  @ApiProperty({ description: &#39;성&#39; })
  lastName!: string;

  @Column({ default: true })
  @ApiProperty({ description: &#39;활동&#39; })
  isActive!: boolean;

  static of(params: Partial&lt;User&gt;): User {
    const user = new User();

    Object.assign(user, params);

    return user;
  }
}</code></pre>
<p>컨트롤러에서 반환하는 타입을 <strong>User로 설정</strong>하였는데 <code>User.ts</code>도 Dto 클래스와 같은 방식으로 <code>Swagger</code>를 사용할 수 있다.</p>
<h2 id="마치며">마치며</h2>
<p>Swagger를 사용하지 않고 Wiki와 같이 API 문서를 따로 관리한다면Swagger보다 더 유연한 API 문서 제공이 가능할 수 있다. 하지만 Wiki를 사용한다면 코드를 수정할 때마다 최신화하는 것을 잊지 말아야 한다. 이 부분이 굉장히 불편하고 실제로 프로젝트를 진행하면서 많은 방해가 되기도한다. 또 추가적으로 Postman처럼 API를 테스트할 수 있는 도구를 제공해야 한다. 물론 Swagger를 통해서 문서화의 일부를 유연하게 가져갈 수 있지만, 문서화를 통해서 진행하는것이 훨씬 더 명확하기 때문에 놓치지 않는 것이 중요하다.</p>
<p>더 많은 @nestjs/swagger의 데코레이터들은 여기에서 확인할 수 있다. 공식문서의 OPENAPI 단락에서 더 많은 정보를 얻을 수 있다.</p>
<blockquote>
<h1 id="reference">Reference</h1>
<p><a href="https://docs.nestjs.com/openapi/introduction">https://docs.nestjs.com/openapi/introduction</a>
<a href="https://docs.nestjs.com/openapi/decorators">https://docs.nestjs.com/openapi/decorators</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NestJS]Controllers]]></title>
            <link>https://velog.io/@brian_kim/NestJSControllers</link>
            <guid>https://velog.io/@brian_kim/NestJSControllers</guid>
            <pubDate>Sat, 25 Sep 2021 06:28:10 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/brian_kim/post/0bd113b8-3ce6-40c5-84d3-384f38cefd46/image.png" alt=""></p>
<h1 id="controllers">Controllers</h1>
<p>컨트롤러는 들어오는 요청(request)를 처리하고 응답(response)를 클라이언트에 돌려주는 역할을 맡는 중심적인 모듈이다. <code>(API).controllers.ts</code>와 같은 파일명으로 작성하게되고, API 디렉토리에 저장하게 된다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/0a785435-d7e7-475e-8a4f-2228d5c25026/image.png" alt=""></p>
<p>컨트롤러의 목적은 <code>애플리케이션에 대한 특정 요청을 수신하는 것</code>입니다. 라우팅 메커니즘은 어떤 컨트롤러가 <code>어떤 요청을 수신하는지 제어</code>합니다. 종종 각 컨트롤러에는 둘 이상의 라우트가 있으며 다른 라우트는 <code>다른 작업을 수행</code>할 수 있다.</p>
<p>기본 컨트롤러를 만들기 위해 <code>클래스</code>와 <code>데코레이터</code>를 사용한다. <strong>데코레이터</strong>는 클래스를 <code>필수 메타데이터와 연결</code>하고 Nest가 라우팅 맵을 만들 수 있도록 한다(<code>요청</code>을 해당 <code>컨트롤러에 연결</code>).</p>
<p><code>Controller.ts</code>에는 비즈니스 로직은 포함되어있지 않고, 실질적인 로직은 Service에 담긴다. 따라서 <code>express</code>에서의 route설정과 동일한 역할을 하게된다. 그렇기 때문에 해당되는 route에 적절한 함수(비즈니스 로직)을 call하는 역할만을 수행한다.</p>
<h2 id="controller-템플릿-생성--기본-형식">Controller 템플릿 생성 &amp; 기본 형식</h2>
<blockquote>
<pre><code class="language-bash">nest g resource [name]</code></pre>
</blockquote>
<pre><code>다음과 같은 명령어를 통해서 Controller의 템플릿 파일을 생성할 수 있다.  위 명령어를 사용해서 생성하게 되면 `name.controller.ts`과 같은 형식으로 파일이 새로 생성된다. 내부는 클래스로 선언된 기본 파일이 만들어진다.

## Routing
예제를 통해서 라우트를 생성하는 방법을 알아보도록 하자. 기본 컨트롤러를 정의하기 위해서는 `@Controller()`과 같은 데코레이터를 사용해야한다. 이전에 공부했던 내용처럼 `@Controller()`과 같이 경로(path)를 지정하지 않으면 기본적으로 `/(루트 경로)`를 통하는 요청을 수신하게 된다. 따라서,컨트롤러 데코레이터에 지정한 경로를 새로 지정하지 않고, API 계층화를 성립시킬 수 있다.

코드를 통해 살펴보자.

```ts
import { Controller, Get } from &#39;@nestjs/common&#39;;
import { UsersService } from &#39;./user.service&#39;;
@Controller(&#39;user&#39;)
    export class UsersController {
         constructor(private readonly usersService:UsersService){ }
    @Get()
    findAll(): Promise&lt;UserEntity[]&gt; {
        return this.usersService.findAll();
    }</code></pre><p>위 코드를 살펴보면 <code>Controller</code>라는 데코레이터로 <code>user</code>라는 라우트를 설정하고 있으며, 거기에 오는 <code>GET HTTP Verb</code>에 대한 응답을 지정하고 있다. <code>contructor</code>를 이용해서 <code>UsersService</code>를 초기화 시켜주고, 내부에서 해당 로직을 사용할 수 있도록 하고 있다. <code>findAll() 내장 메서드</code>를 사용하게 되면, 요청 핸들러가 자바스크립트 객체 또는 배열을 반환할 때 자동으로 <code>JSON</code>으로 직렬화된다. 그러나 <code>자바스크립트 기본 타입</code>(string, number, boolean)을 반환하면 Nest는 직렬화를 시도하지 않고 값만 되돌려보낸다. 이렇게하면 응답처리가 가볍게 처리된다.</p>
<p>응답의 상태코드를 별도로 지정해두지 않으면 성공 코드로, POST 요청의 경우에는 <code>201</code>을 되돌려주고 나머지는 기본적으로 <code>200</code>만을 되돌려준다. 핸들러 수준에서 <code>@HttpCode(...)</code> 데코레이터를 활용하면 이 동작을 변경해줄 수 있다. <code>@HttpCode()</code>나 기타 데코레이터들을 아래에서 다루도록 하자.</p>
<h3 id="요청-객체request-object">요청 객체(Request object)</h3>
<p>핸들러는 종종 클라이언트 요청 세부정보에 액세스할 수 있어야 한다. Get 요청이든, Post 요청이든 서버에 요청이 올 때 내부에 딸려오는 토큰이나 데이터를 가지고 자격권한을 판별해야하니까. Nest는 <code>Express 기반</code>이기 때문에 기본적으로 요청객체 접근이 가능하다. 핸들러의 시그니처에 <code>@Req()</code> 데코레이터를 추가하면 Nest에 주입하도록 지시하고 이를 통해서 요청객체에 접근할 수 있다. 단 사용하기 이전에  <code>@types/express</code>패키지를 미리 설치해줘야 한다.</p>
<blockquote>
<h3 id="함수-시그니쳐란">함수 시그니쳐란?</h3>
<p>함수 시그니처 혹은 메서드 시그니처는 컴파일러가 함수를 구분하기 위한 구성요소라고 한다. 쉽게 말하면 두 가지 다른 함수가 있을 때 이 함수의 구분점이 되는 요소들을 말한다.</p>
</blockquote>
<ul>
<li><ol>
<li>함수의 이름(함수명)</li>
</ol>
</li>
<li><ol start="2">
<li>매개변수(Parameter)의 개수</li>
</ol>
</li>
<li><ol start="3">
<li>매개변수의 타입(Types)</li>
</ol>
</li>
<li><ol start="4">
<li>반환 타입(Return Type)</li>
</ol>
</li>
</ul>
<pre><code class="language-ts">import { Controller, Get, Req } from &#39;@nestjs/common&#39;;
import { Request } from &#39;express&#39;; // 요청객체 express에서 가져오기

@Controller(&#39;user&#39;)// 경로 접두사
export class CatsController {
  @Get() // 요청 라우트
  findAll(@Req() request: Request): string {
    return &#39;This action returns all users&#39;;
  }
}</code></pre>
<p>위의 코드를 살펴보면, <code>express</code>의 기본 타입 패키지에서 <code>Request</code>라는 요청객체를 가져온 것을 확인할 수 있다. 핸들러 내부의 매개변수로 <code>Request타입</code>을 전달함으로서, 컨트롤러 내부에서 요청객체에 접근해서 데이터를 조작할 수 있다. 조작이라기보다는 내부 데이터를 가공해서 어떻게 사용할지를 정하는 과정이겠지만.. 이것을 다시 Service 비즈니스 로직에 필요한 내용들을 분리해서 매개변수로 전달하면 요청객체 내부에 딸려온 데이터나 헤더같은 것을 통해서 다양한 기능을 구현할 수 있다.</p>
<blockquote>
<h4 id="요청객체request">요청객체(Request)</h4>
<p>요청객체는 HTTP 요청 자체의 메타데이터를 나타낸다. 쿼리 문자열(?=&amp;), 매개변수, HTTP 헤더, 본문에 대한 속성 값을 포함단다. 대부분 이러한 속성을 직접 잘라낼 필요는 없다. <code>@Body</code>나 <code>@Query()</code>같은 데코레이터가 미리 준비되어있다! 요청객체에 대한 부분만 좀더 세부적으로 나타내면 좋을 듯 하다.</p>
</blockquote>
<h3 id="요청객체-관련-데코레이터">요청객체 관련 데코레이터</h3>
<ul>
<li>@Req(), @Reqest()
<code>요청객체 전체</code>를 가져오는 데코레이터, 이를 통해서 express의 <code>req</code>인자의 방식으로 요청객체에 접근할 수 있다.</li>
<li>@Res(), @Response()
<code>응답객체 전체</code>를 가져오는 데코레이터, 이를 통해서 express의 <code>res</code>인자의 방식으로 응답객체에 접근할 수 있다.</li>
<li>@Next()
핸들러 처리에서 <code>미들웨어로 사용하기 위해서 다음 콜백을 지정하는 데코레이터</code>다. express의 커스텀 미들웨어의 맛만 봤지만, <code>nestjs에서 미들웨어</code>를 작성하는 방법은 생각해본적이 없지만 공부해보면 좋을 듯하다.</li>
<li>@Session()
핸들러에서 요청객체 내부에 있는 <code>session</code>을 가져오는 데코레이터, 이를 통해 express의 <code>req.session</code>에 접근하는 방식과 동일하게 접근이 가능하다.</li>
<li>@Param(key?: string)
<code>req.params</code>, <code>req.params[key]</code> 와 같이 전달인자에 접근하는 방식이다. </li>
<li>@Body(key?: string)
<code>req.body</code>, <code>req,body[key]</code>와 같이 바디값에 접근하는 방식이다.</li>
<li>@Query(key?: string)
<code>req.query</code>, <code>req.query[key]</code>와 같이 쿼리문자열에 접근하는 방식이다.</li>
<li>@Headers(name?: string)
<code>req.headers</code>, <code>req.headers[name]</code>와 같이 헤더에 접근하는 방식이다.</li>
</ul>
<h2 id="resources">Resources</h2>
<p>이전에는 GET 라우트를 통해서 users 리소스를 가져오는 엔드포인트를 정의했다. 일반적으로 서버 측에 새 레코드를 생성하는 엔드포인트도 제공하려고 한다. 이를 위해 POST 핸들러도 정의해보도록 하겠다.</p>
<pre><code class="language-ts">import { Controller, Get, Post } from &#39;@nestjs/common&#39;;
import { UserEntity } from &#39;./entity/user.entity&#39;;
import { UsersService } from &#39;./user.service&#39;;
@Controller(&#39;user&#39;)
    export class UsersController {
         constructor(private readonly usersService:UsersService){ }
    @Get()
    findAll(): Promise&lt;UserEntity[]&gt; {
        return this.usersService.findAll();
    }
    @Post()
    createUser(): Promise&lt;UserEntity[]&gt; {
         return this.usersService.createNewUser(); 
    }</code></pre>
<p>위와 같이 간단하게 작성해볼 수 있을 것 같다. Nest는 모든 표준 HTTP 메소드에 대해 데코레이터를 제공한다. <code>@Get()</code>, <code>@Post()</code>, <code>@Delete()</code>, <code>@Patch()</code>, <code>@Options()</code>, <code>@Head()</code>, <code>@All()</code> 이를 통해서 express에서 구성했던 엔드포인트를 간단하게 경로 중복코드없이 작성할 수 있다.</p>
<h3 id="route-wildcards">Route wildcards</h3>
<p>패턴 기반 라우트도 지원된다. 별표(*)는 와일드 카드로 사용되며 모든 문자조합과 일치한다.</p>
<pre><code class="language-ts">@Get(&#39;ab*cd&#39;)
findAll() {
    return &#39;This route uses as wildcard&#39;;
    }</code></pre>
<p><code>&#39;ab*cd&#39;</code> 라우트 경로는 <code>abcd</code>, <code>ab_cd</code>, <code>abecd</code> 등의 라우트 경로와 일치한다. <code>?</code>, <code>+</code>, <code>*</code> 및 <code>()</code> 문자는 라우트 경로에 사용될 수 있으며 해당 정규표현식 대응 부분의 하위집합이다. 하이픈(<code>-</code>)과 점(<code>.</code>)은 문자열 기반 경로로 문자 그대로 해석된다.</p>
<h3 id="status-code">Status Code</h3>
<p>위에서 나왔던 내용인데, <code>201</code>로 POST 요청에 대한 응답하는 것을 제외하곤 모든 응답 상태코드는 기본적으로 <code>200</code>이다. 핸들러 레벨에서 <code>@HttpCode(${status code})</code>데코레이터를 추가해서 이러한 동작을 쉽게 변경할 수 있다.</p>
<pre><code class="language-ts">import { HttpCode } from &#39;@nestjs/common&#39;;

...코드 생략...

@Post()
@HttpCode(204)
create() {
  return &#39;This action adds a new user&#39;;
}</code></pre>
<p>종종 상태코드는 정적이 아니지만 다양한 요인에 따라 달라진다. 응답(<code>@Res()</code>를 사용하여 주입)객체를 사용할 수 있다. </p>
<h3 id="headers">Headers</h3>
<p>커스텀 응답헤더를 지정하려면 <code>@Headers()</code> 데코레이터 또는 라이브러리별 응답객체를 사용할 수 있다. (그리고 비즈니스 로직에서는 <code>res.header()</code>을 직접 호출해서 사용한다.)</p>
<pre><code class="language-ts">@Post()
@Header(&#39;Cache-Control&#39;, &#39;none&#39;)
create() {
  return this.usersService.createUser()
}</code></pre>
<h3 id="redirection">Redirection</h3>
<p>응답을 특정 URL로 리디렉션 하려면 <code>@Redirct()</code> 데코레이터 또는 라이브러리별 응답객체를 사용할 수 있다. (그리고 비즈니스 로직에서는 <code>res.redirect()</code>를 직접 호출해서 사용한다.) <code>@Redirect()</code>는 <code>url</code>과 <code>statusCode</code>라는 두개의 인수를 취하며 둘 다 선택사항이다. 생략된 경우는 기본적으로 statusCode의 기본값은 <code>302(Found)</code>이 된다.</p>
<pre><code class="language-ts">@Get()
@Redirect(&#39;https://nestjs.kr&#39;, 301)</code></pre>
<p>가끔 <code>HTTP 상태코드</code> 또는 <code>리디렉션 URL</code>을 동적으로 확인해야 할 수 있다. 다음과 같은 형태로 라우트 핸들러 메서드에서 객체를 반환하면 된다.</p>
<pre><code class="language-ts">{
  &quot;url&quot;: string,
  &quot;statusCode&quot;: number,
}</code></pre>
<p>반환된 값은 <code>@Redirect()</code> 데코레이터에 전달된 모든 인수를 재정의한다. 예를 들면</p>
<pre><code class="language-ts">@Get(&#39;docs&#39;)
@Redirct(&#39;https://docs.nestjs.com&#39;, 302)
getDocs(@Query(&#39;version&#39;) version) {
  if(version &amp;&amp; version === &#39;5&#39;) {
    return { url: &#39;https://docs.nestjs.com/v5/&#39; };
  }
}</code></pre>
<h3 id="route-parameters">Route Parameters</h3>
<p>요청의 일부로 <strong>동적데이터</strong>를 수락해야 하는 경우 정적 경로가 있는 라우트가 동작하지 않는다. (예: <code>GET /users/1</code>은 ID가 1d인 user data를 가져온다.). 매개변수가 있는 라우트를 정의하기위해서 라우트 경로에 라우트 매개변수 토큰 tokens을 추가하여 요청 URL의 해당 위치에서 동적값을 캡처할 수 있다. 아래 <code>@Get()</code> 데코레이터 예제의 경로 매개변수 토큰은 이 사용법을 보여준다. 이렇게 선언된 라우트 매개변수는 <code>@Param()</code> 데코레이터를 사용하여 액세스할 수 있으며, 이는 메소드 시그니처에 추가되어야 한다.</p>
<pre><code class="language-ts">@Get(&#39;:id&#39;)
findOne(@Param() params):string {
  console.log(params.id);
  return `This action returns a #${params.id} user`
}</code></pre>
<p><code>@Param()</code>은 메소드 매개변수(Params)를 데코레이팅한다. 라우트 매개변수를 메소드 본문내에서 장식된 메소드의 매개변수의 속성으로 사용할 수 있도록 한다. 코드에서 보듯이 <code>params.id</code>를 참조해서 <code>id</code> 매개변수에 액세스할 수 있다. 특정 매개변수 토큰을 데코레이터에 전달한 다음에 직접 라우트 매개변수를 참조할 수 있다.</p>
<pre><code class="language-ts">@Get(&#39;:id&#39;)
findOne(@Param(&#39;id&#39;) id : string): string {
      return `This action returns a #${id} user`;
}</code></pre>
<blockquote>
<p>쉽게 말하면 라우트 매개변수에서, <code>@Param()</code>을 전달해서 전체 매개변수를 접근하게 하거나, <code>@Param(&#39;id&#39;)</code>처럼 특정 매개변수에 직접 접근할 수 있도록 하는 방식이다. 이 방식을 이용하면 parameter를 접근해서, 동적으로 요청마다 다른 값들에 대응해서 핸들러가 작동하도록 할 수 있다.</p>
</blockquote>
<h3 id="sub-domain-routing">Sub-Domain Routing</h3>
<p><code>@Controller()</code> 데코레이터는 들어오는 요청의 HTTP 요청의 HTTP 호스트가 특정값과 일치하도록 <code>host</code>옵션을 사용할 수 있다.</p>
<pre><code class="language-ts">@Controller({host : &#39;admin.example.com&#39;})
export class AdminController {
  @Get()
  index(): string {
    return &#39;Admin Page&#39;;
  }
}</code></pre>
<blockquote>
<p>이 부분의 용도가 잘 이해가 가지 않는다.</p>
</blockquote>
<h3 id="scopes">Scopes</h3>
<p>다른 프로그래밍 언어 배경을 가진 사람들의 경우 Nest에서 거의 모든 것이 들어오는 요청에서 공유된다는 사실을 배우는 것은 예상치 못한 일이다. 데이터베이스에 대한 연결 풀, 전역상태의 싱글톤 서비스 등이 있다. <code>Node.js</code>는 모든 요청이 별도의 스레드에서 처리되는 요청/응답 <strong>다중스레드 상태 비저장(Multi-Threaded Stateless)모델을 따르지 않는다.</strong> 따라서 싱글톤 인스턴스를 사용하는 것은 애플리케이션에 완전히 <strong>안전</strong>하다.</p>
<p>그러나 컨트롤러 요청 기반 수명이 바람직한 동작일 수 있는 경우가 있다. 예를 들어 GraphQL 애플리케이션의 요청별 캐싱, 요청 추적 또는 멀티테넌시가 있다.</p>
<h3 id="asynchronicity">Asynchronicity</h3>
<p>우리는 최신 자바스크립트를 좋아하며 데이터 추출이 대부분 <strong>비동기적</strong>이라는 것을 알고 있다. 이것이 Nest가 <code>비동기(async)</code>기능을 지원하고 잘 작동되는 이유다. </p>
<p>모든 비동기 함수는 <code>Promise</code>객체를 반환해야 한다. 즉, Nest가 자체적으로 해결할 수 있는 지연된 값을 반환할 수 있다. 이것의 예를 보자.</p>
<pre><code class="language-ts">Promise 처리법
@Get()
async findAll(): Promise&lt;any[]&gt; {
  return [];
}</code></pre>
<p>위의 코드는 실제로 동작한다. 또한 Nest 라우트 핸들러는 RxJS <code>관찰가능한 스트림</code>을 반환할 수 있으므로 훨씬 더 강력하다. Nest는 자동으로 아래의 소스를 구독하고 마지막으로 내보낸 값을 가져온다.</p>
<blockquote>
<p>RxJS의 Observable과 Promise의 비교에 대한 내용을 글로 따로 남기자.
<a href="https://stackoverflow.com/questions/37364973/what-is-the-difference-between-promises-and-observables">https://stackoverflow.com/questions/37364973/what-is-the-difference-between-promises-and-observables</a></p>
</blockquote>
<pre><code class="language-ts">Observable 처리법
@Get()
findAll(): Observable&lt;any[]&gt; {
  return of([]);
}</code></pre>
<h3 id="request-payloads">Request payloads</h3>
<p>POST 라우트 핸들러의 이전 예제엔 클라이언트 매개변수를 허용하지 않았다. 여기에 <code>@Body()</code> 데코레이터를 추가하여 이 문제를 해결하자. </p>
<p>그러나 <code>TypeScript</code>를 사용하는 경우 <code>DTO(Data Transfer Object : 데이터 전송객체)</code>의 스키마를 결정해야 한다. DTO는 <code>데이터가 네트워크를 통해 전송되는 방식을 정의하는 객체</code>다. TypeScript 인터페이스를 사용하거나 간단한 클래스를 사용하여 DTO 스키마를 확인할 수 있다. 흥미롭게도 여기서 클래스를 사용하는 것이 좋다. 왜냐하면 클래스는 자바스크립트 ES6 표준 기법의 일부이므로 컴파일된 자바스크립트에서 실제 엔티티로 유지된다. 반면 TypeScript 인터페이스는 트랜스 팡리중에 제거되기 때문에 Nest는 런타임에 이를 참조할 수 없다. 파이프와 같은 기능은 런타임에 메타타입에 엑세스 할 수 있을때 추가 가능성을 제공하기 때문에 중요하다. </p>
<h4 id="createuserdto">CreateUserDto</h4>
<pre><code class="language-ts">export class CreateUserDto {
  name: string;
  age: number;
  email: string;
}</code></pre>
<p>기본 속성은 세가지로 설정했다. 이름과, 나이, 그리고 이메일 정보만 가지고 있다. 그런 다음 이를 <code>Controller</code>내부에서 import시키면 새로 만든 DTO를 사용할 수 있다.</p>
<pre><code class="language-ts">import createUserDto from &#39;./interfaces/createUser.dto&#39;;
@Post()
async create(@Body() createUserDto: CreateUserDto) {
  return &#39;This action adds a new user&#39;;
}</code></pre>
<h3 id="handling-errors">Handling errors</h3>
<p>오류 처리에 대한 내용은 따로 글을 작성하자!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NestJS] 기초 개념]]></title>
            <link>https://velog.io/@brian_kim/NestJS-%EA%B8%B0%EC%B4%88-%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@brian_kim/NestJS-%EA%B8%B0%EC%B4%88-%EA%B0%9C%EB%85%90</guid>
            <pubDate>Thu, 16 Sep 2021 05:58:37 GMT</pubDate>
            <description><![CDATA[<p><strong>NestJS</strong>는 효율적이고 확장가능한 NodeJS Server-Side 어플리케이션을 만들기 위한 프레임워크이다. 내부적으로 ExpressJS를 사용하며, 초기 설정을 통해서 Fastify를 사용할 수 있다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/c7f23b07-cfe6-4f8e-a3cf-44ea903d7179/image.png" alt=""></p>
<h1 id="nestjs">NestJS</h1>
<blockquote>
<p>NodeJS 및 Server Side JS를 위한 수많은 우수한 Library와 Helper, Tools가 있지만, 아키텍처 문제를 효과적으로 해결한 라이브러리는 전무하다. 이를 위해서 NestJS 팀은 <code>1.테스트가 용이하며</code>, <code>2.확장 가능및 느슨한 결합</code>, <code>3. 유지 관리에 용이한</code> 조건의 웹 서버 라이브러리로서 NestJS를 개발했다. 아키텍처는 Angular로부터 많은 영감을 받았다.</p>
</blockquote>
<h2 id="설치-방식">설치 방식</h2>
<p>CLI를 통해서 설치한다.</p>
<blockquote>
<pre><code class="language-bash">$ npm i -g @nestjs/cli
$ nest new nest_practice</code></pre>
</blockquote>
<h2 id="src-directory">src directory</h2>
<p><code>nest new nest_practice</code> 명령어를 통해서 새로운 Nest App을 구축하면, <code>node_module</code>, <code>src</code>등과 <code>eslint</code>, <code>tsconfig</code>, <code>prettier</code>등 환경 설정과 같은 파일들이 생성된다. 먼저 src 내부 디렉토리 구조를 살펴보자.</p>
<blockquote>
<pre><code>src
├ app.controller.ts
├ app.controller.spec.ts
├ app.module.ts
├ app.service.ts
⎣ main.ts</code></pre></blockquote>
<pre><code>&gt;&gt;- `app.controller.ts`
하나의 경로(root, `/`)를 지닌 기본 컨트롤러
- `app.controller.spect.ts` 
컨트롤러에 대한 `유닛테스트`
- `app.module.ts`
Nest 어플리케이션의 루트 모듈, 모든 Nest모듈은 이 모듈에 `연결`되어있어야 한다.
- `app.service.ts` 
하나의 메소드를 가진 기본 서비스
- `main.ts`
Nest App instance를 생성하는 함수 `NestFactory`를 사용하는, Nest 어플리케이션의 Entry 파일

## Express.js
---
Nest는 Express를 기반으로하고 있기 때문에 기본 Express 서버코드와 비교해보며 알아보는 것이 도움이 될 수도 있다. 아래 코드는 express에서 `controller`와 `router`를 분리해서 사용하는 예시다.

 ```js
//controller.js
export function sayHello (req, res) {
    res.send(&#39;Hello World!&#39;);
}</code></pre><hr>
<pre><code class="language-js">// router.js
const router = express.Router();
router.get(&#39;/&#39;, sayHello);

export default router;</code></pre>
<hr>
<pre><code class="language-js">// app.js
app.use(&#39;/&#39;, router);</code></pre>
<hr>
<pre><code class="language-js">//http://localhost:3000/
Hello World!</code></pre>
<h2 id="nestjs-1">Nest.js</h2>
<hr>
<h3 id="controller">Controller</h3>
<p>Nest에서 Controller는 Express에서의 <code>Router</code>라고 생각하면된다.
(<code>Service</code>는 바로 다음에 쓸거다.)</p>
<pre><code class="language-js">// src/app.controller.ts
import { Controller, Get } from &#39;@nestjs/common&#39;;
import { AppService } from &#39;./app.service&#39;;

@Controller()
export class AppController {
  constructor(private readonly appService: AppService){}

  @Get()
  sayHello(): string {
    return this.appService.sayhello();
  }
}</code></pre>
<p><code>@Controller()</code>는 express의 <code>app.use(&#39;/&#39;, router)</code>에서 &#39;/&#39;와 같은 역할을 한다. <code>@Controller(&#39;say&#39;)</code> 이렇게 인자로 <code>string</code>을 넘겨주면 express에서 <code>app.use(&#39;/say&#39;, router)</code>로 작성한 코드와 동일한 기능을 한다.</p>
<p><code>AppController</code> 코드를 해석해보면, 루트경로로 <code>GET</code>요청이 들어오면 </p>
<blockquote>
<p>appService 안의 sayHello 함수를 실행하고 결과를 반환해라</p>
</blockquote>
<p>와 동일하게 작동한다. 추가적으로 <code>@Get()</code>, <code>@Post()</code>, <code>@Delete()</code> 등 다른 HTTP 요청 메소드도 동일하게 처리할 수 있는 데코레이터가 있다.</p>
<h3 id="service">Service</h3>
<p>Nest에서 Service는 express에서의 controller라고 생각하면 된다. Nest의 Controller와 비지니스 로직을 분리하기 위해 Service가 존재한다.</p>
<pre><code class="language-js">import { Injectable } from &#39;@nestjs/common&#39;;

@Injectable()
export class AppService {
  sayHello(): string {
    return &#39;Hello Nest!&#39;;
  }
}</code></pre>
<p>위와 같이 메소드를 정의하고 AppModule에서 provider로 등록을 하면 Controller에서 사용할 수 있다.</p>
<pre><code class="language-js">import { Module } from &#39;@nestjs/common&#39;;
import { AppController } from &#39;./app.controller&#39;;
import { AppService } from &#39;./app.service&#39;;

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[네트워크] HTTPS가 동작하는 방식]]></title>
            <link>https://velog.io/@brian_kim/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTPS%EA%B0%80-%EB%8F%99%EC%9E%91%ED%95%98%EB%8A%94-%EB%B0%A9%EC%8B%9D</link>
            <guid>https://velog.io/@brian_kim/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTPS%EA%B0%80-%EB%8F%99%EC%9E%91%ED%95%98%EB%8A%94-%EB%B0%A9%EC%8B%9D</guid>
            <pubDate>Fri, 03 Sep 2021 06:58:42 GMT</pubDate>
            <description><![CDATA[<h1 id="https와-http">HTTPS와 HTTP?</h1>
<h2 id="http">HTTP</h2>
<p>인터넷 상에서 정보를 주고받는 통신목적으로 사용되는 프로토콜이다. 리소스를 받는 쪽을 클라이언트(Client)가 되고, 리소스를 보내주는 쪽이 서버(Server)가 된다. HTTP에 관련된 내용은 이전에 공부한 <a href="https://velog.io/@brian_kim/%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8%EC%99%80-%EC%84%9C%EB%B2%84%EC%9D%98-%ED%86%B5%EC%8B%A0">이전 글 - 클라이언트와 서버의 통신 HTTP</a> 에서 일부 살펴볼 수 있다. 물론 내용은 불충분하지만, 기초적인 HTTP를 이해하는데 무리는 없다.</p>
<h2 id="http의-약점">HTTP의 약점</h2>
<p>HTTP는 사용하기 간편하고, 통신에 적합한 프로토콜이다. 그럼에도 불구하고 모든 통신 프로토콜이 그러하듯 보안과 관련한 몇 가지 약점을 가지고 있는데, HTTP의 약점을 한번 살펴보도록 하자.</p>
<blockquote>
<ul>
<li><code>평문</code>(암호화 하지 않은)통신이기 때문에 도청 가능하다.</li>
</ul>
</blockquote>
<ul>
<li>통신 상대를 확인하지 않기 때문에(<code>인증절차</code>가 없기 때문에) 위장 가능하다.</li>
<li><code>완전성</code>을 증명할 수 없기 때문에 변조 가능하다.</li>
</ul>
<blockquote>
<h3 id="평문이기-때문에-도청-가능하다">평문이기 때문에 도청 가능하다.</h3>
<p>HTTP를 사용한 Request나 Response 통신 내용은 HTTP 자신을 암호화하는 기능은 없기 때문에 통신 전체가 암호화 되지는 않는다. 즉, <code>평문으로 HTTP 메시지를 보내게 된다.</code></p>
</blockquote>
<ul>
<li>TCP/IP는 도청 가능한 네트워크다.</li>
</ul>
<p>TCP/IP 구조의 통신 내용은 전부 통신 도중에 경로에서 엿볼 수 있기 때문이다. 인터넷은 전 세계를 경유하는 네트워크로 되어있다. 어느 서버와 클라이언트가 통신할 때, 통신 경로 상에 있는 네트워크 기기나 케이블이나 컴퓨터 등을 모두 소유하고 있는 경우는 없다. <code>다자간의 통신으로 이루어지기 때문에 메시지가 도청</code>당할 수 있다. <del>통신이 이루어지는동안 지나는 여러 기기들이 있다.</del></p>
<p>같은 세그먼트의 통신은 네트워크 상에 흐르고 있는 패킷을 수집하는 것으로 도청할 수 있다. 패킷을 수집하려면 패킷을 해석하는 <code>패킷 캡처</code>나 <code>스니퍼</code>라는 툴을 이용한다. </p>
<blockquote>
<h3 id="암호화로-도청을-피한다">암호화로 도청을 피한다.</h3>
<p>현재 통신데이터 도청으로부터 피하기 위해서 여러 방법이 고안되고 있다. 그 중에 가장 보급되어있는 기술이 암호화인데, 암호화에는 몇 가지의 대상이 있다.</p>
</blockquote>
<h4 id="1-통신-암호화">1) 통신 암호화</h4>
<p>한 가지는 <code>통신을 암호화하는 방법</code>이다. HTTP에는 암호화 구조는 없지만 <code>SSL(Secure Socket Layer)</code>이나 <code>TLS(Transport Layer Security)</code>(<del>SSL 신버전이 TLS지만, SSL로 통합해서 부른다.</del>)라는 다른 프로토콜을 TCP/IP 위, 애플리케이션 계층 아래에 조합함으로써, HTTP의 통신 내용을 암호화할 수 있다. SSL 등을 이용해 안전한 통신로를 확립하고 나서 그 통신로를 사용해 HTTP 통신을 한다. 이렇게 SSL을 조합한 HTTP를 <code>HTTPS(HTTP Secure)</code>나 <code>HTTP over SSL</code>이라 불린다.</p>
<h4 id="2-콘텐츠-암호화">2) 콘텐츠 암호화</h4>
<p>다른 한 가지는 통신하고 있는 콘텐츠의 내용 자체를 암호화해 버리는 방법이다. HTTP에 암호화를 하는 기능은 없기 때문에 HTTP를 사용해서 운반하는 것을 암호화하는 것이다. 즉 HTTP메시지에 포함되는 <code>콘텐츠(바디)를 암호화</code>해버리는 것이다.</p>
<p>물론 콘텐츠 암호화를 유효하게 적용하려면 클라이언트와 서버가 콘텐츠의 암호화나 복호화 구조를 가지고 있는 것이 전제가 되므로, 평상시에 유저가 사용하는 브라우저와 웹 서버에서 이용하는 것은 어렵다. 주로 웹 서비스에서 적용한다.</p>
<blockquote>
<h3 id="통신-상대를-확인하지-않기-때문에-위장-가능하다">통신 상대를 확인하지 않기 때문에 위장 가능하다.</h3>
<p>HTTP를 사용한 Request나 Response에서는 통신 상대를 확인하지 않는다. Request를 보낸 곳이 정말 URI에서 지정된 호스트인지, Response를 반환한 클라이언트가 진짜 받은 곳인지 HTTP로는 모른다. </p>
</blockquote>
<h4 id="누구나-요청-가능">누구나 요청 가능!</h4>
<p>HTTP에 의한 통신은 상대가 누구인지 확인하는(인증하는) 절차가 없기 때문에 누구든지 요청할 수 있다. 요청이 오면 상대가 누구든지 무언가의 Response를 반환한다.(host나 포트 등에 웹 서버 제한이 없을 경우)</p>
<p>HTTP는 누구이던 간에 요청을 보내면 응답을 무조건 주는 단촐한 구조로 되어있지만, <code>상대를 확인하지 않는 점이 약점</code>일 수가 있다. 예상되는 약점은 아래와 같다.</p>
<blockquote>
<ul>
<li>요청을 보낸 곳의 웹 서버가 원래 의도한 응답을 보내야하는 웹 서버인지 아닌지를 모른다. 가짜 웹 서버 있을 수 있다. <code>서버 신뢰문제</code></li>
</ul>
</blockquote>
<ul>
<li>응답을 돌려준 곳이 원래 의도한 요청을 보내는 클라이언트인지 모른다. 가짜 클라이언트일지도 모른다. <code>클라이언트 신뢰문제</code></li>
<li>통신하고 있는 상대가 접근이 허가된 상대인지 아닌지를 확인할 수 없다. 중요한 정보를 불특정한 곳에 돌려보낼 수도 있다. <code>인증문제</code></li>
<li>어디에서 누가 요청한건지 확인이 안된다. <code>출처 불분명</code></li>
<li>의미없는 요청도 수신하게 된다. <code>DDos 무분별 공격 우려</code></li>
</ul>
<h4 id="상대를-확인하는-증명서">상대를 확인하는 증명서</h4>
<p>HTTP에서는 통신 상대를 확인할 수 없지만, SSL로 간접적으로 확인할 수 있다. SSL은 암호화뿐 아니라 상대를 확인하는 수단으로 증명서를 제공한다. 증명서는 신뢰할 수 있는 제3자인 인증기관에서 발행하기때문에 서버나 클라이언트의 실존한다는 사실을 증명한다!(<code>AWS SSL 인증 절차 관련 블로깅 필요!</code>) 그 증명서를 위조하는 것은 기술적으로 상당히 어렵다.</p>
<p>이 증명서를 이용함으로써, 통신 상대가 내가 통신하고자하는 서버임을 알려주고, 이용자는 불특정한 곳으로 정보가 누설되는 위험성을 크게 줄일 수 있다.</p>
<blockquote>
<h3 id="완전성을-증명할-수-없기-때문에-변조-가능">완전성을 증명할 수 없기 때문에 변조 가능!</h3>
<p>완전성이란 정보의 정확성을 의미한다. 그것을 증명할 수 없다는 이야기는 정보가 진짜인지 가짜인지, 정확한지 틀린것이 있는지 알아내기가 어렵다는 뜻이다.</p>
</blockquote>
<h4 id="수신한-내용이-다를지도-모른다">수신한 내용이 다를지도 모른다.</h4>
<p>HTTP가 완전성을 증명할 수 없다는 뜻은 만약 요청이나 응답이 발신된 후에 수신할때까지 변조되어도 그 사실을 알 수 없다. 발신된 요청/응답 내용이 중간에 변조된지 확인이 어렵다.</p>
<p>예를 들어, 어떤 웹 사이트에서 콘텐츠를 다운로드했다고하면 내 컴에 다운로드 된 파일과 서버에서 날아오는 파일이 같은건지 알 수없다는 뜻이다. 정말 다른 내용으로 변경되었다해도 나는 그 사실을 파악할 수 없다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 프로세스]]></title>
            <link>https://velog.io/@brian_kim/OS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4</link>
            <guid>https://velog.io/@brian_kim/OS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4</guid>
            <pubDate>Fri, 03 Sep 2021 03:48:34 GMT</pubDate>
            <description><![CDATA[<h1 id="프로세스">프로세스</h1>
<ul>
<li>현대 운영체제의 기본 요구조건은 <code>프로세스 관리</code></li>
<li>운영체제는 프로세스에게 자원을 할당하고(인터리빙, 세마포어), 프로세스들이 정보를 공유하고 교환, 각 프로세스의 리소스를 다른 프로세스로부터 보호하고, 프로세스들간에 동기화(세마포어) 시킨다.<ul>
<li>이러한 요구조건을 만족시키기 위해, 운영체제는 각 프로세스에 대해 그 <code>프로세스의 상태</code>와 <code>리소스 소유권</code>을 표시하고, 프로세스 제어를 가능케하는 <code>자료구조</code>(PCB : Process Control Block, 프로세스 제어 블록)를 유지해야 한다.</li>
</ul>
</li>
<li>인터리빙(Interleaving) vs. 동시 수행(execute simultaneously)<ul>
<li>병행성</li>
<li>단일 처리기상에서 다중 프로그래밍을 지원하는 경우, 여러 프로세스의 수행은 시간적으로 번갈아 수행, 즉 인터리빙(Interleaving)이 될 수 있다.</li>
<li>다중 처리기상에서는 프로세스 수행이 인터리빙될 뿐 아니라, 여러 프로세스가 동시에 수행될 수 있다.</li>
</ul>
</li>
<li>쓰레드 개념의 도입으로 인해 프로세스의 관리가 더욱 어려워졌다.<ul>
<li>다중 쓰레드 시스템에서 프로세스는 리소스 소유권에 대한 속성(attribute)를 보유한 반면, 여러 병행수행 스트림(execution stream)의 속성은 한 프로세스 내에서 수행되는 쓰레드의 특성(property)이다.</li>
</ul>
</li>
</ul>
<blockquote>
<h2 id="프로세스-배경지식">프로세스 배경지식</h2>
</blockquote>
<p> 컴퓨터 플랫폼은 하드웨어 자원들의 집합으로 구성되어있다. 컴퓨터 프로그램은 어떤 업무를 수행하기 위해 개발된 것인데, 주어진 하드웨어 플래폼 상에서 직접 응용을 작성하는 것은 비효율적이다. 공통 루틴 그리고 리소스 공유를 위해 소프트웨어가 필요해졌다. 그렇기 때문에 이러한 내부 리소스를 보호하는 기법을 필요로 한다. OS는 프로그램이 사용할 수 있는 편리하고, 풍부하고, 안전하고, 일관성있는 인터페이스를 제공한다. OS는 리소스에 대해 균일하고 추상화된 표현을 제공한다. 프로그램은 해당 리소스를 요청하고 접근 가능하다.</p>
<blockquote>
<h2 id="프로세스란">프로세스란?</h2>
<p>프로세스는 멀티프로그래밍과 시분할 시스템의 메인 컨셉으로, 응용프로그램 실행 모델을 이야기한다. <code>실행중인 프로그램</code>, <code>컴퓨터 상에서 실행중인 프로그램의 인스턴스</code>, <code>처리기에 할당되어 수행될 수 있는 개체(entity)</code>, <code>명령들의 순차 수행, 현재 상태, 연계된 시스템 자원들의 집합 등에 의해 특징지어지는 활성화 단위(a unit of activity)</code> 이 모든 것이 프로세스라고 부를 수 있다. 간단하게 실행중인 프로그램이라고 이해하는 것이 편할 것 같다.</p>
</blockquote>
<blockquote>
<h2 id="프로세스의-필수-요소">프로세스의 필수 요소</h2>
</blockquote>
<h3 id="1-프로그램-코드">1. 프로그램 코드</h3>
<p>동일 프로그램을 수행하는 서로 다른 프로세스들이 공유할 수 있는 부분)</p>
<ul>
<li>그 코드와 연계된 데이터의 집합과 스택(User Stack, Kernel Stack)</li>
<li>프로그램이 수행 중 특정 시점에, 프로세스는 여러가지 요소들에 의해 유일하게 식별되어야 한다.</li>
</ul>
<h3 id="2-pcbprocess-control-block">2. PCB(Process Control Block)</h3>
<p><img src="https://images.velog.io/images/brian_kim/post/00d1f37a-90dc-429f-a31c-89d5a801c8b8/image.png" alt=""></p>
<ul>
<li>식별자(Process ID)</li>
<li>상태(Process State)</li>
<li><code>우선순위</code></li>
<li><code>프로그램 카운터</code> </li>
<li>CPU 카운터</li>
<li>메모리 포인터</li>
<li>문맥 데이터(Context data)</li>
<li>입출력 상태 정보</li>
<li>accounting data (아이디 &amp; 비밀번호)</li>
</ul>
<blockquote>
<h4 id="pcb의-주요-역할">PCB의 주요 역할</h4>
</blockquote>
<ul>
<li>수행하는 프로세스를 인터럽트한 후 나중에 그 인터럽트가 발생되지 않은 것처럼 프로세스 수행을 재개할 수 있도록 충분한 정보를 유지하는 것</li>
<li>다수의 프로세스를 지원하고 다중처리를 제공할 수 있게 해주는 주요 도구<blockquote>
<blockquote>
<ul>
<li>Context Switching
어떤 프로세스가 인터럽트될 때, 프로그램 카운터 및 처리기 레지스터들(하드웨어의 Context Data)의 현재 값이 해당 프로세스 제어블록(PCB)의 적절한 필드에 저장되고, 그 프로세스의 상태가 (이후 설명될) 블록 또는 준비 등과 같은 값으로 변경</li>
</ul>
</blockquote>
</blockquote>
<ul>
<li>OS는 다른 프로세스 선택해서 수행 상태로 만들고, 그 프로세스의 프로그램 카운터와 문맥 데이터를 처리기 레지스터로 적재해서 <code>새로운 프로세스</code>를 수행(CPU는 한번에 한개의 프로세스만 수행한다.)</li>
<li>단일 처리기 컴퓨터에서는 임의 시점에 단 하나의 프로세스만이 수행된다.</li>
</ul>
</li>
</ul>
<h2 id="프로세스-상태-수행--비수행">프로세스 상태 (수행 / 비수행)</h2>
<ul>
<li>프로그램을 실행하기 위해 그 프로그램에 대한 프로세스 또는 태스크가 생성된다.</li>
<li><code>처리기 관점</code>에서 볼 때, 처리기는 프로그램 카운터 레지스터(PC Register)값에 의해 <code>결정된 순서에 따라 명령어들을 수행</code>한다.</li>
<li><code>프로그램 카운터</code>는 시간이 흐름에 따라 다른 프로세스들을 표현하는 <code>다른 프로그램 내의 코드를 가리킬 수 있다</code></li>
<li>개별 프로그램의 관점에서 <code>프로그램의 수행</code>은 자신에 속한 <code>일련의 명령어들을 수행</code>한다.</li>
<li>개별 프로세스 행위의 특성은 그 프로세스를 위해 수행되는 일련의 명령어 리스트로 표현한다.</li>
<li>이러한 리스트를 프로세스의 <code>trace</code>라고 부른다.</li>
<li>처리기 행위의 특징은 다양한 프로세스 트레이스이 어떻게 인터리빙되는지를 보임으로써 표현될 수 있다.</li>
</ul>
<h1 id="2상태-프로세스-모델">2상태 프로세스 모델</h1>
<blockquote>
<p><img src="https://images.velog.io/images/brian_kim/post/9d889724-69a5-4071-bcf5-bc389b690ee3/image.png" alt=""></p>
</blockquote>
<ul>
<li>상태 종류<ul>
<li>수행(Running, 실행)</li>
<li>비수행(Not Running, 비실행)</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 운영체제 구조와 원리]]></title>
            <link>https://velog.io/@brian_kim/OS-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@brian_kim/OS-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Thu, 02 Sep 2021 03:36:05 GMT</pubDate>
            <description><![CDATA[<h1 id="운영체제operating-system란">운영체제(Operating System)란?</h1>
<p><img src="https://images.velog.io/images/brian_kim/post/22d2085e-27d6-45e1-b574-b1f953c91330/image.png" alt=""></p>
<blockquote>
<p>운영체제란 컴퓨터 하드웨어(입출력 장치, CPU)의 리소스를 관리해주면서 동시에 여러 애플리케이션이 작동할 수 있는 환경을 제공해주는 소프트웨어다.</p>
</blockquote>
<ul>
<li>OS는 프로그램들이 리소스를 필요로 할 때 필요 리소스를 할당해준다.</li>
<li>OS는 각각 자원을 할당받은 프로그램들이 서로 엉키지 않고 효율적으로 작동하도록 제어해준다.</li>
<li>운영체제(OS)가 하는 일</li>
</ul>
<ol>
<li>프로세스 관리</li>
<li>메모리 관리</li>
<li>저장소 관리</li>
<li>보안</li>
</ol>
<h2 id="운영체제의-부팅과정">운영체제의 부팅과정</h2>
<p>컴퓨터의 전원이 나가면 CPU는 ROM에 저장되어 있는 내용을 읽는다. ROM(Read Only Memory)은 컴퓨터에 전원이 나가도 사라지지않는 비휘발성 메모리며, 계속 보관되어야할 정보들을 저장한다. ROM안에는 <code>POST(Power On Self-Test)</code>와 <code>부트로더(Boot Loader)</code>가 저장되어 있다.</p>
<p>POST는 컴퓨터 전원이 켜지면 가장 먼저 실행되는 프로그램으로 컴퓨터에 이상이 있는지 체크하는 프로그램이다. 부트로더(Boot Loader)는 하드디스크에 저장되어 있는 OS 프로그램을 가져와서 RAM에 넘겨준다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/b16fc525-5dea-483e-bf61-9053492b646a/image.png" alt=""></p>
<blockquote>
<h3 id="부트로더boot-loader">부트로더(Boot Loader)</h3>
<p><code>부트로더</code>란 운영체제가 시동되기 이전에 미리 실행되면서 <code>커널이 올바르게 시동되기 위해 필요한 모든 관련 작업을 마무리</code>하고 최종적으로 <code>운영 체제를 시동</code>시키기 위한 목적을 가진 프로그램을 말한다.</p>
</blockquote>
<h2 id="interrupt인터럽트">Interrupt(인터럽트)</h2>
<p>컴퓨터가 부팅이 되면 OS 프로그램을 실행한 후 사용자의 입력 이벤트를 기다린다. 이 이벤트를 인터럽트라고 한다. 인터럽트가 발생되면 OS는 해당 명령어(Interrupt를 발생시킨) 주소를 기억한다. 그 후 인터럽트가 끝나면 해당 주소로 돌아가 다음 명령어를 수행하거나 대기상태로 돌아간다.</p>
<blockquote>
<h3 id="interrupt인터럽트-1">Interrupt(인터럽트)</h3>
<p>인터럽트는 말그대로 <code>방해</code>의 의미를 가지고 있다. CPU가 프로그램을 실행하고 있을 때 입출력 하드웨어 등의 장치에 예외상황(<code>에러</code>라던지, <code>입력</code>이라던지, <code>출력</code>이라던지..) 다양한 상황에 대해서 CPU가 처리할 수 있도록 중간에 멈추게 한다. 인터럽트가 발생하면 CPU가 수행중이던 작업은 따로 저장하게 되고(<code>CPU 내부 레지스터</code>나 <code>메인 메모리</code> 등), 인터럽트가 발생한 작업을 먼저 수행하게된다.
관련 내용은 나중에 집중해서 쓰도록 하겠다.</p>
</blockquote>
<h1 id="운영체제의-구조">운영체제의 구조</h1>
<p>운영체제는 DOS 시절부터 꾸준히 발전해왔다. 기본적으로 하나의 CPU는 하나의 작업(Interrupt)만 처리할 수 있다. 따라서 예전에는 하나의 작업이 끝날 때까지 다른 작업은 대기만 하고 있어서 효율이 낮았다.</p>
<blockquote>
<p><code>작업 1</code>, <code>작업 2</code>를 처리해야 한다.
<code>작업 1</code>이 <code>I/O 자원</code>을 사용한다. <code>작업 2</code> 대기, <code>CPU 자원</code> 대기
<code>작업 1</code>이 <code>CPU 자원</code>을 사용한다. <code>작업 2</code> 대기, <code>I/O 자원</code> 대기
<code>작업 2</code>가 <code>I/O 자원</code>을 사용한다. <code>CPU 자원</code> 대기
<code>작업 2</code>가 <code>CPU 자원</code>을 사용한다. <code>I/O 자원</code> 대기</p>
</blockquote>
<h2 id="멀티-프로그래밍multi-programming">멀티 프로그래밍(Multi-Programming)</h2>
<p>이러한 문제를 해결하기 위해 생긴 방법론이 멀티 프로그래밍 원리다. 멀티 프로그래밍의 기본 개념은 입출력을 수행하고 있는 경우, 다른 작업에 CPU를 할당해서 처리하도록 한다. 반대로 CPU가 작업을 하고 있는 경우, 입출력 장치들을 대기 상태로 만들어서 입출력이 필요한 작업에게 입출력 리소스를 할당한다.</p>
<blockquote>
<p><code>작업 1</code>, <code>작업 2</code>를 처리해야 한다.
<code>작업 1이 CPU 자원</code>을 사용한다. <code>작업 2가 I/O 자원</code>을 사용한다.
<code>작업 1이 I/O 자원</code>을 사용한다. <code>작업 2가 CPU 자원</code>을 사용한다.</p>
</blockquote>
<h2 id="멀티-태스킹multi-tasking">멀티 태스킹(Multi-tasking)</h2>
<p>기술이 발전하면서 프로세서의 처리 속도가 더욱 빨라졌는데 역설적으로 C프로세서의 낭비가 더욱 커졌다. 그 이유는 프로세서의 처리 속도의 발전 속도를 입출력 장치가 따라가지 못해서 프로세서의 낭비가 더욱 커지게 된다.</p>
<blockquote>
<p><code>작업 1</code>, <code>작업 2</code>를 처리해야 한다.
<code>작업 1</code>에게 <code>CPU 자원 할당</code>, <code>작업 2</code>에게 <code>I/O 자원 할당</code>
<code>작업 1</code>를 완료하여 <code>CPU 대기</code>, <code>작업 2</code> 처리 중
(이때, <code>작업 2가 처리될 때까지 CPU는 대기 상태여서 자원 낭비</code> 발생)</p>
</blockquote>
<p>이러한 문제를 해결하기 위해 나온 개념이 <code>멀티 태스킹(Multi-tasking)</code>이다. 멀티 태스킹은 각각에 작업들에게 <code>자원 할당 시간</code>을 정해줘서 그 시간이 지나면 <code>다른 작업들에게 자원을 넘겨준다.</code> 이때, 각 자원들에게 시간을 할당하는 것이 <code>스케쥴링</code>이고 <code>Job 스케쥴링</code>과 <code>CPU 스케쥴링</code>이 있다.</p>
<h1 id="운영체제-원리">운영체제 원리</h1>
<p>운영체제는 <code>interrupt-driven</code>방식으로 사용자의 요청(Event 혹은 Interrupt)이 발생하면 운영체제는 적절하게 자원(CPU, I/O, 메모리 등)을 분배하여 그 요청을 처리하는 구조이다.</p>
<p>Interrupt에는 크게 두 가지가 있다. <code>H/W interrupt</code>와 <code>S/W interrupt</code>가 있다. H/W interrupt는 <code>I/O, 메모리, CPU</code>와 관련된 interrupt이고 S/W interrupt는 프로그램이 실행되다가 발생될 수 있는 <code>Errors</code>, 운영체제 Services들에 대한 요청인 <code>System Call</code>이 있다. S/W interrupt는 잘못 처리하면 한 작업이 자원을 계속 점유하거나 컴퓨터의 동작을 크게 저해할 수 있기 때문에 여러 방법을 써서 이를 예방해야 한다.</p>
<p>그 첫 번째로 <code>Dual-Mode Execution</code>이다. 운영체제는 기본적으로 사용자에게 인터페이스를 제공하는 <code>User Mode</code>와 기기들을 직접 관리하는 <code>Kernel Mode</code>로 구분된다. <code>Kernel</code>에서의 작업은 컴퓨터의 중요한 부분에 해당하는 작업이기에 사용자가 직접 작업하다가 문제가 생길 시 컴퓨터 전체에 영향을 끼치기 때문에 User Mode와 Kernel Mode로 나눠 <code>사용자가 접근하지 못하게 한다.</code></p>
<p>사용자가 <code>User Mode에서 작업을 명령</code>하면 <code>Kernel Mode에서 이를 처리</code>해야하는데 그 연결고리 역할을 하는 것이 바로 <code>Mode-Bit</code>이다. 운영체제는 User mode에 들어온 명령어와 일치하는 Mode-Bit을 가진 Kernel Mode의 명령어를 찾아 Kernel에서 실행한 후, 그 결과를 User-Mode에 넘기고 일을 마무리한다. 이러한 행위를 <code>System Call</code>이라 한다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/1bc2d132-2cab-45c3-9145-76e81f48d3db/image.png" alt=""></p>
<p>두 번째로 <code>Timer</code>가 있다. Timer는 말 그대로 프로세스들에게 <code>유효 시간을 부여</code>하여 그 시간이 지나면 프로세스를 종료시켜 <code>Error가 발생하여 작업이 멈추더라도 CPU를 계속 점유하는 것을 방지</code>한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[함수형 프로그래밍이란?]]></title>
            <link>https://velog.io/@brian_kim/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@brian_kim/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Thu, 02 Sep 2021 03:10:09 GMT</pubDate>
            <description><![CDATA[<p>아무래도 주니어도 못된 내가 이런 글을 쓰는 것이 조금은 이상해보일지도 모르겠지만, 이러저러 공부를 하다보니 한자 적어보자는 취지에서 적게되었다. 물론 지금은 취준을 하는 시기고, 기술면접을 대비하는 면도 없지 않아 있지만, 이런 생각들이 모이면 언젠가 내게 강한 무기로 다가오지 않을까하는 생각에서다. 글을 5-6시간 쓰면 모르겠지만, 1시간 안에 짧게 글로 작성하려고 한다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/28e5f27b-a93d-4a8c-93ef-505840805058/image.png" alt=""></p>
<h1 id="프로그래밍-패러다임">프로그래밍 패러다임</h1>
<p>패러다임이라는 것은 일종의 생각이나 사고의 틀이라고 생각하면 된다. 그동안 <code>패러다임의 전환</code>과 같은 다양한 광고카피를 봐왔지만 패러다임이라는 용어에는 익숙해지지 못했던 것 같다. 그래서 위키를 찾아 간단하게 정리해보고자 한다.</p>
<blockquote>
<h2 id="패러다임">패러다임</h2>
<p>한 시대의 사람들의 견해나 사고를 근본적으로 규정하고 있는 인식의 체계. 또는, 사물에 대한 이론적인 틀이나 체계. 순화어는 `틀&#39;.</p>
</blockquote>
<p>이를 통해 간단하게 생각해보자면 프로그래밍 패러다임이라는 것은 프로그래머가 어떤 관점에서 코드를 작성할 지를 결정하는 하나의 틀이라고 생각하면 된다. 코드를 어떤 생각을 가지고 작성하는지에 관한 문제라고 생각한다. 가장 근대에 와서는 <code>명령형 프로그래밍</code>그리고 <code>선언형 프로그래밍</code> 이 두가지 패러다임이 가장 메인스트림의 형태를 띠고 있는 패러다임이다. </p>
<h2 id="명령형-프로그래밍">명령형 프로그래밍</h2>
<p>명령형 프로그래밍은 기본적으로 코드를 작성하는 것이 원하는 결과를 <code>달성해나가는 과정</code>에만 중심을 두는 프로그래밍 패러다임이다. 그렇기 때문에 무엇(What)을 달성할 것인지 나타내는 것보다 어떻게(How)할 것인지를 설명하는 사고에 가깝다. 간단하게 예제 코드를 만들어보자.</p>
<pre><code class="language-js">var str = &#39;111111211111&#39;
let answer = &#39;&#39;
var target = &#39;2&#39;

for(let i = 0; i &lt; str.length; i++){
  if(str[i] === target){
        answer += &#39;1&#39;;
      } else {
         answer += str[i] 
    }
}</code></pre>
<p>위의 코드는 <code>str</code>이라는 대상 문자열에서 <code>2</code>라는 타겟을 찾아 <code>1</code>로 바꾸어 만들어주는 과정을 담고 있다. 중간 중간 <code>target</code>이나 <code>answer</code>등의 변수명을 통해서 목적의 방향성을 이야기하지만, 코드만 한번 보고 목적을 파악하는 것은 어렵다. 따라서, 최종적으로 <code>어떤 목적을 두고 프로그래밍을 한 것인지에 대한 것</code>을 주석으로 남겨두어야 코드를 쉽게 읽을 수 있다.</p>
<h2 id="선언형-프로그래밍">선언형 프로그래밍</h2>
<p>그렇다면 선언형 프로그래밍은 어떨까? 선언적 프로그래밍은 명령형 프로그래밍과 다르게 달성하는 세세한 과정(How)보다 목표한 바가 무엇이고, 어떻게 이루어지는지 <code>결과(What)</code>에 대한 것을  중심에 두는 프로그래밍 패러다임이다. 그렇기 때문에 세부적인 과정은 간략화되어 과정보다 결과물에 좀더 집중한 결과물을 만들 수 있다. 이번엔 선언형 프로그래밍의 예시 코드를 살펴보자.</p>
<pre><code class="language-js">var str = &#39;111111211111&#39;
1. str[str.indexOf(&#39;2&#39;)]=&#39;1&#39;
2. str.replace(&#39;2&#39;,&#39;1&#39;)</code></pre>
<p>위에서 하나하나 살펴보며 찾아서 무엇을 바꿀지에 대한 것을 일일히 <code>명령</code>해줬다면, 해당 과정을 간략화된 단어 몇개로 코드가 어떻게 어떤 결과물을 만들어내는지 직관적으로 이해할 수 있다. 이건 새로운 명령을 만들지 않고, 추상화되어있는 일련의 과정을 사고로 결과물을 만들어내는 코드로 구성되어있다. 두 가지 방법을 각각 간단하게 보면 첫번째는 <code>&#39;2&#39;의 인덱스를 찾아서 해당 인덱스의 값을 &#39;1&#39;로 바꾸어준다.</code>가 되고, 두번째는 <code>&#39;2&#39;라는 문자열을 찾아서, &#39;1&#39;로 바꾸어준다.</code>라는 방식으로 주석도 없이 간결하게 코드를 이해할 수 있다.</p>
<h1 id="그렇다면-함수형-프로그래밍이란">그렇다면 함수형 프로그래밍이란?</h1>
<p>함수형 프로그래밍이란 선언형에서 뿌리를 뻗어나온 패러다임인데, 말 그대로 <code>함수가 프로그래밍 전반의 중심</code>이 되도록 하는 패러다임이다. 위의 선언형 프로그래밍을 보면 <code>JavaScript 내장 메서드</code>를 이용해서 연산이 이루어지고 있다.</p>
<blockquote>
<p><code>indexOf(&#39;2&#39;)</code>메서드는 때려죽여도, 문자열 내부의 <code>2</code>의 <code>index</code>값만 가져올 것이고, <code>replace(&#39;2&#39;,&#39;1&#39;)</code>는 미친듯이 때려도 처음 만난 <code>2</code>의 값을 <code>1</code>로 바꾸기만 할 것이다. </p>
</blockquote>
<p>함수형 프로그래밍이란 함수의 기능은 본연의 기능으로 유지하면서, 작성하는 프로그래밍 패러다임이다.</p>
<h2 id="함수형-프로그래밍의-컨셉">함수형 프로그래밍의 컨셉</h2>
<blockquote>
<h3 id="1-변경-가능한-상태를-불변상태immutable로-만들어-sideeffect를-없애자">1. 변경 가능한 상태를 <code>불변상태(Immutable)</code>로 만들어, <code>SideEffect</code>를 없애자.</h3>
</blockquote>
<p>어렸을 때 수학책에서 봤던 함수를 살펴보면 <code>f(x) = y</code> 뭐가 들어가든 같은 결과가 나오게끔 만들어진다. 위의 함수는 <code>x</code>를 넣으면 때려죽여도 <code>y</code>값만 출력하게된다. 여기서 중요한 것은 함수 내부의 상태는 <code>어떤 상황에서도 유지되고 결과값은 항상 동일해야 한다</code>는 것이다. 내부에 어떤 상황도 만들지 않기 때문에 결과예측이 틀리는 경우는 없다.</p>
<pre><code class="language-js">//순수함수
function func1(a,b){
 return a+b; 
}
--------------------------

state =&#39;add&#39;;

function func2(a,b){
  //상태에 따른 결과값 변경
  if(state === &#39;add&#39;){
    return a+b;
  } else {
       return a-b; 
  }
}</code></pre>
<p>위의 코드를 보면 명확하게 알 수 있다. 첫번째 함수는 어떤 외부 상황이나 내부 상황에 의해서 값이 변동되지 않고 동일하게 두 전달인자의 합만을 반환한다. 하지만 두번째 함수는 외부의 <code>state</code> 혹은 내부의 상황에 따라서 <code>a+b</code> 혹은 <code>a-b</code>를 출력한다. 함수형 프로그래밍의 가장 핵심은 외부에 영향을 받지 않고, 상황에 따라 변동하지 않는 <code>순수함수</code>가 되어야한다는 것이다. 순수함수에 대한 이야기는 다음에 담도록 하겠다.</p>
<blockquote>
<h4 id="sideeffect">SideEffect</h4>
<p>  Side Effect란, 본래 의도와 다르게 다음과 같은 변화 혹은 변화가 발생하는 작업을 말한다.</p>
</blockquote>
<ul>
<li>변수의 값이 변경됨</li>
<li>자료 구조를 제자리에서 수정함</li>
<li>객체의 필드값을 설정함</li>
<li>예외나 오류가 발생하여 실행이 중단됨</li>
<li>콘솔 또는 파일 I/O가 발생됨</li>
</ul>
<blockquote>
<h3 id="2-모든-것은-객체이다">2. 모든 것은 객체이다.</h3>
</blockquote>
<p>함수형 프로그래밍에서 모든 것은 객체다. 클래스 외에 함수 또한 객체이기 때문에 <code>함수를 값으로도 할당</code>할 수 있고, <code>파라미터로 전달</code> 및 <code>결과 값을 반환</code>할 수 있다. 위 3가지를 모두 지키는 객체를 <code>1급 객체</code>라고 한다. 함수형 프로그래밍 언어에서는 위 3가지 조건을 모두 만족 시켜 1급 객체가 된다. 1급 객체에 대한 것도 다른 글로 남기겠다.</p>
<blockquote>
<h3 id="3-코드를-간결하게-하고-가독성을-높여-로직에-집중시키자">3. 코드를 간결하게 하고, 가독성을 높여 로직에 집중시키자.</h3>
<p>Lambda 및 Collection, Stream과 같은 API를 통해 보일러 플레이트를 제거하고, 내부에 직접적인 함수 호출을 통해 가독성을 높일 수 있다. 일을 위한 일이 줄어 실제 구현할 로직에만 집중할 수 있다.</p>
</blockquote>
<blockquote>
<h3 id="4-동시성-작업을-보다-쉽고-안전하게-구현하자">4. 동시성 작업을 보다 쉽고 안전하게 구현하자.</h3>
<p>위에 설명한 immutable 값을 사용해, 여러 쓰레드에서 접근을 하더라도 SideEffect가 발생하지 않는다. 또한 Lock이나, UnLock같은 보호장치도 필요하지 않다.</p>
</blockquote>
<h1 id="마치며">마치며</h1>
<p>기본적으로 함수형 프로그래밍 언어인 JavaScript를 통해 여러 경험을 할 수 있었다. 내가 원하는 결과를 만들어 내기위해서 중간에 진행해야했던 많은 명령형 코드들을 추상화시켜서 가볍게 만들 수 있었고, C++이나 C언어를 할때와는 다르게 편리성을 크게 느끼기도 했다. 그런만큼 여전히 이전 언어에서 사용하던 불필요한 과정들을 자꾸만 해서 코드가 가독성이 떨어지고, 결과 예측이 어렵게 되고 하던 다양한 과정을 느꼈다. JavaScript를 좀 더 자세하게 공부해서 함수형 프로그래밍, 즉 만들어진 바퀴를 어떻게 더 잘 활용할 것인가를 지속적으로 고민해야된다. </p>
<p>이렇게 글을 쓰고나니 이전에 공부한 것들을 적던 때랑은 또 다르게 느껴진다. 이런 글들이 쌓여 언젠가 내 무기가 될 것이라고 생각하니 타자를 치는 손이 훨씬 가볍게 느껴진다. 물론 쓰면서 100% 이해되지 않은 부분도 많지만, 공부해나가다보면 언젠가 확실히 이해해서 다른 사람에게도 명쾌하게 설명할 수 있지 않을까? 물론 코드스테이츠를 하면서 공부했던 부분들도 있어서 이해가 조금 더 쉽긴했지만 아직 가야할 길이 멀게만 느껴진다. 힘내자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DB] SQL(Structured Query Language) 기초]]></title>
            <link>https://velog.io/@brian_kim/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-SQLStructured-Query-Language-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@brian_kim/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-SQLStructured-Query-Language-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Fri, 27 Aug 2021 05:51:48 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/brian_kim/post/b32949d7-3e03-4458-b11c-16567f1beb43/image.png" alt=""></p>
<h1 id="sql-structured-query-language">SQL (Structured Query Language)</h1>
<p>SQL은 RDBMS에 저장된 데이터와 통신하기 위해 필요한 프로그래밍 언어다. SQL문법은 영어와 유사하게 만들어져서 쉽게 읽고 쓰고 해석할 수 있다. </p>
<h2 id="sql-명령어">SQL 명령어</h2>
<hr>
<blockquote>
<h3 id="1-dmldata-manipulation-language--데이터-조작어">1. DML(Data Manipulation Language) : 데이터 조작어</h3>
</blockquote>
<p>데이터 조작어는 데이터베이스 사용자 또는 응용 프로그램 소프트웨어가 컴퓨터 데이터베이스에 대해 데이터 <code>검색, 등록, 삭제, 갱신</code>을 위한, 데이터베이스 언어 또는 데이터베이스 언어다. 2007년 현재 가장 대중적 데이터 조작 언어는 SQL 데이터 조작 언어이다. SQL은 관계형 데이터베이스에 대해 검색 및 업데이트 등의 데이터 조작을 위해 사용된다. 데이터베이스 사용자가 사용하는 언어다.</p>
<h4 id="1-select">(1) SELECT</h4>
<p>DB에 있는 데이터를 조회하거나 검색하기 위한 명령어. RETRIEVE 라고도 부름.
<img src="https://images.velog.io/images/brian_kim/post/ac4a994a-6a90-43b8-a6d6-902fffb68ba9/image.png" alt=""></p>
<h4 id="2-insert">(2) INSERT</h4>
<p>DB에 데이터를 삽입할때 사용하는 명령어.
<img src="https://images.velog.io/images/brian_kim/post/b03271e6-81d2-49e9-b7d3-6e3d306e547d/image.png" alt=""></p>
<h4 id="3-update">(3) UPDATE</h4>
<p>DB에 있는 데이터를 갱신(내용 변경)할 때 사용하는 명령어.
<img src="https://images.velog.io/images/brian_kim/post/8cefead4-a9c1-48c2-8c61-01de0a9333b4/image.png" alt=""></p>
<h4 id="4-delete">(4) DELETE</h4>
<p>DB에 있는 데이터를 삭제할 때 사용하는 명령어.
<img src="https://images.velog.io/images/brian_kim/post/a9699e77-6e31-43d8-9f34-4b5c614e7519/image.png" alt=""></p>
<blockquote>
<h3 id="2-ddldata-definition-language--데이터-정의어">2. DDL(Data Definition Language) : 데이터 정의어</h3>
</blockquote>
<p>데이터 정의어는 데이터베이스의 데이터를 정의하는 언어다. DDL은 데이터를 정의하는데, 정의라 함은 데이터베이스의 객체들을 정의하는 것이다. 데이터 베이스 객체는 테이블, 뷰, 인덱스 (기타 : synonym, sequence, partitioin table)등을 포함한다. 데이터를 정의하기 위해서 객체들을 생성, 삭제, 변경할 수 있다.</p>
<h4 id="1-create">(1) CREATE</h4>
<p>DB에 새로운 테이블 구조를 생성하기 위한 명령어.
<img src="https://images.velog.io/images/brian_kim/post/8fb2053f-ed07-40fc-87aa-90e6a8b6ac91/image.png" alt=""></p>
<h4 id="2-alter">(2) ALTER</h4>
<p>DB에 있는 테이블 구조를 변경할 때 사용하는 명령어.</p>
<blockquote>
<p>테이블 구조 변경 명령어</p>
</blockquote>
<ul>
<li><code>ADD COLUMN</code> : 테이블에 새로운 속성을 추가한다.<pre><code class="language-sql">ALTER TABLE 테이블명 ADD(추가할컬럼명, 데이터타입);</code></pre>
</li>
<li><code>MODIFY COLUMN</code> : 테이블의 속성을 수정한다.<pre><code class="language-sql">ALTER TABLE 테이블명 MODIFY(변경할컬럼명, 변경할데이터TYPE);</code></pre>
</li>
<li><code>DROP COLUMN</code> : 테이블에 속성을 삭제한다.<pre><code class="language-sql">ALTER TABLE 테이블명 DROP COLUMN 삭제할컬럼명;</code></pre>
</li>
<li><code>RENAME TO</code> : 테이블명을 새로운 이름으로 변경한다.<pre><code class="language-sql">ALTER TABLE 기존테이블명 RENAME TO 새로운 테이블명;</code></pre>
</li>
</ul>
<p><img src="https://images.velog.io/images/brian_kim/post/76c2a1c2-1467-49cd-a680-11bd0029a906/image.png" alt=""></p>
<h4 id="3-drop">(3) DROP</h4>
<p>DB의 테이블을 삭제할 때 사용하는 명령어.
<img src="https://images.velog.io/images/brian_kim/post/0ee35326-7eac-42ea-8578-28bf348b78ec/image.png" alt=""></p>
<h4 id="4-truncate">(4) TRUNCATE</h4>
<p>DB의 테이블 내부의 모든 내용을 삭제하는 명령어. 내용만 삭제하므로 구조는 남는다.
<img src="https://images.velog.io/images/brian_kim/post/dfe98c1b-af62-4715-a8e6-f124c6d5e550/image.png" alt=""></p>
<blockquote>
<h3 id="3-dcldata-control-language--데이터-제어어">3. DCL(Data Control Language) : 데이터 제어어</h3>
</blockquote>
<p>데이터 제어어는 데이터베이스에서 데이터에 대한 액세스를 제어하기 위한 데이터베이스 언어다. 권한 부여(GRANT)와 권한 회수(REVOKE)등이 있으며, 설정할 수 있는 권한으로는 연결(CONNECT), 질의(SELECT), 자료 삽입(INSERT), 갱신(UPDATE), 삭제(DELETE) 등이 있다.</p>
<h4 id="1-grant문">(1) GRANT문</h4>
<p>데이터베이스 사용자에게 사용권한을 부여한다.</p>
<h4 id="2-revoke문">(2) REVOKE문</h4>
<p>데이터베이스 사용자로부터 권한을 회수한다.</p>
<pre><code class="language-sql">GRANT CONNECT FROM kim62210
GRANT CONNECT, RESOURCE FROM kim62210</code></pre>
<h4 id="3-설정-가능한-권한-목록">(3) 설정 가능한 권한 목록</h4>
<ul>
<li><code>CONNECT</code> - DB 또는 스키마에 연결하는 권한</li>
<li><code>SELECT</code> - DB에서 데이터를 검색/조회하는 권한</li>
<li><code>INSERT</code> - DB에 데이터를 등록할 수 있는 권한</li>
<li><code>UPDATE</code> - DB에 데이터를 갱신할 수 있는 권한</li>
<li><code>DELETE</code> - DB에 데이터를 삭제할 수 있는 권한</li>
<li><code>USAGE</code> - 스키마 또는 함수와 같은 데이터베이스 객체를 사용할 수 있는 권한</li>
</ul>
<blockquote>
<h2 id="4-tcltransaction-control-language--트랜잭션-제어어">4. TCL(Transaction Control Language) : 트랜잭션 제어어</h2>
</blockquote>
<h4 id="1-commit">(1) COMMIT</h4>
<p>커밋은 트랜잭션 처리가 정상적으로 종료되어 트랜잭션이 수행한 변경 내용을 데이터베이스에 반영하는 연산. 내용을 변경한 트랜잭션이 완료되면 그 트랜잭션에 의해 데이터베이스는 새롭게 저장된다. 이 상태는 시스템 오류가 발생하더라도 취소되지 않는다.
<img src="https://images.velog.io/images/brian_kim/post/1b7f32b8-3e6f-4c7d-a96e-2b640f7013f4/image.png" alt=""></p>
<h4 id="2-rollback">(2) ROLLBACK</h4>
<p>롤백은 <code>하나의 트랜잭션 처리</code>가 비정상적으로 종료되어 데이터베이스의 일관성이 깨졌을 때, 트랜잭션이 만든 <code>모든 변경상황을 취소하고 이전 상태</code>로 되돌리는 연산
<img src="https://images.velog.io/images/brian_kim/post/c63a21af-f527-49fa-92c8-ee0e447781f9/image.png" alt=""></p>
<h4 id="3-savepoint">(3) SAVEPOINT</h4>
<p>세이브포인트는 <code>현재의 트랜잭션을 작게 분할</code>하는 명령어다. 저장된 SAVEPOINT는 <code>ROLLBACK TO SAVEPOINT</code>를 이용해서 지정한 곳까지 <code>ROLLBACK</code>할 수 있다. 여러개의 SQL문을 수반한 트랜잭션의 경우, 사용자가 트랜잭션 중간단계에서 SAVEPOINT를 지정할 수 있다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/76414ad1-87ad-4332-b7e2-0487d544a4c8/image.png" alt=""></p>
<blockquote>
<h4 id="주의사항">주의사항</h4>
<p>세이브포인트를 만들고 COMMIT 연산을 하게되면 커밋 연산 이전에 만든 세이브포인트들은 모두 날아간다. 세이브포인트는 한 트랜잭션에 여러개가 있을 수 있다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DB] DBMS 톺아보기]]></title>
            <link>https://velog.io/@brian_kim/DB-DBMS-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@brian_kim/DB-DBMS-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Wed, 25 Aug 2021 08:36:22 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터베이스시스템-dbms">데이터베이스시스템? DBMS!</h1>
<p>데이터베이스시스템은 데이터베이스를 효과적으로 관리하기 위한, 많은 데이터를 효율적으로 관리하고 지원하기 위한 소프트웨어라고 일전에 공부했다. 데이터베이스시스템 통칭 <code>DBMS는 사용자로 하여금 데이터를 추가,삭제,갱신,삽입하더라도 데이터베이스 전체의 통일성(원자성)이 깨지지 않도록 해주며, 데이터 추상화로 데이터 접근성을 높이고 계속적인 관리로 기존 데이터와의 불일치성이 나타나지 않도록 균일하게 관리해주는 일종의 데이터 관리 프로세스</code>라는 것을 배웠다. 지금부터는 DBMS의 구성요소, DBMS의 언어외 기타 다양한 것들을 톺아보도록 하자!</p>
<h2 id="데이터베이스-언어">데이터베이스 언어</h2>
<p>DBMs는 사용자들이 데이터베이스에 원하는 바(View)를 표현하기 위해 데이터베이스 언어를 제공한다. SQL(질의어), QUEL(미적분학..머시기..), 관계대수 등의 데이터베이스 언어가 제안되고 상용 DBMS에 구현되어있다. SQL이 현대에서는 짱먹었지만, SQL에 다양한 것이 있다. 이후에 데이터베이스 언어인 SQL을 다루도록 할 때 상세히 다루도록하고 이런 언어가 있다 정도만 알고 넘어가야겠다.</p>
<h3 id="sql-예제">SQL 예제</h3>
<blockquote>
</blockquote>
<ol>
<li>sID 2222인 학생의 이름을 찾자!<pre><code class="language-sql">SELECT name
FROM student
where sID = &#39;2222&#39;;</code></pre>
</li>
<li>sID가 2222인 학생이 듣고있는 교과목을 찾아보자!<pre><code class="language-sql">SELECT subject 
FROM student
where sID = &#39;2222&#39;;</code></pre>
</li>
</ol>
<p>위의 SQL은 간단하게 나타내 본 예제다. DB응용 애플리케이션은 SQL이라는 언어를 이용해서 개발한다. 일반적으로 SQL에 프로그래밍 요소를 추가하는 방식 또는 SQL API를 이용해서 진행한다.</p>
<h2 id="데이터베이스-관리-시스템-구성-요소">데이터베이스 관리 시스템 구성 요소</h2>
<p>데이터베이스 관리 시스템(DBMS)는 아주 복잡하고 방대한 소프트웨어다. 상용에 쓰고있는 mySQL, mariaDB, MongoDB 등 다양한 소프트웨어들이 있다. DBMS는 개념적으로 두가지의 구성요소를 가지고 있는데, 첫째는 질의어 처리기, 둘째로는 저장 관리자다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/30e3852a-d350-4304-9726-bbfc4dadaa1f/image.png" alt=""></p>
<ol>
<li>질의어 처리기<ul>
<li>사용자의 질의어(Query)를 처리한다.</li>
<li>데이터 접근 권한을 부여하고 철회한다.</li>
<li>인증 기능을 담당한다.</li>
</ul>
</li>
<li>저장관리자</li>
</ol>
<ul>
<li>데이터 하단부분을 의미한다.</li>
<li>데이터 저장, 검색 역할을 맡는다.</li>
<li>파일 구조, index, 트랜잭션 관리 등을 맡는다.
1) 데이터베이스 관리
2) 데이터 사전(metadata) 관리</li>
</ul>
<h3 id="metadata데이터-사전">Metadata(데이터 사전)</h3>
<p> DBMS는 사용자가 저장하여 관리하고자하는 DB 외에도 DB에 대한 데이터를 관리한다. 데이터베이스 관리 시스템에서는 메타 데이터(즉, 데이터를 설명하는 데이터)를 저장하는 장소를 데이터 사전이라고 부르며, 데이터 사전에는 데이터베이스 스키마에 대한 데이터, 제약조건에 대한 데이터, 접근 권한에 대한 데이터 등 다양한 데이터가 관리되고 있다.</p>
<h3 id="트랜잭션-관리">트랜잭션 관리</h3>
<p>트랜잭션 관리는 DBMS의 주요한 기능이다. 트랜잭션 관리는 동시성 제어와 복구 기능으로 나뉜다.</p>
<h2 id="데이터베이스-시스템의-역사">데이터베이스 시스템의 역사</h2>
<p>데이터베이스 기술 시스템에 대한 간단한 역사를 이야기해보자. <code>50,60년대</code>에는 데이터베이스 이전 단계인 <code>파일 시스템</code>을 이용하여 자료 처리를 했고, 이후 <code>70년대</code>에는 <code>네트워크 데이터 모델</code>과 <code>계층 데이터 모델</code>을 주로 사용했다. <code>1970년 E.Codd가 관계형 데이터 모델을 처음 제안</code>했는데, <code>80년대 초</code>에 <code>관계형 모델을 지원하는 상용 DBMS</code>가 처음 출시되고 이후 데이터베이스 기술은 급박하게 발전했다. 80년대 중후반에 객체지향 데이터베이스 시스템에 대한 개념이 생겨서 이후 많은 연구가 이루어졌다.</p>
<p><code>90년대 중후반에 데이터 보관과 데이터 마이닝</code>에 대한 연구가 이뤄지면서 객체 관계형 데이터 모델이 90년대 후반에 정립되었다. <code>2000년대에는 XML</code>이 나타나면서 데이터베이스 산업에서는 튜닝 및 자동 데이터베이스 관리 기술이 발전했으며 이를 지원하는 상업 데이터베이스 시스템이 나타났다. <code>2010년 이후 BigTable, Pnuts, Hadoop(apache)</code>와 같은 <code>대용량 저장 시스템 또는 대용량 분산처리 플랫폼</code>이 개발되어 사용되고있다.</p>
<h1 id="마치며">마치며</h1>
<p>DBMS에 대한 내용을 간단하게 훑고 넘어간다. 이런 역사가 있고, 이런 구성요소들이 있다는 내용을 빠르게 읽고 습득했다. 차후에 DBMS 혹은 데이터베이스 관련 서적을 구하거나 웹 페이지를 통해서 좀더 학습하고 정리해서 내 머리속에 넣어야겠다. 이전까지 DB, DBMS가 헷갈리고있었는데 어느정도 정리는 된 것 같다. 이후에 mySQL이나 MongoDB같은 DB 플랫폼 Documentation으로 공부해야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DB] 데이터 추상화 / 데이터 모델]]></title>
            <link>https://velog.io/@brian_kim/DB-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B6%94%EC%83%81%ED%99%94-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8</link>
            <guid>https://velog.io/@brian_kim/DB-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B6%94%EC%83%81%ED%99%94-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8</guid>
            <pubDate>Wed, 25 Aug 2021 08:08:21 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터-추상화--데이터-모델">데이터 추상화 / 데이터 모델</h1>
<blockquote>
<h4 id="인스턴스와-스키마">인스턴스와 스키마</h4>
<p>데이터 베이스의 인스턴스와 스키마는 데이터베이스 분야에서 사용하는 용어인데, 프로그래밍에서의 <code>변수의 값</code>과 <code>타입(type)</code>에 대응되는 유사한 개념이다. 인스턴스(instance)는 실질적인 데이터 리소스를 이야기하고, schema는 데이터베이스의 구조를 의미하니, 거의 유사한 개념이라고 봐도 될 것 같다.</p>
</blockquote>
<p>데이터베이스 스키마는 데이터베이스의 논리적(추상적? 의미적?) 또는 물리적 구조(실질적 데이터)를 의미한다.구체적으로 데이터베이스 모델에 따라서 또한 데이터베이스를 보는 높이에 따라 다르다. 그러나 <code>데이터베이스 스키마는 데이터가 저장되는 공간</code>에 대한 <code>구조</code>를 표현한다는 점에서는 같다. 우선 데이터 스키마가 결정되고 나면 실제 데이터 값이 <code>스키마 형태</code>로 저장하고 관리되는데 데이터의 <code>실질적인 값을 인스턴스</code>라고 부른다.일반적으로 시간이 지나면 데이터베이스의 인스턴스는 계속 바뀌고 수정되지만, 스키마는 시간에 따라서(효율성에 따라서 바뀔 수도 있지만) 대체로 바뀌지 않는 형식이다.</p>
<h2 id="데이터-추상화">데이터 추상화</h2>
<p>일반적으로 컴퓨터과학에서는 추상화가 어떤 사물에 대한 <code>세세한 개체로부터 중요한 개념을 분리하는 프로세스</code>라고 길게 이야기하는데, 어떤 기능 구현을 위해서 필요한 과정들을 하나로 뭉쳐서 핵심을 볼 수 있도록 만드는 과정이다. 저번에는 밥을 먹는 과정을 이야기했지만, 이번에는 조금 컴과틱하게 예시를 들어보겠다.</p>
<p>가령, <code>정수 100보다 작고, 0보다 큰 숫자들의 모임인 n배열이 있다고 했을 때 n배열을 구해보도록 하자.</code> 
그러면 답 n을 구하고자 할때 과정의 중간 단계들이 있을 것이다. 
중간 단계가 다음과 같다고 가정해보자.</p>
<ol>
<li>우선 전체 <strong>0에서 100까지의 숫자를 가지고 각각의 숫자들이 소수인지 아닌지 확인</strong>해야할 것이다. </li>
<li>확인한 뒤에는 <strong>n이라는 배열 변수에 담아주어야 한다.</strong> </li>
<li>이후에 이를 <strong>출력하는 과정</strong>이 필요하다.</li>
</ol>
<p>가볍게 적어봤다. 작은 문제를 세세히 나누려고 하니 쉽지않다. 여기에서 좀 더 나눠 본다고 하면, 두번째 소수체크 부분이 나누어진다.</p>
<blockquote>
<blockquote>
<p>** 2. 해당 숫자가 소수인지 확인해야 한다. (isPrime(num)) **
2-1. target인 num의 제곱근 범위까지 나누어 떨어지는 숫자가 1외에 있는지 확인한다.
2-1-1. 만약 1이외에 숫자가 있다면, false
2-1-2. 1이외에 숫자가 없다면, true</p>
</blockquote>
</blockquote>
<p>이렇게 세가지 과정이 되면, 중간의 소수인지 확인하는 과정을 따로 묶어 <code>isPrime(num)</code>과 같이 표현할 수 있다. 물론 문제를 해결하려고 할 때 알고리즘을 작성해야하는 것은 마찬가지지만, 소수를 구하는 기능이 되고나면 <code>isPrime</code>이라는 하나의 방법적인 도구가 된다. 이런 식으로 큰 문제에서 떨어져 나온 세부적인 사항들을 묶어서, 단순화 시켜나가는 방식이다. 데이터베이스 역시, 관련된 데이터를 묶어서 연관데이터를 구성할 수 있고, 이를 통해서 특정한 데이터베이스 구축이라는 목표를 달성할 수 있다. 내가 이해한 것이 맞는지는 모르나, 후에 더 공부하다보면 상세히 알게되리라 믿는다. 현실에서의 <code>실눈뜨고 보기</code>랑 비슷해보인다.</p>
<h3 id="데이터-추상화-레벨">데이터 추상화 레벨</h3>
<p>데이터베이스 시스템은 데이터베이스에 대한 추상화를 제공하는데, 추상화를 위해 관점(높이 또는 레벨)은 세 가지로 구성되어있다. 데이터베이스는 사실 컴퓨터 내부에는 물리적으로 아주 어렵게 저장되어있겠지만, 세가지 다른 관점에서 편하게 볼 수 있다. 논리적 레벨의 데이터 추상화는 데이터베이스에 저장되어 있는 데이터와 데이터간의 관계를 논리적 관점에서 추상화하는 것이다. </p>
<pre><code class="language-sql">    Type student = record
        ID : string;
        name : string;
        department : string;
        grade : string;
    end;</code></pre>
<p>다음과 같은 스키마를 선언한다고 할 때, student는 하나의 레코드이고, ID(string 타입), name(string타입), department(string 타입), grade(string 타입) 4가지 구성요소로 이루어져있다고 선언하는 것이다.</p>
<h4 id="3단계-추상화">3단계 추상화</h4>
<p><img src="https://images.velog.io/images/brian_kim/post/e401141c-8442-4f33-a56e-d75741aead8c/image.png" alt=""></p>
<p>3단계 추상화를 나타낼 때, 위와 같이 나타낸다. 내부 단계를 내부 스키마 혹은 물리적 스키마라고 부르고, 개념 단계를 논리적 스키마 혹은 개념 스키마라고 부른다. 가장 최외곽을 외부 스키마 혹은 뷰 레벨이라고 부르는데, 나눠진 것이 어려운 것이지 이해하면 쉽다. </p>
<blockquote>
<p>뷰 레벨에서는 <code>개념 스키마</code>를 이용해서 사용자가 원하는 <code>데이터 조합으로 만들어 낸 뷰</code>를 볼 수 있다. 내가 뽑아내는 방식에 따라 뷰가 달라지기 때문에 조합은 무한에 가깝다.(그래도 조합으로 따지면 범위를 찾을 수는 있겠지만..)<code>논리적 레벨</code>에서는 <code>개략적인 데이터 구조</code>를 보여준다. ID, name, department, grade와 같이 이런 데이터들을 포함하고 있다는 것을 보여준다. <code>물리적 레벨</code>에서는 추상화는 <code>실제 데이터 레코드가 어떻게 저장되는지</code>를 보여주며, <code>데이터 필드의 길이, 필드간의 간격길이, 레코드의 전체 길이</code>와 같은 것이 들어가기도 한다.</p>
</blockquote>
<p>각 레벨마다 추상화하는 방식은 DBMS마다 좀 다르기도 하지만, 기본적으로 한 데이터베이스에 기반하고 있는 정보들이라는 것이 중요하다. 어찌됐던 스키마와 뷰들이 가르키고 있는 곳은 컴퓨터에 저장되어있는 데이터 베이스 하나다. 데이터베이스에서 3단계 추상화가 성립되면, 추상화에 따라 데이터베이스 스키마를 생성하고, 그 결과 <code>3단계 스키마 구조</code>가 짜여진다. 각 레벨에 따른 스키마는 <code>뷰 스키마</code>, <code>논리적 스키마</code>, <code>물리적 스키마</code>로 부른다. 참고로, 3단계 스키마 구조는 1978년에 제안되었고, 일명 ANSI/SPARC 구조라고도 한다. 상용 데이터베이스는 기본적으로 3단계 스키마 구조를 지원하려고 한다.</p>
<h2 id="데이터-모델data-model">데이터 모델(data model)</h2>
<p>데이터 모델은 데이터, 데이터 관계성, 데이터 의미, 데이터 제약 조건 등을 기술하는 specification 또는 개념적인 도구다. 데이터 모델은 데이터 추상화를 지원하는 도구이며, 우리는 데이터 모델을 이용해서 데이터를 개념화하거나 조작할 수 있다.</p>
<p>데이터 모델의 종류에는 관계형 데이터 모델, 객체지향 데이터 모델, 객체관계형 데이터모델, 네트워크 데이터 모델, 계층 데이터 모델등이 있으며 또한 개체-관계 데이터 모델, XML 데이터 모델 등 다수가 제안되어있다. 네트워크 데이터 모델 및 계층(트리 구조)데이터 모델은 현대사회에서는 더이상 사용되지 않으며 이를 지원하는 구 시스템을 레거시라고 부른다. 상용 DBMS는 위에서 하나를 제공하는데 관계형 데이터모델은 관계형 데이터베이스만을 지원한다. 데이터 모델은 사용자가 데이터베이스를 보는 관점을 나타내기 때문에 데이터 모델이 다른 DBMS은 동일 데이터베이스를 저장/관리해도 서로 완전히 다른 DBMS로 보인다.</p>
<h3 id="relation-예제">Relation 예제</h3>
<table>
<thead>
<tr>
<th>sId</th>
<th>name</th>
<th>gender</th>
<th>deptName</th>
<th>age</th>
<th>GPA</th>
<th>totalCredits</th>
</tr>
</thead>
<tbody><tr>
<td>152</td>
<td>Eric Lee</td>
<td>M</td>
<td>CS</td>
<td>22</td>
<td>3.54</td>
<td>15</td>
</tr>
<tr>
<td>201</td>
<td>Alice Kim</td>
<td>F</td>
<td>AT</td>
<td>24</td>
<td>3.99</td>
<td>103</td>
</tr>
<tr>
<td>301</td>
<td>Jordan Park</td>
<td>M</td>
<td>Bio</td>
<td>21</td>
<td>4.4</td>
<td>54</td>
</tr>
<tr>
<td>157</td>
<td>Brian Kim</td>
<td>CS</td>
<td>M</td>
<td>29</td>
<td>3.85</td>
<td>22</td>
</tr>
<tr>
<td>154</td>
<td>Jason Ban</td>
<td>Media</td>
<td>F</td>
<td>24</td>
<td>2.45</td>
<td>19</td>
</tr>
</tbody></table>
<p>관계형 데이터 모델은 80년대 이후 가장 많이 사용되는 데이터 모델이며, 위의 그림은 관계형 데이터 모델의 기본 요소인 Relation(릴레이션)을 보여준다. 우리가 일반적으로 인지하고 있는 테이블 형식이다. 각 column은 속성을 의미하고, 각 row는 단일 records다.</p>
<blockquote>
<p>일단 여기까지만 정리하고 넘어가자. 객체형 데이터 베이스나 NoSQL도 공부해야하고 공부해야할 것이 산더미다..</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DB] 데이터베이스란?]]></title>
            <link>https://velog.io/@brian_kim/DB-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EB%9E%80</link>
            <guid>https://velog.io/@brian_kim/DB-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EB%9E%80</guid>
            <pubDate>Wed, 25 Aug 2021 07:03:50 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터베이스란">데이터베이스란?</h1>
<blockquote>
<p>데이터베이스(DB, Database)는 서로 <code>연관성있는 데이터들의 모임</code>을 이야기한다. 일반적으로 우리가 관심 있는 데이터베이스는 컴퓨터에 저장되어 있는 데이터이며, 또한 <code>데이터 용량이 방대하며</code> 주기억장치에는 저장이 불가능하여 <code>2차저장장치인 하드디스크 또는 플래시 메모리에 저장되는 데이터</code>다. 
<img src="https://images.velog.io/images/brian_kim/post/25c4cdc2-934d-4677-9a26-f063acfd0b22/image.png" alt=""></p>
</blockquote>
<p>말그대로 데이터베이스 분야는 대용량 데이터 처리 기술을 연구 및 개발하는 것이 목적이다. 관심있는 데이터 베이스분야는 모두 대용량 데이터이며 정형화 데이터 및 비정형 데이터를 모두 포함하고 있다. 참고적으로 비교적 작은 데이터 처리를 다루는 분야는 자료구조(data structure)이다.</p>
<h2 id="db-dbms">DB? DBMS?</h2>
<p>위에 적힌 것처럼 데이터베이스는 연관성있는 데이터들의 모임이다. 데이터베이스는 컴퓨터에 저장되는 데이터의 모임으로 자료량이 어마무시해서 HDD나 SSD에 저장되곤 한다. 컴퓨터에 데이터베이스를 넣어놓기만 하면 어디에 쓸 수 있을까? 데이터를 처리하고 관리하기 위해서 사용되는 소프트웨어를 DBMS(Database Management System)라고 부른다. 한국어로 데이터베이스 관리 시스템이다. DBMS에는 다양한 종류가 있는데, DBMS 혹은 DBS라고 부르기도 한다. </p>
<blockquote>
<h3 id="dbms">DBMS</h3>
<p>DBMS는 사용자에게 데이터를 관리하는데에 필요한 기능들을 제공한다. 기본적으로 데이터를 정의한다던지, 생성한다던지 변경하고 삭제하고 접근하고 <code>조작에 필요한 모든 기본 연산 기능</code>을 제공한다. 또 DBMS는 데이터 추상화(간편하게 부르기!), 데이터 독립성(데이터는 독립되어 저장), 데이터 보호 등의 관리차원에서 필요한 것들도 모두 제공해준다. DBMS는 <code>데이터베이스와 데이터베이스 관리시스템을 통칭하는 말</code>에 가깝다.</p>
</blockquote>
<h1 id="그래서-db가-있으면-뭐가-좋은데">그래서? DB가 있으면 뭐가 좋은데?</h1>
<hr>
<p>일단 데이터베이스를 왜 쓰는건지 생각해봐야한다. 예를 들어 20~30명 정도의 데이터를 보관하고 관리한다면 간단한 자료구조들로도 충분히 가능하다. 연결리스트, 해시테이블, 스택, 큐 같은 것들이다. 하지만 수백만에 달한다고하면 단순한 데이터 자료구조만으로는 감당하기 힘들다. 우리나라 국민 전체의 신상데이터를 보관한다고 하면 전체 데이터 용량이 엄청나고, 일반적인 조회방식이나 관리방식으로는 데이터를 관리하기가 현실적으로 어렵다. 그러면 왜 쓰면 좋을까?</p>
<h2 id="사용자-입장에서-데이터베이스-사용-장점">사용자 입장에서 데이터베이스 사용 장점</h2>
<h3 id="1-데이터-추상화-제공">1. 데이터 추상화 제공</h3>
<p>데이터를 추상화할 수 있게 도와준다. <code>추상화</code>라는 의미가 되게 어렵게 다가오는데 기본적으로 중심적인 개념을 가지고 전체 큰 부분을 간략하게 나타낼 수 있도록 하는 것이다. </p>
<blockquote>
<p>예를 들어 <code>밥을 먹다.</code>라는 간단한 행동이지만, 세부적으로 따져보면 <code>숟가락을 든다. 숟가락을 밥 위로 이동시킨다. 숟가락으로 밥을 푼다. 숟가락을 그대로 들어올린다. 숟가락을 입으로 이동시킨다. 입을 연다. 숟가락을 입속으로 넣는다.</code>와 같은 어이없이 긴 이야기가 될 수 있다. </p>
</blockquote>
<p>밥을 먹는다는 작은 행동을 표현하기 위해 이만큼의 설명이 필요한데, <code>밥을 먹다</code>라는 두 단어로도 저 과정을 충분히 연상할 수 있다. 데이터도 한 사람에 대한 의료정보라고하면 수많은 내역들이 있는데 이를 응집해서 <code>OOO님의 의료정보</code>식으로 간략하게 추상화시킬 수 있다. 내가 이해하는 추상화는 정보를 하나로 표현할 수 있도록 간략화하는 것에 가깝다. 이후에 추상화에 대한 이야기를 좀 더 적어보겠지만, 우선은 내가 이해한대로 이해하는 것이 좋겠다.</p>
<h3 id="2-데이터-접근의-용이성-제공">2. 데이터 접근의 용이성 제공</h3>
<p>데이터베이스 시스템은 데이터 접근을 위한 언어를 제공하고 편리한 사용자 인터페이스를 제공한다. 만약에 node의 기본 모듈인 fs을 이용해서 데이터에 접근한다고하면 수많은 코드들이 엉기어 읽기 힘들어질 것이다. 파일을 열고, 파일을 연 상태에서 내부 파일에 들어있는 데이터를 받아서 이를 가공하고 다시 데이터 변경 메소드를 사용하고... 과정만 생각해도 복잡하다. 하지만 DBMS라면 SELECT * FROM (TABLE)과 같이 간편하게 데이터를 열람할 수 있다. 수정/삭제도 동일하다.</p>
<h3 id="3-데이터-중복-및-불일치성에-대한-제어-용이">3. 데이터 중복 및 불일치성에 대한 제어 용이</h3>
<p>데이터베이스 불일치성은 데이터 간에 값이 서로 일치하지 않는 현상을 말하는데, 파일 시스템을 사용하면 놓치는 부분이 생겨서 데이터가 온전히 유지되기 힘들다. 실수로 하나라도 놓치거나 하나라도 더 추가하면 원래 데이터와 갱신된 데이터간의 차이가 생기기 시작하고, 어디서 비틀렸는지 찾지 못하면 그 수많은 데이터에서 문제인 부분을 찾아야하니 고깝다. 중복이 생기면 불일치성이 생기고, 하나라도 손실되면 불일치성이 생긴다.</p>
<h3 id="4-데이터-무결성-제약조건integrity-constraint-유지-용이">4. 데이터 무결성 제약조건(integrity constraint) 유지 용이</h3>
<p>말이 어렵지만, 데이터에는 제약조건이 있다. <code>님 나이가 몇살이에요?</code>라고 물어보는데 <code>음.. 저는 -33살이요</code>라고 말하는 사람이 어디있을까? 나이에는 예컨데 <code>1살에서 100살 사이</code>와 같은 제약조건이 붙는다. 그런 제약조건이 존재하지 않는 데이터는 없다. 명확성도 떨어질 뿐더러, 데이터가 말하는 바를 이해하기 어렵다. 하지만 이를 수동으로 조작하게 된다면? 혹여 조건문에서 예외케이스를 발견하지 못한다면? 아마 데이터베이스에는 제약조건을 어긴 데이터가 들어갈지도 모른다. 수백만의 데이터가 있다고 생각한다면 매번 이를 정상화 시키기 위한 시간조차도 허비되는 자원이 될지도 모른다.</p>
<h2 id="데이터-관리-측면에서-데이터베이스-사용-장점">데이터 관리 측면에서 데이터베이스 사용 장점</h2>
<h3 id="1-갱신-원자성-제공">1. 갱신 원자성 제공</h3>
<p>데이터베이스 시스템에서는 데이터 갱신이 원자적으로(전체가 동일하게) 이루어져야 하며, 이는 데이터 갱신시에 갱신 연산이 부분적으로 데이터베이스에 반영되질 않음을 의미한다. 갱신 연산이 부분적으로 이루어지면 데이터베이스 상태가 불일치되거나 데이터베이스 제약조건이 깨질 수도 있다. 예컨데 나이 조건을 <code>20살 이상</code>으로 변경했다고 치자. 근데 절반의 데이터만 적용되어 갱신되고 나머지가 되지 않는다면? 전체 데이터베이스는 통일성(원자성)을 잃고 무너진다. 제약조건이 깨진 것도 문제고, 데이터베이스 상태가 맛이 간 것이나 다름없다.</p>
<h3 id="2-다수-사용자의-동시성-제어">2. 다수 사용자의 동시성 제어</h3>
<p>데이터베이스 시스템 환경은 다수의 사용자가 동시에 동일한 데이터베이스 시스템 환경에 접근하게 된다. 내가 접속한 곳과, 다른 곳에서 접속했을 때 데이터베이스 상태가 다르다면 문제가 된다. 그렇기 때문에 다수가 사용하더라도 같은 데이터베이스 상태로 제어를 제공할 수 있어야 된다.</p>
<h3 id="3-데이터-보호">3. 데이터 보호</h3>
<p>데이터 보호는 다양한 사이버 공격, 혹은 데이터 접근으로부터 데이터를 보호하는 것이다. 데이터베이스는 기본적으로 이러한 데이터 보호 기능을 제공한다. 파일 시스템이랑 계속 비교하는데, 아무래도 데이터를 다루는 것은 동일하니 비교하는 것이다. 데이터베이스 시스템에서 제공하는 것은 데이터만을 위한, 데이터에 의한, 데이터의 보호를 목적으로 만들어진 보호 기능이기 때문에 OS에서 기본적으로 제공하는 보안 기능과는 확연한 차이를 보인다. 이러한 차이는 나중에 알아보자! </p>
<h3 id="데이터-백업-및-회복">데이터 백업 및 회복</h3>
<p>데이터가 날아갔다! 그러면 지옥을 경험할지도 모른다. 100만명 분의 데이터가 갑자기 날아갔다면 어떻게 반응해야될까? 아마 깜짝놀래고 키보드 샷건치는 것만으로는 부족하다. 시스템 장애에 의해서 날아갔다면 그것도 나름대로 모니터가 부서지는 일이 벌어질지도 모른다. 기본적으로 DBMS는 히스토리를 이용해서 데이터를 백업해두거나 리스토어 시킬 수 있는 기능을 제공한다.</p>
<blockquote>
<h4 id="파일시스템file-system">파일시스템(file System)</h4>
<p>일반적으로 운영체제(OS)에 기본적으로 탑재된 기능이다. 유닉스나 리눅스는 fileSystemㅇ이라는 파일시스템을 제공한다. 파일을 읽고, 쓰고, 저장하고, 삭제하고, 열고, 닫고 등의 기본적인 파일 관리 기능을 제공하는 것이다. 데이터베이스 관리 시스템은 이 파일 시스템을 이용한 경우가 대부분인데, 따라서 DBMS는 운영체제의 프로세스 중에 하나다. 파일 시스템으로도 DB관리가 가능하지만, 데이터가 너무 많을 때, 그리고 일일히 OS에서 관리하기 어렵다는 점에서 DBMS에 밀리는 부분이 많다. 알아두자!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[네트워크]네트워크, 인터넷, DNS]]></title>
            <link>https://velog.io/@brian_kim/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%9D%B8%ED%84%B0%EB%84%B7-DNS</link>
            <guid>https://velog.io/@brian_kim/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%9D%B8%ED%84%B0%EB%84%B7-DNS</guid>
            <pubDate>Tue, 24 Aug 2021 15:23:10 GMT</pubDate>
            <description><![CDATA[<h1 id="네트워크network">네트워크(Network)</h1>
<blockquote>
<p>네트워크의 사전적 의미는 <code>전선이나 혈관, 통로 등으로 이루어진 망형 조직</code>이다. &#39;네트워크&#39;라는 용어는 방송사 네트워크, 인맥을 의미하는 <code>휴먼 네트워크(Human Network)</code> 등 다양한 의미로 사용하는데, 그 중 가장 많이 쓰이는 의미는 <code>컴퓨터와 컴퓨터를 연결해주는 망</code>이다.</p>
</blockquote>
<p><img src="https://images.velog.io/images/brian_kim/post/ac74a624-a119-4107-9f23-0d546aa81b03/image.png" alt=""></p>
<p>컴퓨터와 컴퓨터를 연결한 네트워크는 이전보다 더 편리한 세상을 만들었다. 네트워크가 보편화되기 전에는 보고서를 제출하려면 직접 하드카피를 인쇄해 전달해야 했지만, 지금은 이메일(Email)이나 웹하드(Webhard), 클라우드(Cloud) 기반의 스토리지(Storage)를 통해 제출하는 것이 일반적인 상황이 되었다. 이처럼 네트워크는 이전과는 비교할 수 없는 편리함을 가져다줬다. 인터넷은 이런 <code>네트워크 응용 서비스의 한 종류</code>라고 할 수 있는데, 스마트폰을 통해 인터넷을 사용할 수 있는 것도 각각의 응용 서비스 모두가 네트워크로 연결되어 있기 때문에 가능한 것이다. 스마트폰에서 사용하는 모바일 네트워크는 <code>WIFI, 4G LTE, 5G</code> 등 무선 통신망을 이용한다.</p>
<p>네트워크를 구축하려면 컴퓨터 간의 연결 규격 즉, 프로토콜(Protocol)이라는 것이 필요하다. 여러 프로토콜 중 가장 대표적으로 널리 쓰이고 또한 인터넷에서 사용되고 있는 TCP/IP에 대해 자세히 알아보자!</p>
<h2 id="tcpip">TCP/IP</h2>
<hr>
<p>TCP/IP(<code>Transmission Control Protocol/Internet Protocol의 약자</code>)는 컴퓨터 간에 통신할 수 있도록 만든 프로토콜의 하나다. 이 프로토콜에 기반하고 있는 것이 인터넷인데, TCP/IP가 인터넷의 기반 프로토콜로 자리잡은 이유는 <code>하드웨어(Hardware), 운영체제(OS), 접속 매체와 관계없이 동작할 수 있는 개방형 구조</code>이기 때문이다. 원래는 TCP/IP는 OSI(Open Systems Interconnection) 7계층에 포함되는 프로토콜로, TCP/IP는 네 개의 계층으로 이루어져 있다.</p>
<table>
<thead>
<tr>
<th align="left">계층</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="left">응용 계층</td>
<td align="center"><strong>WWW, FTP, Telnet, SMTP</strong>같은 네트워크 프로그램으로 구성된다.</td>
</tr>
<tr>
<td align="left">전송 계층</td>
<td align="center">각 시스템을 연결하고 <strong>TCP 프로토콜</strong>을 이용하여 <strong>데이터를 전송</strong>한다.</td>
</tr>
<tr>
<td align="left">인터넷 계층</td>
<td align="center"><strong>IP 프로토콜</strong>을 이용해서 <strong>데이터를 정의하고 경로를 배정</strong>한다.</td>
</tr>
<tr>
<td align="left">물리 계층</td>
<td align="center"><strong>실제 네트워크</strong>를 접근할 수 있도록 하는 <strong>하드웨어</strong>적인 부분이다.</td>
</tr>
</tbody></table>
<p>원래 OSI 7계층은 네트워킹을 위한 <code>물리적 장비에서 실제 서비스를 제공하기 위한 애플리케이션에 이르는 단계를 계층화</code>한 것을 말한다. 이러한 계층화를 통해, 상위 레벨에서는 하위 레벨에서 구현한 내용을 모르더라도 <code>표준화된 인터페이스</code>를 통해 네트워크 시스템을 개발하고 운영할 수 있다. TCP/IP는 OSI 7계층을 좀더 단순화해서 4계층으로 정의한 것이다.<code>TCP는 데이터의 흐름 관리, 데이터 정확성 확인</code> 등의 역할을 수행하고 <code>IP는 데이터(패킷)을 목적까지 전송하는 역할</code>을 담당한다. <code>TCP/IP는 개방형 구조</code>로서, 특정 운영체제나 하드웨어에 영향을 받지 않고 근거리와 원거리 모두 데이터를 전송할 수 있다.</p>
<h2 id="ipinternet-protocol">IP(Internet Protocol)</h2>
<hr>
<p>IP 주소(IP Address)는 TCP/IP로 연결된 네트워크에서 각각의 컴퓨터를 구분하려고 사용하는 주소다. IP 주소는 숫자로 구성되어 있고, &#39;123.123.123.123.&#39;과 같이 네 개로 구분된 10진수를 사용한다. 사용할 수 있는 IP 주소 범위는 다음과 같다.</p>
<table>
<thead>
<tr>
<th align="left">구분</th>
<th align="left">범위</th>
<th align="left">네트워크 수</th>
<th align="left">사용목적 / 네트워크당 주소</th>
</tr>
</thead>
<tbody><tr>
<td align="left">클래스 A</td>
<td align="left">1.0.0.0 ~ 127.0.0.0</td>
<td align="left">128</td>
<td align="left">대형 통신망 / 16,777,214개</td>
</tr>
<tr>
<td align="left">클래스 B</td>
<td align="left">128.0.0.0 ~ 191.255.0.0</td>
<td align="left">16,384</td>
<td align="left">중형 통신망 / 65,534개</td>
</tr>
<tr>
<td align="left">클래스 C</td>
<td align="left">192.0.0.0 ~ 223.255.255.0</td>
<td align="left">2,097,152</td>
<td align="left">소형 통신망 / 256개</td>
</tr>
<tr>
<td align="left">클래스 D</td>
<td align="left">224.0.0.0 ~ 239.255.255.255</td>
<td align="left">-</td>
<td align="left">멀티캐스트</td>
</tr>
<tr>
<td align="left">클래스 E</td>
<td align="left">240.0.0.0 ~ 225.255.255.255</td>
<td align="left">-</td>
<td align="left">실험 목적 / 배포 중지</td>
</tr>
</tbody></table>
<p>이론적으로 컴퓨터가 TCP/IP 네트워크에 연결되려면 <code>IP 주소가 있어야 하고, 인터넷에 연결된다면 전세계 모든 컴퓨터에 원격으로 접속할 수 있어야 한다.</code> 하지만 수많은 컴퓨터에 각기 다른 고유한 IP주소를 할당하기에는 한계가 있다. 모바일 인터넷의 급속한 확산과 함께 IP 주소 고갈 문제가 심각해졌다. 그러나 현재는 초기 보다 문제가 어느정도 해결되었다. 네트워크 및 라우터의 발달로 사설 IP를 통해 대부분의 인터넷 서비스를 이용할 수 있게 되었기 때문이다. 따라서 모든 인터넷 클라이언트가 공인IP를 사용할 필요가 없고, 이를 해결하려고 고안된 방안인 IPv6의 보급은 다소 늦춰질 전망이다.</p>
<p>사설 IP는 일반적으로 10.x.x.x, 192.x.x.x 등 몇 가지 IP 블록을 사용하지만, 실제로는 모든 인터넷 IP를 사용할 수 있다. 다만 네트워크 구성상 직접 인터넷에 연결되지 않고 <code>라우터 장비</code> 등에서 제공하는 <code>NAT(Network Access Translator)</code> 기능을 이용해서 접속해야 한다. NAT를 이용해서 공인 IP로 대응하면 인터넷에 접속할 수 있다. 쉽게 생각하면 집에서 사용하는 유무선 인터넷 공유기를 생각하면 된다. 공유기에 연결된 컴퓨터나 스마트폰은 <code>DHCP(Dynamic Host Configuration Protocol)</code>라고 하는 <code>동적 IP 할당 프로토콜</code>에 의해서 사설 IP를 배정받게 되고, <code>공유기를 통해 인터넷 연결</code>이 관리된다.</p>
<h2 id="인터넷">인터넷</h2>
<hr>
<p>인터넷 자체는 네트워크 인프라를 의미하고, 우리가 알고있는 WWW, Email 서비스 등은 인터넷 기반의 서비스다. 웹은 인터넷에 기반한 서비스이기 때문에 인터넷과 관련된 기본 기술과 용어, 동작원리들은 잘 이해하고 있어야한다.</p>
<h3 id="인터넷-기반-서비스">인터넷 기반 서비스</h3>
<p>인터넷 기반의 대표적인 서비스는 웹(WWW) 이외에도 이메일(Email), FTP, Telnet, DNS, News 등이 있다. 인터넷 초창기에는 웹보다 다른 것들이 주된 서비스였으나, 지금은 웹이 절대적이다. 최근에는 이메일 서비스 조차도 독립적인 사설 웹 서비스 위에 올라가 있다. SNS 서비스가 등장하면서 웹 서비스 위에서 구동되는 서비스는 훨씬 더 다양해졌다. 아래 적혀진 모든 서비스의 프로토콜이 따로 되어있는데 모두 <code>TCP/IP</code> 라는 프로토콜로 물리적으로 연결되어 있다.</p>
<table>
<thead>
<tr>
<th align="left">서비스</th>
<th align="left">기능</th>
<th align="left">프로토콜</th>
<th align="left">포트</th>
</tr>
</thead>
<tbody><tr>
<td align="left">웹(WWW)</td>
<td align="left">웹 서비스</td>
<td align="left">HTTP</td>
<td align="left">80</td>
</tr>
<tr>
<td align="left">이메일(Email)</td>
<td align="left">이메일 서비스</td>
<td align="left">SMTP/POP3/IMAP</td>
<td align="left">25/110/143</td>
</tr>
<tr>
<td align="left">FTP</td>
<td align="left">파일 전송 서비스</td>
<td align="left">FTP</td>
<td align="left">21</td>
</tr>
<tr>
<td align="left">Telnet</td>
<td align="left">원격 로그인 서비스</td>
<td align="left">TELNET</td>
<td align="left">23</td>
</tr>
<tr>
<td align="left">DNS</td>
<td align="left">도메인 이름 변환 서비스</td>
<td align="left">DNS</td>
<td align="left">53</td>
</tr>
<tr>
<td align="left">News</td>
<td align="left">인터넷 뉴스 서비스</td>
<td align="left">NNTP</td>
<td align="left">119</td>
</tr>
</tbody></table>
<blockquote>
<p><strong>프로토콜(Protocol)</strong>
프로토콜은 네트워크에 연결된 컴퓨터들간의 통신 규약</p>
</blockquote>
<p>물리적인 네트워크 연결은 TCP/IP를 사용하지만, 응용 서비스를 위한 별도의 규격으로 이해하면 된다. <code>포트</code>는 네트워크 서비스를 <code>접속하기 위한 접점</code>으로 하나의 컴퓨터에서 여러 개의 네트워크 서비스를 제공하는 경우 이들을 구분하기 위한 목적으로 사용한다. 은행에서 <code>입출금, 대출, 신용카드, 보험 등 업무에 따라 창구를 구분해 놓은 것과 같은 개념</code>으로 이해하면 된다. 해당 업무를 처리하지 않는 창구에서는 내가 원하는 서비스를 받을 수 없는 것과 마찬가지로 <code>포트와 프로토콜이 일치하지 않는 경우에는 정상적으로 네트워크 서비스를 사용할 수 없다.</code></p>
<h2 id="dnsdomain-name-system">DNS(Domain Name System)</h2>
<hr>
<p><img src="https://images.velog.io/images/brian_kim/post/b936cc66-0190-4db3-b078-b3d69cf58e5a/image.png" alt=""></p>
<p>우리나라 국민이라면 다른 사람과 구별되는 고유번호인 주민번호가 있다. 컴퓨터도 마찬가지로 단말기마다 부여된 고유한 번호가 있는데, 그게 IP다. IP주소는 네트워크에서 사용하는 구분 번호다. 그런데, 사람들끼리 이름이 아니라 주민번호로 부르면 얼마나 힘들까? 그래서 만들어진게 도메인 이름 시스템이다. 고유번호에 이름을 만들어줘서 쉽게 구분지을 수 있도록 만든 것이다. <code>www.naver.com</code>, <code>www.google.com</code> 등의 인터넷 주소는 호스트(컴퓨터) 이름(www) + 도메인 이름(google.com)의 형태로 되어 있다. 여기서 도메인 이름은 전 세계적인 관리 체계가 있기 때문에 마음대로 붙일 수는 없고, 도메인을 관리하는 기관이나 업체에 일정 비용을 지불하고 사용할 수 있다.</p>
<p>우리가 일상적으로 사용하는 도메인 이름을 통한 웹 사이트 접속도 겉으로는 보이지 않지만, 내부적으로 도메인 이름을 IP Address로 변환하는 서비스를 이용하는 것이다. 이러한 서비스를 <code>도메인 이름 시스템</code>이라고 부른다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/86614975-b2f1-48ea-a40b-473ed6be49d7/image.png" alt=""></p>
<h3 id="dns-처리-과정">DNS 처리 과정</h3>
<ol>
<li><p>PC의 호스트 파일에 <code>www.google.com</code>에 대한 IP 주소정보가 있는지 확인한다.</p>
<blockquote>
<p>윈도우 : c:\windows\system32\drivers\etc\hosts
리눅스 : /etc/hosts</p>
</blockquote>
</li>
<li><p>PC의 DNS캐시에 <code>www.google.com</code>에 대한 IP 주소가 있는지 확인한다.</p>
</li>
<li><p><code>Local DNS</code>에 <code>www.google.com</code>에 대한 <code>DNS query</code>를 보낸다. Local DNS는 내 PC 에 설정되어 있는 네임서버다.
<code>예) 168.126.63.1 (KT DNS), 8.8.8.8 (google DNS) 등</code></p>
</li>
<li><p><code>Local DNS</code>의 DNS 캐시정보에 <code>www.google.com</code>에 대한 IP 주소가 있는지 확인한다.</p>
</li>
<li><p><code>Local DNS</code>는 <code>Root DNS</code>에 <code>www.google.com</code>에 대한 IP 주소를 요청하는 <code>DNS query</code>를 보낸다.</p>
</li>
<li><p><code>Root DNS</code>는 자신의 ZONE 파일에 정보가 있다면 IP 주소를 응답하고, 없다면 <code>.COM</code>의 DNS 서버 주소를 반환한다.</p>
</li>
<li><p><code>Local DNS</code>는 <code>Root DNS</code>에서 받은 <code>COM DNS</code>에 <code>www.google.com</code>에 대한 IP 주소정보를 요청하는 <code>DNS query</code>를 보낸다.</p>
</li>
<li><p><code>COM DNS</code>는 자신의 ZONE파일에 정보가 있다면 IP주소를 응답하고, 없다면 <code>google.com</code>의 DNS 서버 주소를 응답한다.</p>
</li>
<li><p><code>Local DNS</code>는 <code>COM DNS</code>에서 받은 <code>google.com DNS</code>에 <a href="http://www.google.com%EC%97%90">www.google.com에</a> 대한 IP 주소 정보를 요청하는 <code>DNS query</code>를 보낸다.</p>
</li>
<li><p><code>google.com DNS</code> 는 ZONE 파일 정보를 확인하여 IP 주소를 응답해준다.</p>
</li>
<li><p><code>Local DNS</code>는 <code>google.com DNS</code>에서 응답받은 IP 주소를 <code>client</code>에 응답한다. 그러면서 TTL 시간 동안 <code>www.google.com 의 IP 주소</code>를 캐싱한다.</p>
</li>
<li><p><code>client</code>는 <code>Local DNS</code>에서 받은 IP 주소(<a href="http://www.google.com)%EB%A1%9C">www.google.com)로</a> 접속 요청을 한다. 그러면서 TTL 시간 동안 <code>www.google.com의 IP 주소</code>를 캐싱한다.</p>
</li>
<li><p><code>www.google.com 서버</code>는 <code>www.google.com</code> 첫 화면을 <code>client</code>에 전송한다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[웹]브라우저 내에서 사용하는 알고리즘]]></title>
            <link>https://velog.io/@brian_kim/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%82%B4%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@brian_kim/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%82%B4%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Tue, 24 Aug 2021 07:53:07 GMT</pubDate>
            <description><![CDATA[<h1 id="브라우저-내에서-사용되는-알고리즘">브라우저 내에서 사용되는 알고리즘</h1>
<p>이전에 브라우저가 리소스를 가져와서 파서를 이용해서 파싱트리를 구성하고, 파싱트리를 컴파일러를 통해서 기계어로 번역하는 과정까지 살펴봤다. 그 과정에서 HTML이라는 마크업 언어는 유연하기 때문에 파싱이 어렵다는 사실까지 알았다. 그렇다면 내부에서 파싱이 일어날때 어떤 알고리즘을 이용해서 이것들을 파싱하게 되는지, 중간에는 어떤 알고리즘을 이용해서 토큰화하는지, 최종적으로는 이런 트리를 어떻게 구성하는지에 대한 알고리즘들을 간단하게 살펴보도록 하겠다.</p>
<h2 id="파싱-알고리즘">파싱 알고리즘</h2>
<p>HTML은 일반적인 하향식, 상향식 파싱이 안되는데 이전 글에서 살펴본 것과 마찬가지로 문법에 예외 사항이 많이 있다는 이유로 하나로 퉁치기에는 조금 성의가 부족한 것 같아 몇 가지를 살펴보자.</p>
<blockquote>
<ol>
<li>언어의 너그러운 속성, 간혹 태그가 생략되는 경우가 존재한다.</li>
<li>잘 알려져 있는 HTML 오류에 대해서 브라우저에서 미리 필터링을 한다.</li>
<li>변경에 의한 재파싱, 일반적으로 소스는 파싱하는 동안 변하지 않지만 HTMl에서 <a href="https://developer.mozilla.org/ko/docs/Web/API/Document/write">document.write</a>를 포함하고 있는 스크립트태그는 토큰을 추가할 수 있기 때문에 실제로는 입력과정에서 파싱이 수정된다.</li>
</ol>
</blockquote>
<p><code>일반적인 파싱 기술을 사용할 수 없기 때문에</code> 브라우저는 HTML 파싱을 위해 <code>별도의 파서를 생성</code>한다. 파싱 알고리즘은 <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html">HTML Documentation</a>에 자세히 설명되어 있다. 알고리즘은 <code>토큰화(어휘 나누기)</code>와 <code>트리 구축(구조로 만들기)</code> 이렇게 두 단계로 되어 있다. </p>
<p>토큰화는 어휘 분석으로서 입력 값을 토큰으로 파싱한다. HTML에서 토큰은 <code>시작 태그</code>, <code>종료 태그</code>, <code>속성 이름</code>과 <code>속성 값</code>이다.</p>
<p><code>토큰화</code>는 토큰을 인지해서 <code>트리 생성자</code>로 넘기고 다름 토큰을 확인하기 위해 <code>다음 문자</code>를 확인한다. 그리고 입력의 마지막까지 이 과정을 반복한다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/6ade5cb9-484b-45d0-8fb2-9946451e2ea2/image.png" alt=""></p>
<p>HTML 공식 문서에 나와있는 파싱 과정이다.(HTML5 명세에 나와있음)</p>
<h2 id="토큰화-알고리즘">토큰화 알고리즘</h2>
<p>알고리즘을 돌고 난후 문서 리소스는 HTML 토큰이 된다. 알고리즘은 상태 기계(State Machine)이라고 볼 수 있다. 각 상태는 <code>하나 이상의 연속된 문자</code>를 입력받아 <code>이 문자에 따라 다음 상태를 갱신</code>한다. 그러나 결과는 <code>현재의 토큰화 상태</code>와 <code>트리 구축 상태</code>의 영향을 받는데. 이것은 같은 문자를 읽어 들여도 현재 상태에 따라 다음 상태의 결과가 다르게 나온다는 것을 의미한다. 알고리즘은 전체를 설명하기에 너무 복잡하니 원리 이해를 도울만한 간단한 예제를 한번 보자.</p>
<pre><code class="language-html">&lt;html&gt;
   &lt;body&gt;
      Hello world
   &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>초기 상태는 &quot;resource state&quot;다. <code>&lt;</code>이 문자를 만나면 &#39;태그 열림 상태&#39;가 된다. a부터 z까지의 문자를 만나면 &#39;시작 태그 토큰&#39;을 생성하고 상태는 <code>태그 이름 상태</code>로 변하는데 이 상태는 <code>&gt;</code>문자를 만날 때까지 유지한다. 각 문자에는 새로운 토큰 이름이 붙는데 이 경우 생성된 토큰은 html토큰이 된다. (<del>일종의 flag 상태 방식을 이용한 알고리즘인 것 같다.</del>)</p>
<p><code>&gt;</code> 문자에 도달하면 현재 토큰이 발행되고 상태는 다시 <code>자료 상태</code>로 바뀐다. 자료 상태는 토큰화 디폴트 상태값인 것 같다. 태그는 동일한 절차에 따라 처리된다. html과 body 태그를 발행하고 다시 디폴트 상태가 됐다. <code>Hello World</code>의 H 문자를 만나면 <code>문자 토큰</code>이 생성되고 발행된다. 이것은 종료 태그의 <code>&lt;</code>문자를 만날때까지 진행한다. Hello World의 각 문자에 대한 문자 토큰이 발행된다.</p>
<p>이후 진행은 똑같다.
<img src="https://images.velog.io/images/brian_kim/post/1a038b5c-03cb-4b26-b53f-24bf57002284/image.png" alt=""></p>
<p>일종의 문자 번역 방식인데, 시작태그(&lt;)와 종료태그(&gt;)를 가지고 토큰 대상에 대한 속성을 정의내리는 방식인 것 같다.</p>
<h2 id="트리-구축-알고리즘">트리 구축 알고리즘</h2>
<blockquote>
<p>파서가 생성되면 문서 객체가 생성된다. </p>
</blockquote>
<p>트리 구축이 진행되는 동안 문서 최상단에서는 DOM트리가 수정되고 요소가 추가된다. 토큰화에 의해 생긴 노드는 트리 생성자에 의해 처리된다. 각 토큰을 위한 DOM 요소의 명세는 정의되어 있다. DOM 트리에 요소를 추가하는 것이 아니라면 열린 요소는 스택(Stack, 임시 버퍼)에 추가된다. 이 스택은 부정확한 중첩과 종료되지 않은 태그를 교정한다. 알고리즘은 상태기계라고 설명할 수 있고, 상태는 <code>삽입모드</code>라고 부른다.</p>
<p>토큰 알고리즘과 마찬가지로 동일한 예제를 통해 살펴보자.</p>
<pre><code class="language-html"> &lt;html&gt;
   &lt;body&gt;
      Hello world
   &lt;/body&gt;
&lt;/html&gt;  </code></pre>
<p>트리 구축 단계에서 입력 값은 토큰화 단계에서 만들어진 토큰들이다. 받아온 html 토큰은 <code>html 태그 전 상태</code>에서 읽게 되고, 토큰은 이 모드에서 처리한다. 이것은 HTMLHtmlElement 요소를 생성하고 문서 객체의 최상단에 추가된다.</p>
<p>상태는 <code>head 태그 이전</code> 모드로 바뀌고 <code>body</code>토큰을 받는다. <code>head</code> 토큰이 없어도 HTMLHeadElement는 무조건 생성되어 트리에 추가된다.</p>
<p>이후 <code>head 내부</code> 모드가 되고, 다음은 <code>head 다음</code>으로 바뀐다. body 토큰이 처리되고, HTMLBodyElement가 생서되어 추가되고, <code>body 안쪽</code> 모드가 된다.</p>
<p><code>Hello World</code>의 문자열의 모든 문자 토큰을 받는데, 첫 번째 토큰이 생성되면 <code>본문</code> 노드가 추가되면서 다른 문자들이 그 노드에 추가된다. <code>body 종료</code>토큰을 받으면 <code>body 다음</code>상태가 된다. 이후 <code>html 종료</code>토큰을 받으면 <code>body 다음 다음</code>모드로 바뀐다. 마지막 파일 토큰을 모두 받으면 파싱이 종료된다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/d3633f71-c0e0-4710-b6b3-977ac19fd82d/image.png" alt=""></p>
<h2 id="브라우저의-오류-처리">브라우저의 오류 처리</h2>
<p>HTML 페이지에서 &quot;유효하지 않은 구문&quot;이라는 오류를 본 적이 없다. 이는 브라우저가 모든 오류 구문을 교정하기 때문이다. 아래 오류가 포함된 예시를 살펴보자.</p>
<pre><code class="language-html">&lt;html&gt;  
   &lt;mytag&gt;&lt;/mytag&gt;
   &lt;div&gt;
     &lt;p&gt;
   &lt;/div&gt;
   Really lousy HTML
   &lt;/p&gt;
&lt;/html&gt;  </code></pre>
<blockquote>
<ol>
<li>mytag라는 존재하지 않는 태그명을 사용했다.</li>
<li>p태그와 div태그는 중첩되어 있다.
그럼에도 불구하고 정상적으로 파싱이 가능한데, 그 이유는 파서가 HTML 오류를 일부 자동적으로 수정하기 때문이다.</li>
</ol>
</blockquote>
<p>북마크와 이전/다음 버튼 처럼 수 년간 브라우저 안에서 구현되어있는 것이다. 잘 알려진 HTML 오류를 찾을 수 있지만, 브라우저는 다른 브라우저들처럼 관습적으로 오류를 수정한다. 이는 명세에 잘 정리 되어있지만 몇 가지만 짚어보도록 하겠다.</p>
<blockquote>
<ol>
<li>어떤 태그의 안쪽에 추가하려는 태그가 금지된 것일 때 일단 허용된 태그를 먼저 닫고 금지된 태그는 외부에 추가한다.
.</li>
<li>파서가 직접 요소를 추가해서는 안된다. <code>HTML, BODY, TBODY, TR, TD, LI</code>같은 태그들은 생략해도 가능하다.
.</li>
<li>인라인 요소 안쪽에 블록 요소가 있는 경우 부모 블록 요소를 만날 때까지 모든 인라인 태그를 닫는다.
.</li>
<li>이런 방법으로 해결되지 않으면 태그를 추가하거나 무시할 수 있는 상태가 될때까지 요소를 닫는다.</li>
</ol>
</blockquote>
<h3 id="br-대신-br"><code>&lt;br&gt;</code> 대신 <code>&lt;/br&gt;</code></h3>
<p>인터넷 익스플로러, 파이어폭스의 호환성을 위해서 이것을 대체해서 이해한다. 오류는 내부적으로 처리되고, 사용자에게 보여지지 않는다.</p>
<blockquote>
<p>추가내용 기술 예정..</p>
</blockquote>
<h1 id="마치며">마치며</h1>
<p>이번에는 브라우저 내부의 파싱 알고리즘, 토큰화 알고리즘, 마지막으로 트리 구축 알고리즘이 어떤 방식으로 작동하는지에 대해 알아봤다. 기본적으로 모든 파싱과정에서 사용되는 알고리즘들은 특정 문자 혹은 토큰을 flag 현재 상태를 구분하는 구분자 역할로 사용한다. </p>
<blockquote>
<h1 id="references">References</h1>
<p><a href="https://developer.mozilla.org/ko/docs/Web/API/Document/write">document.write</a>
<a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html">HTML Documentation</a>
<a href="https://d2.naver.com/helloworld/59361">Naver D2</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[웹]브라우저 파서(Parser)와 DOM]]></title>
            <link>https://velog.io/@brian_kim/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%ED%8C%8C%EC%84%9CParser</link>
            <guid>https://velog.io/@brian_kim/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%ED%8C%8C%EC%84%9CParser</guid>
            <pubDate>Tue, 24 Aug 2021 05:26:46 GMT</pubDate>
            <description><![CDATA[<h1 id="파서parser">파서(Parser)</h1>
<p>파서는 이전 글에서 봤듯이, 데이터(문서 파일)이 왔을 때 이것을 컴퓨터가 이해할 수 있게끔 구조를 재구성하는 단계라고 이해하면 되겠다. 파서는 우선 문서가 오게되면 이 문서를 <code>토큰</code>이라는 유효성이 있는 단어 단위로 나누어 분해하고, 이것을 언어구문규칙에 따라 파싱트리로 재생성한다. 결과적으로는 기계어로 바꾸기 직전단계까지의 과정을 파서가 담당하고 있는 것이다. 파서가 파싱을 통해 파싱트리가 완성되면 파싱트리를 가지고 컴파일러는 기계어로 변환하는 작업에 들어간다. 일종의 컴퓨터에서 <code>전처리기의 역할</code>을 브라우저 파서가 맡고 있다고 생각하면 된다.</p>
<h2 id="파싱-예">파싱 예</h2>
<blockquote>
<p><img src="https://images.velog.io/images/brian_kim/post/06012b9f-eeaf-49e6-b91f-13dd0d3dcd8e/image.png" alt="">
전에 이렇게 정해진 규칙에 따라서 <code>2 + 3 - 1</code>을 분해하는 과정을 거쳤다. 이 과정에서 의미 있는 어휘들인 연산자 +,-, 그리고 중간에 들어가는 숫자원소들 단위로 나누어 파싱트리의 노드를 구성했던 것을 기억하고 있을 것이다.</p>
</blockquote>
<p>여기에서 사용된 어휘 기준(어휘를 나누는 기준)은 
<code>수학에서는 표현식의 정수, 기호단위로 나누어진다</code>
라는 것이다.</p>
<p>사용된 구문 조건에는 여러 개가 있을 텐데,
대표적인 것들을 따져보면 다음과 같다.</p>
<blockquote>
<ol>
<li>언어 구문의 기본적인 요소는 <strong>표현식, 항, 연산자</strong>다.</li>
<li>언어에 포함되는 <strong>표현식의 수는 제한이 없다.</strong></li>
<li>표현식은 <strong>&#39;항&#39;뒤에 &#39;연산자&#39; 그 뒤에 또 다른 항</strong>이 따르는 형태다.</li>
<li>연산자는 <strong>더하기 토큰 또는 빼기 토큰</strong>이 온다.</li>
<li><strong>정수 토큰 또는 하나의 표현식은 항</strong>이다.</li>
</ol>
</blockquote>
<p>입력된 값 2+3-1을 분석해 보자.</p>
<p>규칙에 맞는 첫 번째 부분 문자열은 <code>2</code>이다. 규칙 <code>5</code>번에 따르면 이것은 하나의 항이다. 두 번째로 맞는 것은 <code>2+3</code> 인데 이것은 <code>항 뒤에 연산자와 또 다른 항이 등장한다</code>는 세 번째 규칙과도 일치한다. 입력 값의 마지막 부분까지 진행하면 또 다른 일치를 발견할 수 있다. <code>2+3</code>은 <code>항과 연산자와 항</code>으로 구성된 하나의 새로운 항이라는 것을 알고 있기 때문에 <code>2+3-1은 하나의 표현식</code>이 된다. 2++은 어떤 규칙과도 맞지 않기 때문에 유효하지 않은 입력이 된다.</p>
<h2 id="파서의-종류">파서의 종류</h2>
<p>파서는 기본적으로 <code>하향식 파서</code>와 <code>상향식 파서</code>가 있다. 하향식 파서는 구문의 <code>상위 구조로부터 일치하는 부분을 찾기 시작</code>하는데 반해 상향식 파서는 <code>낮은 수준에서 점차 높은 수준</code>으로 찾는다.</p>
<p>두 종류의 파서가 예제를 어떻게 파싱하는지 살펴보자. <code>하향식 파서</code>는 <code>2+3</code>과 같은 표현식에 해당하는 <code>높은 수준의 규칙</code>을 먼저 찾는다. 그 다음 표현식으로 <code>2+3-1</code>을 찾을 것이다. 표현식을 찾는 과정은 일치하는 다른 규칙을 점진적으로 더 찾아내는 방식인데 어쨌거나 <code>가장 높은 수준의 규칙을 먼저 찾는 것</code>으로부터 시작한다.</p>
<p>상향식 파서는 <code>입력 값이 규칙에 맞을 때까지 찾아서 맞는 입력 값을 규칙</code>으로 바꾸는데 이 과정은 <code>입력 값의 끝</code>까지 진행된다. 부분적으로 일치하는 표현식은 <code>파서 스택</code>에 쌓인다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/5dec6d87-95e7-4ea2-84a8-7c2c10a8619f/image.png" alt=""></p>
<p>상향식 파서는 입력 값의 오른쪽으로 이동하면서(<code>입력 값의 처음을 가리키는 포인터가 오른쪽으로 이동하는 것</code>을 상상) 구문 규칙으로 갈수록 남는 것이 점차 감소하기 때문에 <code>이동-감소 파서</code>라고 부른다.</p>
<h2 id="파서-자동-생성">파서 자동 생성</h2>
<p>파서를 생성해 줄 수 있는 도구를 <code>파서 생성기</code>라고 한다. 언어에 <code>어휘나 구문 규칙 같은 문법</code>을 부여하면 동작하는 파서를 만들어 준다. 파서를 생성하는 것은 파싱에 대한 깊은 이해를 필요로 하고 수동으로 파서를 최적화하여 생성하는 것은 쉬운 일이 아니기 때문에 파서 생성기는 매우 유용하다.</p>
<p>웹킷은 잘 알려진 두 개의 파서 생성기를 사용한다. 어휘 생성을 위한 플렉스(Flex)와 파서 생성을 위한 바이슨(Bison)이다. 렉스(Lex)와 약(Yacc)이라는 이름과 함께 들어본 적이 있을지도 모르겠다. 플렉스는 <code>토큰의 정규 표현식 정의를 포함하는 파일을 입력</code> 받고 바이슨은 <code>BNF 형식의 언어 구문 규칙</code>을 입력 받는다.</p>
<blockquote>
<p><strong>Flex(Fast lexical analyzer generator)</strong>
<img src="https://images.velog.io/images/brian_kim/post/bf8ac2ee-2af2-4ea4-a392-e142f9d540a1/image.png" alt=""></p>
</blockquote>
<h2 id="html-파서">HTML 파서</h2>
<p>HTML 파서는 HTML마크업을 파싱 트리로 변환한다.</p>
<h3 id="html-문법-정의">HTML 문법 정의</h3>
<p>HTML의 어휘와 문법은 W3C에 의해 명세로 정의되어 있다.
현재 버전은 HTML4와 초안 상태로 진행 중인 HTML5 이다.</p>
<h3 id="문맥-자유-문법이-아님">문맥 자유 문법이 아님</h3>
<p>파싱 일반 소개를 통해 알게 된 것처럼 문법은 BNF와 같은 형식을 이용하여 공식적으로 정의할 수 있다. </p>
<p>안타깝게도 모든 전통적인 파서는 HTML에 적용할 수 없다. 그럼에도 불구하여 지금까지 파싱을 설명한 것은 그냥 재미때문은 아니다. 파싱은 CSS와 자바스크립트를 파싱하는 데 사용된다. HTML은 파서가 요구하는 문맥 자유 문법에 의해 쉽게 정의할 수 없다.</p>
<p>HTML 정의를 위한 공식적인 형식으로 DTD(문서 형식 정의)가 있지만 이것은 문맥 자유 문법이 아니다. 이것은 언뜻 이상하게 보일 수도 있는데 HTML이 XML과 유사하기 때문이다. 사용할 수 있는 XML 파서는 많다. HTML을 XML 형태로 재구성한 XHTML도 있는데 무엇이 큰 차이점일까?</p>
<p>차이점은 <code>HTML이 더 &quot;너그럽다&quot;</code>는 점이다. HTML은 암묵적으로 <code>태그에 대한 생략이 가능</code>하다. 가끔 시작 또는 종료 태그 등을 생략한다. 전반적으로 뻣뻣하고 부담스러운 XML에 반하여 HTML은 &quot;유연한&quot; 문법이다.</p>
<p>이런 작은 차이가 큰 차이를 만들어 낸다. 웹 제작자의 실수를 너그럽게 용서하고 편하게 만들어주는 이것이야 말로 HTML이 인기가 있었던 이유다. 다른 한편으로는 <code>공식적인 문법으로 작성하기 어렵게 만드는 문제</code>가 있다. 정리하자면 <code>HTML은 파싱하기 어렵고 전통적인 구문 분석이 불가능</code>하기 때문에 <code>문맥 자유 문법이 아니라는 것</code>이다. <code>XML 파서로도 파싱하기 쉽지 않다.</code> </p>
<h2 id="dom">DOM</h2>
<p><code>파싱 트리</code>는 DOM 요소와 속성 노드의 트리로서 출력을 위한 출력 트리가 된다. DOM은 <code>문서 객체 모델(Document Object Model)</code>의 준말이다. 이것은 HTML 문서의 객체 표현이고 외부를 향하는 자바스크립트와 같은 HTML 요소의 연결 지점이다. 트리의 최상위 객체는 <a href="https://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/level-one-core.html">문서</a>이다.</p>
<blockquote>
<p>DOM은 마크업과 1:1 관계를 맺는다.</p>
</blockquote>
<pre><code class="language-html">&lt;html&gt;
  &lt;body&gt;
      &lt;p&gt;Hello World&lt;/p&gt;
      &lt;div&gt;
          &lt;img src=&quot;example.png&quot;/&gt;&lt;div&gt;
      &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>다음과 같은 마크업이 있다고 했을 때,
<img src="https://images.velog.io/images/brian_kim/post/ac0a571c-9575-4b44-acc0-1cbf0c801427/image.png" alt="">
이런 방식으로 DOM트리를 구성하게 된다.</p>
<p>HTML과 마찬가지로 DOM은 <a href="www.w3.org/DOM/DOMTR">W3C에 의해 명세</a>가 정해져 있다. 이것은 문서를 다루기 위한 일반적인 명세인데 부분적으로 HTML 요소를 설명하기도 한다. HTML 정의는 <a href="http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/idl-definitions.html%EC%97%90%EC%84%9C">www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/idl-definitions.html에서</a> 찾을 수 있다.</p>
<p>트리가 <code>DOM 노드를 포함한다고 말하는 것</code>은 <code>DOM 접점의 하나를 실행하는 요소를 구성한다</code>는 의미다. 브라우저는 내부의 다른 속성들을 이용하여 이를 구체적으로 실행한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[웹]브라우저 파싱과 변환]]></title>
            <link>https://velog.io/@brian_kim/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%ED%8C%8C%EC%8B%B1-DOM-%ED%8A%B8%EB%A6%AC-%EA%B5%AC%EC%B6%95</link>
            <guid>https://velog.io/@brian_kim/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%ED%8C%8C%EC%8B%B1-DOM-%ED%8A%B8%EB%A6%AC-%EA%B5%AC%EC%B6%95</guid>
            <pubDate>Tue, 24 Aug 2021 05:13:55 GMT</pubDate>
            <description><![CDATA[<h1 id="파싱과-변환">파싱과 변환</h1>
<h2 id="파싱">파싱</h2>
<p>파싱은 렌더링 엔진에서 매-우 중요한 과정이다. 파싱은 중요하기 때문에 자세하게 들어가보자. 우선 <code>문서 파싱(parsing)</code>은 브라우저가 코드를 이해하고 사용할 수 있는 구조로 변환하는 것을 의미한다. 파싱 결과는 보통 문서 구조를 나타내는 노드트리인데, <code>파싱 트리(Parse Tree)</code> 또는 <code>문법 트리(syntex tree)</code>라고 부른다. 기본적으로 파싱이라는 것은 어떤 문서를 브라우저가 읽을 수 있게끔 구조를 분해하는 과정이라고 이해할 수 있다.</p>
<blockquote>
<p>2 + 3 - 1 이라는 표현식이 있을때, 파싱 트리로 만들면
<img src="https://images.velog.io/images/brian_kim/post/07d0beab-aa91-455c-8653-0146f812cb14/image.png" alt="">
다음과 같은 구조를 가지게 된다.</p>
</blockquote>
<h3 id="문법">문법</h3>
<p>파싱은 문서에 작성된 언어 또는 형식의 규칙에 따르는데 파싱할 수 있는 모든 형식은 정해진 용어와 구문 규칙에 따라야한다. 이를 <a href="http://ko.wikipedia.org/wiki/%EB%AC%B8%EB%A7%A5_%EC%9E%90%EC%9C%A0_%EB%AC%B8%EB%B2%95">문맥 자유 문법</a>이라는데 정확한 내용은 나중에 참고해야겠다.</p>
<h3 id="파서-어휘-분석기-조합">파서-어휘 분석기 조합</h3>
<p>파싱은 어휘 분석, 그리고 구문 분석이라는 두 가지로 구분할 수 있다. 어휘 분석은 <code>자료를 토큰으로 분해</code>하는 과정이다. 토큰은 <code>유효하게 구성된 단위의 집합체로 용어집</code>이라고 볼 수 있다. 보통 사전에 등장하는 모든 단어라고 생각하면 쉽다. </p>
<p>파서는 보통 두 가지의 일을 하는데 자료를 유효한 토큰으로 분해하는 어휘 분석(토큰 변환)이 있고, 언어 구문 규칙에 따라 문서를 분석함으로써 파싱 트리를 생성하는 파서가 있다. (일단 데이터가 오면, 단어별로 나누고, 정해진 규칙에 따라 이전에 만들어진 것 같은 파싱 트리를 구성한다.) 어휘 분석기는 공백과 줄 바꿈같은 의미 없는 문자를 제거하기도 한다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/c8a22bd9-0727-4bef-9c6a-5d787acae54d/image.png" alt=""></p>
<p>파싱은 계속 반복된다. 전체가 모두 파싱트리가 될 때까지... 파서는 보통 어휘 분석기로부터 새 토큰을 받아서 구문 규칙과 일치하는지 확인한다. 규칙에 맞으면 토큰에 해당하는 노드가 파싱 트리에 추가되고 파서는 또 다른 토큰을 요청한다. </p>
<blockquote>
<p><code>나는 밥을 먹는다.</code>라는 문장이 있을때, <code>어휘 분석기 혹은 토큰 분석기</code>는 각각을 <code>나</code>, <code>는</code>, <code>밥</code>, <code>을</code>, <code>먹</code>, <code>는다.</code> 식으로 의미가 있는 단어(토큰)으로 분해하고, <code>나는</code> + <code>밥을</code> + <code>먹는다.</code> 식으로 의미가 이어질 수 있는 구문 규칙에 따라 <code>언어 구문 규칙</code>에 따라 조합한다는 식으로 이해하면 좋을 것 같다.</p>
</blockquote>
<p>규칙에 맞지 않으면 파서는 토큰을 내부적으로 저장하고 토큰과 일치하는 규칙이 발견될 때까지 요청한다. 맞는 규칙이 없는 경우 예외로 처리하는데 이것은 문서가 유효하지 않고 구문 오류를 포함하고 있다는 의미다.</p>
<h2 id="변환-컴파일">변환 (컴파일)</h2>
<p>파서트리는 최종 결과물이 아니다. 중간단계에서 문서를 쪼개서 이해할 수 있는 단위로 묶어주는 역할이라고 볼 수 있다. 파싱은 보통 문서를 다른 양식으로 변환하는데 컴파일의 한 예에 가깝다. 소스 코드를 기계 코드로 만드는 컴파일러는 파싱 트리가 생성된 후에 이걸 기계 코드 문서로 다시 바꾼다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/f0fda6b5-e9bb-4851-babb-ba9e52811aa9/image.png" alt=""></p>
<blockquote>
<p>소스코드를 받아서, 파서가 문서를 <code>토큰</code>이라는 단위로 쪼개어 <code>문법</code>에 맞게끔 파싱트리를 구성하는 단계까지 진행하고, <code>컴파일러</code>는 이렇게 생서된 <code>파싱트리</code>를 가지고 기계어로 변환하는 컴파일 과정을 거친다.</p>
</blockquote>
<blockquote>
<p>이 부분에 대해서는 나중에 보충하도록 하자.(2021.8.24)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[웹]브라우저의 기본 개념, 구성]]></title>
            <link>https://velog.io/@brian_kim/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EC%9E%91%EB%8F%99-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@brian_kim/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EC%9E%91%EB%8F%99-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Fri, 20 Aug 2021 08:35:11 GMT</pubDate>
            <description><![CDATA[<h1 id="브라우저의-구성">브라우저의 구성</h1>
<h2 id="서론">서론</h2>
<p>브라우저는 사람들이 웹을 이용하기 위해 사용하는 응용소프트웨어다. 아마 다른 어떤 소프트웨어보다도 (물론 OS가 제일 많겠지만...) 많이 사용한다. 이제부터 나는 브라우저가 어떻게 작동하는지 공부해보고 정리하려고 한다. 브라우저 주소창에 google.com을 입력했을 때 어떤 과정을 거쳐 페이지가 나타나고 화면에 뿌려지게 되는지 하나하나 찾아가보고자 한다.</p>
<h2 id="브라우저에-대해-알아보자">브라우저에 대해 알아보자.</h2>
<h3 id="브라우저의-종류">브라우저의 종류</h3>
<p>브라우저에는 정말 다양한 것들이 있다. 윈도우의 부산물인 edge나, firefox, 구글의 chrome, apple의 safari, 오페라와 같은 다양한 것들이 있다. <a href="https://gs.statcounter.com/">statcounter</a>의 통계를 보면 65%가 넘는 과반이 크롬 브라우저를 사용하는 것으로 볼 수 있다. 과거 12년 기준으로 62%였다고 하니 브라우저 판은 크게 변한 것이 없다. 근데 chrome은 오픈소스 브라우저니까 브라우저시장은 오픈소스 브라우저가 지배하고 있다고 해도 과언이 아니다.</p>
<h3 id="브라우저가-뭘까">브라우저가 뭘까?</h3>
<p>브라우저는 사용자가 어떤 페이지 요소를 클릭해서 리소스를 서버측에 요청할 수 있도록 해주고 응답으로 받아온 리소스를 브라우저에 표시하는 것이 메인 기능이다. 리소스는 보통 HTML이지만 PDF 나 이미지 혹은 동영상 형태이기도 하다. 리소스는 리소스마다 고유한 주소를 가지게 되는데, 과거 <code>URL</code>이라고 불렸던 <code>URI(Uniform Resource Identifier)</code>에 의해 정해진다.</p>
<p>브라우저는 HTML과 CSS에 적혀진 그대로 HTML을 번역해서 뿌려주게 되는데, 이 세부 내용은 W3C(World Wide Web Consortium)에서 결정한다. 과거에는 사람마다 형식이나 양식에 대해서 자유로워 호환성 문제에서 큰 문제가 있었지만 현재는 이것이 표준 규약으로 굳어졌다.</p>
<p>브라우저의 사용자 인터페이스는 거의 비슷하다. 어떤 브라우저를 사용하던지간에 어려움없이 사용할 수 있는 이유다.</p>
<ul>
<li>URI를 입력하는 줄</li>
<li>이전 페이지, 다음 페이지</li>
<li>북마크 기능</li>
<li>홈 버튼</li>
</ul>
<p>그 외에도 요즘에는 Extension이 부지기수로 쏟아져 나오고 있지만, 가장 기본적이고 중심적인 기능은 이것들이고 대부분의 UI들이 비슷하게 구성되어있어 중간에 다른 브라우저를 사용한다고 해도 어렵지 않게 사용할 수 있다.</p>
<h2 id="브라우저의-기본-구조">브라우저의 기본 구조</h2>
<p>브라우저는 다음과 같은 기본 구성 요소를 가지고 있따.</p>
<blockquote>
<ol>
<li>사용자 인터페이스(User Interface)
위에서 적어두었던 것들이 바로 UI다.</li>
</ol>
</blockquote>
<blockquote>
<ol start="2">
<li>브라우저 엔진
사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어한다.</li>
</ol>
</blockquote>
<blockquote>
<ol start="3">
<li>렌더링 엔진
요청한 리소스를 표시하는 역할을 한다. HTML을 요청하면 HTML과 CSS를 파싱해서 각 플랫폼 하부에서 실행된다.</li>
</ol>
</blockquote>
<blockquote>
<ol start="4">
<li>통신 
HTTP 요청과 같은 네트워크 호출에 사용된다. 이건 플랫폼 독립적인 인터페이스고 각 플랫폼의 하부에서 실행된다.</li>
</ol>
</blockquote>
<blockquote>
<ol start="5">
<li>UI 백엔드
콤보박스와 창 같은 기본적인 장치를 그린다. 플랫폼에서 명시하지 않은 일반적인 인터페이스로서 OS사용자 인터페이스 체계를 가져와 그린다.(Mac 유저와, Windows 유저가 스크롤 바, 콤보박스, 인풋 같은 것들이 다르게 그려지는 이유다.)</li>
</ol>
</blockquote>
<blockquote>
<ol start="6">
<li>자바스크립트 해석기 
스크립트 코드를 해석하고 실행시킨다.</li>
</ol>
</blockquote>
<blockquote>
<ol start="7">
<li>자료 저장소
이 부분은 자료를 저장하는 계층이다. 쿠키를 저장하는 것이나 모든 종류의 리소스를 하드디스크에 저장할 필요가 있다. HTML5 명세에는 웹 데이터 베이스가 정의되어 있다.</li>
</ol>
</blockquote>
<p><img src="https://images.velog.io/images/brian_kim/post/97ea5fcc-1a6a-4863-9a1a-83612aeae883/image.png" alt="">
출처 : <a href="d2.naver.com/helloworld/59361">naver D2 - 브라우저는 어떻게 동작하는가</a></p>
<p>크롬은 대부분의 브라우저와 달리 각 탭마다 별도의 렌더링 엔진 인스턴스를 유지한다. 각 탭은 독립된 프로세스로 처리된다. 그렇기 때문에 프로세스 관리자를 열었을 때 탭 갯수만큼이나 많이 올라와있는 크롬 프로세스들을 확인할 수 있다.</p>
<h2 id="렌더링-엔진">렌더링 엔진</h2>
<p>렌더링 엔진의 역할은 요청 받은 내용을 브라우저 화면에 표시하는 일이다. 렌더링 엔진은 HTML 및 XML 문서와 이미지를 표시할 수 있다. 물론 플러그인이나 브라우저 extension을 이용해 PDF나 다른 유형도 표시할 수 있다. </p>
<h3 id="렌더링-엔진들">렌더링 엔진들</h3>
<p>여러가지 브라우저가 있지만 주로 쓰이는 파이어 폭스나 크롬, 사파리는 두 종류의 렌더링 엔진으로 이루어져 있다. 파이어폭스는 모질라에서 직접 만든 게코(Gecko) 엔진을 사용하고 사파리와 크롬은 웹킷(WebKit)엔진을 이용한다.</p>
<p>웹킷은 최초 리눅스 플랫폼에서 동작하기 위해서 제작된 오픈소스 엔진으로 애플이 맥과 윈도우즈에서 사파리 브라우저를 지원하기 위해서 수정을 더했다. 자세한 내용은 <a href="webkit.org">webkit.org</a>에서 확인할 수 있다.</p>
<h2 id="동작-과정">동작 과정</h2>
<p>렌더링 엔진은 통신으로부터 요청한 문서의 내용을 얻는 것으로 시작하는데 문서의 내용은 보통 8Kb 단위로 전송한다. 
다음은 렌더링 엔진의 기본적인 동작 과정이다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/598416af-6d0d-41dd-82bf-ab764b8c8038/image.png" alt="">
출처: <a href="https://d2.naver.com/helloworld/59361">naver D2</a></p>
<p><img src="https://images.velog.io/images/brian_kim/post/65ca627f-e9e9-445b-9072-4307739bffe0/image.png" alt=""></p>
<p>렌더링 엔진은 HTML 문서를 먼저 파싱하고, &#39;콘텐츠 트리&#39; 내부에서 태그를 <a href="http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/">DOM</a> 노드로 변환한다. 그 다음 외부 CSS 파일과 함께 포함된 스타일 요소도 파싱한다. 스타일 정보와 HTML 표시 규칙은 &quot;렌더 트리&quot;라고 부르는 또 다른 트리를 생성한다.</p>
<p>렌더 트리는 색상 또는 면적과 같은 시각적 속성이 있는 사각형을 포함하고 있는데 정해진 순서대로 화면에 표시된다. 렌더 트리 생성이 끝나면 배치가 시작된다. 이것은 각 노드가 화면의 정확한 위치에 표시되는 것을 의미한다. 다음은 UI 백엔드에서 렌더 트리의 각 노드를 가로지르며 형상을 만들어내는 그리기 과정이다.</p>
<p>일련의 과정들이 차례대로 진행된다는 것이 중요하다. 렌더링 엔진은 좀 더 나은 사용자 경험을 위해 가능하면 빠르게 내용을 표시하는데 <code>모든 HTML을 파싱할 때까지 기다리지 않고 배치와 그리기 과정을 시작한다.</code> 네트워크로부터 나머지 내용이 전송되기를 기다리는 동시에 받은 내용의 일부를 먼저 화면에 표시한다.</p>
<p><img src="https://images.velog.io/images/brian_kim/post/aae4492e-da5f-4d30-b3ab-8793849c33ac/image.png" alt=""></p>
<ul>
<li>웹킷</li>
</ul>
<p><img src="https://images.velog.io/images/brian_kim/post/aeca531f-f31c-4c7f-85b4-1a5f0e8b090e/image.png" alt=""></p>
<ul>
<li>게코</li>
</ul>
<p>웹킷과 게코는 용어가 조금 다를 뿐 동작 과정의 중심 개념은 거의 동일하다. </p>
<p>게코는 시각적으로 처리되는 렌더 트리를 <code>&#39;형상 트리(frame tree)&#39;</code>라고 부르고 각 요소를 <code>&#39;형상(frame)&#39;</code>이라고 하는데 웹킷은 <code>&#39;렌더 객체(render object)&#39;</code>로 구성되어 있는 <code>&#39;렌더 트리(render tree)&#39;</code>라는 용어로 부른다. 웨빗은 요소를 배치하는데 <code>&#39;배치(layout)&#39;</code>이라는 용어를 사용하지만 게코는 <code>&#39;리플로우(reflow)&#39;</code>라는 용어로 부른다. <code>&#39;어태치먼트(attachment, 부착)&#39;</code>은 웹킷이 렌더 트리를 생성하기 위해 DOM 노드와 시각 정보를 연결하는 과정이다. 게코는 HTML과 DOM 트리 사이에 <code>&#39;콘텐츠 싱크(content sink)&#39;</code>라고 부르는 과정을 두는데 이는 DOM 요소를 생성하는 공정으로 웹킷과 비교하여 거의 비슷하다.</p>
<blockquote>
<h3 id="references">References</h3>
</blockquote>
<ul>
<li><a href="http://d2.naver.com/helloworld/59361">브라우저는 어떻게 동작하는가?</a></li>
<li><a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction?hl=ko">Render-tree Construction, Layout, and Paint</a></li>
<li><a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/adding-interactivity-with-javascript?hl=ko">Adding interactivity with javascript</a></li>
<li><a href="http://rtcc.hanyang.ac.kr/sitedata/2015_2_ISP/howbrowserswork_20150915.pdf">오픈소스 웹킷(Webkit) 구조와 원리</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>