<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.2">Jekyll</generator><link href="https://minje0204.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://minje0204.github.io/" rel="alternate" type="text/html" /><updated>2022-05-03T13:19:00+09:00</updated><id>https://minje0204.github.io/feed.xml</id><title type="html">꾸준한 사람이 되자</title><subtitle>게임 좋아하는 개발자 지망생!!</subtitle><author><name>조민제</name></author><entry><title type="html">Jsconvention</title><link href="https://minje0204.github.io/JSConvention/" rel="alternate" type="text/html" title="Jsconvention" /><published>2021-11-08T00:00:00+09:00</published><updated>2021-11-08T00:00:00+09:00</updated><id>https://minje0204.github.io/JSConvention</id><content type="html" xml:base="https://minje0204.github.io/JSConvention/">&lt;hr /&gt;
&lt;p&gt;title:  “JS 컨벤션 정리(추가 중~~)”
excerpt: “구글(Google), 에어비엔비(Airbnb), NHN style guide”&lt;/p&gt;

&lt;p&gt;categories:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;JavaScript
tags:&lt;/li&gt;
  &lt;li&gt;Convention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;last_modified_at: 2021-11-08T18:00:00-19:00:00&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;웹개발자를 지망하고 있는데 &lt;strong&gt;JS style guide&lt;/strong&gt;를 한번도 제대로 보지 못했다.&lt;br /&gt;
그래서 &lt;strong&gt;구글, 에어비엔비, NHN의 js style guide&lt;/strong&gt;를 정리해보려고 한다.&lt;/p&gt;

&lt;h2 id=&quot;source-file--basics&quot;&gt;Source File  Basics&lt;/h2&gt;

&lt;h3 id=&quot;231-white-spaces-공백-문자&quot;&gt;2.3.1 White spaces (공백 문자)&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;All other whitespace characters in string literals are escaped, and
‘string literals’ 안에 있는 모든 공백문제는 escape =&amp;gt; &lt;strong&gt;\&lt;/strong&gt; 처리 되어야 한다.&lt;/li&gt;
    &lt;li&gt;Tab characters are  &lt;strong&gt;not&lt;/strong&gt;  used for indentation.
indentation(들여쓰기)를 위해서 Tab을 사용하면 &lt;strong&gt;안 된다??&lt;/strong&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tab을 쓰면 안되는 이유는 다음과 같다.
Tab 문자 자체가 태생적으로 모호하고 (&lt;em&gt;can be blank 2칸 or 4칸&lt;/em&gt;)  Tab이 코드라인 처음에 위치하기 때문에 &lt;strong&gt;Tool에 따라서 같은 코드가 다르게 렌더될 수 있다.&lt;/strong&gt; &lt;a href=&quot;http://www.javapractices.com/topic/TopicAction.do?Id=244&quot;&gt;코드예시&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;objects&quot;&gt;Objects&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/airbnb/javascript#objects--no-new&quot;&gt;3.1&lt;/a&gt;  Use the literal syntax for object creation. eslint:  &lt;a href=&quot;https://eslint.org/docs/rules/no-new-object.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no-new-object&lt;/code&gt;&lt;/a&gt;
    &lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// bad&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// good&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://github.com/airbnb/javascript#es6-computed-properties&quot;&gt;3.2&lt;/a&gt;  Use computed property names when creating objects with dynamic property names.&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;Why? They allow you to define all the properties of an object in one place.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`a key named &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// bad&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;San Francisco&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// good&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;San Francisco&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/airbnb/javascript#es6-object-shorthand&quot;&gt;3.3&lt;/a&gt;  Use object method shorthand. eslint:  &lt;a href=&quot;https://eslint.org/docs/rules/object-shorthand.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;object-shorthand&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;c1&quot;&gt;// bad&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;atom&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    
      &lt;span class=&quot;na&quot;&gt;addValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;atom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// good&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;atom&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    
      &lt;span class=&quot;nx&quot;&gt;addValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;atom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>조민제</name></author><summary type="html">title: “JS 컨벤션 정리(추가 중~~)” excerpt: “구글(Google), 에어비엔비(Airbnb), NHN style guide”</summary></entry><entry><title type="html">target=_blank을 쓸 때 유의할 점</title><link href="https://minje0204.github.io/web/TargetBlankIssue/" rel="alternate" type="text/html" title="target=_blank을 쓸 때 유의할 점" /><published>2021-11-08T00:00:00+09:00</published><updated>2021-11-09T20:00:00+09:00</updated><id>https://minje0204.github.io/web/TargetBlankIssue</id><content type="html" xml:base="https://minje0204.github.io/web/TargetBlankIssue/">&lt;p&gt;개발자들은 새 탭이나 새 창으로 특정 페이지를 여는 링크를 구현할 때, 아래와 같이 &lt;strong&gt;target=”_blank”&lt;/strong&gt; 옵션을 이용하곤 한다.&lt;br /&gt;
  하지만 이 방식에는 2가지 문제가 있었다. 오늘은 이 2가지 문제에 대해서 알아보려고 한다.&lt;/p&gt;
&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://minje0204.github.io/&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;target=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_blank&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
	Made by minje0204 &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;target_blank의-문제점&quot;&gt;target=”_blank”의 문제점&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;target=”_blank”&lt;/strong&gt; 에는 2가지 문제가 있는데 한가지는 &lt;strong&gt;tab-napping&lt;/strong&gt;이고 다른 한가지는&lt;/p&gt;

&lt;h3 id=&quot;1--보안상-취약점이-생긴다&quot;&gt;1.  보안상 취약점이 생긴다.&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;target=”_blank”&lt;/strong&gt; 가 사용된 a tag는 사용자가 클릭하면 &lt;strong&gt;새 탭&lt;/strong&gt;에서 링크된 페이지가 열린다. 여기서, 해당 링크를 연 윈도우가 &lt;strong&gt;window.opener&lt;/strong&gt;에 저장된다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Window.opener&lt;/strong&gt;&lt;br /&gt;
Window 인터페이스의 &lt;strong&gt;opener 속성&lt;/strong&gt;은 open()을 사용해 현재 창을 열었던 창의 참조를 반환합니다.&lt;/p&gt;

  &lt;p&gt;예제로 설명하자면, 창 A가 창 B를 열었을 때 B.opener는 A를 반환합니다.&lt;br /&gt;
&lt;strong&gt;ref by. &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Window/opener&quot;&gt;Mozilia|MDN&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;그리고 &lt;strong&gt;window.opener&lt;/strong&gt;를 사용하면 새 페이지에서 이전 윈도우를 마음대로 조작할 수 있다. 예를 들면, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window.opener.location = new malicious URL&lt;/code&gt; 와 같이 악성 url로 리다이렉트 시킬 수 도 있다.&lt;/p&gt;

&lt;h3 id=&quot;2-퍼포먼스가-떨어질-수-있다&quot;&gt;2. 퍼포먼스가 떨어질 수 있다&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;target=”_blank”&lt;/strong&gt; 가 사용된 링크에 의해 열린 링크된 페이지는 링크를 건 페이지와 같은 프로세스를 통해서 실행된다. 그래서 main-thread에서 진행중이던 모든 작업들이 순간적으로 disrupt 될 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;현재는 target=”blank”로 이 문제를 재현 할 수 없지만, window.open으로는 가능하다. 심심하면 해보시길…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;문제-해결방법이었던-것&quot;&gt;문제 해결방법(이었던 것)&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;예시 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &amp;lt;a
	href=&quot;https://minje0204.github.io/&quot;
	target=&quot;_blank&quot;
	rel=&quot;_noreferrer noopener&quot;
&amp;gt;
	Made by minje0204
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;위 두가지 문제 때문에 보통 &lt;strong&gt;_blank 옵션&lt;/strong&gt;으로 새창에서 링크를 띄울 경우 위와 같이 &lt;strong&gt;rel=”_noreferrer noopener”&lt;/strong&gt; 를 보통 사용해왔다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;noreferrer&lt;/strong&gt; &lt;br /&gt;
브라우저가 링크를 건 페이지의 주소와 같은 정보를 Referer: HTTP 헤더에 리퍼러(referer 또는 referrer)로 송신하지 않습니다.  &lt;br /&gt;
&lt;strong&gt;noopener&lt;/strong&gt;&lt;br /&gt;
noopener(노오프너)를 지정하면, 링크된 페이지에서 window.opener을 사용해서 링크를 건 페이지를 참조(reference)할 수 없게 됩니다. 더불어 링크된 페이지와 링크를 건 페이지는 별개의 프로세스로 취급&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;이제는-상관없다&quot;&gt;이제는 상관없다?&lt;/h2&gt;

&lt;p&gt;그럼 첫번째 이슈(보안상 취약점이 생긴다.)를 재현해보자!
 window.opener로 부모 윈도우를 실제로 조작해보기 재밌겠다~!&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;a href=&quot;www.naver.com&quot; target=&quot;_blank&quot;&amp;gt;naver&amp;lt;a/&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;target=”_blank”&lt;/strong&gt; 만 주고 별다른 옵션은 주지 않았다.  그리고 브라우저에 opener를 쳐보았는데…(또잉..?)&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
&lt;img width=&quot;123&quot; alt=&quot;null&quot; src=&quot;https://user-images.githubusercontent.com/32082727/138868264-d9aa2214-f0b4-42a4-9921-159035686acf.png&quot; align=&quot;center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;noopener 옵션을 주지 않아도 opener를 받아 오지 못했고, 두번째 퍼포먼스 이슈도 재현되지 않아서 찾아보니 &lt;strong&gt;이미&lt;/strong&gt; &lt;strong&gt;크롬&lt;/strong&gt;은 작년에 해당 이슈관련 &lt;strong&gt;업데이트를&lt;/strong&gt; 했다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;The new update to Chrome will instead force  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;target=&quot;_blank&quot;&lt;/code&gt;  to behave as  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rel=&quot;noopener&quot;&lt;/code&gt;&lt;/strong&gt; by default.
ref. &lt;a href=&quot;https://chromeunboxed.com/chrome-javascript-block-malicious-redirects-update&quot;&gt;GOOGLE CHROME WILL SOON BLOCK JAVASCRIPT REDIRECTS WHEN CLICKING WEB LINKS&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;결론은 chromium 88 업데이트 이후 크롬에서 &lt;strong&gt;target=”_blank”&lt;/strong&gt; 는 기본적으로 noopener옵션으로 동작한다. 따라서, 개발자가 따로 신경을 써주지 않아도 된다.&lt;/p&gt;

&lt;p&gt;인프런 강의를 보다가 강사분께서 말씀해주신 이슈를 찾아봤는데 과거에 이슈였던 것이었다….&lt;/p&gt;</content><author><name>조민제</name></author><category term="Web" /><category term="Browser" /><summary type="html">(이었던것)</summary></entry><entry><title type="html">ORM vs Raw Query / N+1 Problem</title><link href="https://minje0204.github.io/database/ORMvsRawQuery/" rel="alternate" type="text/html" title="ORM vs Raw Query / N+1 Problem" /><published>2021-09-02T00:00:00+09:00</published><updated>2021-09-04T04:38:05+09:00</updated><id>https://minje0204.github.io/database/ORMvsRawQuery</id><content type="html" xml:base="https://minje0204.github.io/database/ORMvsRawQuery/">&lt;p&gt;수 많은 정보가 저장되는 &lt;strong&gt;Data Base&lt;/strong&gt;에서 원하는 정보를 얻기 위해서는 &lt;strong&gt;Query문을 작성&lt;/strong&gt;해야 한다.&lt;br /&gt;
간단하게, single 테이블에서 정보를 가져오기도 하고 좀 복잡하게는 여러 join문을 이용하여 여러 테이블에서 정보를 가져올 수 도 있다.&lt;br /&gt;
현업에서는 다양하고 복잡한 Query문 작성이 요구되고 SQL에 능숙해지기까지 많은 시간이 걸린다.&lt;br /&gt;
그리고 꼬리에 꼬리를 무는 Query문에서 작은 실수는 디버깅을 힘들게 만든다.  &lt;br /&gt;
이를 해결해줄 도구가 &lt;strong&gt;ORM&lt;/strong&gt;이다.&lt;br /&gt;
ORM(Object - Relational Mapping)은 &lt;strong&gt;관계형 데이터베이스&lt;/strong&gt;와 &lt;strong&gt;객체&lt;/strong&gt; 사이를 매핑시키는 것을 말한다.&lt;br /&gt;
ORM은 &lt;strong&gt;객체 지향&lt;/strong&gt; 언어를 사용하여 데이터베이스에 접근할 수 있는 여러 &lt;strong&gt;method&lt;/strong&gt;들을 제공해준다.&lt;br /&gt;
ORM이 매핑 시켜놓은 객체를 통해 데이터베이스 데이터를 다룰 수 있게 되는 것이다.  &lt;br /&gt;
그럼 ORM에 대해서 본격적으로 알아보자!&lt;/p&gt;

&lt;h2 id=&quot;orm의-장점&quot;&gt;ORM의 장점&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Code와 Database 간의 종속성 &lt;strong&gt;DOWN&lt;/strong&gt;&lt;br /&gt;
DB 위에 하나의 추상화된 층을 쌓는 것이기 때문에 개발자들이 MySQL, PostgreSQL, SQLite…등 DB간의 사소한 차이들을 일일이 몰라도 된다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;SQL Query 작성 부담을 덜 수 있다.&lt;br /&gt;
인터페이스 작성에 할애하는 시간을 &lt;strong&gt;비지니스 로직&lt;/strong&gt;에 쏟을 수 있다.
직관적 쿼리 =&amp;gt; 에러, 버그 발생 가능성 &lt;strong&gt;DOWN&lt;/strong&gt;, 가독성 &lt;strong&gt;UP&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;재사용 및 유지보수에 용이하다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;orm의-단점&quot;&gt;ORM의 단점&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;실행 속도가 잘 짜여진 raw query보다 &lt;strong&gt;느리다&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;한정된 명령문으로 인한 한계&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;추상화로 인해 Low level 디버깅이 불편함&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;ORM은 주로 library나 framework, API 형태로 제공되기 때문에 ORM에 종속되게 되고 다른 solution으로의 이동이 어려워진다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;raw-query의-장점&quot;&gt;Raw Query의 장점&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Best Performance를 달성할 수 있다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;ORM을 사용할 때보다 디버깅이 편하다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;third-party code에 대한 종속성이 없다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Raw Query의 단점은 위에 적었으니 따로 적지 않겠다.&lt;br /&gt;
여기까지 읽어보면 사실 ORM의 단점이 곧 Raw Query의 장점이고 ORM의 장점이 곧 Raw Query의 단점이다.&lt;br /&gt;
그래서, SQL query문에 능숙하다는 전제하에 정답은 없고 주어진 task 환경에 맞추어 어떤 방법을 사용할지 선택해야 한다. &lt;del&gt;SQL에 익숙하지 않으면 ORM…&lt;/del&gt;&lt;/p&gt;

&lt;h2 id=&quot;n1-problem&quot;&gt;N+1 Problem&lt;/h2&gt;
&lt;p&gt;ORM은 N+1 문제라는 대표적인 Anti - pattern을 가진다.&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;
	&lt;img src=&quot;https://user-images.githubusercontent.com/32082727/131852937-c5a24040-d9bb-4968-9cd3-5744cbd81893.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;위 그림과 같은 관계 모델에서 DB에 있는 모든 Book을 차례로 불러와 &lt;strong&gt;(iterative)&lt;/strong&gt; 책마다 달려있는 BookReview에 접근한다고 생각해보자.&lt;br /&gt;
여기서 ORM은 default가 &lt;strong&gt;lazy-loading&lt;/strong&gt; (정말 필요한 시점에만 SQL을 호출한다)이기 때문에, 아래와 같이 진행될 것 이다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;SELECT * FROM Books;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;for each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Book&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;SELECT * FROM BookReview WHERE BookId = ?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;결과적으로 &lt;strong&gt;1번&lt;/strong&gt;의 Books를 가져오는 SELECT문과 &lt;strong&gt;N번&lt;/strong&gt;의 추가적인 SELECT문이 필요하다.&lt;br /&gt;
만약, Book이 100개 있다면 BookReview SQL은 &lt;strong&gt;100번&lt;/strong&gt; 호출된다.&lt;/p&gt;

&lt;p&gt;Query를 한번 날릴 때 마다 오버헤드가 발생하기 때문에 Query문 100 개에 1개의 정보를 return받는 것 보다 &lt;strong&gt;Query문 1개에 100개의 정보&lt;/strong&gt;를 return 받는 것이 &lt;strong&gt;훨씬 빠르다&lt;/strong&gt;.&lt;br /&gt;
이 차이는 DB가 다른 machine에서 돌아가고 있을 때 더 극명해진다.&lt;br /&gt;
통신하는데 걸리는 속도가 1-2ms 라면, 100개의 Query를 날리는데 필요한 시간은 100ms-200ms다.&lt;/p&gt;

&lt;p&gt;이 문제를 해결하기 위해서는 Eager-Loading을 사용하면 된다.  Eager-Loading을 사용하면 사전에 쓸 데이터를 포함하여 쿼리를 날리기 때문에 비효율적으로 늘어나는 쿼리 요청을 방지할 수 있다.&lt;/p&gt;</content><author><name>조민제</name></author><category term="DataBase" /><category term="ORM" /><category term="SQL" /><summary type="html">ORM이 항상 정답은 아니다!</summary></entry><entry><title type="html">Virtual Dom (가상돔)</title><link href="https://minje0204.github.io/web/VirtualDom/" rel="alternate" type="text/html" title="Virtual Dom (가상돔)" /><published>2021-08-25T00:00:00+09:00</published><updated>2021-08-27T03:44:01+09:00</updated><id>https://minje0204.github.io/web/VirtualDom</id><content type="html" xml:base="https://minje0204.github.io/web/VirtualDom/">&lt;h1 id=&quot;virtual-dom-가상돔&quot;&gt;Virtual Dom (가상돔)&lt;/h1&gt;

&lt;p&gt;react를 사용해오면서 가상돔을 알게 되고, 이게 왜 필요한 것인지 궁금해졌다. 먼저, 
한줄 요약을 해보자면, 실제 DOM 트리를 직접 조작하기에 시간이 오래 걸리기 때문에 가상돔을 활용하여 DOM트리 노드들의 배치를 최적화 시킬 수 있다고 한다. 이를 더 자세히 알아보기 위해서는 먼저 브라우저의 작동 방식을 알아야 한다.&lt;/p&gt;

&lt;h3 id=&quot;브라우저-주요-기능&quot;&gt;브라우저 주요 기능&lt;/h3&gt;
&lt;p&gt;사용자가 선택한 자원(주로, html문서)의 URI를 참조하여 서버에 요청한다. 이를 W3C가 정한 HTML CSS 명세에 따라 해석하여 브라우저에 표시한다.&lt;/p&gt;
&lt;h3 id=&quot;브라우저의-렌더링-방식-webkit엔진-기준&quot;&gt;브라우저의 렌더링 방식 (WebKit엔진 기준)&lt;/h3&gt;
&lt;p&gt;&lt;img width=&quot;691&quot; alt=&quot;howwebkitworks&quot; src=&quot;https://user-images.githubusercontent.com/32082727/130776446-13622635-82ee-4f77-a86b-d7c57ae0ec8f.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;다음은 webkit이 작동하는 방식이다.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;브라우저는 HTML문서를 파싱하여 &lt;strong&gt;DOM Tree&lt;/strong&gt;를 생성한다.&lt;/li&gt;
  &lt;li&gt;css style에 관한 style sheet를 파싱하고 해당하는 Node의 &lt;strong&gt;Attach Method&lt;/strong&gt;를 실행하여 해당 노드에 스타일을 덫붙힌다. 이 동작을 &lt;strong&gt;Attachment&lt;/strong&gt;라고 하며, &lt;strong&gt;Synchronous&lt;/strong&gt;하게 처리된다.&lt;/li&gt;
  &lt;li&gt;브라우저에서 각 Node들이 어떤 위치에 있어야하는지 스크린의 좌표를 계산하는 &lt;strong&gt;Layout 과정&lt;/strong&gt;을 거친다.&lt;/li&gt;
  &lt;li&gt;Tree에 각 노드들을 거쳐가면서 색을 칠해준다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Rendering&lt;/strong&gt; 완료&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;왜-dom-tree를-직접-수정하는-것이-오래걸릴까&quot;&gt;왜 DOM Tree를 직접 수정하는 것이 오래걸릴까?&lt;/h2&gt;
&lt;p&gt;DOM Tree에 변화가 생기면, 위 렌더링 과정이 처음부터 다시 시작되어야 한다. 특히, &lt;strong&gt;attachement&lt;/strong&gt; 과정에서 style은 tag, class, id별로 style이 다르게 주어질 수 있고, 별다른 언급이 없다면 부모 노드의 style을 따르기 때문에 상당한 연산이 필요한데, 복잡한 &lt;strong&gt;SPA&lt;/strong&gt; 와 같이 DOM 변경이 잦아 진다면, 렌더링 과정을 비효율적으로 만들것이다.&lt;/p&gt;

&lt;h3 id=&quot;가상돔을-쓴다면&quot;&gt;가상돔을 쓴다면?&lt;/h3&gt;
&lt;p&gt;뷰의 변화가 있을 때, 실제 DOM에서 만들어 질 수 있는 가능한 모든 후보군을 가상돔에서 만들어보고(&lt;em&gt;실제 DOM에서 적용하는 것이 아니기 때문에 비용이 덜 들어간다.&lt;/em&gt;) 실제 DOM에 적용 시킴으로서 렌더링 과정을 더 효율적으로 만들 수 있다.
렌더링의 연쇄과정을 가상 DOM에서 진행하고 이 결과물만 떼어 실제 DOM에 적용시킨다고 난 이해했다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;DOM fragment를 직접 관리하지 않아도 되게(어디를 변화시켜야 하는지, 어디까지 변화를 반영했는지 등등) 자동화, 추상화 시켜 준다. 
DOM Tree변화를 하나로 묶어 적용시킴으로서, 변경된 노드사이의 동기화 작업이 필요없어진다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;어쨌든 가상 돔을 사용해도, 연산이 아예 사라지는 것이 아니기 때문에 단순히 &lt;strong&gt;가상 돔&lt;/strong&gt;을 쓴다고 해서 빠르다고 볼 수 없다. 그래도 보통 문제없이 사용할 정도는 된다고 한다. &lt;strong&gt;가상 돔&lt;/strong&gt;에서의 연산과정 조차 줄이기 위해서 아예 빌드시 해당 연산을 해버리는 &lt;strong&gt;svelte&lt;/strong&gt;도 있다. 하지만 html 변경시 재빌드가 필요하다는 단점이 있다.&lt;/p&gt;

&lt;h3 id=&quot;reference&quot;&gt;REFERENCE&lt;/h3&gt;
&lt;p&gt;(https://hashnode.com/post/the-one-thing-that-no-one-properly-explains-about-react-why-virtual-dom-cisczhfj41bmssp53mvfwmgrq)
(https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/)&lt;/p&gt;</content><author><name>조민제</name></author><category term="WEB" /><category term="Browser" /><category term="Virtual DOM" /><summary type="html">브라우저 작동방식에서 알아보는 가상돔의 필요성</summary></entry><entry><title type="html">DOM트리</title><link href="https://minje0204.github.io/web/DomTree/" rel="alternate" type="text/html" title="DOM트리" /><published>2021-08-18T00:00:00+09:00</published><updated>2021-08-20T07:10:01+09:00</updated><id>https://minje0204.github.io/web/DomTree</id><content type="html" xml:base="https://minje0204.github.io/web/DomTree/">&lt;h1 id=&quot;document-object-model-dom&quot;&gt;Document Object Model (DOM)&lt;/h1&gt;

&lt;h2 id=&quot;dom-이란&quot;&gt;DOM 이란?&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;브라우저에 의해 생성되는 node/element 트리&lt;/li&gt;
  &lt;li&gt;객체지향적인 표현방식&lt;/li&gt;
  &lt;li&gt;JavaScript는 DOM트리를 읽기/쓰기/수정 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;는 DOM트리를 읽을 수 있어 JS를 이용하면 웹 페이지에 존재하는 것들을 모두 &lt;strong&gt;수정, 추가, 제거&lt;/strong&gt;할 수 있다. 이를 위해 예전에는 Jquery를 사용했지만,  요즘은 &lt;strong&gt;vanilla JS&lt;/strong&gt;가 더 자주 쓰인다고 한다.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
	&lt;img src=&quot;https://user-images.githubusercontent.com/32082727/129891746-2557765f-8b8e-40c8-a289-796161004a47.gif&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;위 그림에서는 생략 됐지만 브라우저는 DOM tree 최상단에 &lt;strong&gt;window&lt;/strong&gt; object를 위치시키고 바로 밑에 DOM tree의 core인 Document object를 둔다.&lt;/p&gt;

&lt;p&gt;Root element부터 html로 표현해본다면 이렇게 될 것 같다.&lt;/p&gt;
&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE HTML&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My title&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~~~&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;My link&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;My header&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;
&lt;p&gt;그럼 이제 vanilla JS를 이용해서 DOM tree을 조작해보자.&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;
	&lt;img src=&quot;https://user-images.githubusercontent.com/32082727/129896213-93dbe55b-e273-4ac5-9ea8-8ca5d1191d90.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;개발자 도구를 켜서 document를 찍어보면&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;URL이 나오고 all에는 html 문서에 작성한 순서대로 웹을 구성하는 모든 태그들이 들어 있다. 이외에도 많은 정보들이 담겨있다.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
	&lt;img src=&quot;https://user-images.githubusercontent.com/32082727/129895946-0e08700c-8f93-4261-9a41-6c5d2bc9421e.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;그럼 이제 document node를 이용해 h1 태그를 &lt;strong&gt;수정&lt;/strong&gt;해보자.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.html&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt;  &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;title-container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
		&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&lt;/span&gt;  &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;header-title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Item Lister1&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;console&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;header-title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textContent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;   
&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;header-title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerText&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p align=&quot;center&quot;&gt;
	&lt;img src=&quot;https://user-images.githubusercontent.com/32082727/129900967-946c1170-e35a-428c-a2ab-61b670a439de.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;getElementById&lt;/strong&gt;를 이용하여 간단하게 title을 바꿔 보았다.
(참고. innerText와 textContent 둘의 차이점은 style의 영향 유무이다 )&lt;/p&gt;
&lt;div class=&quot;language-diff highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gi&quot;&gt;+ display:none인 다른 tag가 있을 때 
+ innerText는 그 태그 text를 제외하고 출력
+ textContent는 style 무시하고 모든 text를 출력
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이제 h1 태그 안에 새로운 태그를 &lt;strong&gt;추가&lt;/strong&gt;해보자&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;console&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newTag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  
&lt;span class=&quot;nx&quot;&gt;newTag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerText&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h1Tag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;header-title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;h1Tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;newTag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p align=&quot;left&quot;&gt;
	&lt;img src=&quot;https://user-images.githubusercontent.com/32082727/129904225-1e2df556-64e0-4dbe-a06b-fb8b5863b84e.png&quot; /&gt;
&lt;/p&gt;</content><author><name>조민제</name></author><category term="WEB" /><category term="DOM Tree" /><category term="JS" /><summary type="html">DOM트리 개념과 실습</summary></entry><entry><title type="html">Story Mapping, Product Backlog를 시각적으로 구성하는 방법</title><link href="https://minje0204.github.io/project/Productbacklog-burndownchart/" rel="alternate" type="text/html" title="Story Mapping, Product Backlog를 시각적으로 구성하는 방법" /><published>2021-03-30T00:00:00+09:00</published><updated>2021-03-30T09:10:00+09:00</updated><id>https://minje0204.github.io/project/Productbacklog-burndownchart</id><content type="html" xml:base="https://minje0204.github.io/project/Productbacklog-burndownchart/">&lt;p&gt;졸업프로젝트를 시작한지 한달….
이제 대략적인 컨셉이 잡혔다. 
프로젝트 구현에 앞서 구체적인 개발 계획을 짜야한다.
애자일 방법론을 활용한 프로젝트 관리를 알아보자.
애자일 방법론에서 제일 선행되어야 할 일은 Product backlog이다.&lt;/p&gt;

&lt;h3 id=&quot;product-backlog&quot;&gt;Product backlog&lt;/h3&gt;
&lt;hr /&gt;
&lt;p&gt;Product backlog는 프로젝트에서 &lt;strong&gt;구현해야할 모든 List&lt;/strong&gt;를 말한다. 
그렇다면 Product backlog는 어떻게 작성해야 할까?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;누가, 무엇을,왜&lt;/strong&gt; 3가지 항목을 포함하여 작성해보자 (사실상 유저 스토리 작성법)&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;누가(type of user)&lt;br /&gt;
여기서 &lt;strong&gt;누가&lt;/strong&gt;는 고객이나 사용자를 말한다. 연령대,취미등을 고려하여 구체화시키면 좋다. 예를 들자면, 30~40대 안전한 거래를 원하는 여성 주부들&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;무엇을(goal)&lt;br /&gt;
&lt;strong&gt;누가&lt;/strong&gt;에 해당하는 이해관계자의 goal이다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;왜&lt;br /&gt;
단순하게 왜 해당기능을 사용하는지 이기도 하지만
결과적으로 &lt;strong&gt;누가&lt;/strong&gt;에 해당하는 고객이나 사용자가 얻을 수 있는 이점이 된다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;product-backlog-작성시-생각해야할-3가지&quot;&gt;Product Backlog 작성시 생각해야할 3가지&lt;/h4&gt;
&lt;ol&gt;
  &lt;li&gt;Product Backlog는 항상 우선순위에 따라 정리한다.&lt;br /&gt;
팀 내부 판단하에 중요한 일들은 올리고 상대적으로 덜 중요하거나 기한의 여유가 있는 일은 백로그의 아래로 위치시킨다.&lt;/li&gt;
  &lt;li&gt;Detail and Rough&lt;br /&gt;
백로그 상단에 위치한 일들은 중요도가 높은 일이기 때문에 Detail한 표기가 필요하다. 반대로 하단에 위치한 일들은 상대적으로
Rough해도 괜찮다. 자세할수록 좋겠지만, &lt;strong&gt;최소한 제품이 지향하는 핵심가치나 차별화 포인트가 드러나야한다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Product Owner&lt;br /&gt;
프로덕트 오너는 백로그를 관리하는 사람이다. 일들의 우선순위를 정하고, 새로운일을 추가하거나 이미 진행중인 일들을 수정하기도 한다.
그래서, 프로덕트 오너는 모든 StakeHolders들과 의사소통하고 이를 백로그에 반영하여 한다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;요구사항의-우선순위-정하기&quot;&gt;요구사항의 우선순위 정하기&lt;/h3&gt;
&lt;hr /&gt;
&lt;p&gt;(MoSCow 방법)[https://wemake.services/meta/rsdp/requirements-analysis/#requirements-prioritization]&lt;/p&gt;

&lt;p&gt;총 4가지 카테고리로 요구사항을 나눈다.&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;must&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;should&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;could&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;won't&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;sprint-backlog&quot;&gt;Sprint Backlog&lt;/h3&gt;
&lt;hr /&gt;
&lt;p&gt;Product Backlog를 작성했으면 Sprint Backlog를 정해야한다.&lt;br /&gt;
Sprint는 무엇인가?&lt;br /&gt;
Sprint란 작은 기능 하나에 대한 계획부터 개발, 테스트, 기능 구현까지의 주기를 말한다.&lt;br /&gt;
대략 1~4주 사이의 기간으로 정해진다.&lt;br /&gt;
Sprint Backlog는 해당 Sprint기간에 해야할 백로그다.&lt;br /&gt;
하지만 당장 해야할 일들이기 때문에 백로그에 위치할 때보다 더 세분화 되어야 한다. 주로 task형식으로&lt;/p&gt;

&lt;h3 id=&quot;burndown-chart&quot;&gt;Burndown Chart&lt;/h3&gt;
&lt;hr /&gt;
&lt;p&gt;위에서 Sprint를 알아봤다. 번다운 차트는 스프린트동안의 개발 진행정도를 알려주는 차트다.&lt;br /&gt;
daily scrum에서 매일 업데이트 된다.&lt;/p&gt;

&lt;h3 id=&quot;story-mapping&quot;&gt;Story Mapping&lt;/h3&gt;
&lt;hr /&gt;
&lt;p&gt;요구사항 분석하는 top-down 방식 tree형태로 그려진다. Story Map의 최상단은 Vision이다. 이 Vision은 Goal을 통해서 이루어진다.
그리고 이 Goal은 activities에 의해서 이루어진다. 다시 이 activites는 Task로 이루어지고, 이 Task는 User Story가 된다.&lt;/p&gt;

&lt;p&gt;Story Map Structure: Goals &amp;gt; Activities &amp;gt; Tasks &amp;gt; Stories 순이다.&lt;/p&gt;</content><author><name>조민제</name></author><category term="Project" /><category term="Agile Project Management" /><category term="Product Backlog" /><category term="Story Map" /><summary type="html">유저스토리 작성, 애자일 방법론</summary></entry><entry><title type="html">Add profile image &amp;amp; File transfer from Window10 to WSL2</title><link href="https://minje0204.github.io/blog/AddProfile/" rel="alternate" type="text/html" title="Add profile image &amp;amp; File transfer from Window10 to WSL2" /><published>2021-03-14T00:00:00+09:00</published><updated>2021-03-14T16:46:00+09:00</updated><id>https://minje0204.github.io/blog/AddProfile</id><content type="html" xml:base="https://minje0204.github.io/blog/AddProfile/">&lt;p&gt;프로필 이미지를 추가하려고 아이폰에 저장되있는 사진을 불러오려고 했는데,원래 블로그 작업을 wsl에서 하고 있다 보니까 윈도우에 사진을 옮기고 scp로 wsl로 옮기려고 했다.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;scp profile.jpg minje0204@ip:/mnt/c/...(파일저장위치)  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;위명령어를 쳤는데 ssh: connect to host (wsl ip) port 22: Connection refused 에러가 떴다.&lt;/p&gt;

&lt;p&gt;찾아본 결과 나는 wsl에서&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vi /etc/ssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;로 ssh 세팅 환경에서 port지정해주는 부분의 주석처리를 지웠다 default는 22다.&lt;br /&gt;
PasswordAuthentication yes도 No에서 yes로 바꿔주었다.&lt;/p&gt;

&lt;p&gt;이렇게 세팅 2개를 완료하고도 똑같이 connection refused 에러가 뜨길래
찾아보니까 WSL2부터는 hyper-v 엔진위에서 Linux를 돌리기 때문에 별도의 가상 NIC를 가지고 있다는 말을 보고&lt;br /&gt;
WSL 내에서 ip를 확인해보니 왠걸 window 프롬프트에서 wsl로 나온 ip주소와 다른 ip주소가 나왔다.&lt;/p&gt;

&lt;p&gt;WSL에서 찾은 ip주소를 입력해주는 정상적으로 scp 가 작동했다.&lt;/p&gt;

&lt;hr /&gt;</content><author><name>조민제</name></author><category term="Blog" /><category term="Blog" /><category term="ssh" /><summary type="html">프로필 이미지를 추가하면서 해결한 ssh connection refuse 오류</summary></entry><entry><title type="html">github.io 블로그 시작하기</title><link href="https://minje0204.github.io/blog/GitHubBlogStart/" rel="alternate" type="text/html" title="github.io 블로그 시작하기" /><published>2021-03-13T00:00:00+09:00</published><updated>2021-03-13T11:36:00+09:00</updated><id>https://minje0204.github.io/blog/GitHubBlogStart</id><content type="html" xml:base="https://minje0204.github.io/blog/GitHubBlogStart/">&lt;p&gt;GitHub Blog 서비스인 github.io 블로그 시작하기로 했다.&lt;/p&gt;

&lt;p&gt;GitHub Blog 서비스의 이름은 Pages이다.&lt;/p&gt;

&lt;p&gt;Pages가 다른 블로그 플랫폼 보다 편한 것 같아서 마음에 든다.&lt;/p&gt;

&lt;p&gt;다른 사람들도 같이 많이 사용했으면 좋겠다는 생각이 든다.&lt;/p&gt;

&lt;p&gt;YFM에서 정의한 제목을 이중 괄호 구문으로 본문에 추가할 수 있다.&lt;/p&gt;

&lt;p&gt;이 글의 제목은 github.io 블로그 시작하기 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{&lt;/code&gt;{page.title&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;}&lt;/code&gt;}로 표현) 이고&lt;/p&gt;

&lt;p&gt;마지막으로 수정된 시간은 2021-03-13T00:00:00-02:36:00 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{&lt;/code&gt;{ page.last_modified_at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;}&lt;/code&gt;}로 표현)이다.&lt;/p&gt;

&lt;p&gt;다음은 GitHubBlog를 작성하기 위해 필요한 간단한 markdown을 알아보자.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;텍스트 줄바꿈
    &lt;hr /&gt;
    &lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;텍스트 줄바꿈을 하려면 스페이스 2번을 표기하면 된다.  
&lt;span class=&quot;ge&quot;&gt;*기울이기*&lt;/span&gt;는 '&lt;span class=&quot;err&quot;&gt;*&lt;/span&gt;'를 이용하고,  
&lt;span class=&quot;gs&quot;&gt;**볼딕체**&lt;/span&gt;는 '&lt;span class=&quot;ge&quot;&gt;**&lt;/span&gt;'를 이용한다.  
~~취소선~~은 '~~'를 이용한다.  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;글자 크기 지정
    &lt;hr /&gt;
    &lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;'#'개수가 적을 수록 글자가 커지며 # 개수는 6개 까지 가능하다.
&lt;span class=&quot;gh&quot;&gt;#h1  ###h3  ######h6  &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;인용
    &lt;hr /&gt;
    &lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gt&quot;&gt;&amp;gt; 인용문 &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;코드인용
    &lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;int main(){
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;markdown 코드를 그대로 표현하고 싶은데 C언어 처럼 ‘`’ 백틱은 작동하지 않는 것 같다. 한번 알아봐야겠다.&lt;/p&gt;

&lt;p&gt;왜 인지는 아직 모르겠지만 지킬 서비스를 background에서 수행중에 post 내용을 수정하면 반영이 되지 않는데, 다른 터미널에서 지킬 서비스를
동작시키고 또다른 터미널에서 post내용을 수정하면 그때는 바로 반영이 된다.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;GitHubBlog 개설 처음부터 마크 다운까지 &lt;a href=&quot;https://devinlife.com/howto/&quot;&gt;devinlife님&lt;/a&gt;의 블로그를 참조했다.&lt;/p&gt;</content><author><name>조민제</name></author><category term="Blog" /><category term="Blog" /><summary type="html">개인 기록, 공부한 것 기록을 위해서 블로그 시작하기로 했다.</summary></entry></feed>