<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>bolee.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 06 May 2025 10:32:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. bolee.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/octo__" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[시대예보: 핵개인의 시대 - 송길영]]></title>
            <link>https://velog.io/@octo__/%EC%8B%9C%EB%8C%80%EC%98%88%EB%B3%B4-%ED%95%B5%EA%B0%9C%EC%9D%B8%EC%9D%98-%EC%8B%9C%EB%8C%80-%EC%86%A1%EA%B8%B8%EC%98%81-1ez2w6c4</link>
            <guid>https://velog.io/@octo__/%EC%8B%9C%EB%8C%80%EC%98%88%EB%B3%B4-%ED%95%B5%EA%B0%9C%EC%9D%B8%EC%9D%98-%EC%8B%9C%EB%8C%80-%EC%86%A1%EA%B8%B8%EC%98%81-1ez2w6c4</guid>
            <pubDate>Tue, 06 May 2025 10:32:57 GMT</pubDate>
            <description><![CDATA[<p>데이터를 통해 사람의 마음을 캐는 마인드 마이너(Mind Miner)이신 송길영 작가의 책이다.</p>
<p>유튜브를 통해 많이 접하였던 송길영 작가의 책임을 이전부터 알았으나, 단순히 영상으로만 접하고 책을 읽어볼 생각은 하지 못하였었다.
그러나, 머리를 자르러 미용실을 가던 중 우연히 들르게된 알라딘 판매대에서 해당 책을 보고 사서 읽게 되었다.</p>
<p>저자는 한 철의 기상을 알려주는 일기예보처럼, 데이터를 통해 본 시대의 흐름을 파악하고 개인의 삶을 대비하기 위한 목적으로 책을 썻다고 한다.
책의 목적처럼 현 시대의 흐름을 여러 레퍼런스와 함께 잘 정리되어 작성되었고 쉽게 읽을 수 있었다.</p>
<pre><code>프롤로그 - 쪼개지는, 흩어지는, 홀로 서는

제1장 K는 대한민국이 아니다.
 - K 프리미엄, 국적은 사라지고 스타일은 남아
 - &#39;서울러&#39;라는 소속감 혹는 구별 짓기
 - &#39;오리너구리&#39;를 포용할 수 있는 세계
 - &#39;국민교육현장&#39;의 공허한 메아리
 - 언어 습관이 조직의 운명을 바꾼다.

제2장 코파일럿은 퇴근하지 않는다.
 - 출퇴근 없는 AI 동료
 - 기계가 좋아서가 아니라 사람이 불편해서
 - 이심전심, 심심상인, AI 비서
 - 작가는 사라지고 장르만 남는다.
 - 주말 오후, 2시간만에 쇼핑몰을 개업하다.
 - 인류에겐 축복이지만, 당신에게는 재양일 수도
 - 재앙을 축복으로 만드는 연금술

제3장 채용이 아니라 영입
 - 대학은 입학만, 졸업 혹은 창업은 당신의 선택
 - 유명 대학 나온 동네 사장님들
 - 개인의 유동성, 조직의 역동성
 - 캘빈 클라인 모델이 상위 1% 프로그래머
 - 투명 사회의 생존법
 - 당신은 영입 대상입니까

제4장 효도의 종말, 나이듦의 미래
 - 아버지를 고용한 딸, 가녀장의 시대
 - 엄마처럼 OO하며 살고 싶지 않아
 - 죄책감은 나의 몫? 주고받음의 아름다움
 - 나이듦은 천차만별
 - &#39;영웅시대&#39;에는 효도가 필요 없어
 - 문제는 &#39;나이&#39;가 아니라 &#39;나&#39;이다

제5장 핵개인의 출현
 - 세계관을 주고받는 우아한 핵개인들
 - 그게 다 빚이었다.
 - 천륜은 사라져도 연대는 남는다.
 - 미정산 세대의 필연
 - 5분 존경 사회

에필로그 - 인정 강박, 경쟁하지 않는 사회를 위하여</code></pre><p>위의 목차만 봐도 책에서 저자가 말하고 싶은 것이 어떤 건지 유추가 가능하다. 그러나, 저자는 주제 뿐만 아니라 시대적으로 왜 그러한 현상이 발생했는지 논리적으로 설명하고 주제에 대해 개인과 공동체가 가져야할 모습을 제안한다는 부분에서 책을 집필할 때의 고민이 느껴져 좋았다.</p>
<p>책 제목처럼 시대를 예보하는 책이기에 현재 시점에서 예보된 내용과 맞춰 읽어보면 흥미롭게 읽을 수 있을 것이다.</p>
<blockquote>
<p>2023년에 나온 책으로써 이 책을 읽은 2025년 관점에서 봤을 때 2023년에 예측된 시대의 흐름이 너무나도 빠르게 다가왔다. 그래서 저자도 그러한 빠른 시대 변화에 맞춰 &quot;시대예보: 호명사회&quot;라는 책을 2024년에 빠르게 발간했지 않을까 싶다.(다음에 읽으려고 예정 중이다.😊)</p>
<p>물론 책이 쓰여진 그 당시에 데이터로도 해당 경향이 보여 작성된 것이겠지만, 이러한 경향이 불과 2년만인 2025년 현재에 매우 빠르게 주류가 된 것이 놀라웠다.(필자 기준 그렇게 느끼고 있다😅)
필자는 책에 쓰여진 내용이 벌써 적용되어 &#39;음 맞지 맞지&#39;의 느낌으로 읽었지만, 이러한 부분에 민감하지 않거나 생각해보지 않은 사람들에게는 신선한 시각을 줄 수 있는 책이라고 생각된다.</p>
<p>필자가 본 신선한 시각은 최근 AI Agent에 대해 관심이 많은 만큼 &#39;제2장 코파일럿은 퇴근하지 않는다&#39; 중 문제 해결에 관한 부분이다. 책에서 말하는 버전에 다른 문제 해결은 다음과 같다.</p>
<ul>
<li>문제 해결 1.0: 내가 문제를 정의하고 전문가가 해결을 도와주는 것</li>
<li>문제 해결 2.0: 내가 문제를 정의하고 해결에 필요한 것을 파악해서 직접 해결하는 것</li>
<li>문제 해결 3.0: 내가 문제를 제기하고 AI가 문제 인식과 정의, 해결을 도와주는 것</li>
</ul>
<p>여기에서 &#39;문제 해결 3.0&#39;이 많이 달라진 부분은 문제의 정의과 제기 그리고 문제 해결의 주체이다. AI가 고도화된 시점에서는 문제를 정의조차 하지 않아도 될 것이라는 부분이 신선하기 다가왔으며, 앞으로 문제를 제기할 수 있는 시각을 가지기 위해 관성적인 태도가 아닌 다양한 시각에서 문제를 바라볼 수 있는 태도를 가져야겠다는 생각이 들었다.</p>
<p>책에서 제안하고 말하는 상호 존중과 자기 인생의 능동적 결정권을 가지는 핵개인의 태도를 받아드리고 지향하여 이를 달성하고 싶다.(원래 필자는 원래 그쪽 성향이긴 했다.🤣)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DevOps] 클라우드 서비스 개요]]></title>
            <link>https://velog.io/@octo__/DevOps-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EC%84%9C%EB%B9%84%EC%8A%A4-%EA%B0%9C%EC%9A%94</link>
            <guid>https://velog.io/@octo__/DevOps-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EC%84%9C%EB%B9%84%EC%8A%A4-%EA%B0%9C%EC%9A%94</guid>
            <pubDate>Wed, 25 Jan 2023 14:35:58 GMT</pubDate>
            <description><![CDATA[<h1 id="클라우드-컴퓨팅의-유형">클라우드 컴퓨팅의 유형</h1>
<p>클라우드 컴퓨팅은 크게 4가지로 나눌 수 있다.</p>
<ul>
<li>퍼블릭(Public)</li>
<li>프라이빗(Private)</li>
<li>하이브리드(Hybrid)</li>
<li>멀티(Multi)</li>
</ul>
<p>이 4가지 유형의 특징을 간단히 정리하면 다음과 같다.</p>
<table>
<thead>
<tr>
<th>유형</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>퍼블릭(Public) 클라우드</td>
<td>- 사용자는 컴퓨팅 리소스를 <strong>소유하지 않음</strong><br>- <strong>인터넷</strong>을 통해 제공</td>
</tr>
<tr>
<td>프라이빗(Private) 클라우드</td>
<td>- 특정 조직내에서 컴퓨팅 리소스를 <strong>소유</strong><br><strong>프라이빗 네트워크</strong>를 통해 제공</td>
</tr>
<tr>
<td>하이브리드(Hybrid) 클라우드</td>
<td>- 퍼블릭 클라우드와 프라이빗 클라우드 또는 데이터센터 간 <strong>네트워크를 연결</strong></td>
</tr>
<tr>
<td>멀티(Multi) 클라우드</td>
<td>- <strong>다수의 퍼블릭 클라우드</strong>를 사용<br>- e.g. AWS + GCP + Azure</td>
</tr>
</tbody></table>
<p>일반적으로 퍼블릭 클라우드와 프라이빗 클라우드를 많이 사용한다.</p>
<h2 id="퍼블릭public-클라우드">퍼블릭(Public) 클라우드</h2>
<p><img src="https://velog.velcdn.com/images/octo__/post/733af716-e0fb-4cf6-9069-6c65eabe5fce/image.png" alt=""></p>
<ul>
<li>가장 일반적인 유형</li>
<li>사용자는 컴퓨팅 리소스를 <strong>소유하지 않음</strong></li>
<li><strong>인터넷</strong>을 통해 제공</li>
<li>클라우드 제공 업체가 가상화 기술로 만든 서비스를 <strong>그대로 사용</strong></li>
</ul>
<h2 id="프라이빗private-클라우드">프라이빗(Private) 클라우드</h2>
<p><img src="https://velog.velcdn.com/images/octo__/post/b389266d-d47a-44b5-9b1b-bf44de5a44bb/image.png" alt=""></p>
<ul>
<li>특정 조직 내 컴퓨팅 리소스를 <strong>소유</strong></li>
<li><strong>사설(Private) 네트워크</strong>를 통해 제공</li>
<li>가상 컴퓨팅 기술을 직접 구축</li>
</ul>
<hr>
<h1 id="클라우드-서비스란">클라우드 서비스란?</h1>
<p><img src="https://velog.velcdn.com/images/octo__/post/34f76dd3-463a-4d38-a71a-aeb262df5911/image.png" alt=""></p>
<p>클라우드 서비스는 <strong>인터넷을 통해 서버, 스토리지, 소프트웨어 등 필요한 IT 리소스와 애플리케이션을 사용하기 원할 때 언제든지 사용한 만큼(on-demand) 요금을 내는 서비스</strong>라고 할 수 있다.</p>
<p>이러한 클라우드 서비스는 여러가지 특징을 가지고 있다.</p>
<h2 id="클라우드-서비스-특징">클라우드 서비스 특징</h2>
<ol>
<li><strong>탄력성/민첩성(Agility/Elasticity)</strong>
 a. 간략한 조작으로 생성/삭제 및 확장
 b. 리소스에 대해 필요할 때 언제든 늘리고, 줄일 수 있음</li>
<li><strong>확장성(Scalability)</strong>
 a. 급증하는 서비스 트래픽에 빠르게 대비
 b. 물리 서버를 확장하려면 시간이 오래 걸리는 반면, 클라우드는 즉시 확장 가능</li>
<li><strong>사용한 만큼 지불(on-demand)</strong>
 a. 무리한 자본지출 없이 빠른 시도와 회수 가능
 b. 사용한 만큼 과금되며, 비용 예측이 가능
 c. 기존 온프레미스 환경에서는 CAPEX가 많이 필요했지만 클라우드 환경에서는 CAPEX가 없이 운영 지출인 OPEX로 대체할 수 있게 되었다. -&gt; 빠르게 투자 비용을 회수 할 수 있게 된다.</li>
</ol>
<blockquote>
<p>OPEX(Operational Expenditures): 운영 지출
CAPEX(Capital Expenditures): 자본 지출</p>
</blockquote>
<ol start="4">
<li><strong>내결함성 및 재해 복구(Fault tolerance &amp; Disaster Recovery)</strong>
 a. 내결함성과 재해 복구를 고려한 설계 가능
 b. 클라우드 백업 및 클라우드 DR 구성으로 데이터 손상 등 긴급 상황에 대해 대처 가능</li>
</ol>
<blockquote>
<p>내결함성(Fault tolerance)</p>
<ul>
<li>시스템의 일부 구성 요소가 작동하지 않더라도 계속 작동할 수 있는 기능</li>
</ul>
</blockquote>
<ol start="5">
<li><strong>고 가용성(High Availability)</strong>
 a. 여러 개의 데이터센터가 고속 네트워크 망으로 연결되어 가용성 설계 가능
 b. 손쉬운 다중 가용영역 설정에 따라 고 가용성 보장</li>
<li><strong>유지 관리 최소화(Maintenance)</strong>
 a. 물리적 리소스 유지보수 불필요 -&gt; 눈에 보이지 않는 비용(인력, 전기세, 임대 비용 등) 절약 가능
 b. 물리적 리소스를 유지할 필요가 없고, 부분적으로 클라우드 CSP 벤더에 위임</li>
</ol>
<hr>
<h1 id="클라우드-서비스-제공업체csp">클라우드 서비스 제공업체(CSP)</h1>
<p><img src="https://velog.velcdn.com/images/octo__/post/96a1cab2-e128-4cf8-a75e-5b032c5bf4d4/image.png" alt=""></p>
<p><strong>클라우드 서비스를 제공하는 벤더(vendor)를 클라우드 서비스 제공업체(CSP, Cloud Service Provider)</strong>라고 한다.</p>
<p>대표적인 해외 업체</p>
<ul>
<li>AWS(아마존)</li>
<li>GCP(구글)</li>
<li>Azure(MS)</li>
<li>ORACLE Cloud(오라클)</li>
<li>IBM Cloud(IBM)</li>
<li>Alibaba Cloud(알리바바)</li>
<li>Tencent Cloud(텐센트)</li>
</ul>
<p>대표적인 국내 업체</p>
<ul>
<li>Naver Cloud Platform(네이버)</li>
<li>NHN Cloud(NHN)</li>
<li>KT Cloud(KT)</li>
<li>Kakao i Cloud(카카오)</li>
<li>Gabia Cloud(가비아)</li>
</ul>
<h2 id="클라우드-시장">클라우드 시장</h2>
<p><img src="https://velog.velcdn.com/images/octo__/post/0862701b-ef40-4bed-a16b-24a90a70c4f2/image.png" alt=""></p>
<p>2021년 기준 세계 클라우드 시장 점유율에서 AWS가 33%로 돋보적인 1위를 차지하고 있다. 해외뿐만 아니라 국내에서도 많이 사용되고 있다.</p>
<hr>
<h1 id="클라우드-서비스-모델">클라우드 서비스 모델</h1>
<p><img src="https://velog.velcdn.com/images/octo__/post/40ffd136-fb8a-4680-9289-7b2d830f9361/image.png" alt=""></p>
<p>클라우드 SCP 벤더에서 제공하는 클라우드 서비스 종류에는 크게 3가지 모델이 존재한다.</p>
<ul>
<li>IaaS(Infrastructure-as-a-Service)</li>
<li>PaaS(Platforms-as-a-Service)</li>
<li>SaaS(Software-as-a-Service)</li>
</ul>
<p>이를 구분하는 기준은 위 사진에서 볼 수 있는 클라우드에서 제공할 수 있는 9가지 기준에 따라 구분된다.</p>
<p>모든 것을 관리해야 하는 온프레미스(On-Premise) 환경과 달리 클라우드 서비스는 서비스에 따라 클라우드 제공자가 일부 또는 전부를 관리한다.</p>
<h2 id="iaasinfrastructure-as-a-service">IaaS(Infrastructure-as-a-Service)</h2>
<p>IaaS는 <strong>물리적인 자원이 가상화되어서 제공되는 서비스</strong>이다. 예를 들어 AWS의 EC2 등이 있다.</p>
<p>가상화(Virtualization)를 포함한 아래 존재하는 물리적인 자원인 서버(Server), 스토리지(Storage), 네트워킹(Networking)을 클라우드 제공자가 관리를 하게 된다.</p>
<h2 id="paas">PaaS</h2>
<p>PaaS는 <strong>어플리케이션을 바로 구축할 수 있는 플랫폼을 제공</strong>한다.</p>
<p>모든 물리적 장비와 가상 인프라를 클라우드 제공자가 관리하고, 추가적으로 OS 영역, Middleware, 데이터베이스 관리 시스템, 분석 툴과 같은 Runtime을 제공한다. 예를 들어 AWS RDS, AWS Elastic Beanstalk 등이 있다.</p>
<h2 id="saas">SaaS</h2>
<p>SaaS는 <strong>서비스형 소프트웨어를 말하며, PaaS에서 제공되는 것에 추가로 데이터와 응용 프로그램이 포함</strong>된다. 
즉, SaaS는 <strong>특정 앱 또는 웹 포털(Web Portal)를 통해서 제공되는 서비스로 완전한 소프트웨어 솔루션</strong>을 말한다. </p>
<p>예를 들어, 구글 드라이브나 네이버 박스가 있고 AWS에서는 머신러닝 서비스인 Amazon SageMaker, VDI 서비스인 Amazon WorkSpaces 같은 것들이 여기에 해당된다.</p>
<hr>
<h1 id="on-premise-vs-cloud">On-Premise vs Cloud</h1>
<p>아래는 온프레미스 환경과 클라우드 환경을 비교한 표이다.</p>
<table>
<thead>
<tr>
<th>항목</th>
<th>On-Premise</th>
<th>Cloud</th>
</tr>
</thead>
<tbody><tr>
<td>인프라 운영/보안</td>
<td>사용자가 모두 운영 및 관리</td>
<td>공동 책임 모델 적용</td>
</tr>
<tr>
<td>구축 및 배포</td>
<td>자원 구축 및 배포 시간이 많이 소요</td>
<td>단 시간 내에 인프라 구성 가능</td>
</tr>
<tr>
<td>탄력성/확장성</td>
<td>서버 증설 시 예산 및 시간 소요</td>
<td>단 시간 내로 서버 증설 가능</td>
</tr>
<tr>
<td>비용 지출 방식</td>
<td>자본 지출: Capital Expense(CAPEX)</td>
<td>운영 지출: Operation Expense(OPEX)</td>
</tr>
<tr>
<td>네트워크 트래픽</td>
<td>인터넷 공급자(ISP) 회선 계약에 따라 회선 속도 및 트래픽 용량을 사전에 설정</td>
<td>회선 속도나 용량을 정할 수 없음<br>트래픽을 사용한만큼 지출(outbound)</td>
</tr>
<tr>
<td>오픈소스</td>
<td>모든 오픈소스 Application을 스스로 구축</td>
<td>Pre-built된 오픈소스 Application을 즉시 사용</td>
</tr>
</tbody></table>
<hr>
<h1 id="참고-강의">참고 강의</h1>
<blockquote>
<ul>
<li><a href="https://fastcampus.co.kr/dev_online_awsdevops">초격차 패키지 Online. 한 번에 끝내는 AWS 기반 아키텍처 설계와 DevOps</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Switch와 Router]]></title>
            <link>https://velog.io/@octo__/Switch%EC%99%80-Router</link>
            <guid>https://velog.io/@octo__/Switch%EC%99%80-Router</guid>
            <pubDate>Mon, 16 Jan 2023 08:41:55 GMT</pubDate>
            <description><![CDATA[<h1 id="switch">Switch</h1>
<p>Host는 간단히 말하자면 네트워크에 연결이 되어 있는 컴퓨터를 말하며, 크게 2가지로 나눌 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/f034a918-1b06-40a3-8a26-8f594deaae8f/image.png" alt=""></p>
<ul>
<li>Host 중 네트워크 자체를 이루는 Host</li>
<li>네트워크를 이용하는 이용 주체로써의 Host</li>
</ul>
<p>Host 중 네트워크 자체를 이루는 Host라면 이를 Switch라고 부르며, 네트워크를 이용하는 이용 주체로써의 Host는 End Point라고도 부른다.</p>
<p>기본적으로 <strong>스위치(Switch)의 역할은 스위치에 도착한 패킷을 특정 장치로 보내주는 스위칭(Switching)을 해주는 것</strong>이다.
네트워크 자체를 이루는 Host들을 모두 스위치라고 부를 수 있지만 특화된 역할에 따라, 속한 OSI 계층에 따라 세부적으로 다른 이름으로 불린다. </p>
<p>특수한 목적을 가진 스위치들을 제외한 <strong>스위치들은 여러 장치를 연결하여  LAN(local area network)를 형성하며 이는 로컬 영역 네트워크 즉, 같은 네트워크 주소를 가진다는 말과 같다.</strong></p>
<hr>
<h1 id="router">Router</h1>
<p><strong>라우터(Router)는 스위치 중 하나로 서로 다른 IP 네트워크 간의 네트워크 트래픽을 전달하는 장치</strong>이다. 다시 말해, 다른 네트워크 주소들을 연결하기 위한 장치이다.
또한 라우터 또한 목적지로 가는 적합한 경로를 찾아주는 라우팅 기능을 한다.</p>
<hr>
<h1 id="switch와-router의-차이점">Switch와 Router의 차이점</h1>
<table>
<thead>
<tr>
<th>구분</th>
<th>Switch</th>
<th>Router</th>
</tr>
</thead>
<tbody><tr>
<td>OSI 7계층</td>
<td>MAC주소를 기반으로 데이터링크 계층에서 동작(L2 switch)</td>
<td>IP 주소를 기반으로 네트워크 계층에서 동작(L3 switch)</td>
</tr>
<tr>
<td>브로드캐스트(Broadcast)</td>
<td>브로드캐스트 도메인을 구분할 수 없다.</td>
<td>브로드캐스트 도메인을 구분하여 서로 다른 네트워크 대역을 구분한다.</td>
</tr>
<tr>
<td>불명확한 목적지를 가지는 데이터</td>
<td>불명확한 목적지를 가진 데이터를 처리할 때 모든 포트로 데이터를 퍼뜨리는 브로드캐스트를 한다.</td>
<td>불명확한 목적지를 가진 데이터를 버린다.</td>
</tr>
<tr>
<td>관리자 설정</td>
<td>관리자의 설정이 필요 없다.</td>
<td>관리자의 설정으로 라우팅 테이블 생성과 통신을 해야한다.</td>
</tr>
</tbody></table>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
<ul>
<li><a href="https://velog.io/@mseo/NetPractice-%EA%B3%BC%EC%A0%9C%EB%A5%BC-%EC%9C%84%ED%95%9C-%EA%B8%B0%EC%B4%88%ED%95%99%EC%8A%B5">[NetPractice] 과제를 위한 기초학습 - mseo</a></li>
<li><a href="https://velog.io/@jihoon97/%EC%8A%A4%EC%9C%84%EC%B9%98-%EB%9D%BC%EC%9A%B0%ED%84%B0%EC%9D%98-%EC%B0%A8%EC%9D%B4">스위치, 라우터의 차이 - jihoon97</a></li>
<li><a href="https://server-engineer.tistory.com/582">https://server-engineer.tistory.com/582</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[IPv4 주소 구조와 Subnet Mask]]></title>
            <link>https://velog.io/@octo__/IPv4%EC%99%80-Subnet-Mask</link>
            <guid>https://velog.io/@octo__/IPv4%EC%99%80-Subnet-Mask</guid>
            <pubDate>Mon, 16 Jan 2023 08:33:13 GMT</pubDate>
            <description><![CDATA[<h1 id="ipv4-주소-구조">IPv4 주소 구조</h1>
<p><strong>IP는 Internet Protocal의 약자로, IP 주소는 Host에 대한 식별자</strong>이다.</p>
<p>현재 IP 주소는 IPv4, IPv6 버전을 가지고 있으며, 이 둘의 가장 큰 차이점은 주소의 길이이다. <strong>IPv4는 32 bit 주소 길이를 가지며, IPv6는 128 bit 주소 길이</strong>를 가진다. 일반적으로는 IPv4 환경을 사용한다.</p>
<p>IPv4주소는 일반적으로 <code>192.168.123.132</code>와 같이 마침표로 구분된 4개의 숫자가 있는 10진수의 형식으로 표시되지만, 이는 사실 2진수 숫자를 10진수로 표현한 것에 불과하다. 위의 IPv4 주소를 32비트로 표현하자면 <code>11000000.10101000.01111011.10000100</code>가 될 것이다. 즉, <strong>IPv4 주소는 8 bit 씩 끊어서 표시</strong>하는 것이다. 
8개의 비트를 묶은 세션을 옥텟(octet)이라고 하는데, 이 옥텟을 변환한 수가 우리가 익히 아는 IP주소의 형태를 띄는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/6e2432e6-b4d8-4bb5-bc57-1d94d3bee772/image.png" alt=""></p>
<p>이러한 IP 주소는 아래 명령어를 통해 확인할 수 있다.</p>
<ul>
<li>윈도우(Window): <code>ipconfig</code></li>
<li>맥(Mac): <code>ifconfig</code></li>
</ul>
<p>IPv4의 경우 32 bit 체계를 가지고 있으므로 약 43억개의 경우의 수를 가진다. 따라서 IPv4를 사용할 경우 인터넷에 Host로 참여할 수 있는 Host의 개수는 약 43억개로 제한된다. 이는 단순하게 생각해봐도 매우 부족하다.
따라서 이런 문제를 해결하기 위해 IP를 사용하는 네트워크 장치 수에 따라 효율적으로 사용할 수 있는 Network ID와 HostID가 등장하였다.</p>
<h2 id="network-id-host-id">Network ID, Host ID</h2>
<p>IP 주소는 Network ID, Host ID 두 부분으로 나뉘어진다.</p>
<ul>
<li>Network ID<ul>
<li><strong>Host들을 모은 네트워크를 지칭하는 주소</strong></li>
<li>네트워크 주소가 동일한 네트워크를 로컬 네트워크라고 한다.</li>
</ul>
</li>
<li>Host ID<ul>
<li><strong>하나의 네트워크 내에 존재하는 Host를 구분하기 위한 주소</strong></li>
</ul>
</li>
</ul>
<p>그런데 IP 주소에서 네트워크 ID와 호스트 ID를 구분하는 경계점이 고정되어있지 않다. 따라서 필요한 호스트 IP 개수에 따라 네트워크의 크리를 다르게 할당할 수 있다록 클래스(class)라는 개념을 도입하였다.
클래스는 A, B, C, D, E 클래스가 존재하며, 각각의 클래스에 할당되는 IP 주소 갯수와 역할이 다르다.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/adbddf17-c7c0-4b7f-9455-d783daeb9f27/image.png" alt=""></p>
<blockquote>
<p>C 클래스는 멀티캐스트를 위해 사용되고, E 클래스는 예약 되어있는 클래스이기 때문에 A, B, C 클래스와는 구분된다.</p>
</blockquote>
<h2 id="클래스풀classful-기반-주소-체계">클래스풀(Classful) 기반 주소 체계</h2>
<p>대표적으로 많이 사용되는 A, B, C 클래스들의 IP 주소의 갯수는 대략 다음과 같다.</p>
<ul>
<li>A 클래스 : 약 16,000,000개</li>
<li>B 클래스 : 약 65,000개</li>
<li>C 클래스 : 약 250개</li>
</ul>
<p>각각의 클래스에서 네트워크 주소와 호스트 주소를 나누는 기준은 아래와 같다.</p>
<pre><code>A 클래스 -&gt; 네트워크.호스트.호스트.호스트
B 클래스 -&gt; 네트워크.네트워크.호스트.호스트
C 클래스 -&gt; 네트워크.네트워크.네트워크.호스트
</code></pre><p>이러한 클래스들을 구분하기 위한 클래스 구분법은 맨 앞 옥텟의 주소가 무엇인지만 보면 구분할 수 있다. 각 클래스마다 가지는 맨 앞자리 옥텟은 아래와 같다.</p>
<pre><code>A 클래스 -&gt; 1~127.0.0.0 (로컬호스트)
B 클래스 -&gt; 128~191.0.0.0
C 클래스 -&gt; 192~223.0.0.0
D 클래스 -&gt; 224~239.0.0.0</code></pre><p>그런데 사실 클래스 기반으로 네트워크를 분할하는 기법은 현재는 사용하지 않는다. 클래스 기반보다 네트워크 주소를 세밀하게 분할하고 할당하기 위해서 네트워크 크기에 맞춰 1 bit 단위로 네트워크를 상세히 분할하는 방법을 사용한다.</p>
<p>과거 클래스 기반의 IP 주소 체계를 클래스풀(Classful)이라고 하는 반면 현재는 클래스 개념 자체를 버리는 클래스리스(Classless) 기반의 주소 체계를 사용한다.
그리고 이 클래스리스 기반 주소 체계를 사용하기 위해 도입된 것이 서브넷 마스크(Subnet Mask)이다.</p>
<hr>
<h1 id="subnet-mask">Subnet Mask</h1>
<p><strong>서브넷(Subnet)은 부분 망이라는 뜻이다. IPv4 주소에서 네트워크 영역을 부분적으로 나눈 부분 망, 즉 부분 네트워크</strong>를 뜻하는 것이다. 
이러한 <strong>서브넷을 만들 때 사용되는 것이 서브넷 마스크(Subnet Mask)</strong>이다. 이 서브넷 마스크를 이용하여 IP주소 체계의  Network ID와 Host ID를 서브넷 마스크를 통해 분리할 수 있다.</p>
<p>서브넷 마스크의 형태는 기본적으로 IPv4 주소와 같은 32 bit 이진수이며, IPv4와 같은 xxx.xxx.xxx.xxx 와 같은 형태를 가지고 있다. 이러한 서브넷 마스크를 이용해 IPv4 주소와 AND 연산하여 Network ID를 걸러낸다.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/90998f7a-d269-49b7-a8b3-b3c63159ce68/image.png" alt=""></p>
<hr>
<h1 id="서브넷팅subnetting">서브넷팅(Subnetting)</h1>
<p><strong>서브네팅(Subnetting)</strong>은 네트워크 관리자가 네트워크 성능을 향상시키기 위해, 자원을 효율적으로 분배하는 것이다. 다시 말해, <strong>IP 주소 낭비를 방지하기 위해 원본 네트워크를 여러개의 서브넷으로 분리하는 과정</strong>을 뜻한다.</p>
<p>네트워크적인 측면에서 말하자면, 너무 큰 브로드캐스트 도메인은 네트워크 환경에서 패킷전송을 느리게하고 성능저하를 발생시킨다. 따라서 네트워크를 쪼개서 통신 성능을 보장하는 것이다. 
또한 IPv4 주소는 한정적이기 때문에 서브넷마스크를 이용해 필요한 네트워크 주소만 호스트 ID로 할당 할 수 있게 만들어 네트워크 낭비를 방지하는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/d36343e3-ddce-4af5-8cef-5bc831700c13/image.png" alt=""></p>
<blockquote>
<p>서브네팅의 반대는 슈퍼네팅이라고 한다.</p>
</blockquote>
<p>서브넷팅은 서브넷 마스크의 bit 수를 증가시키는 것이라고 생각하면 이해가 편하다. 서브넷마스크의 bit 수를 1씩 증가시키면 할당할 수 있는 네트워크가 2배로 증가하고 호스트 수는 2배로 감소한다.</p>
<p>예를 들어 C클래스인 <code>192.168.32.0/24</code>를 서브넷 마스크의 bit 수를 1 증가시켜서 <code>192.168.32.0/25</code>로 변경한다고 하자.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/06d3a5b7-e095-4329-8dd1-6f70f22e29b8/image.png" alt=""></p>
<p><code>192.168.32.0/24</code>는 원래 하나의 네트워크였다. 이때 할당 가능한 host의 수는 $2^8 - 2 = 254개$이다. 
여기서 2개를 빼는 이유는 첫번째 주소인 <code>192.168.32.0</code>은 Network Address로 쓰이고 마지막 주소인 <code>192.168.32.255</code>는 Broadcast로 쓰이기 때문에 호스트에 할당할 수 없기 때문이다. </p>
<p>이 때 <strong>서브넷 마스크의 bit 수를 1증가시켜서(서브넷팅)</strong> <code>192.168.32.0/25</code>로 변경하게 되면 Network ID부분을 나타내는 부분이 24비트에서 25비트로 증가하고 Host ID를 나타내는 부분이 8개 비트에서 7개 비트로 줄어든다. 
즉 할당 가능한 네트워크 수가 2개로 증가하고 각 네트워크(서브넷)당 할당가능한 호스트수는 $2^7-2 = 126$개로 줄어든다. 또한 서브넷 마스크가 <code>255.255.255.128</code>로 변한 것을 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/f00ff5c1-6760-44d6-a73e-b369bfbbf745/image.png" alt=""></p>
<p>이런 식으로 효율적으로 IP 주소를 사용할 수 있게 만드는 것이다.</p>
<hr>
<h1 id="네트워크-브로드캐스트-주소">네트워크 브로드캐스트 주소</h1>
<p><strong>네트워크 주소(Network address)</strong>는 호스트 주소가 모두 0인 주소**로, 네트워크를 구별하기 위한 네트워크 주소로 사용되기 때문에 각 기기들이 통신하기 위한 고유 번호로는 사용되지 않는다.</p>
<p><strong>브로드캐스트 주소(Broadcast adddress)</strong>는 반대로 호스트 부분이 모두 1인 주소를 말하며, 특정 네트워크에 속하는 모든 호스트/클라이언트들이 듣게 되는 주소이다. 
목적이 있는 주소이기 때문에, 이 또한 각 기기들이 통신하는 고유 번호로 사용되지 않는다.</p>
<hr>
<h1 id="사설-ipprivate-ip">사설 IP(Private IP)</h1>
<p>사설 IP는 전세계적으로 고유한 IP가 아닌, **네트워크 내에서 자유롭게 할당해서 쓰는 IP주소, 또는 대역으로 각 클래스마다 사설 IP대역이 존재((한다.</p>
<pre><code>10.0.0.0~10.255.255.255 (A 클래스 사설 IP 대역)
172.16.0.0~172.31.255.255 (B 클래스 사설 IP 대역)
192.168.0.0~192.168.255.255 (C 클래스 사설 IP 대역)</code></pre><p>이 사설 IP는 라우터에 의해 로컬 네트워크 상에서 PC나 장치에 할당되기 때문에 <strong>하나의 네트워크 안에서는 유일하나, 전체 네트워크 상에서는 유일하지 않다.</strong> 또한 <strong>사설 IP로는 인터넷에 직접 연결할 수 없다.</strong></p>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
<ul>
<li><a href="https://youtu.be/gOMljj6K2V0">IPv4주소 체계에 대한 암기사항 - 널널한 개발자 TV</a></li>
<li><a href="https://code-lab1.tistory.com/34">https://code-lab1.tistory.com/34</a></li>
<li><a href="https://engkimbs.tistory.com/622">https://engkimbs.tistory.com/622</a></li>
<li><a href="https://medium.com/@su_bak/%EC%84%9C%EB%B8%8C%EB%84%B7-%EB%A7%88%EC%8A%A4%ED%81%AC-subnet-mask-%EB%9E%80-398ecdfd5c0d">서브넷 마스크(Subnet Mask)란? - Su Bak</a></li>
<li><a href="https://velog.io/@mseo/NetPractice-%EA%B3%BC%EC%A0%9C%EB%A5%BC-%EC%9C%84%ED%95%9C-%EA%B8%B0%EC%B4%88%ED%95%99%EC%8A%B5">[NetPractice] 과제를 위한 기초학습 - mseo</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Host, Switch, Network]]></title>
            <link>https://velog.io/@octo__/Host-Switch-Network</link>
            <guid>https://velog.io/@octo__/Host-Switch-Network</guid>
            <pubDate>Mon, 16 Jan 2023 06:43:00 GMT</pubDate>
            <description><![CDATA[<h1 id="host-와-switch">Host 와 Switch</h1>
<p>간단히 말하자면 <strong>네트워크에 연결이 되어 있는 컴퓨터</strong>를 말한다.
그런데 Host는 크게 나누어서 생각할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/71ef275d-be53-4465-88fe-c5850797963a/image.png" alt=""></p>
<ul>
<li>Host 중 네트워크 자체를 이루는 Host</li>
<li>네트워크를 이용하는 이용 주체로써의 Host</li>
</ul>
<p><strong>Host 중 네트워크 자체를 이루는 Host라면 이를 <em>Switch</em></strong>라고 부르며, <strong>네트워크를 이용하는 이용 주체로써의 Host는 <em>End Point</em></strong>라고도 부른다.</p>
<p><em>End Point*의 역할에 따라 peer, server, client 등으로 불려진다.
*Switch</em> 또한 역할에 따라 여러 종류로 불리는데, 대표적으로 Router가 있다. OSI 7계층 위치에 따라서 L1 Switch, L2 Switch, ... 등으로도 불린다.</p>
<blockquote>
<p><strong>참고</strong></p>
<ul>
<li>IDS (침입 탐지 시스템) : 네트워크 비정상 행동을 감지해 관리자에게 알린다</li>
<li>IPS (침입 방지 시스템) : 침입 이전에 방지하고, 탐지했을 경우 처리까지 한다</li>
<li>FireWall(방화벽) : 접근을 통제한다</li>
<li>Peer : 동일 프로토콜 계층에서 대등한 지위로 동작하는 장치</li>
<li>Switch : 데이터 링크 계층에서 작동하며 물리 포트에서 전송된 패킷을 MAC 주소로 스위칭한다 (로컬)</li>
<li>Switching : 노드 간 연결을 중개하는 것을 뜻한다</li>
<li>Router : 네트워크 계층에서 작동하며 다른 네트워크와 연결한다 (WAN)</li>
<li>Ethernet : 다수의 시스템이 랜선 / 통신포트로 연결되어 통신하는 구조이다</li>
</ul>
</blockquote>
<hr>
<h1 id="network">Network</h1>
<p>네트워크 중 가장 유명한 네트워크는 인터넷(Internet)이다.
이러한 인터넷을 구성하는 가장 중요한 2가지는 Router와 DNS 이다. 다시 말해 <strong>인터넷은 Router와 DNS의 집합체</strong>라고 할 수 있다.</p>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
<ul>
<li><a href="https://youtu.be/kGst-VftN1w">Host, Switch, Network 이들의 관계에 대해... - 널널한 개발자 TV</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[MAC 주소, IP 주소, Port 번호]]></title>
            <link>https://velog.io/@octo__/MAC-%EC%A3%BC%EC%86%8C-IP-%EC%A3%BC%EC%86%8C-Port-%EB%B2%88%ED%98%B8</link>
            <guid>https://velog.io/@octo__/MAC-%EC%A3%BC%EC%86%8C-IP-%EC%A3%BC%EC%86%8C-Port-%EB%B2%88%ED%98%B8</guid>
            <pubDate>Mon, 16 Jan 2023 06:17:18 GMT</pubDate>
            <description><![CDATA[<p>OSI 7계층에서 <strong>MAC 주소는 데이터 링크 계층, IP 주소는 네트워크 계층, Port 번호는 전송 계층에 위치</strong>하고 있다.
각각은 식별자로서 사용되는데, 아래에 해당하는 부분들을 식별한다.</p>
<ul>
<li>MAC 주소<ul>
<li><strong>네트워크 인터페이스 카드(Network Interface Card, NIC)에 대한 식별자</strong></li>
<li>NIC 갯수에 따라 여러 개 존재할 수 있다.</li>
<li>하드웨어 주소라고도 하며, 변경 가능하다.</li>
</ul>
</li>
<li>IP 주소<ul>
<li><strong>호스트(Host)에 대한 식별자</strong></li>
<li>호스트(Host): <strong>인터넷에 연결된</strong> 컴퓨터(또는 터미널(terminal))</li>
<li>NIC 하나 당 여러 개의 IP 주소를 바인딩(binding)할 수 있다.</li>
</ul>
</li>
<li>Port 번호<ul>
<li>소프트웨어 관점에서는 <strong>프로세스(Process)에 대한 식별자</strong></li>
<li>커널 관점(전송 계층 관점)에서는 <strong>서비스(Service)에 대한 식별자</strong></li>
<li>하드웨어 관점에서는 <strong>인터페이스(Interface)에 대한 식별자</strong></li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>참고</strong>
랜카드(Lan Card) = 네트워크 인터페이스 카드(Network Interface Card, NIC) = 이더넷카드(Ethernet Card)</p>
</blockquote>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
<ul>
<li><a href="https://youtu.be/JDh_lzHO_CA">MAC주소, IP주소, Port번호가 식별하는 것 - 널널한 개발자 TV</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 데코레이터(Decorator)]]></title>
            <link>https://velog.io/@octo__/TypeScript-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0Decorator</link>
            <guid>https://velog.io/@octo__/TypeScript-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0Decorator</guid>
            <pubDate>Sun, 15 Jan 2023 08:02:45 GMT</pubDate>
            <description><![CDATA[<h1 id="데코레이터">데코레이터</h1>
<p><strong>데코레이터(<em>Decorator</em>)는 타입스크립트에서는 실험적으로 도입된 기능</strong>이다. 타입스크립트의 데코레이터는 자바(<em>Java</em>)의 어노테이션이나 파이썬(<em>Python</em>)의 데코레이터와 유사한 기능을 한다.그러나 자바 어노테이션은 컴파일 타임에 상관있지만 타입스크립트 데코레이터는 컴파일 타임에는 상관하지 않기 때문에, 오히려 <strong>파이썬(Python)의 데코레이터와 거의 비슷</strong>하다고 볼 수 있다.</p>
<p><strong>데코레이터는 일종의 함수로 코드 조각을 장식해주는 역할을 하며, 타입스크립트에서는 그 기능을 함수로 구현하는 것</strong>이다.
메소드, 클래스, 프로퍼티, 파라미터 등 위에 <code>@</code>로 시작하는 데코레이터를 선언하여 장식하면 코드가 실행(런타임)이 되면 데코레이터 함수가 실행되어, 장식한 멤버를 보다 강력하게 만들어주는 것이다.</p>
<p>데코레이터를 잘 사용하면 횡단 관심사(<em>cross-cutting concern</em>)를 분리하여 관점 지향 프로그래밍을 적용한 코드를 작성할 수 있다.
또한 <strong>데코레이터 패턴은 클래스를 수정하지 않고 클래스의 멤버들의 정의를 수정 및 기능을 확장할 수 있는 구조적 패턴의 하나로,</strong> 데코레이터 패턴을 사용하면 전체 기능에 신경 쓰지 않고 특정 인스턴스에 초점을 맞출 수 있다.</p>
<p>지금까지의 데코레이터의 특징 정리하면 다음과 같다.</p>
<ul>
<li>데코레이터는 클래스 선언, 메서드(method), 접근자(accessor), 프로퍼티(property) 또는 매개변수(parameter)에 첨부할 수 있는 특수한 종류의 선언이다.</li>
<li>데코레이터 함수에는 target(현재타겟), key(속성이름), descriptor(설명)가 전달된다. (단, 어떤 멤버를 장식했느냐에 따라 인수가 달라짐)</li>
<li>메소드나 클래스 인스턴스가 만들어지는 런타임에 실행된다. 즉, 매번 실행되지 않는다.</li>
<li>데코레이터는 클래스 또는 클래스 내부의 생성자, 프로퍼티, 접근자, 메서드, 그리고 매개변수에만 장식될 수 있다.</li>
</ul>
<h2 id="데코레이터-설정">데코레이터 설정</h2>
<p>타입스크립트의 데코레이터는 정식 지원하는 문법 기능이 아닌 실험적인(experimental) 기능이다.
타입스크립트에서 데코레이터를 사용하기 위해선 <code>tsconfig.json</code> 파일에서 <code>experimentalDecorators</code> 옵션을 활성화 해야 한다.</p>
<pre><code class="language-json">// tsconfig.json
{
  &quot;compilerOptions&quot;: {
    ...
    &quot;experimentalDecorators&quot;: true,
    ...
  }
}</code></pre>
<h2 id="데코레이터-함수-선언과-데코레이터-팩토리">데코레이터 함수 선언과 데코레이터 팩토리</h2>
<h3 id="데코레이터-함수-선언">데코레이터 함수 선언</h3>
<p>데코레이터를 사용하기 위해서는 테코레이터 함수를 선언해야 한다. <strong>데코레이터 함수는 테코레이팅된 선언(데코레이터가 선언되는 클래스, 메서드 등)에 대한 정보와 함께 호출되는 함수</strong>여야 한다.</p>
<p>아래는 메서드 데코레이터의 예시이며 테코레이터 함수의 인자는 어떤 테코레이터 함수이냐에 따라 다르다.</p>
<pre><code class="language-typescript">function deco(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  console.log(&#39;데코레이터가 평가됨&#39;);
}

class TestClass {
  @deco()
  test() {
    console.log(&#39;함수 호출됨&#39;);
  }
}

const t = new TestClass();
t.test();</code></pre>
<pre><code class="language-shell">데코레이터가 평가됨
함수 호출됨</code></pre>
<h3 id="데코레이터-팩토리">데코레이터 팩토리</h3>
<p><strong>데코레이터 팩토리 함수(<em>decorator factory function</em>)는 데코레이터 함수를 감싸는 래퍼(<em>wrapper</em>) 함수</strong>이다. 보통 데코레이터가 선언에 적용되는 방식을 원하는 대로 바꾸고 싶을 때 사용된다.</p>
<p>프로그래밍에서 함수에게 사용자가 인자를 전달할 수 있는 것과 유사하게, <strong>데코레이터 함수 또한 팩토리를 사용해 사용자로부터 인자를 전달 받도록 설정할 수 있다.</strong>
즉, 데코레이터 팩토리는 사용자로부터 전달 받은 인자를, 내부에서 반환되는 데코레이터 함수는 데코레이터로 사용되는 것이다.</p>
<p>아래 예시를 보면, 클로저 변수로 사용자 인자를 받고 리턴값으로 데코레이터 함수를 반환하여 데코레이터를 실행하는 것을 볼 수 있다.</p>
<pre><code class="language-typescript">// 데코레이터 팩토리
function deco(value: string) {
  console.log(&#39;데코레이터가 평가됨&#39;);

  // 데코레이터 함수
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log(value);
  };
}

class TestClass {
  // 데코레이터 팩토리를 사용하면 인자 값을 전달할 수 있다.
  @deco(&#39;HELLO&#39;)
  test() {
    console.log(&#39;함수 호출됨&#39;);
}

const t = new TestClass();
t.test();</code></pre>
<pre><code class="language-shell">데코레이터가 평가됨
HELLO
함수 호출됨</code></pre>
<h2 id="데코레이터-합성--멀티-데코레이터">데코레이터 합성 / 멀티 데코레이터</h2>
<p>데코레이터의 또 다른 장점으로는 <strong>하나의 멤버에 동시에 여러 개의 데코레이터를 장식할 수 있는 점이다. 이를 데코레이터 합성(<em>Decorator Composition</em>)</strong>이라고도 부른다.
여러 개의 데코레이터를 사용하면 수학의 함수 합성(<em>function compsition</em>)과 같이 합성할 수 있게 되기 때문에 이렇게 부르며, 아래 데코레이터 선언의 합성 결과는 수학적으로 $f(g(x))$와 같다.</p>
<pre><code class="language-typescript">@f
@g
test</code></pre>
<p>멀티 데코레이터의 실행 흐름은 다음 순으로 처리된다.</p>
<ol>
<li>각 데코레이터 표현식은 위에서 아래 방향(⬇︎)으로 평가(<em>evaluate</em>)된다.</li>
<li>실행 결과는 아래에서 위로(⬆︎) 함수를 호출(<em>call</em>)된다.</li>
</ol>
<p>데코레이터 팩토리를 사용해 멀티 데코레이터의 실행 흐름을 살펴보면 다음과 같다.</p>
<pre><code class="language-typescript">// Size 데코레이터 팩토리
function Size() {
  console.log(&#39;Size(): 평가됨&#39;);
  // Size 데코레이터
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log(&#39;Size(): 실행됨&#39;);
  };
}

// Color 데코레이터 팩토리
function Color() {
  console.log(&#39;Color(): 평가됨&#39;);
  // Color 데코레이터
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log(&#39;Color(): 실행됨&#39;);
  };
}

// Button 클래스 정의
class Button {
  // 메서드에 멀티 데코레이터 적용
  @Size()
  @Color()
  isPressed() {}
}</code></pre>
<pre><code class="language-shell">Size(): 평가됨
Color(): 평가됨
Color(): 실행됨
Size(): 실행됨</code></pre>
<p>이처럼 <code>@expression</code>에서 <code>expression</code> 표현식을 함수로 평가하는 순서는 위에서 아래이다.
그리고 <code>expression</code>이 함수로 평가된(데코레이터 팩토리) 후에, 실행 결과(데코레이터 함수)가 실행되는 순서는 아래에서 위가 된다.</p>
<hr>
<h1 id="데코레이터-종류">데코레이터 종류</h1>
<h2 id="class-decorator">Class Decorator</h2>
<p><strong>클래스 데코레이터(<em>class decorator</em>)는 클래스 선언 직전에 선언되는 데코레이터</strong>이다. 클래스 데코레이터는 <strong>클래스의 생성자의 클래스 정의(<em>definiton</em>)을 읽거나 수정할 수 있어 기존의 클래스 정의를 확장하는 용도로 사용할 수 있다.</strong>
선언 파일(<code>*.d.ts</code>)과 선언 클래스(<em>declare class</em>) 내에서는 사용할 수 없다. 클래스 데코레이터 매개변수로는 클래스 생성자 자체를 받게 되는 특징이 있다.</p>
<p>클래스 데코레이터 매개변수</p>
<ul>
<li>첫 번째 <code>argument</code> (<code>constructor</code>) : 클래스(생성자 함수)가 전달된다. 타입스크립트가 클래스를 실행할 때 클래스의 생성자를 데코레이터의 <code>constructor</code> 파라미터로 자동 전달하므로, 생성자를 명시적으로 전달하지 않아도 된다.</li>
<li>클래스 데코레이터 리턴값<ul>
<li><code>class</code> 또는 <code>void</code></li>
</ul>
</li>
</ul>
<pre><code class="language-typescript">// 제네릭 - 해당 함수를 호출할 때 동적으로 &lt;&gt;에 정의된 타입을 받음. 여기선 클래스 생성자 타입으로 받는의미
function classDecorator&lt;T extends { new (...args: any[]): {} }&gt;(constructorFn: T)
{
    ... 
} // 리턴값은 class 혹은 void</code></pre>
<h3 id="클래스-데코레이터-예제">클래스 데코레이터 예제</h3>
<p>아래 예시는 데코레이터가 <code>Test</code>의 <code>constructor</code>를 상속해서 추가로 프로퍼티를 지정하고 리턴해주었는데, 이게 그대로 <code>Test</code> 클래스의 <code>constructor</code> 쪽으로 가서 확장이 된다고 생각하면 된다.
그래서 실행 결과가 기존의 Test의 생성자에 없던 프로퍼티들이 추가된 것으로 <strong>데코레이터가 클래스의 멤버를 확장</strong>한 것이다.</p>
<pre><code class="language-typescript">function classDecorator&lt;T extends { new (...args: any[]): {} }&gt;(constructor: T) {
  // Test 클래스의 constructor를 상속해서 new Test() 가 되면 추가된 생성자도 실행되도록 설정
  return class extends constructor { 
    first_prop = &#39;override&#39;; // 데코레이터에서 새로 프로퍼티를 덮어씌움
    new_prop = &#39;new property&#39;; // 데코레이터에서 새로 프로퍼티를 추가
  };
}

@classDecorator
class Test {
  first_prop: string;

  constructor(m: string) {
    this.first_prop = m;
  }
}

let t = new Test(&#39;abcdefg&#39;);
console.log(t);
console.log( t.first_prop ); // &#39;override&#39;

// 데코레이터로 설정된 프로토타입 확장은 타입 단언(Type Assertion) 필요
console.log( (t as any).new_prop ); // &#39;new property&#39;</code></pre>
<pre><code class="language-shell">Test { 
    first_prop: &#39;override&#39;, 
    new_prop: &#39;new property&#39; 
}
override
new property</code></pre>
<h3 id="클래스-데코레이터-팩토리-사용-예제">클래스 데코레이터 팩토리 사용 예제</h3>
<p>클래스 데코레이터에 데코레이터 팩토리를 이용한 예제이다.
데코레이터 팩토리에 전달된 사용자 인자값을 데코레이터 함수에서 사용해 결과를 리턴한다.</p>
<pre><code class="language-typescript">// 데코레이터 팩토리
function classDecorator(param1: string, param2: string) {
  // 데코레이터 함수
  return function &lt;T extends { new (...args: any[]): {} }&gt;(constructor: T) {
    return class extends constructor {
      new_prop = param1;
      first_prop = param2;
    };
  };
}

@classDecorator(&#39;안녕하세요&#39;, &#39;반갑습니다&#39;)
class Test {
  first_prop: string;

  constructor(m: string) {
    this.first_prop = m;
  }
}

let t = new Test(&#39;world&#39;);
console.log(t);</code></pre>
<pre><code>Test { 
    first_prop: &#39;반갑습니다&#39;, 
    new_prop: &#39;안녕하세요&#39; 
}</code></pre><h3 id="프로토타입prototype을-이용한-확장">프로토타입(prototype)을 이용한 확장</h3>
<p>장식된 클래스의 constructor를 확장하는 것뿐만 아니라 프로토타입을 이용하여 확장할 수 있다.</p>
<pre><code class="language-typescript">function classDecoratorFactory&lt;T extends { new (...args: any[]): {} }&gt;(constructorFn: T) {

   // 프로토타입으로 새로운 프로퍼티를 추가
   constructorFn.prototype.print2 = function () {
      console.log(&#39;this is print2&#39;);
   };
   constructorFn.prototype.gender = &#39;male&#39;;

   // 클래스를 프로퍼티에 상속시켜 새로운 멤버를 추가 설정
   return class extends constructorFn {
      public name = &#39;mark&#39;;
      private _age = 36;

      constructor(...args: any[]) {
         super(args);
      }

      public print() {
         console.log(&#39;this is print&#39;);
      }
   };
}

@classDecoratorFactory
class Test2 {}

const test2 = new Test2();

console.log(test2); // class_1 { name: &#39;mark&#39;, _age: 36 }

// 클래스 Test의 타입에는 print 함수가 없고, 데코레이터로 동적으로 추가된 형태이니, 타입 단언을 사용
(test2 as any).print(); // this is print 
(test2 as any).print2(); // this is print2 

console.log((test2 as any).gender); // male</code></pre>
<pre><code class="language-shell">Test2 { name: &#39;mark&#39;, _age: 36 }
this is print
this is print2
male</code></pre>
<h2 id="method-decorator">Method decorator</h2>
<p><strong>메서드 데코레이터(<em>method decorator</em>)는 메서드 선언 직전에 선언되는 데코레이터로 메서드 관찰, 수정 또는 대체하는 데 사용</strong>할 수 있다.
메서드의 속성 설명자(<em>property descriptor</em>)에 적용되고 메서드의 정의를 읽거나 수정할 수 있다. 선언 파일(<code>*.d.ts</code>), 오버로드 메서드(<em>overload method</em>), 선언 클래스에 사용할 수 없다.</p>
<blockquote>
<p><strong>참고</strong>
<em>Property Descriptor</em>는 객체의 프로퍼티들을 기존보다 정교하게 정의할 수 있는 ES5의 스펙이며, 프로퍼티의 특성을 설명하는 역할을 하는 객체이다.
이 <em>Property Descriptor</em>는 <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty"><code>Object.getOwnPropertyDescriptor</code></a>를 사용해서 가져올 수 있다.</p>
</blockquote>
<p>메서드 데코레이터 함수가 전달 받는 인자는 총 3가지로 다음과 같다.</p>
<ul>
<li>첫 번째 <code>argument</code> : <code>static</code> 프로퍼티가 속한 클래스의 생성자 함수 또는 인스턴스 프로퍼티에 대한 클래스의 <code>prototype</code> 객체</li>
<li>두 번째 <code>argument</code> : 해당 <code>method</code>의 이름</li>
<li>세 번째 <code>argument</code> : 해당 <code>method</code>의 <code>property descriptor</code></li>
</ul>
<pre><code class="language-typescript">function methodDecorator(
    target: any, // static 메서드라면 클래스의 생성자 함수, 인스턴스의 메서드라면 클래스의 prototype 객체
    propertyKey: string, // 메서드 이름
    descriptor: PropertyDescriptor // 메서드의 Property Descriptor
) {
    ... 
} // return 값 무시됨</code></pre>
<p>메서드 데코레이터는 클래스, 메서드 이름, 호출된 메서드(해당 메서드는 <code>Object.defineProperty()</code>로 만들어 짐)로 정의된 메서드 순으로 전달받는다.</p>
<blockquote>
<p><strong>PropertyDescriptor interface</strong>
<code>PropertyDescriptor</code>는 객체 속성의 특성을 기술하는 객체이다.</p>
<pre><code class="language-typescript">interface PropertyDescriptor {
 configurable?: boolean;    // 속성의 정의를 수정할 수 있는지 여부
 enumerable?: boolean;    // 열거형인지 여부
 value?: any;                // 속성 값
 writable?: boolean;        // 수정 가능 여부
 get?(): any;                // getter
 set?(v: any): void;        // setter
}</code></pre>
</blockquote>
<h3 id="메서드-데코레이터-예제1">메서드 데코레이터 예제1</h3>
<p>만약 해당 메서드가 호출될 때 특정 무엇인가를 동작시키고 싶다면 데코레이터에서 <code>descriptor</code>를 다음과 같이 재정의 해주면 된다.</p>
<pre><code class="language-typescript">function methodDecorator() {
  return function (target: any, property: string, descriptor: PropertyDescriptor) {

    // descriptor.value는 test() 함수 자체를 가리킨다. 이 함수를 잠시 변수에 피신 시킨다.
    let originMethod = descriptor.value; 

    // 그리고 기존의 test() 함수의 내용을 다음과 같이 바꾼다.
    descriptor.value = function (...args: any) {
      console.log(&#39;before&#39;);
      originMethod.apply(this, args); // 위에서 변수에 피신한 함수를 call, apply, bind 를 통해 호출
      console.log(&#39;after&#39;);
    };
  };
}

class Test {
  property = &#39;property&#39;;
  hello: string;

  constructor(m: string) {
    this.hello = m;
  }

  @methodDecorator()
  test() {
    console.log(&#39;test&#39;);
  }
}

let test = new Test(&quot;world&quot;)
test.test()</code></pre>
<pre><code class="language-shell">before
test
after</code></pre>
<p>데코레이터 인수의 <code>descriptor.value</code> 로 접근하면 장식된 함수 자체로 접근하게 되는데 이를 잠시 백업하고 나중에 실행하는 식으로 응용이 가능하다.
<strong>중요한 점은 백업된 메서드를 호출할 때 <code>apply</code>를 이용하여 <code>this</code>를 바인딩해줘야 한다는 점이다. 만일 <code>this</code>를 바인딩하지 않으면 해당 메서드를 어느 객체가 호출 했는지 알 수 없기 때문이다.</strong></p>
<h3 id="메서드-데코레이터-예제2">메서드 데코레이터 예제2</h3>
<p>좀더 응용하자면, 메서드 데코레이터로 특정 메서드의 실행 전/후 로깅, 실행시간을 측정 가능하다.</p>
<pre><code class="language-typescript">function methodDecorator() {
  return function (target: any, property: string, descriptor: PropertyDescriptor) {

    // descriptor.value는 test() 함수 자체를 가리킨다. 이 함수를 잠시 변수에 피신 시킨다.
    let originMethod = descriptor.value;

    // 그리고 기존의 test() 함수의 내용을 다음과 같이 바꾼다.
    descriptor.value = function (...args: any) {
      let startTS = new Date().getTime();

      originMethod.apply(this, args); // 위에서 변수에 피신한 함수를 call,apply,bind 를 통해 호출

      let endTS = new Date().getTime();

      console.log(`실행시간: ${(endTS - startTS) / 1000} S`);
    };
  };
}

// ...</code></pre>
<pre><code class="language-shell">test
실행시간: 0 S</code></pre>
<h2 id="accessor-decorators">Accessor Decorators</h2>
<p><strong>접근자 데코레이터(<em>accessor decorator</em>)는 접근자(<em>accessor</em>) 바로 앞에 선언한다. 접근자의 속성 설명자에 적용되고 접근자의 정의를 읽거나 수정할 수 있다.</strong> 선언 파일(<code>*.d.ts</code>)과 선언 클래스에는 사용할 수 없다.</p>
<blockquote>
<p><strong>접근자(accessor)</strong>
객체 프로퍼티를 객체 외에서 읽고 쓸 수 있는 함수이다. 쉽게 말하자면 <code>getter</code>와 <code>setter</code>이다.
타입스크립트에서는 <code>getter</code>, <code>setter</code>를 구현할 수 있는 <code>get</code>, <code>set</code> 키워드가 있다.</p>
</blockquote>
<p>접근자 데코레이터 매개변수</p>
<ul>
<li>첫 번째 <code>argument</code> : <code>static</code> 프로퍼티가 속한 클래스의 생성자 함수 또는 인스턴스 프로퍼티에 대한 클래스의 <code>prototype</code> 객체</li>
<li>두 번째 <code>argument</code> : 해당 <code>method</code>의 이름</li>
<li>세 번째 <code>argument</code> : 해당 <code>method</code>의 <code>property descriptor</code></li>
</ul>
<p>접근자 데코레이터 리턴값</p>
<ul>
<li><em>Property Descriptor</em> 형태</li>
<li><code>void</code></li>
</ul>
<h3 id="접근자-데코레이터-예제">접근자 데코레이터 예제</h3>
<p>특정 프로퍼티가 열거가 가능하지 결정하는 데코레이터 예제이다.</p>
<pre><code class="language-typescript">function Enumerable(enumerable: boolean) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.enumerable = enumerable;
  };
}

class Person {
  constructor(private name: string) {}

  @Enumberable(true)
  get getName() {
    return this.name;
  }

  @Enumberable(false)
  set setName() {
    this.name = name;
  }
}

const person = new Person(&#39;hello&#39;);
for (let key in person) {
  console.log(`${key}: ${person[key]}`);
}</code></pre>
<p>결과를 출력하면 <code>getName</code>은 출력되지만 <code>setName</code>은 열거하지 못하게 되었기 때문에 <code>for</code> 문에서 <code>key</code>로 받을 수 없다.</p>
<pre><code class="language-shell">name: hello
getName: hello</code></pre>
<h2 id="property-decorators">Property Decorators</h2>
<p><strong>속성 데코레이터(<em>property decorator</em>)는 클래스의 프로퍼티 선언 바로 전에 선언</strong> 된다. 
속성 데코레이터는 메서드 데코레이터와 다르게 데코레이터 함수에 <strong><em>Property Descriptor</em>가 인자로서 제공되지 않는다</strong>는 차이가 있다. 대신에 속성 데코레이터도 마찬가지로 <strong><em>Property Descriptor</em> 형식의 객체를 반환해서 프로퍼티의 설정을 바꿀 수 있다.</strong></p>
<p>속성 데코레이터 매개변수</p>
<ul>
<li>첫 번째 <code>argument</code> : <code>static</code> 프로퍼티라면 클래스의 생성자 함수, 인스턴스 프로퍼티라면 클래스의 <code>prototype</code> 객체</li>
<li>두 번째 <code>argument</code> : 해당 <code>property</code>의 이름</li>
</ul>
<p>속성 데코레이터 리턴값</p>
<ul>
<li><em>Property Descriptor</em> 형태</li>
<li><code>void</code></li>
</ul>
<pre><code class="language-typescript">function propertyDecorator(
  target: any, // static 프로퍼티라면 클래스의 생성자 함수, 인스턴스 프로퍼티라면 클래스의 prototype 객체
  propertyName: string, // 프로퍼티 이름
): any {
    ...
} // return하는 값이 Property Descriptor 형태 또는 void. 이로서 해당 property의 writable 등을 조작할 수 있음</code></pre>
<h3 id="속성-데코레이터-예제">속성 데코레이터 예제</h3>
<p>리턴값으로 <code>Object.defineProperty()</code>를 반환함으로써, 이를 통해 속성의 부가적인 설정을 할 수 있다.</p>
<p>예를들어 다음과 같이, 앞의 데코레이터는 <code>boolean</code> 타입의 인자를 전달받아 <code>writable</code>로 설정하게 되는데 <code>writable</code>이 <code>false</code>일 경우 해당 속성은 값을 수정할 수 없게 된다.</p>
<pre><code class="language-typescript">function writable(isWritable: boolean) {
  return function (target: any, propertyName: any): any {
    return {
      writable,
    };
  };
}

class Test {
  property = &#39;property&#39;;

  @writable(false)
  public data1 = 0;

  @writable(true)
  public data2 = 0;
}

const t = new Test();
t.data1 = 1000;
t.data2 = 1000; // 런타임 에러 !! - data2는 writable이 false라서 값을 대입할 수가 없다.</code></pre>
<h3 id="속성-데코레이터-getter-setter-설정-예제">속성 데코레이터 getter, setter 설정 예제</h3>
<p>좀더 응용하자면 다음과 같이 <code>getter</code>와 <code>setter</code>도 설정이 가능하다.</p>
<pre><code class="language-typescript">function SetDefaultValue(numberA: number, numberB: number) {
  return (target: any, propertyKey: string) =&gt; {
    const addNumber = numberA * numberB;
    let value = 0;

    // 데코레이터가 장식된 DataDefaultType의 num 이라는 프로퍼티의 객체 getter / setter 설정을 추가한다.
    Object.defineProperty(target, propertyKey, {
      get() {
        return value + addNumber; // 조회 할때는 더하기 시킴
      },
      set(newValue: any) {
        value = newValue - 30; // 설정 할때는 30을 뺌
      },
    });
  };
}

class DataDefaultType {
  @SetDefaultValue(10, 20)
  num: number = 0;
}

const test = new DataDefaultType();

test.num = 30;
console.log(`num is 30, 결과 : ${test.num}`); // num is 30, 결과 : 200

test.num = 130;
console.log(`num is 130, 결과 : ${test.num}`); // num is 130, 결과 : 300</code></pre>
<pre><code class="language-shell">num is 30, 결과 : 200
num is 130, 결과 : 300</code></pre>
<h2 id="parameter-decorators">Parameter Decorators</h2>
<p><strong>매개변수 데코레이터(<em>parameter decorator</em>)는 생성자 또는 메서드의 매개 변수에 선언되어 적용된다. 데코레이터는 가로로 써도 인식되기 때문에 함수의 매개변수 왼쪽 옆에 명시</strong>해 주면 된다. 선언 파일(<code>*.d.ts</code>), 선언 클래스에서는 사용할 수 없다.</p>
<p>파라미터 데코레이터 매개변수</p>
<ul>
<li>첫 번째 <code>argument</code> : <code>static</code> 프로퍼티가 속한 클래스의 생성자 함수 또는 인스턴스 프로퍼티가 속한 클래스의 <code>prototype</code> 객체</li>
<li>두 번째 <code>argument</code> : 매개변수가 들어있는 <code>method</code>의 이름</li>
<li>세 번째 <code>argument</code> : 메서드 파라미터 목록에서의 <code>index</code></li>
</ul>
<pre><code class="language-typescript">function parameterDecorator(
  target: any, // static 메서드의 파라미터 데코레이터라면 클래스의 생성자 함수, 인스턴스의 메서드라면 prototype 객체
  methodName: string, // 매개변수가 들어있는 메서드의 이름
  paramIndex: number // 매개변수의 순서 인덱스
) {
    ...
} // 리턴값은 무시됨</code></pre>
<h3 id="매개-변수-데코레이터-예제">매개 변수 데코레이터 예제</h3>
<p>아래 예제는 제대로 된 값이 전달되었는지 확인하는 데코레이터이다. 매개 변수 데코레이터는 단독으로 사용하기 보다는 메서드 데코레이터와 함께 사용할 때 유용하게 사용된다.</p>
<pre><code class="language-typescript">import { BadRequestException } from &#39;@nestjs/common&#39;;

// 매개 변수 데코레이터 함수
// target 클래스의 validators 속성에 유효성을 검사하는 함수 할당
function MinLength(min: number) {
  return function(target: any, propertyKey: string, parameterIndex: number) {
    target.validators = {
      minLength: function(args: string[]) {
        return args[parameterIndex].length &gt;= min;
      }
    }
  }
}

// 메서드 데코레이터 함수
function Validate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const method = descriptor.value;

  // 설명자의 value에 유효성 검사 로직이 추가된 함수를 할당
  descriptor.value = function(...args) {
    // target에 저장해둔 validators를 모두 수행한다. 이때 원래 메서드에 전달된 인수들을 각 validator에 전달한다.
    Object.keys(target.validators).forEach(key =&gt; {
      if (!target.validators[key](args)) {
        throw new BadRequestException();
      }
    })
    // 기존 함수를 실행
    method.apply(this, args);
  }
}

class User {
  private name: string;

  @Validator
  setName(@MinLength(3) name: string) {
    this.name = name;
  }
}

const t = new User();
t.setName(&#39;hello&#39;);
console.log(&#39;---------------&#39;);
t.setName(&#39;hi&#39;);    // BadRequestException</code></pre>
<hr>
<h1 id="데코레이터-요약-및-호출-순서">데코레이터 요약 및 호출 순서</h1>
<p>각 데코레이터의 특징을 간략하게 정리하면 다음과 같다.</p>
<table>
<thead>
<tr>
<th>데코레이터</th>
<th>역할</th>
<th>호출 시 전달되는 인수</th>
<th>선언 불가능한 위치</th>
</tr>
</thead>
<tbody><tr>
<td>클래스 데코레이터</td>
<td>클래스의 정의를 읽거나 수정</td>
<td><code>constructor</code></td>
<td><code>.d.ts</code> 파일, <code>declare</code> 클래스</td>
</tr>
<tr>
<td>메서드 데코레이터</td>
<td>메서드의 정의를 읽거나 수정</td>
<td><code>target</code>, <code>propertyKey</code>, <code>propertyDescriptor</code></td>
<td><code>.d.ts</code> 파일, <code>declare</code> 클래스, 오버로드 메서드</td>
</tr>
<tr>
<td>접근자 데코레이터</td>
<td>접근자의 정의를 읽거나 수정</td>
<td><code>target</code>, <code>propertyKey</code>, <code>propertyDescriptor</code></td>
<td><code>.d.ts</code> 파일, <code>declare</code> 클래스</td>
</tr>
<tr>
<td>속성 데코레이터</td>
<td>속성의 정의를 읽음</td>
<td><code>target</code>, <code>propertyKey</code></td>
<td><code>.d.ts</code> 파일, <code>declare</code> 클래스</td>
</tr>
<tr>
<td>매개변수 데코레이터</td>
<td>매겨변수의 정의를 읽음</td>
<td><code>target</code>, <code>propertyKey</code>, <code>parameterIndex</code></td>
<td><code>.d.ts</code> 파일, <code>declare</code> 클래스</td>
</tr>
</tbody></table>
<p>다양한 타입의 데코레이터에 대한 호출 순서는 다음과 같이 잘 정의되어 있다.</p>
<ol>
<li>매개 변수, 메서드 데코레이터에 이어서 접근자, 속성 데코레이터가 <strong>각 인스턴스 멤버에 적용</strong>된다.<ul>
<li>평가 순서는 메서드/접근자/속성 &gt; 매개변수</li>
</ul>
</li>
<li>매개 변수 데코레이터에 이어서 메서드, 접근자, 속성 데코레이터가 <strong>각 정적 멤버에 적용</strong>된다.<ul>
<li>평가 순서는 메서드/접근자/속성 &gt; 매개변수</li>
</ul>
</li>
<li>매개 변수 데코레이터가 생성자 &gt; 클래스 데코레이터가 클래스에 적용된다.<ul>
<li>평가 순서는 클래스 &gt; 생성자</li>
</ul>
</li>
</ol>
<p>속성/접근자/메서드 데코레이터의 호출 순서는 코드에서 나타나는 순서에 따라 달라진다.</p>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
<ul>
<li>한용재, &quot;NestJS로 배우는 백엔드 프로그래밍&quot;, 제이펍, 2022</li>
<li><a href="https://typescript-kr.github.io/pages/decorators.html">https://typescript-kr.github.io/pages/decorators.html</a></li>
<li><a href="https://inpa.tistory.com/entry/TS-%F0%9F%93%98-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-%EA%B0%9C%EB%85%90-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%A0%95%EB%A6%AC">타입스크립트 - @데코레이터 개념 &amp; 사용법 정리</a></li>
</ul>
</blockquote>
<ul>
<li><a href="https://itchallenger.tistory.com/765">https://itchallenger.tistory.com/765</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Blockchan A-Z] 소프트 포크와 하드 포크(soft and hard forks)]]></title>
            <link>https://velog.io/@octo__/Blockchan-A-Z-%EC%86%8C%ED%94%84%ED%8A%B8-%ED%8F%AC%ED%81%AC%EC%99%80-%ED%95%98%EB%93%9C-%ED%8F%AC%ED%81%ACsoft-and-hard-forks</link>
            <guid>https://velog.io/@octo__/Blockchan-A-Z-%EC%86%8C%ED%94%84%ED%8A%B8-%ED%8F%AC%ED%81%AC%EC%99%80-%ED%95%98%EB%93%9C-%ED%8F%AC%ED%81%ACsoft-and-hard-forks</guid>
            <pubDate>Tue, 10 Jan 2023 04:54:52 GMT</pubDate>
            <description><![CDATA[<p>MODULE 3 - SMART CONTRACT INTUITION
07. SOFT AND HARD FORKS</p>
<h1 id="하드-포크hard-fork">하드 포크(hard fork)</h1>
<p><strong>하드 포크(hard fork)란 기본적으로 이전에는 허용되지 않았으며 불가능했던 작업을 가능하게 만드는 블록체인 소프트웨어에 대한 업그레이드이다. 즉, 개별적인 버전의 분할이 발생하게 된 것</strong>이다.</p>
<p>이더리움의 경우 2016년 The DAO 공격에 의해 하드포크를 진행하여 이더리움(Ethereum)과 이더리움 클래식(Ethereum Classic)으로 나뉘어졌다.
하드 포크의 또 다른 예로 비트코인은 2017년 트랜잭션 처리를 위해 분리된 증인(Segregated Witness, SegWit)를 도입하느냐 블록 크기를 늘리느냐에 대한 견해 차이로 하드포크되어 비트코인(Bitcoin)과 비트코인 캐시(Bitcoin Cash)로 나뉘어졌다.
또한 비트코인에서 ASIC을 이용한 채굴로 GPU가 불필요해짐에 따라 이에 불만으로 ASIC 채굴을 금지하는 하드포크로 인해 비트코인으로부터 나와 비트코인 골드(Bitcoin Gold)가 나오게 되었다.</p>
<p>이처럼 <strong>기존 블록체인에 호환이 되지 않는 기능을 추가하기 위해서는 체인 분할이 필수적이며 이를 하드 포크(hard fork)</strong>라고 부른다.</p>
<p>이는 분산 시스템에서 자주 발생하는 일인데 참여자들이 본인들의 미래를 직접 결정하고 현상에 만족스럽지 못한 참여자가 있다면 충분한 지지가 있을 때 자체적으로 네트워크를 분할해서 그들만의 블록체인을 시작할 수도 있는 것이다.
이는 막거나 허용하지 않는 중앙 당국이 없기 때문에 원하는 대로 할 수 있는 것이며, 이 시스템의 미학이라고 할 수 있다.</p>
<p>여기서 중요한 것운 우선 하드 포크 자체가 분할을 초래하는 것이 아니다. 특정 사안이 만족스럽지 못한 사람들이 있을 때만 분할이 발생하는 것이다. 만약 비트코인 캐시의 경우, 모든 이가 블록의 크기를 8MB로 늘리는 것에 동의했다면 전체 비트코인 네트워크가 8MB로 바뀌어 이 그대로를 비트코인이라고 불렀을 것이다.
즉, <strong>하드 포크란 소프트웨어를 지칭하는 용어이며, 체인이 아닌 소프트웨어에 대한 작업</strong>이다.</p>
<hr>
<h1 id="소프트-포크soft-fork">소프트 포크(soft fork)</h1>
<p><strong>소프트 포크(soft fork)는 기존 블록체인의 기능을 일부 수정하는 것</strong>을 말한다. 하드포크와 달리 기존 블록체인의 기본 구조는 변경되지 않고 부분적인 기능 개선만 이루어지는 것이다.
즉, 기존 블록체인과 호환되지 않는 하드 포크와 달리 <strong>소프트 포크는 기존 블록체인의 프로토콜을 그대로 따르기 때문에 호환이 가능</strong>하다.</p>
<p>이러한 소프트 포크의 예로는 비트코인의 분리된 증인(Segregated Witness, SegWit)이 있다. 비트코인은 세그윗을 도입하기 위해 포크를 진행하였지만 세그윗은 기존 비트코인의 프로토콜을 따르기 때문에 다른 체인으로 분리되지 않으며, 기존 비트코인과 호환이 가능하다. 즉, 소프트 포크가 일어난 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Node.js] 웹 프레임워크와 Node.js]]></title>
            <link>https://velog.io/@octo__/%EC%9B%B9-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EC%99%80-Node.js</link>
            <guid>https://velog.io/@octo__/%EC%9B%B9-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EC%99%80-Node.js</guid>
            <pubDate>Sun, 08 Jan 2023 12:46:48 GMT</pubDate>
            <description><![CDATA[<h1 id="웹-프레임워크web-framework">웹 프레임워크(Web Framework)</h1>
<p>초기 인터넷은 정적 이미지와 텍스트로만 이루어져 있어 HTML만 있다면 웹페이지를 만드는데 충분했다. 이후 인터넷은 발전하여 많은 일을 처리할 수 있게 되었고, 필요한 애플리케이션 역시 웹과 모바일 앱 양쪽으로 작성되고 있다.
이를 위해 자바스크립트는 화면을 동적으로 구성하기 위한 필수적인 도구로 떠올랐고 웹 기반 애플리케이션을 작성하기 위해 반드시 배워야하는 언어가 되었다.</p>
<p>이전에는 웹 페이지에서 구동되는 애플리케이션은 모두 SSR(<em>server-side rendering</em>) 방식으로 동작했다. 즉, 서버가 요청을 처리하고 HTML과 자바스크립트 응답을 브라우저에 전송하면 브라우저는 서버가 전송한 HTML 코드를 화면에 그려주고 동적으로 구성되는 부분은 함께 전달된 자바스크립트를 파싱하여 화면을 구성하였다.</p>
<p>하지만 시간이 지나면서 웹 기술은 복잡해지며 발전하였고, 웹 앱을 만드는데 필요한 기술들을 기존의 방식으로 개발하기에는 시간과 노력이 많이 들었다. 이에 따라<strong>웹 개발에 필요한 요소들을 묶어 개발자들이 쉽게 사용할 수 있도록 하고자하는 시도가 생겨났으며, 이러한 결과물들을 웹 프레임워크(<em>web framework</em>)</strong>라고 한다.</p>
<p>이러한 웹 프레임워크들은 다양하게 존재하기 때문에 선택에 어려움이 존재한다. 이 때 다음 사항들을 고려하면 좋다.</p>
<ul>
<li><strong>개발 문서</strong><ul>
<li>쉽게 이해할 수 있게 잘 쓰인 개발 문서는 생산성을 올려준다.</li>
</ul>
</li>
<li><strong>사용자 수</strong><ul>
<li>사용자 수가 많다는 것은 안정적으로 운용되고 있다는 것에 증거이다.</li>
<li>궁금한 점을 커뮤니티를 통해 쉽게 찾을 수 있다.</li>
</ul>
</li>
<li><strong>활성 커뮤니티</strong></li>
<li><strong>깃허브 스타 수와 이슈 대응</strong></li>
</ul>
<hr>
<h1 id="nodejs">Node.js</h1>
<p>Node.js는 2009년에 릴리스되었다. 그 전까지 자바스크립트는 프런트엔드에서만 사용하는 언어라는 인식이 강했고 실제로도 그랬다.
웹 시장이 커지자 동적 페이지를 다루기 위해 HTML 내 <code>&lt;script&gt;</code> 태그로 삽입하여 주로 사용하였다. 그러나 브라우저에 삽입된 소스 코드가 그대로 노출되므로 보안에 취약하다는 인식이 있었고, 사용은 많이 하지만 &#39;어디까지나 스크립트 언어&#39;라는 괄시를 받기도 하였다.</p>
<p>이후 <strong>Node.js의 등장으로 자바스크립트를 이용해 서버를 구동할 수 있게 되었으며,</strong> 자바스크립트는 하나의 언어로 인정받게 되었다. 또 2008년 구글은 크롬 브라우저를 출시하면서 자체 개발한 자바스크립트 엔진인 V8을 크롬에 내장했고, 이 V8 엔진의 뛰어난 성능을 &#39;자바스크립트는 느리다&#39;라는 인식을 바꾸었다.</p>
<p>Node.js는 <em>npm</em>이라는 패키지 관리 시스템을 가지고 있어 누구나 자신이 만든 Node.js 기반 라이브러리를 등록해 다른 사람들이 사용할 수 있도록 공개할 수 있다. <em>npm</em>에 따르면 2022년 3월 기준 등록된 패키지 수가 약 190만개에 다다른다.이런 많은 패키지로 인해 많은 커뮤니티가 생성되고 자바스크립트와 Node.js의 입지는 증가하였다. 
이러한 영향으로 인해 <em>npm</em>에 공개되어 있는 대부분의 소스 코드가 깃허브에 공개되어 있는데 깃허브는 2020년 3월에 <em>npm</em>을 인수하였다. 깃허브는 마이크로소프트가 인수하였으므로 사실상 <em>npm</em>은 마이크로소프트가 주도하게 되었다.</p>
<p>이러한 Node.js의 특징은 다음과 같다.</p>
<h2 id="단일-스레드에서-구동되는-논블로킹-io-이벤트-기반-비동기-방식">단일 스레드에서 구동되는 논블로킹 I/O 이벤트 기반 비동기 방식</h2>
<p>여러 작업 요청이 한번에 많이 들어올 때, 각 작업을 처리하기 위한 스레드를 만들고 할당하는 방식을 멀티스레딩(<em>multi-threading</em>)이라고 한다. 멀티스레딩 방식은 여러 작업을 동시에 처리하기 때문에 처리 속도가 빠르기만, 공유 자원을 관리해야하고 잘 못하면 교착 상태(<em>dead lock, 데드락</em>)이 발생할 수 있다. 또한 스레드가 늘어날 때마다 메모리를 소모하기 때문에 메모리 관리 또한 중요하다.</p>
<p>이에 비해 <strong>Node.js는 단일 스레드에서 작업을 처리한다. 사실 애플리케이션 단에서는 단일 스레드이지만 백그라운드에서는 스레드 풀을 구성해 작업을 처리</strong>한다.
Node.js는 개발자 대신 Node.js에 포함된 비동기 I/O 라이브러리인 <em>libuv</em>에서 스레드 풀을 관리하기 때문에 개발자는 단일 스레드에서 동작하는 것처럼 쉬운 코드를 작성할 수 있다. <strong>웹 서버를 운용할 때는 CPU 코어를 분산해 관리하기 때문에 실제 작업은 여러 개의 코어에서 별개로 처리</strong>된다.</p>
<blockquote>
<p><strong>libuv</strong>
Node.js에서 사용하는 비동기 I/O 라이브러리이다.
커널을 사용해 처리할 수 있는 비동기 작업을 발견하면 바로 커널로 넘기고, 이후 해당 작업들이 종료되어 커널로부터 시스템 콜을 받으면 이벤트 루프에 콜백을 등록한다.
커널이 지원하지 않는 작업일 경우 별도의 스레드에서 작업을 처리한다.</p>
</blockquote>
<p>Node.js는 이렇게 들어온 작업을 <strong>앞의 작업이 끝날 때까지 기다리지 않고(<em>논블로킹(non-blocking) 방식</em>) 비동기로 처리</strong>한다.
즉, <strong>입력은 하나의 스레드에서 받지만 순서대로 처리하지 않고 먼저 처리된 결과를 이벤트로 반환해주는 방식이 바로 Node.js가 사용하는 단일 스레드 논블로킹 이벤트 기반 비동기 방식</strong>이다.</p>
<h2 id="nodejs의-장단점">Node.js의 장단점</h2>
<p>이러한 단일 스레드 논블로킹 이벤트 기반 비동기 방식은 <strong>서버의 자원에 크게 부하를 가하지 않는다.</strong> 이는 대규모 네트워크 애플리케이션을 개발하기에 적합하지만 스레드를 하나만 사용하기 때문에 <strong>하나의 스레드에 문제가 생기면 애플리케이션 전체가 오류를 일으킬 위험</strong>이 있다.</p>
<p><strong>하나의 스레드로 동작하는 것처럼 코드를 작성할 수 있다는 것은 개발자에게 큰 장점</strong>이다. 멀티 스레드를 직적 만들고 관리하며, 데드락을 생각할 필요가 없기 때문이다.</p>
<p><strong>Node.js의 단점은 컴파일러 언어의 처리 속도에 비해 성능이 떨어진다는 점</strong>이다. 하지만 서버의 성능과 자바스크립트 엔진의 성능도 계속 늘어나고 있거 웬만한 웹 애플리케이션을 만들기에 충분하다.
다만 <strong>이벤트 기반 비동기 방식으로 복잡한 기능을 구현하다 보면 여러 이벤트를 동시에 처리하는 경우 &#39;콜백 지옥&#39;에 빠져 가독성이 떨어지는 코드가 만들어 질 수 있다.</strong></p>
<p>하지만 ECMAScript 2016(ES6)에서 프로미스(<code>Promis</code>)가 도입되면서 간결한 표현으로 작성할 수 있게 되었고, ECMAScript 2017(ES7)에서는 <code>async/await</code>가 추가되면서 비동기 코드를 마치 동기적으로 처리하는 것처럼 코드를 작성할 수 있게 되었다.</p>
<h2 id="이벤트-루프event-loop">이벤트 루프(Event Loop)</h2>
<p><strong>이벤트 루프(<em>event loop</em>)는 시스템 커널에서 가능한 작업이 있다면 그 작업을 커널에 이관하는 역할</strong>을 한다. 자바스크립트가 단일 스레드 기반이지만 Node.js가 논블로킹 I/O 작업을 수행할 수 있도록 해주는 핵심 기능이다.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/f0b07334-8727-4fcb-930e-e85ecf35c3f7/image.png" alt=""></p>
<p>이벤트 루프에는 6 단계로 이루어져 있다. 아래 그림은 위 그림의 이벤트 루프 동작 방식을 좀 더 단순화한 것이다. <strong>각 단계는 처리해야 하는 콜백 함수를 담기 위한 큐(<em>queue</em>)를 가지고 있으며</strong>, 화살표는 각 단계가 전이되는 방향을 뜻한다. 꼭 반드시 다음 단계로 넘어가는 것은 아니다.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/5b56c4c6-7fb3-4bbb-adc8-5525e1de2589/image.png" alt=""></p>
<p>각 단계에는 해당 단계에서 실행되는 작업을 저장하는 큐(<em>queue</em>)가 있다. 또한 이벤트 루프의 구성 요소는 아니지만 <em>nextTickQueue</em>와 <em>microTaskQueue</em>가 존재한다. <em>nextTickQueue</em>와 <em>microTaskQueue</em>에 들어 있는 작업은 이벤트 루프가 어느 단계에 있든지 실행될 수 있다.</p>
<p>자바스크립트 코드는 유휴, 준비(<em>idle, prepare</em>) 단계를 제외한 어느 단계에서나 실행될 수 있다. 
<code>node main.js</code> 명령어로 Node.js 애플리케이션을 콘솔에서 실행하면 Node.js는 먼저 이벤트 루프를 생성한 다음 메인 모듈인 <code>main.js</code>를 실행한다. 이 과정에서 생성된 콜백들이 각 단계에 존재하는 큐에 들어가게 되는데, 메인 모듈의 실행을 완료한 다음 이벤트 루프를 계속 실행할 지 결정한다. 큐가 모두 비어 더 이상 수행할 작업이 없다면 Node.js는 루프를 빠져나가고 프로세스를 종료한다.</p>
<p>각 단계를 차례대로 살펴보자.</p>
<h3 id="타이머timer-단계">타이머(Timer) 단계</h3>
<p>이벤트 루프는 타이머 단계(<em>timer phase</em>)에서 시작한다.
<strong>타이머 단계의 큐에는 <code>setTimeout</code>이나 <code>setInterval</code>과 같은 함수를 통해 만들어진 타이머들을 큐에 넣고 실행</strong>한다. <code>now - registeredTime &gt;= delta</code>인 타이머들이 큐에 들어간다. 여기서 <code>delta</code>는 <code>setTimeout(() =&gt; {}, delta)</code>와 같이 타이머가 등록된 시각에서 얼마나 시간이 흐른 후 동작해야 하는지를 나타내는 값으로 대상 타이머들은 이미 실행할 시간이 지났다는 뜻이다.
<strong>타이머들을 최소 힙(<em>min heap</em>)으로 관리되며, 힙을 구성할 때 기준으로 실행할 시각이 가장 적게 남은 타이머가 힙의 루트</strong>가 된다. 이 단계에서는 최소 힙에 들어 있는 타이머들을 순차적으로 찾아 실행 후 힙을 재구성한다.</p>
<blockquote>
<p><strong>최소 힙(min heap)</strong>
최솟값을 찾기 위해 완전 이진 트리를 사용하는 자료구조</p>
</blockquote>
<p>실행할 시간이 지난 타이머들의 콜백이 무한정 실행되는 것은 아니고 시스템의 실행 한도(<em>hardl limit</em>)에 도달하면 다음 단계로 넘어간다.</p>
<h3 id="대기-콜백pending-io-callbacks-단계">대기 콜백(Pending I/O callbacks) 단계</h3>
<p><strong>대기 단계(<em>pending i/o callbacks phase</em>)의 큐(<em>pending_queue</em>)에 들어 있는 콜백들은 현재 돌고 있는 루프 이전의 작업에서 큐에 들어온 콜백</strong>이다.
예를 들어 TCP 핸들러 내에서 비동기의 쓰기 작업을 한다면, TCP 통신과 쓰기 작업이 끝난 후 해당 작업의 콜백이 큐에 들어오며, 에러 핸들러 콜백도 <em>pending_queue</em>에 들어 온다.</p>
<p><strong>타이머 단계를 거처 대기 콜백 단계에 들어오면, 이전 작업들의 콜백이 <em>pending_queue</em>에서 대기 중인지를 검사한다. 만약 실행 대기 중이라면 시스템 실행 한도에 도달할 때까지 꺼내 실행</strong>한다.</p>
<h3 id="유휴-준비idle-prepare-단계">유휴, 준비(Idle, prepare) 단계</h3>
<p><strong>유휴 단계(<em>idle phase</em>)는 틱(<em>tick</em>)마다 실행되며, 준비 단계(<em>prepare phase</em>)는 매 폴링 직전에 실행</strong>된다.
이 두 단계는 Node.js의 내부 동작을 위한 것이다.</p>
<blockquote>
<p><strong>틱(tick)</strong>
프로그램 실행 시 최소 간격을 말하며 &#39;틱 카운트&#39;라고도 한다.
이벤트 루프에서는 각 단계가 이동하는 것을 뜻한다.</p>
</blockquote>
<h3 id="폴poll-단계">폴(Poll) 단계</h3>
<p><strong>폴 단계(<em>poll phase</em>)는 이벤트 루프 중 가장 중요한 단계로 새로운 I/O 이벤트를 가져와 관련 콜백을 수행</strong>한다.
예를 들어 소켓 연결과 같은 새로운 커넥션을 맺거나 파일 읽기와 같이 데이터 처리를 받아들인다.</p>
<p>이 단계가 가지고 있는 큐는 <em>watch_queue<em>이다. 이 단계에 진입한 후 *watch_queue</em>가 비어 있지 않다면, 큐가 비거나 시스템 실행 한도에 다다를 때까지 동기적으로 모든 콜백을 실행한다.
만약 큐가 비게 되면 Node.js는 바로 다음 단계로 이동하지 않고 *check_queue(체크 단계의 큐)</em>, <em>pending_queue(대기 콜백 단계의 큐)</em>, <em>closing_queue(종료 콜백 단계의 큐)</em>에 남은 작업이 있는지 검사한 후 작업이 있다면 다음 단계로 이동한다.
만약 큐가 모두 비어 해야할 작업이 없다면, 잠시 대기를 한다(타이머 최소 힙의 첫 번째 타이머를 꺼내 지금 실행할 수 있는 상태라면 그 시간만큼 대기 후 다음 단계로 이동한다.).
이렇게 하는 이유는 타이머 단계로 넘어가도 어짜피 첫 번째 타이머를 수행할 시간이 되지 않았기 때문에 이벤트 루프를 한 번 더 돌아야 하기 때문이다.</p>
<h3 id="체크check-단계">체크(Check) 단계</h3>
<p><strong>체크 단계(<em>check phase</em>)는 <code>setImmediate</code>의 콜백 만을 위한 단계</strong>이다. 큐가 비거나 시스템 실행 한도에 도달할 때까지 콜백을 수행한다.</p>
<h3 id="종료-콜백close-callbacks-단계">종료 콜백(Close callbacks) 단계</h3>
<p><strong>종료 콜백 단계(<em>close callbacks phase</em>)에서는 <code>socket.on(&#39;close&#39;, () =&gt; {})</code>과 같은 <code>close</code>나 <code>destory</code> 이벤트 타입의 콜백이 처리</strong>된다. 이벤트 루프는 종료 콜백 단계를 마치고 나면 다음 루프에서 처리해야 하는 작업이 남아 있는지 검사한다. 만약 작업이 남아 있다면 타이머 단계부터 한 번 더 루프를 돌고, 아니라면 루프를 종료한다.</p>
<h3 id="nexttickqueue-microtaskqueue">nextTickQueue, microTaskQueue</h3>
<p>한편 <em>nextTickQueue<em>는 <code>process.nextTick()</code> API의 콜백들을 가지고 있으며, *microTaskQueue</em>는 <code>resolve</code>된 <code>Promise</code>의 콜백을 가지고 있다. 즉, *libuv</em> 라이브러리에 포함된 것이 아닌 Node.js에 포함된 기술이다.
이 두 큐에 들어 있는 콜백은 단계를 넘어가는 과정에서 먼저 실행되며, <em>nextTickQueue</em>는 <em>microTaskQueue</em>보다 높은 우선순위를 가지고 있다.</p>
<h2 id="패키지-의존성-관리">패키지 의존성 관리</h2>
<h3 id="packagejson">package.json</h3>
<p>Node.js 관련 프로젝트를 생성하게 되면 <code>package.json</code> 파일이 존재하게 된다. 생성된 <code>package.json</code> 파일의 역할은 다음과 같다.</p>
<ul>
<li>애플리케이션이 필요 하는 패키지 목록 나열</li>
<li>각 패키지는 시멘틱 버저닝(<em>semantic versioning</em>) 규칙으로 필요한 버전을 기술한다.</li>
<li>다른 개발자와 같은 빌드 환경을 구성할 수 있어 버전이 달라 발생하는 문제를 예방할 수 있다.</li>
</ul>
<p>유의적 버전(<em>semantic versioning</em>)은 패키지의 버전명을 숫자로 관리하는 방법으로 많이 사용되고 있으며 규칙은 다음과 같다.</p>
<pre><code>[Major].[Minor].[Patch]-[label]</code></pre><p><code>Major</code>, <code>Minor</code>, <code>Patch</code>는 각각 숫자를 사용한다. 규칙에 따라 <code>1.2.3-beta</code>와 같이 사용한다.</p>
<ul>
<li><code>Major</code><ul>
<li>이전 버전과 호환이 불가능할 때 숫자를 하나 증가시킨다.</li>
<li><code>Major</code> 버전이 바뀐 패키지를 사용하려면 반드시 <em>breaking change(하위 호환성이 깨진 기능)</em> 목록을 확인하고 이전 기능을 사용하는 코드를 수정해야 한다.</li>
</ul>
</li>
<li><code>Minor</code><ul>
<li>기능이 추가되는 경우 숫자를 증가시킨다.</li>
<li>숫자가 증가되어도 이전 버전과 호환이 가능하다.</li>
</ul>
</li>
<li><code>Patch</code><ul>
<li>버그 수정 패치를 적용할 때 사용한다.</li>
</ul>
</li>
<li><code>label</code><ul>
<li>선택 사항으로 <code>pre</code>, <code>alpha</code>, <code>beta</code>와 같이 버전에 대해 부가 설명을 붙이고자 할 때 문자열로 작성한다.</li>
</ul>
</li>
</ul>
<p>유의적 버전을 사용할 때 완전히 동일한 버전만을 정의해야하는 것은 아니다. 다음과 같은 규칙을 사용해 의존성을 해치지 않는 다른 버전을 설치할 수 있다.</p>
<ul>
<li><code>ver</code>: 완전히 일치하는 버전</li>
<li><code>=ver</code>: 완전히 일치하는 버전</li>
<li><code>&gt;ver</code>: 큰 버전</li>
<li><code>&gt;=ver</code>: 크거나 같은 버전</li>
<li><code>&lt;ver</code>: 작은 버전</li>
<li><code>&lt;=ver</code>: 작거나 같은 버전</li>
<li><code>~ver</code>: 버전 범위(지정한 마지막 자리 내 범위)<ul>
<li>~1.0, 1.0.x: 1.0.0 이상 1.1.0 미만의 버전</li>
</ul>
</li>
<li><code>^ver</code>: SemVer 규약을 따른다는 가정에서 동작하는 규칙<ul>
<li>^1.0.2: 1.0.2 이상 2.0 미만의 버전</li>
<li>^1.0: 1.0.0 이상 2.0 미만의 버전</li>
<li>^1: 1.0.0 이상 2.0 미만의 버전</li>
</ul>
</li>
</ul>
<h3 id="package-lockjson">package-lock.json</h3>
<p>프로젝트 루트 디렉토리에서 <code>npm install</code> 명령을 수행하면 <code>node_modules</code> 디렉토리와 <code>package-lock.json</code> 파일이 생성된다. <code>node_modules</code>는 프로젝트가 필요한 패키지들이 실제로 설치되는 장소이다. 애플리케이션은 런타임에 여기에 설치된 패키지들을 참조한다. <strong><code>package-lock.json</code> 파일은 <code>package.json</code>에 선언된 패키지들이 설치될 때의 정확한 버전과 서로 간의 의존성을 표현</strong>한다.</p>
<p><code>package-lock.json</code> 파일은 <code>node_modules</code>나 <code>package.json</code> 파일의 내용이 바뀌면 <code>npm install</code> 명령을 수행할 때 자동 수정된다. 만약 소스 코드 내에 <code>package-log.json</code> 파일이 이미 존재한다면 <code>npm install</code> 명령을 수행할 때 이 파일을 기준으로 패키지들을 설치하게 된다. 
따라서 이를 이용해 팀원들 간의 정확한 개발 환경을 공유할 수 있기 때문에 소스 코드 저장소에서 관리해야 한다.</p>
<h3 id="packagejson-파일-분석">package.json 파일 분석</h3>
<p>NestJS로 생성된 프로젝트의 <code>package.json</code> 파일을 바탕으로 <code>package.json</code>에 기술된 내용을 살펴볼 것이다.</p>
<pre><code class="language-json">{
  &quot;name&quot;: &quot;test&quot;,            // 1
  &quot;version&quot;: &quot;0.0.1&quot;,        // 2
  &quot;description&quot;: &quot;&quot;,        // 3
  &quot;author&quot;: &quot;&quot;,                
  &quot;private&quot;: true,            // 4
  &quot;license&quot;: &quot;UNLICENSED&quot;,    // 5
  &quot;scripts&quot;: {                // 6
    &quot;prebuild&quot;: &quot;rimraf dist&quot;,
    &quot;build&quot;: &quot;nest build&quot;,
    &quot;format&quot;: &quot;prettier --write \&quot;src/**/*.ts\&quot; \&quot;test/**/*.ts\&quot;&quot;,
    &quot;start&quot;: &quot;nest start&quot;,
    &quot;start:dev&quot;: &quot;nest start --watch&quot;,
    &quot;start:debug&quot;: &quot;nest start --debug --watch&quot;,
    &quot;start:prod&quot;: &quot;node dist/main&quot;,
    &quot;lint&quot;: &quot;eslint \&quot;{src,apps,libs,test}/**/*.ts\&quot; --fix&quot;,
    &quot;test&quot;: &quot;jest&quot;,
    &quot;test:watch&quot;: &quot;jest --watch&quot;,
    &quot;test:cov&quot;: &quot;jest --coverage&quot;,
    &quot;test:debug&quot;: &quot;node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand&quot;,
    &quot;test:e2e&quot;: &quot;jest --config ./test/jest-e2e.json&quot;
  },
  &quot;dependencies&quot;: {            // 7
    &quot;@nestjs/common&quot;: &quot;^9.0.0&quot;,
    &quot;@nestjs/core&quot;: &quot;^9.0.0&quot;,
    &quot;@nestjs/platform-express&quot;: &quot;^9.0.0&quot;,
    &quot;reflect-metadata&quot;: &quot;^0.1.13&quot;,
    &quot;rimraf&quot;: &quot;^3.0.2&quot;,
    &quot;rxjs&quot;: &quot;^7.2.0&quot;
  },
  &quot;devDependencies&quot;: {        // 8
    &quot;@nestjs/cli&quot;: &quot;^9.0.0&quot;,
    &quot;@nestjs/schematics&quot;: &quot;^9.0.0&quot;,
    &quot;@nestjs/testing&quot;: &quot;^9.0.0&quot;,
    &quot;@types/express&quot;: &quot;^4.17.13&quot;,
    &quot;@types/jest&quot;: &quot;28.1.8&quot;,
    &quot;@types/node&quot;: &quot;^16.0.0&quot;,
    &quot;@types/supertest&quot;: &quot;^2.0.11&quot;,
    &quot;@typescript-eslint/eslint-plugin&quot;: &quot;^5.0.0&quot;,
    &quot;@typescript-eslint/parser&quot;: &quot;^5.0.0&quot;,
    &quot;eslint&quot;: &quot;^8.0.1&quot;,
    &quot;eslint-config-prettier&quot;: &quot;^8.3.0&quot;,
    &quot;eslint-plugin-prettier&quot;: &quot;^4.0.0&quot;,
    &quot;jest&quot;: &quot;28.1.3&quot;,
    &quot;prettier&quot;: &quot;^2.3.2&quot;,
    &quot;source-map-support&quot;: &quot;^0.5.20&quot;,
    &quot;supertest&quot;: &quot;^6.1.3&quot;,
    &quot;ts-jest&quot;: &quot;28.0.8&quot;,
    &quot;ts-loader&quot;: &quot;^9.2.3&quot;,
    &quot;ts-node&quot;: &quot;^10.0.0&quot;,
    &quot;tsconfig-paths&quot;: &quot;4.1.0&quot;,
    &quot;typescript&quot;: &quot;^4.7.4&quot;
  },
  &quot;jest&quot;: {                    // 9
    &quot;moduleFileExtensions&quot;: [
      &quot;js&quot;,
      &quot;json&quot;,
      &quot;ts&quot;
    ],
    &quot;rootDir&quot;: &quot;src&quot;,
    &quot;testRegex&quot;: &quot;.*\\.spec\\.ts$&quot;,
    &quot;transform&quot;: {
      &quot;^.+\\.(t|j)s$&quot;: &quot;ts-jest&quot;
    },
    &quot;collectCoverageFrom&quot;: [
      &quot;**/*.(t|j)s&quot;
    ],
    &quot;coverageDirectory&quot;: &quot;../coverage&quot;,
    &quot;testEnvironment&quot;: &quot;node&quot;
  }
}</code></pre>
<ol>
<li><code>name</code>: 패키지 이름이다. <code>version</code>과 함께 고유한 식별자가 된다. 패키지를 <code>npm</code>에 공개하지 않는다면 선택 사항이다.</li>
<li><code>version</code>: 패키지의 버전이다.</li>
<li><code>description</code>: 패키지에 대한 설명이다.</li>
<li><code>private</code>: <code>true</code>로 설정할 경우 공개되지 않는다.</li>
<li><code>license</code>: 패키지의 라이센스이다. 공개된 패키지를 사용할 때 참고해야 한다.</li>
<li><code>scripts</code>: <code>npm run</code> 명령과 함께 수행할 수 있는 스크립트이다. 스크립트를 이용해 다양한 기능을 구현할 수 있다.</li>
<li><code>dependencies</code>: 패키지가 의존하는 다른 패키지들이 표기되어 있다. 프로덕션 환경에서 필요한 주요 패키지를 선언한다.</li>
<li><code>devDependencies</code>: <code>dependencies</code>와 같은 기능을 하지만 개발 환경 또는 테스트 환경에서만 필요한 패키지를 여기서 선언한다. 실 사용 서비스에서는 불필요한 패키지를 설치하지 않도록 해야 한다.</li>
<li><code>jest</code>: 테스팅 라이브러리 <code>Jest</code>를 위한 환경 구성 옵션이다. NestJS는 기본으로 <code>Jest</code>를 이용한 테스트를 제공한다.</li>
</ol>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
<ul>
<li>한용재, &quot;NestJS로 배우는 백엔드 프로그래밍&quot;, 제이펍, 2022</li>
<li><a href="https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/">https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/</a></li>
<li><a href="https://www.voidcanvas.com/nodejs-event-loop">https://www.voidcanvas.com/nodejs-event-loop</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NestJS] NestJS ?]]></title>
            <link>https://velog.io/@octo__/NestJS-NestJS</link>
            <guid>https://velog.io/@octo__/NestJS-NestJS</guid>
            <pubDate>Sat, 07 Jan 2023 15:43:14 GMT</pubDate>
            <description><![CDATA[<p><strong>NestJS 또는 줄여서 Nest는 Node.js의 유연함을 가지면서 프레임워크 내에 유용한 기술을 다수 구현해둔 프레임워크</strong>이다.</p>
<h1 id="nestjs의-장점">NestJS의 장점</h1>
<p><strong>NestJS는 Node.js에 기반을 둔 웹 API 프레임워크로서 Express 또는 Fastify 프레임워크를 래핑(<em>wrapping</em>)하여 동작</strong>한다.</p>
<blockquote>
<p><strong>래핑(<em>Wrapping</em>)</strong>
랩(<em>wrap</em>)으로 감싸듯이 기존의 라이브러리 등을 조금 더 사용이 쉽고 수월하게 한번 더 만드는 것</p>
</blockquote>
<p><strong>기본적으로 NestJS는 Express를 사용</strong>한다.
Fastify는 밴치마크상으로 Express에 비해 약 2배 정도 빠르지만 <strong>Express가 가장 널리 사용되고 있고 Express 기반 미들웨어가 NestJS와 호환되기 때문</strong>이다.</p>
<blockquote>
<p><strong>미들웨어(<em>Middleware</em>)</strong>
서비스 및 기능을 애플리케이션에 제공하는 소프트웨어</p>
</blockquote>
<p>Node.js는 쉽게 사용할 수 있고 확장성이 좋지만, 과도한 유연함으로 인해 결과물인 소프트웨어의 품질이 일정하지 않고 적절한 라이브러리를 찾기 위해 사용자가 많은 시간을 사용해야한다.
이를 보완하기 위해 NestJS는 데이터베이스, 객체 관계 매핑(<em>object-reletional mapping, ORM</em>), 설정(<em>configuration</em>), 유효성 검사 등 많은 기능을 기본 제공하면서도 필요한 라이브럴리르 쉽게 설치하여 확장할 수 있는 Node.js의 장점을 그대로 가지고 있다.</p>
<p>NestJS는 앵귤러(<em>Angular</em>)의 영향을 많이 받았다. <strong>모듈/컴포넌트 기반으로 프로그램을 작성할 수 있어 재사용성을 높이고</strong>, 제어의 역전(<em>inversion of control, IoC</em>), 의존성 주입(<em>dependency injection, DI</em>), 관점 지향 프로그래밍(<em>aspect-oriented programming, AOP</em>) 같은 <strong>객체 지향 개녕을 도입</strong>하였다.
또한 <strong>타입스크립트(<em>typescript</em>)를 기본으로 사용</strong>하여 타입스크립트가 가진 타입 시스템의 장점을 누릴 수 있다.</p>
<p>웹 프레임워크가 갖추어야 할 필수 기능이라면 다음과 같은 것들이 있다.</p>
<ul>
<li>최신 ECMA 스크립트 지원</li>
<li>타입스크립트(선택 사항이지만 사용 추세가 계속 늘어나고 있음)</li>
<li>CQRS(<em>command query responsibility separation</em>)</li>
<li>HTTP 헤더 보안(Express는 helmet을 사용)</li>
<li>편리한 설정</li>
<li>인터셉터(<em>Interceptor</em>)</li>
<li>다양한 미들웨어(<em>middleware</em>)</li>
<li>스케줄링(<em>scheduling</em>)</li>
<li>로깅(<em>logging</em>)</li>
<li>테스팅(<em>testing</em>)</li>
<li>스웨거(<em>Swagger</em>) 문서화</li>
<li>ORM</li>
</ul>
<p>NestJS는 이 중 대부분을 프레임워크에 내장하고 있고, 내장하지 않는 기능들은 쉽게 다른 모듈을 가져다 사용할 수 있다.</p>
<hr>
<h1 id="express-vs-nestjs">Express vs NestJS</h1>
<p>Express는 이미 많은 회사들이 선택하여 운용되고 있는 검증된 프레임워크이다. 그러나 NestJS 또한 Express를 기본으로 선택하고 그 위에 여러 기능을 미리 구현해놓은 것이다.
이 둘을 간단히 비교하면 다음과 같다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>Express</th>
<th>NestJS</th>
</tr>
</thead>
<tbody><tr>
<td>유연함/확장성</td>
<td>Express는 가볍게 테스트용 서버를 띄울 수 있다.<br>아이디어를 빠르게 검증하는 데 좋지만, 단순하고 자유도가 높은 만큼 맞는 라이브러리를 찾기 위해 시간을 들여야 한다.<br>보일러플레이트를 미리 얹어놓은 깃허브 저장소(<em>repository</em>)들이 있어 이를 활용하는 것도 좋은 선택일 것이다.</td>
<td>미들웨어, IoC, CQRS 등 많은 기능을 프레임워크 자체에 포함한다.<br>사용자는 공식 문서를 통해 쉽게 따라할 수 있으며, 원하는 기능이 없다면 다른 라이브러리를 적용하여 사용하는 것도 가능하다.</td>
</tr>
<tr>
<td>타입스트립트 지원</td>
<td>추가 설정을 통해 사용 가능하다.</td>
<td>기본 설정이다.<br>바닐라 자바스크립트로도 작성이 가능하다.</td>
</tr>
<tr>
<td>커뮤니티</td>
<td>가장 크다.</td>
<td>증가하고 있다.</td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/octo__/post/1d8e326c-a05a-47f0-84ee-a732e0c02d49/image.png" alt=""></p>
<p><a href="https://2021.stateofjs.com/en-US/libraries/back-end-frameworks/">State of JS 2021</a>에 따르면 아직 사용 경험은 많지 않다.
Express가 상위에 있는 이유는 다른 프레임워크들이 Express 기반으로 만들어진 이유도 있다.</p>
<p>이어서 설문 조사 결과를 살펴볼 것인데, SvelteKit, Astro, Remix, Next.js, Nuxt, Gatsby는 엄밀히 말해 모두 프런트엔드의 영역에 가깝고 순수 백엔드 프레임워크라고는 할 수 없다. 그러나 프레임워크가 해결하고자 하는 목적에 맞게 도입해서 함께 사용하면 좋은 프레임워크들이다.</p>
<p>이를 이해하고 State of JS 2021를 기반으로 만족도와 인지도 등의 측면에서 살펴보자.</p>
<h2 id="만족도">만족도</h2>
<p><img src="https://velog.velcdn.com/images/octo__/post/ccdd0386-fe45-45c3-840a-09a710748d5a/image.png" alt=""></p>
<p>NestJS 사용자들의 만족도는 여러 프레임워크 중 중간 정도 순위로 85% 정도로 나왔다.</p>
<h2 id="인지도">인지도</h2>
<p><img src="https://velog.velcdn.com/images/octo__/post/d62b95e6-41cb-4a55-bad2-41380ab82671/image.png" alt=""></p>
<p>NestJS의 인지도는 69% 정도로 Express의 97%라는 수치에 비해서는 낮다. 
따라서 인기 있는 Express를 사용하는 것이 좋아보이지만 상용 제품을 만들기까지 시간이 오래 걸릴 수 있다. Express를 사용하면 필요한 라이브러리들을 npm에서 찾고 검토하는 과정이 필요하기 때문이다.</p>
<p>반면에 NestJS는 백엔드 서버가 갖추어야할 많은 필수 기능을 프레임워크 내에 내장하고 있고, 필요한 기능을 추가 설치 및 적용하기 쉽다. 또한 IoC, DI를 채택하여 객체 지향 프로그래밍과 모듈화를 쉽게 할 수 있다.</p>
<h2 id="성능">성능</h2>
<p><a href="https://github.com/nestjs/nest">Nestjs 깃허브</a>에는 PR이 제출될 때마다 Express, Fastify와의 성능 벤치마크 결과가 공개된다.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/660b669f-3bb5-4e5d-acf9-9ed58e9294f8/image.png" alt=""></p>
<p>이는 각 PR의 Checks 탭에서 확인할 수 있으며, 위의 벤치마크 결과는 <a href="https://github.com/nestjs/nest/pull/10811/checks?check_run_id=10481244227">2023년 1월 6일에 merge된 #10811 PR의 결과</a>이다.</p>
<p>NestJS에서는 Express와 Fastify를 적용했을 경우를 각각 구분하고, Express/Fastify 자체 성능도 측정한다. 측정 결과를 보면, Express가 Fastify보다 느리고, NestJS에 각각을 적용하면 약간 더 성능이 떨어지는 것을 알 수 있다.
이는 NestJS가 기본 제동하는 프레임워크의 크기가 크기 때문이다. 그러나 순수 Express/Fastify로 서버를 개발하다 보면 필수로 요구하는 라이브러리들을 추가하기 때문에 결국 NestJS에서 제공하는 기능을 모두 구현하면 성능 차이는 크지 않을 것이다.</p>
<h2 id="지속-가능성">지속 가능성</h2>
<p><a href="https://github.com/expressjs/express">Express 깃허브</a>를 보면 최근 4.18.2 버전을 업데이트했지만 그 전까지는 몇 년간 개발이 정체되어 있었따. 5.0을 준비하고 있기도 하고 매우 안정적인 프레임워크라서 문제없이 운용되고 있다는 증거로도 볼 수 있지만 최신 트렌드를 따라가지 못한다는 우려가 있다.
그러나 NestJS는 꾸준히 발전하고 있으며, 깃허브를 통해 커뮤니케이션도 활발히 하고 있다.</p>
<hr>
<h1 id="nestjs-설치">NestJS 설치</h1>
<h2 id="nodejs-설치">Node.js 설치</h2>
<p>NestJS는 Node.js를 기반으로 한다. 따라서 먼저 Node.js를 먼저 다운로드 해야 한다.
안정적인 버전인 LTS를 선택하여 설치하는 것을 권장하며 <a href="https://nodejs.org/ko/download/">Node.js 공식 사이트</a>를 통해 설치할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/81242b3b-0ea3-4443-ab2c-890cfe882b52/image.png" alt=""></p>
<h2 id="nestjs-설치-및-프로젝트-생성">NestJS 설치 및 프로젝트 생성</h2>
<p>Node.js를 설치하면 기본적으로 Node.js의 패키지 매니저인 <em>npm</em>이 함께 설치된다. <em>npm</em>을 통해 <a href="https://www.npmjs.com/">https://www.npmjs.com/</a>에 등록된 라이브러리 및 프레임워크들을 쉽게 설치, 삭제할 수 있게 해준다.</p>
<p>NestJS를 사용하기 위해서 먼저 <code>@nestjs/cli</code>를 설치해야한다.</p>
<pre><code class="language-shell">$ npm i -g @nestjs/cli</code></pre>
<p><code>i</code> 명령어는 <code>install</code> 명령어의 약어이다. <code>-g</code> 옵션은 컴퓨터의 클로벌 환경에 설치하겠다는 것으로 모든 디렉토리에서 해당 패키지를 실행할 수 있다.
참고로 글로벌 환경에서 패키지가 설치되는 경로는 <code>npm root -g</code> 명령어로 확인할 수 있다.</p>
<p>이제 콘솔에 <code>nest</code>, <code>nest -h</code> 또는 <code>nest --help</code>라고 입력하면 <code>@nest/cli</code>가 제공하는 기능의 목록을 볼 수 있다.</p>
<pre><code class="language-shell">$ nest</code></pre>
<p><img src="https://velog.velcdn.com/images/octo__/post/2aee4603-368f-4c32-9947-8bd935d51663/image.png" alt=""></p>
<p>다양한 기능이 있지만 우리는 NestJS 프로젝트를 생성할 것이기 때문에 아래 명령어를 통해 프로젝트를 생성할 것이다.</p>
<pre><code class="language-shell">$ nest new &lt;project-name&gt;</code></pre>
<p>project-name에 해당하는 부분에 자신이 원하는 프로젝트 명을 기입하여 생성할 수 있다.
설치 도중 패키지 매니저를 어느 것으로 정할 것인지 묻는 화면이 나오면 원하는 것으로 선택하면 된다. 가장 무난한 것으로는 <em>npm</em>이며, <em>yarn</em>과 <em>npnpm 또한 *npm</em>과 함께 많이 쓰이는 자바스크립트 라이브러리 패키지 매니저이다.</p>
<p>설치를 마치면 보일러플레이트(<em>boilerplate</em>) 코드가 생성되어 아래처럼 디렉토리 구조를 구성한다.</p>
<blockquote>
<p><strong>보일러플레이트(<em>boilerplate</em>)</strong> 코드
꼭 필요한 기본 기능을 미리 준비해놓은 코드</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/octo__/post/891d9f01-2a9b-4756-be69-b75e9c063204/image.png" alt=""></p>
<p>아래 명령어를 통해 실행할 수 있다.</p>
<pre><code class="language-shell">$ npm run start:dev</code></pre>
<blockquote>
<p>운영이 아닌 개발 단계에서는 <code>npm run start</code>가 아닌 <code>npm run start:dev</code> 명령어를 이용한 것이 좋다.
<code>package.json</code>를 보면 <code>start:dev</code>키에 해당하는 값은 <code>nest start --watch</code>로 <code>--watch</code> 옵션은 소스 코드 변경을 감지하여 코드를 저장할 때마다 서버를 다시 구동하는 옵션이다.</p>
</blockquote>
<p>포트는 기본적으로 3000번으로 설정되어 있는데, <code>main.ts</code> 파일을 보면 포트 설정 코드를 볼 수 있다.</p>
<pre><code class="language-typescript">import { NestFactory } from &#39;@nestjs/core&#39;;
import { AppModule } from &#39;./app.module&#39;;

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);    // 포트 설정 부분
}
bootstrap();</code></pre>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
<ul>
<li>한용재, &quot;NestJS로 배우는 백엔드 프로그래밍&quot;, 제이펍, 2022</li>
<li><a href="https://2021.stateofjs.com/en-US/libraries/back-end-frameworks/">https://2021.stateofjs.com/en-US/libraries/back-end-frameworks/</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Solidity] NatSpec Format]]></title>
            <link>https://velog.io/@octo__/Solidity-NatSpec-Format</link>
            <guid>https://velog.io/@octo__/Solidity-NatSpec-Format</guid>
            <pubDate>Sun, 25 Dec 2022 05:15:46 GMT</pubDate>
            <description><![CDATA[<h1 id="solidity-comment">Solidity Comment</h1>
<p>solidity 내에서도 주석을 사용할 수 있다.</p>
<p>먼저 <code>//</code> 은 한 줄 주석이다. 주석을 달 부분에 //를 추가하면 쉽게 주석을 달 수 있다.
또한 여러 줄의 주석을 사용하고 싶다면 <code>/*</code>, <code>*/</code>을 사용하면 된다. 두개의 사이에 여러 줄의 주석을 사용하면 된다.</p>
<p>주석을 사용하여 자신이 코드를 작성한 의도를 적는 것이 좋다. 
특히, 함수에서 예상되는 행동값을 자네의 코드에 주석으로 설명한다면, 다른 개발자들(또는 6개월 동안 프로젝트를 멈춘 후 자네 자신!)이 코드 자체를 다 읽어보지 않고 훑어보더라도 큰 맥락에서 그 코드를 이해할 수 있다.</p>
<hr>
<h1 id="natspec-format">NatSpec Format</h1>
<p>Solidity에서는 특수한 형태의 주석을 사용하여 함수, 반환 변수 등에 대한 풍부한 문서를 제공할 수 있다.</p>
<p>이를 위해 NatSpec Format 이라고 한다. 
NatSpec Format은 <code>the Ethereum Natural Language Specification Fromat</code>의 약자로 solidity 커뮤니티에서 표준으로 쓰이는 주석 형식이다.</p>
<p>NatSpec Format으로 만들어진 주석은 컴파일러를 통해 따로 JSON 파일로 추출해 낼 수 있다.
또한 NatSpec Format은 개발자 중심 메세지와 최종 사용자 대상 메세지로 구분되며, 이러한 메세지는 컨트랙트와 상호작용할 때(즉, 트랜잭션에 서명할 때) 최종 사용자에게 표시될 수 있다.</p>
<h2 id="natspec-format-예시">NatSpec Format 예시</h2>
<p>NatSpec Format은 컨트랙트에서 각각 <code>contract</code>, <code>interface</code>, <code>library</code>, <code>function</code>, <code>event</code>, 변수(vaiable)들에서 사용할 수 있다.</p>
<p>한 줄을 위한 NatSpec Format은 <code>///</code>을 사용하고, 여러 줄을 위한 NatSpec Format은 <code>/**</code>, <code>*/</code>을 사용한다.</p>
<p>아래는 NatSpec 예시이다.</p>
<pre><code class="language-solidity">/// @title 기본적인 산수를 위한 컨트랙트
/// @author H4XF13LD MORRIS 💯💯😎💯💯
/// @notice 지금은 곱하기 함수만 추가한다.
contract Math {
  /// @notice 2개의 숫자를 곱한다.
  /// @param x 첫 번쨰 uint.
  /// @param y 두 번째 uint.
  /// @return z (x * y) 곱의 값
  /// @dev 이 함수는 현재 오버플로우를 확인하지 않는다.
  function multiply(uint x, uint y) returns (uint z) {
    // 이것은 일반적인 주석으로, natspec에 포함되지 않는다.
    z = x * y;
  }
}</code></pre>
<h2 id="태그tags">태그(Tags)</h2>
<p>위 예시에도 나타나 있듯이 NatSpec은 태그를 이용해 문서를 설명한다.
모든 태그들은 선택적이며, 만약 태그가 사용되지 않았다면 컴파일러는 해당 줄을 <code>@notice</code>로 태그가 지정된 것으로 간주한다.</p>
<p>아래는 각 NatSpec 태그의 용도와 사용 위치를 설명하는 표이다.</p>
<table>
<thead>
<tr>
<th>Tag</th>
<th>Description</th>
<th>Context</th>
</tr>
</thead>
<tbody><tr>
<td><code>@title</code></td>
<td>컨트랙트, 라이브러리, 인터페이스를 설명하는 제목</td>
<td><code>contract</code>, <code>library</code>, <code>interface</code></td>
</tr>
<tr>
<td><code>@author</code></td>
<td>저자의 이름</td>
<td><code>contract</code>, <code>library</code>, <code>interface</code></td>
</tr>
<tr>
<td><code>@notice</code></td>
<td>이것이 무엇을 하는지 최종 사용자에게 제공되는 설명</td>
<td><code>contract</code>, <code>library</code>, <code>interface</code>, <code>function</code>, <code>public</code> state variable, <code>event</code></td>
</tr>
<tr>
<td><code>@dev</code></td>
<td>개발자에게 제공되는 추가 세부 정보</td>
<td><code>contract</code>, <code>library</code>, <code>interface</code>, <code>function</code>, state variable, <code>event</code></td>
</tr>
<tr>
<td><code>@param</code></td>
<td>함수 또는 이벤트의 매개변수에 대한 설명(<code>@param</code> 뒤에 매개변수 이름과 그에 대한 설명이 와야 한다.)</td>
<td><code>function</code>, <code>event</code></td>
</tr>
<tr>
<td><code>@return</code></td>
<td>반환되는 변수에 대한 설명<br/>여러 개의 값을 반환하는 경우 여러면 <code>@return</code>을 사용하여 표기하면 된다.</td>
<td><code>function</code>, <code>public</code> state variable</td>
</tr>
<tr>
<td><code>@inheritdoc</code></td>
<td>기본 기능에서 누락된 모든 태그들을 복사한다.(<code>@inheritdoc</code> 뒤에 컨트랙트 이름이 와야 함)</td>
<td><code>function</code>, <code>public</code> state variable</td>
</tr>
<tr>
<td><code>@custom:...</code></td>
<td>사용자 정의 태그<br/>뒤에 하나 이상의 소문자 또는 하이픈(<code>-</code>)이 와야 한다. 하지만 하이픈으로 시작할 수 없다.<br/>개발자 문서의 일부이다.</td>
<td>everywhere</td>
</tr>
</tbody></table>
<h2 id="dynamic-expressions">Dynamic expressions</h2>
<p>Solidity 컴파일러는 solidity 코드에서 JSON 출력으로 NatSpec 문서로 전달한다.
출력된 JSON은 최종 사용자에게 직접 제공하거나 일부 전처리를 적용할 수 있다.</p>
<p>예를 들어 어떠한 함수에 다음과 같은 NatSpec이 있다고 하자.</p>
<pre><code class="language-solidity">/// @notice This function will multiply `a` by 7</code></pre>
<p>만약 함수가 호출되고 <code>a</code>에 10이라는 값이 전달 되었다면, 최종 사용자에게는 다음과 같이 표기된다.</p>
<pre><code>This function will multiply 10 by 7</code></pre><p>이러한 동적 표현을 지정하는 것은 <a href="https://github.com/aragon/radspec">radspec 프로젝트</a>에 자세하게 설명되어 있다.</p>
<h2 id="inheritance-notes">Inheritance Notes</h2>
<p>NatSpec을 사용하지 않는 함수들은 자동으로 해당 컨트랙트의 기본 함수의 문서를 자동으로 상속한다.</p>
<p>이에 대한 예외는 다음과 같다.:</p>
<ul>
<li>매개변수 이름이 다른 경우</li>
<li>하나 이상의 기본 기능이 있는 경우</li>
<li>문서 상속의 사용할 컨트랙트를 지정하는 명시적인 태그인 <code>@inheridoc</code> 태그가 존재할 경우</li>
</ul>
<h2 id="documentation-output">Documentation Output</h2>
<pre><code class="language-solidity">// ex1.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity &gt;=0.8.2 &lt; 0.9.0;

/// @title A simulator for trees
/// @author Larry A. Gardner
/// @notice You can use this contract for only the most basic simulation
/// @dev All function calls are currently implemented without side effects
/// @custom:experimental This is an experimental contract.
contract Tree {
    /// @notice Calculate tree age in years, rounded up, for live trees
    /// @dev The Alexandr N. Tetearing algorithm could increase precision
    /// @param rings The number of rings from dendrochronological sample
    /// @return Age in years, rounded up for partial years
    function age(uint256 rings) external virtual pure returns (uint256) {
        return rings + 1;
    }

    /// @notice Returns the amount of leaves the tree has.
    /// @dev Returns only a fixed number.
    function leaves() external virtual pure returns(uint256) {
        return 2;
    }
}</code></pre>
<p>컴파일러에 의해 구문 분석될 때 위와 같은 예제는 두개의 서로 다른 JSON 파일을 생성한다.
하나는 최종 사용자가 기능 실행 시 알림으로 사용하기 위한 것이고, 다른 하나는 개발자가 사용하가 위한 것이다.</p>
<p>다음과 같은 명령어로 생성할 수 있다.</p>
<pre><code class="language-shell">solc --userdoc --devdoc ex1.sol</code></pre>
<blockquote>
<p>Note
solidity 0.6.11 버전 이후로 NatSpec 출력에서는 <code>version</code> 및 <code>kind</code> 필드도 포함된다.
현재 <code>version</code>은 <code>1</code>로 설정되며, <code>kind</code>는 <code>user</code> 또는 <code>dev</code>이어야 한다.
추후 이전 버전을 더 이상 사용하지 않는 새 버전이 도입될 수도 있다.</p>
</blockquote>
<h3 id="사용자-문서-예시">사용자 문서 예시</h3>
<pre><code class="language-json">{
  &quot;version&quot; : 1,
  &quot;kind&quot; : &quot;user&quot;,
  &quot;methods&quot; :
  {
    &quot;age(uint256)&quot; :
    {
      &quot;notice&quot; : &quot;Calculate tree age in years, rounded up, for live trees&quot;
    }
  },
  &quot;notice&quot; : &quot;You can use this contract for only the most basic simulation&quot;
}</code></pre>
<h3 id="개발자-문서-예시">개발자 문서 예시</h3>
<pre><code class="language-json">{
  &quot;version&quot; : 1,
  &quot;kind&quot; : &quot;dev&quot;,
  &quot;author&quot; : &quot;Larry A. Gardner&quot;,
  &quot;details&quot; : &quot;All function calls are currently implemented without side effects&quot;,
  &quot;custom:experimental&quot; : &quot;This is an experimental contract.&quot;,
  &quot;methods&quot; :
  {
    &quot;age(uint256)&quot; :
    {
      &quot;details&quot; : &quot;The Alexandr N. Tetearing algorithm could increase precision&quot;,
      &quot;params&quot; :
      {
        &quot;rings&quot; : &quot;The number of rings from dendrochronological sample&quot;
      },
      &quot;return&quot; : &quot;age in years, rounded up for partial years&quot;
    }
  },
  &quot;title&quot; : &quot;A simulator for trees&quot;
}</code></pre>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
</blockquote>
<ul>
<li><a href="https://docs.soliditylang.org/en/v0.8.17/natspec-format.html">https://docs.soliditylang.org/en/v0.8.17/natspec-format.html</a></li>
<li><a href="https://github.com/aragon/radspec">https://github.com/aragon/radspec</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[C++] 정렬 확인하기 std::is_sorted()]]></title>
            <link>https://velog.io/@octo__/C-%EC%A0%95%EB%A0%AC-%ED%99%95%EC%9D%B8%ED%95%98%EA%B8%B0-stdissorted</link>
            <guid>https://velog.io/@octo__/C-%EC%A0%95%EB%A0%AC-%ED%99%95%EC%9D%B8%ED%95%98%EA%B8%B0-stdissorted</guid>
            <pubDate>Sat, 24 Dec 2022 13:10:20 GMT</pubDate>
            <description><![CDATA[<h1 id="stdis_sort"><code>std::is_sort()</code></h1>
<pre><code class="language-cpp">#include &lt;algorithm&gt;

// default (1)
template &lt;class ForwardIterator&gt;  bool is_sorted (ForwardIterator first, ForwardIterator last);

// custom (2)    
template &lt;class ForwardIterator, class Compare&gt;  bool is_sorted (ForwardIterator first, ForwardIterator last, Compare comp);</code></pre>
<p>범위 내의 요소들이 정렬되어 있는지 확인하는 함수이다.
기본적으로 오름차순(asceding)으로 정렬되어 있는지 확인하며, <code>comp</code>를 통해 정렬 기준을 정하여 정렬되어 있는지 확인할 수 있다.</p>
<p>시간 복잡도는 $O(N)$이다. 여기에서 $N$은 범위의 첫 번째와 마지막 사이의 거리이다.
<code>std::is_sorted()</code>는 범위 내에서 정렬이 맞지 않는 것이 발견될 때까지 요소의 쌍을 비교한다.</p>
<h2 id="parameters">Parameters</h2>
<table>
<thead>
<tr>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><code>first</code></td>
<td>정렬을 확인할 범위의 첫번째 forward iterator<br/>범위에 포함된다.</td>
</tr>
<tr>
<td><code>last</code></td>
<td>정렬을 확인할 범위의 마지막 forward iterator<br/>범위에 포함되지 않는다.</td>
</tr>
<tr>
<td><code>comp</code></td>
<td>인자 두 개를 받는 비교 함수로<code>bool</code> 값을 반환한다.<br/>인수를 수정하지 않으며, 함수 포인터 또는 함수 객체일 수 있다.</td>
</tr>
</tbody></table>
<p><code>comp</code> 함수의 원형을 아래와 같은 형태를 취해야 한다.</p>
<pre><code class="language-cpp">bool cmp(const Type &amp;a, const Type &amp;b);</code></pre>
<h2 id="return-value">Return value</h2>
<ul>
<li>주어진 범위내 정렬되어 있을 경우 <code>true</code><ul>
<li>주어진 범위 내 요소가 1개일 경우 항상 <code>true</code>를 반환한다.</li>
</ul>
</li>
<li>주어진 범위내 정렬되어 있지 않은 경우 <code>false</code></li>
</ul>
<hr>
<h1 id="example">Example</h1>
<h2 id="do-not-use-comp">Do not use <code>comp</code></h2>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;algorithm&gt;

int main()
{
    int A[] = { 10, 11, 15, 12 };

    // Index 0 to 2
    int range1 = 3;

    // Index 0 to 3
    int range2 = 4;

    if (std::is_sorted(A, A + range1)) {
        std::cout &lt;&lt; &quot;Sorted in the range : &quot; &lt;&lt; range1 &lt;&lt; std::endl;
    } else {
        std::cout &lt;&lt; &quot;Not Sorted in the range : &quot; &lt;&lt; range1 &lt;&lt; std::endl;
    }

    if (std::is_sorted(A, A + range2)) {
        std::cout &lt;&lt; &quot;Sorted in the range : &quot; &lt;&lt; range2 &lt;&lt; std::endl;
    } else {
        std::cout &lt;&lt; &quot;Not Sorted in the range : &quot; &lt;&lt; range2 &lt;&lt; std::endl;
    }

    return 0;
}</code></pre>
<h3 id="output">Output</h3>
<pre><code class="language-shell">Sorted in the range : 3
Not Sorted in the range : 4</code></pre>
<h2 id="use-comp">use <code>comp</code></h2>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;algorithm&gt;

using namespace std;

bool ignore_case(char a, char b)
{
    // Converts both characters to lowercase and checks if a &lt;= b
    return (tolower(a) &lt;= tolower(b));
}

// Function that checks if string is sorted while ignoring the case
bool check_if_sorted(string str)
{
    // Function call to is_sorted with binary predicate ignore_case
    return is_sorted(str.begin(), str.end(), ignore_case);
}

int main()
{
    // String which is to be checked
    string str = &quot;tOY&quot;;

    // Function returned true, string is sorted
    if (check_if_sorted(str)) {
        cout &lt;&lt; &quot;Sorted&quot;;
    }
    // Function returned false, string not sorted
    else {
        cout &lt;&lt; &quot;Not sorted&quot;;
    }

    return 0;
}</code></pre>
<h3 id="output-1">Output</h3>
<pre><code class="language-shell">Not sorted</code></pre>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
</blockquote>
<ul>
<li><a href="https://cplusplus.com/reference/algorithm/is_sorted/?kw=is_sorted">https://cplusplus.com/reference/algorithm/is_sorted/?kw=is_sorted</a></li>
<li><a href="https://www.geeksforgeeks.org/stdis_sorted-in-cpp/">https://www.geeksforgeeks.org/stdis_sorted-in-cpp/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Solidity] call function]]></title>
            <link>https://velog.io/@octo__/Solidity-call-function</link>
            <guid>https://velog.io/@octo__/Solidity-call-function</guid>
            <pubDate>Fri, 23 Dec 2022 13:46:21 GMT</pubDate>
            <description><![CDATA[<h1 id="call-function">call function</h1>
<ul>
<li><code>call()</code>은 <code>address</code> 데이터 타입 내에 존재하는 메서드로 <strong>다른 컨트랙트와 상호작용하는 저수준(low lever) 함수</strong>다.</li>
<li><code>call()</code>를 이용해 <strong>송금을 하거나 다른 스마트 컨트랙트의 함수를 호출</strong>할 수 있다.</li>
<li>가변적인 가스(gas)가 발생한다.<ul>
<li><code>send()</code> 와 <code>trasfer()</code>의 경우 2,300 gas를 발생시킨다.</li>
</ul>
</li>
<li>이스탄불 하드포크(2019년 12월) 이후 gas 가격 상승에 따른 다른 스마트 컨트랙트 상호 작용 시 <code>call()</code> 사용을 권장한다.<ul>
<li><code>send()</code> 와 <code>trasfer()</code>이 소비하는 2,300 gas 로는 다른 스마트 컨트랙트을 작동하기에는 부족할 수 있기 때문이다.</li>
</ul>
</li>
<li><a href="https://docs.soliditylang.org/en/v0.8.17/security-considerations.html#re-entrancy">re-entrancy(재진입) 공격</a> 위험이 있기 때문에, <strong>Check Effects Interactions Pattern</strong>을 사용해야 한다.<ul>
<li>또는 <a href="https://docs.openzeppelin.com/contracts/4.x/api/security#ReentrancyGuard">재진입 가드</a>를 사용하여 해결할 수 있다.</li>
</ul>
</li>
<li>유형 검사, 함수 존재 확인 및 인수 패킹을 우회하기 때문에 <a href="https://solidity-by-example.org/call/">fallback 함수 호출을 통해서 이더를 보낼경우에 추천하지만, 존재하는 함수를 호출하는 방법으로는 추천하지 않는다.</a></li>
</ul>
<h1 id="사용-형태">사용 형태</h1>
<p><code>call()</code> 은 다양한 형태로 사용된다.</p>
<h2 id="call-함수를-이용한-non-payable-함수-호출">call 함수를 이용한 non-payable 함수 호출</h2>
<pre><code class="language-solidity">function myFunction(uint _x, address _addr) public returns(uint, uint) {
    // do something
    return (a, b);
}

// function signature string should not have any spaces
(bool success, bytes memory result) = addr.call(abi.encodeWithSignature(&quot;myFunction(uint,address)&quot;, 10, msg.sender));</code></pre>
<p>다른 컨트랙트의 함수를 호출할 때 사용되는 형태이다.
반환값은 함수 호출의 성공, 실패를 반환하는 <code>bool</code>과 호출한 함수의 반환값을 담는 <code>bytes</code>이며, <code>abi.decode()</code>로 변환하여 사용 가능하다.</p>
<pre><code class="language-solidity">(bool success, ) = addr.call(abi.encodeWithSignature(&quot;myFunction(uint,address)&quot;, 10, msg.sender));</code></pre>
<p>호출한 함수의 반환값이 존재하지 않는다면 위와 같이 <code>bytes</code>를 생략해도 된다.</p>
<pre><code class="language-solidity">(bool success, bytes memory result) = addr.call(&quot;&quot;);</code></pre>
<p><code>call</code>에 전달된 함수가 존재하지 않으면 해당 스마트 컨트랙트의 fallback 함수가 호출된다.
만약, fallback 함수가 구현되지 않았다면, <code>call()</code>는 false를 반환한다.</p>
<pre><code class="language-solidity">(bool success, bytes memory result) = addr.call{gas: 1000000}(abi.encodeWithSignature(&quot;myFunction(uint,address)&quot;, 10, msg.sender));</code></pre>
<p>위와 같이 호출할 함수에서 사용될 가스비를 지정해 줄 수도 있지만, 가스비를 하드코딩하는 것은 권장되지 않는다.
만약 사용할 가스비를 지정하지 않는다면, <code>call()</code> 함수전에 남아 있는 모든 가스가 호출할 함수로 공급된다.</p>
<h2 id="call-함수를-이용한-payable-함수-호출">call 함수를 이용한 payable 함수 호출</h2>
<pre><code class="language-solidity">function myFunction(uint _x, address _addr) public payable returns(uint, uint) {
    // do something
    return (a, b);
}

(bool success, bytes memory result) = addr.call{value: msg.value}(abi.encodeWithSignature(&quot;myFunction(uint,address)&quot;, 10, msg.sender));</code></pre>
<p><code>value</code>를 통해 이더를 호출할 수 있다.</p>
<pre><code class="language-solidity">(bool success, bytes memory result) = addr.call{value: msg.sender}(&quot;&quot;);</code></pre>
<p><code>call</code>에 전달된 함수가 존재하지 않으면 해당 스마트 컨트랙트의 receive 함수가 호출된다.
만약, receive 함수가 구현되지 않았다면 fallback 함수가 호출되고, fallback 함수가 구현되지 않았다면 <code>call()</code>는 false를 반환한다.</p>
<pre><code class="language-solidity">(bool success, bytes memory result) = addr.call{value: msg.value, gas: 1000000}(abi.encodeWithSignature(&quot;myFunction(uint,address)&quot;, 10, msg.sender));</code></pre>
<p>마찬가지로 권장되지 않지만 가스비를 하드코딩하는 것도 가능하다.</p>
<h1 id="예제">예제</h1>
<p>아래 컨트랙트를 <code>call()</code>을 이용해 호출하는 예제들이다.</p>
<pre><code>contract callee {
    event JustFallback(string _str);
    event JustReceive(string _str);

    function addNumber(uint256 _num1, uint256 _num2) public pure returns (uint256) {
        return _num1 + _num2;
    }

    fallback() external {
        emit JustFallback(&quot;JustFallback is called&quot;);
    }

    received() external {
        emit JustReceive(&quot;JustReceive is called&quot;);
    }
}</code></pre><h2 id="call-이용한-송금">call() 이용한 송금</h2>
<pre><code class="language-solidity">contract callSend {
    function transferEther(address payable _to) public payable {
        (bool success, ) = _to.call{value: msg.value}(&quot;&quot;);
        require(sucess, &quot;failed to transfer ether&quot;);
    }
}</code></pre>
<h2 id="call-이용한-외부-컨트랙트-함수-호출">call() 이용한 외부 컨트랙트 함수 호출</h2>
<pre><code class="language-solidity">contract callFunction {
    event calledFunction(bool _success, bytes _data);

    function callMethod(address _contractAddress, uint256 _num1, uint256 _num2) public {
        (bool success, btyes memory data) = _contractAddress.call(
            abi.encodeWithSignature(&quot;addNumber(uint256, uint256)&quot;, _num1, _num2);
        );
        require(success, &quot;failed to call outer function&quot;);
        emit calledFunction(success, data);
    }
}</code></pre>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
</blockquote>
<ul>
<li><a href="https://solidity-by-example.org/call/">https://solidity-by-example.org/call/</a></li>
<li><a href="https://dayone.tistory.com/37?category=918008">https://dayone.tistory.com/37?category=918008</a></li>
<li><a href="https://kushgoyal.com/ethereum-solidity-how-use-call-delegatecall/">https://kushgoyal.com/ethereum-solidity-how-use-call-delegatecall/</a></li>
<li><a href="https://kimsfamily.kr/514">https://kimsfamily.kr/514</a></li>
<li><a href="https://docs.openzeppelin.com/contracts/4.x/api/security#ReentrancyGuard">https://docs.openzeppelin.com/contracts/4.x/api/security#ReentrancyGuard</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Solidity] receive function]]></title>
            <link>https://velog.io/@octo__/Solidity-receive-function</link>
            <guid>https://velog.io/@octo__/Solidity-receive-function</guid>
            <pubDate>Sat, 17 Dec 2022 11:15:38 GMT</pubDate>
            <description><![CDATA[<h1 id="receive-function">receive function</h1>
<p>solidity는 <strong>0.6.0 버전 이후로 fallback 함수가 receive와 fallback으로 나뉘어졌다.</strong> 
0.6.0 버전 이전의 fallback 함수는 이더를 보내거나 받을 때 실행되지만 0.6.0 버전 이후의 fallback 함수는 이더를 보낼 때 실행되고, 이더를 받을 때는 receive 함수가 실행된다.
즉, 하나의 기능을 세분화시켜 두가지로 나누어 놓은 것으로, 여기에서는 0.6.0 버전 이후의 fallback 함수에서 분화된 receive 함수를 소개할 것이다.</p>
<p>컨트렉트의 호출 함수가 확인되지 않을 때, 함수에서 이더를 보낼 때(transfer) 디폴트 함수로 동작하는 fallback 함수와는 다르게 <strong>receive 함수는 오직 이더를 받을 때 디폴트 함수로 실행</strong>된다.</p>
<h1 id="선언-형태">선언 형태</h1>
<p>receive 함수는 다음과 같은 형태로 선언된다.</p>
<pre><code class="language-solidity">receive() external payable {
    // ...
}</code></pre>
<h1 id="특징">특징</h1>
<ul>
<li><code>external</code>과 <code>payable</code> 식별자가 필요하다.</li>
<li><strong>각 컨트렉트는 하나의 receive 함수를 선언할 수 있다.</strong></li>
<li>함수는 파라미터를 가질 수 없다.</li>
<li>virtual 식별자를 사용할 수 있으며, override가 가능하다.</li>
</ul>
<h1 id="예제">예제</h1>
<p>아래 예제로 작성된 컨트랙트 주소(CA)로 사용자 지갑(EOA)에 있는 이더를 전송하면, 컨트렉트는 receive 함수를 호출할 것이다.</p>
<pre><code class="language-solidity">//SPDX-License-Identifier: MIT
pragma solidity 0.8.3;

contract FunctionsExample {

    mapping(address =&gt; uint) public balanceReceived;

    function receiveMoney() public payable {
        assert(balanceReceived[msg.sender] + msg.value &gt;= balanceReceived[msg.sender]);
        balanceReceived[msg.sender] += msg.value;
    }

    function withdrawMoney(address payable _to, uint _amount) public {
        require(_amount &lt;= balanceReceived[msg.sender], &quot;not enough funds.&quot;);
        assert(balanceReceived[msg.sender] &gt;= balanceReceived[msg.sender] - _amount);
        balanceReceived[msg.sender] -= _amount;
        _to.transfer(_amount);
    } 

    receive() external payable {
        receiveMoney();
    }
}</code></pre>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
</blockquote>
<ul>
<li><a href="https://docs.soliditylang.org/en/v0.8.17/contracts.html#receive-ether-function">https://docs.soliditylang.org/en/v0.8.17/contracts.html#receive-ether-function</a></li>
<li><a href="https://log4day.tistory.com/13">https://log4day.tistory.com/13</a></li>
<li><a href="https://dayone.tistory.com/36">https://dayone.tistory.com/36</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Solidity] fallback function]]></title>
            <link>https://velog.io/@octo__/Solidity-fallback-function</link>
            <guid>https://velog.io/@octo__/Solidity-fallback-function</guid>
            <pubDate>Sat, 17 Dec 2022 11:15:03 GMT</pubDate>
            <description><![CDATA[<h1 id="fallback-function">fallback function</h1>
<p>fallback 함수는 무기명 함수 즉, 이름이 없는 함수이며 컨트랙트에서 하나의 디폴트 함수와 같다.
fallback 함수는 직접 호출되지 않으며, 다음과 같은 상황에서 실행된다.</p>
<ul>
<li>호출한 함수가 컨트렉트 내에서 조회되지 않을 경우 <ul>
<li>외부에서 특정 컨트렉트를 호출했을 때, 해당 호출 주소(function identifier)가 확인되지 않으면 디폴트로 fallback 함수가 실행된다.</li>
</ul>
</li>
<li>이더(ETH, ether)를 보낼 때 자동으로 실행</li>
</ul>
<p>다시 말해, <strong>스마트 컨트렉트에 함수로 요청을 보냈는데 실제로 없는 함수를 호출하거나 또는 이더를 보낼 때 fallback 함수가 디폴트로 실행</strong>된다.
fallback 함수는 디폴트 함수와 같기 때문에 <strong>solidity에서 하나의 컨트렉트는 하나의 fallback 함수를 가질 수 있다.</strong></p>
<p>solidity는 <strong>0.6.0 버전 이후로 fallback 함수가 receive와 fallback으로 나뉘어졌다.</strong> 
0.6.0 버전 이전의 fallback 함수는 이더를 보내거나 받을 때 실행되지만 0.6.0 버전 이후의 fallback 함수는 이더를 보낼 때 실행되고, 이더를 받을 때는 receive 함수가 실행된다.
즉, 하나의 기능을 세분화시켜 두가지로 나누어 놓은 것이다. 여기에서는 0.6.0 버전 이후의 fallback 함수를 소개할 것이다.</p>
<h1 id="선언-형태">선언 형태</h1>
<p>fallback 함수는 다음과 같은 형태로 선언된다.</p>
<pre><code class="language-solidity">// 선언 유형 1
fallback () external [payable] {
    // ...
}

// 선언 유형 2
fallback (bytes calldata _input) external [payable] returns (bytes memory _output) {
    // ...
}</code></pre>
<h1 id="특징">특징</h1>
<ul>
<li><code>function</code> 키워드가 없다.</li>
<li><code>external</code> 식별자가 붙는다.</li>
<li>함수 이름이 없다. (<code>fallback</code>으로 고정)</li>
<li>파라미터(parameter)를 받지 않는다. <ul>
<li>2번째 유형에서 <code>byte calldata</code> 형태의 파라미터를 설정하면 컨트랙트에 보내진 모든 데이터(= <code>msg.data</code>)를 반환하게 할 수 있다.</li>
</ul>
</li>
<li>반환값이 없다.<ul>
<li>2번째 유형의 경우 컨트랙트에 보내진 모든 데이터(= <code>msg.data</code>)를 반환하게 할 수 있다.</li>
</ul>
</li>
<li><strong>payable 옵션 적용 시, 이더를 받고 나서도 실행</strong>된다.<ul>
<li>기본은 이더 전송(transfer) 시점에서 실행된다.</li>
</ul>
</li>
<li><strong>payable fallback 함수에서는 2300 gas 제한이 존재</strong>한다.</li>
<li><code>virtual</code> 키워드를 가질 수 있기 때문에 override 할 수 있다. </li>
<li>modifier들을 가질 수 있다.</li>
</ul>
<h1 id="예제">예제</h1>
<p>아래 예제는 <a href="https://docs.soliditylang.org/en/v0.8.17/contracts.html#fallback-function">솔리티디 공식 문서 내에 존재하는 예제</a>이다.</p>
<pre><code class="language-solidity">// SPDX-License-Identifier: GPL-3.0
pragma solidity &gt;=0.6.2 &lt;0.9.0;


contract Test {
    uint x;

    // 해당 코드는 Test 컨트렉트에 보내지는 모든 메세지에 대한 응답 코드로 작성하였다.
    //     -&gt;    fallback 함수는 컨트렉트에서 조회한 함수가 없을 때 호출되기 때문
    // 이 컨트렉트 주소로 보내지는 이더를 전송(transfer) 요청은 예외를 발생시킬 수 있다.
    //    -&gt;    `payable` 옵션이 없기 때문
    fallback() external { x = 1; }
}


contract TestPayable {
    uint x;
    uint y;

    // 이더를 보내는 요청이 아닌 모든 요청에서 fallback이 실행된다. - 컨트렉트 어카운트에서 이더 전송
    // 데이터를 포함한 요청에서 fallback 함수를 실행하게 한다.
    fallback() external payable { x = 1; y = msg.value; }

    // 이더를 보내는 요청에서 아래 함수는 실행된다. - 컨트렉트 어카운트로 이더 받음
    // 데이터가 포함되어 있지 않은 요청에서 함수 실행
    receive() external payable { x = 2; y = msg.value; }
  }


contract Caller {
    function callTest(Test test) public returns (bool) {
        (bool success,) = address(test).call(abi.encodeWithSignature(&quot;nonExistingFunction()&quot;));

        // 조건식 -&gt; test.x == 1
        require(success);

        // address(test)는 fallback 함수에 payable 옵션이 없기 때문에 send 요청을 할 수 없다.
        //    -&gt;    address(test)는 address payable으로 변환 되어야 한다.
        address payable testPayable = payable(address(test));

        // 먄약 누군가 이더를 아래와 같이 보낸다면, 요청을 실패할 것이다. (return = false) 
        return testPayable.send(2 ether);
    }

    function callTestPayable(TestPayable test) public returns (bool) {
        (bool success,) = address(test).call(abi.encodeWithSignature(&quot;nonExistingFunction()&quot;));

        // 조건식 -&gt; test.x == 1 &amp;&amp; test.y == 0
        require(success);

        (success,) = address(test).call{value: 1}(abi.encodeWithSignature(&quot;nonExistingFunction()&quot;));

        // 조건식 -&gt; test.x == 1 &amp;&amp; test.y == 1
        require(success);

        // 누군가 이더를 아래와 같이 이더를 보내면 해당 컨트렉트의 receive 함수가 호출될 것이다.
         //    -&gt;    실제 이더 전송에 필요한 가스는 더 많이 필요할 것이다. 해당 함수가 storage에 접근하기 때문
        (success,) = address(test).call{value: 2 ether}(&quot;&quot;);

        // 조건식 -&gt; test.x == 2 &amp;&amp; test.y == 2
        require(success);

        return true;
    }
}</code></pre>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
</blockquote>
<ul>
<li><a href="https://docs.soliditylang.org/en/v0.8.17/contracts.html#fallback-function">https://docs.soliditylang.org/en/v0.8.17/contracts.html#fallback-function</a></li>
<li><a href="https://log4day.tistory.com/12">https://log4day.tistory.com/12</a></li>
<li><a href="https://dayone.tistory.com/36">https://dayone.tistory.com/36</a></li>
<li><a href="https://kimsfamily.kr/514">https://kimsfamily.kr/514</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Solidity] tx.origin 인증 공격]]></title>
            <link>https://velog.io/@octo__/Solidity-tx.origin-%EC%9D%B8%EC%A6%9D-%EA%B3%B5%EA%B2%A9</link>
            <guid>https://velog.io/@octo__/Solidity-tx.origin-%EC%9D%B8%EC%A6%9D-%EA%B3%B5%EA%B2%A9</guid>
            <pubDate>Sat, 17 Dec 2022 11:14:20 GMT</pubDate>
            <description><![CDATA[<h1 id="txorigin">tx.origin</h1>
<ul>
<li>솔리디티에는 <code>tx.origin</code>이라는 전역 변수가 있다.</li>
<li><code>tx.origin</code>은 <code>call</code>을 호출한 계정의 주소를 저장한다.</li>
</ul>
<h2 id="msgsneder-vs-txorigin">msg.sneder vs tx.origin</h2>
<p><code>msg.sender</code>와 <code>tx.origin</code>의 차이점을 알아보기 위해 아래와 같은 상황이 있다고 하자.</p>
<p><img src="https://velog.velcdn.com/images/octo__/post/19db1b77-84ea-4aa4-8b6e-576c11b397d4/image.png" alt=""></p>
<p>해당 상황은 다음과 같다.</p>
<ol>
<li>일반 이더리움 지갑 주소에 불과한 Externally Owned Address(EOA)을 가진 사용자가 컨트랙트 A를 배포한다.</li>
<li>사용자가 컨트랙트 A의 함수 <code>one()</code>을 호출하면 내부의 함수 <code>two()</code>를 호출하고, 해당 함수는 내부적으로 컨트랙트 B의 함수 <code>three()</code>의 함수를 호출한다.</li>
</ol>
<p>이러한 상황에서 컨트랙트 B에 대해 <code>msg.sender</code>는 컨트랙트 A가 될 것이다.
하지만 <code>tx.origin</code>은 트랜잭션을 시작한 주소가 된다. 즉, 이 경우 사용자(EOA)가 된다.</p>
<p>정리하자면,</p>
<ul>
<li><code>msg.sender</code><ul>
<li>함수의 호출자</li>
<li>스마트 컨트랙트 또는 사용자(EOA)가 될 수 있다.</li>
</ul>
</li>
<li><code>tx.origin</code><ul>
<li>실제 트랜잭션이 시작한 사용자(EOA)</li>
<li>스마트 컨트랙트는 서명된 트랜잭션을 보낼 수 없기 때문에 <code>tx.origin</code>는 컨트랙트가 될 수 없다.</li>
</ul>
</li>
</ul>
<hr>
<h1 id="txorigin-인증-공격">tx.origin 인증 공격</h1>
<p><code>tx.origin</code> 인증 공격은 위와 같이 스마트 컨트랙트에서 <code>tx.origin</code>을 이용해 인증 작업을 하는 상황에서 실행할 수 있는 공격 방법이다.</p>
<p>예를 들어 다음과 같은 스마트 컨트랙트가 존재한다고 하자.</p>
<pre><code class="language-solidity">contract Phishable {
    address public owner;

    constructor (address _owner) {
        owner = _owner;
    }

    // 이더를 모으는 fallback 함수
    fallback () external payable {
        // ...
    }

    function withdrawAll(address _recipient) public payable {
        require(tx.origin == owner);
        _recipiect.transfer(this.balance);
    }
}</code></pre>
<p>해당 컨트랙트는 <code>tx.origin</code>을 통해 인증을 하고 <code>withdrawAll()</code> 함수로 해당 컨트랙트의 이더를 전송하도록 구현되어 있다.
이 경우 공격자는 아래와 같은 컨트랙트를 작성해 공격하여 컨트랙트의 이더를 제한 없이 받을 수 있다.</p>
<pre><code class="language-solidity">interface Phishable {
    // ...
    function withdrawAll(address _recipient) external;
}

contract AttackContract {
    Phishable pishableContract;
    address attacker;

    constructor (Phishable _phisiableContract, address _attacker) {
        phishableContract = Phishable(_phishableContract);
        attacker = _attacker;
    }

    // 공격을 위한 fallback 함수
    fallback () external payable {
        phishableContract.withdrawAll(attacker);
    }
}</code></pre>
<p>위의 공격 컨트랙트는 다음과 같이 실행된다.</p>
<ol>
<li>공격자는 <code>owner</code>에게 <code>AttackContract</code>가 일반 계정인 것 처럼 속여 해당 계정에 이더을 보내도록 유도한다.</li>
<li><code>AttackContract</code>에게 <code>owner</code>가 이더를 보내게 되면, 공격을 위한 fallback 함수가 실행된다.</li>
<li>해당 fallback 함수는 <code>Phishable</code> 컨트랙트의 <code>withdrawAll()</code> 함수를 호출하는데, 인자로 해커의 계정 주소를 넣는다.</li>
<li>해당 트랜잭션의 <code>tx.origin</code>은 <code>owner</code>이다. <ul>
<li><code>owner</code>가 <code>AttackContract</code>에게 이더를 전송해<code>AttackContract</code>의 fallback 함수를 호출했고, 거기서 다시 <code>Phishable</code>의 <code>withdrawAll()</code> 함수를 호출했기 때문이다. </li>
<li>이는 <code>tx.origin</code>은 <code>call</code>을 시작한 계정 정보를 계속 유지하고 있기 때문에 가능하다.</li>
</ul>
</li>
<li>공격은 성공하고 <code>Phishable</code> 컨트랙트에 모아진 이더는 공격자에게 전송된다!</li>
</ol>
<p>이처럼 <code>tx.origin</code>을 사용하는 것은 위험하며, 최대한 사용하지 않는 것이 좋다.
<a href="https://docs.soliditylang.org/en/v0.8.17/security-considerations.html#tx-origin">솔리디티 공식 문서에서도 사용하지 않는 것을 강력 권장</a>하고 있다.</p>
<h2 id="해결법">해결법</h2>
<ul>
<li><code>tx.orgin</code> 대신 <code>msg.sender</code>를 사용하자.</li>
<li>꼭 사용해야하는 상황일 경우 외부 컨트랙트가 현재 컨트랙트를 호출하지 못하게 막기 위해 <code>require(tx.origin == msg.sender)</code>같은 방법을 사용하자.</li>
</ul>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
</blockquote>
<ul>
<li><a href="https://docs.soliditylang.org/en/v0.8.17/security-considerations.html#tx-origin">https://docs.soliditylang.org/en/v0.8.17/security-considerations.html#tx-origin</a></li>
<li><a href="https://blog.finxter.com/tx-origin-phishing-attack-smart-contract-security-series-part-4/">https://blog.finxter.com/tx-origin-phishing-attack-smart-contract-security-series-part-4/</a></li>
<li><a href="https://steemit.com/kr/@etainclub/16-tx-origin">https://steemit.com/kr/@etainclub/16-tx-origin</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Blockchan A-Z] The DAO 공격]]></title>
            <link>https://velog.io/@octo__/Blockchan-A-Z-The-DAO-%EA%B3%B5%EA%B2%A9</link>
            <guid>https://velog.io/@octo__/Blockchan-A-Z-The-DAO-%EA%B3%B5%EA%B2%A9</guid>
            <pubDate>Wed, 14 Dec 2022 15:12:42 GMT</pubDate>
            <description><![CDATA[<p>MODULE 3 - SMART CONTRACT INTUITION
06. THE DAO ATTACK</p>
<h1 id="the-dao">The DAO</h1>
<p><img src="https://velog.velcdn.com/images/octo__/post/3f0e1234-3802-4878-a15a-27fc8541079e/image.png" alt=""></p>
<p><strong>The DAO는 최초의 탈중앙화된 자율조직</strong>으로 2016년 이더리움을 통해 Vitalik과 다른 사람들이 개발하였다.</p>
<p>핵심 프로토콜은 이더리움이었고, 벤처 투자 조합이라는 목적으로 설립되었다.
창립자들은 The DAO를 통해 이더리움 블록체인 상에 구현할 탈중앙화된 애플리케이션(Dapp) 개발을 지원하고, 블록체인을 통해서 본인들의 프로젝트를 탈중앙화하여 구현하려는 조직들을 도우려고 하였다.</p>
<p>The DAO는 탈중화된 자율조직 즉, DAO이기 때문에 국적이 없는 상태였기 때문에 권한에 대한 문제가 제기될 만했지만 그 문제는 차치하고 넘어갔다.</p>
<hr>
<h1 id="the-dao-공격">The DAO 공격</h1>
<p>The DAO가 설립되고 활동하던 도중 The DAO는 토큰 판매를 통해서 크라우드 펀딩을 진행했다.
크라우드 펀딩이 끝난 2016년 5월까지 역사상 가장 성공적인 크라우드 펀딩 캠페인 모금액인 총 1억 5천만 달러가 모였다.</p>
<p>사람들은 블록체인에 무언가를 구현한다는 탈중앙화라는 개념과 새로운 형태의 인터넷 그리고 새로운 형태의 세계로 이동한다는 생각을 그저 믿고 있었다.</p>
<p>탈중앙화된 자율조직(DAO)은 전적으로 사람이 아닌 스마트 컨트랙트을 통해 운영되는데, 안타깝게도 <strong>The DAO의 코드에는 에러가 있었다.</strong> 
즉, 이 자율조직에 스마트 컨트랙트에 오류가 있었던 것이다.</p>
<p>이에 따라 The DAO는 2016년 6월에 해킹 공격을 당해 5천만 달러를 잃었다.
여기서 흥미로운 점은 <strong>공격자가 실질적으로 아무런 불법도 저지르지 않았다는 것이다.</strong>
그들은 단지 코드에서 결함을 발견하고 이를 이용해서 본인들의 계좌로 돈을 빼냈을 뿐이다.</p>
<p>하지만 아무 조치도 취할 수 없었죠
The DAO는 자율조직이기 때문에 자율적으로 정해진 알고리즘과 코드를 따를 뿐이기 때문이다.</p>
<p>그리고 <strong>계약서에도 결함이 있었기 때문에 공격자가 계약의 일부로서 이를 유효한 트랜잭션처럼 실행시킬 수 있었다.</strong>
이때 계약서는 불변이며 블록체인 상에 존재하기 때문에 수정할 수도 없다.</p>
<p>하지만 여기서 좋은 소식은 <strong>The DAO가 코딩된 방식에 따르면 실패 방지 메커니즘이 존재</strong>하기 때문에 이번 경우처럼 공격자가 The DAO의 자회사인 다른 계정으로 돈을 옮겼다가 이들을 완전히 가지고 가는 경우가 발생하더라도 자금을 이동시키는 데에 30일가량이 필요하도록 설정되어 있디.
그 시간에 모두가 머리를 맞대 어떤 결정을 내릴지 숙고할 수 있는 것이다.</p>
<h1 id="dao의-딜레마와-이더리움">DAO의 딜레마와 이더리움</h1>
<h2 id="dao의-딜레마">DAO의 딜레마</h2>
<p>위에 상황과 같은 상황에서 딜레마가 발생한다.
바로 <strong>&#39;코드는 법인가?&#39;라는 딜레마</strong>이다.</p>
<p><strong>커뮤니티의 한편에서는 DAO에서 코드는 법</strong>이기 때문에 이를 아무 말 없이 따를 것이다.</p>
<p>또 <strong>한편에서는</strong> 5천만 달러는 너무 많은 돈이고 이는 사람들의 소유라고 할 것이다. 따라서 이들은 <strong>블록체인에 하드 포크를 적용하고 규칙을 바꾸자고 주창</strong>할 것이다.
즉, 하드 포크를 적용하고 규칙을 바꾸어서 결국에는 계약의 규칙을 바꿀 수 있게 되는 것이며, 기본적으로 계약의 규칙을 파기하고 돈을 회수해서 다시 주인에게 돌려주자는 뜻이다.</p>
<h2 id="이더리움-하드-포크">이더리움 하드 포크</h2>
<p>이런 *<em>딜레마 끝에 하드 포크를 실행한다는 결정</em>이 내려졌으며, Vitalik의 계획 하에 하드 포크로 이루어졌다.</p>
<p>하드 포크라고 해서 항상 분할을 뜻하는 것은 아니지만 이 경우에는 분할이 발생했다.
이는 일부가 이 결정에 만족하지 못했기 때문인데 공격자를 보호하려는 뜻에서가 아니라 이 블록체인 개념의 무결성을 보존하고자 하는 뜻에서 스마트 계약을 존중하는 것이 올바르다고 생각했기 때문이다.</p>
<p>이 <strong>하드 포크 작업에서 이더리움은 이더리움(Ethereum, ETH)과 이더리움 클래식(Ethereum Classic, ETC)으로 분할된다.</strong></p>
<p>하드 포크 된 이더리움에서는 해커의 돈이 다시 The DAO의 손에 돌아가고 사람들에게 잘 분배가 되었으나 이더리움 클래식에서는 해커의 돈이 이더리움 클래식에 남게 되었다.</p>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
</blockquote>
<ul>
<li>&quot;이더 도둑&quot; - Matthew Leising
<a href="https://www.bloomberg.com/features/2017-the-ether-thief/">Matthew Leising, (2017), The Ether Thief</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[C++] 클래스 템플릿(class template)]]></title>
            <link>https://velog.io/@octo__/C-%ED%81%B4%EB%9E%98%EC%8A%A4-%ED%85%9C%ED%94%8C%EB%A6%BFclass-template</link>
            <guid>https://velog.io/@octo__/C-%ED%81%B4%EB%9E%98%EC%8A%A4-%ED%85%9C%ED%94%8C%EB%A6%BFclass-template</guid>
            <pubDate>Wed, 14 Dec 2022 15:10:23 GMT</pubDate>
            <description><![CDATA[<h1 id="클래스-템플릿class-template">클래스 템플릿(class template)</h1>
<p>C++에서 <strong>클래스 템플릿(class template)이란 클래스의 일반화된 선언을 의미</strong>한다.</p>
<p>클래스 템플릿을 사용하면, 타입에 따라 다르게 동작하는 클래스 집합을 만들 수 있다.
즉, 클래스 템플릿에 전달되는 템플릿 인수(template argument)에 따라 별도의 클래스를 만들 수 있게 된다.
템플시 인수는 타입이거나 명시된 타입의 상수값일 수 있다.</p>
<h2 id="클래스-템플릿-문법">클래스 템플릿 문법</h2>
<p>클래스 템플릿은 다음과 같은 문법으로 정의할 수 있다.</p>
<pre><code class="language-cpp">template &lt;typename 타입 이름&gt;
class 클래스 템플릿 이름
{
    // ...
}</code></pre>
<p>C++98에서 추가된 <code>typename</code> 키워드는 이전에 <code>class</code> 키워드를 사용했기 때문에 템플릿 정의 내에서 <code>typename</code> 키워드 대신에 <code>class</code> 키워드를 사용할 수 있다.</p>
<hr>
<h1 id="클래스-템플릿-예제">클래스 템플릿 예제</h1>
<pre><code class="language-cpp">#include &lt;iostream&gt;

tmplate &lt;typename T&gt;
class Data
{
private:
    T data_;
public:
    Data(T dt);
    T get_data();
}

int main()
{
    Data&lt;string&gt; str_data(&quot;클래스 템플릿&quot;);
    Data&lt;int&gt; int_data(12);

    std::cout &lt;&lt; &quot;str_data : &quot; &lt;&lt; str_data.get_data() &lt;&lt; std::endl;
    std::cout &lt;&lt; &quot;int_data : &quot; &lt;&lt; int_data.get_data() &lt;&lt; std::endl;
    return 0;
}

template &lt;typename T&gt;
Data&lt;T&gt;::Data(T dt)
{
    data_ = dt;
}

template &lt;typename T&gt;
T Data&lt;T&gt;::get_data()
{
    return data_;
}</code></pre>
<p><strong>Output</strong></p>
<pre><code class="language-shell">str_data : 클래스 템플릿
int_data : 12</code></pre>
<hr>
<h1 id="클래스-템플릿의-특징">클래스 템플릿의 특징</h1>
<p>클래스 템플릿은 다음과 같은 특징을 가진다.</p>
<ol>
<li>하나 이상의 템플릿 인수를 가지는 클래스 템플릿을 선언할 수 있다.<pre><code class="language-cpp"> // 두 개의 템플릿 인수를 가지는 클래스 템플릿 선언
 template &lt;typename T, int i&gt;
 class X
 { ... }</code></pre>
</li>
<li>클래스 템플릿에 디폴트 템플릿 인수를 명시할 수 있다.<pre><code> // 디폴트 템플릿 인수의 타입을 int형으로 명시
 template &lt;typename T = int, int i&gt;
 class X
 { ... }</code></pre></li>
<li>클래스 템플릿을 기초 클래스로 하여 상속할 수 있다.<pre><code> // 클래스 템플릿 X를 상속받음
 template &lt;typename T&gt;
 class Y : public X &lt;T&gt;
 { ... }</code></pre></li>
</ol>
<hr>
<h1 id="특수화specialization">특수화(specialization)</h1>
<h2 id="암시적-특수화implicit-specialization">암시적 특수화(implicit specialization)</h2>
<p>클래스 템플릿이 각각의 타입에 대해 처음으로 호출될 때, C++ 컴파일러는 해당 타입의 인스턴스(instance)를 생성한다.</p>
<p><strong>생성된 인스턴스는 해당 타입에 대해 암시적으로 해당 타입에 특수화된 템플릿 함수</strong>이다.
따라서 해당 인스턴스는 함수 템플릿에 해당 타입이 사용될 때마다 호출된다.</p>
<h2 id="명시적-특수화explicit-specialization">명시적 특수화(explicit specialization)</h2>
<p>클래스 템플릿은 <strong>특정 타입이나 값의 템플릿 인수에 대해 특수화</strong>를 할 수 있다.
<strong>특수화를 명시하면, 해당 타입에 대한 특변한 동작을 정의할 수 있다.</strong></p>
<p>컴파일러는 전달된 인수에 정확히 대응하는 특수화된 정의를 발견하면, 더는 다른 템플릿을 찾지 않고 해당 정의를 사용한다.</p>
<h3 id="명시적-특수화-예제">명시적 특수화 예제</h3>
<p><code>double</code>형에 대한 명시적 특수화를 추가시킨 예제이다.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;

tmplate &lt;typename T&gt;
class Data
{
private:
    T data_;
public:
    Data(T dt);
    T get_data();
}

// double형에 대한 명시적 특수화
template &lt;&gt;
class Data&lt;double&gt;
{
private:
    double data_;
public:
    Data(double dt) { data_ = dt; }
    double get_data();
    {
        std::cout &lt;&lt; &quot;double형 데이터를 출력합니다.&quot; &lt;&lt; std::endl;
        return data_;
    }
}


int main()
{
    Data&lt;string&gt; str_data(&quot;클래스 템플릿&quot;);
    Data&lt;double&gt; double_data(3.14);

    std::cout &lt;&lt; &quot;str_data : &quot; &lt;&lt; str_data.get_data() &lt;&lt; std::endl;
    std::cout &lt;&lt; &quot;double_data : &quot; &lt;&lt; double_data.get_data() &lt;&lt; std::endl;
    return 0;
}

template &lt;typename T&gt;
Data&lt;T&gt;::Data(T dt)
{
    data_ = dt;
}

template &lt;typename T&gt;
T Data&lt;T&gt;::get_data()
{
    return data_;
}</code></pre>
<p><strong>Output</strong></p>
<pre><code class="language-shell">str_data : 클래스 템플릿
double형 데이터를 출력합니다.
double_data : 3.14</code></pre>
<h2 id="stdbasic_string-stdstring">std::basic_string, std::string</h2>
<p>클래스 템플릿의 대표적인 예 중에 하나는 <code>std::basic_string</code>이다.</p>
<p><code>std::basic_string</code>은 문자 유형에서 문자열을 만들기 위한 클래스 탬플릿이다.</p>
<pre><code class="language-cpp">template &lt;class charT, class traits = char_traits&lt;charT&gt;, class Alloc = allocator&lt;charT&gt;&gt; class basic_string;</code></pre>
<p>이러한 <code>std::basic_string</code>에 대해 <code>char</code> 형에 대한 명시적 특수화를 한 클래스의 <code>typedef</code> 한 클래스가 <code>std::string</code>이다.</p>
<pre><code class="language-cpp">typedef basic_string&lt;char&gt; string;</code></pre>
<hr>
<h2 id="부분-특수화partial-specialization">부분 특수화(partial specialization)</h2>
<p>만약 <strong>템플릿 인수가 2개 이상이고, 그 중 일부에 대해서만 특수화를 해야할 때는 부분 특수화(partial specialization)</strong>을 할 수 있다.</p>
<p>부분 특수화 방법은 먼저 <code>template</code> 키워드 다음에 나오는 꺾쇠괄호(<code>&lt;&gt;</code>)에 특수화하지 않는 타입의 템틀릿 인수를 명시한다.
그리고 다음에 다오는 꺾쇠괄호(<code>&lt;&gt;</code>)에 특수화하는 타입을 명시하면 된다.</p>
<h3 id="부분-특수화-예제">부분 특수화 예제</h3>
<pre><code class="language-cpp">template &lt;typename T1, typename T2&gt;
class X
{ ... }</code></pre>
<p>템플릿 인수가 2개인 위의 템플릿 클래스 X를 double형에 대해 부분 특수화를 하면 다음과 같다.</p>
<pre><code class="language-cpp">template &lt;typename T1&gt;
class X&lt;T1, double&gt;
{ ... }</code></pre>
<p>모든 템플릿 인수를 특수화하게 되면, 앞서 살펴본 완전한 명시적 특수화가 된다.</p>
<pre><code class="language-cpp">template &lt;&gt;
class X&lt;double, double&gt;
{ ... }</code></pre>
<hr>
<h1 id="중첩-클래스-템플릿nested-class-template">중첩 클래스 템플릿(nested class template)</h1>
<p>C++에서 <strong>클래스나 클래스 템플릿 내에 또 다른 템플릿을 중첩하여 정의할 수 있으며, 이러한 템플릿을 멤버 템플릿(member template)</strong>이라고 한다.</p>
<p><strong>멤버 템플릿 중 클래스 템플릿을 중첩 클래스 템플릿(nested calss template)</strong>이라고 한다.
이러한 중첩 클래스 템플릿은 바깥쪽 클래스 범위 내에서 클래스 템플릿으로 선언되며, <strong>정의는 바깥쪽 클래스의 범위 내애서 뿐만아니라 범위 밖에서도 가능</strong>하다.</p>
<h2 id="중첩-클래스-템플릿-문법">중첩 클래스 템플릿 문법</h2>
<p>중첩 클래스 템플릿은 다음과 같은 문법으로 정의할 수 있다.</p>
<pre><code class="language-cpp">template &lt;typename T&gt;
class X
{
    template &lt;typename U&gt;
    class Y
    {
        // ...
    }

    // ...
}

int main()
{
    // ...
}

template&lt;typename T&gt;
template&lt;typename U&gt;
X&lt;T&gt;::Y&lt;U&gt;::멤버함수이름()
{
    // 멤버 함수 구현
}</code></pre>
<p>이처럼 바깥쪽 클래스인 X의 외부에 중첩 클래스 템플릿 Y를 정의하면, 클래스 템플릿의 템플릿 인수와 멤버 템플릿의 템플릿 인수가 둘 다 앞에 명시되어야 한다.</p>
<hr>
<h1 id="템플릿을-위한-새로운-이름">템플릿을 위한 새로운 이름</h1>
<p>C++11부터는 <code>typedef</code> 키워드를 이용해 템플릿 특수화를 위한 새로운 이름을 선언할 수 있다.</p>
<pre><code>typedef X&lt;double, 3.14&gt; DoubleX;

// double_x는 X&lt;double, 3.14&gt; 타입이다.
DoubleX double_x;</code></pre><hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
</blockquote>
<ul>
<li><a href="http://www.tcpschool.com/cpp/cpp_template_class">http://www.tcpschool.com/cpp/cpp_template_class</a></li>
<li><a href="https://stackoverflow.com/questions/1662107/whats-the-difference-between-stdstring-and-stdbasic-string-and-why-are-bot">https://stackoverflow.com/questions/1662107/whats-the-difference-between-stdstring-and-stdbasic-string-and-why-are-bot</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[C++] 함수 템플릿(function template)]]></title>
            <link>https://velog.io/@octo__/C-%ED%95%A8%EC%88%98-%ED%85%9C%ED%94%8C%EB%A6%BFfunction-template</link>
            <guid>https://velog.io/@octo__/C-%ED%95%A8%EC%88%98-%ED%85%9C%ED%94%8C%EB%A6%BFfunction-template</guid>
            <pubDate>Sun, 11 Dec 2022 07:19:16 GMT</pubDate>
            <description><![CDATA[<h1 id="함수-템플릿function-template">함수 템플릿(function template)</h1>
<p>함수 템플릿(function template)은 <strong>함수의 일반화된 선언을 의미</strong>한다.</p>
<p>함수 템플릿을 사용하면 같은 알고리즘을 기반으로 하면서, 서로 다른 타입에서 동작하는 함수를 한 번에 정의할 수 있다.</p>
<p>이는 임의의 타입으로 작성된 함수에 특정 타입을 매개변수로 전달하면, C++ 컴파일러에서 해당 타입에 맞는 함수를 생성해주기 때문이다.</p>
<h2 id="함수-템플릿-문법">함수 템플릿 문법</h2>
<p>함수 템플릿은 다음과 같은 문법으로 사용할 수 있다.</p>
<pre><code class="language-cpp">template &lt;typename 타입이름&gt;
함수의 원형
{
    // 함수 구현
}</code></pre>
<p>C++98에서 추가된 <code>typename</code> 키워드는 이전에 <code>class</code> 키워드를 사용했다.
따라서 C++ 컴파일러는 템플릿 정의 내의 <code>typename</code> 키워드와 <code>class</code> 키워드를 같은 것으로 간주한다.</p>
<p><code>typename</code> 키워드를 사용해 정의된 타입 이름은 함수의 원형과 본체에서 임의의 타입으로 사용할 수 있다.
<code>typename</code> 키워드로 정의된 매개변수에 어떠한 타입을 전달하면, 함수의 원형과 본체에서 정의된 타입은 모드 해당 타입으로 바뀌게 된다.</p>
<h2 id="함수-템플릿-예제">함수 템플릿 예제</h2>
<p>아래 예제는 여러 타입의 변수의 값을 서로 바꾸는 <code>Swap()</code> 함수를 함수 템플릿으로 작성한 예제이다.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

template &lt;typename T&gt;
void Swap(T &amp;a, T &amp;b);

int main()
{
    int c = 2, d = 3;
    cout &lt;&lt; &quot;c : &quot; &lt;&lt; c &lt;&lt; &quot;, d : &quot; &lt;&lt; d &lt;&lt; endl;
    Swap(c, d);
    cout &lt;&lt; &quot;c : &quot; &lt;&lt; c &lt;&lt; &quot;, d : &quot; &lt;&lt; d &lt;&lt; endl;

    string e = &quot;hong&quot;, f = &quot;kim&quot;;
    cout &lt;&lt; &quot;e : &quot; &lt;&lt; e &lt;&lt; &quot;, f : &quot; &lt;&lt; f &lt;&lt; endl;
    Swap(e, f);
    cout &lt;&lt; &quot;e : &quot; &lt;&lt; e &lt;&lt; &quot;, f : &quot; &lt;&lt; f &lt;&lt; endl;

    return 0;
}

template &lt;typename T&gt;
void Swap(T &amp;a, T &amp;b)
{
    T temp;

    temp = a;
    a = b;
    b = temp;
}</code></pre>
<h2 id="output">Output</h2>
<pre><code class="language-shell">c : 2, d : 3
c : 3, d : 2
e : hong, f : kim
e : kim, f : hong</code></pre>
<hr>
<h1 id="특수화된-템플릿-함수specialized-function-template">특수화된 템플릿 함수(specialized function template)</h1>
<h2 id="함수-템플릿의-인스턴스화암시적-특수화implicit-specialization">함수 템플릿의 인스턴스화(암시적 특수화(implicit specialization))</h2>
<p>함수 템플릿이 각각의 타입에 대해 처음으로 호출될 때, C++ 컴파일러는 해당 타입의 인스턴스(instance)를 생성한다.</p>
<p>생성된 인스턴스는 해당 타입에 대해 암시적으로 특수화된 템플릿 함수이다.
따라서 해당 인스턴스는 함수 템플릿에 해당 타입이 사용될 때마다 호출된다.</p>
<h2 id="명시적-특수화explicit-specialization">명시적 특수화(explicit specialization)</h2>
<p>C++의 함수 템플릿은 특정 타입에 대한 명시적 특수화(explicit specialization)를 제공하여 특정 타입에 대해 특정한 동작을 정의할 수 있다.</p>
<p>컴파일러는 호출된 함수에 정확히 대응하는 특수화된 정의를 발견하면, 더 이상 테블릿을 찾지 않고 해당 정의를 사용한다.</p>
<h3 id="명시적-특수화-예제">명시적 특수화 예제</h3>
<p><code>Swap()</code> 함수 템플릿에서 <code>double</code> 형에 대한 동작만 변경하기 위해 명시적 특수화를 사용한 예제이다.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

template &lt;typename T&gt; void Swap(T &amp;a, T &amp;b);
template &lt;&gt; void Swap&lt;double&gt;(double &amp;a, double &amp;b);

int main()
{
    int c = 2, d = 3;
    cout &lt;&lt; &quot;c : &quot; &lt;&lt; c &lt;&lt; &quot;, d : &quot; &lt;&lt; d &lt;&lt; endl;
    Swap(c, d);
    cout &lt;&lt; &quot;c : &quot; &lt;&lt; c &lt;&lt; &quot;, d : &quot; &lt;&lt; d &lt;&lt; endl;

    double e = 1.234, f = 4.321;
    cout &lt;&lt; &quot;e : &quot; &lt;&lt; e &lt;&lt; &quot;, f : &quot; &lt;&lt; f &lt;&lt; endl;
    Swap(e, f);
    cout &lt;&lt; &quot;e : &quot; &lt;&lt; e &lt;&lt; &quot;, f : &quot; &lt;&lt; f &lt;&lt; endl;

    return 0;
}

template &lt;typename T&gt;
void Swap(T &amp;a, T &amp;b)
{
    T temp;

    temp = a;
    a = b;
    b = temp;
}

template &lt;&gt;
void Swap&lt;double&gt;(double &amp;a, double &amp;b)
{
    return ;
}</code></pre>
<h3 id="output-1">Output</h3>
<pre><code class="language-shell">c : 2, d : 3
c : 3, d : 2
e : 1.234, f : 4.321
e : 1.234, f : 4.321</code></pre>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
<ul>
<li><a href="http://www.tcpschool.com/cpp/cpp_template_function">http://www.tcpschool.com/cpp/cpp_template_function</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[C++] 템플릿(template)]]></title>
            <link>https://velog.io/@octo__/C-%ED%85%9C%ED%94%8C%EB%A6%BFtemplate</link>
            <guid>https://velog.io/@octo__/C-%ED%85%9C%ED%94%8C%EB%A6%BFtemplate</guid>
            <pubDate>Sun, 11 Dec 2022 06:48:14 GMT</pubDate>
            <description><![CDATA[<h1 id="c-특징-일반화-프로그래밍generic-programming">C++ 특징: 일반화 프로그래밍(generic programming)</h1>
<p><strong>C++의 프로그래밍 언어로서의 특징 중 하나는 일반화 프로그래밍(generic programming)</strong>이다.</p>
<p>일반화 프로그래밍은 데이터를 중시하는 객체 지향 프로그래밍과는 달리 <strong>프로그램의 알고리즘에 중점을 두는 프로그래밍</strong>이다.</p>
<p>C++에서 이런 <strong>일반화 프로그래밍을 지원하는 대표적인 기능 중 하나가 템플릿(template)</strong>이다.</p>
<h1 id="템플릿template">템플릿(template)</h1>
<p>템플릿(template)이란 <strong>매개변수의 타입에 따라 함수나 클래스를 생성하는 매커니즘</strong>을 의미한다.</p>
<p>템플릿은 타입이 매개변수에 의해 표현되기 때문에, <strong>매개변수화 타입(parameterized type)이라고도 한다.</strong></p>
<p>템플릿을 사용하면 <strong>타입마다 별도의 함수나 클래스를 만들지 않고, 여러 타입에서 동작할 수 있는 하나의 함수나 클래스를 작성하는 것이 가능</strong>하다.</p>
<p>이러한 템플릿을 사용하는 함수는 함수 템플릿(function template), 클래스는 클래스 템플릿(class template)이라고 한다.</p>
<hr>
<h1 id="참고-자료">참고 자료</h1>
<blockquote>
<ul>
<li><a href="http://www.tcpschool.com/cpp/cpp_template_function">http://www.tcpschool.com/cpp/cpp_template_function</a></li>
</ul>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>