<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jakeseo-javascript.js 🔨</title>
        <link>https://velog.io/</link>
        <description>풀스택 웹개발자로 일하고 있는 Jake Seo입니다. 주로 Jake Seo라는 닉네임을 많이 씁니다. 프론트엔드: Javascript, React 백엔드: Spring Framework에 관심이 있습니다. </description>
        <lastBuildDate>Thu, 06 Nov 2025 11:11:45 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jakeseo-javascript.js 🔨</title>
            <url>https://images.velog.io/images/jakeseo_me/profile/ac161dd9-cee4-4a7a-8864-3d49d806f9b7/깡깡이.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jakeseo-javascript.js 🔨. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jakeseo_me" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[컴퓨터 공학에서 쓰이는 회귀라는 용어에 대해 알아보기]]></title>
            <link>https://velog.io/@jakeseo_me/%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B3%B5%ED%95%99%EC%97%90%EC%84%9C-%EC%93%B0%EC%9D%B4%EB%8A%94-%ED%9A%8C%EA%B7%80%EB%9D%BC%EB%8A%94-%EC%9A%A9%EC%96%B4%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@jakeseo_me/%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B3%B5%ED%95%99%EC%97%90%EC%84%9C-%EC%93%B0%EC%9D%B4%EB%8A%94-%ED%9A%8C%EA%B7%80%EB%9D%BC%EB%8A%94-%EC%9A%A9%EC%96%B4%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Thu, 06 Nov 2025 11:11:45 GMT</pubDate>
            <description><![CDATA[<h1 id="회귀regression-라는-용어에-대해">회귀(Regression) 라는 용어에 대해</h1>
<blockquote>
<p>회귀 (回歸): 한 바퀴 돌아 제자리로 돌아오거나 돌아감.</p>
</blockquote>
<p>컴퓨터공학쪽에서 회귀(Regression)라는 단어는 보통 두가지 맥락 속에서 사용된다.</p>
<ol>
<li>Machine Learning</li>
<li>Software Testing</li>
</ol>
<h2 id="machine-learning-맥락에서의-회귀">Machine Learning 맥락에서의 회귀</h2>
<ul>
<li>이 맥락에서는 회귀(Regression) 라는 단어 자체가 가진 본래의 의미에서 관계의 근사와 예측의 의미로 확장된다.</li>
<li>여기서 회귀는 주로 변수들 간의 관계를 수학적으로 근사하고 결과 값을 예측하는 방법을 의미한다.</li>
<li>독립 변수와 종속 변수 간의 관계를 수학적으로 모델링하여 종속 변수 값을 예측하거나 설명하는 분석 기법을 가리키는 용어로 사용된다.</li>
<li>집값 예측을 예로 들면, 입력 변수(ex. 지리적 요인, 면적)에 따라 결과 변수(ex. 가격)을 예측하는 경우, 이를 회귀 모델을 구성한다고 표현할 수 있다.</li>
</ul>
<p>회귀가 예측과 가까운 뜻을 가지게 된데는 역사적 맥락이 있다고 한다. 현대 통계학의 선구자 중 한명인 프랜시스 골턴은 &quot;부모의 키가 극단적일 때 자식의 키는 부모의 키보다 평균에 더 가까운 키로 회귀한다(regression toward the mean)&quot;는 사실을 발견했고, 이후 사람들은 회귀를 평균으로 되돌아가는 현상뿐 아니라, &quot;변수 간의 관계를 수학적으로 모델링하여 값을 예측하는 기법&quot;을 말할 때 썼다고 한다.</p>
<h2 id="software-testing-맥락에서의-회귀">Software Testing 맥락에서의 회귀</h2>
<ul>
<li>원래의 회귀(Regression)의 의미 즉, 되돌아감의 의미로 사용된다.</li>
<li>소프트웨어가 버그가 있던 시절로 돌아가는지를 검증하는 테스트를 이야기한다.</li>
<li>개발이 앞으로 나아가야 하는데, 수정 후 예전 버그가 다시 등장했다면, &quot;뒤로 회귀했다(regressed)&quot; 라고 표현할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[#1, LLM 이란?]]></title>
            <link>https://velog.io/@jakeseo_me/1-LLM-%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@jakeseo_me/1-LLM-%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Tue, 21 Oct 2025 13:36:21 GMT</pubDate>
            <description><![CDATA[<h2 id="llm이란">LLM이란?</h2>
<p><img src="https://jakeseo.blog/ce2933c7403b6c572c92d49c6365ad105552ba7eb225733399511df1e84acb20.png" alt="picture 5"></p>
<ul>
<li>대규모 언어 모델 (Large Language Model)</li>
<li>심층 신경망 모델 (Deep Neural Network)<ul>
<li>여러개의 층으로 복잡한 관계까지 학습 가능한 모델<ul>
<li>얕은 모델은 단순 규칙만 학습 가능</li>
</ul>
</li>
<li>입력 -&gt; 특징 추출 -&gt; 출력으로 변환하는 구조</li>
</ul>
</li>
<li>대용량의 텍스트 데이터로 훈련<ul>
<li>인터넷에 공개된 전체 텍스트의 상당 부분</li>
</ul>
</li>
<li>사람의 텍스트를<ul>
<li>이해</li>
<li>생성</li>
<li>응답</li>
</ul>
</li>
</ul>
<h2 id="대규모란-어떤-뜻인가">대규모란 어떤 뜻인가?</h2>
<ul>
<li>모델 파라미터의 크기와 대량의 훈련 데이터셋을 의미</li>
<li>수백 또는 수천억 개의 파라미터</li>
<li>모델 파라미터는 시퀀스의 다음 단어를 예측하도록 훈련하는 과정에서 조정되는 신경망의 가중치 (weight)</li>
</ul>
<h2 id="학습에서-머신러닝과-딥러닝의-차이">학습에서 머신러닝과 딥러닝의 차이</h2>
<ul>
<li>머신러닝: 사람이 직접 특성을 추출</li>
<li>딥러닝: 모델이 자동으로 학습</li>
</ul>
<p>머신러닝에서는 사람이 직접 특성을 설계(feature engineering) 해야 하고, 딥러닝에서는 신경망이 데이터로부터 유용한 특성을 자동으로 학습(representation learning) 한다.</p>
<h3 id="오해하면-안되는-부분">오해하면 안되는 부분</h3>
<ul>
<li>모델이 특성을 자동으로 학습하긴 하지만, 사람이 여전히 모델 구조, 데이터 전처리, 하이퍼파라미터를 설계해야 함</li>
<li>즉, &quot;수동 특성(feature engineering)&quot;은 줄었지만 &quot;모델 설계(model engineering)&quot;는 여전히 인간의 몫</li>
</ul>
<h2 id="llm-애플리케이션의-쓸모">LLM 애플리케이션의 쓸모</h2>
<ul>
<li>텍스트 분석과 생성에 관련된 거의 모든 작업을 자동화하는데 매우 유용함</li>
</ul>
<h2 id="llm-구축-단계">LLM 구축 단계</h2>
<p><img src="https://jakeseo.blog/b943aabb471d80ca9fda211c3255b6fe612c384160a34036da6571cb3aff3d0b.png" alt="picture 6"></p>
<ul>
<li>사전 훈련과 미세 튜닝으로 구성됨<ul>
<li>사전 훈련: LLM 모델을 대규모 데이터셋에서 훈련시켜 언어에 대한 폭넓은 이해를 쌓는 초기 단계</li>
<li>미세 튜닝: 사전 훈련된 파운데이션 모델을 개선</li>
</ul>
</li>
</ul>
<h3 id="1단계-사전-훈련">1단계: 사전 훈련</h3>
<ul>
<li>원시 텍스트인 대규모 텍스트 말뭉치(corpus)에서 훈련<ul>
<li>&#39;원시&#39;란 데이터에 레이블 정보가 없는 일반적인 텍스트</li>
<li>ML의 지도 학습에선 정답(레이블)이 필요하지만, LLM은 입력 데이터로부터 레이블을 생성하는 자기 지도 학습(self-supervised learning)을 사용</li>
</ul>
</li>
<li>첫번째 훈련 단계를 사전 훈련(pretraining) 이라 부름</li>
<li>이렇게 훈련된 모델을 베이스 모델(base model) 혹은 파운데이션 모델(foundation model) 이라 부름</li>
</ul>
<blockquote>
<p>사전 훈련만 끝나도, 입력 데이터를 기반으로 다양한 작업을 해결 가능.
ex. 텍스트 훈련, 제로-샷, 퓨-샷</p>
</blockquote>
<h3 id="2단계-미세-튜닝">2단계: 미세 튜닝</h3>
<ul>
<li>이번엔 원시 텍스트가 아닌 레이블이 있는 데이터를 이용해 LLM을 추가적으로 훈련 가능<ul>
<li>이것을 미세 튜닝이라고 함</li>
</ul>
</li>
<li>인기 있는 미세 튜닝의 종류<ul>
<li>지시 미세 튜닝 (instruction fine-tuning)<ul>
<li>지시와 정답 쌍 (ex. 번역하기 위한 쿼리와 번역된 텍스트)</li>
</ul>
</li>
<li>분류 미세 튜닝 (classification fine-tuning)<ul>
<li>ex. 스팸인 메일 / 스팸이 아닌 메일</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="트랜스포머-구조">트랜스포머 구조</h2>
<p><img src="https://jakeseo.blog/184b4909feed286178e0374d51042059b37dbcf6b5829ee1bea3be6e12f4b545.png" alt="picture 7"></p>
<ul>
<li>대부분의 최신 LLM은 <a href="https://arxiv.org/abs/1706.03762">Attention is All You Need</a> 에서 소개된 심층 신경망 구조인 트랜스포머(transformer)를 기반으로 함</li>
<li>트랜스포머는 크게 인코더(encoder)와 디코더(decoder)로 구성됨<ul>
<li>인코더(encoder): 입력 문장의 각 토큰을 임베딩(숫자 벡터)로 바꾼 뒤, 위치 정보를 더해서 여러 층(layer)을 통과시키며 문장 전체의 표현을 만듦</li>
<li>디코더(decoder): 이전에 생성한 단어들을 입력으로 받아 다음 단어를 하나씩 예측. 단, 미래 단어는 못보게 막아둠</li>
</ul>
</li>
</ul>
<h3 id="셀프-어텐션이란">셀프 어텐션이란?</h3>
<ul>
<li>인코더와 디코더는 셀프 어텐션(Self-Attention) 매커니즘으로 연결된 많은 층으로 구성되어 있음<ul>
<li>모델이 시퀀스에 있는 서로 다른 단어 또는 토큰(token)에 상대적인 가중치를 부여할 수 있음</li>
<li>모델이 입력데이터에서 긴 범위에 걸친 의존성과 맥락관계를 포착하여 일관성 있고 맥락에 맞는 출력을 생성할 수 있음</li>
</ul>
</li>
</ul>
<h4 id="셀프-어텐션의-동작-방식">셀프 어텐션의 동작 방식</h4>
<ul>
<li>각 단어가 모든 단어를 훑어보고, 지금은 이 단어에 얼마나 주목해야 하는지 가중치(중요도)를 계산</li>
<li>가중치로 다른 단어들의 정보를 모아서(가중 합) 그 단어의 새로운 표현을 만듦</li>
<li>장점<ul>
<li>모든 단어가 서로 직접 소통하므로, 멀리 떨어진 관계(장거리 의존성)을 바로 포착 가능</li>
<li>계산을 병렬화 할 수 있어서 GPU 에서 훨씬 빠르게 학습 가능</li>
</ul>
</li>
<li>Multi-Head Attention 이란?<ul>
<li>여러명의 팀원이 다양한 관점으로 동시에 문장을 검토하는 것</li>
<li>문법, 의미, 관계 같은 다양한 관점으로 바라보고 그 결과를 모아서 더 풍부한 표현을 만듦</li>
</ul>
</li>
</ul>
<h3 id="bert와-gpt">BERT와 GPT</h3>
<ul>
<li>BERT: 인코더 모듈을 기반으로 함<ul>
<li>주어진 문장에서 마스킹 되거나 가려진 단어를 예측하는 마스킹 단어 예측에 특화</li>
<li>감성 분석과 문서 분류를 포함해 텍스트 분류 작업에 강점을 가짐</li>
</ul>
</li>
<li>GPT: 디코더 모듈을 기반으로 함<ul>
<li>텍스트 생성 특화</li>
</ul>
</li>
</ul>
<h3 id="트랜스포머가-나온-맥락">트랜스포머가 나온 맥락</h3>
<ul>
<li>기존 RNN의 한계 극복<ul>
<li>병럴 처리: 한 문장을 순차적으로 훑지 않고, 한번에 모든 단어의 관계를 계산하므로 학습 속도가 빠름</li>
<li>장거리 의존성 처리: 멀리 있는 단어끼리도 직접 연결되므로 복잡한 문장 구조를 더 잘 포착</li>
<li>확장성 문제: 문장이 매우 길어지면 모든 단어 쌍을 계산하므로 비용이 커지는 단점(그러나 이후 연구들이 이를 개선)</li>
</ul>
</li>
</ul>
<h2 id="gpt-구조">GPT 구조</h2>
<ul>
<li><a href="https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf">Improving Language Understanding by Generative Pre-Training</a> 에서 소개</li>
<li><a href="https://arxiv.org/pdf/2203.02155">Training language models to follow instructiosn with human feedback</a></li>
</ul>
<h3 id="자기지도-학습">자기지도 학습</h3>
<p><img src="https://jakeseo.blog/cf848df37347b2c186374d650199bfd8e2c1ef2597abeae0f477d2a36752fb23.png" alt="picture 8"></p>
<ul>
<li>방대한 텍스트 데이터에서 다음 단어를 모델이 예측해야 할 레이블로 사용 가능 (Autoregressive model)</li>
<li>이전 출력을 입력으로 사용해 미래를 예측함</li>
<li>이전 시퀀스를 기반으로 다음 단어를 선택하는 식으로 출력 텍스트의 일관성을 향상</li>
</ul>
<h2 id="gpt-구현-단계">GPT 구현 단계</h2>
<p><img src="https://jakeseo.blog/22ec18cb68d45c81b3758801b551ce029ce62c8aeb9859eb972f772cb572c92c.png" alt="picture 9"></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드숨 스프링 편 8주차 회고: 문서화, 빌드]]></title>
            <link>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-8%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EB%AC%B8%EC%84%9C%ED%99%94-%EB%B9%8C%EB%93%9C</link>
            <guid>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-8%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EB%AC%B8%EC%84%9C%ED%99%94-%EB%B9%8C%EB%93%9C</guid>
            <pubDate>Tue, 07 Jun 2022 23:35:52 GMT</pubDate>
            <description><![CDATA[<h2 id="무엇을-했는가">무엇을 했는가?</h2>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/90">asciidoctor 를 통해 Spring REST Docs 를 자동 생성</a>해보았다.<ul>
<li><a href="https://jake-seo-dev.tistory.com/88">javadoc 한글깨짐 현상 해결</a></li>
</ul>
</li>
<li><a href="https://jake-seo-dev.tistory.com/118?category=943963">도커를 이용해 스프링부트 프로젝트를 배포</a>해보았다.</li>
</ul>
<h2 id="무엇을-배웠는가">무엇을 배웠는가?</h2>
<ul>
<li>도커에 대해서 배웠다.</li>
<li>asciidoctor 로 스프링 REST 문서를 작성하는 방법에 대해 배웠다.</li>
</ul>
<h2 id="어떤-감정을-느꼈는가">어떤 감정을 느꼈는가?</h2>
<ul>
<li>문서작업과 배포를 통해 프로젝트가 말 그대로 &#39;완성&#39;되는 느낌을 받았다.</li>
<li>프로그램은 보통 혼자 개발하는 것이 아니라 많은 사람과 협업하게 된다.</li>
<li>이 과정에서 물론 코드도 중요하지만 코드 외적인 것들도 아주 중요하다는 것을 느꼈다.</li>
<li>결과적으로는 코딩을 통해 기존에 있던 문제를 해결하는 것이다.</li>
</ul>
<h2 id="다짐">다짐</h2>
<p>최종 목표는 좋은 코드가 아니라 좋은 프로덕트라고 생각한다. 좋은 프로덕트를 만들기 위해 문서화 작업 등 코드 외적인 부분을 많이 신경쓰자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드숨 스프링 편 7주차 회고: 보안]]></title>
            <link>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-7%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EB%B3%B4%EC%95%88</link>
            <guid>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-7%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EB%B3%B4%EC%95%88</guid>
            <pubDate>Mon, 09 May 2022 15:37:37 GMT</pubDate>
            <description><![CDATA[<h2 id="무엇을-했는가">무엇을 했는가?</h2>
<p>프로젝트에 스프링 시큐리티를 이용한 보안 처리를 했다.</p>
<h2 id="무엇을-배웠는가">무엇을 배웠는가?</h2>
<p>말 그대로 <code>Spring Security (스프링 앱에서의 보안)</code>에 대해서 배웠다.</p>
<h3 id="스프링-시큐리티를-적용하면-기본으로-활성화되는-csrf-에-대해-배웠다">스프링 시큐리티를 적용하면 기본으로 활성화되는 CSRF 에 대해 배웠다.</h3>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/78">CSRF 공격 정리 포스팅</a></li>
</ul>
<h3 id="반복적으로-이루어지는-인증인가-처리가-어떻게-이루어지는지-배웠다">반복적으로 이루어지는 인증/인가 처리가 어떻게 이루어지는지 배웠다.</h3>
<p>Spring 을 이용한 서블릿 앱에서는 주로 2가지 기술을 이용했다.</p>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/80">스프링 인터셉터 포스팅</a></li>
<li><a href="https://jake-seo-dev.tistory.com/79">서블릿 필터 포스팅</a></li>
</ul>
<p>둘 다 서블릿 요청 메인 로직을 타기 전, 후에 로직을 넣기 용이했다. 다만, 실행 시점이 다르며 할 수 있는 일도 달랐다.</p>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/83">Filter, Interceptor, AOP 알아보기 포스팅</a></li>
</ul>
<p>Filter 랑 Interceptor 를 알아보는 겸 AOP 까지 같이 한번 짧게 정리해보았다.</p>
<h3 id="스프링의-메서드-시큐리티를-배워보았다">스프링의 메서드 시큐리티를 배워보았다.</h3>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/82">스프링 메서드 시큐리티 정리 포스팅</a></li>
</ul>
<h2 id="어떤-감정을-느꼈는가-그리고-어떤-생각을-했는가">어떤 감정을 느꼈는가? 그리고 어떤 생각을 했는가?</h2>
<ul>
<li>놀랐다. 정말 창의적인 방식으로 해킹을 한다는 생각을 했다.</li>
<li>해킹의 다양한 기법들을 공부해보며 원리를 꼭 알아야겠다는 생각을 했다.<ul>
<li>다양한 해킹도 결국 하나의 원리를 기반으로 하였다.</li>
</ul>
</li>
</ul>
<p>CSRF 같은 경우는 내 생각에 2가지 핵심원리가 있다고 생각했다.</p>
<ul>
<li>인증 정보를 가지고 있는 브라우저가 있다.</li>
<li>게시글, 댓글, 이메일 등 다양한 방식을 통해 스크립트를 심을 수 있었고, 보안 정보가 담긴 브라우저에서는 이러한 스크립트 하나하나가 치명적이다.</li>
</ul>
<h2 id="다짐">다짐</h2>
<p>보안에 대해서 공부하는 것은 굉장히 시간 소비가 컸지만, 네트워크나 해킹과 같이 평소에 생각해볼 일이 없던 것들을 생각해보게 되었다. 한 번에 보안에 대한 모든 것을 공부하기엔, 공부량에 압도되고 주객이 전도될 것 같으니 관련 키워드가 등장할 때마다 보안 원리에 대해 조금씩 제대로 공부해보자.</p>
<h2 id="코드-리뷰-지적-사항들">코드 리뷰 지적 사항들</h2>
<h3 id="여러-줄의-주석은-javadoc-주석을-사용하자">여러 줄의 주석은 javadoc 주석을 사용하자</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/fed6c41d-eb0a-477c-add4-8e5575a959d0/image.png" alt=""></p>
<h3 id="주석의-괴리를-조심하자">주석의 괴리를 조심하자</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/c68c0097-1e0f-4227-bc55-08fbddc56e51/image.png" alt=""></p>
<p>주석도 팀원들끼리 같이 관리해보자!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드숨 스프링 편 6주차 회고: 로그인]]></title>
            <link>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-6%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EB%A1%9C%EA%B7%B8%EC%9D%B8</link>
            <guid>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-6%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EB%A1%9C%EA%B7%B8%EC%9D%B8</guid>
            <pubDate>Mon, 02 May 2022 16:37:42 GMT</pubDate>
            <description><![CDATA[<h2 id="이번-주에는-무엇을-했는가">이번 주에는 무엇을 했는가?</h2>
<p>요약하자면, 이전에 만든 API 에 JWT 를 이용한 인증을 도입해보았다.</p>
<h2 id="인증과-인가의-차이에-대해-배워보았다">인증과 인가의 차이에 대해 배워보았다</h2>
<p>쉽게 말해서 인증은 &#39;누구인지&#39; 확인하는 행위이고 인가는 &#39;할 수 있는지&#39; 확인하는 행위이다. 인증은 인가로 이어질 수 있지만, 인가는 인증으로 이어지지는 않을 수 있다.</p>
<h3 id="내-블로그에-직접-정리한-글">내 블로그에 직접 정리한 글</h3>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/76">인증과 인가의 차이 정리</a></li>
</ul>
<h2 id="jwt-를-배워보았다">JWT 를 배워보았다</h2>
<p>JWT 란 JSON Web Token 으로 보안이 적용된 JSON Object 를 주고받을 수 있는 표준이다.</p>
<blockquote>
<p>JWT 는 들어보기만 하고 써보는 건 처음이라 궁금해서 이것저것 찾아보았다.</p>
</blockquote>
<h3 id="내-블로그에-직접-정리한-글-1">내 블로그에 직접 정리한 글</h3>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/77">JWT (JSON Web Token) 이란 무엇이며 왜 사용하는가?</a></li>
</ul>
<h3 id="jwt-를-사용하며-생기는-이슈-사항들에-대해서도-간단히-알아보았다">JWT 를 사용하며 생기는 이슈 사항들에 대해서도 간단히 알아보았다.</h3>
<ul>
<li><a href="https://velog.io/@0307kwon/JWT%EB%8A%94-%EC%96%B4%EB%94%94%EC%97%90-%EC%A0%80%EC%9E%A5%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C-localStorage-vs-cookie">JWT 는 어디에 저장해야 할까?</a></li>
<li><a href="https://stackoverflow.com/questions/32060478/is-a-refresh-token-really-necessary-when-using-jwt-token-authentication">Is a Refresh Token really necessary when using JWT token authentication?</a></li>
<li><a href="https://velog.io/@park2348190/JWT%EC%97%90%EC%84%9C-Refresh-Token%EC%9D%80-%EC%99%9C-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80">JWT 에서 Refresh Token 은 왜 필요한가?</a></li>
</ul>
<h3 id="저장-위치는-어디가-좋을까">저장 위치는 어디가 좋을까?</h3>
<p>JWT 는 쿠키 혹은 로컬스토리지에 보통 저장하는데, 둘 다 보안에 취약하지만 그래도 HttpOnly 를 적용한 쿠키가 그나마 나은 옵션이라고 여겨지고 있다. 기본적으로 브라우저에 있는 정보들은 자바스크립트로 접근이 가능하기 때문에 XSS 공격에 취약하다고 여겨지고 있다.</p>
<h3 id="jwt-의-보안-이슈사항">JWT 의 보안 이슈사항</h3>
<p>JWT 의 경우 한번 탈취되면, 상당히 골치아파진다. 그렇다고 해서 매번 만료 주기를 짧게 잡으면, 사용자가 사이트를 켜놓고 딴짓을 하게 된다고 쳤을 때, 이용하는 중간 중간에 계속 로그인을 새로 해주어야 한다.</p>
<p>이 경우 토큰을 2개 발급하여, 1개는 <code>Refresh Token</code> 용도로 사용하고 1개는 일반 <code>Access Token</code> 을 만든다. <code>Access Token</code> 은 짧은 만료 주기를 갖고 계속 만료가 되는 형태가 될 것이고, <code>Refresh Token</code> 은 긴 만료주기를 갖고 계속 <code>Access Token</code> 을 업데이트 하는 전략을 사용할 수 있다.</p>
<blockquote>
<p>물론 두 토큰 모두 탈취당하면 답이 없다.</p>
</blockquote>
<h3 id="jwt-는-왜-좋을까">JWT 는 왜 좋을까?</h3>
<p>비교군으로는 세션 기반 인증이 있다.</p>
<p><strong>stateless vs stateful</strong></p>
<p>세션 기반 인증과 JWT 의 가장 커다란 차이는 아무래도 &#39;stateless 로 구현 가능하냐&#39; 인 것 같다. 그러나 JWT 인증도 여러가지 보안 요소를 고려하다보면 결국 실제 서비스에서는 &#39;stateless&#39; 는 될 수도 있고 안 될 수도 있다.</p>
<p><strong>도메인에 대한 제약이 상대적으로 적음</strong></p>
<p>MSA (Micro Service Architecture) 가 유행하며, JWT 가 기본적으로 도메인 제약이 상대적으로 적은 인증 방식이라는 것 때문에 유행하는 것도 있는 것 같다.</p>
<h2 id="코드-리뷰-사항들">코드 리뷰 사항들</h2>
<h3 id="bean-value-configuration-애노테이션-내용을-정리했다"><code>@Bean</code>, <code>@Value</code>, <code>@Configuration</code> 애노테이션 내용을 정리했다</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/42f452f5-9d17-4b61-aeb9-8ec607a09cfd/image.png" alt=""></p>
<p>2개는 이전에 정리해보았던 애노테이션이라 <code>@Value</code> 만 한번 정리해보았다. 스프링의 <code>BeanPostProcessor</code> 를 통해 실행되는지 처음 알았고 SpEL 문법 활용이 가능한 것도 처음 알게 되었다.</p>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/75">https://jake-seo-dev.tistory.com/75</a></li>
</ul>
<h3 id="dto-에서의-쓸모-없는-setter-사용을-자제하자">Dto 에서의 쓸모 없는 <code>@Setter</code> 사용을 자제하자</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/5fb2e35f-e842-4f64-a22f-6cb67fcdb4c0/image.png" alt=""></p>
<p><code>Jackson</code> 라이브러리는 <code>@Setter</code> 없이도 객체 매핑을 잘 해주어서, 사실상 <code>@Setter</code> 가 필요 없었다. 필요할 때만 쓰자.</p>
<h3 id="완곡한-표현을-사용하자">완곡한 표현을 사용하자</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/882aabab-d369-4270-b6ef-307dc0033081/image.png" alt=""></p>
<p>클라이언트에게 메세지를 줄 때는 완곡한 표현을 사용하자. 최근 회사 업무에서도 많이 느끼고 있는데, 서비스 이용 중 예외가 발생하면 고객은 내가 작성한 딱딱한 예외 메세지를 받고 어떤 일이 일어났는지 파악하게 된다. 인터넷 끊김과 같은 케이스도 생각하며 예외 메세지를 조금만 더 완곡하게 표현해 더욱 포용력 있는 답을 해보자.</p>
<h3 id="메서드-추출">메서드 추출</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/cd7ee7ec-0f64-4747-bf07-b76d43d76a48/image.png" alt=""></p>
<p>의미를 가진 코드 조각은 메서드로 추출해서 가독성을 챙기자.</p>
<h3 id="validuser-대신-registereduser"><code>validUser</code> 대신 <code>registeredUser</code></h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/264444a6-0acb-426a-9c99-5ac384fdce20/image.png" alt=""></p>
<p>코드의 의미는 간결하면서 명확하게 드러날수록 좋다. <code>valid</code> 는 <code>registered</code> 보다는 덜 구체적이므로 생각을 한번만 더 해보고 조금 더 구체적인 표현이 없는지 생각해보자.</p>
<h3 id="junit의-displayname-작성-시-클래스명의-디커플링을-조심하자">Junit의 <code>@DisplayName</code> 작성 시 클래스명의 디커플링을 조심하자</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/70b6e8b6-516a-4447-b0c4-6272d22128d0/image.png" alt=""></p>
<p>여기서 <code>UserLoginException</code> 이라는 예외 이름을 변경하여, 디커플링 되는 경우가 생겨버렸다. 다음부터 이런 경우를 조금만 더 생각해보자.</p>
<h3 id="내부적으로-보여지게-되는-로그-메세지는-미래의-디버깅하는-나를-배려해주는-마음으로-작성하자">내부적으로 보여지게 되는 로그 메세지는 미래의 디버깅하는 나를 배려해주는 마음으로 작성하자</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/54793ee8-bffb-49bc-a5c6-2ef030bea785/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드숨 스프링 편 5주차 회고: 유효성 검사]]></title>
            <link>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-5%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC</link>
            <guid>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-5%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%82%AC</guid>
            <pubDate>Wed, 27 Apr 2022 13:29:07 GMT</pubDate>
            <description><![CDATA[<h2 id="이번-주에는-무엇을-했는가">이번 주에는 무엇을 했는가?</h2>
<ul>
<li>간단히 말하자면, 애플리케이션에 검증 프로세스를 더했다.</li>
</ul>
<h2 id="자바의-bean-validation-을-배웠다">자바의 Bean validation 을 배웠다.</h2>
<ul>
<li>자바의 Bean validation 은 스프링 부트에서 <code>spring-boot-starter-validation</code> 의존성으로 쉽게 추가할 수 있다.</li>
<li>Bean validation 은 java ee 에서 표준화된 스펙이다.<ul>
<li><a href="https://javaee.github.io/javaee-spec/javadocs/javax/validation/package-summary.html">javax.validation</a> 패키지에서는 전체적으로 어떤 기능이 있는지에 대한 명세가 있다.</li>
<li><a href="https://javaee.github.io/javaee-spec/javadocs/javax/validation/constraints/package-summary.html">javax.validation.contraints</a> 패키지에서는 우리가 실질적으로 자주 사용하게 되는 애노테이션들에 대한 명세가 있다.</li>
</ul>
</li>
</ul>
<h3 id="배우며-생각해본-것">배우며 생각해본 것</h3>
<p>실무에서 <code>Controller</code> 를 개발하면서 아래의 로직들이 섞이는 것을 많이 봐왔다.</p>
<ul>
<li>사용자의 요청에서 받은 데이터에 대한 변환 (Converting)</li>
<li>받은 데이터에 대한 검증 (Validation)</li>
<li>받은 데이터에 대한 처리 (Business Logic)</li>
<li>받은 데이터에 대한 반환 (View)</li>
</ul>
<p>구조상 Validation 에 대한 완전한 분리가 가능할지는 모르겠지만 어느정도는 분리하여 앱의 복잡성을 제거할 수 있겠다고 생각이 들었다. 검증에 대해 간단하게 표현 가능한 부분을 <code>javax.validation</code> 을 통해 간소화할 수 있었다.</p>
<p>특히 도메인 클래스에 대한 검증을 매우 쉽게 만들어준다. 필드 위에 검증 애노테이션을 하나 얹고, 컨트롤러에서 <code>@Valid</code> 애노테이션을 파라미터 앞에 붙여주면 컨트롤러 단으로 데이터가 넘어올 때 자동으로 검증된다.</p>
<blockquote>
<p>경험상 validation 을 구성할 때, 컨트롤러의 파라미터 앞에 <code>@Valid</code> 애노테이션을 깜빡하는 경우가 생각보다 많았다. 꼭 테스트를 꼼꼼히 하자.</p>
</blockquote>
<h3 id="스프링과의-연동">스프링과의 연동</h3>
<p>아래의 포스팅들을 통해 스프링과의 연동 방식을 알았고, <code>@ControllerAdivce</code> 를 통해 API 에 대한 예외처리를 잘 할 수 있었다.</p>
<ul>
<li><a href="https://www.baeldung.com/spring-custom-validation-message-source">커스텀 메세지 설정하는 방법</a></li>
<li><a href="https://kapentaz.github.io/spring/Spring-Boo-Bean-Validation-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%95%8C%EA%B3%A0-%EC%93%B0%EC%9E%90/#">Bean Validation 실무 사용 방법 관련 상세 포스팅</a></li>
<li><a href="https://medium.com/chequer/spring-methodargumentnotvalidexception-valid-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC-2f63e8087759">@Valid MethodArgumentNotValidException 처리하기</a></li>
</ul>
<h3 id="공부-결과물">공부 결과물</h3>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/73">Java Bean Vallidation 블로그 정리</a></li>
</ul>
<h2 id="lombok-을-배워보았다">Lombok 을 배워보았다.</h2>
<p>자바에서 자주 쓰이는 보일러 플레이트 코드인 <code>Getter</code>, <code>Setter</code>, <code>Constructor</code>, <code>Builder</code> 등을 쉽게 만들 수 있도록 도와주는 라이브러리이다.</p>
<h3 id="배우며-생각해본-것-1">배우며 생각해본 것</h3>
<p>Lombok 은 말도 많고 탈도 많다. 편의성 측면에서는 매우 좋다. 그러나, 설계 측면에서는 글쎄..? 내 코드에 어떤 부작용을 줄 수 있을지 항상 생각하며 사용하자.</p>
<p>개발자는 라이브러리나 프레임워크를 활용하여 쉽게 프로덕션을 만들어낼 수 있다. 그러나 해당 라이브러리나 프레임워크에 대한 이해가 없다면 이로 인해 많은 버그를 만들어내기도 쉽다.</p>
<ul>
<li>롬복의 애노테이션이 하는 역할을 이해하며 사용하자.</li>
<li>롬복에서 제공하는 <code>access</code> 엘리먼트를 잘 활용하자.</li>
<li><code>lombok.config</code> 파일을 이용하여 롬복의 자유도를 제한하자.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/e3ffbb57-a3bb-450e-a80b-c027e697c556/image.png" alt=""></p>
<h3 id="공부-결과물-1">공부 결과물</h3>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/70">Lombok 을 사용할 때 주의해야 하는 점들</a></li>
</ul>
<h2 id="jpa-와-dto-에-대한-생각을-해보았다">JPA 와 DTO 에 대한 생각을 해보았다.</h2>
<p>JPA 는 ORM 기술 중 하나로, 관계형 DB 와 자바 객체간의 불일치를 해결해주는 데 도움을 준다. JPA 에서 사용하는 엔티티(<code>@Entity</code>)는 관계형 DB 에서 테이블에 있는 한 row 와 매칭된다.</p>
<p>엔티티는 데이터를 매핑하여, 활용하기에는 좋으나 Input, Output 에는 별도의 객체를 구성해 활용하는 편이 좋다.</p>
<p>엔티티를 그대로 요청이나 응답에 활용하기 보다는 <code>DTO (Data Transfer Object)</code>를 활용할 수 있고 이는 컨트롤러 단에서 요청 또는 응답에 사용되는 매개체로 훌륭한 역할을 할 수 있다.</p>
<h3 id="dto-의-장점은-무엇인가">DTO 의 장점은 무엇인가?</h3>
<p>간단히 축약해서 말하자면, 엔티티를 그대로 사용했을 때에 발생하는 문제를 해결할 수 있다.</p>
<ul>
<li>첫째, 원하는 정보만 받거나 보여줄 수 있다.</li>
<li>둘째, 원하는 검증 조건만 걸 수 있다.</li>
</ul>
<p>첫째는 엔티티를 그대로 반환하거나 받아들일 때의 단점을 해결한다. 회원 정보 조회를 할 때 엔티티를 그대로 반환한다면, 비밀번호 등 모든 정보를 보여주게 될 것이다. 그러나 DTO 를 반환하면 DTO 에 외부로 보여주기 원하는 필드만 세팅하여 보여줄 수 있다.</p>
<p>둘째는 엔티티를 그대로 검증할 때의 단점을 해결한다. 회원 가입 시에는 아이디, 이름, 비밀번호 등 대부분의 정보가 필수인 반면에, 회원 정보 수정 시에는 필수 값이 아닐 수 있다. 이를테면 회원 수정 폼 제출 시 이름에 대한 정보만 받았다면, 이름만 바꿔주는 식이다. 이렇게 특정 작업에 특화된 검증 객체로서 활용될 수 있다.</p>
<h3 id="dto-는-어디까지-공개해야-하는가">DTO 는 어디까지 공개해야 하는가?</h3>
<p>이 부분은 개발자마다 생각이 다른듯 하다.</p>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/4a760be6-a12e-43a3-886d-f3ead115a60b/image.png" alt=""></p>
<p>윤석님: 최소한의 레이어에만 공개해야 하는 것이 바람직하다.
종립님: DTO 클래스를 사용하는 것보다는 차라리 인터페이스를 사용하고, DTO 가 해당 인터페이스를 구현하게 하자.
아샬님: DTO 를 Infrastructure Layer 까지 연결하면 오히려 CQRS 에서까지 유용하게 쓸 수 있다.</p>
<p>핵심은 <strong>프로그램을 복잡하게 만드는 요인을 파악해서 제거하자는 것</strong>이다.</p>
<p>결국 정답은 없는 것 같다.</p>
<h3 id="공부-결과물-2">공부 결과물</h3>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/74">DTO 정리</a></li>
</ul>
<h2 id="객체를-매핑하는-라이브러리들에-대해서-알아보았다">객체를 매핑하는 라이브러리들에 대해서 알아보았다.</h2>
<p>대표적으로 <code>ModelMapper</code>, <code>Dozer</code> 등이 있었다.</p>
<h3 id="나의-시간을-낭비시켰던-것">나의 시간을 낭비시켰던 것</h3>
<p>이 라이브러리들은 모두 <code>@Getter</code>, <code>@Setter</code> 가 <code>public</code> 으로 공개되어 있어야 제 역할을 한다. 없다면, 로그 메세지라도 줬으면 좋겠는데 어떠한 말도 없이 동작을 하지 않아서 약간의 혼란을 주었다.</p>
<h2 id="코드-리뷰-discussion">코드 리뷰 Discussion</h2>
<h3 id="configuration-과-bean-에-대해-이해해보자"><code>@Configuration</code> 과 <code>@Bean</code> 에 대해 이해해보자</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/81815a74-5ba1-449f-9da2-c7ca54a86179/image.png" alt=""></p>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/67">자바 @Retention 애노테이션 정리</a><ul>
<li><code>@Retention</code> 을 잘 모르면, 애노테이션 자체를 이해할 수 없다.</li>
</ul>
</li>
<li><a href="https://jake-seo-dev.tistory.com/68">스프링 @Configuration 애노테이션 정리</a></li>
<li><a href="https://jake-seo-dev.tistory.com/69">스프링 @Bean 애노테이션 정리</a></li>
</ul>
<h3 id="롬복-사용의-주의점을-알아보자">롬복 사용의 주의점을 알아보자.</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/4541c14e-738a-421e-8fe9-d2a730febfac/image.png" alt=""></p>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/70">Lombok 을 사용할 때 주의해야 하는 점들</a></li>
</ul>
<h3 id="generatedvalue-의-전략들을-알아보자"><code>@GeneratedValue</code> 의 전략들을 알아보자.</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/50b1750f-1552-45ef-af90-37817f0853f5/image.png" alt=""></p>
<ul>
<li><a href="https://jake-seo-dev.tistory.com/71">Java EE @GeneratedValue 공식문서 번역 정리</a></li>
<li><a href="https://jake-seo-dev.tistory.com/72">Java EE GenerationType 정리</a></li>
</ul>
<h3 id="import--의-사용을-지양하자"><code>import *</code> 의 사용을 지양하자.</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/c04b116c-785c-4e79-92d4-b59f49772981/image.png" alt="">
<img src="https://velog.velcdn.com/images/jakeseo_me/post/f8c1b682-5679-4890-b08d-85f048c541e0/image.png" alt=""></p>
<ul>
<li>Intellij 위 설정에서 패키지 하나에서 몇 개의 import 를 할 때 <code>*</code> 이 되는지를 설정할 수 있다. 저걸 늘려서 <code>import *</code> 이 나오는 것을 최대한 방지하자.</li>
</ul>
<h3 id="메서드-테스트에서-메서드는-행동하는-대상으로-생각하자">메서드 테스트에서 메서드는 행동하는 대상으로 생각하자.</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/52bcef58-0374-46f9-89ba-d4023c80802a/image.png" alt=""></p>
<ul>
<li>메서드를 마치 장소처럼 생각하여 <code>... 메서드에서</code> 라는 표현을 썼는데, 메서드는 행동하는 대상으로 보고 <code>... 메서드는</code>, <code>... 메서드가</code> 등의 표현으로 고쳐야겠다.</li>
</ul>
<h3 id="계층형-테스트를-작성할-때는-합쳤을-때-문장이-잘-어우러지는지-확인하자">계층형 테스트를 작성할 때는 합쳤을 때 문장이 잘 어우러지는지 확인하자.</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/7e3af647-3b30-40ea-8b7f-b41c7da46ae6/image.png" alt=""></p>
<h3 id="bad-request-는-에러가-아니라-응답이다">Bad Request 는 에러가 아니라 응답이다.</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/98d56e61-1fa6-4fa1-866c-237402dc4e6f/image.png" alt=""></p>
<h3 id="없는-은-애매한-표현이-될-수-있다">&#39;없는&#39; 은 애매한 표현이 될 수 있다.</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/fc8ff8cd-98f4-43fb-8a14-b108f148e432/image.png" alt=""></p>
<ul>
<li>없는은 <code>&quot;&quot;</code> 과 같이 공백인 경우와 <code>null</code> 같이 null 인 경우로 구분될 수 있어서 어떤 게 &#39;없는&#39; 인지 알기 어려우니 더 명확한 표현을 사용하자.</li>
</ul>
<h3 id="data-가-어떤-역할을-하는지-설명해보자"><code>@Data</code> 가 어떤 역할을 하는지 설명해보자.</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/993bafae-fda5-4c2f-a692-a31c93083453/image.png" alt=""></p>
<ul>
<li><code>@ToString</code>, <code>@EqualsAndHashCode</code>, <code>@Getter</code> 를 모든 필드에 설정한다.</li>
<li><code>@Setter</code> 필드를 <code>final</code> 이 아닌 필드에 설정한다.</li>
<li><code>@RequiredArgsConstructor</code> 를 설정한다.</li>
</ul>
<h2 id="기타-혼자서-생각해본-것들">기타 혼자서 생각해본 것들</h2>
<h3 id="테스트에서의-생성자-사용">테스트에서의 생성자 사용</h3>
<ul>
<li>테스트 시 한번만 실행했으면 좋겠는 것은 <code>생성자</code> 로 처리하자.</li>
<li>매 테스트 메서드마다 실행할 것만 <code>@BeforeEach</code> 를 사용하자.</li>
<li><code>@BeforeAll</code> 은 <code>static</code> 메서드로 작성해야 해서 별로이다.</li>
</ul>
<h3 id="valid-잊지-않기"><code>@Valid</code> 잊지 않기</h3>
<p>Bean Validation 을 적용하고도 컨트롤러 파라미터 부분에 <code>@Valid</code> 애노테이션이 없으면 Bean Validation 은 작동하지 않는다.</p>
<h3 id="jacoco-테스트-커버리지-제외-기능">jacoco 테스트 커버리지 제외 기능</h3>
<p>테스트 커버리지가 필요 없는 부분들을 제거할 수 있다.</p>
<pre><code>jacocoTestCoverageVerification {
    violationRules {
        rule {
            element = &quot;CLASS&quot;

            limit {
                counter = &#39;LINE&#39;
                minimum = 1
            }

            limit {
                counter = &#39;BRANCH&#39;
                minimum = 1
            }

            excludes = [
                    &quot;com.codesoom.assignment.App&quot;,
                    &quot;com.codesoom.assignment.dto.*&quot;,
                    &quot;com.codesoom.assignment.domain.*&quot;
            ]
        }
    }
}</code></pre><h3 id="망할-javabeans-에러">망할 JavaBeans 에러</h3>
<p>좋은 설계를 위해 <code>Setter</code>, <code>Constructor</code> 등을 제한하면 자꾸 JavaBeans 가 내 앞길을 막는다.</p>
<p><code>Dozer</code> 의 경우에는 <code>Setter</code> 가 없으면 제대로 매핑이 되지 않았다. 앞으로 공식문서에서 이러한 부분들을 잘 찾아봐야겠다. <code>JavaBeans Mapper</code> 라는 이름부터 <code>Setter</code> 가 필요하다는 의미였을 수도 있겠다.</p>
<h3 id="공식문서의-중요성">공식문서의 중요성</h3>
<p>모르는 키워드가 나올 때마다 공식문서에서 찾아서 하나씩 정리하다보면, 언젠가는 인간 스펙이 될 것 같다. 이제 공식문서 정리하는 게 좀 더 익숙해지고 있는데, 이렇게 공식문서 내용을 이해하는 게 익숙해지면 어떤 언어, 어떤 라이브러리, 어떤 프레임웍을 사용하게 되더라도 해낼 수 있다는 자신감이 생길 것 같다.</p>
<p>공식문서의 정리 방법은 처음부터 목차대로 하나하나씩 정리하기보다는 모르는 게 나올 때마다 하나하나 확실히 알아가는 게 좋을 것 같다. 그리고, 보통 공식문서를 검색하면 스펙이 나오는데, 구현체를 구현한 웹사이트에 세부적인 내용이 많다. 이를테면 이번에는 Java ee persistence 에 있는 <code>@GeneratedValue</code>, <code>GenerationType</code> 등에 대해 알아보았는데, 하이버네이트 공식문서에 세부적인 구현을 아주 자세히 설명해놓았었다.</p>
<p>그것도 모르고 java ee 공식문서만 뒤졌더니 굉장히 추상적이고 이해하기 힘든 내용만 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드숨 스프링 편 4주차 회고: 도메인]]></title>
            <link>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-4%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EB%8F%84%EB%A9%94%EC%9D%B8</link>
            <guid>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-4%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EB%8F%84%EB%A9%94%EC%9D%B8</guid>
            <pubDate>Tue, 19 Apr 2022 17:23:04 GMT</pubDate>
            <description><![CDATA[<h2 id="4주차-이번에는-무엇을-했는가">4주차, 이번에는 무엇을 했는가?</h2>
<h3 id="클린-아키텍처라는-것을-처음-배웠다">클린 아키텍처라는 것을 처음 배웠다.</h3>
<p>클린 코드, 클린 xxx 등 많은 클린 시리즈를 배워봤는데, 이번엔 클린 아키텍처라는 것을 처음 봤다. 스프링을 배우면서 자연스레 단순히 <code>@Controller</code> 는 웹 연결, <code>@Service</code> 에는 비즈니스 로직, <code>@Repository</code> 는 디비 연결 관련 로직을 넣는다고만 막연히 알고 있었는데, 이번 기회에 조금 더 정리된 아키텍처 개념을 알게 됐다.</p>
<p>아키텍처를 통해 계층을 나누게 되면 결국에 테스트하기 쉬운 형태가 되며, 외부 모듈이 바뀌었을 때 유연하게 대응할 수 있는 애플리케이션이 된다.</p>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/7d8e4a74-7343-4d9e-8cbe-c69c844319e7/image.png" alt=""></p>
<p><strong>핵심 규칙</strong></p>
<ul>
<li>핵심은 관심사의 분리라는 목적을 달성하는 것이다.</li>
<li>관심사를 분리하며, 테스트가 용이한 구조를 만들어낸다.</li>
<li>UI에 독립적이어야 한다.</li>
<li>외부 환경에 독립적이어야 한다.<ul>
<li>DB 등이 바뀌어도 상관없어야 한다.</li>
</ul>
</li>
<li>바깥쪽 써클은 안쪽 써클에 대해 알 수 있지만, 안쪽 써클은 바깥쪽 써클에 대해 몰라야 한다.</li>
</ul>
<p><strong>각 계층에 대한 간략한 설명</strong></p>
<ul>
<li><code>엔티티</code>: 비즈니스 규칙을 캡슐화한 것이다. 다른 계층에 어떤 변화가 일어나더라도 웬만해선 영향을 받지 않는다.</li>
<li><code>유즈 케이스</code>: 스프링에서 <code>Service</code> 에 대치되는 것이다. 비즈니스 규칙을 지닌다.</li>
<li><code>인터페이스 어댑터</code>: 스프링에서 <code>Controller</code>, <code>Repository</code> 등에 해당하는 것이다. 유즈 케이스와 Web, UI, DB, Device 등의 영역을 연결해준다.</li>
<li><code>프레임워크와 드라이버</code>: DB 구현체와 같은 가장 구체적인 것들이 있다. 안쪽 써클들과 통신할 수 있는 glue code 를 많이 작성한다.</li>
</ul>
<p><strong>계층간의 경계를 넘을 때는?</strong></p>
<ul>
<li>의존성 역전 원칙을 이용한다.</li>
<li>인터페이스인 <code>Use Case Input Port</code> 와 <code>Use Case Output Port</code>를 이용해 서로의 구체적인 타입을 몰라도 커뮤니케이션이 가능하다.</li>
</ul>
<p><strong>최종 목적은?</strong></p>
<ul>
<li>독립적으로 동작하는 테스트 가능한 시스템을 만들자.</li>
<li>프레임워크와 드라이버가 바뀌어도 정상동작할 수 있는 유연한 시스템을 만들자.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/f1e2e1af-e29f-4127-bda4-87d278e77acf/image.png" alt=""></p>
<p><strong>참고자료</strong></p>
<p><a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html">클린 아키텍처 by Robert C. Martin</a></p>
<p><strong>직접 번역한 것</strong></p>
<p><a href="https://jake-seo-dev.tistory.com/65">클린 아키텍처란? - (직접 번역한 Robert C. Martin 의 게시글)</a></p>
<h3 id="스프링-데이터-jpa-를-사용해서-api-를-구성해봤다">스프링 데이터 JPA 를 사용해서 API 를 구성해봤다.</h3>
<p>스프링 데이터 JPA 는 JPA 를 기반으로 한 데이터 엑세스 계층을 쉽게 구현할 수 있도록 도와주는 도구이다. 기본적인 CRUD 는 interface 를 통해 실제 구현 코드작성 없이도 자동 구현이 되게 만들어준다. 또한 <code>Pagination</code>, <code>Auditing</code> 등 DB 부가기능도 DB 에 구애받지 않고 쉽게 구현할 수 있도록 도와준다.</p>
<blockquote>
<p>JPA 를 이용한 서비스계층 클래스에 <code>@Transactional</code> 애노테이션을 거는 것만으로, 메서드 호출이 종료된 후 엔티티 수정 시 자동 반영이 되는 등의 기능도 있었다.</p>
</blockquote>
<h3 id="자바-진영의-대표적인-orm-인-jpa-를-사용해보았다">자바 진영의 대표적인 ORM 인 JPA 를 사용해보았다.</h3>
<blockquote>
<p>Object–relational mapping (ORM, O/RM, and O/R mapping tool) in computer science is a programming technique for converting data between type systems using object-oriented programming languages. This creates, in effect, a &quot;virtual object database&quot; that can be used from within the programming language. There are both free and commercial packages available that perform object–relational mapping, although some programmers opt to construct their own ORM tools.</p>
</blockquote>
<p>ORM 이란, Object Relational Mapping 으로 관계형 DB 등에 저장된 데이터를 객체지향 프로그래밍 언어로 매핑할 수 있도록 도와준다.</p>
<h3 id="관계형-db-와-자바-객체와의-괴리에-대해-공부해보았다">관계형 DB 와 자바 객체와의 괴리에 대해 공부해보았다.</h3>
<h4 id="불일치가-발생하는-이유-1-식별-기준">불일치가 발생하는 이유 1: 식별 기준</h4>
<ul>
<li>자바 객체는 식별을 &#39;메모리 주소&#39;를 기준으로 한다.</li>
<li>데이터베이스의 데이터는 식벽을 &#39;식별자&#39;를 기준으로 한다.</li>
<li>자바 객체의 데이터를 데이터베이스에 저장하는 순간 객체가 사용하던 식별자는 사라진다.</li>
</ul>
<h4 id="불일치가-발생하는-이유-2-다수의-데이터를-저장할-때">불일치가 발생하는 이유 2: 다수의 데이터를 저장할 때</h4>
<ul>
<li>데이터베이스는 최적의 효율을 위해 외래키를 이용한 참조를 이용해 각각 다른 테이블에 저장한다.</li>
<li>자바에서는 객체 타입의 컬렉션을 이용해 다수의 데이터를 저장한다.</li>
</ul>
<blockquote>
<p>JPA 는 데이터를 다루는 행위를 컬렉션을 다루는 것처럼 해준다.</p>
</blockquote>
<h3 id="mock-을-이용한-테스트를-이용해-tdd-를-수련했다">Mock 을 이용한 테스트를 이용해 TDD 를 수련했다.</h3>
<p>Mock 을 이용한 테스트를 만든다고 해서 사실 내가 작성한 프로그램이 100% 정상적으로 동작하는지에 대해 테스트할 수는 없다. 그러나, 다음과 같은 이점이 있다.</p>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/a6397793-92ba-4cb3-b570-daa0eaff5ab8/image.png" alt=""></p>
<blockquote>
<p>그냥 개발을 엄청 빨리할 수 있게 된다. 설계와 관련된 사항들을 인지하며 진행할 수 있게 된다.</p>
</blockquote>
<h2 id="과제-코드리뷰에서-배운-것">과제 코드리뷰에서 배운 것</h2>
<h3 id="서비스-분리">서비스 분리</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/ea2929b2-50a9-488b-8ec2-798ecf6c7b6a/image.png" alt=""></p>
<p>단순히 <code>Service</code> 하나를 보는 것이 아닌 조회용 - <code>QueryService</code> 수정/저장용 - <code>CommandService</code>로 분리해보자는 요청을 받았다.</p>
<p>자세히는 모르지만 <a href="https://martinfowler.com/bliki/CQRS.html">마틴 파울러의 CQRS</a> 에서 나오는 내용인 것 같았다. 나중에 더 알아봐야겠다.</p>
<p><a href="https://justhackem.wordpress.com/2016/09/17/what-is-cqrs/">좋은 워드 프레스 블로그 포스팅</a></p>
<h3 id="dto-와-관련된-내용을-더-자세히-알아보게-됨">DTO 와 관련된 내용을 더 자세히 알아보게 됨</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/103ae164-ea75-4762-b878-22a991953d2d/image.png" alt=""></p>
<p><a href="https://martinfowler.com/eaaCatalog/dataTransferObject.html">마틴 파울러의 DTO 관련 글</a>을 읽고서 DTO 가 나온 배경과 현재 내가 사용하는 방식에 대해서 인지하게 됐다. 현재 내가 사용하는 방식은 Domain Model 과 Presentation Layer 와의 괴리를 극복하기 위해 연결고리정도로 사용하고 있었다.</p>
<blockquote>
<p>원래 DTO는 굳이 도메인 모델을 지키며 데이터를 주고받을 때 네트워크 오버헤드가 많이 발생하여 한 번에 모든 데이터를 주고 모든 데이터를 받기 위해 나왔다고 한다.</p>
</blockquote>
<h2 id="어떤-기분을-느꼈는가">어떤 기분을 느꼈는가?</h2>
<h3 id="tdd-를-하며-느꼈던-기분">TDD 를 하며 느꼈던 기분</h3>
<p>일단 테스트를 만들고 개발한다는 자체가 추후 리팩토링에도 대비가 되며, 간단한 클래스의 의존성 설계도 짚어가며 하나씩 진행할 수 있고, 내가 어떤 기능을 만들지에 대한 목적성도 확실히 가져갈 수 있었다. 그래서 상당한 안정감을 느꼈다.</p>
<p>그런데 한편으로는 불안감을 느꼈다. 과연 이렇게 모든걸 일일이 테스트로 작성하는 것이 옳은가 하는 물음이 들었다. 아직 테스트를 만드는 속도가 느려서 그런지 상당히 시간을 잡아먹고 있다. 아직 많은 수련이 필요할 것 같다.</p>
<h3 id="클린-아키텍처를-살짝-맛보고-느낀-기분">클린 아키텍처를 살짝 맛보고 느낀 기분</h3>
<p>이미 선대의 개발자들은 많은 엔터프라이즈 앱을 구성해보며, 많은 구현 부분이 반복된다는 느낌을 받았을 것이다. 거기서 각자의 책임을 나누어 최대한 깔끔한 그림으로 만든 것이 클린 아키텍처라고 생각한다.</p>
<p>앞으로 책임이 마구잡이로 흩어지고 테스트가 어렵고 모듈화되지 않은 소프트웨어를 생산하는 것은 지양하고 할 수 있는 만큼 상황에 맞게 적절히 책임이 분리된 아키텍처를 가진 소프트웨어를 만들도록 지향해야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드숨 스프링 편 3주차 회고: 테스트]]></title>
            <link>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-3%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%ED%85%8C%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-3%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%ED%85%8C%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Wed, 13 Apr 2022 13:43:19 GMT</pubDate>
            <description><![CDATA[<h2 id="이번-주에-한-것">이번 주에 한 것</h2>
<p><strong>간단하게 말하면, 테스트를 작성했다.</strong></p>
<ul>
<li>유닛 테스트 작성</li>
<li>계층형 테스트 작성<ul>
<li>준비, 시작, 단언 (AAA, arrange-act-assert) 규약을 약간 변형했다.</li>
<li>Given, When, Then 에서 Describe, Context, It 이 된다.</li>
</ul>
</li>
<li>Controller 에 대한 Mock 테스트 작성<ul>
<li><code>@WebMvcTest</code> 를 이용한 웹 레이어 테스트</li>
<li><code>@AutoConfigureMockMvc</code> 를 이용한 통합 테스트</li>
</ul>
</li>
<li><a href="https://jake-seo-dev.tistory.com/64">Test Double 에 대한 학습</a></li>
<li>Mockito 활용법에 대한 학습</li>
</ul>
<h3 id="배운-것-1-테스트-코드조차-코드의-퀄리티가-중요하다">배운 것 1: 테스트 코드조차 코드의 퀄리티가 중요하다.</h3>
<ul>
<li>의도를 명확히 드러내기 위해서 JUnit5 가 기본적으로 제공하는 단정문(Assertion)이 아닌 AssertJ 라이브러리를 따로 설치해서 이용했다.</li>
<li>고정적으로 사용되는 데이터를 Fixture 라는 형태로 만들어두어 재사용했다.</li>
<li>그 외에도, 비슷한 메서드가 매 테스트마다 쓰이는 경우엔 상속 등을 이용할 수 있었고 일반 코드 퀄리티를 지키듯 테스트 코드도 코드 퀄리티를 지켜나갔다.</li>
</ul>
<h3 id="배운-것-2-테스트-코드는-항상-꼼꼼하게-작성해야-한다">배운 것 2: 테스트 코드는 항상 꼼꼼하게 작성해야 한다.</h3>
<ul>
<li>특히 정상 작동하는 것 외에 정상작동하지 않을만한 것에 집중해보자.<ul>
<li>경계값, 예상치 못한 입력값, 쉽게 생각할 수 있는 틀린 값 등을 테스트해보자.</li>
</ul>
</li>
</ul>
<h3 id="배운-것-3-테스트-대상-코드를-격리해보자">배운 것 3: 테스트 대상 코드를 격리해보자.</h3>
<ul>
<li>스프링의 웹 아키텍처에서 가장 널리 쓰이는 레이어로는 <code>Controller</code>, <code>Service</code>, <code>Repository</code> 가 있다. 이를 레이어 별로 나눠서 잘 테스트할 수 있다면, 해당 레이어는 다른 레이어의 영역에 침범하지 않는 것으로 간주할 수 있다.</li>
<li><code>Mock</code> 을 적극 활용하면 테스트 대상 코드를 격리할 수 있다.<ul>
<li>단, <code>Mock</code> 을 이용한 격리는 상호작용하는 다른 객체가 올바르게 값을 준다는 가정 하에 이뤄지는 테스트이니 꼭 통합 테스트로 다시한번 검증해보자.</li>
</ul>
</li>
</ul>
<h3 id="배운-것-4-mock-은-왜-사용하는가">배운 것 4: Mock 은 왜 사용하는가?</h3>
<ul>
<li>객체간의 관계를 알 수 있다.</li>
<li>&quot;Mocking 이 너무 어렵다는 것은 =&gt; 결합도가 높다. =&gt; 설계 개선이 필요하다.&quot;</li>
</ul>
<h2 id="과제-풀이-영상-리뷰">과제 풀이 영상 리뷰</h2>
<h3 id="과제를-하며-배운-것-1-mock-을-적극-활용하여-코드-격리를-한다">과제를 하며 배운 것 1: Mock 을 적극 활용하여 코드 격리를 한다.</h3>
<ul>
<li>Mockito 에는 <code>spy()</code>, <code>given()</code>, <code>verify()</code>, <code>eq()</code>, <code>any()</code> 등 어떤 객체든 흉내낼 수 있는 다양한 메서드를 제공한다.</li>
<li>풀이 영상에서는 이를 적극 활용하여 각각의 레이어를 나눠 테스트했다.
1) <code>Service</code> 레이어에서는 Mocking 없이 꼼꼼한 유닛 테스트로 동작을 보장했다.
2) <code>Controller</code> 레이어에서는 <code>Controller</code> 에 정상적인 <code>Service</code> 가 주입되어 있다고 가정하에 <code>Controller</code> 객체가 올바르게 동작하는지 테스트했다.
3) <code>Web</code> 레이어에서는 <code>mockMvc</code>를 이용해서 실제로 HTTP 요청을 하는 것처럼 테스트를 해보았다.</li>
</ul>
<h2 id="코드-리뷰에서-지적받은-것">코드 리뷰에서 지적받은 것</h2>
<h3 id="parameterizedtest-고려의-필요성"><code>ParameterizedTest</code> 고려의 필요성</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/b855f237-3662-4384-922e-b22f26526f9d/image.png" alt=""></p>
<p><code>ParameterizedTest</code> 의 경우, 아직 한번도 사용해본 적이 없는데, 특정한 파라미터가 오면 이뤄지는 동작이라는 것을 더 강조하고 싶을 때 사용해보면 괜찮을 것 같다.</p>
<p>위에서는 <code>task.setTitle()</code> 에 오는 파라미터에 따라 달라지는 동작을 표현했으면 더 좋았을 것 같다.</p>
<h3 id="테스트에서-사용된-애매한-단어-잘못된">테스트에서 사용된 애매한 단어 &#39;잘못된&#39;</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/e64631dc-bb0b-4e9e-a145-0b716a4989b3/image.png" alt=""></p>
<p><code>잘못된</code> 이라는 단어는 구체적이지 않다. <code>존재하지 않는 ID</code>, <code>형식에 맞지 않는 ID</code> 등으로 테스트의 목적을 작성할 때는 더욱 구체적으로 작성해보자.</p>
<h3 id="너무-긴-변수명은-쓸데-없는-주의를-끈다">너무 긴 변수명은 쓸데 없는 주의를 끈다.</h3>
<p><img src="https://velog.velcdn.com/images/jakeseo_me/post/34029351-0d89-4ba2-8e89-9e30efdb7435/image.png" alt=""></p>
<p>위에서 <code>taskArgumentWithTitle</code> 은 사실 딱히 길게 쓸 이유는 없는 변수명이다. 너무 길게 지어서 쓸데 없는 주의를 끌지 말자.</p>
<h2 id="내가-느낀-것">내가 느낀 것</h2>
<ul>
<li>테스트를 이용해 코드를 빠르게 작성하면, 쉽게 리팩토링할 수 있다는 장점이 있다.</li>
<li>테스트 코드에서도 코드의 퀄리티를 지키려 노력해야 한다.</li>
<li>테스트 영역을 격리하여 관심사의 분리를 확실히 하고, 어떤 영역에서 문제가 발생했는지 더 확실히 알아보자.</li>
</ul>
<h2 id="여전히-남은-의문사항">여전히 남은 의문사항</h2>
<ul>
<li>모든 메서드에 대해 테스트를 만드는 것이 바람직한가?<ul>
<li>가끔은 시간낭비가 아닐까? 일단은 학습 단계이니 작성해보자.</li>
</ul>
</li>
<li><code>@Service</code> 를 테스트할 때 통합 테스트와 <code>Mock</code> 테스트 어떤 것을 우선시 해야하는가?<ul>
<li>분리 테스트: <code>@WebMvcTest</code> 를 사용하고 <code>Service</code> 에 대해 <code>@MockBean</code> 을 사용하는 것</li>
<li>통합 테스트: <code>@SpringBootTest</code> 와 <code>@AutoConfigureMockMvc</code> 를 사용하는 것</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드숨 스프링 편 2주차 회고: 스프링 프레임워크 사용]]></title>
            <link>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-2%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-2%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 03 Apr 2022 15:03:21 GMT</pubDate>
            <description><![CDATA[<h2 id="이번-주는-무엇을-했는가">이번 주는 무엇을 했는가?</h2>
<ul>
<li>스프링 웹을 이용해 Todo API 를 작성했다.</li>
</ul>
<blockquote>
<p>Week1 에는 프레임워크를 사용하지 않고 작성해보았었다.</p>
</blockquote>
<h2 id="어땠는가">어땠는가?</h2>
<ul>
<li>당연하지만, 프레임워크를 쓰지 않을 때보다 편리했다.</li>
<li>프레임워크를 쓸 때, 어떤 것들이 자동화되는 지에 대해서 더 생각해보게 되었다.</li>
<li>프레임워크가 정확히 어떤 기능을 제공하는지, 어떤 점을 편리하게 하는지에 대해서도 더 조사하게 되었다.</li>
</ul>
<h2 id="이번-주는-기술적으로는-무엇을-배웠는가">이번 주는 기술적으로는 무엇을 배웠는가?</h2>
<p>일단은 피드백을 제외하고 아래와 같은 것들을 배웠다. 정리한 것들은 최대한 포스팅을 작성해보았다.</p>
<ul>
<li>스프링 웹</li>
<li>Marko</li>
<li><a href="https://jake-seo-dev.tistory.com/60">Springboot-dev-tools</a></li>
<li><code>@CrossOrigin</code></li>
<li><code>MockMvc</code><ul>
<li><a href="https://jake-seo-dev.tistory.com/62">한글이 깨질 때 해결 방법</a></li>
</ul>
</li>
<li>Configuration in Gradle</li>
<li><a href="https://jake-seo-dev.tistory.com/63">Plugins in Gradle</a></li>
<li><a href="https://jake-seo-dev.tistory.com/59">javadoc 작성 방법</a></li>
<li><a href="https://jake-seo-dev.tistory.com/61">자바 <code>synchronized</code> 블록문</a></li>
</ul>
<h2 id="기술적인-것-외에-깨달음은-무엇을-얻었는가">기술적인 것 외에 깨달음은 무엇을 얻었는가?</h2>
<ul>
<li>프레임워크에서 제공하는 코드를 이용할 때는 적어도 1번쯤은 주석을 꼼꼼히 읽어보자.<ul>
<li><code>@RequestMapping</code> 애노테이션에 달린 주석을 읽으며 느낀 부분이 생각보다 많다.</li>
</ul>
</li>
<li>나는 어떻게 다른 개발자들과 차별점을 두고 더욱 경쟁력을 가질 것인가?<ul>
<li>남들보다 공식문서를 잘 읽고 영어에 친숙한 개발자가 되자. <code>from 여러 공식문서 지식들을 얻으며...</code></li>
<li>자동화에 누구보다 힘써서 효율적으로 output을 만들어보자. <code>from 종립님의 vim 사용...</code></li>
</ul>
</li>
</ul>
<h2 id="이번-주를-거쳐보니-다음엔-무엇을-배워보고-싶었는가">이번 주를 거쳐보니, 다음엔 무엇을 배워보고 싶었는가?</h2>
<ul>
<li>e2e 테스트 방법</li>
<li>CORS 완벽 정리해보기</li>
<li>Rest Tutorial 읽어보기</li>
<li>vim 사용 방법</li>
<li><a href="https://johngrib.github.io/wiki/junit5-nested/">계층 구조의 테스트 코드 작성하기</a></li>
</ul>
<h2 id="내가-받았던-리뷰를-리뷰하기">내가 받았던 리뷰를 리뷰하기</h2>
<h3 id="새로운-디펜던시를-추가할-때-풀리퀘스트에-기능-남겨보기">새로운 디펜던시를 추가할 때, 풀리퀘스트에 기능 남겨보기</h3>
<p><img src="https://media.vlpt.us/images/jakeseo_me/post/a13ee46e-8a3a-42b2-8715-5c25732f5349/image.png" alt=""></p>
<ul>
<li>다른 개발자들이 내가 추가한 디펜던시가 어떤 것인지 어떤 기능이 있는지 쉽게 알게 해주자.</li>
</ul>
<h3 id="import-문을-작성할-때는-보다는-확실히-어떤-것을-추가하는지-명시해주자">import 문을 작성할 때는 <code>.*</code>보다는 확실히 어떤 것을 추가하는지 명시해주자.</h3>
<p><img src="https://media.vlpt.us/images/jakeseo_me/post/4534026d-0ec8-4788-a61e-c064465f0c99/image.png" alt=""></p>
<ul>
<li>이렇게 나눠주면, 내가 어떤 패키지를 이용하고 있는지 더 정확히 알 수 있는 장점도 있다.</li>
</ul>
<blockquote>
<p>auto import 기능을 이용하면, 이렇게 기껏 나눠놓은 것이 다시 <code>.*</code>로 바뀌는 것도 주의하자.</p>
</blockquote>
<h3 id="멀티-스레드에서-동시성-문제-고려하기">멀티 스레드에서 동시성 문제 고려하기</h3>
<p><img src="https://media.vlpt.us/images/jakeseo_me/post/ac66f925-8038-44f2-a3d1-6d3feb9ad814/image.png" alt=""></p>
<ul>
<li>멀티스레드에서 숫자를 계산할 때 프리미티브 타입보다는 <code>Atomic...</code>으로 시작하는 클래스를 이용하자.</li>
<li><a href="https://jake-seo-dev.tistory.com/61">관련 포스팅</a></li>
</ul>
<h3 id="테스트-코드에-대한-displayname을-잘-적어보기">테스트 코드에 대한 <code>@DisplayName</code>을 잘 적어보기</h3>
<p><img src="https://media.vlpt.us/images/jakeseo_me/post/49166509-a285-429b-8ee8-b4c00c8289a5/image.png" alt=""></p>
<ul>
<li>나중에는 명확히 <code>Request: POST /tasks, Response: status 201, body Task JSON</code> 과 같이 불필요한 표현 없이 적어보자.</li>
</ul>
<h3 id="requestmapping의-설명을-적어보기"><code>@RequestMapping</code>의 설명을 적어보기</h3>
<p><img src="https://media.vlpt.us/images/jakeseo_me/post/c736e7c8-0209-4134-b706-a96365e329ae/image.png" alt=""></p>
<ul>
<li>유연한 메서드 시그니처 메서드를 가진 요청 핸들링 클래스에 웹 요청을 매핑하는 애노테이션이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드숨 스프링 편 1주차 회고: 기본 HTTP API 만들기]]></title>
            <link>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-1%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@jakeseo_me/%EC%BD%94%EB%93%9C%EC%88%A8-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%8E%B8-1%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 27 Mar 2022 09:48:00 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>참고: 강의를 듣게 된 배경과 느낀점을 먼저 서술한 뒤에 구체적으로 어떤 것들을 피드백 받았는지 적었습니다. 코드숨 강의에 대해 간단히 느낀점만 궁금해서 들어오셨다면 위쪽 부분만 읽으시고 아래쪽은 무시하셔도 됩니다.</p>
</blockquote>
<h2 id="코드숨-강의를-듣게-된-배경">코드숨 강의를 듣게 된 배경</h2>
<p>코드숨 과정은 포트폴리오 제작 과정까지 합쳐서 <strong>330만원</strong>이다. 누군가에게는 충분히 지불할 수 있는 돈이겠지만, 박봉을 받으며 일하는 나에게는 매우 큰 돈이다. 그럼에도 불구하고 코드숨 과정을 수강한 이유는 역시나 성장에 대한 갈증 때문이었다. 내가 현재 일하는 조직은 매우 작은 조직이며, 좋은 개발문화를 경험해본 사람이 없다.</p>
<p>나는 소위 네카라쿠배라 불리는 좋은 개발문화를 가진 회사에 입사해본 적이 없다. <code>코드 리뷰</code>는 나에겐 유니콘처럼 먼 존재이며, <code>테스트코드 작성</code>은 회사에서 나 외에는 하는 사람이 없다. 나도 그나마 테스트코드 작성 강의 영상을 보고 이것저것 따라하려 시도할 뿐, 제대로 하고 있는지는 모른다. <code>객체지향 설계</code>, <code>좋은 코드, 설계에 대한 고민</code>도 우리 회사에서는 현실과 동떨어져 있다.</p>
<p><strong>과연 좋은 개발조직은 어떤 느낌일까? 너무 궁금해서 비싼 돈을 내고 코드숨 교육 과정을 듣게 되었다.</strong></p>
<p>사실 비싼만큼 이 강의를 진짜 들어야할지 많은 고민을 하고 후기를 찾아보고 했는데, 결국 <strong>트레이너 중에 평소에 존경하던 개발자였던 종립님과 코딩의신 아샬님이 계신다는 것이 내 의사결정에 큰 영향을 미쳤다.</strong></p>
<blockquote>
<p>혹시나라도 코드숨 강의를 들을까 말까 고민하는 예비 수강생이 있을 수 있는데, 마지막 주차 때 내가 느낀 장점, 단점, 누가 들으면 좋을지에 대한 글도 정리해서 올리려 한다.</p>
</blockquote>
<h2 id="강의를-1주차까지-들으며-깨달은-것들">강의를 1주차까지 들으며 깨달은 것들</h2>
<p>아직 1주차까지만 들어봐서 많은 깨달음을 얻지는 못했다.</p>
<h3 id="작은-설계부터-소프트웨어를-만들-때-내가-잘못-생각하던-부분을-깨달았다">작은 설계부터: 소프트웨어를 만들 때 내가 잘못 생각하던 부분을 깨달았다</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/9bfa8be5-8691-43ce-a7c5-ae78c45ca4d4/image.png" alt=""></p>
<p>위와 같은 커멘트를 받았는데, 내가 요즘 하고 있는 실수를 정확히 관통하는 이야기였다. 자기 개발을 위해 이것저것 강의를 보고 새로운 기술을 공부하고 난 뒤에 난 확실히 많은 기술들의 존재에 대해 인지하게 되었다. 그리고 그것을 실무에 적용시키려고 많은 노력을 했다.</p>
<p>그런데 때때로 내가 그 기술을 사용해보려고 마구잡이로 코드를 끼워맞추려고 할 때가 있었다. 장황하게 끼워맞추는 행위는 어쩌면 문제 해결이라는 소프트웨어의 본질에서 멀어지게 한다. 다음부터 이러한 실수를 하지 않도록 주의해야겠다.</p>
<p>동작하는 프로그램을 최소한의 설계로 만든 뒤에 지속적 리팩토링으로 소프트웨어를 개선해나가자.</p>
<h3 id="테스트를-작성하는-습관을-들이는-게-확실히-이득이라는-것을-깨달았다">테스트를 작성하는 습관을 들이는 게 확실히 이득이라는 것을 깨달았다</h3>
<p>API 를 작성한 뒤에 Postman 이나 HTTPie 와 같은 도구로 계속 내 서버에 요청을 보내고 결과를 확인하는 나의 모습을 보았다.</p>
<p>사실 이건 애초에 요구사항을 받았을 때 해당 요구사항대로 테스트코드를 작성해놓았으면 굳이 서버키고 API 날려보고 눈으로 결과 하나씩 확인하고 할 필요가 없었던 것이다.</p>
<p>내가 작성할 프로그램의 동작 목표를 테스트라는 형태로 작성해두고 작성이 완료되었다면 테스트가 통과되는지 확인하는 식으로 프로그램을 작성해보자.</p>
<h3 id="영어로-된-딱딱한-공식문서를-읽는-버릇을-빨리-들여야겠다는-것을-깨달았다">영어로 된 딱딱한 공식문서를 읽는 버릇을 빨리 들여야겠다는 것을 깨달았다</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/31c1f3cf-089b-4b90-9e5c-2c90482da4de/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/4f660443-fef1-4b2a-b5ff-eb4e666af6a1/image.png" alt=""></p>
<p>종립님이 해주신 말인데, &#39;블로그에 글을 작성한 개발자는 나보다 더 초보개발자일 수 있다.&#39;는 것이다. 종종 영어 읽기가 귀찮아서 한글로 검색하고 대충 작성된 글로 문제를 해결하려 하는 경우가 있는데, 번역기를 이용하더라도 공식문서 읽는 습관을 꼭 들여야겠다.</p>
<h2 id="구체적-피드백들">구체적 피드백들...</h2>
<p>본격적으로 어떤 구체적 피드백들을 받았는지 정리해본다.</p>
<h3 id="1주차-과제의-내용">1주차 과제의 내용</h3>
<ul>
<li>자바언어를 이용해 ToDo REST API 앱을 작성해야 한다.<ul>
<li>HTTP Content 에 JSON 형식의 Input Output 을 통해 간단한 CRUD 를 제공한다.</li>
</ul>
</li>
</ul>
<h2 id="과제에서-피드백-받은-것들">과제에서 피드백 받은 것들</h2>
<h3 id="의도가-드러나지-않은-코드-리팩토링">의도가 드러나지 않은 코드 리팩토링</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/f2cb4a1e-ea19-4a03-957c-0c6c7baf56a5/image.png" alt=""></p>
<pre><code class="language-java">try(OutputStream responseBody = exchange.getResponseBody()) {
    exchange.sendResponseHeaders(httpResponse.getStatusCode(), httpResponse.getContent().getBytes(UTF_8).length);
    responseBody.write(httpResponse.getContent().getBytes(UTF_8));
    responseBody.flush();
}</code></pre>
<ul>
<li>위 코드에서 <code>exchange.sendResponseHeaders(httpResponse.getStatusCode(), httpResponse.getContent().getBytes(UTF_8).length);</code> 부분에서 갑자기 왜 <code>length</code>를 넘기는지 한 눈에 이해가지 않을 수 있다.<ul>
<li>그 외에도 <code>.</code>이 너무 많고 글자가 많아서 한 눈에 들어오는 코드가 아니다.</li>
</ul>
</li>
</ul>
<pre><code class="language-java">exchange.sendResponseHeaders(httpResponse.getStatusCode(), httpResponse.getContentLength());
responseBody.write(httpResponse.getContentAsByte());</code></pre>
<p><code>HttpResponse</code> 객체에 <code>getContentLength()</code> 라는 메서드를 만들어 코드의 의도를 좀 더 명확히 해주었다.</p>
<blockquote>
<p>개발자는 보통 작성된 코드를 읽으며, 한줄 한줄이 어떤 의도를 가지고 작성되었는지 생각하는 과정을 거치고 자신의 코드를 적절한 위치에 삽입한다. 소위 말하는 &#39;읽기 어려운 코드&#39;를 작성할수록 협업과 거리가 멀어지고, 생산성도 떨어진다. 나 자신도 며칠 뒤에는 내 코드를 이해할 수 없는 상황을 맞딱뜨리지 말자.</p>
</blockquote>
<h3 id="switch-문에서-default-의-누락">switch 문에서 default 의 누락</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/8afaf385-9d42-4801-a5f3-8fe823ff7dcd/image.png" alt=""></p>
<p><code>switch... case</code>문에서는 반드시 <code>default</code>를 작성해주자.</p>
<h3 id="헷갈리는-메서드명">헷갈리는 메서드명</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/4d4582a3-fc2e-4f14-b53b-9c6a191ba1ff/image.png" alt=""></p>
<p><code>parseJsonToTask</code>와 <code>parseTaskToJson</code>는 이름이 매우 비슷하다. 헷갈리는 이름을 자제하고 의도를 좀 더 명확히하자. 위 경우에는 최종에는 <code>getJson</code>과 <code>getTask</code>로 짧게 바꾸었다. <code>from A to B</code>와 같이 이름을 지을 필요가 없는 이유는 파라미터가 이미 <code>from</code>을 알려주고 있기 때문이다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/22dd11e9-310a-438c-ac9f-e0d52c39fbdb/image.png" alt=""></p>
<p>이 경우도 위와 마찬가지의 이유였다.</p>
<h3 id="에러메세지-작성-방법">에러메세지 작성 방법</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/69be646f-663a-4132-8939-7257b67dfc61/image.png" alt=""></p>
<p>에러 메세지는 1. 무엇이 잘못된지 알려주고 2. 어떻게 해야 하는지 알려주어야 한다.</p>
<h3 id="시그니쳐만-보고-알아보기-힘든-메서드">시그니쳐만 보고 알아보기 힘든 메서드</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/05d3dd7a-4213-4970-b025-777041747374/image.png" alt=""></p>
<p>일단 여기서 지적받은 점은 <strong>함수가 무엇을 하는지 함수의 시그니쳐만 보고 이해하기 어렵다</strong>는 것이었다.</p>
<p>내가 처음 지었던 메서드 이름은 장황하게도 <code>processPathVariablesTaskIdWithStrategy</code>이다. 내가 이렇게 길게 메서드 이름을 짓게 된 이유는 메서드가 하는 일을 명확히 표현하는 메서드 이름을 짓고 싶어서였다.</p>
<p>그런데 메서드 이름이 이렇게 길게 나온다는 것은 한 메서드에서 가진 책임도 그만큼 많다는 뜻일 것이다. 모든 코드는 덩어리가 커질수록 이해하기 어려워진다고 믿는다. 그래서 적절히 객체, 메서드 단위로 관심사별 코드 분리를 해야 할 것이다.</p>
<p>해당 메서드 내부에는 많은 책임이 있었는데,</p>
<ol>
<li>올바른 PathVariable 이 들어왔는지 검증한다.</li>
<li>올바른 PathVariable 이 들어왔다면, PathVariable 이 제공하는 <code>taskId</code>는 실제로 존재 하는지 찾아보고 없다면, 예외를 던진다.</li>
<li>해당 <code>taskId</code>를 이용해 <code>Task</code> 객체를 찾는다.</li>
<li>찾은 <code>Task</code> 객체를 이용해 <code>Strategy</code>에 따른 코드를 적용한다.</li>
<li>적용 결과를 <code>HttpResponse</code>로 반환한다.</li>
</ol>
<p>간단히 살펴봐도 5가지나 책임을 가지고 있었다. 나중에 하나하나 잘게 분리하니 훨씬 알아보기가 쉬워졌다.</p>
<h3 id="upper_snake_case-에-대한-잘못된-사용">UPPER_SNAKE_CASE 에 대한 잘못된 사용</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/7502f41b-7482-437a-8294-6eaaf819c378/image.png" alt=""></p>
<p>UPPER_SNAKE_CASE 는 멤버 필드 중 <code>static final</code>을 가진 경우에만 사용하는 것인데, 메서드 내부 <code>final</code> 변수에 UPPER_SNAKE_CASE 를 잘못 적용했다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/57079be5-60b7-40ff-a3d3-465fd9ad3588/image.png" alt=""></p>
<p>위는 <a href="https://www.oracle.com/java/technologies/javase/codeconventions-namingconventions.html">오라클 공식문서</a>에 있는 내용이다. 클래스 상수와 ANSI 상수에만 적용하라고 되어있다.</p>
<h3 id="생성자에서-너무-많은-일을-한다">생성자에서 너무 많은 일을 한다.</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/23fe7a65-d12b-4ee9-9a6c-8cf93b37970b/image.png" alt=""></p>
<p>생성자에 너무 많은 코드를 넣는 것을 피하자. <code>final</code> 로 된 멤버 변수들을 채우려다가 생성자를 너무 복잡하게 만들어버리는 우를 범했다.</p>
<p>일단 간단한 메서드명으로 의도는 명확히 정리해두었는데, 아직 답이 안달려 어떻게 해야하는지 정확히 모르겠다.</p>
<h3 id="객체-내부에서-객체의-속성을-하나도-사용하지-않는-코드를-작성했다">객체 내부에서 객체의 속성을 하나도 사용하지 않는 코드를 작성했다.</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/2de99851-f7fb-41ea-90ea-1d3b29797ee0/image.png" alt=""></p>
<p>위 경우 사실상 해당 객체와 연관이 없는 코드일 수도 있으니 항상 주의해야 한다. 위의 코드도 어떻게 고쳐야 하는지 아직은 피드백을 받지 못했다.</p>
<p>객체 내부에서 객체의 속성을 하나도 사용하지 않는 코드는 응집도가 낮은 코드일 수 있으니 주의하자.</p>
<h3 id="의존성을-추가하고-주석을-남기지-않았다">의존성을 추가하고 주석을 남기지 않았다.</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/3e59d0ec-ba48-44e9-b5d5-9a2542cf0a0b/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL Sever 인덱싱에 대한 정리]]></title>
            <link>https://velog.io/@jakeseo_me/SQL-Sever-%EC%9D%B8%EB%8D%B1%EC%8B%B1%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jakeseo_me/SQL-Sever-%EC%9D%B8%EB%8D%B1%EC%8B%B1%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 19 Nov 2021 04:42:38 GMT</pubDate>
            <description><![CDATA[<h3 id="db-server-인덱싱에-대한-간략한-설명">DB Server 인덱싱에 대한 간략한 설명</h3>
<p><a href="https://www.sqlshack.com/indexing-sql-server-temporary-tables/">참고링크</a></p>
<h5 id="장점">장점</h5>
<ul>
<li>데이터 검색을 빠르게 만들기 위함.</li>
<li>데이터의 중복 방지. (Primary key, Unique)</li>
<li>LOCK을 최소화. (동시성 증대)</li>
</ul>
<h5 id="단점">단점</h5>
<ul>
<li>물리적인 공간 차지. (테이블처럼 데이터를 가짐)</li>
<li>인덱스에 대한 유지/관리 부담</li>
<li>데이터가 적다면 유지/관리 부담이 더 클 수 있음</li>
</ul>
<h3 id="인덱싱에-따른-테이블-구조의-3가지-형태-힙-클러스터형-인덱스-논클러스터형-인덱스">인덱싱에 따른 테이블 구조의 3가지 형태 (힙, 클러스터형 인덱스, 논클러스터형 인덱스)</h3>
<h4 id="1-힙heap-인덱싱되지-않은-테이블">1. 힙(HEAP): 인덱싱되지 않은 테이블</h4>
<h5 id="특성">특성</h5>
<ul>
<li>인덱싱되지 않은 상태</li>
<li>정렬의 기준이 없음</li>
<li>데이터 페이지 내의 행들 간에 순서가 없음</li>
<li>클러스터형 인덱스가 없는 테이블</li>
</ul>
<h5 id="장단점">장단점</h5>
<ul>
<li>INSERT에 유리. 순서없이 그냥 페이지 빈 곳에 새 데이터를 추가하기만 하면 됨.</li>
<li>SELECT에 불리. 원하는 데이터를 찾기 위해서는 모든 데이터를 스캔해보아야 함. (Table Scan)</li>
</ul>
<h4 id="2-클러스터형-인덱스">2. 클러스터형 인덱스</h4>
<h5 id="특성-1">특성</h5>
<ul>
<li>인덱스된 컬럼을 기준으로 데이터가 <strong>물리적으로</strong> 정렬된다.</li>
<li>물리적으로 테이블의 row를 정렬하는 것이 필수적이라서 결과적으로는 클러스터된 인덱스는 로우의 모든 컬럼을 포함한다.</li>
<li>테이블에서 단 하나의 클러스터드 인덱스만 존재할 수 있고, 모든 로우는 클러스터 인덱스에 명시된 순서대로 정렬된다.</li>
<li>이 말은 즉, 데이터를 삽입하거나 업데이트할 때도 클러스터드 인덱스는 순서를 보장한다는 뜻이다. 이러한 프로세스는 애플리케이션 퍼포먼스에 좋은 영향을 미칠 수 있다.</li>
<li>클러스터드 인덱스가 없는 테이블에서는 데이터가 위에 설명한대로 정렬되지 않은 힙으로 저장된다. 힙은 정렬된 구조를 갖지 않는다. 테이블의 사이즈가 증가할수록 이러한 구조는 많은 문제를 발생시킬 수 있다.</li>
</ul>
<blockquote>
<p><strong>모든 컬럼을 읽을 필요가 있는 읽기 전용 프로그램을 구성한다면, 클러스터형 인덱스는 좋은 선택이 될 수 있다.</strong></p>
</blockquote>
<ul>
<li>클러스터드 인덱스는 트리로 저장된다. 클러스터 인덱스를 설정하면, 실제 데이터는 Leaf Node에 저장된다. 이러한 구성은 인덱스에 대한 look-up이 수행됐을 때 속도를 빠르게 해준다. 결과적으로, 낮은 숫자의 IO 연산이 요구된다.</li>
</ul>
<p><img src="https://images.velog.io/images/jakeseo_me/post/9fca3abc-2a02-43e2-8981-ce944da32c10/image.png" alt=""></p>
<blockquote>
<p>간소화를 위해 위 구조에서 non-leaf intermediate nodes를 뺐다.</p>
</blockquote>
<ul>
<li>추가적으로 인덱스는 데이터를 새로운 테이블에 옮기지 않고도 재구성이 가능하다.</li>
<li>SQL Server는 자동으로 Primary key 제약사항을 클러스터된 인덱스에 생성한다. 이 Primary key 제약사항은 해당 Row를 고유하게 만들기 위함이다.</li>
</ul>
<h4 id="3-논클러스터형-인덱스">3. 논클러스터형 인덱스</h4>
<ul>
<li>B-tree 인덱스라고도 불린다.</li>
<li>논클러스터드 인덱스 내부에서 논리적인 방법으로 데이터가 정렬된다. 로우는 논클러스터드 인덱스의 열과 다른 순서로 물리적으로 저장될 수 있다. 따라서 인덱스가 생성되고, 인덱스의 데이터가 인덱스 컬럼에 따라 논리적으로 정렬된다.</li>
<li>논클러스터드 인덱스는 실제 데이터의 상단에 생성된다.</li>
<li>클러스터드 인덱스와 다르게, 논클러스터드 인덱스의 리프 페이지들이 실제 데이터를 포함하지 않는다. 논클러스터드 인덱스의 리프 페이지는 포인터를 가지고 있다.</li>
</ul>
<p><img src="https://images.velog.io/images/jakeseo_me/post/98075425-9b2a-4733-9294-b6dc17ede850/image.png" alt=""></p>
<blockquote>
<p>이번에도 마찬가지로 간소화를 위해 non-leaf intermediate nodes를 뺐다.</p>
</blockquote>
<ul>
<li>위 포인터들은 클러스터드 인덱스의 리프 노드를 가리킨다. 필요한 열에 대한 주소를 가지고 있다.</li>
</ul>
<blockquote>
<p>포인터들은 책 목차 부분에 있는 페이지 숫자들과 같은 역할을 한다.</p>
</blockquote>
<ul>
<li>클러스터드 인덱스의 경우에는 리프 노드가 실제 데이터를 저장하고 있다는 것을 다시 상기해보자.<ul>
<li>만일, 클러스터드 인덱스가 테이블에 존재하지 않는다면, 논클러스터드 인덱스는 데이터가 저장된 힙 페이지를 포인팅한다. 그리고 힙은 이전에 말했듯 정렬되지 않은 형태로 데이터를 보관한다.</li>
<li>우리가 쿼리를 날릴 때, 처음 데이터의 주소를 얻기 위해 논클러스터드 인덱스가 검색이 되고, 이후에 클러스터드 인덱스에서 데이터를 얻기 위해 룩업이 수행된다. 이런 이유로 논클러스터드 인덱스가 일반적으로는 클러스터드 인덱스보다 느리다.</li>
<li>테이블에는 여러 개의 논클러스터드 인덱스가 있을 수 있다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>테이블의 로우가 물리적으로 클러스터드 인덱스의 순서에 의해 정렬되지만, 논클러스터드 인덱스는 인덱스에 명시된 순서대로 컬럼의 고유한 값을 포함한다. 그리고 실제 데이터를 가리키는 포인터를 갖는다. 논 클러스터드 인덱스는 테이블의 딕셔너리로 생각해볼 수 있다.</p>
</blockquote>
<h3 id="인덱스의-사용법">인덱스의 사용법</h3>
<h4 id="클러스터드-인덱스를-사용해야-할-때는-언제인가">클러스터드 인덱스를 사용해야 할 때는 언제인가?</h4>
<blockquote>
<p>먼저, 성능 보틀넥이 어디서 발생하는지 이해하기 위해 쿼리를 실행하고 실행 계획을 분석하는 것이 항상 기본이 되어야 한다. 하지만, 다음과 같은 경우에는 클러스터드 인덱스를 만들어보는 것도 현명한 선택이다.</p>
</blockquote>
<ul>
<li>특정한 컬럼을 기준으로 JOIN 이나 WHERE 문을 많이 이용할 때 해당 컬럼에 클러스터드 인덱스를 사용하면 좋다.<ul>
<li>단, 업데이트가 자주 일어나는 컬럼이 아니어야 한다.</li>
</ul>
</li>
<li>특정한 컬럼에 대해 언제나 정렬된 데이터가 필요로 될 때, 해당 컬럼에 대해 매번 ORDER BY 구문을 이용하게 될 때 해당 컬럼에 클러스터드 인덱스를 사용하면 좋다.<ul>
<li>이 인덱싱을 통해 테이블이 매번 스캔될 필요가 없게 만들 수 있다.</li>
</ul>
</li>
<li>애플리케이션이 테이블에서 다량의 데이터를 읽어온다면 클러스터드 인덱스를 통해 많은 성능향상이 가능하다.</li>
<li>SELECT 쿼리에서 대부분, 혹은 모든 컬럼의 내용을 읽어오는 경우에도 클러스터드 인덱스를 사용하는 것을 고려할 수 있다.</li>
<li><strong>단, 최소한의 컬럼을 클러스터형 인덱스 키 컬럼으로 지정하는 것이 중요하다.</strong></li>
</ul>
<h4 id="논-클러스터드-인덱스를-사용해야-할-때는-언제인가">논 클러스터드 인덱스를 사용해야 할 때는 언제인가?</h4>
<blockquote>
<p>먼저, 성능 보틀넥이 어디서 발생하는지 이해하기 위해 쿼리를 실행하고 실행 계획을 분석하는 것이 항상 기본이 되어야 한다. 하지만, 다음과 같은 경우에는 논클러스터드 인덱스를 만들어보는 것도 현명한 선택이다.</p>
</blockquote>
<ul>
<li>테이블의 로우를 필터링하기 위해 다수의 쿼리가 요구되고, WHERE 문이나 JOIN 문에서 다른 그룹의 컬럼들이 있을 때, 논클러스터드 인덱스를 사용하면 좋다.</li>
<li>지속적으로 특정한 정렬 순서로 데이터를 출력한다면, 논클러스터드 인덱스로 속도 향상 효과를 볼 수 있다.<ul>
<li>추가적인 정렬이 필요 없어서 메모리상의 이득을 볼 수 있다.<ul>
<li>실제 데이터의 물리적인 정렬은 발생하지 않는다. 다만, 각 로우에 RID라는 것이 붙어 RID가 데이터를 찾는 것을 도와준다.</li>
<li>RID 구조: 파일 식별자 + 페이지 번호 + 페이지 내의 로우 번호</li>
</ul>
</li>
</ul>
</li>
<li>힙과 클러스터드 인덱스에서의 비클러스터드 인덱스의 동작 비교<ul>
<li>HEAP클러스터드구조정렬 없이 단순 적재클러스터드 인덱스 컬럼에 따라 정렬된 상태모든 페이지를 다 읽을 때Table ScanClustered Index Scan논 클러스터드 인덱스 구조RID + 인덱스 Key 컬럼Clustered Index Key + 인덱스 Key 컬럼논 클러스터드 인덱스에서 해결이 되지 않을 때RID LookupKey Lookup
인덱스를 사용하여 데이터 조회가 이루어지면, Index Seek 동작이 발생한다.</li>
</ul>
</li>
<li>만일, 쿼리에서 특정한 컬럼들이 더 자주 사용된다면, 논 클러스터드 인덱스를 테이블에 걸어둬서 효과를 볼 수 있다.<ul>
<li>이 방식은 Cover Non Clustered Index 라고 불린다. (<a href="https://stackoverflow.com/questions/609343/what-are-covering-indexes-and-covered-queries-in-sql-server">참고링크</a>)</li>
</ul>
</li>
<li>특정한 기준(criteria)에 맞춘 열들만 인덱스를 걸고 싶다면, 논 클러스터드 인덱스 내부에 WHERE 조건을 추가할 수 있다.<ul>
<li>이 방식은 Filter Non Clustered Index 라고 불린다.</li>
</ul>
</li>
<li>SELECT 할 때, 논 클러스터드 인덱스 내부에서 리프 노드로 필요로 되는 컬럼을 INCLUDE 할 수 있다. 이러한 작업은 검색속도를 빠르게 만들어 준다.</li>
<li><strong>논클러스터드 인덱스 또한 선별된 컬럼에만 걸어야 효과를 볼 수 있다.</strong></li>
<li>조회하려는 모든 컬럼이 인덱스에 포함되어 있을 때는 데이터 페이지까지 내려가지 않고도 모든 데이터 조회가 가능하기 때문에 Included column을 사용하는 것도 고려할만 하다.</li>
<li>동일한 데이터가 많은 컬럼에 인덱스를 걸면, 인덱스를 걸지 않는 것보다 느려질 수도 있다.</li>
</ul>
<h3 id="인덱스-생성법">인덱스 생성법</h3>
<h4 id="클러스터드-인덱스-생성-방법">클러스터드 인덱스 생성 방법</h4>
<p>2가지 방법이 있다.</p>
<ol>
<li>Primary Key를 만든다.</li>
<li>혹은 create index statement를 이용한다.</li>
</ol>
<pre><code>-- Via primary key constraint
ALTER TABLE FinTechExplained.Trade ADD CONSTRAINT PK_Trade_TradeId
PRIMARY KEY CLUSTERED (TradeId ASC, TradeType ASC);

-- using create index statement
CREATE CLUSTERED INDEX IX_Trade_TradeId ON FinTechExplained.Trade(TradeId ASC, TradeType ASC);</code></pre><h4 id="논-클러스터드-인덱스-생성-방법">논 클러스터드 인덱스 생성 방법</h4>
<p>2가지 방법이 있다.</p>
<ol>
<li>NonClustered 키워드를 사용하는 방식</li>
<li>혹은 NonClustered 키워드를 사용하지 않는 방식</li>
</ol>
<pre><code>-- By using the non-clustered index
CREATE NONCLUSTERED INDEX IX_Trade_CreatedAtCreatedBy ON FinTechExplained.Trade(CreatedAt ASC,CreatedBy ASC);

CREATE INDEX IX_Trade_CreatedAtCreatedBy ON FinTechExplained.Trade (CreatedAt ASC,CreatedBy ASC);</code></pre><h3 id="인덱스-생성-이슈들">인덱스 생성 이슈들</h3>
<p>가끔은 인덱스를 만들어서 성능에 나쁜 영향이 미치기도 한다.</p>
<ol>
<li>인덱스는 어찌됐건, 디스크 공간을 차지하고 SQL 프로세스 중 memory footprint에 영향을 줄 수 있다. 클러스터드 인덱스는 논클러스터드 인덱스만큼 많은 공간을 차지하지는 않는다. 왜냐하면 논 클러스터드 인덱스는 디스크의 분리된 공간에 저장되기 때문이다.</li>
<li>클러스터드 인덱스는 많은 양의 READ 를 수행한다면, 유용하다. 하지만 인서트 시에는 데이터가 섞이고 다시 정렬되는 작업이 필요해진다. 그래서 빠른 INSERT가 필요한 테이블에는 적합하지 않다. 빠른 INSERT만을 원한다면 사실 인덱스를 다 지워버리는 것이 맞다.</li>
<li>클러스터드 인덱스의 컬럼들이 아닌 다른 컬럼 집합에 대해 ORDER BY 를 수행한다면, 클러스터드 인덱스는 아무런 도움이 되지 않는다.</li>
<li>논클러스터드 인덱스는 주의깊게 설계되어야 한다. 만일 컬럼의 하위집합만 추가한다면, 인덱스는 모든 컬럼을 추가했을 때보다 유용하지 않을 수 있다. 컬럼을 많이 추가할수록, 인덱스가 커지고, 인덱스가 커지면 디스크에서 차지하는 크기도 늘어난다. 한 컬럼을 포함하는 논클러스터드 인덱스를 2개 추가했다면, 해당 컬럼의 고유한 값을 복사하게 될 것이다. 이러한 작업이 이루어지기 때문에 디스크에서 더 많은 공간을 소비하게 된다.</li>
<li>많은 인덱스는 성능을 해칠 수 있다. 이를테면 2개의 논클러스터드 인덱스를 생성했다고 가정해보자. 첫번째 논클러스터드 인덱스가 컬럼 A와 B에 붙어있고, 두번째 논클러스터드 인덱스가 B와 C와 D에 붙어있다. 이 상태에서 만일 컬럼 A, C, D를 조회하면, SQL은 필요한 포인터를 찾기 위해 두개의 인덱스를 사용하고 테이블에서 그 데이터를 찾게 된다. 이러한 일은 쿼리 성능에 매우 안 좋은 영향을 준다.</li>
<li>만일, bulk import를 할 필요가 있다면, 인덱스가 성능에 영향을 줄 수 있으므로 인덱스를 만들지 않는 것이 좋다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[#4 프로토타입 - 심화 3 - deprecated __proto__과 모던 프로토타입 메소드들]]></title>
            <link>https://velog.io/@jakeseo_me/4-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85-%EC%8B%AC%ED%99%94-3-deprecated-proto%EA%B3%BC-%EB%AA%A8%EB%8D%98-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85-%EB%A9%94%EC%86%8C%EB%93%9C%EB%93%A4</link>
            <guid>https://velog.io/@jakeseo_me/4-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85-%EC%8B%AC%ED%99%94-3-deprecated-proto%EA%B3%BC-%EB%AA%A8%EB%8D%98-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85-%EB%A9%94%EC%86%8C%EB%93%9C%EB%93%A4</guid>
            <pubDate>Wed, 13 Oct 2021 11:26:02 GMT</pubDate>
            <description><![CDATA[<h2 id="__proto__"><code>__proto__</code></h2>
<p><img src="https://images.velog.io/images/jakeseo_me/post/18104a6e-129f-42f6-860e-f83088d15cc9/image.png" alt=""></p>
<p><code>__proto__</code>는 사실 더 이상 권장되지 않는 기능이다. 최근 관련된 웹 표준에서 사라졌을 수 있으며, 혹은 사라지는 중일 수 있다. 물론, 호환성을 위해 아직 없애지 않는 브라우저가 대부분이긴 할 것이다. <code>__proto__</code>를 사용하기보다는 가능하다면 존재하는 코드를 업데이트하여 <code>__proto__</code>의 사용을 자제하자. </p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/38855840-3414-4c01-a032-913b533fdea4/image.png" alt=""></p>
<p>호환성 목록에서 어떤 환경에서 호환하지 않는지 볼 수 있다.</p>
<h2 id="모던한-프로토타입-메소드들">모던한 프로토타입 메소드들</h2>
<p>현대식 자바스크립트에서 프로토타입을 다루기 위한 모던한 메소드들이 있다.</p>
<ul>
<li><code>Object.create(proto, [descriptors])</code>: <code>[[Prototype]]</code>이 <code>proto</code>를 참조하는 빈 객체를 만든다. 이 때, 프로퍼티 설명자도 추가로 넘길 수 있다.</li>
<li><code>Object.getPrototypeOf(obj)</code>: <code>obj</code>의 <code>[[Prototype]]</code>을 반환한다.</li>
<li><code>Object.setPrototypeOf(obj, proto)</code>: <code>obj</code>의 <code>[[Prototype]]</code>이 <code>proto</code>가 되도록 설정한다.</li>
</ul>
<blockquote>
<p>앞으로는 <code>__proto__</code>대신 위의 메소드를 이용해서 프로토타입 관련 기능을 작성하자.</p>
</blockquote>
<h3 id="모던-프로토타입-메소드-활용해보기">모던 프로토타입 메소드 활용해보기</h3>
<pre><code class="language-js">const module = {
  detach: true,
  attach: true
}

const monitor = Object.create(module);

alert(`monitor.detach = ${monitor.detach}`); // true
alert(`monitor.attach = ${monitor.attach}`); // true

alert(Object.getPrototypeOf(monitor) === module); // true

// 아이맥의 모니터라면?
Object.setPrototypeOf(monitor, {detach: false, attach: false});

alert(`monitor.detach = ${monitor.detach}`); // false
alert(`monitor.attach = ${monitor.attach}`); // false

alert(Object.getPrototypeOf(monitor) === module); // false</code></pre>
<p>위와 같이 활용해볼 수 있다.</p>
<h3 id="프로퍼티-설명자-이용해보기">프로퍼티 설명자 이용해보기</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/1d8f715e-746e-4d21-86d4-d590184abe43/image.png" alt=""></p>
<p>간단하게 설명자로 프로퍼티 플래그를 건드려보고 출력해본 결과이다.</p>
<h2 id="모던-프로토타입은-왜-생겨난것인가">모던 프로토타입은 왜 생겨난것인가?</h2>
<p>일단 모던 프로토타입 메서드를 어떻게 사용하는지를 먼저 배워봤는데, 그렇다면 기존에 <code>__proto__</code> 도 엄청 편했던 것 같은데, 뭐가 문제여서 모던 프로토타입 메서드를 권장하는 것일까?</p>
<ul>
<li>프로토타입 기능 자체는 원래 오래된 것이다.</li>
<li>2012년, <code>Object.create()</code>가 등장하여 프로토타입이 설정된 객체를 만들어낼 수 있게 되었다.</li>
<li><code>__proto__</code>가 등장하여 마음대로 프로토타입을 얻거나 설정할 수 있게 되었다.<ul>
<li>그러나 이 기능을 이용해 프로토타입을 마음대로 바꾼다면, 자바스크립트 엔진의 최적화를 방해한다.</li>
</ul>
</li>
<li>2015년, <code>getPrototypeOf</code>와 <code>setPrototypeOf</code>가 표준에 추가되었다.</li>
</ul>
<blockquote>
<p>그러나 여전히 <code>Object.setPrototypeOf</code>로도 마음대로 프로토타입을 바꾸게 되면 자바스크립트 엔진의 최적화가 저해된다.</p>
</blockquote>
<h2 id="아주-단순한-객체">&#39;아주 단순한&#39; 객체</h2>
<ul>
<li>객체는 키-값 쌍을 저장할 수 있는 단순한 연관 배열이다.</li>
<li>그럴 일은 잘 없지만, <code>__proto__</code>를 키로 이용하여 값을 넣게 되면 값이 제대로 들어가지 않는다.</li>
</ul>
<pre><code class="language-js">const obj = {};

const key = prompt(&quot;사용할 key를 입력&quot;, &quot;__proto__&quot;);
obj[key] = &quot;value&quot;;

alert(obj[key]);</code></pre>
<p>위의 코드가 제대로 작동하지 않는 이유는 <code>__proto__</code>에는 객체만 들어갈 수 있기 때문이다. 그래서 <code>[object Object]</code>가 나오는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JMeter로 웹사이트 성능 측정해보기]]></title>
            <link>https://velog.io/@jakeseo_me/JMeter%EB%A1%9C-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EC%84%B1%EB%8A%A5-%EC%B8%A1%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@jakeseo_me/JMeter%EB%A1%9C-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EC%84%B1%EB%8A%A5-%EC%B8%A1%EC%A0%95%ED%95%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Wed, 13 Oct 2021 00:29:12 GMT</pubDate>
            <description><![CDATA[<h2 id="다운로드-주소">다운로드 주소</h2>
<p><a href="https://jmeter.apache.org/download_jmeter.cgi">https://jmeter.apache.org/download_jmeter.cgi</a> 에서 binary 타입을 받으면 됨</p>
<h2 id="실행">실행</h2>
<p>윈도우에서는 <code>bin</code> 디렉토리에 있는 <code>jmeter.bat</code> 실행하면 됨. 맥에서는 <code>ApacheJMeter.jar</code> 직접 실행 가능한듯.</p>
<h2 id="가상의-접속자-만드는-방법">가상의 접속자 만드는 방법</h2>
<p><img src="https://images.velog.io/images/jakeseo_me/post/11f4e26e-0e6d-48e9-9ec6-78c6be71630b/image.png" alt=""></p>
<p>위처럼 <code>Add &gt; Threads</code>에 들어가서 <code>Thread Group</code> 눌러서 가상의 접속자를 만들 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/4527c51d-d9b2-4c41-b55b-31587fcc75f8/image.png" alt=""></p>
<ul>
<li><code>Number of Threads</code>가 몇명이 접속하는지 </li>
<li><code>Ramp-up period</code>는 테스트 유저를 추가하는데 얼마만큼의 간격을 줄건지이다.<ul>
<li><a href="https://www.blazemeter.com/blog/jmeter-ramp-up-the-ultimate-guide">설명 링크</a></li>
</ul>
</li>
<li><code>Loop Count</code>는 몇번 반복할건지</li>
</ul>
<h3 id="가상의-접속자가-접속할-프로토콜-선택하기">가상의 접속자가 접속할 프로토콜 선택하기</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/87578101-b62a-4953-9fe1-e1adbc05f79b/image.png" alt=""></p>
<p> 웹 사용자는 보통 <code>HTTP Request</code>를 보낼 확률이 높다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/f3fbbe1a-5779-4222-9095-9a83c6294755/image.png" alt=""></p>
<ul>
<li><code>HTTP</code>가 아닌 <code>https</code>인 경우에는 <code>Protocol</code> 항목에 <code>https</code>를 적어주면 된다.</li>
<li><code>Path</code>는 해당 서버의 어떤 URL에 접근할지에 대한 세부 정보이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[#3 프로토타입 - 심화 2 - 네이티브 프로토타입]]></title>
            <link>https://velog.io/@jakeseo_me/3-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85-%EC%8B%AC%ED%99%94-2-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@jakeseo_me/3-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85-%EC%8B%AC%ED%99%94-2-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85</guid>
            <pubDate>Sun, 10 Oct 2021 16:04:11 GMT</pubDate>
            <description><![CDATA[<h2 id="object의-내장-프로토타입">Object의 내장 프로토타입</h2>
<h3 id="object-object-">[object Object] ?</h3>
<pre><code class="language-js">const obj = {};
alert(obj);</code></pre>
<p>위의 코드를 실행시키면 결과가 어떤 것이 나올지 예측이 가능한가? 정답은 아래와 같다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/0b73150c-9f8a-4f43-9b43-9323ae2c420f/image.png" alt=""></p>
<blockquote>
<p>응? 나는 <code>alert(&#39;[object Object]&#39;)</code>를 입력한 적이 없는데?</p>
</blockquote>
<p>이전에 배웠던 내용이 잘 기억난다면, 위의 내용은 잘 풀어썼을 때 아래와 같다는 것을 생각해낼 수 있을 것이다.</p>
<pre><code class="language-js">const obj = new Object();
alert(obj.toString());</code></pre>
<p><code>{}</code>가 할당된 <code>obj</code>는 자동적으로 <code>Object</code> 객체의 프로토타입인 <code>Object.prototype</code>을 상속 받게 된다. 그말인 즉, 던더(더블 언더) 프로토(<code>__proto__</code>)에 <code>Object.prototype</code>이 들어가게 된다는 이야기이다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/d94a7ecb-8d9d-4977-8cee-235006cdd006/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/188d1468-3c55-44c7-abe6-56af024a9b9b/image.png" alt=""></p>
<p>위의 그림과 같은 현상이 일어난다.</p>
<pre><code class="language-js">alert(Object.prototype.toString());</code></pre>
<p>위와 같은 코드를 작성한 것과 같은 결과이다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/5b5d3c0d-cdcd-409e-96b6-b61dc9f3cfc8/image.png" alt=""></p>
<blockquote>
<p>참고로 <code>Object.prototype.__proto__</code>에는 아무것도 없음을 잠깐 생각해두자. 당연히 <code>prototype</code>은 <code>__proto__</code>로 상속될 것들이 모여있는 건데, 이중으로 상속할 일은 없다.</p>
</blockquote>
<h2 id="다른-내장-객체들의-내장-프로토타입과-상속">다른 내장 객체들의 내장 프로토타입과 상속</h2>
<p><code>Array</code>, <code>Date</code>, <code>Function</code>을 비롯한 다른 내장 객체들도 프로토타입에 메서드를 저장해놓는다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/86f3250a-1112-403d-b3ee-6c46dec0beb9/image.png" alt=""></p>
<p>위와 같이 <code>[1, 2, 3]</code>이라는 배열을 만들어보면, <code>__proto__</code>에 들어가는 내용이 <code>Array.prototype</code>에 있는 내용과 일치한다는 것을 알 수 있다.</p>
<p>이렇게 프로토 타입을 상속받음으로써, <code>push()</code>, <code>pop()</code>등 다양한 배열 메소드도 제공받으며, 이런 내부동작 덕에 메모리 효율도 높아진다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/8e5a6d81-6d73-4680-bc4b-3190c8b7f5a3/image.png" alt=""></p>
<p><code>100</code> 이라는 임의의 숫자가 들어있는 상수를 만들고, <code>__proto__</code>에 들어가는 내용을 <code>Number.prototype</code>과 비교하면 또 일치한다.</p>
<p>역시 이번에도 프로토 타입을 통해 <code>toFixed()</code>와 같은 숫자 전용 메소드를 제공받는다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/2509e4af-bedb-4cb1-9368-12f9ba626cab/image.png" alt=""></p>
<p>위와 같은 방식으로 프로토타입은 계층 구조로 연결되어 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/bb3ef226-403c-482c-bc0c-e81aacf7ce6b/image.png" alt=""></p>
<p>위 코드 예제를 보면, 쉽게 이해할 수 있을 것이다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/b149b91d-fec1-4311-a8b3-3d38c1c668bd/image.png" alt=""></p>
<p>한번 더 상위로 가면 <code>null</code>이 존재하는 것도 확인할 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/0c74b04a-42df-4fd9-9e55-ed683ad848e1/image.png" alt=""></p>
<h3 id="상속-우선순위">상속 우선순위</h3>
<p>일단 프로토타입이 상속되면, 동일한 이름의 메소드가 있을 때, 나와 가장 가까운 거리에 있는 상속된 메소드를 사용한다.</p>
<p>이를테면 아래의 코드에서는,</p>
<pre><code class="language-js">const array = [1, 2, 3];
console.log(array.toString());</code></pre>
<p><code>toString()</code>을 할 때, <code>Object.prototype.toString()</code>도 있지만, 가장 가까이에 있는 <code>Array.prototype.toString()</code>을 사용하게 된다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/930bbbf5-48a5-4ad6-9c21-cd2c83a86291/image.png" alt=""></p>
<h2 id="원시primitive-타입">원시(Primitive) 타입</h2>
<p>이제까지 사용했던 문자열, 숫자, 불린 값은 내장 생성자인 <code>String</code>, <code>Number</code>, <code>Boolean</code>을 사용하는 임시 래퍼(wrapper) 객체에 의해 감싸졌다. 임시 래퍼 객체는 이러한 메서드를 제공한 이후에는 사라진다.</p>
<p>래퍼 객체는 보이지 않는 곳에서 만들어진다. 최적화는 엔진이 담당한다. 명세서에서는 각 자료형에 해당하는 래퍼 객체의 메서드를 프로토타입 안에 구현해놓고, <code>String.prototype</code>, <code>Number.prototype</code>, <code>Boolean.prototype</code>을 사용해 쓸 수 있도록 규정한다.</p>
<h3 id="null과-undefined는">null과 undefined는?</h3>
<p><code>null</code>과 <code>undefined</code>도 자바스크립트에서는 원시 타입으로 분류되는데, 이에 대응하는 래퍼 객체는 존재하지 않는다.</p>
<h2 id="네이티브-프로토타입-변경">네이티브 프로토타입 변경</h2>
<pre><code class="language-js">String.prototype.log = function() {
  console.log(this.toString()); 
}

&quot;안녕하세요&quot;.log();</code></pre>
<p><img src="https://images.velog.io/images/jakeseo_me/post/81540ff0-9538-464f-a530-db1f42f192a4/image.png" alt=""></p>
<p>위와 같은 형식의 조작이 가능하지만, <strong>라이브러리에서 중복으로 네이티브 프로토타입을 바꿔버리면 충돌의 가능성이 매우 크기 때문에 반드시 주의해야 한다.</strong></p>
<h3 id="폴리필">폴리필</h3>
<p><strong>네이티브 프로토타입이 변경되어야 한다면, 보통 그 이유는 오직 폴리필밖에 없다.</strong></p>
<p>특정 브라우저에서 구현되지 않은 메소드를 직접 구현할 때 쓰면 유용하다.</p>
<h2 id="프로토타입-메소드-빌려오기">프로토타입 메소드 빌려오기</h2>
<pre><code class="language-js">const obj = {
  0: &quot;Hello&quot;,
  1: &quot;World&quot;,
  length: 2
};

obj.join = Array.prototype.join;

alert(obj.join(&#39; &#39;)); // Hello World!</code></pre>
<p>내장 메서드인 <code>join</code>의 특성을 이용한 코드이다. 인덱스가 있는지와 <code>length</code> 프로퍼티가 있는지만 확인하기 때문에 이와 같은 동작이 가능하다.</p>
<p>또는, <code>obj.__proto__ = Array.prototype</code>을 통해서도 가능하긴하다. 다만, <code>obj</code>가 이미 다른 객체를 상속받고 있을 때는 불가능하다. 자바스크립트는 단일상속만을 허용하기 때문이다.</p>
<h2 id="코드로-프로토타입-연습해보기">코드로 프로토타입 연습해보기</h2>
<h3 id="defer-1">defer 1</h3>
<pre><code class="language-js">Function.prototype.defer = function(ms) {
  setTimeout(this, ms);
};</code></pre>
<p>위 코드를 작성하게 되면, 모든 함수(<code>Function</code> 객체)에 <code>.defer()</code> 메소드를 사용할 수 있게 된다.</p>
<h3 id="defer-2">defer 2</h3>
<pre><code class="language-js">Function.prototype.defer = function(ms) {
  const f = this;
  return function(...args) {
    setTimeout(() =&gt; f.apply(this, args), ms);
  }
}</code></pre>
<p>위와 같이 <code>apply</code>를 이용하면, 넘어온 <code>this</code>를 기억하고, 넘어온 <code>args</code>를 이용하여 데코레이팅 함수도 만들 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[#2 프로토타입 - 심화 1]]></title>
            <link>https://velog.io/@jakeseo_me/2-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85-%EC%8B%AC%ED%99%94</link>
            <guid>https://velog.io/@jakeseo_me/2-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85-%EC%8B%AC%ED%99%94</guid>
            <pubDate>Wed, 29 Sep 2021 17:14:15 GMT</pubDate>
            <description><![CDATA[<h2 id="함수의-prototype-프로퍼티">함수의 prototype 프로퍼티</h2>
<pre><code class="language-js">let animal = {
  eats: true
};

function Rabbit(name) {
  this.name = name;
}

Rabbit.prototype = animal; // 프로토타입 객체 설정
let rabbit = new Rabbit(&quot;White Rabbit&quot;); //  rabbit.__proto__ == animal
alert( rabbit.eats ); // true</code></pre>
<p>위와 같이 함수에서 <code>new</code> 키워드를 이용해 새로운 객체를 생성하면, 함수의 <code>.prototype</code>에 존재하는 객체가 새롭게 생성된 객체의 프로토타입 객체가 된다.</p>
<blockquote>
<p>참고로 자바스크립트에서는 함수도 객체이다. 단순히 객체 뒤에 괄호를 넣어 <code>객체()</code>와 같은 형태를 띄었을 때 무언가 실행할 뿐이다.</p>
</blockquote>
<p><img src="https://images.velog.io/images/jakeseo_me/post/2521c8d5-90d1-4627-a895-b50bf8a04ce3/image.png" alt=""></p>
<p><code>Rabbit.prototype</code>에 들어있던 객체가 생성자로 생성한 객체의 <code>__proto__</code>에 할당된다.</p>
<h3 id="functionprototype과-new-function">Function.prototype과 new Function()</h3>
<blockquote>
<p><code>new Function()</code> 코드를 통해 생성된 객체의 <code>[[Prototype]]</code>에는 <code>Function.prototype</code>이 참조하던 객체가 들어간다.</p>
</blockquote>
<p><img src="https://images.velog.io/images/jakeseo_me/post/2b5e65e1-9dcf-4017-a18d-61673e30d9dd/image.png" alt=""></p>
<blockquote>
<p>주의해야 할 것은 <code>Rabbit.prototype</code> 자체의 레퍼런스를 할당하는 것이 아니라 <code>Rabbit.prototype</code>이 가지고 있던 객체의 레퍼런스를 할당한다는 것이다. 다시 말하면 <code>Rabbit.prototype === object</code>일 때, <code>object</code>의 레퍼런스를 할당하는 것이지, <code>Rabbit.prototype</code> 자체를 할당하는 것이 아니다.</p>
</blockquote>
<p><code>new Rabbit()</code>과 같이 <code>new Function()</code>이 호출될 때만 <code>Function.prototype</code>을 <code>newObject.__proto__</code>에 할당한다. 단, 프로토타입 객체의 레퍼런스를 할당해서 <code>Function.prototype</code>이 변경되면 <code>newObject.__proto__</code>도 변경된다.</p>
<p>단, <code>Rabbit.prototype</code>에 사용되었던 <code>animal</code>은 바뀌어도 상관없다. 왜냐하면 <code>Rabbit.prototype</code>이 <code>animal</code>을 직접적으로 참조하지 않기 때문이다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/b5c2e60a-ed29-4628-a5ac-4ebeda1a9ce6/image.png" alt=""></p>
<p><code>new Rabbit()</code>코드로 생성된 <code>rabbit</code>의 <code>__proto__</code>는 <code>Rabbit.prototype</code>가 가리키던 객체를 그대로 참조했기 때문에, 해당 객체의 내용을 바꾸고, <code>rabbit.__proto__</code>객체의 내용을 확인해보면 이 객체가 <code>Rabbit.prototype</code>가 가리키던 객체를 그대로 참조하고 있음을 다시 확인할 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/b38d2964-52d2-4e07-85dd-278d8df9afae/image.png" alt=""></p>
<p>하지만, 위와 같이 <code>Rabbit.prototype</code>이 참조하는 객체를 바꿔버리는 경우에는 <code>rabbit.__proto__</code>에 변화가 없다. <code>rabbit.__proto__</code>는 이전에 <code>Rabbit.prototype</code>에 존재하던 객체를 여전히 가리키고 있을 것이다.</p>
<h2 id="함수의-prototype-프로퍼티와-constructor-프로퍼티">함수의 prototype 프로퍼티와 constructor 프로퍼티</h2>
<p>모든 선언된 함수는 내부적으로 <code>prototype</code> 프로퍼티를 갖는다. 그리고 그 <code>prototype</code> 내부에는 <code>constructor</code>가 들어있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/54682cc1-093e-49d1-aa43-113378b814f2/image.png" alt=""></p>
<p>그래서 <code>Function.prototype</code>을 강제로 수정하지 않았다면, <code>new Function()</code>으로 생겨난 어떤 객체에서도 <code>.constructor()</code>를 통해 생성자를 호출할 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/43b9343c-6678-4acd-8e15-f7c946c705b1/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/9c4cc91e-725a-4af8-bcca-4f692f6778e2/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/1d4139b7-294b-420c-9e13-bbc4af9de946/image.png" alt=""></p>
<p>대략 위와 같은 관계가 되는데, <code>Function</code>에서는 <code>.prototype</code>을 통해 <code>Function.prototype</code>에 접근 가능하다. 그리고 <code>Function.prototype</code>에서는 <code>constructor</code>를 통해 <code>Function</code>에 접근 가능하다. 그리고 <code>new Function()</code>으로 인해 생겨난 객체에서도 또 프로토타입을 통해 <code>.constructor()</code>를 사용하여 <code>Function</code>에 접근 가능하다.</p>
<p>서드파티 라이브러리를 사용하다가 자바스크립트 객체가 어디서 온지 모를 때, 이를 이용하면 유용하다. </p>
<p><strong>단, 자바스크립트는 <code>constructor</code>의 값을 보장하지 않는다.</strong> 우리가 멋대로 <code>object.prototype</code>을 수정해버리면 <code>constructor</code>는 날아간다.</p>
<p>그래서, <code>object.prototype = {}</code> 식으로 프로토타입의 속성을 지어주는 것보다는, <code>object.prototype.a = &#39;value&#39;</code>와 같은 형식으로 프로토타입을 지어줘야 <code>constructor</code>도 지키면서 프로토타입의 값도 넣어줄 수 있다.</p>
<h2 id="예제-코드를-통해-특징-더-알아보기">예제 코드를 통해 특징 더 알아보기</h2>
<h3 id="rabbitprototype--">Rabbit.prototype = {}</h3>
<pre><code class="language-js">function Rabbit() {}
Rabbit.prototype = {
  eats: true
};

let rabbit = new Rabbit();

Rabbit.prototype = {};

alert( rabbit.eats ); // ?</code></pre>
<p>위의 결과 값은 <code>true</code>이다 그 이유는 아무리 <code>Rabbit.prototype</code>에 <code>{}</code>라는 빈 객체를 할당해도 <code>rabbit.__proto__</code>는 <code>Rabbit.prototype</code>이 참조하던 객체를 그대로 참조한다. 되려 <code>Rabbit.prototype.eats = false</code>와 같은 코드를 입력했다면, <code>rabbit.__proto__</code>가 참조하던 객체가 직접 변경되어 결과는 <code>false</code>가 되었을 것이다.</p>
<h3 id="rabbitprototypeeats--false">Rabbit.prototype.eats = false</h3>
<pre><code class="language-js">function Rabbit() {}
Rabbit.prototype = {
  eats: true
};

let rabbit = new Rabbit();

Rabbit.prototype.eats = false;

alert( rabbit.eats ); // ?</code></pre>
<p>이건 위에 설명했듯, 참조하는 객체의 프로퍼티를 직접 바꾼 케이스라 결과도 <code>false</code>가 나온다.</p>
<h3 id="delete-rabbiteats">delete rabbit.eats</h3>
<pre><code class="language-js">function Rabbit() {}
Rabbit.prototype = {
  eats: true
};

let rabbit = new Rabbit();

delete rabbit.eats;

alert( rabbit.eats ); // ?</code></pre>
<p>이 코드에서 출력하는 값은 <code>true</code>이다. <code>rabbit.eats</code>는 현재 프로토타입 객체를 거쳐 출력은 가능하지만, 실제 <code>rabbit.eats</code>에 직접적으로는 아무것도 없는 상태이기 때문이다.</p>
<h3 id="delete-rabbitprototypeeats">delete Rabbit.prototype.eats</h3>
<pre><code class="language-js">function Rabbit() {}
Rabbit.prototype = {
  eats: true
};

let rabbit = new Rabbit();

delete Rabbit.prototype.eats;

alert( rabbit.eats ); // ?</code></pre>
<p>이 코드에서 출력하는 값은 <code>undefined</code>이다. <code>rabbit.__proto__</code>가 참조하던 객체의 <code>eats</code>를 직접 지워버렸다.</p>
<h3 id="constructor의-활용">constructor의 활용</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/a21a71c7-2818-4e7b-ae5c-6b632d8cfab4/image.png" alt=""></p>
<p>위의 로그 내용처럼 <code>constructor</code>를 <code>new person1.constructor()</code>와 같은 코드로 응용할 수도 있다. <code>new</code>라는 키워드를 이렇게 붙이는 것이 좀 낯설어보일 수 있다.</p>
<h3 id="prototype--">prototype = {}</h3>
<pre><code class="language-js">function Person(name) {
  this.name = name;
}

Person.prototype = {};

const newPerson1 = new Person(&quot;Peter&quot;);
const newPerson2 = new newPerson1.constructor(&quot;jake&quot;);

console.log(newPerson1.name);
console.log(newPerson2.name);</code></pre>
<p><img src="https://images.velog.io/images/jakeseo_me/post/f9dee1fd-1ec1-4054-be01-223b130258a5/image.png" alt=""></p>
<p>위 코드는 <strong><code>Function.prototype.constructor</code>의 값은 보장되지 않는다는 특성</strong>을 이용했다. 기본적으로 <code>Function.prototype.constructor</code>는 자동으로 생성되지만, 사용자에 의해 수정될 수 있다. 위의 경우에는 <code>Function.prototype</code> 자체가 <code>{}</code>로 변해버렸다.</p>
<p>위의 코드를 잘 보면 <code>newPerson1.name</code>을 로그로 찍어봤을 때는 <code>Peter</code>가 잘 나오는데, <code>newPerson2.name</code>을 로그로 찍어보면 <code>jake</code>가 나오지 않는다. 그 이유는 <code>newPerson2</code>를 생성할 때 <code>newPerson1.constructor</code>로 생성을 하였는데, 우리가 <code>Person.prototype</code>를 수정하지 않았다면 정상적으로 생성됐지만, 우리는 <code>Person.prototype</code>을 <code>{}</code> 값으로 바꾸어놓았다. 그래서 자바스크립트는 <code>newPerson1.__proto__</code>에서 <code>constructor</code> 프로퍼티를 찾아보지만 찾아낼 수 없다. 그래서 자바스크립트는 <code>newPerson1.__proto__.__proto__</code>와 같이 프로토타입 체인을 타고 <code>constructor</code>를 찾으려 한다. <code>newPerson1.__proto__</code>는 <code>{}</code> 이므로, <code>{}</code>는 일반 자바스크립트 객체이고 프로토타입으로 <code>Object</code>를 갖는다. </p>
<p>마침내 자바스크립트는 <code>Object.constructor</code>를 찾아 해당 코드를 수행한다. <code>Object.constructor(&quot;jake&quot;)</code> 가 실행되는데, <code>Object.constructor()</code>는 내부에 무슨 인자가 오더라도 오직 <code>{}</code>만 반환한다. 그러므로 <code>{}.name</code>은 <code>undefined</code>가 되는 것이다.</p>
<h2 id="레퍼런스">레퍼런스</h2>
<blockquote>
<p><a href="https://ko.javascript.info/function-prototype">https://ko.javascript.info/function-prototype</a> </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[#1 프로토타입]]></title>
            <link>https://velog.io/@jakeseo_me/1-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@jakeseo_me/1-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85</guid>
            <pubDate>Wed, 29 Sep 2021 00:22:06 GMT</pubDate>
            <description><![CDATA[<h2 id="프로토타입이-해결하려는-문제">프로토타입이 해결하려는 문제</h2>
<p>객체지향을 배우다보면, 항상 나오는 핵심 개념으로 &#39;상속&#39;이라는 개념이 있다. &#39;상속&#39;이란 말 그대로 부모가 가진 특성을 자식이 그대로 이어받는 것을 말한다. 객체에는 크게 멤버와 메소드가 존재하는데, 자바와 같은 언어에서 부모 객체를 상속 받으면 멤버와 메소드가 그대로 자식 객체에 전달된다.</p>
<p>실제 예를 들자면 온라인 스토어 웹사이트에서 판매자(<code>Seller</code>)와 구매자(<code>Buyer</code>)는 모두 이용자(<code>User</code>)라는 카테고리 안에 들어갈 수 있다. 클린한 코드를 만들기 위해서 때때로 중요한 것은 이러한 공통사항을 추출하여 추상화하는 것이다. </p>
<p>그러면 먼저 가장 상위 부모 객체로 이용자(<code>User</code>)를 만들어놓고, 이용자가 가지는 공통적인 속성을 몇개 정의해보자.</p>
<ul>
<li>이용자 실명 (<code>username</code>)</li>
<li>이용자 아이디 (<code>id</code>)</li>
<li>이용자 패스워드 (<code>password</code>)</li>
<li>이용자 이메일 (<code>email</code>)</li>
</ul>
<p>간단하게 자바 클래스로 정의해보면 아래와 같을 것이다.</p>
<pre><code class="language-java">public class User {
  private String username;
  private String id;
  private String password;
  private String email;
}</code></pre>
<p>만약에 여기서 판매자는 &#39;판매 물품 정보&#39;만 더 가지고 구매자는 &#39;구매 물품 정보&#39;만 더 가진다고 해보자. 간단하게 다음과 같이 정의할 수 있다.</p>
<pre><code class="language-java">public class Seller extends User {
  private ArrayList&lt;String&gt; sellItems;
}</code></pre>
<pre><code class="language-java">public class Buyer extends User {
  private ArrayList&lt;String&gt; buyItems;
}</code></pre>
<p>물론 사실 전통적 OOP 상속에 대한 몇가지 단점을 아는 사람도 있겠지만, 일단은 추상화로 인해 코드 자체가 매우 깔끔해졌다. 프로토타입도 이와 비슷한 기능을 제공하고 있다는 게 프로토타입의 시작이다.</p>
<h2 id="사실-프로토타입-기반-언어인-자바스크립트">사실 프로토타입 기반 언어인 자바스크립트</h2>
<p>자바스크립트는 상속을 위해 <code>prototype</code> 오브젝트를 가질 수 있기 때문에 <strong>prototype-based language</strong>라고 불리기도 한다. <code>prototype</code> 오브젝트는 메소드와 프로퍼티를 상속하기 위한 템플릿 오브젝트쯤으로 보면 된다.</p>
<h3 id="프로토타입-체인">프로토타입 체인</h3>
<p>그리고 이러한 <code>prototype</code> 오브젝트는 또 다른 <code>prototype</code> 오브젝트에서 메소드와 프로퍼티를 상속받을 수도 있다. 이렇게 <code>prototype</code>이 다른 <code>prototype</code>을 상속하는 것에 대하여 <strong>prototype chain</strong>이라는 용어를 사용한다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/a2de004d-fef3-4f20-8988-1a31111fb8ae/image.png" alt=""></p>
<blockquote>
<p>객체 내부에 프로토타입이 존재하고, 그 프로토타입은 사실 다른 프로토타입의 자식 프로토타입으로서 동작하고 있을 수 있다.</p>
</blockquote>
<h3 id="자바-객체-상속과의-프로토타입-상속과의-차이">자바 객체 상속과의 프로토타입 상속과의 차이</h3>
<p>자바 객체 상속에서는 자바 객체에 상속한 모든 내용이 들어있는 반면에 자바스크립트의 프로토타입은 각 객체에 직접 들어있는 것이 아닌 객체 생성자의 <code>prototype</code>이라는 속성에 정의되어 있다. </p>
<p>Javascript에서는 오브젝트 인스턴스와 그 프로토타입 사이에 연결이 형성되고, 프로토타입 체인을 타고 올라가며 속성과 메소드를 찾는 일은 흔한 일이다. (생성자의 <code>prototype</code> 프로퍼티로부터 나온 <code>__proto__</code> 프로퍼티가 해당 객체의 프로토타입이다.)</p>
<h3 id="생성자-함수의-prototype-속성">생성자 함수의 prototype 속성</h3>
<p>한가지 알아두고 가면 좋은 것이 있는데, <code>Object.getPrototypeOf(obj)</code>함수 혹은 deprecated 된 <code>__proto__</code> 속성으로 접근 가능한 객체의 프로토타입과 생성자의 프로토타입의 차이를 인지하는 것이 중요하다. </p>
<pre><code class="language-js">function Person(name, age) {
  this.name = name;
  this.age = age;
}</code></pre>
<p>위와 같은 코드가 있을 때 생성자 함수인 <code>Person</code>은 자신만의 프로토타입 속성을 가지고 있고, 해당 프로토타입은 <code>Object.getPrototypeOf(Person)</code>으로 접근 가능하다. 그런데 사실 <code>Person</code>은 <code>Person.prototype</code>이라는 속성을 하나 더 갖고 있다. 이렇게 생성자 함수가 가지고 있는 <code>prototype</code> 속성은 이 생성자 함수의 인스턴스를 위한 청사진 역할을 한다.</p>
<p><code>new Person()</code>을 이용해 객체를 생성했을 때, 생성된 객체는 <code>Person.prototype</code>을 <code>__proto__</code>로 물려받게 된다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/978962b7-47e1-495c-8567-f78465f3501b/image.png" alt=""></p>
<p>위 코드의 결과에서 <code>true</code>를 보면 대략적으로 이해가 될 것이다.</p>
<h2 id="프로토타입-오브젝트-이해하기">프로토타입 오브젝트 이해하기</h2>
<pre><code class="language-js">function Person(name, age) {
  this.name = name;
  this.age = age;
}</code></pre>
<p>위에서 정의한 <code>Person</code> 생성자로 부터 예제 코드를 하나씩 돌려보며 프로토타입을 이해해보자.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/defc100a-8c73-4b53-9903-4768d5342fe9/image.png" alt=""></p>
<p>콘솔에 <code>person1</code>이라는 이름을 갖는 새로운 <code>Person</code> 객체를 만들어놨다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/45c862db-e512-4f0d-9037-e172b0c8b90a/image.png" alt=""></p>
<p>위와 같이 <code>.</code> 기호를 이용해 해당 오브젝트가 가지고 있는 메소드들을 볼 수 있는데, <code>toString()</code>, <code>valueOf()</code>와 같은 메소드들이 보인다. 이는 최상위 객체인 <code>Object</code>의 프로토타입인 <code>Object.prototype</code>을 상속한 것이다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/dbf9c0a1-d36d-4ac4-9e14-6385597be340/image.png" alt=""></p>
<p><code>Object.prototype</code>에는 아래와 같이 다양한 메소드가 존재한다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/cebd6f41-10c4-4d75-beb5-cca1a6d42acd/image.png" alt=""></p>
<p>그렇다면 만일 <code>Object.prototype</code>으로부터 물려받은 메소드를 실행해보면 어떤 결과가 나올까?</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/20219c9d-1bbf-4c7a-8b12-350576938908/image.png" alt=""></p>
<p>그냥 오브젝트가 그대로 결과로 나온다. 그리고 <code>[[Prototype]]</code>에는 <code>Object</code>가 들어있다. 결과는 별 거 없지만, 이 때 내부적으로 일어난 일은 다음과 같다.</p>
<ul>
<li>브라우저는 처음으로 <code>person1</code> 오브젝트가 <code>valueOf()</code> 메소드를 가지고 있는지 확인한다. 이전에 사용했던 생성자 <code>Person()</code>에 <code>valueOf()</code> 메소드가 있었다면, <code>person1</code>에도 <code>valueOf()</code> 메소드가 있었을테지만, 없었다.</li>
<li>브라우저는 다음으로 <code>person1</code>의 프로토타입 오브젝트에 <code>valueOf()</code> 메소드가 있는지 확인한다. 이번에도 없다.  그 이후에 브라우저는 <code>person1</code>의 프로토타입 오브젝트의 프로토타입 오브젝트를 확인한다. 거기엔 있다. 발견된 메소드가 호출된다.</li>
</ul>
<blockquote>
<p><img src="https://images.velog.io/images/jakeseo_me/post/7b80b940-0633-4860-818b-65ba235a2208/image.png" alt="">
만일 위와 같이 <code>this.valueOf</code>가 내부에 함수로 존재했다면, 프로토타입을 찾아보기 이전에 이미 해당 함수를 찾아서 실행했을 것이다.</p>
</blockquote>
<h2 id="프로토타입이란-상속-받은-멤버들이-정의된-곳이다">프로토타입이란, 상속 받은 멤버들이 정의된 곳이다.</h2>
<h3 id="상속-받는-것들과-그렇지-않은-것들">상속 받는 것들과 그렇지 않은 것들</h3>
<p>사실 <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a> 레퍼런스에는 아래에 보이듯, 수많은 속성과 메소드들이 존재한다. </p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/e6fe36fb-1078-48d9-a4ad-1b9b171bcc24/image.png" alt=""></p>
<p>사실 이전에 보았던 <code>person1</code>이 상속받은 것들은 그 중 일부일 뿐이다. 그러면 상속하는 것과 그렇지 않은 것은 어떻게 구분할까? 정답은 <strong><code>.prototype</code>에 있는 것만 상속한다.</strong> </p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/a94544c7-8cf3-4b59-8c67-104a38cc677e/image.png" alt=""></p>
<p>위에 보이는 것들만 상속이 된다.</p>
<blockquote>
<p>여기서 다른 언어를 쓰다 온 사람은 뭔가 위화감을 느낄 것이다. &quot;클래스 선언도 안하고 함수에서 생성자를 사용하고 멤버와 메소드도 정의한다고?&quot; 그렇다. 자바스크립트에서는 함수도 그저 객체 중 하나일 뿐이다. <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function">Function() 생성자</a> 레퍼런스를 확인해보자.</p>
</blockquote>
<h3 id="자바-표준-내장-객체의-프로토타입">자바 표준 내장 객체의 프로토타입</h3>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects">자바 표준 내장 객체들</a>의 프로토타입을 확인해보면 자바스크립트 전반에 걸쳐 프로토타입 체인 상속이 어떻게 구성되어 있는지 확인해볼 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/e6ea6ed7-1cc1-49ea-8fd2-6ab82404f50f/image.png" alt=""></p>
<blockquote>
<p><code>String</code>을 생성자로 이용하면 위와 같이 어마어마한 메소드들이 프로토타입으로 연결될 것이다. 자바스크립트에서는 그냥 문자열 선언을 하면 자동으로 <code>String</code>이 프로토타입으로 붙는다. 그렇기에 우리는 <code>.split()</code>, <code>.indexOf()</code> 등 유용한 메소드를 마음대로 이용할 수 있는 것이다.</p>
</blockquote>
<p><img src="https://images.velog.io/images/jakeseo_me/post/10461183-8c70-408c-b6d0-8ac3835dcd9d/image.png" alt=""></p>
<p>그 외에 다른 많은 객체들이 존재한다.</p>
<h3 id="단-__proto__와-prototype은-다르다는-것을-주의해야-한다">단, <code>.__proto__</code>와 <code>.prototype</code>은 다르다는 것을 주의해야 한다.</h3>
<p><code>.__proto__</code>도 한국어로 하면 프로토타입이라고 부르기 쉽고 <code>.prototype</code>도 한국어로 하면 프로토타입 이라 불리기 쉽다. 그러나 <code>.__proto__</code>즉, <code>Object.getPrototypeOf(object)</code>로 얻을 수 있는 내용은 내가 상속받은 프로토타입의 내용인 것이고, <code>.prototype</code>으로 얻을 수 있는 내용은 내가 상속하는 객체에게 줄 프로토타입의 내용임을 인지하자.</p>
<h3 id="objectcreate-메소드는-인자로-받은-객체를-프로토타입으로-만든다">Object.create() 메소드는 인자로 받은 객체를 프로토타입으로 만든다.</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/9036a8c6-4a04-42cd-a7e0-c13352911013/image.png" alt=""></p>
<p>위와 같이 만일 <code>Object.create(person1)</code>이라는 구문으로 객체를 생성하게 되면, 상속받은 프로토타입이 위치하는 <code>.__proto__</code>에는 <code>person1</code> 객체가 그대로 들어가게 된다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/cf7454ba-ea90-4b1c-a970-5586c63012b0/image.png" alt=""></p>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/create">Object.create() 메소드의 공식문서</a>에도 자세히 나와 있다.</p>
<h2 id="생성자를-잘-모를-때-constructor-꼼수-사용하기">생성자를 잘 모를 때, constructor 꼼수 사용하기</h2>
<p>모든 자바스크립트 오브젝트는 <code>constructor</code>를 가지고 있다. <code>object.constructor()</code>를 이용하면 해당 오브젝트를 생성했던 생성자를 다시 불러올 수 있으므로, 어떤 생성자로 생성되었는지 모를 때 사용하면 유용하다.</p>
<p>이를테면 다음과 같은 것이 가능하다.</p>
<h2 id="프로토타입으로-상속된-모든-오브젝트에-공통-메소드-추가하기">프로토타입으로 상속된 모든 오브젝트에 공통 메소드 추가하기</h2>
<h3 id="array에-새-메소드-추가해보기">Array에 새 메소드 추가해보기</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/015925a4-66d3-4333-9f3c-402e132ba1ea/image.png" alt=""></p>
<p>위와 같이 <code>nums1</code>과 <code>nums2</code>라는 숫자 배열 2개를 만들었다고 가정하자.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/11f59d43-5502-447d-9aed-8ad3cadc6b5a/image.png" alt=""></p>
<p>그리고 위와 같이 <code>Array.prototype</code>에 새로운 함수를 추가했다면,</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/79e94914-82ce-4258-bf2b-16209120edde/image.png" alt=""></p>
<p>모든 <code>Array</code>를 상속받은 곳에서 이용 가능하다.</p>
<h3 id="person에-새-메소드-추가해보기">Person에 새 메소드 추가해보기</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/ee988a72-8df3-44e7-87ef-7da158cc22fd/image.png" alt=""></p>
<p>위와 같이 내가 정의했던 생성자 함수의 프로토타입에도 추가할 수 있어서 용이하다.</p>
<h2 id="prototype에는-메소드는-추가해도-변수-상수는-잘-추가하지-않는다">Prototype에는 메소드는 추가해도 변수, 상수는 잘 추가하지 않는다.</h2>
<p><img src="https://images.velog.io/images/jakeseo_me/post/7d4ae8d7-be41-46d5-b07b-00fe50625464/image.png" alt=""></p>
<p>만일 <code>prototype</code>에서 위와 같이 해당 객체가 가지고 있는 <code>name</code>과 <code>age</code>를 출력시키려고 위와 같이 정의한다면, <code>undefined</code>가 나온다. 왜냐하면 함수 내부에서는 <code>this</code>가 해당 객체의 컨텍스트를 잘 가리키지만, 함수 밖에서는 <code>window</code> 객체를 가리키고 있기 때문이다.</p>
<p>물론 상수는 넣어도 되겠지만, 일반적으로 상수는 처음 function에서 <code>this.</code>로 추가해주는 편이 좋다.</p>
<h2 id="자바스크립트-객체와-prototype-다시보기">자바스크립트 객체와 [[Prototype]] 다시보기</h2>
<p>자바스크립트를 처음 배울 때는 잘 모르지만, 자바스크립트의 객체는 사실 이전에 살펴봤듯, <code>[[Prototype]]</code>이라는 숨김 프로퍼티를 갖는다. <code>[[prototype]]</code>에 물론 <code>null</code>이 들어올 수도 있다. </p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/9f1b7377-3b8d-4936-9723-cfffa86b5ab7/image.png" alt=""></p>
<p>위와 같이 간단한 생성자 함수를 만들었을 때,</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/7562398e-f0f6-43d6-9f65-be620bc7f540/image.png" alt=""></p>
<p>기본으로 <code>[[Prototype]]</code>에는 최상위 오브젝트인 <code>Object</code>를 참조하고 있다. </p>
<h3 id="예제-코드---prototype을-이용해-프로토타입-체인-객체-상속해보기">예제 코드 - [[Prototype]]을 이용해 프로토타입 체인 객체 상속해보기</h3>
<p>우리는 <code>.__proto__</code> 속성을 사용해서 <code>[[Prototype]]</code>에 들어갈 오브젝트를 직접 정해줄 수도 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/cbeba075-0fe8-4cdf-a9b4-6573f3717561/image.png" alt=""></p>
<p>위 코드의 실행결과를 보면 이해가 한층 쉽다. <code>rabbit.__proto__</code>로 <code>animals</code>를 할당했을 때는 <code>rabbit.eats</code>가 <code>true</code>가 되고, <code>rabbit.jumps</code>도 <code>true</code>가 된다. 말 그대로 <code>animals</code>에 있던 속성을 그대로 상속받는데, <code>rabbit.__proto__ = {}</code>와 같이 빈 오브젝트를 다시 할당했더니 <code>rabbit.eats</code>도 <code>undefined</code>가 되었다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/82fce283-6913-4ea4-871e-d3f372b5b709/image.png" alt=""></p>
<p>상속으로 인해 <code>animals</code>가 부모 클래스가 되고, <code>rabbit</code>이 자식 클래스인 구조가 되었다. <code>rabbit</code>이 물려받은 <code>eats</code> 프로퍼티는 &#39;상속 프로퍼티&#39;라고 부른다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/44098303-c3f6-4882-b88d-05a15411eb8f/image.png" alt=""></p>
<p>위와 같이도 이용 가능하다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/0305a0dc-9a0d-46bc-94fa-4c6c3986fac2/image.png" alt=""></p>
<p>이렇게 위의 <code>male</code>을 상속하여 <code>jake</code>를 만들 수도 있다. 그러면 구조는 다음과 같아진다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/36ba0294-6ef4-4957-9d2e-b0bdc1121c72/image.png" alt=""></p>
<p>말 그대로 체인이 생긴다. <code>Jake</code>는 <code>Male</code>을 구현한 것이고, <code>Male</code>은 <code>Human</code>을 구현한 것이다.</p>
<h3 id="prototype의-제약사항">[[Prototype]]의 제약사항</h3>
<ol>
<li>순환참조는 허용되지 않는다. <code>__proto__</code>를 이용해 닫힌 형태로 다른 객체를 참조하면 에러가 발생</li>
<li><code>[[Prototype]]</code>을 정의할 수 있는 <code>.__prototype__</code> 속성에는 <code>object</code>나 <code>null</code>만 들어갈 수 있다. 다른 타입은 넣어도 무시당한다</li>
<li>하나의 <code>[[Prototype]]</code>만 가능하다. 객체는 두개의 프로토타입을 상속받진 못한다.</li>
</ol>
<h2 id="값을-씌울-때는-프로토타입을-사용하지-않는다">값을 씌울 때는 프로토타입을 사용하지 않는다.</h2>
<pre><code class="language-js">let animal = {
  eats: true,
  walk() {
    alert(&quot;usual animal walk&quot;);
  }
};

let rabbit = {
  __proto__: animal
};

rabbit.walk = function() {
  alert(&quot;it&#39;s not usual animal! it&#39;s Rabbit! Bounce-bounce!&quot;);
};

rabbit.walk(); // Rabbit! Bounce-bounce!</code></pre>
<p>위와 같은 코드가 있을 때, <code>rabbit</code>은 다른 <code>animal</code>들과는 걸어다니는 방식이 다르기 때문에 <code>rabbit</code>만의 <code>walk()</code>메소드를 따로 추가해주고 싶다면, 프로토타입을 사용하는 것이 아니라 그냥 <code>rabbit.walk</code> 프로퍼티에 함수를 추가해주면 된다. 그러면, 자바스크립트에서 프로토타입을 뒤져보는 단계 전에 이미 내부 프로퍼티 메소드인 <code>walk</code>를 찾기 때문에 정상동작한다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/e7474e66-c6b7-4f15-aec3-a3a657cd1bcb/image.png" alt=""></p>
<h3 id="간혹-주의해야-할-것-접근자-프로퍼티">간혹 주의해야 할 것, 접근자 프로퍼티</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/8ff722e1-7206-49ef-b1b8-b208a6b06576/image.png" alt=""></p>
<p>위와 같이 프로퍼티에서 <code>get</code>, <code>set</code>을 붙여 접근자 프로퍼티를 만든 경우에는 <code>name.fullName = &quot;&quot;</code>를 수행한다고 해도 실제로 프로퍼티에 값을 넣는 행위가 실행되지 않고 지정한 <code>getter</code> 메소드가 실행되니 동작에 오해가 없도록 주의해야 한다.</p>
<h3 id="알면-좋은것-접근자-프로퍼티의-this">알면 좋은것, 접근자 프로퍼티의 this</h3>
<pre><code class="language-js">const name = {
  lastName: &#39;Seo&#39;,
  firstName: &#39;Jake&#39;,
  set fullName(value) {
    [this.firstName, this.lastName] = value.split(&quot; &quot;);
  },
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

const englishName = {
  isEnglish: true,
  __proto__: name
};

englishName.fullName = &quot;Paul Seo&quot;;</code></pre>
<p>위와 같은 코드를 실행시키면, <code>englishName.fullName</code>의 <code>setter</code>는 <code>name</code> 객체의 <code>lastName</code>, <code>firstName</code>을 바꿀지 아니면 <code>englishName</code>객체의 <code>lastName</code>, <code>firstName</code>을 바꾸게 되는 것인지 잘 알아두는 것이 좋다.</p>
<p><code>setter</code>는 프로토타입에 들어있더라도 프로퍼티를 할당하거나 불러올 때 대신 실행되는 함수일 뿐, 그 이상도 그 이하도 아니다. 그래서 <code>this</code>에서 실행 컨텍스트가 어떻게 될지 잘 안다면, 여기서는 당연히 <code>englishName</code>의 다음에 <code>.fullName</code>을 하였으므로, <code>.</code> 앞에 있는 것은 <code>englishName</code>이다.</p>
<p>그래서 <code>englishName</code>의 <code>lastName</code>, <code>firstName</code> 프로퍼티가 바뀌게 된다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/1db4219c-d148-46cc-be54-0044fc1b338f/image.png" alt=""></p>
<blockquote>
<p><strong><code>this</code>의 실행 컨텍스트는 프로토타입에 영향을 받지 않는다. 프로토타입은 메소드 자체는 공유하지만, 객체의 상태 공유와는 상관없다.</strong></p>
</blockquote>
<h2 id="forin은-프로토타입으로부터-상속받은-프로퍼티도-순회한다">for...in은 프로토타입으로부터 상속받은 프로퍼티도 순회한다.</h2>
<pre><code class="language-js">const animal = {
  eats: true
};

const rabbit = {
  jumps: true,
  __proto__: animal
};

alert(Object.keys(rabbit)); // jumps

for(let prop in rabbit) alert(prop); // jumps, eats</code></pre>
<ul>
<li><code>Object.keys()</code>: 상속받은 프로퍼티를 제외하고, 객체에서 선언된 프로퍼티만을 순회</li>
<li><code>for ... in</code>: 상속받은 프로퍼티와 객체에서 선언된 프로퍼티 모두를 순회</li>
</ul>
<h3 id="objecthasownproperty를-이용하면-구분-가능하다">object.hasOwnProperty()를 이용하면 구분 가능하다.</h3>
<pre><code class="language-js">const animal = {
  eats: true
};

const rabbit = {
  jumps: true,
  __proto__: animal
};

for(let property in rabbit) {
  const isOwnProperty = rabbit.hasOwnProperty(property);

  if(isOwnProperty) {
     alert(`상속받지 않은 프로퍼티: ${property}`); 
  } else {
     alert(`상속받은 프로퍼티: ${property}`); 
  }
}</code></pre>
<p>상속받은 프로퍼티로 <code>eats</code>가 잘 나오고, 상속받지 않은 프로퍼티로 <code>jumps</code>가 잘 나온다.</p>
<h3 id="그렇다면-hasownpropety는-어디서-온-것일까">그렇다면 .hasOwnPropety()는 어디서 온 것일까?</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/b9a2d7d0-70a3-434f-b29e-29ae02736fd2/image.png" alt=""></p>
<p>위는 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty">MDN 공식문서 중 Object.prototype.hasOwnProperty()</a> 부분을 캡처한 것이다. 위에서 볼 수 있듯, <code>hasOwnProperty()</code>는 <code>Object</code> 프로토타입에 내장된 메소드 중 하나이다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/4af139ae-3c79-49f7-9c32-3dc4fda64902/image.png" alt=""></p>
<p>프로토타입 체인을 살펴보면 위와 같이 구성되어 있기 때문에 가능한 것이다.</p>
<blockquote>
<p><code>animal</code>은 객체 리터럴로 선언되었기에 <code>Object</code> 프로퍼티를 프로토타입 객체로 갖는다.</p>
</blockquote>
<h3 id="그렇다면-forin에-hasownproperty가-걸리지-않은-이유는">그렇다면 for...in에 hasOwnProperty()가 걸리지 않은 이유는?</h3>
<p><code>for...in</code>은 이전에 보았듯, 상속받은 프로퍼티도 모두 순회한다. 그런데 왜 <code>hasOwnProperty()</code>에 걸리지 않았을까? 그 이유는 <code>enumerable</code> 플래그에 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/cedaf5a4-91ee-46b6-a999-d74193838f8c/image.png" alt=""></p>
<p><code>object.propertyIsEnumerable()</code> 메소드를 통해 해당 프로퍼티가 순회 가능한지 알아볼 수 있다.</p>
<h3 id="enumerable-플래그를-설정하는-방법">enumerable 플래그를 설정하는 방법</h3>
<p><code>enumerable</code> 플래그를 설정하려면, <code>Object.defineProperty()</code>를 이용하면 된다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/1ef7f30b-7a05-4923-bf2f-be4b7762777e/image.png" alt=""></p>
<p>위는 <code>defineProperty()</code> 메소드를 이용해서 <code>enumerable</code>에 <code>false</code>를 할당한 예이다. 이렇게 하면 <code>for ... in</code>에서 해당 프로퍼티를 순회하지 않는다.</p>
<h2 id="정리">정리</h2>
<ul>
<li>자바스크립트의 모든 객체에는 숨김 프로퍼티 <code>[[Prototype]]</code>이 있는데, 이 객체에서는 다른 객체 혹은 <code>null</code>을 가리킨다.</li>
<li><code>[[Prototype]]</code>이 참조하는 객체를 프로토타입 객체라고 한다.</li>
<li>객체에서 메소드를 실행하면, 처음에 해당 객체의 프로퍼티부터 뒤져보고 없다면, 프로토타입과 프로토타입의 프로토타입을 순서대로 뒤진다.</li>
<li><code>accessor</code> 프로퍼티라고 불리는 <code>getter</code>, <code>setter</code> 등은 프로토타입을 뒤지지 않고, 그냥 함수로서 실행된다.</li>
<li><code>accessor</code> 프로퍼티가 프로토타입에 선언되어 있더라도 <code>this</code>의 실행 컨텍스트는 프로토타입에 영향을 받지 않는다.</li>
<li><code>for...in</code>은 자신의 프로퍼티 뿐만 아니라 상속받은 프로퍼티까지 순회한다.</li>
<li><code>object.defineProperty</code>로 <code>enumerable</code>을 <code>false</code>로 만들면 해당 프로퍼티는 순회하지 않는다.</li>
</ul>
<h2 id="프로토타입-예제코드-몇개로-복습하기">프로토타입 예제코드 몇개로 복습하기</h2>
<h3 id="자바스크립트-객체가-값을-찾는-순서">자바스크립트 객체가 값을 찾는 순서</h3>
<pre><code class="language-js">let animal = {
  jumps: null
};
let rabbit = {
  __proto__: animal,
  jumps: true
};

alert( rabbit.jumps ); // ? (1)
delete rabbit.jumps;
alert( rabbit.jumps ); // ? (2)
delete animal.jumps;
alert( rabbit.jumps ); // ? (3)</code></pre>
<p>위 코드의 결과는 순서대로 <code>true</code>, <code>null</code>, <code>undefined</code>가 나온다. 코드에서 <code>rabbit.jumps</code>는 <code>rabbit</code> 객체의 <code>jumps</code> 프로퍼티를 찾는다는 뜻이고, 프로퍼티를 찾는 순서는 아래와 같다.</p>
<ol>
<li>해당 객체가 직접 가지고 있는지</li>
<li>프로토타입에서 가지고 있는지 </li>
</ol>
<p>처음에는 1.로 찾았을 때 바로 나오는 케이스고, 그 뒤에는 <code>rabbit</code>의 <code>jumps</code> 속성을 지웠기 때문에 <code>animal</code>의 <code>jumps</code> 속성이 나오게 되고, 그 뒤에는 <code>animal</code>의 <code>jumps</code> 속성도 지우기 때문에 끝끝내 찾지 못해 <code>undefined</code>가 나온다.</p>
<h3 id="프로토타입-체인-만들어보기">프로토타입 체인 만들어보기</h3>
<pre><code class="language-js">const _head = {
  glasses: 1
};

const _table = {
  pen: 3
};

const _bed = {
  sheet: 1,
  pillow: 2
};

const _pockets = {
  money: 2000
};

_pockets.__proto__ = _bed;
_bed.__proto__ = _table;
_table.__proto__ = _head;</code></pre>
<p>위와 같이 코드를 짜면 <code>_pockets &gt; _bed &gt; _table &gt; _head</code> 순으로 프로토타입 체인이 완성된다. 각각의 객체가 <code>[[Prototype]]</code> 프로퍼티에 다음 객체를 프로퍼티 타입으로 가지게 되는 것이다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/5aec966d-b95a-4883-a513-56df46b3a646/image.png" alt=""></p>
<ul>
<li>이렇게 체인을 구성하면 <code>_pockets.glasses</code>를 입력해도 1을 반환받을 수 있고, <code>_head.glasses</code>를 입력해도 1을 반환받을 수 있다. 다만 두 입력값 사이에는 프로토타입을 거치는지에 대한 차이가 있다.</li>
<li>또한 프로토타입 체인을 통해 값을 가져온데도 첫 접근 이후에는 해당 프로퍼티가 발견됐던 곳을 캐싱하기 때문에 성능상의 차이도 거의 없이 엔진에서 자동적으로 최적화가 된다.</li>
</ul>
<h3 id="프로토타입과-this">프로토타입과 this</h3>
<pre><code class="language-js">let animal = {
  eat() {
    this.full = true;
  }
};

let rabbit = {
  __proto__: animal
};

rabbit.eat();</code></pre>
<p>위 코드는 당연히 <code>rabbit</code> 객체의 <code>full</code> 프로퍼티를 <code>true</code>로 만들 것이다. 이전에도 나왔던 내용이지만, 프로토타입은 따로 실행 컨텍스트를 변경시키지 않는다. 프로퍼티를 찾는 것과 뭔가 실행하는 것은 다른 일로 보는 것이 맞다.</p>
<h3 id="프로토타입과-this-2">프로토타입과 this 2</h3>
<pre><code class="language-js">let hamster = {
  stomach: [],

  eat(food) {
    this.stomach.push(food);
  }
};

let speedy = {
  __proto__: hamster
};

let lazy = {
  __proto__: hamster
};

// 햄스터 한 마리가 음식을 찾았습니다.
speedy.eat(&quot;apple&quot;);
alert( speedy.stomach ); // apple

// 이 햄스터도 같은 음식을 가지고 있습니다. 왜 그럴까요? 고쳐주세요.
alert( lazy.stomach ); // apple</code></pre>
<p>위 코드의 경우에는 약간 예상과 다른 결과가 나올 수 있는데, 그 이유는 <code>this.stomach.push()</code> 부분에서 자바스크립트가 <code>this.stomach</code>를 프로토타입 체인을 통해 찾아다니기 때문이다. 그러면 <code>speedy</code>와 <code>lazy</code>가 공통으로 사용하고 있는 프로토타입 객체 <code>hamster</code>가 가진 <code>stomach</code>를 공유하는 일이 벌어진다. 그러지 않기 위해서는 다음과 같은 코드를 작성하면 된다.</p>
<pre><code class="language-js">let hamster = {
  stomach: [],

  eat(food) {
    // this.stomach.push 대신에 this.stomach에 할당
    this.stomach = [food];
  }
};

let speedy = {
   __proto__: hamster
};

let lazy = {
  __proto__: hamster
};

// Speedy는 음식을 발견합니다.
speedy.eat(&quot;apple&quot;);
alert( speedy.stomach ); // apple

// Lazy의 stomach는 비어있습니다.
alert( lazy.stomach ); // &lt;nothing&gt;</code></pre>
<p>위는 어떤 프로퍼티에 무언가를 할당할 때는 프로토타입 체인을 이용하지 않는 점을 활용한 코드이다. 위 경우에는 그냥 <code>speedy.stomach</code>에 <code>[apple]</code>이 들어가게 된다. 그러나, 위 방법으로는 딱 한가지 음식밖에 못담는다.</p>
<pre><code class="language-js">let hamster = {
  stomach: [],

  eat(food) {
    this.stomach.push(food);
  }
};

let speedy = {
  __proto__: hamster,
  stomach: []
};

let lazy = {
  __proto__: hamster,
  stomach: []
};

// speedy는 음식을 발견합니다.
speedy.eat(&quot;apple&quot;);
alert( speedy.stomach ); // apple

// lazy의 stomach은 비어있습니다.
alert( lazy.stomach ); // &lt;nothing&gt;</code></pre>
<p>위와 같이 코드를 작성하면, 프로토타입을 뒤져보기 전에 이미 해당 객체에 <code>stomach</code> 배열이 존재하니 독립된 <code>stomach</code>를 이용하는 것이 가능해진다.</p>
<h2 id="레퍼런스">레퍼런스</h2>
<blockquote>
<p><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes</a>
<a href="https://ko.javascript.info/prototype-inheritance#ref-530">https://ko.javascript.info/prototype-inheritance#ref-530</a>
<a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes#%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85_%EA%B0%9D%EC%B2%B4_%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0">https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes#%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85_%EA%B0%9D%EC%B2%B4_%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[#2 이벤트 캡처링과 버블링]]></title>
            <link>https://velog.io/@jakeseo_me/2-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%BA%A1%EC%B2%98%EB%A7%81-%EB%B2%84%EB%B8%94%EB%A7%81</link>
            <guid>https://velog.io/@jakeseo_me/2-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%BA%A1%EC%B2%98%EB%A7%81-%EB%B2%84%EB%B8%94%EB%A7%81</guid>
            <pubDate>Sun, 26 Sep 2021 05:20:49 GMT</pubDate>
            <description><![CDATA[<h2 id="이벤트-버블링이란">이벤트 버블링이란?</h2>
<p>이벤트 버블링이란, UI상에 중첩된 DOM 요소에 이벤트가 걸려있을 때, 가장 구체적인 부분으로부터 밖으로 이벤트가 퍼져나가는 현상을 의미한다.</p>
<h3 id="예시-코드로-살펴보기">예시 코드로 살펴보기</h3>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;ko&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot; /&gt;
    &lt;title&gt;이벤트 버블링 테스트&lt;/title&gt;
    &lt;style&gt;
      div {
        border: 1px solid black;
        padding: 5px;
        max-width: 200px;
      }
    &lt;/style&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div
      id=&quot;hello&quot;
      onclick=&quot;alert(&#39;안녕하세요&#39; +  &#39;\n this.id: &#39; + this.id + &#39;\n event.target.id: &#39; + event.target.id)&quot;
    &gt;
      안녕하세요
      &lt;div
        id=&quot;mynameis&quot;
        onclick=&quot;alert(&#39;제 이름은&#39; +  &#39;\n this.id: &#39; + this.id + &#39;\n event.target.id: &#39; + event.target.id)&quot;
      &gt;
        제 이름은
        &lt;div
          id=&quot;jake&quot;
          onclick=&quot;alert(&#39;Jake입니다.&#39; +  &#39;\n this.id: &#39; + this.id + &#39;\n event.target.id: &#39; + event.target.id)&quot;
        &gt;
          Jake입니다.
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>해당 코드예제는 <a href="https://codesandbox.io/s/ibenteu-beobeulring-yeje-ly03c?file=/index.html">여기에서</a> 구경해볼 수 있다. 위 코드의 결과는 아래와 같다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/0c0ec084-2cee-415c-b2d2-b7b2dd11853d/image.png" alt=""></p>
<p>HTML 코드를 살펴보면 알 수 있듯, 3개의 DIV가 중첩된 형태이고, 각 DIV마다 <code>onclick</code> 이벤트가 걸려있다.</p>
<p>가장 안쪽 요소인 <code>Jake입니다.</code>를 클릭하면, 어떤 일이 일어날까?</p>
<p>순서대로 다음의 메시지가 출력된다.</p>
<ol>
<li>Jake입니다.</li>
<li>제 이름은</li>
<li>안녕하세요</li>
</ol>
<p>이게 바로 이벤트 버블링 현상이다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/9ecad76e-3140-4abe-97ab-535ccd7176d6/image.png" alt=""></p>
<p>동작의 핵심을 짚어보자면 위와 같은 DOM tree가 존재할 때, <strong>실제로 클릭한 하위 영역의 객체부터 <code>document</code> 객체를 만날 때까지 각 요소에 할당된 이벤트(<code>onclick</code>) 핸들러가 동작한다는 것이다.</strong></p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/2bc8beef-6a09-4ca9-b514-35a2b668f43f/image.png" alt=""></p>
<p>이렇게 가장 내부적인(구체적인) 요소에서부터 바깥 요소까지 이벤트가 퍼지게 된다. 버블링이라고 불리는 이유는 바닷속에서 우리가 공기를 뱉었을 때를 생각해보면 이해가 쉽다. 바닷속에서 공기를 뱉으면 기포 같은 게 뽀글뽀글 생기면서 수면 위까지 올라오게 된다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/d2ed53c6-0c75-464c-86b7-98aa3348c725/image.png" alt=""></p>
<blockquote>
<p>무료 이미지중에 찾다보니 마땅한게 이거밖에 없었다.. 저 거품은 수면 위로 떠오르게 될 것이다.</p>
</blockquote>
<h3 id="모든-이벤트가-버블링되지는-않는다">모든 이벤트가 버블링되지는 않는다.</h3>
<p>모든 이벤트가 버블링되진 않는다. <code>focus</code>처럼 버블링되지 않는 이벤트도 존재한다.</p>
<h2 id="이벤트-버블링이-가져오는-문제">이벤트 버블링이 가져오는 문제</h2>
<p>이벤트 버블링 때문에 주로 발생하는 문제는 </p>
<ol>
<li>내가 실제로 클릭한 <code>Element</code>에 대해서만 어떤 행동을 취하고 싶은데, 실제로 클릭한 요소를 알 수 있는 방법을 모르겠다.</li>
<li>내가 의도하지 않은 <code>Element</code>에도 이벤트가 걸려버렸다.</li>
</ol>
<p><img src="https://images.velog.io/images/jakeseo_me/post/0c0ec084-2cee-415c-b2d2-b7b2dd11853d/image.png" alt=""></p>
<p>이를테면 위 그림에서 <code>Jake입니다.</code>를 눌렀을 때 <code>alert</code> 메시지로 <code>Jake입니다.</code>만 출력시키고 싶은데, 자꾸 <code>안녕하세요</code> <code>제 이름은</code>까지 출력되는 현상이 발생하는 것이다. 물론, <code>div</code>가 겹치지 않게 배치해서 해결할 수도 있지만, <code>div</code>의 구조는 그대로 가져가고 싶다고 예를 들어보자.</p>
<h3 id="실제로-클릭한-element-구분하기---eventtarget과-this">실제로 클릭한 Element 구분하기 - event.target과 this</h3>
<p>사용자가 진짜로 클릭한 <code>Element</code>가 무엇인지 알기 위해서 <code>event.target</code>을 사용할 수 있다. 그리고 이 <code>event.target</code>은 <code>this</code>와 구분될 수 있다.</p>
<p><code>onclick</code>에 들어가는 코드를 유심히 살펴보자.</p>
<pre><code class="language-html">onclick=&quot;alert(&#39;안녕하세요&#39; +  &#39;\n this.id: &#39; + this.id + &#39;\n event.target.id: &#39; + event.target.id)&quot;</code></pre>
<p><code>this.id</code>와 <code>event.target.id</code>를 출력하도록 되어있다.</p>
<blockquote>
<p>해당 코드예제는 <a href="https://codesandbox.io/s/ibenteu-beobeulring-yeje-ly03c?file=/index.html">여기에서</a> 구경해볼 수 있다.</p>
</blockquote>
<p><code>Jake입니다.</code> 텍스트가 적혀있는 <code>div</code>를 클릭하고 결과를 확인해보자.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/d7247ff7-3a13-4164-97a8-b39fd7ecb46f/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/6449276e-0d62-4ec7-b7b3-5b947834a692/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/9fe02137-6dfa-43b5-9356-f64f3f6b6e7f/image.png" alt=""></p>
<p>가장 안쪽에 위치한 <code>div</code> 하나만 클릭했음에도 위에서 배웠던 <strong>&#39;버블링&#39;</strong> 때문에 3개의 메시지가 차례로 뜬다.</p>
<p>여기서 <strong>유심히 봐야 할 것은 <code>event.target.id</code>는 버블링에 의해 출력되는 메시지에서 한번도 변하지 않았다는 것이다. 그런데 <code>this</code>는 계속해서 변하고 있다.</strong></p>
<ul>
<li><code>event.target</code>: 사용자가 실제로 클릭한 Element</li>
<li><code>event.currentTarget(=this)</code>: 현재 등록된 이벤트가 트리깅된 Element</li>
</ul>
<p>위와 같이 정리할 수 있다.</p>
<h3 id="의도하지-않은-element에-이벤트-끊기---stoppropagation">의도하지 않은 Element에 이벤트 끊기 - stopPropagation()</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/9ecad76e-3140-4abe-97ab-535ccd7176d6/image.png" alt=""></p>
<p>버블링은 위와 같은 DOM tree를 타고 올라가는데, <code>HTML</code> 객체를 넘어 <code>document</code>를 만날 때까지 진행된다. 그런데 버블링이 해당 <code>Element</code>에서 더이상 버블링되지 않고 멈추게 하고 싶을 때가 있다. </p>
<p>그럴 때 사용하는 것이 <code>stopPropagation()</code> 함수이다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/600f6d2e-1844-4dd7-9be2-240aa9adc594/image.png" alt=""></p>
<p>영어단어 사전의 뜻 그대로 이벤트의 전파를 막는 역할을 한다.</p>
<pre><code class="language-html">&lt;div
          id=&quot;jake&quot;
          onclick=&quot;alert(&#39;Jake입니다.&#39; +  &#39;\n this.id: &#39; + this.id + &#39;\n event.target.id: &#39; + event.target.id); event.stopPropagation();&quot;
        &gt;
          Jake입니다.
        &lt;/div&gt;</code></pre>
<p>위처럼 <code>onclick</code> 이벤트의 끝에 <code>event.stopPropagation()</code>을 붙이면, </p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/9fe02137-6dfa-43b5-9356-f64f3f6b6e7f/image.png" alt=""></p>
<p>클릭 시, 이 메시지 하나만 나오게 된다.</p>
<h3 id="stopimmediatepropagation">stopImmediatePropagation()</h3>
<p><code>stopImmediatePropagation()</code>은 여러개의 이벤트가 하나의 <code>Element</code>에 걸려있을 때에 유용하다. 이를테면 한 <code>Element</code>에 두개의 <code>onclick</code> 이벤트 리스너를 단 경우를 생각해볼 수 있다.</p>
<p>한 <code>Element</code>에 여러 개의 <code>onclick()</code> 이벤트 리스너가 달렸다면, 가장 앞에 달린 <code>onclick</code> 이벤트부터 처리하다가, <code>stopImmediatePropagation()</code>를 만나는 순간 뒤 이후에 있는 <code>onclick</code> 이벤트들은 무시된다.</p>
<blockquote>
<p><a href="https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_event_stopimmediatepropagation">w3schools 링크</a>에서 체험해볼 수 있다.</p>
</blockquote>
<p><img src="https://images.velog.io/images/jakeseo_me/post/c06276eb-f38a-48ee-938d-73f23e5e6734/image.png" alt=""></p>
<p>그림으로 설명하면 위와 같다.</p>
<ul>
<li><code>stopPropagation</code>: 다른 <code>Element</code>로의 전파를 막는다.</li>
<li><code>stopImmediatePropagation</code>: 같은 <code>Element</code>의 다음 이벤트로의 전파를 막는다.</li>
</ul>
<h3 id="오히려-stoppropagation이-문제를-일으키는-경우">오히려 stopPropagation()이 문제를 일으키는 경우</h3>
<p><strong>버블링을 막을 때는 반드시 이유가 필요하다.</strong></p>
<p><code>stopPropagation()</code>을 의미없이 남발하면, 나중에 해당 이벤트 영역이 &#39;죽은 영역(dead zone)&#39;인지 구분하지 못하고 이벤트가 왜 동작하지 않는지 이해할 수 없는 경우가 생긴다.</p>
<p>어찌됐건간에 이벤트 버블링을 막아야 하는 경우는 거의 드물다. 버블링을 막아야 해결되는 문제는 <a href="https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent">CustomEvent</a>를 이용해 해결할 수도 있다. 핸들러의 <code>event</code> 객체에 데이터를 저장해 다른 핸들러에서 읽을 수 있게 하면 아래쪽에서 어떤 일이 일어나는지 부모 요소의 핸들러에게 전달할 수 있으므로, 이 방법으로도 이벤트 버블링을 통제할 수 있다.</p>
<blockquote>
<p>커스텀 이벤트는 <a href="https://ko.javascript.info/dispatch-events">여기</a>에서 공부해볼 수 있다.</p>
</blockquote>
<h2 id="이벤트-캡쳐링이란">이벤트 캡쳐링이란?</h2>
<p><img src="https://images.velog.io/images/jakeseo_me/post/dde7ebb4-a296-44ae-a4a9-786165f8a95f/image.png" alt=""></p>
<p>사실 위의 그림과 같이 버블링보다 먼저 일어나는 것이 캡처링이다. 자주 쓸 일이 생기진 않지만 가끔 유용할 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/dec2cd2c-6255-4fb7-8b31-a53cf44be304/image.png" alt=""></p>
<blockquote>
<p>위는 <a href="https://www.w3.org/TR/DOM-Level-3-Events/">w3.org에서 정한 표준 DOM 이벤트의 흐름</a>이다. 위 그림은 문서 내부 <code>&lt;td&gt;</code> 요소를 클릭했을 때의 경우이다.</p>
</blockquote>
<p>총 3가지 단계인데,</p>
<ol>
<li>캡처링 단계 - 이벤트가 하위 요소로 전파되는 단계</li>
<li>타깃 단계 - 이벤트가 실제 타깃 요소에 전달되는 단계</li>
<li>버블링 단계 - 이벤트가 상위 요소로 전파되는 단계</li>
</ol>
<p>이렇게 3단계가 있다.</p>
<p>우리는 보통 자바스크립트에서 <code>selector</code>를 이용해 <code>element</code>를 선택한 뒤에 <code>.addEventListener()</code> 메소드를 통해 이벤트를 등록한다. <code>.addEventListener()</code>의 두번째 파라미터에서 해당 이벤트를 캡처링 단계에서 동작하게 할 것인지를 정할 수 있다.</p>
<p><code>element.addEventListener(() =&gt; {doSomething;}, true)</code> 혹은 <code>element.addEventListener(() =&gt; {doSomething;}, {capture: true})</code>와 같은 방식으로 해당 이벤트가 캡처링 단계에서 동작하게 만들 수 있다.</p>
<h3 id="코드로-이해하기">코드로 이해하기</h3>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;ko&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot; /&gt;
    &lt;title&gt;이벤트 캡쳐링 + 버블링 테스트&lt;/title&gt;
    &lt;style&gt;
      div,
      p,
      form {
        border: 1px solid black;
        padding: 5px;
        max-width: 200px;
      }
    &lt;/style&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;form&gt;
      난 form 태그
      &lt;div&gt;
        난 div 태그
        &lt;p&gt;
          난 p 태그
        &lt;/p&gt;
      &lt;/div&gt;
    &lt;/form&gt;
    &lt;script&gt;
      for (let elem of document.querySelectorAll(&quot;*&quot;)) {
        elem.addEventListener(
          &quot;click&quot;,
          (e) =&gt; alert(`캡쳐링: ${elem.tagName}`),
          true
        );
        elem.addEventListener(&quot;click&quot;, (e) =&gt; alert(`버블링: ${elem.tagName}`));
      }
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>위 코드는 모든 <code>HTMLElement</code>에 버블링과 캡처링 이벤트를 건 코드이다.  </p>
<blockquote>
<p>위 코드의 실행결과는 <a href="https://codesandbox.io/s/ibenteu-kaebcyeoringgwa-beobeulring-yeje-5wnn7?file=/index.html">이 링크</a>에서 체험해볼 수 있다.</p>
</blockquote>
<p>실행 결과를 그림으로 표현하면 다음과 같이 실행된다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/e2d6e874-d3cd-4b09-9b6e-581a4d148030/image.png" alt=""></p>
<p>컬러풀한 좋은 그림으로 설명하면 아래와 같다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/467fcd62-2183-4f37-87f6-336cb32ce57d/image.png" alt=""></p>
<p><a href="https://domevents.dev/">이 웹사이트</a>에서 캡처링과 버블링을 체험해볼 수 있다.</p>
<blockquote>
<p>오잉? 3 단계라고 했는데 &#39;타겟 단계는 어디갔지?&#39; 생각한다면, 타겟 단계는 해당 엘리먼트에 대한 이벤트가 진행되는 시점이다. </p>
</blockquote>
<p><code>event.phase</code>로 이벤트 단계를 알 수 있다. 이전에 보여준 소스코드 예제에 <code>event.phase</code>를 넣어보면 단계를 알 수 있는데, <code>난 p 태그</code>라고 써져있는 텍스트를 클릭했을 때의 예시를 잠시 살펴보자.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/b3ab1f06-73a8-4a61-a830-bc7bb9a6d82a/image.png" alt=""></p>
<p>HTML이 캡처링되는 건 당연히 1단계이다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/1d8c9ba0-8a72-4254-8612-84cd5f12eeec/image.png" alt=""></p>
<p>BODY도 당연히 1단계고, 1단계인 캡처링은 타겟 요소에 도달할 때까지 유지된다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/3bfdc0e6-c3bf-42f9-bd7f-e7bb56dfeb5a/image.png" alt=""></p>
<p>타겟 요소에 도달하니 캡처링이긴 하지만, 2단계에 도달한 것을 확인할 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/0010cd98-a131-49a8-bba4-fb9cb2aebea5/image.png" alt=""></p>
<p>버블링도 타겟 요소에서는 2단계이며, 타겟을 벗어나면 3단계인 진짜 버블링이 일어난다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/b8b46fed-4d3e-47da-9039-60396fb1088e/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[#1 웹브라우저의 DOM과 기타 요소들]]></title>
            <link>https://velog.io/@jakeseo_me/1-%EC%9B%B9%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-DOM%EA%B3%BC-%EA%B8%B0%ED%83%80-%EC%9A%94%EC%86%8C%EB%93%A4</link>
            <guid>https://velog.io/@jakeseo_me/1-%EC%9B%B9%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-DOM%EA%B3%BC-%EA%B8%B0%ED%83%80-%EC%9A%94%EC%86%8C%EB%93%A4</guid>
            <pubDate>Sat, 25 Sep 2021 08:31:16 GMT</pubDate>
            <description><![CDATA[<h2 id="element">Element</h2>
<p>DOM, HTML 등을 설명하다보면 필연적으로 맞딱드리게 되는 것이 <code>Element</code>라는 용어이다. <code>Element</code>는 웹 페이지의 일부이며, <code>XML</code> 혹은 <code>HTML</code> 내부에서 텍스트나 이미지의 일부 혹은 데이터 아이템을 가지고 있을 수 있다. 물론 아무것도 가지고 있지 않는 것도 가능하다. 일반적인 <code>Element</code>는 <a href="https://developer.mozilla.org/en-US/docs/Glossary/Attribute">attributes</a>과 함께, 열린 태그로 시작하며 그 내부에 텍스트가 있고 닫는 태그로 끝나게 된다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/e552be46-7b1f-496e-b0f2-a11d3bfc3f56/image.png" alt=""></p>
<p><strong><code>Element</code>와 <a href="https://developer.mozilla.org/en-US/docs/Glossary/Tag">tag</a>는 동일한 것이 아니다.</strong> 태그는 소스코드에서 엘리먼트를 시작하거나 끝내긴 하지만, 엘리먼트는 브라우저에서 페이지를 보여주는 document model인 <a href="https://developer.mozilla.org/en-US/docs/Glossary/DOM">DOM</a>의 일부이다.</p>
<h3 id="인터페이스로서의-element">인터페이스로서의 Element</h3>
<p><code>Element</code>는 가장 일반적인 베이스 클래스로 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document">Document</a> 내부에 있는 모든 엘리먼트 오브젝트가 상속한다. 모든 종류의 엘리먼트에 공통적인 메소드와 프로퍼티만을 가지고 있다. 더 상세한 클래스들이 <code>Element</code>로부터 상속을 받는다.</p>
<p>이를테면 <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement">HTMLElement</a> 인터페이스는 HTML 엘리먼트들에 대한 베이스 인터페이스가 된다. <a href="https://developer.mozilla.org/en-US/docs/Web/API/SVGElement">SVGElement</a>인터페이스는 모든 SVG 엘리먼트의 베이스가 된다. 대부분의 기능은 계층 구조가 내려가면서 구체화된다.</p>
<p>XUL에서의 <code>XULElement</code>와 같이 웹 플랫폼 밖에서도 <code>Element</code>를 구현하기도 한다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/7218c0cb-97b3-46cc-8a56-4c7ac68a387b/image.png" alt=""></p>
<p><code>Element</code>는 <code>Node</code>를 구현하고, <code>Node</code>는 <code>EventTarget</code>을 구현한 것이다. 그래서 <code>Element</code>는 <code>Node</code>의 속성과 <code>EventTarget</code>의 속성을 상속한다.</p>
<p><a href="https://dom.spec.whatwg.org/#interface-element">whatwg의 doom spec 표준 interface element</a>에서 <code>Element</code> 인터페이스를 구경할 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/21692e02-dc1f-4863-b99a-233c6025fbe7/image.png" alt=""></p>
<h2 id="document">Document</h2>
<p>앞으로 설명에 <code>Document</code>라는 용어가 많이 등장하는데 <code>Document</code>는 <code>HTMLDocument</code>나 <code>XMLDocument</code>를 구현하는 인터페이스 정도로 보면 된다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/db279eff-23d9-49fe-9ddf-6ed2d0f721f7/image.png" alt=""></p>
<p><code>Document</code> 인터페이스는 브라우저에 로드된 웹페이지를 표시하며 웹페이지의 내용으로의 엔트리 포인트를 제공한다. 여기서 엔트리 포인트가 되는 것이 바로 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document">DOM tree</a>이다.</p>
<p>DOM tree는 <code>&lt;body&gt;</code>, <code>&lt;table&gt;</code>과 같은 엘리먼트들을 포함한다. DOM tree는 <code>document</code> 전역에 기능성을 제공하며, 그 기능성을 이용해 페이지의 URL을 얻거나 <code>document</code>에 새로운 엘리먼트를 추가하는 등의 행위를 할 수 있다.</p>
<p><code>Document</code> 인터페이스는 어떤 타입의 document이든 공통적인 프로퍼티와 메소드를 제공한다. document 의 타입은 <code>HTML</code>, <code>XML</code>, <code>SVG</code> 등 여러가지가 있는데, <code>&quot;text/html&quot;</code> content type을 가진 HTML documents의 경우에 더욱 많은 API를 제공한다. 또한 XML과 SVG에서는 <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLDocument">XMLDocument</a> 인터페이스를 구현하는 반면에 HTML documents에서는 <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLDocument">HTMLDocument</a> 인터페이스를 구현한다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/2efd87a0-e549-4978-b234-65cc8e4aab76/image.png" alt=""></p>
<p>브라우저 콘솔 화면에서 <code>document.</code>을 쳐보면 다양한 메소드들을 볼 수 있으며, 단순 웹페이지의 경우 <code>constructor</code> 옆에 회색 글씨로 <code>HTMLDocument</code>라고 적혀있는 것을 볼 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/feacbb97-b66e-4146-aedf-d7bcff659844/image.png" alt=""></p>
<p>XML 페이지에 접속한 경우에는 <code>constructor</code> 옆에 <code>XMLDocument</code>라는 회색글씨가 적혀있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/812e7575-db6e-4375-aca5-490f80b994b7/image.png" alt=""></p>
<h2 id="dom---구글링으로-찾은-dom">DOM - 구글링으로 찾은 DOM</h2>
<h3 id="dom이란">DOM이란?</h3>
<p>DOM은 웹 페이지에 대한 인터페이스이다. 웹페이지의 콘텐츠 및 구조, 스타일을 읽고 조작할 수 있도록 편리한 API도 제공한다. DOM을 이해하기 전에 웹 페이지가 어떻게 빌드되는지 이해해야 한다.</p>
<h3 id="웹-페이지가-빌드되는-과정">웹 페이지가 빌드되는 과정</h3>
<p>웹페이지가 빌드되려면 웹 브라우저가 HTML 문서를 읽고, 스타일을 입히고, 대화형 페이지로 만들어 뷰 포트에 표시해야 하는데, 이 과정을 <code>Critical Rendering Path</code>라고 한다. <a href="https://bitsofco.de/understanding-the-critical-rendering-path/">Critical Rendering Path 설명 링크</a>에 가보면 자세한 설명을 알 수 있다.</p>
<p>간단하게 6단계를 설명하면,</p>
<ol>
<li>DOM Tree 생성(Construct)</li>
<li>CSSOM Tree 생성(Construct)</li>
<li>자바스크립트 실행</li>
<li>Render Tree 생성(Create)</li>
<li>Layout 생성(Generate)</li>
<li>페인팅</li>
</ol>
<p>위 6단계를 2단계로 축약하면, </p>
<ol>
<li>브라우저가 HTML 문서를 파싱하여 어떤 내용을 페이지에 렌더링할지 결정한다.</li>
<li>렌더링을 실행한다.</li>
</ol>
<p>1번 과정을 거치면 위 6가지 항목 중 <code>4.</code>에 해당하는 <code>Render Tree</code>가 생성되며, <code>Render Tree</code>는 HTML 요소와 스타일 요소로 구성된다. 브라우저는 렌더 트리를 생성하기 위해 다음의 두 모델이 필요하다.</p>
<ul>
<li>DOM(Document Object Model) - HTML Elements들의 구조화된 표현</li>
<li>CSSOM(Cascade Style Sheets OBject Model) - Elements들과 연관된 스타일 정보와 구조화된 표현</li>
</ul>
<h3 id="dom은-어떻게-생성될까">DOM은 어떻게 생성될까?</h3>
<p>DOM은 HTML문서를 객체 기반으로 표현한 것이다. 어떻게 보면 비슷해보이지만, DOM이 가진 근본적 차이는 단순 텍스트로 구성된 HTML 문서가 객체 모델로 변환되어 다양한 프로그램에서 사용될 수 있다는 점이다.</p>
<p>DOM의 개체 구조는 <code>Node Tree</code>로 표현된다. 하나의 부모가 여러 개의 자식을 가질 수 있다. 또 그 자식이 가진 컨텐츠는 노드의 끝으로 <code>Leaf</code>라고 표현된다.</p>
<h3 id="dom이-아닌-것---html">DOM이 아닌 것 - HTML</h3>
<p><strong>DOM과 HTML이 완전히 같아보이지만, 의외로 HTML은 DOM이 아니다.</strong></p>
<p>DOM은 이전에도 설명했듯, HTML 문서를 객체 기반으로 표현한 것이다. 둘은 같지 않다. 대표적인 케이스로는 아래의 케이스가 있다.</p>
<h4 id="html-문서가-유효하지-않을-때">HTML 문서가 유효하지 않을 때</h4>
<p>HTML에서 태그를 덜닫거나 필수 태그를 빠뜨렸을 때, 브라우저는 유효하지 않은 태그를 임의로 올바르게 교정하여 일단 브라우저에서 동작시킬 수 있게 만들어버린다.</p>
<pre><code class="language-html">&lt;html&gt;
  안녕하세요.
&lt;/html&gt;</code></pre>
<p>위의 경우에는 HTML 룰에서 필수인 <code>&lt;head&gt;</code>와 <code>&lt;body&gt;</code>가 없지만, 올바르게 교정되어 브라우저에서 표기될 것이다.</p>
<h4 id="자바스크립트에-의해-dom이-수정될-때">자바스크립트에 의해 DOM이 수정될 때</h4>
<p>자바스크립트는 DOM을 동적으로 변경할 수 있다. 그 경우 자바스크립트는 DOM을 동적으로 수정하지만, HTML 문서의 내용이 변경되진 않는다.</p>
<h3 id="dom이-아닌-것---브라우저에서-보이는-것이-전부-dom은-아니다">DOM이 아닌 것 - 브라우저에서 보이는 것이 전부 DOM은 아니다.</h3>
<p>브라우저의 뷰 포트는 DOM을 이용해서 웹페이지를 표기해주긴 하지만, DOM을 이용하긴 하지만 DOM 그 자체는 아니다. 정확히 말하면, 브라우저 뷰 포트에는 렌더 트리가 보이게 되며, 렌더 트리는 오직 화면에 그려지는 것으로만 구성되어 있어 DOM과는 다르다.</p>
<p>달리 말하면, 렌더링되는 요소만 관련있어서, 시각적으로 보이지 않는 요소는 제외된다. <code>display:none</code>과 같은 스타일 속성을 가지고 있다면, DOM에는 있지만 렌더 트리에는 없어서 브라우저에는 보이지 않는다.</p>
<h3 id="dom이-아닌-것---가상-요소">DOM이 아닌 것 - 가상 요소</h3>
<p>크롬과 같은 브라우저의 개발자 도구는 DOM과 비슷한 형태를 보여주지만, 몇가지 DOM에 없는 정보도 추가적으로 보여준다.</p>
<p>이를테면 <code>::before</code>, <code>::after</code> 선택자와 같은 가상 요소가 있는데, 해당 가상요소는 CSSOM과 렌더 트리의 일부를 구성할 뿐이다.</p>
<p>DOM의 일부는 아니며, DOM은 오직 원본 HTML 문서로부터 빌드되고, Element에 적용되는 스타일을 포함하지 않는다.</p>
<blockquote>
<p>가상 요소는 DOM이 아니라서 자바스크립트로 수정도 불가능하다.</p>
</blockquote>
<blockquote>
<p>또한 자바스크립트로 수정될 수 있는 동적 모델이 DOM이다.</p>
</blockquote>
<h2 id="dom-소개---mdn에서의-설명">DOM 소개 - MDN에서의 설명</h2>
<h3 id="dom-이란">DOM 이란?</h3>
<p>DOM은 문서 객체 모델 (The Document Object Model)로 HTML, XML 문서의 프로그래밍 인터페이스이다. DOM은 문서의 구조화된 표현을 제공한다. 여기서 HTML, XML 문서의 프로그래밍 인터페이스라는 말은 브라우저가 이 인터페이스를 구현한다는 것을 뜻한다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/73890a7c-c956-411c-871d-cc867f937568/image.png" alt=""></p>
<p>DOM은 우리가 프로그래밍 언어를 통해 DOM 구조에 접근할 수 있는 방법을 제공해 문서의 구조, 스타일, 내용 등을 바꿀 수 있게 해준다. 또한 DOM은 구조화된 <code>node</code>, <code>property</code>, <code>method</code>를 갖고 있는 <code>object</code>로 문서를 표현한다. 이 오브젝트들을 통해 우리는 웹 페이지를 스크립트 혹은 프로그래밍 언어에서 이용할 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/efc85f00-f389-48ce-b893-d71afd395996/image.png" alt=""></p>
<p>웹페이지는 일종의 문서(document)로 취급된다. 문서는 웹브라우저를 통해 내용이 해석되어 화면에 렌더링될 수도 있고, HTML 소스 코드 그대로 나타날 수도 있다. 동일한 문서를 사용해 다른 형태로 나타날 수 있다는 점에 주목하자. DOM은 동일한 문서를 표현, 저장, 조작하는 방법을 제공한다. DOM은 웹 페이지의 객체지향적 표현이며, 자바스크립트와 같은 스크립팅 언어를 통해 DOM을 수정할 수도 있다.</p>
<p><a href="https://www.w3.org/DOM/">W3C DOM</a>, <a href="https://dom.spec.whatwg.org/">WHATWG DOM</a>와 같은 곳에서 DOM에 대한 표준을 정하고 브라우저는 그에 맞춰 구현한다. 많은 브라우저는 표준 규약에서 제공하는 기능 외 자신만의 특별한 기능도 제공하니 다양한 브라우저 환경에서 DOM이 모두 동일하게 적용되지는 않음을 알고 있는게 좋다.</p>
<p>자바스크립트 콘솔에서 간단히 DOM의 특성에 대해 공부해볼 수 있는데,</p>
<pre><code class="language-js">var paragraphs = document.getElementsByTagName(&quot;P&quot;);</code></pre>
<p>웹페이지 내부에 <code>P</code>태그가 있다는 전제 하에 위의 내용을 콘솔에 입력한 뒤에 </p>
<pre><code class="language-js">alert(paragraphs[0]);</code></pre>
<p>위의 코드를 입력하면 아래와 같은 메시지가 뜬다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/3ddbcaa0-5958-4d36-aba3-39b6be2f7c9b/image.png" alt=""></p>
<blockquote>
<p>DOM은 웹페이지의 객체지향적 표현이다.</p>
</blockquote>
<pre><code class="language-js">alert(paragraphs[0].nodeName);</code></pre>
<p>위 코드를 입력해보면,</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/7abff257-ca39-47a5-b280-b35de7eb9b31/image.png" alt=""></p>
<p><code>P</code>라는 내용이 정상적으로 송출된다.</p>
<h3 id="dom과-자바스크립트">DOM과 자바스크립트</h3>
<p>주로 웹브라우저에서 <code>document</code>와 <code>element</code>에 접근하기 위해 DOM이 사용된다. DOM이 없다면, 자바스크립트 언어는 웹페이지 혹은 XML 페이지 및 요소들과 관련된 모델이나 개념들에 대한 정보를 갖지 못하게 된다.</p>
<p><code>document</code> 내부에 있는 모든 <code>element</code>, <code>head</code>, <code>table</code>, <code>th</code>, <code>tr</code>, <code>td</code> 혹은 그 안의 <code>text</code>들이 전부 DOM (document object model)의 한 부분이다. 이러한 요소들을 자바스크립트와 같은 스크립팅 언어로 DOM에 접근해 컨트롤할 수 있다.</p>
<p>웹 초창기에는 자바스크립트와 DOM이 밀접하게 연결됐었지만, 나중에는 분리하여 발전했다. 페이지 컨텐츠는 DOM에 저장되고 자바스크립트를 통해 접근하거나 조작할 수 있다.</p>
<blockquote>
<p>API (web or XML page) = DOM + JS (scripting language)</p>
</blockquote>
<p>DOM은 프로그래밍 언어와 독립적으로 디자인되어 문서의 구조적 표현은 단일 API를 통해 이용 가능하다. 주로 자바스크립트가 사용되지만, DOM을 구현하는 데는 어떠한 언어라도 상관없다.</p>
<h3 id="참고-dom---mdn에서의-정의-2">참고) DOM - MDN에서의 정의 2</h3>
<blockquote>
<p>DOM은 브라우저가 이해하는 Element의 원형으로서, 문서를 <code>논리 트리</code>로 표현한 것이다.</p>
</blockquote>
<p>DOM(Document Object Model)은 웹페이지를 표현하는 HTML과 같은 문서(document) 구조를 메모리에 표현함으로써 웹페이지를 스크립트 혹은 프로그래밍 언어에 연결한다. HTML, SVG, XML 도큐먼트를 오브젝트로 모델링하는 것은 코어 자바스크립트 언어의 일부분이 아님에도 불구하고, 주로 자바스크립트를 참조한다.</p>
<p>DOM은 문서(document)를 논리적 트리구조로 표현한 것이다. 트리의 각각의 브랜치는 노드로 끝나며, 각 노드는 오브젝트를 포함한다. DOM 메소드는 트리로의 프로그래밍적인 접근을 허용한다. 이러한 메소드와 함께, 문서(document)의 구조, 스타일, 내용을 변경할 수 있다.</p>
<p>노드는 이벤트 핸들러를 가질 수 있으며, 이벤트가 발생하면, 이벤트 핸들러가 실행된다.</p>
<blockquote>
<p>The Document Object Model (DOM) connects web pages to scripts or programming languages by representing the structure of a document—such as the HTML representing a web page—in memory. Usually it refers to JavaScript, even though modeling HTML, SVG, or XML documents as objects are not part of the core JavaScript language.</p>
<p>The DOM represents a document with a logical tree. Each branch of the tree ends in a node, and each node contains objects. DOM methods allow programmatic access to the tree. With them, you can change the document&#39;s structure, style, or content.</p>
<p>Nodes can also have event handlers attached to them. Once an event is triggered, the event handlers get executed.</p>
</blockquote>
<h3 id="dom의-platform-independent-특성">DOM의 platform-independent 특성</h3>
<p>돔은 XML혹은 HTML 문서를 트리 구조로 다루며 플랫폼에 무관하고, 언어에 구애받지 않는 인터페이스이다. 그래서 웹의 UI를 표현할 때 뿐만 아니라 앱의 UI를 표현할 때도 사용된다.</p>
<h3 id="whatwg의-dom-모형">WHATWG의 DOM 모형</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/653fbfa9-05c0-4bcb-a579-b2f3ab3ec153/image.png" alt=""></p>
<blockquote>
<p>WHATWG는 Web Hypertext Application Technology Working Group으로 HTML과 관련된 기술의 진보에 관심이 많은 사람들이 모인 커뮤니티이다. 애플, 모질라 파운데이션, 오페라 소프트웨어 등으로부터 모였다. 현재 사실상 살아있는 웹 표준(living standard)을 만들고 있다.</p>
</blockquote>
<p>WHATWG가 정의한 모형에서는 <code>Events</code>, <code>Aborting ongoing activities</code>, <code>Nodes</code>, <code>Ranges</code>, <code>Traversal</code>, <code>Sets</code>, <code>XPath</code>, <code>XSLT</code>라는 큰 그룹으로 돔의 구성요소를 정의하고 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/78ea991a-f89a-45ec-a4b6-b61b95a78c1a/image.png" alt=""></p>
<p>위는 돔의 예제이다. 위와 같이 트리 모양으로 구성되어 있으며, 엘리먼트로 연결되어 있다. 엘리먼트는 다른 엘리먼트, 텍스트, 속성을 가질 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/1aadb64a-d01e-481c-a01c-e7c841f1221f/image.png" alt=""></p>
<pre><code class="language-html">&lt;div id=&quot;root&quot;&gt; &lt;!-- Element와 Attribute --&gt;
  &lt;p&gt;안녕하세요&lt;/p&gt; &lt;!-- 다른 Element와 Text Node --&gt;
&lt;/div&gt;</code></pre>
<blockquote>
<p><code>TextNode</code>도 어떻게 보면 <code>Element</code>로 볼 수 있지 않을까?</p>
</blockquote>
<h3 id="dom과-html-dom">DOM과 HTML DOM</h3>
<p>DOM은 HTML 요소들의 구조화된 표현으로 볼 수 있다.</p>
<p>DOM은 기본적으로 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document">Document</a> 인터페이스를 사용하여, HTML을 포함하고 있는 <code>document</code>를 말한다. <code>document</code>는 다양한 HTML 특화 기능들을 포함하는 HTML 스펙에 의해 확장된다. </p>
<p>특히, <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element">Element</a> 인터페이스는 <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement">HTMLElement</a>와 다양한 서브클래스들 그리고 엘리먼트 중 하나를 표현하는 각각의 개체가 되기 위해 강화(enhanced)된다.</p>
<p>HTML DOM API는 탭, 윈도우, CSS 스타일, 브라우저 히스토리와 같은 다양한 브라우저 기능에 대한 접근을 제공한다. 이러한 인터페이스들은 <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API">The HTML DOM API</a>에서 자세히 살펴볼 수 있다.</p>
<h2 id="dom-tree">DOM tree</h2>
<p>DOM tree는 tree의 한 종류로 HTML 혹은 XML 문서의 내용을 보여주는 노드를 가진 트리를 말한다. 각 HTML 혹은 XML 문서는 유니크한 DOM 트리 표현식을 가지고 있다. 예를 들면, 아래의 코드를 돔트리로 표현한 그림을 살펴보자.</p>
<pre><code class="language-html">&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;My Document&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;Header&lt;/h1&gt;
  &lt;p&gt;Paragraph&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p><img src="https://images.velog.io/images/jakeseo_me/post/042b8434-8df0-468f-aff7-10bd434ff992/image.png" alt=""></p>
<p>위에 보이는 document의 DOM tree가 사실 엄밀하게 진짜 DOM tree의 모습과 동일하지는 않다. 왜냐하면 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Whitespace">실제 DOM tree는 공백을 보존하기 때문이다.</a></p>
<p>웹 브라우저가 HTML 문서를 파싱하려고 할 때, 웹 브라우저는 DOM tree를 빌드하고 document를 보여주는데 DOM tree를 이용한다.</p>
<h2 id="정리">정리</h2>
<ul>
<li>DOM은 웹브라우저에서 사용하는 인터페이스이며, 여러 프로그래밍 언어로 구현될 수 있다. </li>
<li>HTML은 DOM이 아니다.</li>
<li>DOM은 HTML 문서를 기반으로 생겨난 객체 모델이다.</li>
<li>DOM은 트리 구조로 표현된다.</li>
<li>DOM은 플랫폼에 무관하다.</li>
<li>브라우저에서 자바스크립트로 DOM에 대한 접근 및 제어가 가능하다.</li>
<li>CSS에서 사용되는 가상 요소는 DOM의 일부가 아니다. <strong>(그러므로 자바스크립트로 접근도 불가능하다.)</strong></li>
</ul>
<h2 id="레퍼런스">레퍼런스</h2>
<p><a href="https://wit.nts-corp.com/2019/02/14/5522">https://wit.nts-corp.com/2019/02/14/5522</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프론트엔드 환경 파악 도구 Wappalyzer]]></title>
            <link>https://velog.io/@jakeseo_me/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%99%98%EA%B2%BD-%ED%8C%8C%EC%95%85-%EB%8F%84%EA%B5%AC-Wappalyzer</link>
            <guid>https://velog.io/@jakeseo_me/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%99%98%EA%B2%BD-%ED%8C%8C%EC%95%85-%EB%8F%84%EA%B5%AC-Wappalyzer</guid>
            <pubDate>Fri, 24 Sep 2021 10:49:07 GMT</pubDate>
            <description><![CDATA[<h2 id="wappalyzer란">Wappalyzer란?</h2>
<h3 id="공식문서-소개">공식문서 소개</h3>
<p>웹사이트에 사용된 기술을 알려줍니다.</p>
<p>어떤 웹사이트에서도 기술 스택을 알아냅니다. 회사 및 연락처 세부정보와 함께 특정 기술을 사용하는 웹사이트의 목록을 만듭니다. 시장 분석과 경쟁업체 조사, 잠재고객 발굴을 위해 우리 도구를 사용해보세요.</p>
<blockquote>
<p>Identify technologies on websites</p>
<p>Find out the technology stack of any website. Create lists of websites that use certain technologies, with company and contact details. Use our tools for lead generation, market analysis and competitor research.</p>
</blockquote>
<h3 id="설치-방법">설치 방법</h3>
<p>기본적으로 이 도구는 구글 확장프로그램이다.</p>
<p><a href="https://chrome.google.com/webstore/detail/wappalyzer/gppongmhjkpfnbhagpmjfkannfbllamg/related?hl=en">이 설치 링크</a>에 들어가면 설치할 수 있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/61cf900b-e66d-49a0-8326-59fb0636a90d/image.png" alt=""></p>
<h3 id="사용-예제---1-파파고">사용 예제 - 1. 파파고</h3>
<p>사용법은 매우 간단하다. 그냥 어떤 웹 개발 스택을 사용하는지 알고 싶은 사이트에 들어가서 구글 익스텐션을 켜보면 된다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/ad1e0a3c-f147-4488-bb7f-1555e9366bf6/image.png" alt=""></p>
<p>파파고의 경우 아무런 프론트엔드 프레임웍을 사용하지 않는 것 같다. 백엔드는 자바를 쓰는 것 같다.</p>
<h3 id="사용-예제---2-원티드">사용 예제 - 2. 원티드</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/99b73954-d2f0-443c-aeff-fc7cc812d1b4/image.png" alt=""></p>
<p>원티드는 <code>Next.js</code>랑 <code>React</code>, <code>styled-components</code>를 사용하는 것을 알 수 있다.</p>
<h3 id="사용-방법-추천">사용 방법 추천</h3>
<p>내가 관심있는 회사나 좋아하는 웹사이트에서 어떤 스택을 사용하는지 알아낸 뒤에 그 스택을 열심히 공부하면 조금 도움이 될 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프론트엔드 개발 환경 공부 #19 번들 결과 최적화]]></title>
            <link>https://velog.io/@jakeseo_me/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B3%B5%EB%B6%80-19-%EB%B2%88%EB%93%A4-%EA%B2%B0%EA%B3%BC-%EC%B5%9C%EC%A0%81%ED%99%94</link>
            <guid>https://velog.io/@jakeseo_me/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B3%B5%EB%B6%80-19-%EB%B2%88%EB%93%A4-%EA%B2%B0%EA%B3%BC-%EC%B5%9C%EC%A0%81%ED%99%94</guid>
            <pubDate>Thu, 23 Sep 2021 12:14:47 GMT</pubDate>
            <description><![CDATA[<h2 id="번들-결과-최적화란">번들 결과 최적화란?</h2>
<p>번들링한 결과물의 코드가 커지면, 브라우저에서 해당 파일을 로드하는데 너무 많은 시간을 소모할 수 있다. 결과적으로 사용자가 기다려야 할 로딩 시간이 너무 길어진다. 그렇다면 번들링한 결과를 어떻게 최적화할 수 있을지 몇가지 방법에 대해 알아보자.</p>
<h2 id="윈도우즈-환경에서-node_env-모드-설정-후에-웹팩-실행하기">윈도우즈 환경에서 NODE_ENV 모드 설정 후에 웹팩 실행하기</h2>
<h3 id="set-이용하기">SET 이용하기</h3>
<pre><code class="language-js">&quot;scripts&quot;: {
    &quot;test&quot;: &quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;,
    &quot;build&quot;: &quot;SET NODE_ENV=production&amp;webpack --progress&quot;,
    &quot;start&quot;: &quot;webpack-dev-server --progress&quot;
  },</code></pre>
<p>위와 같이 <code>SET NODE_ENV=production&amp;webpack --progress</code>와 같은 방식으로 실행하면 된다.</p>
<h3 id="cross-env-이용하기">cross-env 이용하기</h3>
<p><strong>설치</strong></p>
<pre><code class="language-bash">npm install -D cross-env</code></pre>
<pre><code class="language-js">  &quot;scripts&quot;: {
    &quot;test&quot;: &quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;,
    &quot;build&quot;: &quot;cross-env NODE_ENV=production webpack --progress&quot;,
    &quot;start&quot;: &quot;webpack-dev-server --progress&quot;
  },</code></pre>
<p><code>cross-env</code>는 리눅스에서 사용하는 명령어들을 윈도우에서도 똑같이 지원할 수 있게 만든 의존성이다.</p>
<h3 id="win-node-env-이용하기">win-node-env 이용하기</h3>
<p><strong>설치</strong></p>
<pre><code class="language-bash">npm install -g win-node-env</code></pre>
<pre><code class="language-js">  &quot;scripts&quot;: {
    &quot;test&quot;: &quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;,
    &quot;build&quot;: &quot;NODE_ENV=production webpack --progress&quot;,
    &quot;start&quot;: &quot;webpack-dev-server --progress&quot;
  },</code></pre>
<p>이건 새로운 명령어를 생성해서 실행하는 방법인데, 환경이 바뀌었을 때 글로벌에 대한 의존성 추가를 명시하지 않으면 에러날 때 조금 헤맬 것 같아서 조금 걱정이 되는 방법이다.</p>
<p>그래도 이 방법을 쓰면 리눅스 환경에서 윈도우즈로 가져왔을 때, 아무런 명령어 변경도 안하고 그대로 실행 가능하다.</p>
<h2 id="모드에-따른-최적화">모드에 따른 최적화</h2>
<p><a href="https://webpack.js.org/configuration/mode/">Webpack Configuration Mode 공식문서</a></p>
<h3 id="development-모드">development 모드</h3>
<p>웹팩 설정파일에서 <code>mode</code> 값을 설정하는 것이 최적화에서 생각보다 큰 의미를 갖는다. <code>mode</code>에는 총 3가지 값이 올 수 있는데, </p>
<blockquote>
<p><code>development</code>는 디버깅에 최적화된 모드이다.</p>
</blockquote>
<p>지금까지 설정했던 <code>development</code>는 디버깅 편의를 위해 아래 두개의 플러그인을 사용하고 있었다.</p>
<ul>
<li><code>NamedChunksPlugin</code> (웹팩 v4)</li>
<li><code>NamedModulesPlugin</code> (웹팩 v4)</li>
</ul>
<p><code>development</code> 모드에서 <code>DefinePlugin</code>을 사용한다면, <code>process.env.NODE_ENV</code>의 값이 <code>development</code>로 설정되어 애플리케이션에 전역변수로 주입된다.</p>
<h3 id="production-모드">production 모드</h3>
<blockquote>
<p><code>production</code>은 배포에 최적화된 모드이다.</p>
</blockquote>
<p><code>mode</code>를 <code>production</code>으로 설정하면, 번들링한 결과물을 최소화하기 위해서 다음 7개 플러그인을 사용한다.</p>
<ul>
<li><code>FlagDependencyUsagePlugin</code></li>
<li><code>FlagIncludedChunksPlugin</code></li>
<li><code>ModuleConcatenationPlugin</code></li>
<li><code>NoEmitOnErrorsPlugin</code></li>
<li><code>TerserPlugin</code></li>
<li><code>OccurrenceOrderPlugin</code> (웹팩 v4)</li>
<li><code>SideEffectsFlagPlugin</code> (웹팩 v4)</li>
</ul>
<p><code>production</code> 모드에서 <code>DefinePlugin</code>을 사용한다면, <code>process.env.NODE_ENV</code>의 값이 <code>production</code>으로 설정되어 애플리케이션에 전역변수로 주입된다.</p>
<h3 id="모드-설정-코드-만들기">모드 설정 코드 만들기</h3>
<pre><code class="language-js">const mode = process.env.NODE_ENV || &#39;development&#39;

module.exports = {
  mode,
}</code></pre>
<p><code>webpack.config.js</code>에 위와 같이 코드를 작성하면, <code>process.env.NODE_ENV</code>로 받은 값이 있을 때는 해당 <code>mode</code>로 실행시키고, 만일 없다면 기본 값인 <code>development</code>를 이용하게 된다.</p>
<h3 id="프로덕션-빌드-결과물-확인해보기">프로덕션 빌드 결과물 확인해보기</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/b33585e8-db69-40a5-9780-c6f85c24662c/image.png" alt=""></p>
<p>코드를 알아볼 수 없게 난독화되어있다.</p>
<h2 id="optimization-속성에-따른-최적화">Optimization 속성에 따른 최적화</h2>
<p>빌드 과정을 커스터마이징할 수 있는 속성이 <code>optimization</code> 속성이다.</p>
<h3 id="css-최적화---css-minimizer-webpack-plugin">CSS 최적화 - css-minimizer-webpack-plugin</h3>
<p><code>HtmlWebpackPlugin</code>이 html 파일을 압축했던것처럼 css 파일도 빈칸을 없애고 압축하고 싶다면 어떻게 해야 할까? <code>css-minimizer-webpack-plugin</code>을 사용하면 된다.</p>
<blockquote>
<p>웹팩 버전 4 에서는 <code>optimize-css-assets-webpack-plugin</code>을 사용한다.</p>
</blockquote>
<h3 id="js-최적화---terser-webpack-plugin">JS 최적화 - terser-webpack-plugin</h3>
<p><code>TerserWebpackPlugin</code>은 자바스크립트 코드를 난독화하고, <code>debugger</code> 구문을 제거한다. 이 외에도 콘솔로그를 제거하는 옵션도 있다. 배포 버전에는 굳이 <code>console.log()</code>가 필요하지 않기 때문이다.</p>
<h3 id="플러그인-설치">플러그인 설치</h3>
<pre><code class="language-bash">npm i -D css-minimizer-webpack-plugin terser-webpack-plugin</code></pre>
<h3 id="웹팩-설정-추가">웹팩 설정 추가</h3>
<pre><code class="language-js">const CssMinimizerPlugin = require(&quot;css-minimizer-webpack-plugin&quot;);
const TerserPlugin = require(&quot;terser-webpack-plugin&quot;);

module.exports = { 
  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin(), new CssMinimizerPlugin()],
  },
}</code></pre>
<p><code>terser-webpack-plugin</code>은 자바스크립트를 minify하는데 사용되는 플러그인인데, 커스터마이즈된 minimize를 하려면 저렇게 다시 직접 설치해서 입력해주어야 한다.</p>
<p><code>css-minimizer-webpack-plugin</code>을 사용하기 위함이다.</p>
<h3 id="웹팩-설정-변경---production에서만-minimize">웹팩 설정 변경 - production에서만 minimize</h3>
<pre><code class="language-js">const CssMinimizerPlugin = require(&quot;css-minimizer-webpack-plugin&quot;);
const TerserPlugin = require(&quot;terser-webpack-plugin&quot;);

module.exports = { 
  optimization: {
    minimize: mode === &quot;production&quot;,
    minimizer: [new TerserPlugin(), new CssMinimizerPlugin()],
  },
}</code></pre>
<p>위와 같이 간단하게 <code>mode</code>를 이용해 설정해주면 된다.</p>
<h3 id="콘솔로그-제거-설정-해보기">콘솔로그 제거 설정 해보기</h3>
<pre><code class="language-js">  optimization: {
    minimize: mode === &quot;production&quot;,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true, // 콘솔 로그를 제거
          },
        },
      }),
      new CssMinimizerPlugin(),
    ],
  },</code></pre>
<p>위와 같이 <code>TerserPlugin</code>에 옵션을 주면 콘솔로그를 제거할 수 있다.</p>
<h3 id="결과-살펴보기">결과 살펴보기</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/18ac7dae-2619-4e31-b5ff-8cafd3c2e1dc/image.png" alt=""></p>
<p><code>css</code>가 압축되었다.</p>
<p>실행 결과에서 <code>console.log</code>도 물론 뜨지 않는다.</p>
<h2 id="코드-스플리팅을-통한-최적화">코드 스플리팅을 통한 최적화</h2>
<h3 id="최적화의-필요성">최적화의 필요성</h3>
<pre><code class="language-js">module.exports = {
  mode,
  entry: {
    app: &quot;./src/app.js&quot;,
    math: &quot;./src/math.js&quot;,
  },
  ...</code></pre>
<p>만일 웹팩의 설정파일에서 위와 같이 entry가 2개이고, 두개에서 동일한 패키지를 사용한다고 가정해보자. 이를테면 현재 두 파일에서 공통으로 <code>axios</code> 패키지를 사용한다고 가정해보자.</p>
<h3 id="최적화를-하지-않은채로-빌드했을-때">최적화를 하지 않은채로 빌드했을 때</h3>
<p><code>app.js</code></p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/ddec480b-3db6-403d-a8b7-2d1e68ace759/image.png" alt=""></p>
<p><code>result.js</code></p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/e5eb118c-473b-4514-b0a2-626b336aa473/image.png" alt=""></p>
<p><code>axios</code>라는 동일한 코드들이 중복되고 있다.</p>
<h3 id="optimizationsplitchunks-사용하기">optimization.splitChunks 사용하기</h3>
<p>웹팩은 기본적으로 아래와 같은 조건 하에 chunks를 나눈다.</p>
<ul>
<li>새 chunk가 공유될 수 있거나 모듈이 <code>node_modules</code> 폴더에 있는 경우</li>
<li>새 chunk가 20kb보다 클 경우</li>
<li>요청에 의해 chunk가 로드될 때, 최대 병렬 요청의 수가 30개 이하일 경우</li>
<li>초기 페이지 로드 시, 최대 병렬 요청 수가 30개 이하일 경우</li>
</ul>
<p>마지막 2개의 조건을 만족하려하면, 청크의 크기는 더 큰것이 선호된다.</p>
<p>기본 설정은 아래와 같다.</p>
<pre><code class="language-js">module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: &#39;async&#39;,
      minSize: 20000,
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
      cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          reuseExistingChunk: true,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
};</code></pre>
<p>내가 이번에 해준 설정은 아래와 같다.</p>
<pre><code class="language-js">  optimization: {
    minimize: mode === &quot;production&quot;,
    minimizer: [
      new CssMinimizerPlugin(),
    ],
    splitChunks: {
      chunks: &quot;all&quot;,
    },
  },</code></pre>
<p>그냥 단순히 <code>optimization.splitChunks.chunks: &quot;all&quot;</code>을 주었을 뿐이다. 나머지는 기본 설정으로 적용됐을 것이다.</p>
<h3 id="코드-확인-결과">코드 확인 결과</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/01024fd7-a49d-49eb-ac84-f05f1169c80b/image.png" alt=""></p>
<p>기존에 <code>axios</code>에 <code>createInstance()</code>하던 부분들은 사라지고, 단순히 <code>require()</code>로 불러오는 부분만 남아있다.</p>
<h3 id="파일-확인-결과">파일 확인 결과</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/2db18de5-3e97-4046-892d-3fef66c1cad2/image.png" alt=""></p>
<p>그리고 배포 디렉토리에 정체를 알 수 없는 <code>669.js</code>와 <code>850.js</code>가 있는데, 해당 파일 내부에 <code>Axios</code> 코드가 들어있다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/8ab2bf09-5db8-464c-a8a4-41dfe2ff81e6/image.png" alt=""></p>
<p>용량도 <code>669.js</code>와 <code>850.js</code>가 가장 크다.</p>
<h2 id="다이나믹-임포트-사용해보기">다이나믹 임포트 사용해보기</h2>
<p><code>result.js</code> 파일을 따로 번들링하여 다이나믹하게 임포트해보자.</p>
<h3 id="appjs-코드-변경">app.js 코드 변경</h3>
<pre><code class="language-js">import &quot;./app.css&quot;;

import form from &quot;./form.js&quot;;
// import result from &quot;./result.js&quot;;

console.log(&quot;hello world&quot;);

document.addEventListener(&quot;DOMContentLoaded&quot;, async () =&gt; {
  const formEl = document.createElement(&quot;div&quot;);
  formEl.innerHTML = form.render();
  document.body.appendChild(formEl);

  import(/* webpackChunkName: &quot;result&quot; */ &quot;./result.js&quot;).then(async (m) =&gt; {
    const result = m.default;
    const resultEl = document.createElement(&quot;div&quot;);
    resultEl.innerHTML = await result.render();
    document.body.appendChild(resultEl);
  });
});</code></pre>
<p>기존의 <code>import</code> 구문을 주석처리하고 아래쪽에 <code>import()</code> 메소드를 통해 <code>&quot;./result.js&quot;</code> 파일을 가져왔다. 그리고 파일명 문자열 앞에 <code>/* webpackChunkName: &quot;result&quot; */</code> 주석도 의미가 있다. 반드시 적어주어야 한다.</p>
<h3 id="webpackconfigjs-수정">webpack.config.js 수정</h3>
<p>위와 같이 코드를 변경하고, 기존에 <code>optimizer.splitChunks</code> 부분은 주석처리해두었다.</p>
<p><img src="https://images.velog.io/images/jakeseo_me/post/1fc21ba8-c0c1-4b27-83cd-781b923f3d75/image.png" alt=""></p>
<h3 id="적용-결과">적용 결과</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/28e1c857-6ed2-4d04-ba4a-5d9559f7ac3f/image.png" alt=""></p>
<p><code>app.js</code> 안에 붙어있던, <code>result.js</code> 파일이 분리되었다.</p>
<h2 id="externals---번들하지-않아도-되는-것들">externals - 번들하지 않아도 되는 것들</h2>
<p><code>axios</code> 같은 서드파티 라이브러리는 패키지로 제공될 때 이미 빌드 과정을 거쳤기 때문에, 빌드 프로세스가 필요 없다. 웹팩 설정 중 <code>externals</code>가 이런 기능을 제공한다.</p>
<pre><code class="language-js">// webpack.config.js
module.exports = {
  externals: {
    axios: &#39;axios&#39;
  }
}</code></pre>
<p><code>externals</code>에 추가하면 웹팩은 코드에서 <code>axios</code>를 사용하더라도 번들에 포함하지 않고 빌드한다. 대신에 이를 전역 변수로 접근하도록 키로 설정한 <code>axios</code>가 그 이름이다.</p>
<h3 id="웹팩-코드-변경---externalsaxios">웹팩 코드 변경 - externals.axios</h3>
<pre><code class="language-js">...
  externals: {
    axios: &quot;axios&quot;,
  },
  optimization: {
    minimize: mode === &quot;production&quot;,
    minimizer: [
      new CssMinimizerPlugin(),
    ],
  },
};</code></pre>
<p>위와 같이 <code>externals.axios</code>는 <code>axios</code>라는 모듈을 쓸 때, 전역변수 <code>axios</code>가 있는 것처럼 빌드하라는 뜻이다. <code>axios</code>는 우리가 설치한 것이기 때문에 <code>node_modules</code> 내부에 존재한다.</p>
<h3 id="웹팩-코드-변경---copyplugin">웹팩 코드 변경 - CopyPlugin</h3>
<pre><code class="language-js">  plugins: [
    new CopyPlugin({
      patterns: [
        {
          from: &quot;./node_modules/axios/dist/axios.min.js&quot;,
          to: &quot;./axios.min.js&quot;,
        },
      ],
    }),
  ],</code></pre>
<p>위와 같이 <code>node_modules</code>에 있는 패키지를 <code>dist/axios.min.js</code>라는 파일로 불러온다고 적어주면 된다.</p>
<h3 id="배포-결과">배포 결과</h3>
<p><img src="https://images.velog.io/images/jakeseo_me/post/fd1cc8aa-5786-44c6-ae07-1fc065c168eb/image.png" alt=""></p>
<p>axios.min.js가 따로 빠졌다. 이렇게 하면 웹팩에서 쓸데없는 빌드 시간도 줄일 수 있다.</p>
]]></description>
        </item>
    </channel>
</rss>