<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>글쓰는 개발자</title>
    <link>https://blinders.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 21 Jun 2026 14:47:42 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Blindr_grey</managingEditor>
    <image>
      <title>글쓰는 개발자</title>
      <url>https://t1.daumcdn.net/cfile/tistory/9985373D5B93900819</url>
      <link>https://blinders.tistory.com</link>
    </image>
    <item>
      <title>AI 한테 배운 코드_01</title>
      <link>https://blinders.tistory.com/138</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최근 회사에 CodeRabbit 이라는 친구가 도입됐다.&lt;br /&gt;&lt;s&gt;설정이 거지같지만&lt;/s&gt; 나름 Rabbit 답게 귀여운 거 같은데,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여튼 코드 리뷰를 아주 빠삭하게 해주고 있고 거기에서 배울 것들이 있는 거 같아서 기록차 한개씩 남겨보려고한다.&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;br /&gt;1. 체크박스 클릭시의 로직&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내가 평소에 흔하게 쓰던 로직&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1755153999483&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const value = Number(e.currentTarget.value);

if (e.currentTarget.checked) {
  setState((prev) =&amp;gt; prev.concat(value));
  return;
}
setState((prev) =&amp;gt; prev.filter((id) =&amp;gt; id !== value));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AI가 추천한 로직&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1755154070242&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const studentId = Number(e.currentTarget.value);
if (Number.isNaN(studentId)) return;

setState((prev) =&amp;gt; {
  const next = new Set(prev);
  if (e.currentTarget.checked) next.add(studentId);
  else next.delete(studentId);
  return Array.from(next);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 위 두 코드가 UI 적으로 보이는 동작은 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체크박스가 있는 리스트에서 클릭했을때,&lt;br /&gt;체크되어 있던거라면 체크 해제+선택 목록에서 제거&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체크 안되어있던거라면 체크하고+선택 목록에 추가&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 너무 심플한거라 크게 신경쓰지 않고 관성처럼 써왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 난 여기서 인간과 AI의 차이를 조금 느꼈다.&lt;br /&gt;'굳이 이렇게까지?'라고 생각하는 관점을 코드에 녹여놓을때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간은 '충분해'라고 느끼더라도 AI는 '이렇게까지.'의 방식으로 코드를 대한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 체크박스 클릭시의 로직&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내가 흔하게 쓰던 로직의 예시&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1755163930129&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const handleSubmit = async (formValue) =&amp;gt; {
  const { isMobile } = formValue;
  if(isMobile){
    await updateMobileInfo();
    return;
  }
  await updateTabletInfo();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건에 따라 API를 다르게 부르는 케이스에 보통 이렇게 쓰거나, 아래 if문을 하나 더 넣어서 감싸거나했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 코드 래빗이 이렇게 가이드하면 어떠냐고 제안을 줬다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AI가 추천한 로직&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1755164038201&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const handleSubmit = async (formValue) =&amp;gt; {
  const { isMobile } = formValue;
  if(isMobile){
    await updateMobileInfo();
    return;
  }
  if(isMobile){
    await updateTabletInfo();
    return;
  }
  throw new Error('Invalid device type');
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보자마자 이마를 탁쳤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의도한 방향이 아니니까 Error를 발생시켜서 좀 더 명확하게 잡겠다...라는 거. 너무 좋다.&lt;br /&gt;서비스에서 분명하게 의도한 조건이 명확한데, 그거 외엔 Error를 명시적으로 던지는 거, 너무 좋은 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난 왜 이걸 관성적으로 생각해내지 못 했을까.&lt;/p&gt;</description>
      <category>개발/기타(Etc)</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/138</guid>
      <comments>https://blinders.tistory.com/138#entry138comment</comments>
      <pubDate>Thu, 14 Aug 2025 15:53:43 +0900</pubDate>
    </item>
    <item>
      <title>[sonarqube] intellij에서 analyze current file 했을때, jsonrpc.RemoteEndpoint bad escape 이슈</title>
      <link>https://blinders.tistory.com/134</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;기존 장비를 수리 보낸 사이에 임시장비를 받게 되었고,&lt;br /&gt;세팅을 다시 하는 과정에서 IntelliJ에 소나큐브를 설치했는데...&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;인텔리J에 소나큐브 플러그인을 설치하고 &lt;b&gt;analyze current file&lt;/b&gt;을 실행했는데 아래와 같은 에러가 발생했다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;[SonarLint Server RPC request executor] ERROR org.eclipse.lsp4j.jsonrpc.RemoteEndpoint - Internal error: java.lang.IllegalArgumentException: Bad escape&lt;br /&gt;java.util.concurrent.CompletionException:&amp;nbsp;java.lang.IllegalArgumentException:&amp;nbsp;Bad&amp;nbsp;escape&lt;br /&gt;at&amp;nbsp;java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)&lt;br /&gt;at&amp;nbsp;java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)&lt;br /&gt;at&amp;nbsp;java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:649)&lt;br /&gt;at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:482)&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3284&quot; data-origin-height=&quot;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Pcls8/btsMOrwOMHS/CTYuDmkLfdoNjl5CUmB9CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Pcls8/btsMOrwOMHS/CTYuDmkLfdoNjl5CUmB9CK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Pcls8/btsMOrwOMHS/CTYuDmkLfdoNjl5CUmB9CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPcls8%2FbtsMOrwOMHS%2FCTYuDmkLfdoNjl5CUmB9CK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3284&quot; height=&quot;492&quot; data-origin-width=&quot;3284&quot; data-origin-height=&quot;492&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론부터 말하자면, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;파일 경로에 '한글'이 있는 이슈&lt;/b&gt;&lt;/span&gt;였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(2시간 삽질의 결과치곤 좀 허무하다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 원인을 찾은 방법은 히스토리는 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;구글링해도 딱 맞게 나오지않는 에러라서,&lt;br /&gt;요즘 내 절친인 Chat GPT한테 물어봤더니 아래와 같은 5가지 사항을 확인하라고 했다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.0465%;&quot;&gt;원인&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%;&quot;&gt;해결 방법&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;확인 결과&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.0465%;&quot;&gt;SonarQube URL 설정문제&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%;&quot;&gt;SonarLint -&amp;gt; SonarQube Connection URL 확인 (ex. http://localhost:9000)&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;회사 리모트에 설치된 소나큐브이며, 플러그인 Test Connection에서 성공으로 결과뜸.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;따라서 이 원인은 아님.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.0465%;&quot;&gt;프로젝트 Sonar-project.properties 설정 오류&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%;&quot;&gt;백슬래시, 퍼센트 제거 &amp;amp; 올바른 경로 설정&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;현재 파일 경로 어디에도 백슬래시, 퍼센트와 같은 특수문자가 없음.&lt;br /&gt;&lt;br /&gt;이 원인은 아님.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;...이라고 넘어갔다가 설마 싶었는데 얘가 맞았음. 경로에 한글이 있는 이슈였다니...&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.0465%;&quot;&gt;SonarLint 플러그인 캐시 문제&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%;&quot;&gt;rm -rf ~/.sonarlint 후 IntelliJ 재시작&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;방금 설치한 플러그인이라 캐시 이슈가 있을리 없지만...시도는 함.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;이 원인은 아님.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.0465%;&quot;&gt;SonarLint 실행 JDK 문제&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%;&quot;&gt;JDK 17 이상을 사용하도록 설정(java --version으로 현재 버전 확인)&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;JDK최신의 23을 사용중.&lt;br /&gt;(혹시나 싶어 IntelliJ가 바라보는 JDK도 확인함)&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;이 원인은 아님.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.0465%;&quot;&gt;SonarQube 플러그인 충돌&lt;/td&gt;
&lt;td style=&quot;width: 38.9535%;&quot;&gt;오래된 플러그인 삭제 후 SonarQube 재시작&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;위에 언급했듯, 신규 장비 세팅중이라서 플러그인들도 모두 최신버전.&lt;br /&gt;&lt;br /&gt;혹시나 싶어서 인텔리J와 소나큐브 플러그인 버전의 호환 이슈인가 싶었지만, 둘 다 릴리즈 기준 호환가능한 걸로 각 doc에서 확인.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;얘도 원인이 아님.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 뭐한다고 2시간이나 붙잡고 있었지 싶은데, 트러블 슈팅이 원래 그런거지만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(막상 해결되면 허무함)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1412&quot; data-origin-height=&quot;206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vbnA0/btsMOwELx0O/wdL02bjr33csEJKEtXZE2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vbnA0/btsMOwELx0O/wdL02bjr33csEJKEtXZE2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vbnA0/btsMOwELx0O/wdL02bjr33csEJKEtXZE2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvbnA0%2FbtsMOwELx0O%2FwdL02bjr33csEJKEtXZE2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;605&quot; height=&quot;88&quot; data-origin-width=&quot;1412&quot; data-origin-height=&quot;206&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 '설정'류의 에러는 정말 풀리지않으면 개인적으로 답답해서 잠도 못 자기 때문에 나와 같은 분들을 위해 정리해둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;결국 첫 문장에 복선을 깔아뒀던건데,&lt;br /&gt;내 장비를 수리 맡긴 사이에 받은 임시 장비였고 그래서 아무생각없이 메인 디렉토리 명을 '그레이'라고 정의했다&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(어차피 수리완료되면 반납 할 기기니까...그까이꺼 뭐 대충, 싶었지. 참고로 원래 장비는 'grey'라는 영문명으로 정의되어있다)&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;196&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0VVWB/btsMNJdIqff/RKit7eHW5P33SD8bkwAlh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0VVWB/btsMNJdIqff/RKit7eHW5P33SD8bkwAlh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0VVWB/btsMNJdIqff/RKit7eHW5P33SD8bkwAlh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0VVWB%2FbtsMNJdIqff%2FRKit7eHW5P33SD8bkwAlh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;196&quot; height=&quot;196&quot; data-origin-width=&quot;196&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 이게 이런 트러블 슈팅 거리를 뱉어낼 줄은 몰랐지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자 여러분, path는 영어 씁시다 영어...&lt;/p&gt;</description>
      <category>개발/트러블 슈팅(Trouble Shooting)</category>
      <category>개발</category>
      <category>소나큐브</category>
      <category>인텔리J</category>
      <category>트러블슈팅</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/134</guid>
      <comments>https://blinders.tistory.com/134#entry134comment</comments>
      <pubDate>Wed, 19 Mar 2025 10:19:56 +0900</pubDate>
    </item>
    <item>
      <title>iOS는 다운받은 이미지의 크기를 멋대로 줄여버린다.</title>
      <link>https://blinders.tistory.com/129</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 분들이 업로드하는 이미지에 GPT를 첨가하는 과제를 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 QA를 하다가 티켓이 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 삽질을 엄청 해댔으니까 이렇게 남겨놓는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론부터 말하자면 iOS 이 나쁜 놈들아...다.&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;QA 티켓으로 iOS 환경에서 질의가 들어왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 max로 정의한 해상도 이상의 이미지가 업로드 된다는 거였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어서, validation 로직에 최대 1920 x 1080 이미지로 제한을 걸어뒀는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;QA 분들이 10000 x&amp;nbsp; 20000 짜리 이미지를 업로드 했는데 업로드가 된다는 거였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iOS로 발생한 이슈라고 제보를 받았는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 아이폰은 잘 막는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐, 뭐지...?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://discussions.apple.com/thread/1626442&quot;&gt;https://discussions.apple.com/thread/1626442&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...요약하자면 iOS가 가지고 있는 '자동 이미지 조정'기능이 원인이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까 흔히 말하는 애플식 최적화 로직을 바탕으로 이미지의 픽셀을 줄일 수도 있다는 거였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(참고로 사이즈를 줄이니 용량도 줄어든다. 용량 validation 체크도 티켓이 생성됐었는데, 결국 원인은 이거였다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로 말해서 이건 노운 이슈로 가져가게 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩔 수가 없다...iOS를 내가 뜯어고칠 수는 없으니까...&lt;/p&gt;</description>
      <category>개발/트러블 슈팅(Trouble Shooting)</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/129</guid>
      <comments>https://blinders.tistory.com/129#entry129comment</comments>
      <pubDate>Tue, 19 Sep 2023 10:54:02 +0900</pubDate>
    </item>
    <item>
      <title>해외에서 일을 한 번 해봅시다(스페인:세비야편)</title>
      <link>https://blinders.tistory.com/127</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0.&amp;nbsp; Cero&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://techblog.woowahan.com/10504/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;근무지 자율 선택제&lt;/a&gt;의 일환으로 해외에서 근무가 가능해졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달 살기를 하면서 많은 사람들을 거기서 만났는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만나서 이런 저런 이야기를 하다보면 늘상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;다들 여행 오신지 얼마나 되셨어요?&lt;/span&gt; &lt;/b&gt;라고 누군가 꼭 묻는데&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;&quot;아 저는 한 달 살기 하러 왔어요&quot;&lt;/b&gt;&lt;/span&gt;라고 답하면 다들 부러워하더라구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;s&gt;(사실 퇴사하고 오신 분이 더 부러웠지만)&lt;/s&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;297&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yh3DX/btsoQLjJIIp/1eKHnkUhP5bKVjKBtKlAb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yh3DX/btsoQLjJIIp/1eKHnkUhP5bKVjKBtKlAb0/img.png&quot; data-alt=&quot;이제는 DONE&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yh3DX/btsoQLjJIIp/1eKHnkUhP5bKVjKBtKlAb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fyh3DX%2FbtsoQLjJIIp%2F1eKHnkUhP5bKVjKBtKlAb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;297&quot; height=&quot;255&quot; data-origin-width=&quot;297&quot; data-origin-height=&quot;255&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이제는 DONE&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저도 제가 해보기 전까진 부러워만하던 사람이라 공감하면서 즐겁게 한 달 살기 할 수 있었습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1.&amp;nbsp; 허리가 휜다...&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2632&quot; data-origin-height=&quot;1904&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m8LiS/btsoEqncH80/LCz9fka35n1rgtBKRDYPVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m8LiS/btsoEqncH80/LCz9fka35n1rgtBKRDYPVK/img.png&quot; data-alt=&quot;바리바리 짐을 싸보자&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m8LiS/btsoEqncH80/LCz9fka35n1rgtBKRDYPVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm8LiS%2FbtsoEqncH80%2FLCz9fka35n1rgtBKRDYPVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;521&quot; height=&quot;377&quot; data-origin-width=&quot;2632&quot; data-origin-height=&quot;1904&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;바리바리 짐을 싸보자&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출국은 &lt;b&gt;6/5&lt;/b&gt;에 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;귀국은 &lt;b&gt;7/17&lt;/b&gt;에 했구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스페인에서의 &lt;b&gt;워케이션은 한 달(6/7 ~ 7/5)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 휴가를 써서 &lt;b&gt;열흘간의 포르투칼 여행(7/6 ~ 7/16)&lt;/b&gt;을 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;떠날 당시 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;백팩의 무게는 10kg&lt;/b&gt;&lt;/span&gt;, 캐리어는 15kg 였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;459&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J2jlE/btsoz8AHMea/Rf07nZ9l1dRMPFrn9kdfjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J2jlE/btsoz8AHMea/Rf07nZ9l1dRMPFrn9kdfjK/img.png&quot; data-alt=&quot;무게가 뭐가 이상한데?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J2jlE/btsoz8AHMea/Rf07nZ9l1dRMPFrn9kdfjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ2jlE%2Fbtsoz8AHMea%2FRf07nZ9l1dRMPFrn9kdfjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;408&quot; height=&quot;459&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;459&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;무게가 뭐가 이상한데?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네, 무게가 뭐가 이상하죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경유 포함 20여시간의 비행이었는데 저도 제 허리가 휘는 줄 알았습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백팩이 무거웠던 이유는 간단한데요, 이번 해외행의 중점은 워케이션이었기 때문이죠.&lt;/p&gt;
&lt;pre id=&quot;code_1690167664360&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;맥북, 포터블 모니터, 거치대, 키보드, 마우스, USB 젠더, 카메라, 아이패드, 랜선, 각종 선들,닌텐도 스위치, 소니MX5...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럴일은 없겠지만 캐리어가 유실 될 경우 업무를 할 수 없는 환경이 되면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 돌아 올 마음을 먹고 떠났기 때문에, 지니고 가야 할 귀중품 아닌 귀중품들이 한 가득이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;331&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kse5K/btsoyW79kZB/22xOs9xKPGDm2Na2S160H1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kse5K/btsoyW79kZB/22xOs9xKPGDm2Na2S160H1/img.png&quot; data-alt=&quot;미니멀리즘은 늘 꿈만 굽니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kse5K/btsoyW79kZB/22xOs9xKPGDm2Na2S160H1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKse5K%2FbtsoyW79kZB%2F22xOs9xKPGDm2Na2S160H1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;321&quot; height=&quot;331&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;331&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;미니멀리즘은 늘 꿈만 굽니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐, 결론적으론 다행히도 캐리어도 무사히 잘 도착했고 일을 할 수 있는 환경도 잘 구성할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2.&amp;nbsp;  미리(해)보기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠시 돌아와서, 제주도(2월)와 일본(4월) 이야기를 하려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 근무지 자율 선택제는 작년말에 전격 공지되었고, &lt;b&gt;올해 1월부터 가능&lt;/b&gt;했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpEWkq/btsozTXQ5UM/GyF3K3qj5oFk0zDK51QrCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpEWkq/btsozTXQ5UM/GyF3K3qj5oFk0zDK51QrCk/img.png&quot; data-alt=&quot;이때부터 여행 유튜브를 했어야 싶긴합니다만(by, 회사 자기소개글)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpEWkq/btsozTXQ5UM/GyF3K3qj5oFk0zDK51QrCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpEWkq%2FbtsozTXQ5UM%2FGyF3K3qj5oFk0zDK51QrCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;666&quot; height=&quot;570&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;570&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이때부터 여행 유튜브를 했어야 싶긴합니다만(by, 회사 자기소개글)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 여행을 좋아하는 저는 1월부터 당장 뛰쳐나가고 싶었습니다만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상반기에 바쁠 수 밖에 없는 과제가 예정되어있었고, 현실적으로 나갈 수 있는 여건이 되질 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(가려면 또 갈 수는 있는데, 거기가서 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;우리의 일주일은 월화수목금금금&lt;/b&gt;&lt;/span&gt;하는 다듀의 출석체크를 듣는다면 의미가 없잖아요)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;과제 오픈을 하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달 여 정도 추이를 지켜 본 뒤에 안정적으로 나갈 수 있게끔 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;6월로 계획&lt;/b&gt;&lt;/span&gt;을 잡았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 1월에 무작정 항공권 결제&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;s&gt;(마침 또 1월이라 리셋된 회사 복지포인트로 했더니 내 돈 안 쓴 거 같고 너무 좋았...)&lt;/s&gt;&lt;/span&gt;는 했는데 저도 걱정이 되더라구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달, 혹은 한 달 반. 해외에서 일을 한다? 인터넷은 괜찮을까? 모니터도 작은 거 밖에 없는데? 막상 갔는데 일이 안 되면 어떡하지? 갔는데 막상 일을 할 수 없는 환경이라면, 그리고 그 기간이 일주일이나 이주일, 혹은 열흘 정도로 짧다면 휴가를 쓰고 여행왔다 생각하고 보내고 돌아오면 되는데...한 달 반? 태어나서 한국을 그만큼 떠났던 적이 없는데...?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kBDX3/btsozR6EO8T/TnlzysAHSHFwZmzHn1sfzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kBDX3/btsozR6EO8T/TnlzysAHSHFwZmzHn1sfzk/img.png&quot; data-alt=&quot;결론부터 말하자면 다 쓸데없는 걱정이었다...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kBDX3/btsozR6EO8T/TnlzysAHSHFwZmzHn1sfzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkBDX3%2FbtsozR6EO8T%2FTnlzysAHSHFwZmzHn1sfzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;360&quot; height=&quot;297&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;결론부터 말하자면 다 쓸데없는 걱정이었다...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 미리 연습을 좀 해봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TKsWU/btsoCFEWOR4/wmsTsgoL0CdkpCMKkS7X1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TKsWU/btsoCFEWOR4/wmsTsgoL0CdkpCMKkS7X1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TKsWU/btsoCFEWOR4/wmsTsgoL0CdkpCMKkS7X1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTKsWU%2FbtsoCFEWOR4%2FwmsTsgoL0CdkpCMKkS7X1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;742&quot; height=&quot;402&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;402&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 가볍게 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;2월에 제주도에서 일주일&lt;/b&gt;&lt;/span&gt;을 보냈습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오전과 오후에 주로 카페를 돌아다니면서 일을 했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각보다 제주에는 한적한 카페가 많고 당연하지만 와이파이가 잘 되서 무리가 없더라구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 국내훈련(?)을 끝마쳤으니 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;4월에는 일본(오사카)&lt;/b&gt;&lt;/span&gt;으로 떠났습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오사카는 구글맵을 켜지 않고도 골목 여기저기를 다닐 수 있을만큼,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;너무 자주 갔던 도시라서 크게 부담이 없었는데요.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://www.coworkbooking.com/asia/japan/osaka/fabbit-global-gateway-osaka-honmachi-&quot;&gt;Fabbit Global&lt;/a&gt; 이라는 코워킹 스페이스를 이용해봤습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;631&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AMxNg/dJMcaduJuoa/NWhjgUjvV6wimtvjrMFAN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AMxNg/dJMcaduJuoa/NWhjgUjvV6wimtvjrMFAN1/img.png&quot; data-alt=&quot;Fabbit Global&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AMxNg/dJMcaduJuoa/NWhjgUjvV6wimtvjrMFAN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAMxNg%2FdJMcaduJuoa%2FNWhjgUjvV6wimtvjrMFAN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;425&quot; height=&quot;394&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;631&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Fabbit Global&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일주일의 Hot Desk(지정좌석없이 편한 곳 앉아서 일하는 형태)를 예약했는데 8만원 가량했고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코워킹 스페이스 답게 일을 하는데는 전혀 문제가 없었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 결론은,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;515&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIfTCq/btsoz88w2dG/Evhym566RTNTQzVaOAlUT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIfTCq/btsoz88w2dG/Evhym566RTNTQzVaOAlUT0/img.png&quot; data-alt=&quot;이게 됐애용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIfTCq/btsoz88w2dG/Evhym566RTNTQzVaOAlUT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIfTCq%2Fbtsoz88w2dG%2FEvhym566RTNTQzVaOAlUT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;223&quot; height=&quot;338&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;515&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이게 됐애용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;되더라구요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 6월에도 마음편히 나갔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;403&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sgLoL/btsoGhcKOjB/Kxdshsvijh4Vg2Rkqy3yI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sgLoL/btsoGhcKOjB/Kxdshsvijh4Vg2Rkqy3yI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sgLoL/btsoGhcKOjB/Kxdshsvijh4Vg2Rkqy3yI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsgLoL%2FbtsoGhcKOjB%2FKxdshsvijh4Vg2Rkqy3yI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;322&quot; height=&quot;211&quot; data-origin-width=&quot;403&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 막상 갔는데 실전에서 문제점이 있다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 그냥 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;기회비용으로 시원하게 돈 썼다 생각하고 돌아오지 뭐&lt;/b&gt;,&lt;/span&gt; 라는 마음을 먹은채로 말이죠&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Sevilla&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 떠난 스페인, 한 달 살기를 한 도시는 &lt;b&gt;세비야&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1094&quot; data-origin-height=&quot;727&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpd0eO/btsoEqt1gt3/OpcEwm2pP6kEws0hDZre5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpd0eO/btsoEqt1gt3/OpcEwm2pP6kEws0hDZre5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpd0eO/btsoEqt1gt3/OpcEwm2pP6kEws0hDZre5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpd0eO%2FbtsoEqt1gt3%2FOpcEwm2pP6kEws0hDZre5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1094&quot; height=&quot;727&quot; data-origin-width=&quot;1094&quot; data-origin-height=&quot;727&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플라멩코의 발상지인 안달루시아 지방의 대표적인 여행도시.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올드타운과 뉴타운이 과달키비르 강 하나를 두고 마주보는 도시.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스페인 광장이라는 랜드마크를 가지고 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;론다나 네르하, 그라나다, 코르도바와 같은 근교여행도 용이한 곳.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따릉이와 같은 자전거(Sevici) 시스템이 있어서 일주일 12유로면 자전거 하나로 어디든 갈 수 있을 만큼 작은 소도시.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...그리고 무엇보다 &lt;b&gt;네임드 도시인데 한 달 살이 집 값이 그나마 저렴&lt;/b&gt;한 곳.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 제 생에 첫 유럽 한 달 살기 도시로 선택한 곳입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 집 찾기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세비야에서 지내기 위해서 저는 에어비앤비를 활용했는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 잠깐 팁을 드리자면...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에어비앤비의 그 옛날 카피라이트가 &lt;b&gt;여행은 살아보는거야&lt;/b&gt;라는 문구라는 걸 기억하시는 분이 있을 지 모르겠습니다만, 그 말에 알맞게 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;한 달 이상의 기간으로 예약하면 할인폭이 대폭 상승&lt;/b&gt;&lt;/span&gt;합니다. 우스갯소리로 20일을 빌리는 것보다 30일을 빌리는게 더 저렴한 경우도 있는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 저도 딱 한 달을 빌렸는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리비아 지구에 있는 작은 원룸형태의 아파트먼트 였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;597&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTpDqD/btsox9G9CaP/XI1TGlHJ6F62m0QkrM96f0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTpDqD/btsox9G9CaP/XI1TGlHJ6F62m0QkrM96f0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTpDqD/btsox9G9CaP/XI1TGlHJ6F62m0QkrM96f0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTpDqD%2Fbtsox9G9CaP%2FXI1TGlHJ6F62m0QkrM96f0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;882&quot; height=&quot;597&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;597&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 집을 찾을 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에어비앤비의 필터 중에 &lt;b&gt;집 전체&lt;/b&gt;와 &lt;b&gt;무선 인터넷&lt;/b&gt;을 필수로 체크하고 검색했는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 해외에 있더라도 우리는 한국시간으로 근무를 해야하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 현지에서는 새벽에 일을 해야한다는 걸 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스페인과 우리나라의 시차는 제가 있을 때 기준으로 7시간입니다&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(서머타임 적용, 그외엔 8시간)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;한국의 오전 9시는 현지에서 새벽 2시&lt;/b&gt;구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국의 &lt;b&gt;오후 5시는 거기서 오전 10시&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;까만 밤도 아닌 새벽에 출근&lt;/b&gt;해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아침 해가 빛나는 끝이없는 바닷...가가 아니라 &lt;b&gt;해가 머리위에 뜰랑말랑할 때 퇴근&lt;/b&gt;한다는 이야기죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 독립적으로 업무 할 수 있는 환경 + 편히 낮시간에 잘 수 있는 환경을 위해 &lt;b&gt;집 전체&lt;/b&gt;를 필터로 걸었었구요. 원활한 업무를 위해 인터넷은 필수였기 때문에, 위 2가지 필터로 집을 찾아서 예약하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 일본에서 했던 것처럼 코워킹 스페이스를 이용하려고 찾아봤는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 코워킹 스페이스가 주간 타임만 오픈하고 24h로 운영하는 곳은 없었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또, &lt;b&gt;결국 집 + 코워킹 스페이스 비용&lt;/b&gt; 생각하면 그냥 &lt;b&gt;집 전체를 빌려서 일하는게 마음 편할 것&lt;/b&gt; 같았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(그리고 일본에서 코워킹 스페이스를 이용했었는데, 그때 홈페이지에는 운영시간이 24h로 표기되어있었지만 실제로 갔더니 9 to 7 였던 것도 마음에 걸렸었구요)&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이번에 에어비앤비에서 집을 찾으면서 느낀건데,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;199&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cw0Xlh/btsozTpOdzW/BNn6OJQpZrAn1RoZ4B5FZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cw0Xlh/btsozTpOdzW/BNn6OJQpZrAn1RoZ4B5FZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cw0Xlh/btsozTpOdzW/BNn6OJQpZrAn1RoZ4B5FZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcw0Xlh%2FbtsozTpOdzW%2FBNn6OJQpZrAn1RoZ4B5FZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;470&quot; height=&quot;199&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;199&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각보다 디지털 노마드들이 많다고 느낀 점이 에어비앤비의 숙소 설명을 보면 저렇게 표기된 곳이 많습니다. 혹시 저처럼 에어비앤비를 통해서 집을 빌리시는 분들은 저 안내사항을 잘 참고하시면 될 것 같고...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 가장가장가장 우려하고 걱정거리였던 인터넷 환경은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;1630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RfNWy/btsoyqobMp6/p8zvy5Vr8smjl3NwyCKJk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RfNWy/btsoyqobMp6/p8zvy5Vr8smjl3NwyCKJk1/img.png&quot; data-alt=&quot;...뭔데 왜 우리집보다 빠르냐...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RfNWy/btsoyqobMp6/p8zvy5Vr8smjl3NwyCKJk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRfNWy%2FbtsoyqobMp6%2Fp8zvy5Vr8smjl3NwyCKJk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;502&quot; height=&quot;456&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;1630&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;...뭔데 왜 우리집보다 빠르냐...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희집보다 빨랐습니다^_^&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(우리집 무선이 100MB 안팎인데...근 4배차이...한국 인터넷 빠르다는 거 다 옛말...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 누구나 그럴싸한 계획을 가지고 있다.&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1690161208314&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 스페인 생활 2일차쯤
팀원 : 구현님 시차 적응은 잘 하셨어요?
저 : 시차 적응하면 큰일나요...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스페인에 있지만 한국시간으로 일을 한다는 건 그런겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;시차 적응을 하면 큰일&lt;/b&gt;&lt;/span&gt;납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이번 스페인 워케이션에서 제가 생각했던 24시간은 이랬습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;705&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d9h6K4/btsoGfMEg5u/AnQs8pAQfjcih1HjhVZqX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d9h6K4/btsoGfMEg5u/AnQs8pAQfjcih1HjhVZqX0/img.png&quot; data-alt=&quot;유럽 강변을 따라 러닝...크으........&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d9h6K4/btsoGfMEg5u/AnQs8pAQfjcih1HjhVZqX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd9h6K4%2FbtsoGfMEg5u%2FAnQs8pAQfjcih1HjhVZqX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;567&quot; height=&quot;477&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;705&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;유럽 강변을 따라 러닝...크으........&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 인생은 실전이라고...막상 가보니 &lt;b&gt;큰 변수 2개&lt;/b&gt;가 있더군요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나는, 스페인...그 중에서도 세비야는 남부지방이고 여름엔 아~~~~~~주 덥다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나는, 여름의 스페인의 일몰은 &lt;b&gt;오후 10시&lt;/b&gt;라는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...네, &lt;b&gt;해가 안 져요.&lt;/b&gt; 낮 기온이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;42도&lt;/b&gt;&lt;/span&gt;인데 그게 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;오후 10시&lt;/b&gt;&lt;/span&gt;까지 그래요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;1100&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ys3FT/btsoyIpbtxx/nPEYJcYnsgQE1wxcpwPdgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ys3FT/btsoyIpbtxx/nPEYJcYnsgQE1wxcpwPdgK/img.png&quot; data-alt=&quot;그 당시의 인스타 스토리... 해 쟤 왜 저랬는지 아직도 모르겠음&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ys3FT/btsoyIpbtxx/nPEYJcYnsgQE1wxcpwPdgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYs3FT%2FbtsoyIpbtxx%2FnPEYJcYnsgQE1wxcpwPdgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;289&quot; height=&quot;454&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;1100&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그 당시의 인스타 스토리... 해 쟤 왜 저랬는지 아직도 모르겠음&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마음 편하게 퇴근 후 벌건 대낮에 야외에서 맥주 한 잔 하면서, 유럽의 여유를 만끽하며 사람 구경하겠다는 제 희망사항은 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;내리쬐는 뙤약볕에 타들어가는 목과 팔과 소금기 감도는 등짝에 쏙&lt;/b&gt; &lt;/span&gt;들어가버렸고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(운동선수들이 왜 전지훈련 가는지 깨달음...저 지금 한국왔는데 하나도 안 더움...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;편하게 자려던 밤시간은 눈이 부셔서 비행기에서 받은 안대를 버리지 않은 저를 칭찬할 수 밖에 없었습니다. 그 와중에 숙소에 암막커튼 있어서 정말 다행이었어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;무엇보다 익숙해지지 않은 기분이 문제&lt;/b&gt;&lt;/span&gt;였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 복합적으로 첫 주차때 제일 고생을 많이했죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여행도 하고 싶은데, 일도 해야하고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밤에 일은 필수니까 잠은 자야하는데 낮에 여행도 하고 싶으면...잠은 언제 자?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 자야하니까 집에 들어와서 누웠는데 세상이 너무 환해, 그리고 더워.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;325&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wlZSf/btsoCGDOyBd/L7ZRKGidQZWPC6OISK7kOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wlZSf/btsoCGDOyBd/L7ZRKGidQZWPC6OISK7kOk/img.png&quot; data-alt=&quot;사, 살려줘...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wlZSf/btsoCGDOyBd/L7ZRKGidQZWPC6OISK7kOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwlZSf%2FbtsoCGDOyBd%2FL7ZRKGidQZWPC6OISK7kOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;571&quot; height=&quot;325&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;325&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사, 살려줘...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 계획을 전면수정했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;더울 땐 어차피 못 돌아다닌다, 나도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;시에스타&lt;/b&gt;를 즐겨야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;729&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AEQ2W/btsoyoxesDA/UeSO4doxwASIlHkfoF3I3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AEQ2W/btsoyoxesDA/UeSO4doxwASIlHkfoF3I3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AEQ2W/btsoyoxesDA/UeSO4doxwASIlHkfoF3I3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAEQ2W%2FbtsoyoxesDA%2FUeSO4doxwASIlHkfoF3I3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;585&quot; height=&quot;518&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;729&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여행은 살아보는거야,&lt;/b&gt; 라는 에어비앤비의 카피라이트를 체감하게 되는 계획표인데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 스케쥴이 가능했던 건 결국 제가 있던 곳이 스페인이기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스페인은 시에스타(la siesta)라는 낮잠&amp;amp;휴식 문화를 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;낮이 너무너무너무 뜨겁고 따갑기 때문인데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 대부분의 식당도 오후 1시쯤 문을 닫고 오후 8시에 오픈해요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 제가 살이 타들어가는 걸 감수하고 돌아다닌다고 하더라도 할 수 있는게 한정된다는거죠...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 그럴거면 낮에는 집에서 에어컨 시원하게 켜놓고 푹 자고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨디션 관리하면서 저녁에 맛집가고 돌아다니는 게 훨씬 좋다고 판단한거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(물론 오후 8시쯤 나와도 37~8도...한 여름의 한국보다 더 더웠지만 낮에 비하면 그 정도는 귀엽죠)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. 그래서 얼마?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 적응하고 한 달 동안 스페인에서 일을 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 모니터밖에 없었던 덕에 거북목으로 지내고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;허먼밀러가 아닌 탓에 쿠션을 허리에 덫댄채 의자에 기대고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새벽에 커피를 구할 수가 없어서 카페인 섭취량이 훅 줄어들었지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;좋은 경험&lt;/b&gt;&lt;/span&gt;이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포를 일찍한다구요...? &lt;b&gt;오히려 좋아&lt;/b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(난 어차피 깨어있으니까)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금요일 오전 10시에 시작하는 주말&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(심지어 우리는 월요일 1시 출근인데?)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미련없이 여유있게 유럽을 만끽할 수 있는 시간&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(...솔직히 4주차쯤엔 집에서 넷플릭스보고 뒹굴었...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1397&quot; data-origin-height=&quot;806&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bu7ve1/btsozkvaLW7/yuPP1G76VExNLiSz1Zmwyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bu7ve1/btsozkvaLW7/yuPP1G76VExNLiSz1Zmwyk/img.png&quot; data-alt=&quot;한 달, 좋았다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bu7ve1/btsozkvaLW7/yuPP1G76VExNLiSz1Zmwyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbu7ve1%2FbtsozkvaLW7%2FyuPP1G76VExNLiSz1Zmwyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1397&quot; height=&quot;806&quot; data-origin-width=&quot;1397&quot; data-origin-height=&quot;806&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;한 달, 좋았다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 다음에 또 한다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;한 도시에서 한 달을 사는 것보다는 여러 도시를 떠돌아다니면서 찐 디지털 노마드처럼 해보려고 생각중&lt;/b&gt;입니다 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;(사실 세비야 2주정도 있으니까 질려요...대성당도 처음에 우왕, 했지 그거 뭐 맨날 나가면 거기 있는데 뭐...)&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 대략적인, 아마도 제일 궁금해하실 비용을 오픈해보자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왕복 항공권 96만원&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(복지포인트 만세!)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에어비앤비 숙박 한 달 153만원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하루 식비 평균&amp;nbsp; 6만원 x 30 = 180만원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외 주말 근교 여행하려고 렌트한 거랑 철도비용, 플라멩코 공연 관람같은 여행비용을 대략 30만원 정도로 잡으면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;약 460만원의 비용&lt;/b&gt;을 썼네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고정비인 항공권&amp;amp;숙박을 제외하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식비가 제일 유동적인데 스페인은 보통 한 끼 외식이 20유로 정도라고 보시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(음식이 10 ~ 15유로, 음료가 3~5유로쯤)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;-1.&amp;nbsp; 워케이션 후기보다 더더 중요한 맛집 리스트&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;a href=&quot;https://goo.gl/maps/2h3Mrm9cfuqoqkPn6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cafeter&amp;iacute;a Catunambu&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;츄러스 맛집인데 츄러스보다 맛있는 &lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;&lt;b&gt;Picatostes&lt;/b&gt; 를 꼭 먹어주세요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;델리만쥬처럼 생겼는데, 겉바속촉에 초콜렛 풍덩해서 먹으면 입에서 녹아서 없어집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;여기만 5번 갔음. 제 기준으로 스페인 맛집 1순위(배가 더 고프다 싶으면 이베리코 수육 샌드위치도 같이 먹으면 됩니다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;2. &lt;a href=&quot;https://goo.gl/maps/nih1jujvdNeKQUrx9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Brunch Milk Away&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;아사히볼 맛집. 상큼하고 달달하고 건강한 거 땡길 때는 여기입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;들어가면 사장형이 K-POP 흥얼거리고 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;문 열고 들어갔는데 르세라핌 노래 나와서 어...? 뭐지, 싶었는데 사장님이 한국 노래 흥얼거리고 있음.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;423&quot; data-origin-height=&quot;353&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cq9QAW/btsoyYyghxQ/8MrqDMekEQnXyKws546g7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cq9QAW/btsoyYyghxQ/8MrqDMekEQnXyKws546g7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cq9QAW/btsoyYyghxQ/8MrqDMekEQnXyKws546g7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcq9QAW%2FbtsoyYyghxQ%2F8MrqDMekEQnXyKws546g7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;290&quot; height=&quot;242&quot; data-origin-width=&quot;423&quot; data-origin-height=&quot;353&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;아이돌 중심의 노래가 들려서 내가 유럽인지 성수동인지 헷갈리는데 메뉴판엔 영어와 스페인어가 있는 어색함을 느끼실 수 있습니다. 아, 물론 아사히볼은 당연히 맛있습니다(사실 이 과일조합에 맛없기도 어렵죠)&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;3. &lt;a href=&quot;https://goo.gl/maps/ggHsn4bNuu33sFsD6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;La Brunilda Tapas&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;세비야 파란대문집, 으로 유명한 곳입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;사실 여기 7년전에 갔던 곳인데 그 사이에 더 유명해져서 이제는 예약없으면 못 들어간다는데...오픈런하면 자리 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt; 크림 리조또, 오리다리 타파스, 문어요리가 맛나고 이베리코 타다끼도 맛있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;(근데 앞뒤오른쪽왼쪽 다 한국인임)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;4. &lt;a href=&quot;https://goo.gl/maps/6M24V5s5KwRRKCZW8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Restaurante Cinco Jotas Sevilla&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;Cinco Jotas, 씽코 호타스...라고 읽는데 5J 라는 마크가 이 가게에 있는데요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;우리나라 소고기에 1++, 1+ 라는 등급 붙이듯이 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;이 5J라는게 스페인에서도 이베리코에 대한 검증마크 같은 거라도 하더라구요&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;(어느 날 만난 미식 여행하시는 동행이 알려주심)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;그래서 여기서는 하몽과 이베리코 스테이크 위주로 드시면 되는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;하몽은 진짜...다른데서 먹었던 짜기만 한 애들이랑은 달라요. 담백한데 적당히 씹을수록 고소하고 사알짝 짭쪼름합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;이베리코는 2인 이상이면 이베리코는 플래터를 주문하면 다양한 부위를 조금씩 드셔보실 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(혼자는 양이 좀 많음. 하지만 전 먹었...뭐...그거 사회가 정한 1인분이지)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mu1UP/btsozR6Kdmh/fdFbe38kkO63NrqBiKRTUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mu1UP/btsozR6Kdmh/fdFbe38kkO63NrqBiKRTUK/img.png&quot; data-alt=&quot;이베리코 500g 따위, 흥.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mu1UP/btsozR6Kdmh/fdFbe38kkO63NrqBiKRTUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmu1UP%2FbtsozR6Kdmh%2FfdFbe38kkO63NrqBiKRTUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;446&quot; height=&quot;253&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;357&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이베리코 500g 따위, 흥.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;5. &lt;a href=&quot;https://goo.gl/maps/dCzsJKe6HSfraB9a9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Burladero Tapas y Tintos&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;아, 여긴 진짜...어느날 만났던 식사 동행분이 다음날에 알려준 곳인데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;처음에 찾아갔더니 5성급 호텔의 1층 식당이라서 1차 당황.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;요리 3개를 주문했는데 한 번에 나오는게 아니라 코스처럼 1개씩 가져다주셔서 2차 당황.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: left;&quot;&gt;하나하나 먹는데 내가 왜 이걸 플레이트(Plate)가 아니라 타파(Tapa)로 시켰을까 싶은 대존맛에 3차 당황.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요리의 맛과 퀄리티로 보면 여기가 1등입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5성 호텔 1층에 있는 식당이라 처음에 잘 못 찾아왔나 싶어서 같이 갔던 동행 3분이랑 서로 눈치보다가 일단 들어갔는데, 다행히 예약없이&amp;amp;숙박객 아니라도 식사는 가능했습니다. 그리고 재밌었던 건 요리 3개를 주문후에 첫 음식이 나왔는데요. 다들 인스타 올려야하니까 요리 다 나올때까지 사진 대기중이었거든요? 근데 아무리 기다려도 다음 요리가 안 나오네요? 설마?? 하다가 우선 먹었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 요리 비우자마자 직원분이 오셔서 맛있었는지 물어보고 다음 요리 가져다 줌.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;287&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CEkYO/btsozjJouka/BQWSMkiRixqQ58GVeS3Mvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CEkYO/btsozjJouka/BQWSMkiRixqQ58GVeS3Mvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CEkYO/btsozjJouka/BQWSMkiRixqQ58GVeS3Mvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCEkYO%2FbtsozjJouka%2FBQWSMkiRixqQ58GVeS3Mvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;287&quot; height=&quot;289&quot; data-origin-width=&quot;287&quot; data-origin-height=&quot;289&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...네, 우리가 주문한 요리에 따라서 순서를 정해서 코스처럼 하나씩 가져다 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맛은 말해뭐해요, 그냥 5성이라는 급으로 요약이 가능합니다.&lt;/p&gt;</description>
      <category>개발/기타(Etc)</category>
      <category>세비야</category>
      <category>스페인</category>
      <category>워케이션</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/127</guid>
      <comments>https://blinders.tistory.com/127#entry127comment</comments>
      <pubDate>Mon, 24 Jul 2023 09:33:06 +0900</pubDate>
    </item>
    <item>
      <title>sticky가 안 되요</title>
      <link>https://blinders.tistory.com/124</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;소소한 트러블 슈팅.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 진행하는 과제에서, 상단에 고정형 Header를 추가해달라는 요건이 있었음.&lt;br /&gt;평소처럼 position:sticky를 사용했는데...적용이 안됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안 될 이유가 당장 없는데 안되서 당황함,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 삽질을 좀 함.&lt;br /&gt;그래서 정리를 함.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위에 overflow에 대한 값이 있으면 적용되지 않음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sticky는 상위 요소 중 하나라도 overflow 속성이 설정되어 있으면 작동하지 않음.&lt;br /&gt;(ex. overflow로 hidden이나 auto, scroll등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sticky는 뷰포트를 기준으로 top등의 값을 해석해서 노출하는 역할인데, 상위의 overflow 설정이 해당&amp;nbsp;영역을 또 다른 스크롤 컨테이너로 해석하기 때문이고, 이로 인해 sticky가 적용되는 뷰포트에 대한 해석이 달라지기 때문. 이번 과제에선 서비스 최상위의 스크롤에 대한 정의값이 있었고 그 아래아래아래아래아래....에 내 코드가 있으니 동작이 씹혔던 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 몇가지 대안이 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. overflow의 기본값(visible) 유지. ...당연하지만 나는 적용 불가함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 상위를 overflow를 clip으로 정의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. height 값 고정&lt;/b&gt; (선정) -&amp;gt; 신규 지면의 최상단 스크롤을 설정하기에 높이가 변경될 일이 없고, 무엇보다 overflow clip을 설정함으로써 발생할 예상치 못 한 사이드 이펙트를 트래킹하기보다는, 이 방법이 좋다고 판단되어 적용함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/트러블 슈팅(Trouble Shooting)</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/124</guid>
      <comments>https://blinders.tistory.com/124#entry124comment</comments>
      <pubDate>Sun, 5 Feb 2023 10:13:44 +0900</pubDate>
    </item>
    <item>
      <title>우리는 글을 왜 써야하는가?</title>
      <link>https://blinders.tistory.com/122</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;[서문]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;지금 쓰고 있는 이 글의 첫 문단이 몇번째인지 모르겠다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓰고 지우고, 지우고 쓰고, 백스페이스 몇 번, ㄱㄴㄷㄹㅏㅑㅓㅕ 몇 번.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;취미는 글쓰기입니다, 라는 멘트를 자기소개때마다 쓴 지도 한참인데 여전히 글을 시작한다는 건 어려운 일이다. 문장 한 줄, 단어 하나에 내가 전달하고자 하는 의미가 바뀔 수 있으니 늘 쓰고 지우기를 반복하게 된다. 물론, 내림받은 것처럼 손가락이 알아서 움직여서 하얀 화면을 가득 채워줄 때도 가끔은 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(올림픽 주기 같은 쿨타임이랄까...?)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 사람들은 주제가 무엇이든 글을 써보라고 하면 일단 어렵다, 라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 일었던 일을 글로 옮기는 것도 어려워서 매일 밤 어떻게 쓸 지 고민하며 펜을 돌렸던 어린 날을, 누구나 겪었을거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 쓰는 나도 그랬던 적이 있다. 내가 오늘 겪은 일을 쓰기가 어려워서, 1장에 22줄이나 그어져 있던 일기장의 페이지를 보며 실증의 한숨을 내쉬었던 적이 있다. 그러다 꾀를 부려 만화 주제가로 일기를 때웠던 적도 있다. 똘기 떵이 호치 새초미 자축인묘...어쩌면 내가 십이간지를 다 외운 건 그때 그 일기 덕일지도 모른다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;562&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHarFY/btrD5M4Wona/EHYC61q056uKTHpskxh72K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHarFY/btrD5M4Wona/EHYC61q056uKTHpskxh72K/img.png&quot; data-alt=&quot;이젠 이거 모르는 사람이 더 많다면서요?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHarFY/btrD5M4Wona/EHYC61q056uKTHpskxh72K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHarFY%2FbtrD5M4Wona%2FEHYC61q056uKTHpskxh72K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;562&quot; height=&quot;290&quot; data-origin-width=&quot;562&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이젠 이거 모르는 사람이 더 많다면서요?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때로부터 시간이 제법 흐른 지금의 나는, 그때만큼 글쓰기를 어려워하진 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓸 때마다 글자수가 오버해서 어느 문단을 어떻게 잘라낼지부터 고민한다. 부적절한 단어를 들어내고 사미(&lt;span style=&quot;color: #000000;&quot;&gt;蛇尾&lt;/span&gt;)는 없는지 살핀다. 조사를 어떻게 바꿔야 문장 흐름이 자연스럽고 나 아닌 다른 사람이 읽었을때 부드러우면서도 내가 전달하고자 하는 의미가 누락없이, 퇴색없이 전달될까를 고민한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...종종 이런 나를 주변 사람들은 외계인 보듯 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;글쓰는게...쉽다고??&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇 년전 모기업에 재직중일때 신입사원 연수의 지도선배를 다녀 온 적이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;약 4주간의 합숙이었고 막바지에는 각자 선배들이 담당한 팀원(신입사원)들에 대한 평가를 써야하는 순간이 오는데, 당시 우리 팀원은 16명이었고 인당 최소 2,000자의 평가서를 써야했다. 그러니까 환산하면 총 32,000자...거기에 한 명 한 명에 대한 평가가 겹치지 않아야하기에 전부 다른 멘트와 표현으로 꾸밈새를 갖춰야했다. 그 소식을 들었을때 같이 선배역할을 했던 동료들은 그걸 어떻게 다 쓰지...? 라는 혼란속에서 나 혼자 태연했던 기억이 난다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;그거, 뭐...그냥 쓰면 되지, 뭘.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글은 쓰면 쓸수록 는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자전거 첫 페달의 굴림, 빙글대는 첫 한 바퀴는 누구에게나 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 계속 밟고 타고 쏘다니다보면 결국 누구나 자전거를 타면서 태연하게 전화를 받는 경지에 이를 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;452&quot; data-origin-height=&quot;417&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czYtYb/btrEcyFmAxt/jbIOVVZJZWamNLckDBm5MK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czYtYb/btrEcyFmAxt/jbIOVVZJZWamNLckDBm5MK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czYtYb/btrEcyFmAxt/jbIOVVZJZWamNLckDBm5MK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczYtYb%2FbtrEcyFmAxt%2FjbIOVVZJZWamNLckDBm5MK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;361&quot; height=&quot;333&quot; data-origin-width=&quot;452&quot; data-origin-height=&quot;417&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;...글은 쓰면 쓸수록 는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 또한 우리가 글을 써야하는 이유 중에 하나다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;[표현 매체로써의 글]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글이 좋은 단초적인 이유는 머릿속에 있는 생각들을 온전하게 담아내기에 너무 좋은 그릇이라서다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때론 궁핍하게 간장종지에 밥 한 숟갈 같은 차림새도 있지만 때때론 상다리가 휘어질만큼 차려진 진수성찬 같은 글이 나오기도하니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 하루에도 수백가지의 표현을 하며 살아간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말로 의견을 나누고 손짓으로 가리키고 &lt;span&gt;표정으로 기분을 전한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFmOpL/btrEgonc8n2/XmgLQ2NgnrgArSRQb3fQcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFmOpL/btrEgonc8n2/XmgLQ2NgnrgArSRQb3fQcK/img.png&quot; data-alt=&quot;봐라,얼마나 진정성있는 표정인가.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFmOpL/btrEgonc8n2/XmgLQ2NgnrgArSRQb3fQcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFmOpL%2FbtrEgonc8n2%2FXmgLQ2NgnrgArSRQb3fQcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;416&quot; height=&quot;356&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;봐라,얼마나 진정성있는 표정인가.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글쓰기 또한 이런 표현의 창구로 우리는 곧잘 쓰곤한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참 잘했어요 도장을 위해 매일 썼던 일기에는 친구와 싸워서 화가 났던 일이 적혀있기도하고 비엔나 소시지가 급식으로 나왔는데 친구보다 2개나 더 받아서 기뻤던 일도 적혀있을거다. 수줍게 건냈던 러브레터에는 설렘 가득한 문장이 담겨있을거고, 중간고사 시험지 여백엔 교수님을 향해 펼친 당찬 기말고사 포부가 적어 뒀을거다. 물론, 기말고사때는 다음 학기에...라는 서두로 시작했겠지만 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 &lt;b&gt;글은 우리가 바라는 의도를 온연하게 풀어낼 수 있는 도구&lt;/b&gt;로 쓰여왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;무엇보다 글은, 언제든 고칠 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말은 뱉으면 담을 수 없고, 표정은 숨기지 못 하며, 손짓은 해버렸고, 시선은 가 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 글은 내가 쓰고 보여주고자 할 때까지 얼마든지 수정 할 수 있다. 마치 퍼즐을 맞추듯이 문단을 자르고 옮기고 단어를 추가하고 읽어보고 지우고, 내 의도와 다르게 오해를 살 법한 문장이나 표현은 없는지 읽는 이가 어떻게 받아들일지를 몇 번이고 고민할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히 퇴고라고 말하는 과정을 수없이 거친 이후에야 탈고해서 세상에 내놓을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당장 이 글의 첫 문장을 되짚어보자.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;'사실, 지금 쓰고 있는 이 글의 첫 문단이 몇번째인지 모르겠다.'&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다, 지금 당신이 읽는 이 글도 내겐 첫 번째 글이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 몇 번이고 쓰고 고치고 도르마무 도르마무한 글이라는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;dormamu.gif&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eeJFYt/btrEcRkn4mv/gWiKI4ynR6Q9RddnWhasNk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eeJFYt/btrEcRkn4mv/gWiKI4ynR6Q9RddnWhasNk/img.gif&quot; data-alt=&quot;그,그만해...!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eeJFYt/btrEcRkn4mv/gWiKI4ynR6Q9RddnWhasNk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/eeJFYt/btrEcRkn4mv/gWiKI4ynR6Q9RddnWhasNk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;200&quot; data-filename=&quot;dormamu.gif&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그,그만해...!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 마침표를 찍은 글은,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 내 머릿속에 있는 것들을 온전하게 풀어내어 올바르게 전달할 수 있는 매체가 되어준다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;[ 코딩 ==&amp;nbsp; 글 ? ]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1656514749149&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;printf(&quot;Hello World\n&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 C언어을 배울때 까만 바탕에 흰 글자로 인사를 짓던 콘솔을 본 기억이 아직도 생생하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 생각한 걸 얘가 보여주고 있잖아? 어쩌면 개발에 흥미를 붙인 건 코딩이란 것과 글을 쓴다는 것이 별반 다르지 않기 때문이지 않을까라는 생각을 나는 종종한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글을 쓴다는 것은 결국 내가 가지고 있는 생각들을 글자들을 사용한 단어, 단어들을 사용한 문장, 문장들이 모인 문단, 문단들이 모인 글이란 형태로 현현해내는 것을 의미한다. 그리고 그 속에 내가 가진 생각, 느낌, 때론 상황을 표현해냄으로써 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;읽는이에게 내 의도를 전달하고자 하는 것이 그 글을 쓰는 목적&lt;/b&gt;&lt;/span&gt;이 된다. 우리가 개발을 하는 것도 한 발자국 물러서 넓게 봤을때 그 본질이 가진 목적을 이루기위해 현현해내는 방식이 글을 쓰는 것과 크게 다르지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;635&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nd7F4/btrF1B6yx4M/U42MOHwQ44Ad1KIKOnC2qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nd7F4/btrF1B6yx4M/U42MOHwQ44Ad1KIKOnC2qk/img.png&quot; data-alt=&quot;흐즈믈르그...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nd7F4/btrF1B6yx4M/U42MOHwQ44Ad1KIKOnC2qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnd7F4%2FbtrF1B6yx4M%2FU42MOHwQ44Ad1KIKOnC2qk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;397&quot; height=&quot;395&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;635&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;흐즈믈르그...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;개발의 본질은, 결국 문제를 해결해내는 것&lt;/b&gt;이라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 주어진 문제를 해결하기 위해 우리는 가장 먼저 생각이라는 걸 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제가 요구하는 게 무엇인지 명확히 분석을 하고 그 요구사항들을 해결할 방법들을 떠올려 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 문제를 해결하는 방법은 결코 1개가 아니다. 수많은 방법 중 어떤 방식이 제일 좋을지에 대한 궁리, 나 아닌 다른 사람들은 어떤 방식으로 이 실타래를 풀어나갔을지에 대한 고민, 꼬리를 물듯 이어진 그 생각의 끝에 다다른 결론을 우리는 코딩이라는 수단을 통해서 머릿속에 있는 로직을 실체로써 구현해낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때론 가볍게 들고다닐 수 있는 포켓북처럼, 때론 너무 무거워서 분권해야하는 전공서적처럼.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때론 몇천줄도 가벼이 넘는 문자로 이루어진 파일들을 통해서 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;591&quot; data-origin-height=&quot;641&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIvwz0/btrFZ1dShiq/SeU4XHtfRVSc0N7SQcl9c1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIvwz0/btrFZ1dShiq/SeU4XHtfRVSc0N7SQcl9c1/img.png&quot; data-alt=&quot;엌....ㅋㅋㅋㅋㅋㅋㅋㅋ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIvwz0/btrFZ1dShiq/SeU4XHtfRVSc0N7SQcl9c1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIvwz0%2FbtrFZ1dShiq%2FSeU4XHtfRVSc0N7SQcl9c1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;418&quot; height=&quot;453&quot; data-origin-width=&quot;591&quot; data-origin-height=&quot;641&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;엌....ㅋㅋㅋㅋㅋㅋㅋㅋ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미국으로 여행을 떠나면 우리는 자연스럽게 한국어가 아닌 영어를 쓴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연하게도 미국에 사는 이들과 이야기하고 소통하기 위해선 그들의 언어를 써야하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언어는 내 머릿속에 떠오른 수많은 생각들을 상대방에게 올곧게 전달하기 위해 쓰이는 도구이고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 미국에서 그들과 대화하기 위해 영어를 사용하듯이 지금 이 글을 읽는 당신은 아마도 컴퓨터와 대화하기 위해 프로그래밍 언어를 사용하고 있을 것이다. 그리고 각각의 언어들이 가진 규격화된 문법을 바탕으로 대화를 할 것이다. 중1때 처음 접했던 영문장 1~5형에서부터 내게 영어라는 벽을 실감하게 해 준 관계대명사와 have+p.p 등과 같이 약속된 규격을 바탕으로 서로 다른 언어를 사용하는 이들은, 서로의 생각들을 교환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;미국인과 대화하기 위해 영어를 쓰듯 우리는 컴퓨터와 대화하기 위해 프로그래밍 언어를 사용하고 있다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;다만 입으로 뱉어내던 언어라는 도구를 활용하는 형태가, 코딩이라는 방식으로 바뀌었을 뿐이다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코딩이라고 명명되어진 이 글에는 우리의 의사를 컴퓨터에게 전달하기 위한 문법이 존재하고, 컴퓨터는 우리가 작성한 문자들을 읽고 해석해서 우리에게 어떤 액션을 보여준다. 때로는 그 액션이 우리가 의도한 방향 일 수도 있고 의도하지 않은 방향 일 수도 있지만, 요점은 우리의 의도가 내포된 글(코딩)이 상대방(컴퓨터)에게 전달된다는데있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 문단의 제목을 Javascript 문법 기준으로 예상해보자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌면 true라는 값을 리턴 할 수도 있지 않을까 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그리고 true라면, &lt;span style=&quot;color: #006dd7;&quot;&gt;사실 여러분은 매일 글을 써왔던 셈&lt;/span&gt;&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글 쓰는 게 어렵다는 생각을 가진 채로 살아왔을지라도, 실상은 매일 글을 쓰고 있었다는 이야기다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌면 여러분은 그 어떤 직업보다도 글쓰기에 최적화되었다고 볼 수 있다. 매일 내 의도를 올곧게 전달하는 방법을 고민하고 정의하고 구현해 온 사람들이기 때문이다. 어렵게 생각 할 필요가 없다. &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;글이라는 건 사실 되게 별 거 없는 거다&lt;/b&gt;&lt;/span&gt;. 손짓 발짓 몸짓과 같이 원초적인 의사전달 수단을 제외하고 우리가 가장 오랫동안 익혀 온 의사전달 수단은 말이고, 그 말을 자음과 모음들로 조합해서 단어로 문장으로 문단의 형태로 써내려간 그림이 글인 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;[ 개발자가 쓰는 글[0]&amp;nbsp; ]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모 프로젝트에 투입되었을 때, 내가 겪었던 황당한 일화 중에 하나는 6연속 점점점 커밋이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Git 이력을 보는데 연속한 6개의 커밋메시지가 '...' 으로 되어있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(거짓말 같겠지만, 나도 이게 거짓말이길 바랬었다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckZ220/btrF0jkL0N7/Nyf0h4PgsT0ZYK3fcTAhA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckZ220/btrF0jkL0N7/Nyf0h4PgsT0ZYK3fcTAhA1/img.png&quot; data-alt=&quot;뭐하시는 분이세요...?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckZ220/btrF0jkL0N7/Nyf0h4PgsT0ZYK3fcTAhA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckZ220%2FbtrF0jkL0N7%2FNyf0h4PgsT0ZYK3fcTAhA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;245&quot; height=&quot;280&quot; data-origin-width=&quot;324&quot; data-origin-height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;뭐하시는 분이세요...?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 커밋이라는 것은, 내가 이번에 개발한 사항들에 대해서 기록의 플래그를 꽂는 것이고 이때 커밋메시지에 어떤 내용을 개발했는지를 요약해서 적어야 한다고 나는 배웠다. 누군가는 메시지 한 줄로 설명되는 만큼이 하나의 커밋이어야한다라고하고, 누군가는 의존성을 가진 개발 일감들을 묶어서 하나의 커밋으로 쳐야한다고, 누군가는 당일에 한 분량만큼을 커밋으로 규정짓기도 한다. 이처럼 &lt;span&gt;커밋의 단위에 대해서는 의견들이 분분하지만 내가 짚고자하는 포인트는 단위가 아니라 커밋메시지에 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;커밋 메시지가 개발한 내용을 내포해야한다라는데는 이견이 없을 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;775&quot; data-origin-height=&quot;92&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ct3uGo/btrF0tBfCdm/jyP8bSKYOfOJsu3GGke331/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ct3uGo/btrF0tBfCdm/jyP8bSKYOfOJsu3GGke331/img.png&quot; data-alt=&quot;커밋 메시지만 보더라도 어떤 개발이 이뤄졌는지 분명하다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ct3uGo/btrF0tBfCdm/jyP8bSKYOfOJsu3GGke331/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fct3uGo%2FbtrF0tBfCdm%2FjyP8bSKYOfOJsu3GGke331%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;775&quot; height=&quot;92&quot; data-origin-width=&quot;775&quot; data-origin-height=&quot;92&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;커밋 메시지만 보더라도 어떤 개발이 이뤄졌는지 분명하다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 그 방식은 다양할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jira 티켓 번호일 수도 있고 한 줄로 요약했을수도 있고, 어떤 방식이건 결국 상관은 없지만 &lt;b&gt;점점점과 같은 무치한 메시지는 결코 남겨서는 안 된다&lt;/b&gt;. 커밋 메시지의 핵심은 이 커밋이 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;무엇을 위해 개발되었는지에 대한 의도를 남겨놓는 것&lt;/b&gt;&lt;/span&gt;이다. 이 의도는 결코 타인만을 위한 것은 아니다. 인간은 망각의 동물이고 지금 내가 개발한 건일지라도, 한 달 뒤의 내가 이 건에 대해 명확히 기억한다는 보장은 누구도 할 수 없다. 그리고 그런 시점이 왔을 때 지금의 의도를 담은 커밋 메시지는 시간이 흐른 뒤의 나에게 분명 도움이 될 것이고, 이는 나와 함께하는 내 팀원들에게도 분명하게 도움이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zIdYd/btrF0tOLs3N/kARDpjx2W0kVLHfgMh2AkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zIdYd/btrF0tOLs3N/kARDpjx2W0kVLHfgMh2AkK/img.png&quot; data-alt=&quot;미래의 나를 위해 커밋을 잘 남겨두자&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zIdYd/btrF0tOLs3N/kARDpjx2W0kVLHfgMh2AkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzIdYd%2FbtrF0tOLs3N%2FkARDpjx2W0kVLHfgMh2AkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;466&quot; height=&quot;264&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;미래의 나를 위해 커밋을 잘 남겨두자&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커밋 메시지도 결국은 글이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 머릿속에 있는 의도를 전달하고자하는 매체로써, 커밋 메시지는 분명하게 쓰이고있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글이라는 대상을 떠올릴때 우리는 곧잘 장문들을 떠올리곤 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수려한 문장들로 그득한 책을 채운 글들만을 글이라고 불리진 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작가 혹은 기자라고 불리는 이들이 퇴고를 반복하며 탈고해내는 잘 완성된 글들.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히 그것들을 떠올리며 글이라고 생각할 수도 있겠지만, 어린 날 숙제라는 떠밀림에 겨우 써야만 했던 매일의 초라한 내 일기장도 엄연히 글이고 전혀 다른 언어지만 컴퓨터와의 대화를 위해 작성하는 코딩 또한 엄연히 글이고, 고작 한 문장으로 끝맺음 짓는 커밋 메시지도 결국은 글인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 모든 것들에 당신의 의도가 담겨져 있을테니까.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;[ 첫 술에 배부르기엔, 내가 좀 많이 먹어요 ]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;코딩도 글이다, 커밋 메시지와 같은 한 문장도 엄염히 글이다.&lt;br /&gt;여러분은 이미 글을 써오고 계셨다,&amp;nbsp;내 의도를 전달하고자 하는 매체로써 쓰이는 것들이 글이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...라고 이 글을 쓰고있지만 사실 쉬운데 쉽지않은 게 글이기도하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(이제와서?)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말을 배우고 써온지는 아주 오래됐지만 말을 잘 한다, 라는 말을 듣는 사람은 많지않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글도 배우고 써온지는 제법 오래됐지만 글을 잘 쓴다, 라는 말을 듣는 사람도 많지않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 읽는 당신에게 글을 써야하는 이유를 설파하고 있지만 첫 문단에서 슬쩍 밑밥을 깔았듯이 나도 빈번히 글이 어렵구나, 라는 생각을 하곤한다. 특히나 모자란 필력을 여실히 느끼며 표현해야하는 생각이나 의도를 제대로 작성하지 못 할 때 그렇게 느끼곤 한다. 그리고 &lt;b&gt;아직 탈고되지 않은 날 것의 이 글 또한 그런 모자란 필력을 여실히 느끼며 키보드를 두드리는 중&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 김에 이 글의 의도를 대놓고 직설해보자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;뭐라도 좋으니 써보셨으면 좋겠다&lt;/span&gt;, 라는 게 이 길고 긴 글의 커밋 메시지&lt;/b&gt;라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;447&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OwKxf/btrF2MfPjJy/oK5fkyTvcwzMazRwteGTQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OwKxf/btrF2MfPjJy/oK5fkyTvcwzMazRwteGTQk/img.png&quot; data-alt=&quot;시작이 제일 어렵다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OwKxf/btrF2MfPjJy/oK5fkyTvcwzMazRwteGTQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOwKxf%2FbtrF2MfPjJy%2FoK5fkyTvcwzMazRwteGTQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;501&quot; height=&quot;283&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;447&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;시작이 제일 어렵다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌면 글이 어렵게 느껴질 수도 있지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌면 그리 어렵지 않을수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작이 반이다라는 옛말에 굳이 기대지않더라도 &lt;b&gt;우리는 이미 예전부터 글을 써오고 있었다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 그 형식이 코딩이었을수도 있고, 짧은 커밋 메시지였을 수도 있고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단톡방에 시시콜콜하게 올라오는 잡설이나 찐친사이에 주고받는 흰소리였을 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 &lt;b&gt;막상 '글을 써보라'라는 판이 깔리면 우리는 '글은 어려워'라는 인식을 하게 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일상에 여실없이 써오던 매체가 글이었음에도 불구하고 그 순간 인식의 허들이 세워져 마냥 어렵게 느껴진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 굳이 잘 쓸 필요는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 작가도, 기자도 아니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그저 당신의 생각과 의도를 잘 녹여내는데만 집중한다면, 그 글의 형태가 어쨋건간에 당신은 글을 쓴 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹 글쓰는 게 무척이나 어렵다면, 몇 번이고 몇 번이고 고쳐쓰면된다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;'사실, 지금 쓰고 있는 이 글의 첫 문단이 몇번째인지 모르겠다.'&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이 글의 첫 문장을 당신이 분명하게 기억했으면 좋겠다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;[ 별첨 : &lt;b&gt;개발자가 쓰는 글.length - 1 &lt;/b&gt;]&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글을 통해서 우리는 지식과 생각을 공유한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 이 글을 보고 있을 당신도, 내 생각을 나로부터 공유받는 중이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NVigl/btrF77KH7Fx/6u6ypCTqqizdVLLDiTR2rK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NVigl/btrF77KH7Fx/6u6ypCTqqizdVLLDiTR2rK/img.png&quot; data-alt=&quot;눈 정화 한 번 하시라고...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NVigl/btrF77KH7Fx/6u6ypCTqqizdVLLDiTR2rK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNVigl%2FbtrF77KH7Fx%2F6u6ypCTqqizdVLLDiTR2rK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;381&quot; height=&quot;267&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;눈 정화 한 번 하시라고...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막상 글을 써볼까, 라는 생각으로 책상 앞에 앉았지만 무얼 써야할 지 갈피를 못 잡으시는 분들께 추천하고픈 건 일기다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 주제로 글을 쓰는 것은 좀 더 어렵기마련이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 일기는 내가 오늘 겪었던 일들이기 때문에 머릿속에 있는 기억들을 그저 꺼내기만하면 되다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거창하지않아도 된다. 버스를 타고 출근했다, 라는 문장을 늘리는 것에서부터 출발하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령 예를 들자면 이렇게.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;버스를 타려면 늘 저 육교를 지나야한다.&lt;br /&gt;&lt;br /&gt;왕복 8차선의 긴 차선들 사이를 오작교처럼 띄워진 저 육교는, 칠월칠석에만 건널 일이 있으면 참 좋겠지만 여지없이 매일, 오늘도 내가 출근하며 건너는 곳이다. 때론 저 멀리 신호에 걸린 버스를 보고 육교위를 뛰어 건넌 적도 있고, 어느때는 센치해져서 육교에 기대 지나가는 차들을 멍하니 바라봤던 적도 있다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;...뭐, 물론 그러다 또 신호에 걸린 버스와 정류장에 길게 늘어선 사람들을 보곤 여유없이 후다닥 뛰어내려가긴했지만.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10글자 남짓의 문장을 머릿속으로 떠올리며 엿가락처럼 늘려보면 글은 어느새 읽을거리만큼이 되어있다. 어릴때는 일기라는 게 아주 쓰기 귀찮은 숙제였지만, 지금 돌이켜보면 왜 일기를 쓰게했는지 알 것만 같다. &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;누군가에게나 매일은 있을 것이기에, 있는 일들을 쓰면 되는 것&lt;/b&gt;&lt;/span&gt;이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;976&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNXRoe/btrF3MOV9iO/WHBShKH6GYpW1Y6oyvsYa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNXRoe/btrF3MOV9iO/WHBShKH6GYpW1Y6oyvsYa1/img.png&quot; data-alt=&quot;아니, 이런 거 말구...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNXRoe/btrF3MOV9iO/WHBShKH6GYpW1Y6oyvsYa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNXRoe%2FbtrF3MOV9iO%2FWHBShKH6GYpW1Y6oyvsYa1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;289&quot; height=&quot;280&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;976&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;아니, 이런 거 말구...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일기라는 주제를 우리가 편히 쓸 수 있는 이유는 매일 내게 쌓인 하루가 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 내 머릿속에 있는 일들을 쓰는 것이기 때문에, 거창하고 깊게 생각 할 필요가 없다는데서 우리는 좀 더 편하게 글을 쓸 수 있는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 일기는 내가 알고 있는 것을 글로 풀어내는 것이고, 이게 익숙해지면 어떤 글이든 편히 쓸 수 있는 여력을 얻게 된다. 가령, 내가 평소에 일을 하면서 느꼈던 것들, 혹은 남들은 모를 것 같은 히든 피스가 아니라도 공유하고픈 것들. 흔히 기술 블로그 라고 부르는 형태로 글을 쓸 수 있는 기반을 다지게 되는 것이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(사실 일기는 이 걸 위한 빌드업이었ㄷ....)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대학생때부터 직장인이 된 지금까지, 나도 개발을 하면서 숱한 글들로부터 도움을 받아왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stack overflow, okky등과 같은 네임드 사이트에서 이름모를 블로그들까지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막힌 벽을 보듯 답답할 때 구글링을 통해 찾았던 그 글들이 없었다면, 마셨던 수백번의 고배에 나는 여기까지 오지 못 했을지도 모른다. 그때 내가 절실히 깨달은 점은 &lt;b&gt;나 혼자 아는 건 쓸모가 없다&lt;/b&gt;라는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFeErM/btrF4vsLLhg/ePUKihHUOMoHf1Dkjvyiyk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFeErM/btrF4vsLLhg/ePUKihHUOMoHf1Dkjvyiyk/img.jpg&quot; data-alt=&quot;여러 사람 괴롭힌 아저씨&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFeErM/btrF4vsLLhg/ePUKihHUOMoHf1Dkjvyiyk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFeErM%2FbtrF4vsLLhg%2FePUKihHUOMoHf1Dkjvyiyk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;422&quot; height=&quot;298&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1448&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;여러 사람 괴롭힌 아저씨&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;페르마의 마지막 정리&lt;/b&gt;&lt;/span&gt;라는 것이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 증명되었지만 수학계에 난제 중에 난제로써 357년만에 증명이 된 논제인데, 이와 관련된 책을 보면 아주 밉쌀스런 인물의 일화가 적혀있다. 그는 뉴욕 지하철역 벽면 한 켠에 이런 문구를 남겼다고 한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;나는 페르마의 마지막 정리를 증명해냈지만...약속시간에 늦어 지하철을 타야하기에 미처 여기에 옮겨적지 못 했다&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논제를 던진 이나, 지하철에 탄 이나 아주 그냥 대환장파티다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페르마는 마지막 정리를 증명한 글을 남기지 않았고, 이 증명은 350여년이 지나서야 영국의 한 수학자에 의해 증명되게 된다&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(정확히는 첫 증명이후 오류가 발견되서 더 걸리긴 했지만...)&lt;/span&gt; 만약 페르마가 그냥 글로 써서 남겨뒀으면 350년이 넘는 시간동안 그 많은 수학자들이 고통받지 않았을 수 있다는 이야기다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;혼자만 알고 있는 지식은 결국 쓸모가 없다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 접했던 수많은 기술 관련 글들을 그들이 공유해주지 않았다면 나를 비롯해 많은 개발자들이 고통속에 끙끙댔을 것이고 어쩌면 우리는 여전히 피쳐 폰의 세상에서 살아가고 있을지도 모른다. 그만큼 내가 아는 것을 남과 함께하는 것은 중요한 거고, 이는 흔히 &lt;b&gt;공유지식&lt;/b&gt;이라는 말로 정의되고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 중심적인 썰로 이야기를 풀고있지만, 이는 단순히 개발에 국한되지는 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;김치찌개가 먹고싶어서 네이버에서 검색해 본 레시피나, 여행지에 대한 정보, 심지어 맛집에 대한 리뷰까지도 내가 알고 있는 것을 남에게 글로써 공유하는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbfKLI/btrF4eESW2a/k7Phi9Rjh3h5oRWLKHEcF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbfKLI/btrF4eESW2a/k7Phi9Rjh3h5oRWLKHEcF0/img.png&quot; data-alt=&quot;22.06.29 ~ 07.10 지금, 도전하세요.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbfKLI/btrF4eESW2a/k7Phi9Rjh3h5oRWLKHEcF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbfKLI%2FbtrF4eESW2a%2Fk7Phi9Rjh3h5oRWLKHEcF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;431&quot; height=&quot;293&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;22.06.29 ~ 07.10 지금, 도전하세요.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나 또한 내가 받은 공유 지식의 도움을 함께하고자 미진하지만 하나씩 둘씩 쓰기 시작했고, 종종 도움이 되었다는 댓글들로 응원해주시는 분들을 보며 하나라도 더 아는 걸 공유하고파지곤했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히 이런 알고 있는 것에 대한 글을 쓸 때 염려하는 건&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 알고 있는 게 틀린 답이면 어쩌지? 라는 걱정일텐데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 또한 그렇게 공유함으로써 내가 잘 못 알고 있던 사실을 바로 잡는 계기가 될 수 있다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(혹은 반박시 니 말 맞음, 같은 치트키는 어떤가)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 옳게 알고 있던 내용이라면, 그걸 모르던 사람에겐 도움이 될 것이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 잘못 알고 있던 내용이라면, 그건 나에게 도움이 될 것이고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서로가 서로에게 아는 것을 공유할 수 있으면서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;누구나 사용해왔기에 언제든 활용할 수 있고 편히 접할 수 있는 매체가 바로 글&lt;/b&gt;인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글이란 것의 허들은 그리 높지않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기역과 니은, 디귿과 리을. 아와 야, 어와 여.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;24개의 자음과 모음을 조합하면 누구나 글을 쓸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 지금의 내가 쓰는 글이라면 초등학생때 썼던 일기보단 잘 쓰지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라는 생각으로 가볍게 시작해보는 건 어떨까, 라는 생각을 하며 길었던 이 글을 맺는다.&lt;/p&gt;</description>
      <category>글, 생각./Essay</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/122</guid>
      <comments>https://blinders.tistory.com/122#entry122comment</comments>
      <pubDate>Wed, 18 May 2022 08:32:32 +0900</pubDate>
    </item>
    <item>
      <title>#6 객체 지도</title>
      <link>https://blinders.tistory.com/121</link>
      <description>&lt;p data-pm-slice=&quot;0 0 []&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;459c10d7a06b&quot; data-ke-size=&quot;size18&quot;&gt;이 글은 &lt;b&gt;객체지향의 사실과 오해&lt;/b&gt; 서적의 사내 스터디를 하며 맡은 챕터를 정리한 내용입니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1 data-pm-slice=&quot;0 0 []&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;459c10d7a06b&quot;&gt;&lt;b&gt;객체 지도&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;4bbe875addc1&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;0. 시작에 앞서서 해보는 6장의 요지&lt;/b&gt;&lt;/h2&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;a0f004a76219&quot; data-ke-size=&quot;size16&quot;&gt;이 챕터에서 말하고자 하는 건,&lt;br /&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;결국 좋은 SW를 만들려면 &amp;lsquo;기능&amp;rsquo;보다는 &amp;lsquo;구조&amp;rsquo;에 중점을 둔 설계를 진행해야 한다는 것&lt;/span&gt;&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;a0f004a76219&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;왜, &lt;b&gt;기능 &amp;lt; 구조&lt;/b&gt;냐면&lt;b&gt;,&lt;/b&gt; SW는 필연적으로 변할 수 밖에 없기 때문입니다.&lt;br /&gt;이 챕터는, &lt;b&gt;유일하게 변하지 않는 것은 모든 것이 변한다는 사실뿐이다&lt;/b&gt;라는 문구로 시작하는데요&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;4634638dae5f&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;4634638dae5f&quot; data-ke-size=&quot;size16&quot;&gt;우리가 만드는 SW도 이와 마찬가지라는거죠.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;4634638dae5f&quot; data-ke-size=&quot;size16&quot;&gt;계속해서 변한다는 겁니다.&lt;br /&gt;단순 버저닝만해도 1.0이 있고 2.0이 있고 2.5도 있을거고,&lt;br /&gt;그 버저닝에 따라 SW&amp;hellip;그러니까 우리가 개발하는 서비스들은 조금씩 때때론 와장창창 변화를 해나가기 때문입니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;4634638dae5f&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;1b5873a48839&quot; data-ke-size=&quot;size16&quot;&gt;왜 변할 수 밖에 없느냐면,&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;1b5873a48839&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;1b5873a48839&quot; data-ke-size=&quot;size16&quot;&gt;때론 사용자의 요구사항일수도 있구요&lt;br /&gt;좀 더 나은 서비스를 제공하고픈 개발자들의 욕심일수도 있구요&lt;br /&gt;어제까지 따라야하던 정책이 갑작스레 변해서일수도 있고&lt;br /&gt;사용하던 기술의 트렌드가 바뀌거나 더 좋은 기술이 나와서일수도 있죠.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;1b5873a48839&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;ce3c430cee47&quot; data-ke-size=&quot;size16&quot;&gt;그리고&lt;span style=&quot;color: #009a87;&quot;&gt; &lt;b&gt;이러한 변화의 중심에서 최대한 안정적이기 위해서는 기능보다는 구조에 최선을 다해서 설계해야한다는 것이 이 챕터의 핵심내용&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;ce3c430cee47&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;73e5e43147f2&quot; data-ke-size=&quot;size16&quot;&gt;여기서 말하는 &amp;lsquo;안정적&amp;rsquo;이라는 의미는 폭풍우가 와도 굳건히 버티는 댐처럼 튼튼함에 중점을 둔 건 아니구요,&lt;br /&gt;&lt;b&gt;지진이 나면 같이 흔들리는 내진설계처럼 변화와 함께 무쌍해질 유연함에 중점을 둔 안정의 의미&lt;/b&gt;를 담고 있습니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;63207b9167c4&quot; data-ke-size=&quot;size16&quot;&gt;즉 한 줄로 요약해보자면, 이겁니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;63207b9167c4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;&amp;ldquo;구조에 중점을 둔 설계를 해라, 그래야 변화에 안정적이고 좋은 SW를 만들 수 있다&amp;rdquo;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;fc0d853cdb7c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이를 설득력있게 전파하고자 이 책은 &amp;lsquo;지도&amp;rsquo;라는 매체를 사용합니다.&lt;br /&gt;그래서 6장의 제목이 &amp;lsquo;객체 지도&amp;rsquo;인 거구요.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;7bf96d30b7a7&quot; data-ke-size=&quot;size16&quot;&gt;어떻게 &amp;lsquo;지도&amp;rsquo;가 좋은 SW 설계에 빗대어졌는지를 차근차근히 풀어보도록 하겠습니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;7bf96d30b7a7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;53080cac0710&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 목적지를 찾아가는 방법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;97cb1c7aa28b&quot; data-ke-size=&quot;size16&quot;&gt;다음 마을로 가야하는데 길을 모를 때 해결 할 수 있는 방안 2가지를 제시합니다&lt;/p&gt;
&lt;blockquote data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;97cb1c7aa28b&quot; data-ke-style=&quot;style2&quot;&gt;1. 길을 아는 사람한테 묻는 것&lt;br /&gt;2. 지도를 보고 길을 찾아가는 방법&lt;/blockquote&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;table&quot; data-prosemirror-content-type=&quot;node&quot; data-prosemirror-initial-todom-render=&quot;true&quot;&gt;
&lt;div data-testid=&quot;table-alignment-container&quot;&gt;
&lt;div data-testid=&quot;table-container&quot; data-layout=&quot;align-start&quot; data-number-column=&quot;false&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;우선 길을 아는 사람한테 묻는 것은&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;552c9d39a513&quot; data-ke-size=&quot;size16&quot;&gt;기능적(functional)이고 해결책 지향적(Solution-directed)인 방법이라고 합니다.&lt;br /&gt;왜냐면 이 방법을 통해서는 내가 가고자하는 &lt;b&gt;목적지를 &lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#ff0000&quot;&gt;가는 방법&amp;rsquo;만&amp;rsquo;&lt;/span&gt;이 해결되기 때문&lt;/b&gt;인데요.&lt;br /&gt;즉, 당장의 1차원적인 해결법 그 이상 그 이하도 아니기 때문입니다.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot; data-media-vc-wrapper=&quot;true&quot;&gt;
&lt;div data-media-vc-wrapper=&quot;true&quot; data-width-type=&quot;pixel&quot; data-width=&quot;547&quot; data-layout=&quot;align-start&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qKN4m/dJMcaco7plk/9O5PvxyFBTDlZtnY8gzuC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qKN4m/dJMcaco7plk/9O5PvxyFBTDlZtnY8gzuC0/img.png&quot; data-alt=&quot;이럴 수도 있잖...아요?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qKN4m/dJMcaco7plk/9O5PvxyFBTDlZtnY8gzuC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqKN4m%2FdJMcaco7plk%2F9O5PvxyFBTDlZtnY8gzuC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;587&quot; height=&quot;264&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이럴 수도 있잖...아요?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;0d4cb9f3345c&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;f7647faac418&quot; data-ke-size=&quot;size16&quot;&gt;반면에 지도를 보고 길을 찾아가는 방법은&lt;br /&gt;구조적(structural)이고 문제 지향적(Problem-directed)인 접근법이라고 합니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;f7647faac418&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;왜냐면 &lt;b&gt;&amp;lsquo;지도&amp;rsquo;라는 매체는 여러 마을의 위치와 각 마을간의 길이 그려져있고,&lt;/b&gt;&lt;br /&gt;&lt;b&gt;이를 바탕으로 &lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#339966&quot;&gt;가야할 길을 찾을 수 있는 &amp;lsquo;구조&amp;rsquo;의 형태를 제공하기 때문&lt;/span&gt;&lt;/b&gt;이죠.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;f7647faac418&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;0e78eb06a799&quot; data-ke-size=&quot;size16&quot;&gt;두 방법 모두 &amp;lsquo;A마을로 가는 길을 찾는다&amp;rsquo;라는 목적 자체는 동일합니다만&lt;br /&gt;각 방법이 가지는 해결 방식을 생각해본다면 지도를 활용해서 길을 찾는 것이 훨씬 범용적이며,&lt;br /&gt;무엇보다 길을 찾고자 하는 문제를 해결하기 위한 요구사항에 변경이 발생하더라도 유연하게 대처할 수 있다는 이점이 있는데요.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;0e78eb06a799&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;7b7537c79f7a&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 누군가가 알려준 길만을 따라 가는데 &lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#ff0000&quot;&gt;절벽에서 다리가 끊어져 있다고 가정&lt;/span&gt;&lt;/b&gt;해봅시다.&lt;br /&gt;그럼 &lt;b&gt;길을 모르는 사용자는 &lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#ff0000&quot;&gt;또&lt;/span&gt; 다른 길을 아는 누군가를 찾아서 길을 물어봐야&lt;/b&gt; 합니다.&lt;br /&gt;당장의 해결에 중점을 둔 기능 중심의 접근법은 범용적이지 않고 재사용이 불가능하며 이런 변경사항들에 취약한 모델을 낳게 되는 것이죠.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;e67c347d4d82&quot; data-ke-size=&quot;size16&quot;&gt;하지만, 지도를 활용하는 사용자는 다시 지도를 꺼내서 다른 길을 찾아가면 됩니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;e67c347d4d82&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;지도에는 &lt;b&gt;길을 찾는데 필요한&lt;/b&gt; &lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;주변 지형들을 추상적으로 표현&lt;/span&gt;&lt;/b&gt;해주고 있기 때문에 사용자는 범용적으로 길을 찾는 문제를 해결해 나갈 수 있는 겁니다. 이를 책에서는 &amp;lsquo;기능&amp;rsquo;에 대한 요구사항이 변경되더라도 지도는 유연하게 대처할 수 있는 구조적 매체가 되어준다는 표현을 합니다.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot; data-media-vc-wrapper=&quot;true&quot;&gt;
&lt;div data-media-vc-wrapper=&quot;true&quot; data-width-type=&quot;pixel&quot; data-width=&quot;850&quot; data-layout=&quot;align-start&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1708&quot; data-origin-height=&quot;970&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bW1zLF/dJMcadnZlGn/44UXBsRqojNRfXa4vKujIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bW1zLF/dJMcadnZlGn/44UXBsRqojNRfXa4vKujIK/img.png&quot; data-alt=&quot;[출처 : 페이스북 - 간장이]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bW1zLF/dJMcadnZlGn/44UXBsRqojNRfXa4vKujIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbW1zLF%2FdJMcadnZlGn%2F44UXBsRqojNRfXa4vKujIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;698&quot; height=&quot;396&quot; data-origin-width=&quot;1708&quot; data-origin-height=&quot;970&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[출처 : 페이스북 - 간장이]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;9e771fc513a2&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;37799587e93e&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 기능과 구조&lt;/b&gt;&lt;/h2&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;c81dc1e541c5&quot; data-ke-size=&quot;size16&quot;&gt;그렇다고해서 &lt;b&gt;기능 중심적 접근법이 잘 못 된 것인가? 라는 질문에는 No 라는 답변&lt;/b&gt;을 합니다.&lt;br /&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;&amp;ldquo;SW가 사용자에게 가치 있는 이유는 사용자가 필요로 하는 기능을 제공하기 때문&amp;rdquo;&lt;/span&gt;&lt;/b&gt;인데요.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;f860c5b55bb0&quot; data-ke-size=&quot;size16&quot;&gt;우리가 만드는 SW(서비스)는 &lt;b&gt;누군가가 &amp;lsquo;사용해 주는 덕분에&amp;rsquo; 의미를 가집니다.&lt;/b&gt;&lt;br /&gt;그리고 &lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;사용자가 사용해주는 이유는, 사용자가 필요로 하는 기능을 가지고 있기 때문&lt;/span&gt;&lt;/b&gt;이죠.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;f860c5b55bb0&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;78c5141bb1ed&quot; data-ke-size=&quot;size16&quot;&gt;하지만, 기능 중심적인 SW는 앞선 예시와 같이 문제를 해결할 수 있는 일차원적 방법은 될 수 있을지라도 훌륭한 방법이라고 하기엔 무리가 있습니다. 책에서는 이를 &lt;b&gt;훌륭한 기능이 훌륭한 SW를 만드는 것은 충분조건이고, 훌륭한 구조는 훌륭한 SW를 만들기 위한 필요조건&lt;/b&gt;이라고 합니다. 그렇기 때문에 훌륭한 SW를 만들기 위해서는 구조적 설계를 기반으로 한 SW를 만들어야 한다는 말인데요. 구조적 설계가 훌륭한 SW를 만들 수 있다는 근거로 &amp;lsquo;변경&amp;rsquo;이라는 키워드를 내세웁니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;78c5141bb1ed&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;78c5141bb1ed&quot; data-ke-size=&quot;size16&quot;&gt;마치, 길을 물어보고 찾아가다가 다리가 끊어져있는 사태를 맞이한 것도 변경인 것이죠.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;78c5141bb1ed&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;c8671e370102&quot; data-ke-size=&quot;size16&quot;&gt;다시 이 챕터의 첫 문장을 기억해볼게요.&lt;br /&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;&amp;ldquo;유일하게 변하지 않는 것은 모든 것이 변한다는 사실뿐이다&amp;rdquo;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;4428a01ad856&quot; data-ke-size=&quot;size16&quot;&gt;사실 아무것도 변경되지 않는다면, 당장의 문제만을 해결하는 것으로 끝이라면, 이 명제는 거짓입니다만...&lt;br /&gt;우리가 개발하고 서비스하는 SW는 계속해서 요구사항이 변경 될 수 밖에 없는 특성을 가지고 있습니다.&lt;br /&gt;(개발자로써 이 점은 매우 고단하지만 흥미롭다고 하네요)&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;4428a01ad856&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;a1457b2d6aaa&quot; data-ke-size=&quot;size16&quot;&gt;그리고 우리는 이런 변화무쌍한 요구사항에 유연하게 대처할 수 있는 SW를 설계해야하고 이때 &lt;b&gt;해법으로 활용되는 것이 구조 중심적인 설계&lt;/b&gt;입니다. 여기서 우리가 주의해야 할 점은, 반드시 요구사항이 변경될 것임을 안다고해서 섣부른 예측을 하면 안 된다는 점인데요.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;f224fb3f9267&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;f224fb3f9267&quot; data-ke-size=&quot;size16&quot;&gt;요구사항이 명확치 않은 개발은 부차적인 일거리들을 만들기 마련이고, 설계만 복잡하게 할 따름입니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;f224fb3f9267&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;f224fb3f9267&quot; data-ke-size=&quot;size16&quot;&gt;우리는 당장 이번 주 토요일의 로또번호조차 알 수 없기 때문에, &lt;b&gt;어떤 요구사항이 어떤 방식으로 어떻게 요청 될 지 알 수 없습니다.&lt;/b&gt;&lt;br /&gt;따라서, &lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;성급하게 변경을 예측하는 것보다는 변경을 수용할 수 있는 선택의 여지를 설계에 마련해두는 것이 좋은 방법&lt;/span&gt;&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;bca05a543ad9&quot; data-ke-size=&quot;size16&quot;&gt;그리고 각각이 분명한 역할과 책임을 가진 객체들을 기반으로 유기적인 구조를 설계한다면, 기능에 대한 요구사항이 변경되더라도 시스템 전체를 뒤엎는 일은 없을 것입니다. 그러기 위해 각 객체는 더 작은 책임을 가진 채 분할되고, 서로간의 메시지를 기반으로 협력관계를 구축함으로써 피해 범위를 최소화해야합니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;bca05a543ad9&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;003706c4278f&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 구조를 중심으로 설계된 &amp;lsquo;객체 지도&amp;rsquo;는 기능을 수용할 수 있는 자리를 내포하고 있습니다.&lt;br /&gt;지도는 그저 추상화된 객체를 표시해주고, &amp;lsquo;길을 찾는다&amp;rsquo;라는 기능은 부차적으로 따라오게 되는 것이죠.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;7d7be7bf302a&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;7d7be7bf302a&quot; data-ke-size=&quot;size16&quot;&gt;그래서 정리하자면, 구조는 사용자나 이해관계자들이 도메인(domain)에 관해 생각하는 개념과 개념들 간의 관계로 표현되며&amp;nbsp;이를 표현하기 위한 기법을 도메인 모델링이라고 합니다.&lt;br /&gt;기능은 사용자의 목표를 만족시키기 위해 책임을 수행하는 시스템의 행위라고 표현 할 수 있으며, 이를 위한 기법을 유스케이스 모델링이라고 합니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;7d7be7bf302a&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;024f1d20c8f8&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 구조&lt;/b&gt;&lt;/h2&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;593514a99fb5&quot; data-ke-size=&quot;size16&quot;&gt;위에서 갑작스레 등장한 도메인이란 키워드에 대해 잠깐 정의하겠습니다.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;table&quot; data-prosemirror-content-type=&quot;node&quot; data-prosemirror-initial-todom-render=&quot;true&quot;&gt;
&lt;div data-testid=&quot;table-alignment-container&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-testid=&quot;table-container&quot; data-layout=&quot;align-start&quot; data-number-column=&quot;false&quot;&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;도메인 : 사용자가 프로그램을 사용하는 대상 분야&lt;b&gt;ex) 은행원은 고객과 계좌 사이의 돈의 흐름일 것이고, &lt;/b&gt;&lt;b&gt;중고 자동차 판매상은 구매하는 자동차와 판매되는 자동차의 교환으로, &lt;/b&gt;&lt;b&gt;게이머는 게임 캐릭터와 몬스터, 파밍하는 아이템간의 관계로 각자의 도메인을 파악할 것.&lt;/b&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;73c7a5416d88&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;모델은 이러한 각 업의 지식을 선택적으로 단순화하고 의식적으로 구조화한 형태를 뜻합니다. &lt;br /&gt;즉, 이 &lt;b&gt;도메인을 위해 필요한 지식만을 재구성한 것.&lt;/b&gt;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;cdad08c959b4&quot; data-ke-size=&quot;size16&quot;&gt;그래서 도메인 모델은 &amp;ldquo;SW가 목적하는 영역내의 개념과 개념간의 관계, 다양한 규칙이나 제약등을 추상화한 것&amp;rdquo;을 뜻하며, 이를 모델링 할 수 있는 가장 유사한 패러다임이 바로 객체지향 패러다임인 것입니다.&lt;/p&gt;
&lt;h3 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;790c95691a4a&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3-1. 표현적 차이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;e18df6b2bc89&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜&lt;/b&gt; 객체지향 패러다임이 도메인 모델을 구현할 수 있는 가장 유사한 패러다임일까요?&lt;br /&gt;이를 설명하기 위해선 연결완전성 또는 &lt;b&gt;표현적 차이&lt;/b&gt; 라는 객체지향의 특성을 이해해야 합니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;b55acd53ccf4&quot; data-ke-size=&quot;size16&quot;&gt;우리는 우리가 이루고자 하는 목적을 위해서 객체를 설계하고 활용합니다.&lt;br /&gt;이때의 객체는 엄밀히 말해서, &lt;b&gt;현실 객체를 그대로 본뜨는 의미에서의 추상화가 아니라, &lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;은유를 기반으로 재창조한 개념&lt;/span&gt;&lt;/b&gt;임을 알아둬야 합니다. 즉, Equal이나 Copy가 아니라는 건데요&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#7a869a&quot;&gt;(=== 도 아니고 == 도 아니고...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;b55acd53ccf4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그렇기 때문에 SW객체는 현실 객체를 토대로 하지만 &lt;b&gt;엄연히 다른 존재&lt;/b&gt;이며,&lt;br /&gt;그 차이에서 오는 의미적 거리를 &amp;lsquo;표현적 차이&amp;rsquo;라고 합니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;6e1b83c5f676&quot; data-ke-size=&quot;size16&quot;&gt;그리고 이 표현적 차이를 발생시키는 은유를 통해, &lt;b&gt;우리가 투영해야 할 대상이 바로 &amp;ldquo;사용자가 도메인에 대해 생각하는 개념들&amp;rdquo;&lt;/b&gt;입니다.&lt;br /&gt;그렇기에 우리가 도메인 모델을 바탕으로 도메인 객체들을 은유해낸다는 것은, &lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;사용자가 생각하고 요구하는 의도대로 동작하는 SW를 모델링한다는 말이 되는 것&lt;/span&gt;&lt;/b&gt;인데요.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot; data-media-vc-wrapper=&quot;true&quot;&gt;
&lt;div data-media-vc-wrapper=&quot;true&quot; data-width-type=&quot;pixel&quot; data-width=&quot;670&quot; data-layout=&quot;align-start&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1340&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yyJWw/dJMcagyf7TQ/JSrumMDnM8dSWIddSO9ep0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yyJWw/dJMcagyf7TQ/JSrumMDnM8dSWIddSO9ep0/img.png&quot; data-alt=&quot;[그림 6.4]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yyJWw/dJMcagyf7TQ/JSrumMDnM8dSWIddSO9ep0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyyJWw%2FdJMcagyf7TQ%2FJSrumMDnM8dSWIddSO9ep0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;580&quot; height=&quot;222&quot; data-origin-width=&quot;1340&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 6.4]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;68e188480a15&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;cb6deefe708f&quot; data-ke-size=&quot;size16&quot;&gt;여기서 우리가 도메인 모델을 기반으로 설계 해야 하는 첫 번째 이유가 나오는데, 바로 쉬운 이해를 위해서입니다.&lt;br /&gt;누가 쉽게 이해 할 수 있냐면, 이 시스템을 개발해야 하는 우리가 도메인을 쉽게 이해할 수 있다는 의미입니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;aebae28d2145&quot; data-ke-size=&quot;size16&quot;&gt;도메인 모델은 위에서 말한 것처럼 &amp;lsquo;사용자가 생각하는 개념들&amp;rsquo;을 도식화해서 코드를 작성하기 때문에,&lt;br /&gt;도메인을 먼저 이해하면 코드를 어떤 구조로써 풀어가야할지에 대한 이해가 훨씬 수월해집니다&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;aebae28d2145&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;a5ca37cf5d5e&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3-2. 도메인 모델은 안정적이다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;d29dcacb2921&quot; data-ke-size=&quot;size16&quot;&gt;도메인 모델을 기반으로 해야하는 두번째 이유는 구조가 상대적으로 안정적이기 때문입니다&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;(사실상 이게 메인 사유)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;74e15d28ffdb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;도메인 모델의 핵심은 &lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;&amp;ldquo;사용자가 도메인을 바라보는 관점을 반영해 SW를 설계하고 구현하는 것&amp;rdquo;&lt;/span&gt;&lt;/b&gt;입니다.&lt;br /&gt;그리고 사용자는 도메인에 대해 가장 깊이 이해하기에, 개념과 개념간의 관계도 가장 잘 알고 있고,&lt;br /&gt;이를 바탕으로 설계된 구조는 변화에 있어서 유연하게 대처할 수 있는 특성을 지니게 되는 것입니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;74e15d28ffdb&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;c77ee98bf9b3&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 기능, 그리고 유스케이스&lt;/b&gt;&lt;/h2&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;7d4a3a45daeb&quot; data-ke-size=&quot;size16&quot;&gt;하지만 도메인 모델이 아무리 중요해도, 이는 이를 바탕으로 개발하는 우리들(개발자)에게 중요한 것이지, 사용자들은 굳이 몰라도 되는 내용들입니다. 운전면허증을 가진 드라이버라고해서 본인들 차에 엔진구조나 서스펜션이 어떤 구조로 이뤄졌는지 알 필요가 없잖아요? 엑셀 밟으면 가고 브레이크 밟으면 서고, 핸들 돌리면 그 방향으로 가고. 그 정도만 알아도 누구나 자동차를 &amp;lsquo;사용&amp;rsquo;할 수 있으니까...&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;7d4a3a45daeb&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;aae6a4bcbfc6&quot; data-ke-size=&quot;size16&quot;&gt;그렇기에 &lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;SW역시 사용자에겐 본인들이 생각한대로 동작하는 기능이 중요&lt;/span&gt;&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;aae6a4bcbfc6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;유스케이스는 여기서 이 기능에 중점을 둔 서술방법입니다. 이 서술이란 표현을 좀 더 쉽게 이해해보자면, 우리는 작가가 되고 막을 올리는 연극(SW)의 시나리오를 작성해보는거라고 생각해도 되는데요. 등장인물(사용자, 액터Actor라고 불리며 행위자라고도 함)이 연기를 펼치기 위해서는 짜여진 시나리오(대본)가 필요하고 그 시나리오를 텍스트로써 서술해보는 것입니다 &lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#7a869a&quot;&gt;(그러다보니 이를 책의 한 켠에선 공학적인 규칙과 원칙을 기반으로 한 변환작업이 아니라, 경험과 상식, 의사소통을 기반으로 한 창조 작업이라고 하고 있습니다)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;aae6a4bcbfc6&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;65225f4eef3b&quot; data-ke-size=&quot;size16&quot;&gt;그래서 액터(Actor, 행위자)는 시스템에게 내가 원하는 기능에 대해 동작해달라고 요구하며 그 기능이 동작하는 흐름을 바탕으로 사용자와 시스템간에 상호작용이 어떻게 이뤄지는지에 대한 이야기를 유스케이스를 가지고 보여줍니다. 그리고 &lt;b&gt;이 흐름은 단일적이며 목적한 &lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;기능을 이루는데 중점&lt;/span&gt;을 두기에 구조보다는 기능에 무게&lt;/b&gt;를 두고있습니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;65225f4eef3b&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;1cb3b287d878&quot; data-ke-size=&quot;size16&quot;&gt;유스케이스의 특성은 아래 5가지로 정리됩니다.&lt;/p&gt;
&lt;blockquote data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;1cb3b287d878&quot; data-ke-style=&quot;style2&quot;&gt;1. 사용자와 시스템 간에 상호작용을 보여주는 &amp;lsquo;텍스트&amp;rsquo;다&lt;br /&gt;2. 하나가 아닌 여러 시나리오의 집합이다(여기서의 시나리오가 기능인 것은 아니다. 기능을 이뤄낼 때 부차적인 사례들.&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;ex. 책에서는 이자액을 계산하는 것이 주기능이며, 이를 위해 &amp;lsquo;당일까지&amp;rsquo;라는 시나리오를 부여할지, 혹은 &amp;lsquo;특정 일자까지&amp;rsquo;라는 시나리오를 부여할 지를 텍스트로 적어두었다.)&lt;br /&gt;3. 단순한 피처 목록과는 다르다. 피쳐 목록이 우리가 개발해야하는 기능 목록이라면 유스케이스는 텍스트로써 풀어서 서술된 사례에 가깝다.&lt;br /&gt;4. 사용자 인터페이스는 굳이 포함하지 않는다&lt;br /&gt;5. 일종의 &amp;lsquo;이야기&amp;rsquo;이기 때문에 시스템 내부 설계에 대한 정보는 포함하지 않는다.&lt;/blockquote&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;table&quot; data-prosemirror-content-type=&quot;node&quot; data-prosemirror-initial-todom-render=&quot;true&quot;&gt;
&lt;div data-testid=&quot;table-alignment-container&quot;&gt;
&lt;div data-testid=&quot;table-container&quot; data-layout=&quot;align-start&quot; data-number-column=&quot;false&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;32802e998fbd&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 합!체!&lt;/b&gt;&lt;/h2&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot; data-media-vc-wrapper=&quot;true&quot;&gt;
&lt;div data-media-vc-wrapper=&quot;true&quot; data-width-type=&quot;pixel&quot; data-width=&quot;450&quot; data-layout=&quot;align-start&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTsumZ/dJMcaaLBEEE/ghV8gOSEbdKQ5gBUqWydS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTsumZ/dJMcaaLBEEE/ghV8gOSEbdKQ5gBUqWydS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTsumZ/dJMcaaLBEEE/ghV8gOSEbdKQ5gBUqWydS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTsumZ%2FdJMcaaLBEEE%2FghV8gOSEbdKQ5gBUqWydS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;467&quot; height=&quot;253&quot; data-origin-width=&quot;882&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;6f26f7e4842c&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;6f26f7e4842c&quot; data-ke-size=&quot;size16&quot;&gt;다시 본론으로 돌아와서, 그래서 왜 객체지향적인 시각을 갖춰야 하는지는 아래 2가지의 이유라고 기억하면 될 것 같습니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;6f26f7e4842c&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;c02b8ab34758&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.&amp;nbsp;SW의 기능은 계속해서 변하기 때문에 불안정&lt;/b&gt;하다.&lt;br /&gt;&lt;b&gt;2. 이 불안정함을 보완하기 위해서 안정적인 도메인 모델을 기반으로 &amp;lsquo;구조&amp;rsquo; 중심적인 설계&lt;/b&gt;를 해야한다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;c02b8ab34758&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;87a30c51fc8e&quot; data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;이 도메인 모델을, &lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;실체화할 때 쓰일 수 있는 패러다임이 객체지향 패러다임&lt;/span&gt;&lt;/b&gt;이기 때문입니다.&lt;br /&gt;그래서 결국은 기능과 구조를 모두 아우르려면 객체지향을 쓸 수 밖에 없다, 라는 맥락인건데요.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;969663955764&quot; data-ke-size=&quot;size16&quot;&gt;이를 책에서는 &lt;b&gt;&amp;ldquo;변경에 유연한 SW를 만들기 위해서는 유스케이스에 정리된 시스템의 기능을 도메인 모델을 기반으로 한 객체들의 책임으로 분배해야 한다&amp;rdquo;&lt;/b&gt;라고 표현하고 있습니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;969663955764&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;b2432f688b8c&quot; data-ke-size=&quot;size16&quot;&gt;이는 1~5 챕터에서부터 이야기해왔던 &lt;b&gt;객체가 가지는 역할과 책임&lt;/b&gt;&lt;br /&gt;그리고 &lt;b&gt;이를 바탕으로 구현된 각 객체들간의 협력&lt;/b&gt;을 통해 우리는 도메인 모델을 도메인 객체로써 구현해야 한다는 것이고,&lt;br /&gt;이때 각 객체가 가지는 책임을 작고 작고 작게 설계함으로써 변경이 발생하더라도 그 &lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;파급효과를 최소화 할 수 있는 구조적 설계&lt;/span&gt;&lt;/b&gt;를 해야 한다는 것이죠.&lt;/p&gt;
&lt;div data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;mediaSingle&quot; data-prosemirror-content-type=&quot;node&quot; data-media-vc-wrapper=&quot;true&quot;&gt;
&lt;div data-media-vc-wrapper=&quot;true&quot; data-width-type=&quot;pixel&quot; data-width=&quot;650&quot; data-layout=&quot;align-start&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jnmjn/dJMcagdZGpp/hZOfXVMsT88RH07lagQ6Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jnmjn/dJMcagdZGpp/hZOfXVMsT88RH07lagQ6Kk/img.png&quot; data-alt=&quot;단리 이자일때는 이랬지만, 복리가 추가된다면 아래와 같다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jnmjn/dJMcagdZGpp/hZOfXVMsT88RH07lagQ6Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJnmjn%2FdJMcagdZGpp%2FhZOfXVMsT88RH07lagQ6Kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;582&quot; height=&quot;293&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;단리 이자일때는 이랬지만, 복리가 추가된다면 아래와 같다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;828&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/laIo4/dJMcajn988s/UTgWhaQvnBV3jbcFecnwJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/laIo4/dJMcajn988s/UTgWhaQvnBV3jbcFecnwJ0/img.png&quot; data-alt=&quot;[이자율 그림 6.11 과 6.13]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/laIo4/dJMcajn988s/UTgWhaQvnBV3jbcFecnwJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlaIo4%2FdJMcajn988s%2FUTgWhaQvnBV3jbcFecnwJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;554&quot; height=&quot;365&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;828&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[이자율 그림 6.11 과 6.13]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;a4dc11a7337e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;f34d72a3203c&quot; data-ke-size=&quot;size16&quot;&gt;위 그림은 최초 개발된 단리 이자 시스템에서 복리가 추가됐을 때의 클래스 다이어그램인데, 각 객체가 가지는 책임을 잘 쪼개놨기 때문에 기능의 요구사항이 변경됐더라도 전체가 격변하는 일 없이 일부 클래스의 변경만으로 요구사항을 충족할 수 있었습니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;eb77634fbaf8&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 객체지향을 베이스로 한 구조적 설계를 위해서는 유스케이스와 도메인 모델이 힘을 합쳐야 한다고 하는데요.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;eb77634fbaf8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;84567d5ff0ad&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;유스케이스를 바탕으로 사용자의 관점에서 시스템의 기능을 작성했을 때 이 기능은 객체가 가질 책임&lt;/span&gt;&lt;/b&gt;이 되어집니다.&lt;br /&gt;시스템이 가지게 될 거대한 책임은, 시스템을 구성하는 객체들이 가진 작은 책임들의 협력관계를 바탕으로 하고, 이 협력관계를 가능케 하는 것이 객체들간에 주고받는 메시지입니다.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;84567d5ff0ad&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;99e244fcd149&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;작은 책임을 가지는 객체들이 메시지를 기반으로 시스템을 구성하게되면, &lt;/b&gt;&lt;b&gt;변경사항이 있더라도 주고받는 메시지 혹은 일부 객체간의 대응관계를 수정하는 일은 발생할 수 있으나 시스템 전부를 갈아엎는 사태는 피할 수 있게 되는 것&lt;/b&gt;이죠.&lt;/p&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;99e244fcd149&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;heading&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;617a892ee3c0&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. 결론&lt;/b&gt;&lt;/h2&gt;
&lt;p data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-local-id=&quot;0cd53127bf91&quot; data-ke-size=&quot;size16&quot;&gt;마지막이니 요약을 해봅시다.&lt;br /&gt;1. SW의 요구사항은 계속해서 변한다&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#7a869a&quot;&gt;(우리는 매일 Commit을 친다)&lt;/span&gt;&lt;br /&gt;2. SW에서 기능은 중요하다.&lt;b&gt;&lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt; 누구에게? 사용자에게.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;3. SW를 개발하는 우리는 사용자가 생각하는대로 기능이 동작하게끔 설계를 해야한다.&lt;br /&gt;4. 하지만 그 &amp;lsquo;기능&amp;rsquo;은 요구사항에 따라 언제든 변할 수 있다.&lt;br /&gt;5. 언제든 변할 수 있는 요구사항에 대처하기 위해 우리는 섣부른 예측보단 유연한 여지를 남겨놓자&lt;br /&gt;6. &lt;b&gt;여지를 남겨둔다는 것은, &lt;span data-prosemirror-mark-name=&quot;textColor&quot; data-prosemirror-content-type=&quot;mark&quot; data-text-custom-color=&quot;#0000ff&quot;&gt;시스템을 이루는 각 객체가 가지는 책임이 미니멀해야하고, 메시지를 기반으로 한 책임 요청이 각 객체간에 이뤄짐으로써 요구사항에 대해 변경하는 대상을 최소화&lt;/span&gt;함을 뜻한다.&lt;/b&gt;&lt;br /&gt;7. 이렇게 구조에 기반한 설계는 내가 가려는 마을이 바뀌거나, 중간에 휴게소에 가고싶거나, 길이 끊어져도 유연하게 목적(다음 마을 도착)을 이룰 수 있게 해준다.&lt;/p&gt;</description>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/121</guid>
      <comments>https://blinders.tistory.com/121#entry121comment</comments>
      <pubDate>Thu, 10 Mar 2022 00:46:44 +0900</pubDate>
    </item>
    <item>
      <title>[도서리뷰] Learning React(러닝 리액트) 2판</title>
      <link>https://blinders.tistory.com/119</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 하던 일을 정리하느라, 너무 바쁜 나날을 보내고 있는데 그 덕에 포스팅 주기가 엿가락처럼 너무 늘어지게 됐네요. 될 수 있으면 1주 1포스팅 정도는 지키고 싶었는데...라는 안타까운 마음을 서두로, 이번 포스팅을 시작해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 도서리뷰도 리액트 책의 리뷰다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;882&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/say5j/btronKt5V10/Mp2pyV9tKXmJzRmOQkB3zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/say5j/btronKt5V10/Mp2pyV9tKXmJzRmOQkB3zk/img.png&quot; data-alt=&quot;내돈내산을 인증하기 위한 사진&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/say5j/btronKt5V10/Mp2pyV9tKXmJzRmOQkB3zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsay5j%2FbtronKt5V10%2FMp2pyV9tKXmJzRmOQkB3zk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;377&quot; height=&quot;360&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;882&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;내돈내산을 인증하기 위한 사진&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일전에 했던 리액트 관련 도서리뷰(&lt;a href=&quot;https://blinders.tistory.com/110?category=1015710&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;생활코딩! 리액트 프로그래밍&lt;/a&gt;)가 입문자를 위한 도서였다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책은 입문자보단 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;한 단계 더 나아간 사람들이 읽기 좋은 도서&lt;/b&gt;&lt;/span&gt;라는 느낌을 강하게 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 왜 한 단계 더 나아간 사람들, 이라는 표현을 썼냐면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책에서 설명하고자 하는 리액트에는 함수형 프로그래밍에 대한 저변이 짙게 깔려있기 때문인데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 책의 목차를 보면, 아래와 같이 초반부를 구성되어있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;01. 리액트 소개&lt;br /&gt;02. 리액트를 위한 자바스크립트&lt;br /&gt;03. 자바스크립트를 활용한 함수형 프로그래밍&lt;br /&gt;04. 리액트의 작동원리&lt;br /&gt;[나머지 중략]&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 이런 기술 서적은 1,2챕터를 활용해서 해당 기술의 소개와 이 기술을 익히는 데 필요한 환경설정, 그리고 베이스 지식을 언급하고 3챕터쯤부터 본격적인 썰을 풀어나가는데, 이 책은 4챕터가 되어서야 주제인 리액트에 대해 설명을 시작한다. 그리고 그 전에 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;챕터 하나를 소모해서 '함수형 프로그래밍'이라는 개념을 먼저 소개&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 따르듯 이 책의 예제들은, class에서만 사용가능한 라이프 사이클 메서드 활용 부분을 제외한다면 모두 function 형태로 정의되고있다&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(물론 코드적으로 function을 썼으니 함수형 프로그래밍이다, 라는 건 아니다. 뭐 그렇다고 또 완전 아닌 건 아니긴 하지만, 아닌 게 아닌 것 같은데 아니지만 아니라고 하기에 뭐한 그런 미묘함이 있다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 덕에 class를 활용해서 리액트를 입문하셨거나 공부하신 분들, 혹은 내가 입문서로 추천했던 &lt;a href=&quot;https://blinders.tistory.com/110&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;생활코딩! 리액트 프로그래밍&lt;/a&gt;으로 발을 들인 사람이라면 내가 지금 리액트를 공부하고 있는 게 맞나? &lt;b&gt;그냥 자바스크립트 공부하는 느낌인데? 싶은 생각이 들수도 있지만...되짚어보면 그런 느낌을 받는게 당연&lt;/b&gt;하다. 프레임워크인 Vue와는 달리, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;리액트는 라이브러리&lt;/b&gt;&lt;/span&gt;이고 어디까지나 우리는 자바스크립트를 기반으로 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;리액트라는 라이브러리를 도구로써 가져다가 활용하는 것이기 때문&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 갑작스레 등장한 함수형 프로그래밍이라는 낯선 개념에 멈칫 할 수도 있다. 리액트도 잘 몰라서 공부하려는 건데, 함수형 프로그래밍이라는 것까지 공부해야하는건가? 라는 생각에 머릿속이 복잡해질수도 있지만 굳이 겁부터 먹을 필요는 없다고 생각한다. 왜냐면 다행히도 이 책은, &lt;b&gt;독자들이 이 낯선 느낌을 받을 걸 예견이라도 한 것처럼 매우 자세히 그리고 매우 단계적으로 설명함으로써 읽는 이의 이해를 충분히 도와주고있기 때문&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 이 책을 보면서, 가장 마음에 들었던 점은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;예제로&lt;/b&gt;&lt;b&gt; 주어진 코드의 흐름을 글로 풀어서 설명해준다는 점&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 관련된 기술서적에서 코드는 필수이지만, 편린같은 코드의 흐름까지 설명해주는 책은 내 기억속을 뒤져봐도 손에 꼽을 정도이기 때문이다. 아, 여기서 내가 언급한 흐름은 Code Flow에 대한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;대부분의 서적은 예제로 사용한 코드의 목적을 설명하는데 중심&lt;/b&gt;을 둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 코드는 무엇을 위해, 어떤 동작을 위해 작성된 코드인지를 설명하고 넘어가기 일쑨데, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이 책은 예제로 활용한 코드의 목적과 더불어서 어떻게 흘러가고 동작하는지, 이 변수는 어떤 역할을 하기 위해 사용되었고 코드가 진행될수록 어떻게 변경되고 활용되는지, 호출된 메서드는 무엇을 위해 정의되었고 어떤 상황에서 쓰이는지에 대한 설명을 일일이 언급하며 물 흐르듯이 글로써 설명&lt;/b&gt;&lt;/span&gt;해주고 있다. 그래서 별도로 코드 해석을 위해 머리를 써가기보다는 자연스레 읽으면서 이해하게 되는 부분이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그덕에 나는 기술서적을 볼 때면 이런 예제코드들마다 필기를 통해 주석을 작성하곤 했는데, 이 책만큼은 그 작업을 최소화 할 수 있었던 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 장점을 설명했으니, 단점도 짚어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;책이 재미가 없다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술서적이 재미까지 있으면 그게 더 이상한 거 아닌가? 라는 생각이 들수도 있겠지만, 이 책은 앞서 말했던 것처럼 상세하고 쉽게 개념과 코드를 설명하고 있지만...&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;그로인해 읽는 사람이 생각하는 여지를 많이 좁히고 있다&lt;/b&gt;&lt;/span&gt;. 어느 정도는 밀당을 통해서 코드와 개념을 글로 접했을 때 이 코드가 어떻게 동작하는지 상상도 해보고, 이 개념이 어떻게 활용될 수 있을 지 혹은 뭐가 다른지에 대한 상상을 부풀릴 수 있어야하는데 &lt;b&gt;단계적으로 잘 짜여진 글을 읽다보면 어느새 챕터를 지나와있다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초반 챕터에서는 이런 장점이 극대화되면서 내용에 대한 이해를 쏙쏙 할 수 있어 좋았지만, 예제가 복잡해지고 개념이 난해해지는 중반부를 넘어가게되면, 책의 내용을 머릿속에 정립한다기보다 단순히 책에 있는 글자를 읽기만 한다는 느낌을 강하게 받았다. 물론, 앞서 말했던 장점마냥 읽기만해도 진도를 뺄 수 있는 건 좋은 점이라고 생각하지만 응용의 영역까지 뻗치고자 한다면 내 것으로 만드는 과정이 있어야 하는데, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;의식적으로 책의 내용을 해석하려 하지않으면 그냥 해일에 쓸리듯이 밀려서 어느새 챕터를 넘긴 느낌에 읽은 지식이 겉도는 느낌&lt;/b&gt;&lt;/span&gt;을 받을 수도 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;아무래도 번역서이다 보니 소소한 오탈자 및 어색한 번역이 왕왕&lt;/b&gt;&lt;/span&gt; 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어, 코드에 Baked Salmon 이라고 값을 표기했는데 다른 부분에서 대뜸 '구운 연어'라는 표현이 있어서 응??? 스러웠던 순간이 종종 있었다. 또 &lt;a href=&quot;https://ko.reactjs.org/docs/error-boundaries.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Error Boundaries&lt;/a&gt;에 대한 표현을 오류 경계라고 직역한 부분도 개인적으론 조금 어색했지만, 이런 부분은 충분히 앞뒤 문맥을 보고 파악 할 수 있는 영역이고, 번역서가 가질 수 밖에 없는 흔한 토픽이기에 책을 보기 전에 미리 알고 계시면 좋을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;그래서, 정리하자면...&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;이 책은 리액트 입문서로는 추천하기 어렵지만, &lt;span style=&quot;color: #009a87;&quot;&gt;두 번째 혹은 세 번째 정도의 책으로는 적당하다는 생각&lt;/span&gt;이든다. 특히나 class가 아니라 function 위주로 리액트를 활용하시려는 분이라면 도움이 많이 될 것 같고, 물 흐르듯이 설명 읽는 걸 좋아하시는 분이라면 금상첨화 일 거다. 더불어 2판으로 개선되서 올해 7월에 나온만큼 최신 리액트 버전에 반영된 내용들과 앞으로의 리액트 방향성에 대한 언급도 주창하고 있으니, 관심있으신 분들은 쏠쏠한 인사이트를 얻을 수도 있을 것 같다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/도서리뷰</category>
      <category>react</category>
      <category>도서리뷰</category>
      <category>리액트</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/119</guid>
      <comments>https://blinders.tistory.com/119#entry119comment</comments>
      <pubDate>Tue, 21 Dec 2021 00:36:21 +0900</pubDate>
    </item>
    <item>
      <title>Vue로 Slide Puzzle 만들기(feat. 개발자가 선배님 결혼식을 축하하는 법)</title>
      <link>https://blinders.tistory.com/117</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20211118_232308_1.gif&quot; data-origin-width=&quot;368&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9OS2g/btrlxfXipFQ/u8SAG8CvWGgn2Xk6Q7l06k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9OS2g/btrlxfXipFQ/u8SAG8CvWGgn2Xk6Q7l06k/img.gif&quot; data-alt=&quot;숨기지 않는 팬심&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9OS2g/btrlxfXipFQ/u8SAG8CvWGgn2Xk6Q7l06k/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/9OS2g/btrlxfXipFQ/u8SAG8CvWGgn2Xk6Q7l06k/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;368&quot; height=&quot;654&quot; data-filename=&quot;20211118_232308_1.gif&quot; data-origin-width=&quot;368&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;숨기지 않는 팬심&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;거두절미하고, 회사 선배의 결혼 게시글을 쓰게되었는데...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 참, 사내 인트라넷에 올리는 거니까 흔히 말하는 &lt;b&gt;회사스럽게 쓸 법도 한데,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B급 갬성글을 좋아하는 나로써는 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;그런 딱딱하고 평범한 게시글은 지양하는 편이다&lt;/b&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로&amp;nbsp;3년전에 한땀한땀 정성스레 썼던 13년지기의 결혼게시글은...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게시판 글 용량초과로 10번이나 Reject 당하고 겨우 올렸던 기억이 있을 정도니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이번에도 노멀한 글은 결코 쓰고 싶지 않았고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러던 차에 예전부터 만들어보고 싶었던 결혼 기념 미니게임을 만들어서 올리면 어떨까, 라는 생각이 들었다(이 생각 들자마자 뭐부터 개발할 지 신나기 시작함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;597&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VPsOl/btrly8JQdP5/1KghMs1nE7z2XEcngk3SA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VPsOl/btrly8JQdP5/1KghMs1nE7z2XEcngk3SA1/img.png&quot; data-alt=&quot;이런 일에 진심인 편.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VPsOl/btrly8JQdP5/1KghMs1nE7z2XEcngk3SA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVPsOl%2Fbtrly8JQdP5%2F1KghMs1nE7z2XEcngk3SA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;321&quot; height=&quot;294&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;597&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이런 일에 진심인 편.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 와중에, 단 한가지 아쉬운 점이라면 결혼식이 토요일이라 통상적으로 수요일에는 결혼게시글을 올려야하는데...게시글을 올려달라는 부탁을 받은게 월요일 오후다보니, &lt;b&gt;만들고 싶었던 욕심만큼의 퀄리티있는 아웃풋을 낼 시간이 없었다&lt;/b&gt;는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 게임 자체는 심플하면서도 일정 수준의 완성도도 놓치고 싶지 않았고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누구나 관심을 가지고 쉽게 해볼법한 게임을 만들어야겠다고 생각했는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째로 떠올랐던 건 예전에 Vue Guide 페이지에 이스터에그로 심어놓은 팩맨이었지만 팩맨에 결혼 축하성 이벤트를 심기엔 애매했고, 두 번째로 떠오른 건 쿠키런 같은 러닝게임이었지만 평일 퇴근 후에 이틀만에 후다닥 해서 만들 수 있을까 싶은 생각에 다음으로 미뤄뒀고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 만들게 된 게, 이번 포스팅의 주제인 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Slide Puzzle&lt;/b&gt;&lt;/span&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G0ZIk/btrlyY8qmgy/kCpZak9s6toaNr1HK9POHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G0ZIk/btrlyY8qmgy/kCpZak9s6toaNr1HK9POHk/img.png&quot; data-alt=&quot;솔직히 이거 안 해 본 사람 없잖아요?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G0ZIk/btrlyY8qmgy/kCpZak9s6toaNr1HK9POHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG0ZIk%2FbtrlyY8qmgy%2FkCpZak9s6toaNr1HK9POHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;325&quot; height=&quot;263&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;솔직히 이거 안 해 본 사람 없잖아요?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 키보드 방향키만 조작하면 되는 쉬운 편의성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 이 게임 안 해 본 사람은 없을 거라는 친근한 접근성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 무엇보다 웨딩 사진을 베이스로 하면 결혼 기념이란 의미에 부합하는 목적성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 그리 많은 시간을 투자하지 않아도 될 것 같다는 판단까지 어우러졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게&amp;nbsp;월요일 퇴근 길 버스에 앉은 나는, 신나는 마음으로 설계를 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;895&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I51yv/btrlzM7JCgD/0g4uXpd9V8ubqGkVG3sfvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I51yv/btrlzM7JCgD/0g4uXpd9V8ubqGkVG3sfvk/img.png&quot; data-alt=&quot;내가 갤노트를 애정하는 이유가 바로 이 기능 때문이지.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I51yv/btrlzM7JCgD/0g4uXpd9V8ubqGkVG3sfvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI51yv%2FbtrlzM7JCgD%2F0g4uXpd9V8ubqGkVG3sfvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;653&quot; height=&quot;572&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;895&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;내가 갤노트를 애정하는 이유가 바로 이 기능 때문이지.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 버스를 타고 우리집까지는 20분 남짓걸리는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주효한 피쳐들은 그 사이에 대략 완성할만큼 Slide Puzzle의 설계는 쉬웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 퍼즐조각(PuzzlePiece.vue)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각각의 퍼즐조각(Puzzle Piece)들은 컴포넌트일 것.&lt;/li&gt;
&lt;li&gt;각 조각들은 본인들의 좌표(top,left)를 가질 것&lt;/li&gt;
&lt;li&gt;본인들이 보여줘야 하는 만큼의 이미지 Split 좌표를 가질 것&lt;/li&gt;
&lt;li&gt;퍼즐 이미지 원형이 변경됨에 따라 변경되야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 퍼즐(Puzzle.vue)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지 원형에 대한 정보를 가질 것&lt;/li&gt;
&lt;li&gt;퍼즐 조각들에 전달할 정보를 가질 것&lt;/li&gt;
&lt;li&gt;키보드 이벤트 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딱 요정도가 시작점이었고, 필요한 파일도 사실상 2개밖에 없었기에 그리 어렵지는 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 개발하다보니 조금 더, 조금 더 욕심이 나는 부분이 있어서 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;아래와 같은 사항들을 추가&lt;/b&gt;&lt;/span&gt;했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1. 퍼즐을 그냥 넘기면 뻔하니, 이전 단계를 풀어야 다음 단계로 넘어갈 수 있게하자.&lt;br /&gt;2. 처음부터 뒤섞인 상태로 보여주니, 풀 수 있게끔 유도하기 위해 원본을 보여주는 힌트를 넣자&lt;br /&gt;3. 배경이 심심하니 blur 처리로 나머지 웨딩 사진을 보여주자&lt;br /&gt;4. 초기에 Random 함수로 퍼즐 조각들을 막 흐트려놓으니 풀리지 않는 Slide Puzzle이 발생된다. 따라서 완성된 형태의 세팅을 한 이후에, 조각들을 섞는 함수를 별도로 셀프 호출하자.&lt;br /&gt;5. 이미지 크기는 w600 x h800 으로 고정(퍼즐 좌표 및 Split 값 제한) =&amp;gt; 차후 개선필요&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과, 본 포스팅의 최상단에 있는 Slide Puzzle 이 완성되었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내 Github의 Page 기능을 통해 배포후 해당 링크를 결혼 게시글에 함께 올릴 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 게시글도 B급 갬성 가득 담아서 웨딩 사진과 적절히 밀당하며 작성했고...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;599&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNueZ0/btrlzOqYJQ0/UffLbO74bCfs4IsAw4OOQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNueZ0/btrlzOqYJQ0/UffLbO74bCfs4IsAw4OOQK/img.png&quot; data-alt=&quot;만족스런 반응에 보람을 200% 느낍니다 &amp;amp;amp;amp;gt;_&amp;amp;amp;amp;lt;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNueZ0/btrlzOqYJQ0/UffLbO74bCfs4IsAw4OOQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNueZ0%2FbtrlzOqYJQ0%2FUffLbO74bCfs4IsAw4OOQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;722&quot; height=&quot;538&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;599&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;만족스런 반응에 보람을 200% 느낍니다 &amp;amp;amp;gt;_&amp;amp;amp;lt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음날 데일리 스크럼시간에 깜짝 공개함으로써 팀원들의 즐거운 피드백과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 같이 일했던 동기로부터 미쳤다라는 찬사(?)도 받을수 있었다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 해당 프로젝트에서 이미지(웨딩사진)들을 아이유 사진으로 변경하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 깃헙에 레파지토리를 별도로 생성해서 올려둔 상태다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간이 나면 차후에 리팩토링도하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발 붙인김에 이런 류의 미니게임도 좀 더 구상해서 미리 만들어두면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 언젠가 지인으로부터 이런 축하 요청이 있을때 쓸 수 있지 않을까? 싶은 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 Github 링크와 Demo 사이트는 아래를 참고해주세요 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/onedayz/vue_slide_puzzle&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Slide Puzzle Github Repository&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://onedayz.github.io/vue_slide_puzzle/#/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Slide Puzzle Demo&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/개발일지</category>
      <category>puzzle</category>
      <category>SlidePuzzle</category>
      <category>Vue</category>
      <category>Vue.js</category>
      <category>게임</category>
      <category>미니게임</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/117</guid>
      <comments>https://blinders.tistory.com/117#entry117comment</comments>
      <pubDate>Fri, 19 Nov 2021 00:09:28 +0900</pubDate>
    </item>
    <item>
      <title>[webpack] you are using the runtime-only build of vue where the template compiler is not available</title>
      <link>https://blinders.tistory.com/116</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue Cli로 개발을 하다보면 가끔 이런 에러를 만나게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;you are using the runtime-only build of vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;965&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bV4JRt/btrkSOFZY7N/GqL3V3GfYrIdpHkLGzI0e0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bV4JRt/btrkSOFZY7N/GqL3V3GfYrIdpHkLGzI0e0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bV4JRt/btrkSOFZY7N/GqL3V3GfYrIdpHkLGzI0e0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbV4JRt%2FbtrkSOFZY7N%2FGqL3V3GfYrIdpHkLGzI0e0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;965&quot; height=&quot;94&quot; data-origin-width=&quot;965&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 에러는 아래처럼&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt; Vue.js에서 동적 컴포넌트를 활용하려 할 때 발생하는 에러&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;pre id=&quot;code_1636941260418&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;component :is=&quot;dynamicComponent&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 Vue Cli의 설정에서, 동적 컴포넌트에 대한 컴파일 기본값이 false 이기 때문에 발생하는 것(&lt;a href=&quot;https://cli.vuejs.org/config/#runtimecompiler&quot;&gt;Vue Cli : runtimeCompiler&lt;/a&gt;)으로써, 해결법은 간단하게 vue.config.js 파일에 runtimeCompiler 옵션을 설정해주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1636941520321&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = {
    runtimeCompiler // 혹은 runtimeCompiler : true
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;추가설명&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확장자가 *.vue인 파일들은, vue-loader에 의해 Javascript로 변환되서 동작한다. 그렇기에 서버가 기동되는 중에도 언제든 바뀔 수 있는 동적 컴포넌트를 활용하고자 할 때는, Runtime 시에 Compiler가 함께 동작하게 해달라는 옵션을 줘야하고, 그게 바로 위에서 설명한 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;runtimeCompiler&lt;/b&gt;&lt;/span&gt;다. 즉, 서버가 동작하는 중(Runtime)에도 언제든 *.vue 파일내의 동적 컴포넌트들이 Javascript 화되서 브라우져가 이해할 수 있게끔 변환(Compiler)을 허용해주는 옵션인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공홈 내용 : &lt;a href=&quot;https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Runtime + Compiler] vs [Runtime-only]&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/트러블 슈팅(Trouble Shooting)</category>
      <category>Runtime</category>
      <category>troubleshooting</category>
      <category>Vue</category>
      <category>webpack</category>
      <category>트러블슈팅</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/116</guid>
      <comments>https://blinders.tistory.com/116#entry116comment</comments>
      <pubDate>Mon, 15 Nov 2021 11:08:50 +0900</pubDate>
    </item>
    <item>
      <title>Bus Factor, 혹은 Truck Number</title>
      <link>https://blinders.tistory.com/115</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;The TruckNumber is the size of the smallest set of people in a project such that, if one of them got hit by a truck, the project would be in trouble.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Many people think this definition is broken; they're right&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;출처 : &lt;a href=&quot;https://wiki.c2.com/?TruckNumber&quot;&gt;https://wiki.c2.com/?TruckNumber&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(오늘도 개인썰로 시작해보는 포스팅)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리 회사엔 Agile Core Team이라는 팀이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 많은 회사에서 채택중인 Agile 방법론에 기초해서 프로젝트를 진행하는 팀이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사내에서 Agile 관련 프로세스의 Core적인 역할도 겸하고 있기에 저런 이름을 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 신입사원들의 입문교육기간 중 현장 체험 1순위로 꼽히는 곳이기도하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 이해 될 법한 표현으론...'&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;SDS에도 이런 곳이?!&lt;/b&gt;&lt;/span&gt;'라고 정의할 수 있을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(실제로 신입사원들이 가장 희망하는 부서라고 들었다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 저 팀엔 Tuesday Talk 이라는 게 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'화요일 이야기'정도로 풀어낼 수 있을 것 같은 의미인데, 그냥 가볍게 이야기하는 자리라고 보면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매주 화요일 점심시간에 어떤 주제에 대해 ACT의 누군가가 발표를 하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;듣고 싶은 사람은 도시락을 테이크 아웃 해와서 먹으면서 듣는거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 적절한 표현을 찾지 못 해서 발표라는 표현을 쓰긴했지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각잡고 오랫동안 철저히 준비하고 딱딱한...그런 자리가 아니라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그저 내가 이런 거 해보니 좀 좋더라, 우리는 이런 거 하고 있다, 최근에 이거 해보고 싶은데 어떠냐, 와 같이 평소에 동료들과 담소하듯 나누던 주제들을 공유하는 자리다. 주제에 제한은 없으며 기술적인 부분이 아니라도 좋다. 뭐, 내 취미가 롱보드라면 스케이트 보드랑 롱보드는 뭐가 다른지, 왜 롱보드를 타게됐는지, 월터의 상상은 현실이 된다에서 나오던 롱보드씬은 나도 솔직히 무섭더라, 라던지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UTHHy/btrkOk5LrPs/QmskLx9rFZyTLjUNDPSE2K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UTHHy/btrkOk5LrPs/QmskLx9rFZyTLjUNDPSE2K/img.gif&quot; data-alt=&quot;월터는 아니지만...롱보드 다운힐 영상은 볼 때마다 대단해보인다. 저걸 어떻게 저러고 내려가......&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UTHHy/btrkOk5LrPs/QmskLx9rFZyTLjUNDPSE2K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/UTHHy/btrkOk5LrPs/QmskLx9rFZyTLjUNDPSE2K/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;320&quot; height=&quot;180&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;월터는 아니지만...롱보드 다운힐 영상은 볼 때마다 대단해보인다. 저걸 어떻게 저러고 내려가......&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너나할 것 없이 화자와 청자가 뒤섞여서 이런저런 소소한 이야기를 하는 자리고, 곁다리로 듣는 사람도 편하게 밥 먹으면서 한 귀로 듣고 한 귀로 흘려도 되는, 그런 이야깃자리다. 나는 ACT 소속은 아니지만, Tuesday Talk은 가벼운 자리니만큼 참가인원에 제한이 없었기에(별도 신청방법이 있는 것도 아니고) 흥미로운 주제가 공지되면 종종 가서 듣곤했는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중에 기억에 남는 주제가 바로 오늘 포스팅 거리인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;Bus Factor&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;혹은&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Truck Number&lt;/b&gt;&lt;/span&gt;라고 불리는 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유럽여행을 하다보면, 장거리 버스를 타는 일이 허다하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때론 이동시간을 줄이고자 8시간 정도 걸리는 슬리핑 버스를 타고 도시에서 도시로, 혹은 나라에서 나라로 이동하곤한다. 보통 그런&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;장거리 이동용 버스에는 총 3명이 하나의 크루&lt;/b&gt;&lt;/span&gt;를 이룬다. 이 셋 중&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;한 명은 당연하게도 버스를 운전&lt;/b&gt;하고 나머지&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;한 명은 운전사의 바로 뒷자리에 앉아서 승객들의 불편사항을 듣고 처리해주거나 안내&lt;/b&gt;를 해주곤한다. 그러니까 각각 운전사 1과 승무원 1인 것이다. 그리고 여기에 나머지 한 명이 추가되는건데...이 사람은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;매우 중요한 역할&lt;/b&gt;을 맡고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;그 역할은 바로 쉬는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥, 쉰다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무것도 하지않고, 쉰다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때로는 잠도 자더라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3명이 하나의 크루인데, 2명은 열일하고 나머지 1명은 쉰다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저렇게 아무것도 하지않는데 왜 3인이 하나의 크루를 구성하는걸까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 사람의 진짜 역할은 그냥 푹~잘 쉬다가&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;현재 운전 중인 버스 기사가 운전을 할 수 없는 상황이 됐을 때, 교대하기 위함&lt;/b&gt;&lt;/span&gt;이다. 즉, 장거리 운전이다보니 현재 운전 중인 사람이 졸릴 수도 있고 화장실이 급할수도있고, 혹은 뭐 다양한 돌발의 변수는 언제든 발생할 수 있기 마련이니까. 그럴때는 대비해서 미리 준비해놓는 예비인력인것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이게 Bus Factor(Truck Number)의 핵심개념을 관통한다고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 당신이 현재 진행중인 프로젝트에서 정말 중요한, 핵심 모듈을 만들고있다고 가정해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 그걸&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;오롯이 당신 혼자 설계하고 개발하고 테스트를 하는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정말 당신말고는 그 모듈에 대해서 아는 팀원이 1명도 없는 상황&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상태를 우리는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Bus Factor가 1&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서의 1은,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이 버스에 몇명이 치이면 해당 프로젝트가 망하는가...에 대한 지수&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ut2u8/btrkSOebhEn/IudcK2umzg2kys3xqpFJX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ut2u8/btrkSOebhEn/IudcK2umzg2kys3xqpFJX1/img.png&quot; data-alt=&quot;사, 살려주세요....&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ut2u8/btrkSOebhEn/IudcK2umzg2kys3xqpFJX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUt2u8%2FbtrkSOebhEn%2FIudcK2umzg2kys3xqpFJX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;398&quot; height=&quot;226&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사, 살려주세요....&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;혼자 모듈을 개발하는 당신이 버스에 치임으로써 해당 프로젝트는 아주 큰 리스크를 맞이하게 된다는 것&lt;/b&gt;이다. 그렇기때문에 너무 당연하게도 우리는 이를 미연에 방지하기위해 여러 대책을 세워둬야 하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령 예를들면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크럼과 같은 활동을 통해 지속적으로 팀원간의 정보를 교류하거나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페어 프로그래밍을 통해서 하나의 피쳐를 둘 이상의 사람이 개발하거나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1인에게 역량이 뛰어나다는 이유로 업무를 과중시키지않거나.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...하지만 이런 대책들을 적으면서도 떠오르는 건, 이렇게 당연해야 할 활동들 혹은 그라운드 룰과 같은 서로간의 약속들이 프로젝트를 진행하다보면 대부분 지켜지지 못 한다는 현실이다. 특히나 여기에는 각자의 입장차도 섞여들어가게 되는데, 프로젝트를 관리하고 인력을 운영해야하는 PM의 입장에서는 하나의 모듈을 개발하는데 2명 이상의 개발자를 투입하고 싶지않을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;&quot;2명이서 2가지의 일을 해야지, 왜 2명이서 1개를 같이 개발하냐?&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 내가 실제로 프로젝트 현장에서 들은 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, 다행히도 그 프로젝트에서는 누구도 버스에 치이지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 나는 겪어보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전배를 통해 이동한 선배의 일감을 온전히 받게 되었을 때.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 선배가 혼자 그 모듈을 개발했을 때.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 모듈에 대한 어떤 문서도 가이드도 설명도 없을 때.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 나는 고작 입사 1년을 막 채운 햇병아리였을때.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;555&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4qlMc/btrkJ7lyY3q/qO9LUTXIcCKKmXJ8fgt5zK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4qlMc/btrkJ7lyY3q/qO9LUTXIcCKKmXJ8fgt5zK/img.png&quot; data-alt=&quot;그래, 확실히 많이 강해지긴했어...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4qlMc/btrkJ7lyY3q/qO9LUTXIcCKKmXJ8fgt5zK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4qlMc%2FbtrkJ7lyY3q%2FqO9LUTXIcCKKmXJ8fgt5zK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;318&quot; height=&quot;330&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;555&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그래, 확실히 많이 강해지긴했어...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 생각해도 아찔하기 그지없는 경험이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 그때 그 고난이 나를 더 단단하게 해 준 건 사실이지만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(요즘도 종종 그 선배와 그 당시 이야기를 할때면 고생한 몫만큼 치킨을 사달라고 하곤한다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Bus Factor 지수는 크면 클수록 좋다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 큰 값은 프로젝트의 리스크가 감소하는 지표로도 충분히 활용될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹여나 내 옆 사람이 버스에 치이더라도, 그 사람이 하던 일은 나와 다른 동료들이 충분히 인지하고 과정을 알아왔던 일이기에 프로젝트의 일정 및 진척도엔 차질이 없을테니까 말이다&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(비유긴 하지만 내 동료가 버스에 치였는데 난 일을 해야하다니...말은 했지만 좀..음...그르네...)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 앞서 말했던 것과 같이 보통의 프로젝트들은,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 내가 지원해왔던 프로젝트들이나 지금 하는 업무들까지도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bus Factor가 2를 넘는 경우보다 1에 가까웠던 적이 훨씬 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 해야 할 일은 많고, 우리는 늘 인력이 없으니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그나마 그동안 내가 현장지원을 하거나 종종 업무를 할 때, 홀로 수행해야 하는 경우들이 있었음에도 불구하고 Bus Factor 지수를 1보다 크게 가져갈 수 있었던 이유는 내가 가진 하나의 습관덕이라고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;데일리 로그(Daily Log)&lt;/b&gt;&lt;/span&gt;, 라고 지칭하고 있는 이 습관은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;일종의 일지(&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot; data-hook=&quot;tip&quot; data-type=&quot;arken&quot; data-lang=&quot;hj&quot;&gt;日&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot; data-hook=&quot;tip&quot; data-type=&quot;arken&quot; data-lang=&quot;hj&quot;&gt;誌&lt;/span&gt;)&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2015년부터 2021년 11월인 오늘까지도 쓴, 내가 거의 매일 쓰고 있는 일지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1wHxf/btrkJmwvxmh/dlRBE3KrrCh6C0RGBmhDq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1wHxf/btrkJmwvxmh/dlRBE3KrrCh6C0RGBmhDq1/img.png&quot; data-alt=&quot;입사했던 2014년의 기록은...SI 프로젝트에서 해제될 당시에 PC 강제 포맷으로 사라졌다ㅠㅠ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1wHxf/btrkJmwvxmh/dlRBE3KrrCh6C0RGBmhDq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1wHxf%2FbtrkJmwvxmh%2FdlRBE3KrrCh6C0RGBmhDq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;611&quot; height=&quot;444&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;입사했던 2014년의 기록은...SI 프로젝트에서 해제될 당시에 PC 강제 포맷으로 사라졌다ㅠㅠ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 출근해서 PC를 켜면, 일단 어제 작성한 데일리 로그파일을 연다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 새 메모장도 하나 연다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 어제 뭘 했고 어디까지했고, 오늘은 뭘 하려고 했는지가 어제 데일리 로그에 남아있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 오늘 연 새 메모장에는 일을 하며 오늘 뭘 했고 어디까지했고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내일 출근해서 무엇부터 할지를 적고서야 퇴근을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 쌓인 7년간의 기록은 내게 정말 많은 도움을 주었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 도움 중에 하나가 바로 Bus Factor 지수를 1보다 높게 올려준 것이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령 예를들어, 작년에 혼자 3개월정도 투입됐던 프로젝트가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 프로젝트의 핸들링은 다른 사업부가 하고, 나는 공통을 잡는 역할로 투입됐었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굉장히 타이트한 일정과 다난한 고객의 요구를 힘겹게 클리어하고 무사히 릴리즈 할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 올해 3월쯤, 그 프로젝트의 PM님이 올해 버전업을 준비하며 인력이 필요하자,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리 부서에 다시 한 번 나를 파견해 줄 수 없는지 요청하셨던 적이 있었는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 타이밍에 나는 규모가 제법 큰 다른 프로젝트를 지원하기로 약속이 되어있었기 때문에 다른 팀원이 해당 프로젝트를 지원하게 되었고, 나는 작년 프로젝트 투입시기에 작성해 둔 데일리 로그를 바탕으로 그 팀원에게 프로젝트의 전반적인 히스토리나 내가 지원했던 내용, 고객의 요청에 따라 변경한 세부사항과 같은 세세한 정보까지 손쉽게 전달할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 내가 이런 데일리 로그를 기록해두지 않았다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혼자 투입되서 반년이상 진행했던 프로젝트이기에 Bus Factor가 1이었을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그랬다면 아마 올해 투입된 팀원은 해당 프로젝트에 대한 세부 정보가 없는채로 투입되었을 것이고, 이는 곧 빠르게 빌드업하며 지원해야 할 프로젝트의 일정에 차질을 빚을 수도 있게되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 3개월의 시간동안 나는 착실하게 데일리 로그를 정리해두었고 그덕에 내가 굳이 가지않더라도...즉, 내가 버스에 치였더라도 다른 팀원이 내가 작성해 둔 데일리 로그를 보고 프로젝트를 무사히 진행할 수 있기 때문에 Bus Factor가 1이 아니었던 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 어쩔 수 없이 일은 많고 사람은 적을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다보면 인력적인 운용부분에서 Bus Factor가 1에 근접할 수도 있지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 말한 것과 같이 굳이 페어 프로그래밍이 아니더라도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일 스크럼을 통해 서로가 하는 업무나 이슈사항등을 공유한다거나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹은 하는 일들에 대한 메모 정도의 기록으로라도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;팀원들과 함께 공유함으로써 우리는 Bus Factor가 1에 가까워지지 않도록 늘 유의&lt;/b&gt;&lt;/span&gt;해야한다.&lt;/p&gt;</description>
      <category>개발/기타(Etc)</category>
      <category>BusFactor</category>
      <category>TruckNumber</category>
      <category>개념</category>
      <category>개발</category>
      <category>생각</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/115</guid>
      <comments>https://blinders.tistory.com/115#entry115comment</comments>
      <pubDate>Sun, 14 Nov 2021 10:11:37 +0900</pubDate>
    </item>
    <item>
      <title>[도서리뷰] 알고리즘 문제 해결 전략</title>
      <link>https://blinders.tistory.com/113</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;언젠가 내가 도서리뷰라는 카테고리를 만들고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'야, 이건 진짜 잘 썼다'싶은 책들을 리뷰하는 때가오면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책은 꼭 리뷰를 쓰고싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 쓰는 오늘의 리뷰,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로그래밍 대회에서 배우는 알고리즘 문제 해결 전략.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;921&quot; width=&quot;403&quot; height=&quot;405&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm0Ls8/btrj870iSQy/ZflaPZf79Ug3sAXApqpepk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm0Ls8/btrj870iSQy/ZflaPZf79Ug3sAXApqpepk/img.png&quot; data-alt=&quot;내 낡은 책장 한 켠, 오래된 도서 2권&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm0Ls8/btrj870iSQy/ZflaPZf79Ug3sAXApqpepk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm0Ls8%2Fbtrj870iSQy%2FZflaPZf79Ug3sAXApqpepk%2Fimg.png&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;921&quot; width=&quot;403&quot; height=&quot;405&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;내 낡은 책장 한 켠, 오래된 도서 2권&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 책은 이미 너무 유명하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굳이 리뷰해야 싶을까? 정도로 이 쪽 업계에선 정평이 난 책이기도하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘을 공부하는 사람들...특히나 최근 개발자 취업에 필수 코스라고 불리는 코딩테스트를 준비하는 이들이라면 누구나 다들 한 번은 이 책의 명성을 들어봤을 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 이 책을 처음 접한 건 한창 알고리즘에 빠져살던 대학교 4학년...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까, 지금의 &lt;b&gt;코딩테스트 광풍이 몰아치기도 이전이었던 2013년&lt;/b&gt;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(라떼는 말이야, 썰을 풀자면...내가 이 책을 공부할때만해도 윗 사진의 가장 우측에 있는 해답 서적같은 건 없었다...책의 연습문제를 정말 쌩으로 다 풀어야했는데...세상 참 좋아졌어, 허허)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;632&quot; width=&quot;442&quot; height=&quot;334&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SlNQY/btrj6dtb95e/ZHx5HNvxL3kM7YjlGFZFVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SlNQY/btrj6dtb95e/ZHx5HNvxL3kM7YjlGFZFVk/img.png&quot; data-alt=&quot;실제로 내가 가지고 있는 건 그 옛날의 2판이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SlNQY/btrj6dtb95e/ZHx5HNvxL3kM7YjlGFZFVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSlNQY%2Fbtrj6dtb95e%2FZHx5HNvxL3kM7YjlGFZFVk%2Fimg.png&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;632&quot; width=&quot;442&quot; height=&quot;334&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실제로 내가 가지고 있는 건 그 옛날의 2판이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터 공학을 전공하면서, 내가 제일 재미를 느꼈던 분야는 알고리즘이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제가 제시되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 해법을 찾기위해 이렇게 저렇게 그렇게 요렇게&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머릿속으로 수십번 시뮬레이션하며 로직을 바꿔보고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;놓친 값의 바운더리는 없는지 꼼꼼히 따져보고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 했는데도 Fail 이 뜨면, 다시 검토해보고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;코드는 거짓말을 하지 않는다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;코드는 갈아엎을수록 깔끔해진다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 2가지 개발지론이 정립 된 것도,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숱한 알고리즘 문제를 풀며 나도 모르는 사이에 체감되었기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그랬던 나이기에 알고리즘을 바탕으로 문제를 푼다는 것은 너무 재밌는 놀이였고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 당시 넥슨에서 주최하는 대학생 알고리즘 경연대회인 NOS나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국정보과학진흥협회(KISE)에서 주관한 알고리즘 경진대회에 참가했던 건&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 과연 동년배들 중에서 어느 정도 레벨인지 가늠해보기 위함이기도했지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무엇보다 알고리즘을 풀어내는 게 재밌기 때문이기도 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;379&quot; width=&quot;461&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nou7n/btrj89qj9Ci/KypL9Y011Emb3D2ksGdV20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nou7n/btrj89qj9Ci/KypL9Y011Emb3D2ksGdV20/img.png&quot; data-alt=&quot;NOS 시상식...수상은 못 했지만 정말 재밌었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nou7n/btrj89qj9Ci/KypL9Y011Emb3D2ksGdV20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNou7n%2Fbtrj89qj9Ci%2FKypL9Y011Emb3D2ksGdV20%2Fimg.png&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;379&quot; width=&quot;461&quot; height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;NOS 시상식...수상은 못 했지만 정말 재밌었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;...오늘도 리뷰보단 잡설이 좀 길어지는 거 같으니,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;본론으로 돌아와서.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, 내가 이 책을 선택하게 된 계기는 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;문제 풀(pool)때문&lt;/b&gt;&lt;/span&gt;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금이야 백준, Leetcode, 프로그래머스등 알고리즘 관련 문제 사이트가 널리고 널렸지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시까지만해도 알고리즘 문제를 구하려면 실제 정보 올림피아드 사이트에 접속해서 한글파일(hwp)로 올려져있던 기출문제를 직접 다운받아서 풀어야했고, 그 문제를 푼다고하더라도 제공되는 테스트 케이스가 없기때문에 스스로 직접 검산해서 유추해내는 수 밖에 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러던 와중에 무려 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;'프로그래밍 대회에서 배우는'이라는 슬로건을 내건 책&lt;/b&gt;&lt;/span&gt;이라니...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 얼마나 기쁘고도, 긴 장마 끝에 해뜰날을 맞이하는 기분이 아닐 수 있겠는가.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 누가 내게 이 책을 알고리즘 책인가요? 라는 질문을 한다면, 나는 알고리즘 책은 아니라고 답을 할 것이다. 이 책은 알고리즘들에 대해서 설명하기보다는, 알고리즘을 필두로 문제를 풀어내는 방법을 설명한 책이라고 할 수 있다. 그러니까 비유하자면, 수학과를 전공한 사람과 수학교육과를 전공한 사람의 차이랄까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수학과는 좀 더 깊이있는 순수 학문을 공부함으로써 본질을 쫓는 느낌이라면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수학교육과는 어떻게해야 수학을 쉽게 사람들한테 설명할 수 있는지를 아는 느낌이니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 이 책은 올림피아드나 기타 대회에서 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;실제로 기출된 문제가 중심&lt;/b&gt;&lt;/span&gt;이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;그 문제를 풀기위해서 우리는 어떻게 접근해야하는지, 어떤 방향성으로 바라봐야하는지를&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;읽는이가 쉽게 이해할 수 있게 길고 긴 글로써 풀어서 설명&lt;/b&gt;&lt;/span&gt;을 해놓았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 우리는 &lt;b&gt;소설의 스토리라인을 따라 읽듯,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;저자의 글을 따라가기만 하면 왜 여기서 이런 방식으로 접근했는지를 쉽게 깨달을 수&lt;/b&gt; 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;440&quot; height=&quot;405&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;782&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eoHKKe/btrj4n4aSII/Pzp1sbWM1LlvQNpr5kGKdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eoHKKe/btrj4n4aSII/Pzp1sbWM1LlvQNpr5kGKdk/img.png&quot; data-alt=&quot;그 옛날 필기의 흔적&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eoHKKe/btrj4n4aSII/Pzp1sbWM1LlvQNpr5kGKdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeoHKKe%2Fbtrj4n4aSII%2FPzp1sbWM1LlvQNpr5kGKdk%2Fimg.png&quot; width=&quot;440&quot; height=&quot;405&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;782&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그 옛날 필기의 흔적&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, 내가 이 책을 제대로 팠던 것도 이미 몇년전의 일이고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코딩 테스트 광풍이라 불리는 요즘 시기엔 더 좋은 책이 나와있을 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이 책은, 앞서 말한 것과 같이 내가 도서 리뷰를 한다면 무조건 해야지, 하고 마음먹게 만들만큼 잘 쓰여진 책이고 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;최소한 내가 알고있는 알고리즘 도서 중에서는 원탑&lt;/b&gt;&lt;/span&gt;이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 2015년경, 우리 회사는 SW 검정이라는 이름으로 알고리즘 등급제도를 도입했고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시에 나는 모든 선배님들한테 이 책을 추천하며 이것만 보면 되신다고 말씀드리기도했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(이제와서 생각해보니, 닭 잡는 일에 소 잡는 칼을 추천한 격이긴하다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점과 추천이유만 적으면 섭하니 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;단점도 좀 적어보자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 이 책을 보며 유일하게 느꼈던 단점은 &lt;b&gt;책의 순서&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책은 총 2권으로 이루어져는데&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(해답서적 제외)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굳이 분류해보자면 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;1권은 알고리즘, 2권은 자료구조&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1권은 시간복잡도부터 설명하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2권은 기초 자료구조부터 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터공학, 혹은 이쪽 계열을 전공한 사람이라면 이 순서에 왜 의문이 드는지 알것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조를 배우지 않았는데 알고리즘을 공부한다?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, 알고리즘을 깨우치면 자료구조는 자연스레 따라오기 마련이지만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 시스템 구축을 건물 짓는 것에 비유해보자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘은 건물을 어떻게 세우는 방식에 대한 로직을 구축하는거고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 그 건물을 세우기 위한 주춧돌, 기둥, 기왓장같은 기본 원료들이기때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자료구조를 모르는 상태로는 알고리즘을 제대로 깨우칠 수가 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 흔히 전공을 공부할 때도 자료구조를 배운 후에 알고리즘으로 넘어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 이 책은 그 순서를 역행하고있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 나도 주변에 이 책을 추천해줄때면 &lt;b&gt;2권부터 사고 1권을 나중에 사는게 좋다, 라고 말을 하는 편&lt;/b&gt;이다. 그리고 2권부터 읽더라도 내용을 이해하는데는 아무런 문제도 없다. 챕터별로 독립된 문제들을 바탕으로 알고리즘을 설명하기에, 책의 순서는 뭘 먼저 보든지 상관이 없기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당신이 만약 자료구조를 명확히 이해하고있다면 1권부터.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기초가 조~금 모자란 것 같다면 2권부터 보는 것을 권장한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;그래서, 정리하자면...&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;실제 프로그래밍 대회에 나왔던 문제를 바탕으로 알고리즘을 설명&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제에 대한 해설이 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;조금은 긴 글로 상세하게 설명되어있지만, 오히려 그 덕에 이해가 더 잘 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자료구조부터 차근히 보고싶은 사람은 2권 -&amp;gt; 1권의 역순으로 책을 보는 걸 권장&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책을 보는 순서는 아무런 상관이 없다. 어차피 핵심은 각 챕터에서 설명하는 '알고리즘'에 맞춰져있기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;당신이 만약 신입으로 코딩테스트를 준비한다면, 이 책을 추천&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교적 문제 난이도가 높은 신입 코딩 테스트에는 이 정도 깊이는 알아야 한다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;당신이 만약 경력으로 코딩테스트를 준비한다면, 이 책을 추천하진 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교적 문제 난이도가 낮은 경력 코딩 테스트에게 이 책은 좀 과하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오히려 Leetcode나 Codility, 프로그래머스를 중심으로 실전형으로 준비하는게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;하지만 당신이 알고리즘을 재밌어하는 개발자라면, 나는 이 책을 추천&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;</description>
      <category>개발/도서리뷰</category>
      <category>Algorithm</category>
      <category>도서리뷰</category>
      <category>알고리즘</category>
      <category>코테</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/113</guid>
      <comments>https://blinders.tistory.com/113#entry113comment</comments>
      <pubDate>Sun, 7 Nov 2021 19:49:22 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js] Vue는 MVVM 패턴과 관련이 없지만</title>
      <link>https://blinders.tistory.com/111</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;특히나 요즘엔, 이상하리만큼 알고있던 지식들의 뿌리를 뒤흔드는 일이 종종 생기는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령 예를들어 일전에 썼던 &lt;a href=&quot;https://blinders.tistory.com/93&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[CSS] opacity는 reflow가 발생 안 한다구요...?&lt;/a&gt;&amp;nbsp;포스팅과 같은 일 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅도 그와 비슷한 맥락에서 출발한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Vue는 MVVM 패턴과 관련이 없다, 라는 명제에 대한 증명&lt;/b&gt;&lt;/span&gt;을 위해서.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0. 이 명제의 출발점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작은 언제나 사소하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kr.vuejs.org/v2/guide/instance.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vue.js 공식 Doc에 나와있는 한 문장&lt;/a&gt;으로부터 출발한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;68&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AJ2KU/btrjlpVwxmo/GbtRcwKNXFWT4UK9nAe7LK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AJ2KU/btrjlpVwxmo/GbtRcwKNXFWT4UK9nAe7LK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AJ2KU/btrjlpVwxmo/GbtRcwKNXFWT4UK9nAe7LK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAJ2KU%2FbtrjlpVwxmo%2FGbtRcwKNXFWT4UK9nAe7LK%2Fimg.png&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;68&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;Vue.js와 MVVM패턴은 관련이 없고, 그저 부분적으로 영감을 받았을 뿐, 이라는 이 문장.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오피셜 사이트에 그렇다는데...뭐, 더 할 말이 있겠는가.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 그렇다면 왜 나는 Vue.js가 MVVM이라고 생각해왔는가.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 그럼 나는 왜 Vue.js는 MVVM 패턴이라고 생각해왔던 걸까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;591&quot; width=&quot;408&quot; height=&quot;512&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl4J5O/btrjlPzEzRC/J3pJXaSaKhmjGK02kVEjjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl4J5O/btrjlPzEzRC/J3pJXaSaKhmjGK02kVEjjk/img.png&quot; data-alt=&quot;2017년에 Vue.js 입문당시 봤던 책에 분명...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl4J5O/btrjlPzEzRC/J3pJXaSaKhmjGK02kVEjjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl4J5O%2FbtrjlPzEzRC%2FJ3pJXaSaKhmjGK02kVEjjk%2Fimg.png&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;591&quot; width=&quot;408&quot; height=&quot;512&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2017년에 Vue.js 입문당시 봤던 책에 분명...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스팅을 작성하며 내 기억에 오류가 있는지를 확인하고자 2017년경, 내가 Vue.js에 입문하며 몇번이고 되짚어봤던 책을 다시 꺼내보게 되었다. 하지만 책에는 분명히 저렇게 정의되어있었다(심지어 형광펜으로 밑줄까지 쫙, 그어놨었다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Vue.js는 전형적인 &lt;span style=&quot;color: #ffffff; background-color: #006dd7;&quot;&gt;MVVM 패턴&lt;/span&gt;을 따르고 있습니다&lt;/b&gt;&lt;/span&gt;, 라고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어 오른쪽 페이지엔 MVVM 패턴 그림까지 넣어서말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그간 프로젝트를 뛰며 Vue.js관련 사내교육까지 진행했던 나였기에, 교육을 준비하는 과정에서도 필요시 자료를 리서치했었고 그때마다 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;대부분의 글들은 아래와 같이 Vue.js는 MVVM을 따르고 있다고 말&lt;/b&gt;&lt;/span&gt;을 하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;908&quot; width=&quot;525&quot; height=&quot;595&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/luUC5/btrjk4X6OK5/CkgeZ1Oz9IOcDhUlMRg6R1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/luUC5/btrjk4X6OK5/CkgeZ1Oz9IOcDhUlMRg6R1/img.png&quot; data-alt=&quot;실제로 구글링을 해보면 대부분의 사람들이 Vue.js는 MVVM 패턴이라고 정의하고 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/luUC5/btrjk4X6OK5/CkgeZ1Oz9IOcDhUlMRg6R1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FluUC5%2Fbtrjk4X6OK5%2FCkgeZ1Oz9IOcDhUlMRg6R1%2Fimg.png&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;908&quot; width=&quot;525&quot; height=&quot;595&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실제로 구글링을 해보면 대부분의 사람들이 Vue.js는 MVVM 패턴이라고 정의하고 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트루먼쇼처럼 누가 나만 속이는 몰래카메라라도 찍고있는걸까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. MVVM은 대체 무엇인가.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;MVVM은 Model-View-ViewModel 로 이어지는 SW 아키텍쳐 패턴&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;219&quot; width=&quot;632&quot; height=&quot;184&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4wzEM/btrjk3yaxye/p5fpKoFgeiGta5vSpRsSK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4wzEM/btrjk3yaxye/p5fpKoFgeiGta5vSpRsSK1/img.png&quot; data-alt=&quot;이미지 출처 : MVVM 패턴, 위키피디아&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4wzEM/btrjk3yaxye/p5fpKoFgeiGta5vSpRsSK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4wzEM%2Fbtrjk3yaxye%2Fp5fpKoFgeiGta5vSpRsSK1%2Fimg.png&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;219&quot; width=&quot;632&quot; height=&quot;184&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지 출처 : MVVM 패턴, 위키피디아&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 형태로 우리가 흔히 화면에 보이는 영역을 담당하는 View와&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 View에서 사용할 데이터를 지지고 볶고 Model과 View 사이를 잇는 ViewModel.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 데이터에 대한 비즈니스 로직과 관리를 담당하는 Model.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 3파트로 나뉘는 이 디자인 패턴은, 어플리케이션에서 활용될 데이터 및 그 데이터를 통해 비즈니스 로직을 실행하는 Model 영역과 흔히 표현(Presentation)을 위해 개발되는 화면의 영역(View, View Model)을 분리함으로써 서로간에 가지고있는 의존성을 줄이는 것을 목표로 설계된 패턴이다. 또한 Presentation 영역에서도 View와 View Model을 한 번 더 분리하였다. View는 우리가 흔히아는 HTML/CSS 영역이라고 보면되고, View Model은 View가 실질적으로 동작하는 논리 및 데이터의 흐름을 담당함으로써, Model과 View를 잇는 역할까지 담당한다. 이를 통해 View는 굳이 Model이 어떤 존재인지 어떤 데이터를 담당하는지 알 필요가 없기에 의존성을 떨쳐낼 수 있고 Model은 View Model에게 데이터의 변경을 알림으로써 View에 반영될 수 있게 데이터 중심으로 로직들이 흘러가게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, View는 직접적으로 데이터를 가지고있는 것이 아니며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Model도 직접적으로 데이터를 View에게 전해주지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 둘은 서로를 모르며 독립적일 수 있는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그저, 그 사이에 있는 View Model이 중재자 역할을 하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Vue는 MVVM과 관련이 없지만, 이라는 명제는 거짓이다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;공홈에 버젓이 쓰여있는데도 불구하고, 이 명제는 왜 &lt;span style=&quot;color: #ffffff; background-color: #ee2323;&quot;&gt;거짓&lt;/span&gt;인가.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 명제의 거짓을 증명할 단서는 바로, 아래 그림이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;294&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JtAiC/btrjnHVsAXM/HEeu36vznF1KVfaRM6BK10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JtAiC/btrjnHVsAXM/HEeu36vznF1KVfaRM6BK10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JtAiC/btrjnHVsAXM/HEeu36vznF1KVfaRM6BK10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJtAiC%2FbtrjnHVsAXM%2FHEeu36vznF1KVfaRM6BK10%2Fimg.png&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;294&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue와 MVVM을 함께 검색해보면, 상당히 많은 사이트에서 본 그림을 활용하고 있는데 이 그림의 출처를 찾아봤더니 &lt;a href=&quot;https://012.vuejs.org/guide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;좀 오래된 Vue.js 사이트&lt;/a&gt;였다. 해당 사이트에 접속해보면, 오른쪽 하단에 이런 툴팁이 나온다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;This is the documentation for an older version of Vue. If you&amp;rsquo;re looking for the current documentation &lt;a href=&quot;https://vuejs.org/v2/guide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;click here.&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 해당 멘트 끝의 click here을 누르면, 현재 최신화되어있는 Vue.js 공식 Doc가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 다시 돌아와서...저 오래된 Vue.js 사이트는&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt; Vue.js 초기에 생성됐던 공식 가이드문서&lt;/b&gt;&lt;/span&gt;이며, &lt;b&gt;최신화된 문서에선 볼 수 없는 Vue.js와 MVVM의 상관관계에 대해서 아주 상세하게 설명&lt;/b&gt;해주고 있다. 우리가 보통 Vue.js를 활용하고자 할 때는 아래코드와 같이 Javascript를 바탕으로 new Vue 키워드를 통해 Vue 인스턴스를 생성해준다&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(Vue 3.x 의 경우 createApp이라는 내장함수를 사용한다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1635591000416&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Vue 2.x
import Vue from 'vue';
import App from 'App.vue';

var vm = new Vue({
  el: '#app',
  components: {App},
  template: '&amp;lt;App/&amp;gt;'
})&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3-1. View Model&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 new Vue를 통해 생성되는 Vue 인스턴스가 위 그림에서 중앙에 놓인 View Model 역할을 하게된다. 이는 앞선 MVVM 패턴의 설명에서 언급했듯이 Model과 View를 동기화(sync)해주는 개체이다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3-2. View&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;View는 실제 화면에 렌더링되는 DOM을 뜻한다.&lt;/p&gt;
&lt;pre id=&quot;code_1635591504338&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vm.$el&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Vue는 생성된 인스턴스에 $el 이라는 내부 프로퍼티를 통해, View 역할을 하는 DOM을 관리(manage)하게된다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이때 View Model 역할을 하는 Vue 인스턴스 내부에는, 활용하는 데이터들에 대해 observe 기능이 걸려있고 이로인해 데이터의 변경시 notify 로직이 발동되며, 해당 로직을 바탕으로 그 데이터를 사용중인 View영역의 DOM이 업데이트되게 되어있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3-3. Model&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Model은 아주 평범한 보통의, Javascript 객체다.&lt;/p&gt;
&lt;pre id=&quot;code_1635591898834&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vm.$data&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드로 설명하자면, 아래와 같이 Vue 파일내에서 data 영역에 정의되는 것들이라고 생각하면된다.&lt;/p&gt;
&lt;pre id=&quot;code_1635592158075&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
export default {
    data(){
        return {
            title : 'Grey',
            team : 'A'
        }
    }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 심플한 JSON 형태를 띄는 Javascript 객체가 Vue의 Model 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 데이터들은 선언과 동시에 observe 기능이 활성화되는데, 이는 실제 내부적으로는 ES5의 getter/setter를 통해 데이터의 변조 및 접근시 별도 로직이 구현되어있기 때문이다. 즉, 데이터가 변경되면, notify 기능을 통해 해당 데이터를 사용하는 View(DOM)을 찾게되고 변경된 데이터를 반영하게 되는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;393&quot; width=&quot;638&quot; height=&quot;330&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMbMoL/btrjkkgoRFL/5sCMtTai5KdXQJomS5edc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMbMoL/btrjkkgoRFL/5sCMtTai5KdXQJomS5edc0/img.png&quot; data-alt=&quot;데이터(Model)에 대한 getter/setter 흐름도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMbMoL/btrjkkgoRFL/5sCMtTai5KdXQJomS5edc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMbMoL%2FbtrjkkgoRFL%2F5sCMtTai5KdXQJomS5edc0%2Fimg.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;393&quot; width=&quot;638&quot; height=&quot;330&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;데이터(Model)에 대한 getter/setter 흐름도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림에서, 우측의 거대 녹색 원형은 하나의 Javascript 객체(Model)이고 좌측 하단의 회색 사각형은 DOM(View) 이다. 녹색의 원은 a라는 이름을 가진 객체고 b는 a의 프로퍼티로써 getter/setter를 통해 observe가 구현된 데이터다(물론, a자체도 getter/setter를 가지고 있지만, 위 그림은 b에 대한 getter/setter를 중심으로 표현되어 있다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 흐름에서 보라색의 b라는 원 내부에 setter로부터 흘러나온 Notify 라는 빨간 화살표를 주목해보자. b라는 데이터가 변경되면, 당연하게도 값을 set해주는 setter가 호출될 것이고, 값을 변경하는 setter가 호출되었기 때문에 해당 데이터를 활용중인 DOM(View)에게도 이 소식을 알려주기 위해 Notify 기능이 호출된 것이다. 그렇게 호출된 Notify의 흐름을 통해 b라는 데이터를 사용중인 Directive v-text를 찾았고 이 값이 변경되면서 실제 DOM이 보여주고있던(Presentation) 화면의 값도 변경되게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 그럼 왜 공식 홈페이지에는 MVVM 패턴과 관련이 없다는건가.&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;68&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AJ2KU/btrjlpVwxmo/GbtRcwKNXFWT4UK9nAe7LK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AJ2KU/btrjlpVwxmo/GbtRcwKNXFWT4UK9nAe7LK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AJ2KU/btrjlpVwxmo/GbtRcwKNXFWT4UK9nAe7LK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAJ2KU%2FbtrjlpVwxmo%2FGbtRcwKNXFWT4UK9nAe7LK%2Fimg.png&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;68&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 포스팅은,&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; Vue.js가 MVVM 패턴과 관련이 없다, 라는 명제가 참이라는 것을 증명하기 위해 출발&lt;/b&gt;&lt;/span&gt;했다. 그동안 나를 비롯한 많은 사람들이 잘 못 알고있었구나, 라는 걸 깨닫고 싶었고...&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;우리가 잘 못 알고있는 거라면 바로잡을 필요가 있으니까.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;찾아보면 찾아볼수록, Vue.js는 MVVM 패턴이라는 확신&lt;/b&gt;&lt;/span&gt;이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히나 지금은 활용치 않는 예전에 쓰인 공식 가이드에는, 대놓고 MVVM 그림에 Vue를 대입시켜 놓을 정도로 상세하게 언급되어있었으니까.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 대체 이게 뭘까, 싶다가...&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;설마하는 생각에 해당 문구의 영문&lt;/b&gt;&lt;/span&gt;을 보았다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Although not strictly associated with the MVVM pattern, Vue&amp;rsquo;s design was partly inspired by it&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수능 외국어 영역 5등급인 내가 해당 영문을 번역 해보자면,&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;(수능때 늘 하던 직역)&lt;br /&gt;비록, 긴밀하게 연관되어 있진않다, MVVM 패턴과는. Vue의 디자인은, 부분적으로 영감을 받았다, 그것에 의해.&lt;br /&gt;&lt;br /&gt;(자연스럽게 표현해보는 의역)&lt;br /&gt;MVVM 패턴과 완벽하게 일치하는 것은 아니지만, Vue는 MVVM 패턴으로부터 기인하여 설계되었습니다.&amp;nbsp;&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...직접 번역해보니 어딘가 싸한 느낌이 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나보다 똑똑한 파파고와 구글은 이렇게 번역&lt;/b&gt;해준다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;파파고 : MVVM 패턴과 엄격하게 연관되어 있지는 않지만, Vue의 디자인은 부분적으로 그것의 영감을 받았다.&lt;br /&gt;구글 : MVVM 패턴과 엄격하게 연관되어 있지는 않지만 Vue의 디자인은 부분적으로 영감을 받았습니다.&lt;b&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;373&quot; width=&quot;372&quot; height=&quot;231&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkq0JL/btrjr1tcf0A/R8344WSA39ouU7KQlYrIWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkq0JL/btrjr1tcf0A/R8344WSA39ouU7KQlYrIWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkq0JL/btrjr1tcf0A/R8344WSA39ouU7KQlYrIWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbkq0JL%2Fbtrjr1tcf0A%2FR8344WSA39ouU7KQlYrIWK%2Fimg.png&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;373&quot; width=&quot;372&quot; height=&quot;231&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;'엄격히'&lt;/b&gt;라는 형용사의 위치선정이 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;그 위치선정에 따른 문장의 의미도 전혀 다르다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;엄격히 MVVM 패턴과 관련이 없지만&lt;/b&gt;&lt;/span&gt; 이라는 말과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;MVVM 패턴과 엄격하게 연관되어 있지는 않지만&lt;/b&gt;&lt;/span&gt; 이라는 말은,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;의미가 다르잖아!!!!!!&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;혹시나 싶어서 중국어도 번역을 해봤다(Vue.js의 창시자, Evan You는 중국인이니까)&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;원문 : 虽然没有完全遵循 MVVM 模型，但是 Vue 的设计也受到了它的启发。&lt;br /&gt;파파고 : 뮤직비디오 VM 모델을 그대로 따르진 않았지만, Vue의 디자인도 힌트를 줬다.&lt;br /&gt;구글 : MVVM 모델을 완전히 따르지는 않지만 Vue의 디자인도 MVVM 모델에서 영감을 받았습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...그렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;엄격히 Vue는 MVVM패턴과 관련이 없지만, 이라는 문장은 잘 못 번역된 것&lt;/b&gt;&lt;/span&gt;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Vue가 MVVM 패턴과 관련이 1도 없다는 게 아니라&lt;/b&gt;&lt;/span&gt;, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;100% 일치하는 것은 아니라는 의미&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(파파고가 MVVM을 '뮤직비디오 VM'이라고 번역한 건 그냥 그러려니 하자)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 결론&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Vue.js는 MVVM 패턴을 활용하는 것이 맞다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;번역이 아주 조금...형용사의 위치가 문제였을 뿐이다ㅠㅠ&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;352&quot; width=&quot;421&quot; height=&quot;238&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sPRzh/btrjJAhfLzB/VXrI9RWVVpXXh54HZNM0R0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sPRzh/btrjJAhfLzB/VXrI9RWVVpXXh54HZNM0R0/img.png&quot; data-alt=&quot;없긴 뭐가 없어...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sPRzh/btrjJAhfLzB/VXrI9RWVVpXXh54HZNM0R0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsPRzh%2FbtrjJAhfLzB%2FVXrI9RWVVpXXh54HZNM0R0%2Fimg.png&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;352&quot; width=&quot;421&quot; height=&quot;238&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;없긴 뭐가 없어...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고사이트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;a href=&quot;https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Model-View-View Model 위키피디아&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;a href=&quot;https://www.slideshare.net/myposter_techtalks/vue-the-progressive-framework&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vue - the Progressive Framework(Slideshare)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;a href=&quot;https://012.vuejs.org/guide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Concepts overview in Vue.js&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>frontend</category>
      <category>Vue</category>
      <category>Vue.js</category>
      <category>개발</category>
      <category>웹</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/111</guid>
      <comments>https://blinders.tistory.com/111#entry111comment</comments>
      <pubDate>Sun, 31 Oct 2021 20:24:18 +0900</pubDate>
    </item>
    <item>
      <title>[도서리뷰] 생활코딩! 리액트 프로그래밍</title>
      <link>https://blinders.tistory.com/110</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;도서리뷰라고 글을 쓰기 시작했는데, 어째 서두가 더 길어져버린 이상한 포스팅&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무언가를 배우고자 할 때, 보통 사람은 2가지로 나뉘게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이론은 일단 겪으면서 깨달아가겠다는 실전파와&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실천에 앞서 이론부터 탄탄해야한다는 이론파.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 중 어떤 방식이 더 뛰어나다, 라고는 누구도 말 할 수 없지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적어도 나한테는 어떤 방식이 더 좋은가, 라고 묻는다면 대답은 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;나는 아래에서부터 쌓아올려가는 이론파기 때문&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌면, 글 쓰는 걸 좋아하고 읽는 걸 좋아하는 성격탓인지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 실전보다는 먼저 읽고 쓰며 머릿속에 넣어둬야 마음이 편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 입장에서, 어떤 이론 혹은 스킬들을 받아들이고 활용해야할때마다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;부딪히는 하나의 벽은 무엇을 보고 공부할 것인가&lt;/b&gt;&lt;/span&gt;, 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹자는 공식 문서, 혹은 공식 사이트를 통해서 배우는 게 가장 옳은 방법이라고도 하지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 활용되는 대부분의 스킬셋은 영문, 혹은 중문이 원문인 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐, 물론 많은 서비스와 기술들이 한글로 번역되어있지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러던차에 대학생때, 어떤 키워드로 접속했는지까지는 기억나지않지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터널 속 한 줄기 빛같은 사이트를 알게됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://opentutorials.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;생활코딩&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 머신러닝에 Git에 뭐, 이것저것 컨텐츠가 많아졌지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시만해도 웹에 대한 내용과 HTML, CSS, Javascript와 같은 컨텐츠 정도가 있었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 컨텐츠들의 퀄리티가 정말 놀라울 정도였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 놀라울 정도, 라는 표현의 관점은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹을 하나도 모르는 '초보자'가 봐도 해당 이론들을 만족스럽게 이해할 수 있다는데에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 본격적인 웹 개발을 회사 입사후에 시작한 나도 해당 사이트에서 많은 도움을 받았고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때론 코딩야학이라는 생활코딩의 초보자 입문과정에 참여하며 역량을 쌓기도 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;237&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjF0pQ/btri0CIhf0G/DXbRRFKPrQ7Fjk1NFnPjp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjF0pQ/btri0CIhf0G/DXbRRFKPrQ7Fjk1NFnPjp0/img.png&quot; data-alt=&quot;혹시나 싶어서 메일보관함을 봤더니 2017년 기록이 남아있었다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjF0pQ/btri0CIhf0G/DXbRRFKPrQ7Fjk1NFnPjp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjF0pQ%2Fbtri0CIhf0G%2FDXbRRFKPrQ7Fjk1NFnPjp0%2Fimg.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;237&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;혹시나 싶어서 메일보관함을 봤더니 2017년 기록이 남아있었다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때론 나도 배운만큼 배풀고픈 마음에,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작년에 생활코딩에서 머신러닝과 관련된 교육 컨텐츠를 제작하면서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;베타테스터를 모집한다는 말에 지원해서 참여하기도 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;287&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2p613/btri5kUE7GH/kGuHC0PXqKLcSs2CIVsqo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2p613/btri5kUE7GH/kGuHC0PXqKLcSs2CIVsqo0/img.png&quot; data-alt=&quot;쌀 한 톨만큼의 도움을 드린 것 같지만, 그래도 기뻤다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2p613/btri5kUE7GH/kGuHC0PXqKLcSs2CIVsqo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2p613%2Fbtri5kUE7GH%2FkGuHC0PXqKLcSs2CIVsqo0%2Fimg.png&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;287&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;쌀 한 톨만큼의 도움을 드린 것 같지만, 그래도 기뻤다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 생활코딩에 대한 찬가 아닌 찬가가 왜 이렇게 길었냐면...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;----------- 여기서부터가 실질적인 도서리뷰입니다. ----------&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에도 홀로 리액트 서적을 보고 공부하거나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내 교육을 다녀오는 등 리액트를 계속해서 간간히 공부는 해왔지만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐랄까, 굳게 하자!!!!! 라고 느낌표를 5개나 박을만큼은 아니었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 리액트를 다시 공부해야겠다!!!!!, 라고 느낌표 5개만큼의 마음을 먹게되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 앞서 말한 것과 같이 나는 이론파이기 때문에, 지식을 습득할 경로가 필요했고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러던 와중에&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt; 생활코딩에서 발간한 리액트 프로그래밍이라는 책&lt;/b&gt;&lt;/span&gt;을 발견하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;572&quot; width=&quot;327&quot; height=&quot;336&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdpjt0/btri8tbIZMc/EIR9sVxanpYrk3MqWZKWC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdpjt0/btri8tbIZMc/EIR9sVxanpYrk3MqWZKWC1/img.png&quot; data-alt=&quot;책상 한 켠에 놓은 내돈내산 내 책&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdpjt0/btri8tbIZMc/EIR9sVxanpYrk3MqWZKWC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbdpjt0%2Fbtri8tbIZMc%2FEIR9sVxanpYrk3MqWZKWC1%2Fimg.png&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;572&quot; width=&quot;327&quot; height=&quot;336&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;책상 한 켠에 놓은 내돈내산 내 책&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;책은, 생각보다 얇다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이는, 입문서이기 때문이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마치 내가 &lt;a href=&quot;https://onedayz.github.io/vue_guide/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vue.js에 대한 가이드를 깃헙 블로그&lt;/a&gt;로 만들었지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 블로그가 Vue.js에 대한 모든 것을 담고있는 것은 아닌것처럼,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책도 적당히 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;입문자를 위해서 알아야 할 요소들만을 집약해놓은 느낌&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;필수로 활용되는 요소들과 내용들은 중심으로 확실하게 정리&lt;/b&gt;&lt;/span&gt;되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(예를들어, react-redux라던가 router라던가 컴포넌트, props, state, 이벤트등등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표지에 적힌 문구는 이렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;'처음 프로그래밍을 시작하는 입문자의 눈높이에 맞춘'&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 포인트는 &lt;b&gt;처음 프로그래밍&lt;/b&gt;이라는 문구다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말그대로, 웹을 모르는 사람...혹은 진짜 프로그래밍을 처음 접하는 사람조차도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책에 서술된 내용을 바탕으로 따라가면 브라우져로 화면을 띄울 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(물론...정말 Javascript를 모르는 사람이라면, 책 내용을 따라 단순 타이핑하는 아무개가 될 뿐이니, 그만큼 책의 내용이 쉽고 초보도 이해하기 쉽다는 의미로 알아두길 바란다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 나는 저번 주인 10/18일에 이 책을 바탕으로 공부를 시작했고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;퇴근 후 하루 2~3시간, 약 7일간의 기간에 책을 완독함은 물론&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일 공부한 내용을 블로그에 비공개로 포스팅하여 직접 정리까지 할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;1222&quot; width=&quot;364&quot; height=&quot;799&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wFgYg/btriZHC3l7t/jPkq95CKZE5PAUwKX9kNW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wFgYg/btriZHC3l7t/jPkq95CKZE5PAUwKX9kNW0/img.png&quot; data-alt=&quot;개발일지에 작성한 비공개 포스팅들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wFgYg/btriZHC3l7t/jPkq95CKZE5PAUwKX9kNW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwFgYg%2FbtriZHC3l7t%2FjPkq95CKZE5PAUwKX9kNW0%2Fimg.png&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;1222&quot; width=&quot;364&quot; height=&quot;799&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개발일지에 작성한 비공개 포스팅들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 이 책이 가지고 있는 장점 중에 하나는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생활코딩이라는 원사이트의 기조에 따라 &lt;b&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=XMb0w3KMw00&amp;amp;list=PLuHgQVnccGMCRv6f8H9K5Xwsdyg4sFSdi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;유튜브로 동영상 강의가 제공&lt;/a&gt;&lt;/b&gt;되고 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;책의 군데군데를 살펴보면 아래와같이 QR코드를 통해서 해당 내용에 연관된 유튜브 영상을 같이 볼 수 있다&lt;/b&gt;&lt;/span&gt;는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;551&quot; width=&quot;317&quot; height=&quot;279&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bk4a8c/btriZG5jhNQ/Fdimj2rBxurgusa9wgPxQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bk4a8c/btriZG5jhNQ/Fdimj2rBxurgusa9wgPxQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bk4a8c/btriZG5jhNQ/Fdimj2rBxurgusa9wgPxQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbk4a8c%2FbtriZG5jhNQ%2FFdimj2rBxurgusa9wgPxQ0%2Fimg.png&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;551&quot; width=&quot;317&quot; height=&quot;279&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유튜브 영상 또한, 다년간에 쌓아올리신 강의 역량덕분이신지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상세하고 어떤 포인트에서 사람들이 헷갈려하고 어떤 내용을 필요로하는지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무나도 잘 알고 있는 상태로 설명을 해주시다보니 &lt;b&gt;고구마없는 드라마를 보는 느낌&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유일한 단점이라면, 영상이 너무 잘 되어있다보니 굳이 책을 사지 않아도 유튜브 영상만으로도 충분할 거 같다는 생각이 들게 만드는데...내 경우엔 영상보단 도서가 더 머릿속에 잘 들어오기에 도서를 구매하게 되었다. &lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(도서리뷰에서 책을 사지 않아도 된다는 신박한 소리를 하고있다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 하나의 장점은, 이 책의 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;발매일이 올해 3월&lt;/b&gt;&lt;/span&gt;이라는거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;404&quot; width=&quot;633&quot; height=&quot;341&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dC9WeA/btri4Y5sQYO/ZVh7TUdwj85cIkbEA5kTRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dC9WeA/btri4Y5sQYO/ZVh7TUdwj85cIkbEA5kTRK/img.png&quot; data-alt=&quot;e-book은 10월, 실물책은 3월.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dC9WeA/btri4Y5sQYO/ZVh7TUdwj85cIkbEA5kTRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdC9WeA%2Fbtri4Y5sQYO%2FZVh7TUdwj85cIkbEA5kTRK%2Fimg.png&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;404&quot; width=&quot;633&quot; height=&quot;341&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;e-book은 10월, 실물책은 3월.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 그런 의문이 들것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;발매일이 3월인게 왜 장점이지?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발매일이 장점이 되는 이유는, 개발 시장은 빠르게 변하고 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배워야 할 스킬셋은 하루가 다르게 늘어나고 변모하고 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중에서도 프론트엔드 개발은 Javascript가 가지는 특유의 확장성과 유연함으로 인해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항간에는 자고 일어나면 새로운 게 나왔다, 라고 할 정도로 더 빠르게 변하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt; 발매일이 최근이라는 건 최신버전의 리액트를 바탕으로 책이 써졌다는 것이기 때문&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로...내가 예전에 구매했던 어느 리액트 서적은,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책의 예제 코드를 비롯해서 깃헙을 통해 제공되던 코드들이 제대로 동작하지 않았던 적이 있었다. 책을 만드는 동안 리액트가 메이져급 버전을 올렸고, 그 과정에서 호환되지 않는 코드를 예제로 넣었기 때문인데...재밌었던 건 챕터 1에서 사용하라던 함수가 챕터 10쯤 갔을때 deprecated 됐으니 쓰지말라고도 되어있기도 했다(그 이후에 해당 내용을 개정해주시기 바란다고 메일을 썼던 기억이 난다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샛길을 돌아 본론으로 돌아와보자면 현재 Yes24 기준으로, 리액트 프로그래밍 서적을 조회해보면 생활코딩에서 나온 이책은 발매일을 기준으로 e-book은 1순위, 실물책은 7순위로 나온다. e-book을 제외한 실물책들 만으로 본다면 2순위에 오르게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2021년 10월 28일일 현재 시점으로, 해당 책에 있는 모든 코드는 내가 직접 작성해서 테스트해보았고 정상적으로 잘 동작하는 것을 확인하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서, 정리하자면...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;내가 이 책을 리액트 입문자들에게 추천하는 이유는 6가지&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 초보자들을 위해 다년간 생활코딩 사이트를 운영한 노하우가 결집된 책&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 리액트를 입문하며 기본적으로 알아야 할 건 다 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 부담없는 두께(사실 책이 너무 두꺼우면 거부감부터 든다)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 비교적 최근에 발매되었기에 리액트 최신버전까지도 OK&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 필요한 항목마다 추가적인 유튜브 영상제공(부담없이 핵심만 설명해주는 짧은 스낵영상)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 입문자를 위한, 정말 상세하고 쉬운 설명.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/도서리뷰</category>
      <category>react</category>
      <category>도서리뷰</category>
      <category>리액트</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/110</guid>
      <comments>https://blinders.tistory.com/110#entry110comment</comments>
      <pubDate>Thu, 28 Oct 2021 13:12:42 +0900</pubDate>
    </item>
    <item>
      <title>[211024] React #07 : redux</title>
      <link>https://blinders.tistory.com/109</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생활코딩! React 리액트 프로그래밍 도서를 바탕으로 React 공부시작.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;이번 진도는 308P ~ 358P.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;목차로는 05. React Redux &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;(챕터 05, 끝)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;&lt;b&gt;1. 개요&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react는 사용자 정의 태그, 즉 컴포넌트를 만들어서 체계적이고 잘 정리된 어플리케이션을 만들 수 있게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux는 컴포넌트에서 활용되는 상태(state)를 중앙에서 관리함으로써 데이터가 우리가 예측하지 않은 형태로 변할 가능성을 낮춰주는 기술이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;307&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3vh6Q/btriJua8rvW/mLrVEYwCpKilKq59MMAPwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3vh6Q/btriJua8rvW/mLrVEYwCpKilKq59MMAPwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3vh6Q/btriJua8rvW/mLrVEYwCpKilKq59MMAPwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3vh6Q%2FbtriJua8rvW%2FmLrVEYwCpKilKq59MMAPwk%2Fimg.png&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;307&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 렌더링에서 한 컴포넌트가 사용중인 state 변경시,&amp;nbsp;sibiling 컴포넌트에게 영향을 끼치려면 위로 올리고 올려서 다시 내려가는 절차를 거쳐야하지만, 해당 state를 store에서 중앙집중 관리할 경우 이와같은 걸치고 걸치는 단계가 필요없게된다. 이를 해결하기 위한 개념이 '구독'인데, 관여하고 싶은 state에 구독(subscribe)을 해놓음으로써 해당 state의 변경시 변경되었다고 알림을 받는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. without Redux&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux를 사용하지 않는다면, 하위 컴포넌트가 가지고 있는 값을 this.props의 이벤트를 통해서 위로 올려주고, 또 올려주고, 또 올려줘서 받은뒤에 다시 props로 내려줘야한다. 예제로 활용된코드의 경우엔, number라는 props를 App &amp;gt; Display Number Root &amp;gt; Display Number 와 같이 3계층을 내려갔으며, Display Number와 Display Number Root에서 각각 onClick 이벤트를 구현하여 다시 올려주곤했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. with Redux&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1635068180374&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install redux&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1635068225955&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {createStore} from &quot;redux&quot;;

export default createStore(function(state, action){
    if(state === undefined){
        return {number:0}
    }
    if(action.type === 'INCREMENT'){
        return {...state, number: state.number + action.size}
    }
    return state;
}, window.__REDUX_DEVTOOLS_EXTENSION__ &amp;amp;&amp;amp; window.__REDUX_DEVTOOLS_EXTENSION__());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;number라는 state를 관리하는 store.js 파일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;createStore의 첫번째 인자로 reducer 함수를 전달받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 reducer 함수는 2개의 인자를 또 받으며 첫 번째는 store의 state, 두 번째는 store의 action이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state는 말그대로 상태값을 관리하는 객체이고, action은 해당 store에서 어떤 행동을 취할 것인지에 행위 정보가 들어있는 객체다. 또한, reducer 함수는 기본적으로 state를 리턴(return)해줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;createStore의 두번째 인자로 쓰인 값들(window~~~)은 크롬에서 확장 프로그램인 Redux DevTool을 사용하기 위해 지정한 값이다. 이를 지정하면 크롬 개발자도구의 Redux 탭에서 redux와 관련된 기능들을 활용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store의 state를 변조하고자 하는 화면에선 아래와 같이 createStore를 정의한 store를 import 하고 dispatch 함수를 활용해주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1635068600284&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import store from './store.js'

// 중략
return (
    &amp;lt;input type=&quot;button&quot; value=&quot;Add&quot; onClick={function(){
        store.dispatch({type:'INCREMENT', size: this.state.size});
        }.bind(this)}/&amp;gt;
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store의 state의 변경에따라 변화가 필요한 화면의 경우엔 아래와 같이 subscribe를 정의한다.&lt;/p&gt;
&lt;pre id=&quot;code_1635068796335&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import store from './store.js'

class Sample extends Component{
    state = {number: store.getState().number};
    
    constructor(props){
        super(props);
        
        store.subscribe(function(){
            this.setState({number:store.getState().number});
        }.bind(this));
    }
    
    render(){
        return (
            &amp;lt;div&amp;gt;
                &amp;lt;h3&amp;gt;{this.state.number}&amp;lt;/h3&amp;gt;
            &amp;lt;/div&amp;gt;
        )
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 Sample 이라는 컴포넌트에서는 store의 state.number 값이 변경될 경우, subscribe 함수의 첫번째 인자로 전달한 함수가 실행되게 된다. 여기서는 그저 Sample의 state가 가진 number를 store의 number로 setState해주었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 래핑하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 &lt;a href=&quot;https://blinders.tistory.com/108&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[211024] React #06&lt;/a&gt;의 마지막 목차를 보면 컨테이너 컴포넌트와 프리젠테이션 컴포넌트가 나오는데, redux를 활용하는 곳에서도 그 개념이 나온다. 컨테이너 컴포넌트는 데이터를 가지고 관리하는 주체이기 때문에 리덕스 스토어와 관련된 작업을 실질적으로 처리하는 곳이며, 프리젠테이션 컴포넌트는 스토어와 관련하지않으며 그저 props를 통해 전달된 값을 화면에 잘 출력해서 보여주기만 하면 되는 컴포넌트다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이를 위해 컨테이너 컴포넌트와 프리젠테이션 컴포넌트사이에,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux 관련 처리를 담당하는 래핑 컴포넌트를 하나 만들어서 감싸준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. react-redux&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;래핑 컴포넌트를 만들어줬을 때, 이슈가 되는 점은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너 컴포넌트에서 프리젠테이션 컴포넌트로 데이터를 전달할 게 추가될경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에 존재하는 래핑 컴포넌트를 거쳐야하므로, 그에 대응하는 N개의 props등을 건내주는 로직을 추가로 정의함으로써 줄이고자했던 의존성이 증가하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 점을 해결하려고 react-redux 를 활용하게 되는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1635069815307&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install react-redux&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props가 여러개일 경우를 위해 자동화해주는 역할이라고 생각하면 되는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react-redux에서 핵심은 connect 함수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5-1. Provider&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, react-redux를 통해 공급받는 기능을 추가해야하므로,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어플리케이션의 DOM 최상단에 Provider라는 컴포넌트를 추가해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1635069898344&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {Provider} from &quot;react-redux&quot;;
import store from &quot;./store&quot;;

ReactDOM.render(
    &amp;lt;Provider store={store}&amp;gt;
        &amp;lt;App/&amp;gt;
    &amp;lt;/Provider&amp;gt;,
    document.getElementById('root')
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같이 Provider라는 컴포넌트로 &amp;lt;App/&amp;gt;을 감싸고, props로 어떤 store를 공급받을 대상으로 할지도 정해준다. Provider는 UI와 연관된 컴포넌트가 아니기때문에 보여지는 룩앤필에는 이상이 없으며, props로 store를 정의함으로써, 이하 하위 컴포넌트들에서는 해당 store에 접근할 수 있는 창구를 열어주게 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5-2. connect&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이제 connect 함수를 활용하면 되는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;connect는 아래와 같이 2개의 전달인자와 WrapperComponent를 필요로 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1635070122045&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import PresentaionalComponent from &quot;../components/PresentaionalComponent&quot;;
import {connect} from &quot;react-redux&quot;;

function mapStateToProps(state){
    return {
        number: state.number
    }
}

function mapDispatchToProps(){
    return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(PresentaionalComponent);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react-redux에서 제공하는 connect 함수를 뜯어보면...대략 아래와 같은 구조라서 위와같은 형태가 가능해진다.&lt;/p&gt;
&lt;pre id=&quot;code_1635070487049&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function connect(mapStateToProps, mapDispatchToProps){
  return function(WrappedComponent){
    return class extends React.Component{
      render(){
        return(
          &amp;lt;WrappedComponent
            {...this.props}
            {...mapStateToProps(store.getState(), this.props)}
            {...mapDispatchToProps(store.dispatch, this.props)}
          /&amp;gt;
        )
      }
      
      componentDidMount(){
        this.unsubscribe = store.subscribe(this.handleChange.bind(this))
      }
      
      componentWillUnmount(){
        this.unsubscribe();
      }
      
      handleChange(){
        this.forceUpdate();
      }
    }
  } 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;즉, 내가 WrappedComponent가 프리젠테이션 컴포넌트의 역할을 하기 위해 정의됨과 동시에, 전달된 props를 구조분해 문법으로 전달해주는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5-3. mapStateToProps&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;connect 함수의 첫번째 인자로, 리덕스의 state를 리액트의 props로 연결하는 역할.이다.&lt;/p&gt;
&lt;pre id=&quot;code_1635070646373&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function mapStateToProps(state){
    return {
        number: state.number
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 어떤 객체를 반환하는데, 해당 객체가 프리젠테이션 컴포넌트의 props로 전달되는 것이다. 즉, 위와 같은 형태라면 number라는 이름을 가진 props에 state.number 값이 전달된다. 그리고 이 함수는 리덕스의 스토어 값이 변경될 때마다 호출되도록 약속(subscribe)되어있기 때문에, 전달하고자하는 props의 변경시에도 자동 호출되어 변경된 값을 전달하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기때문에 mapStateToProps의 인자로 받는 state라는 값은, 리덕스 스토어의 state 객체이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5-4. mapDispatchToProps&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;connect 함수의 두번째 인자로, 프리젠테이션에서 발생한 이벤트를 잡아서 리덕스 스토어에 dispatch를 발생시켜야 할 경우 활용되는 인자다.&lt;/p&gt;
&lt;pre id=&quot;code_1635070959421&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// AddNumber라는 프리젠테이션 컴포넌트
class AddNumber extends Component{
    state = {size: 1}
    render(){
        return (
            &amp;lt;div&amp;gt;
                &amp;lt;h1&amp;gt;Add Number&amp;lt;/h1&amp;gt;
                &amp;lt;input type=&quot;button&quot; value=&quot;+&quot; onClick={function (e){
                    this.props.onClick(this.state.size); // 여기!!
                }.bind(this)}/&amp;gt;
                &amp;lt;input type=&quot;text&quot; value={this.state.size} onChange={function(e){
                    this.setState({size: Number(e.target.value)})
                }.bind(this)}/&amp;gt;
            &amp;lt;/div&amp;gt;
        )
    }
}

/**/
// AddNumber 컴포넌트를 감싼 래핑 컴포넌트
function mapDispatchToProps(dispatch){
    return {
        onClick: function(size){
            dispatch({type:'INCREMENT', size: size});
        }
    }
}

export default connect(null, mapDispatchToProps)(AddNumber);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위는 2개 코드를 합친건데, AddNumber 라는 프리젠테이션 컴포넌트에서 &quot;+&quot; 버튼 클릭(onClick)시, this.props.onClick 함수를 호출하는데, 해당 함수가 바로 래핑 컴포넌트에 정의된 onClick: function(size){} 를 호출하며, 그 내부에서 dispatch를 사용함으로써 리덕스 스토어에 액션을 정의해주는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이렇게 프리젠테이션 컴포넌트와 연결지어주는 부분이 바로, connect 함수의 두번째 인자로 전달을 해준 부분이다.&lt;/p&gt;</description>
      <category>개발/개발일지</category>
      <category>frontend</category>
      <category>react</category>
      <category>개발일지</category>
      <category>리액트</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/109</guid>
      <comments>https://blinders.tistory.com/109#entry109comment</comments>
      <pubDate>Sun, 24 Oct 2021 19:26:02 +0900</pubDate>
    </item>
    <item>
      <title>[211024] React #06 : ajax(fetch)</title>
      <link>https://blinders.tistory.com/108</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생활코딩! React 리액트 프로그래밍 도서를 바탕으로 React 공부시작.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;이번 진도는 280P ~ 305P.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;목차로는 04. React &amp;amp; Ajax &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;(챕터 04, 끝)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. fetch API&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 json 파일 따로 만들어서 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Fetch_API/Using_Fetch&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fetch API&lt;/a&gt;를 통해서 가져 온 거임.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;254&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8zy3M/btriGk1azZu/p68eAkcgymcwMl38ri2McK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8zy3M/btriGk1azZu/p68eAkcgymcwMl38ri2McK/img.png&quot; data-alt=&quot;fetch API Browser support&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8zy3M/btriGk1azZu/p68eAkcgymcwMl38ri2McK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8zy3M%2FbtriGk1azZu%2Fp68eAkcgymcwMl38ri2McK%2Fimg.png&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;254&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;fetch API Browser support&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트에 대한 초기화가 필요하다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;componentDidMount 에 적용(Vue로 치면 mounted)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐, 대략 이런 식이랄까.&lt;/p&gt;
&lt;pre id=&quot;code_1635054310204&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;render() {
    let NavTag = null;
    if(this.state.list.isLoading){
        NavTag = &amp;lt;NowLoading/&amp;gt;;
    } else{
        NavTag = &amp;lt;Nav list={this.state.list.items} onClick={function(id){
            let newArticle = Object.assign({}, this.state.article, {isLoading: true});
            this.setState({article: newArticle});
            fetch(id+'.json')
                .then(function(res) {
                    return res.json();
                })
                .then(function(json){
                    this.setState({article: {item:{title: json.title, desc: json.desc}, isLoading: false}})
                }.bind(this));
        }.bind(this)}/&amp;gt;
    }
    
    return (
        &amp;lt;div&amp;gt;
            {NavTag}
        &amp;lt;/div&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NavTag 라는 변수로 return내부에 태그를 렌더링 하도록 정의하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;this.state.list.isLoading 을 통해서 현재 데이터를 가져오는 중인지, 아닌지를 판별한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 onClick을 통해서, fetch를 통해서 get으로 해당 URL(여기선 json)로부터 데이터를 가져오고 this.setState를 통해 state를 변경한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ GET외에 메서드에 대한 fetch API 사용법은 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Fetch_API/Using_Fetch&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Using Fetch - MDN&lt;/a&gt;을 참고하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 프리젠테이션 컨테이너&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 특정 데이터에 종속되지않고, props로 전해받아 활용하거나 보여주는 역할만 하는 컴포넌트를 프리젠테이션(presentation) 컴포넌트라고 한다. 그리고 이런 프리젠테이션 컴포넌트에서 활용될 데이터를 처리하고 사용자의 인터랙션을 처리하며 애플리케이션에 종독된 컴포넌트를 컨테이너(container) 컴포넌트라고 한다. 즉, 데이터 처리의 주체를 누가 가질 것인가, 에 대한 구분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 과정에서 데이터로 인한 서로간의 연관성을 최소화하는 것을 디커플링(decoupling)이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 보여줄 애는 보여주기만하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 다루는 애는 다루는 것을 목적으로 하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/개발일지</category>
      <category>frontend</category>
      <category>react</category>
      <category>개발일지</category>
      <category>리액트</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/108</guid>
      <comments>https://blinders.tistory.com/108#entry108comment</comments>
      <pubDate>Sun, 24 Oct 2021 14:51:45 +0900</pubDate>
    </item>
    <item>
      <title>[211023] React #05 : router</title>
      <link>https://blinders.tistory.com/107</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생활코딩! React 리액트 프로그래밍 도서를 바탕으로 React 공부시작.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;금일 진도는 248P ~ 277P.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;목차로는 03. React Router DOM&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;(챕터 03, 끝)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 설치와 기본 정의&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue-router와 같은 react-router-dom 의 사용법 설명 파트.&lt;/p&gt;
&lt;pre id=&quot;code_1635002483397&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install react-router-dom&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue에서 URL의 변경에 따른 페이지의 변화를 위해 가장 외곽을 &amp;lt;router-view&amp;gt; 태그로 감싸듯이 react-router-dom도 &amp;lt;BrowserRouter&amp;gt; 혹은 &amp;lt;HashRouter&amp;gt;로 감싸줘야 함. 둘의 차이는 이름을 보면 알겠지만 HashRouter가 Hash 태그(#) 붙는 형태의 URL이고 BrowserRouter는 해쉬없이 기존의 브라우져가 인식하던 그 형태임.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 예제에선 아래와 같이 ReactDOM.render에서 감쌈&lt;/p&gt;
&lt;pre id=&quot;code_1635002727938&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Route} from 'react-router-dom';

ReactDOM.render(
    &amp;lt;BrowserRouter&amp;gt;&amp;lt;App/&amp;gt;&amp;lt;/BrowserRouter&amp;gt;),
    document.getElementById('root')
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Route &amp;amp; Switch 컴포넌트&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Route 태그는 path라는 props를 가지며, 해당 path가 인식됐을 타이밍에 렌더링되는 주체를 정의한다.&lt;/p&gt;
&lt;pre id=&quot;code_1635002872106&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Route exact path=&quot;/&quot;&amp;gt;&amp;lt;Home/&amp;gt;&amp;lt;Route&amp;gt;
&amp;lt;Route path=&quot;/act&quot;&amp;gt;&amp;lt;Act/&amp;gt;&amp;lt;Route&amp;gt;
&amp;lt;Route path=&quot;/sample&quot;&amp;gt;&amp;lt;Sample/&amp;gt;&amp;lt;Route&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같을 경우 /sample 경로 입력시 Sample 컴포넌트가 해당 영역에 렌더링된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, exact라는 props가 &quot;/&quot; path로 정의된 Route 컴포넌트에 정의되었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 http://localhost:3000/sample 이라는 경로로 접속시 react-router-dom은 &quot;/&quot; 경로와 &quot;sample&quot; 2개 경로를 인식하기 때문에 이 경우 &amp;lt;Home/&amp;gt;과 &amp;lt;Sample/&amp;gt; 컴포넌트가 동시에 렌더링된다. exact는 이러한 상황을 방지해주는 props이며 URL과 완전히 일치하는 path만을 렌더링하게 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 exact를 사용하지않으려면, 아래와 같이 Switch 컴포넌트로 Route 컴포넌트를 감싸주면된다.&lt;/p&gt;
&lt;pre id=&quot;code_1635003113036&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Switch&amp;gt;
    &amp;lt;Route path=&quot;/act&quot;&amp;gt;&amp;lt;Act/&amp;gt;&amp;lt;Route&amp;gt;
    &amp;lt;Route path=&quot;/sample&quot;&amp;gt;&amp;lt;Sample/&amp;gt;&amp;lt;Route&amp;gt;
    &amp;lt;Route path=&quot;/&quot;&amp;gt;&amp;lt;Home/&amp;gt;&amp;lt;Route&amp;gt;
&amp;lt;/Switch&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 여기서 순서를 역전시켜서 루트경로의 &amp;lt;Home/&amp;gt;이 맨 아래로 온 이유는, Switch 컴포넌트는 URL과 일치하는 첫 번째 컴포넌트가 발견되면 나머지 컴포넌트는 버리기 때문이다. 즉,&amp;nbsp; http://localhost:3000/sample 경로로 접근시 설명했던 것처럼 &quot;/&quot; 경로와 &quot;/sample&quot; 경로를 동시에 인식하는데, 이 중 위에 배치된 &quot;/&quot; 경로가 선인식되어 &amp;lt;Home/&amp;gt; 컴포넌트가 렌더링 될 것이기 때문에 맨 아래로 배치함으로써 이러한 이슈를 해결하 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만...책의 설명에 의하면 사실 아래와 같이 쓰는게 적절한 거 같다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1635003250482&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Switch&amp;gt;
    &amp;lt;Route exact path=&quot;/&quot;&amp;gt;&amp;lt;Home/&amp;gt;&amp;lt;Route&amp;gt;
    &amp;lt;Route path=&quot;/act&quot;&amp;gt;&amp;lt;Act/&amp;gt;&amp;lt;Route&amp;gt;
    &amp;lt;Route path=&quot;/sample&quot;&amp;gt;&amp;lt;Sample/&amp;gt;&amp;lt;Route&amp;gt;
    &amp;lt;Route path=&quot;/&quot;&amp;gt;Not Found&amp;lt;Route&amp;gt;
&amp;lt;/Switch&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;/&quot; 경로에 대해 최상단에 exact를 둠으로써 http://localhost:3000/sample 경로로 접근하더라도 &quot;/sample&quot;과 완전히 일치하는 Route 컴포넌특 렌더링됨과 동시에, 정의해두지 않은 URL에 대해서는 최하단 Route 컴포넌트를 활용해서 Not Found라는 글자를 보여주게 된다(필요하다면 Not Found에 대한 컴포넌트를 별도 정의해서 활용해도 된다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Link &amp;amp; NavLink&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue-router에서 router.push 메서드를 활용해서 URL의 변경 및 화면을 이동시키곤했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react도 Link 컴포넌트를 활용하면 그런 기능이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1635003684959&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Link to=&quot;/sample&quot;&amp;gt;Sample&amp;lt;/Link&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Link 컴포넌트는 to props를 통해 이동할 path를 지정하며, 위 Link 컴포넌트 클릭시&lt;/p&gt;
&lt;pre id=&quot;code_1635003723690&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Route path=&quot;/sample&quot;&amp;gt;&amp;lt;Sample/&amp;gt;&amp;lt;Route&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Route 컴포넌트가 화면에 렌더링되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 NavLink 라는 컴포넌트가 있는데...사실 Link랑 거의 흡사한데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 선택된 URL에 의해 렌더링 된 HTML에 아래와 같이 active 라는 css class가 자동 추가 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;461&quot; data-origin-height=&quot;229&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnqjQF/btriBCuQifW/63cEppgwo7LJ18y0Ka8k0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnqjQF/btriBCuQifW/63cEppgwo7LJ18y0Ka8k0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnqjQF/btriBCuQifW/63cEppgwo7LJ18y0Ka8k0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnqjQF%2FbtriBCuQifW%2F63cEppgwo7LJ18y0Ka8k0K%2Fimg.png&quot; data-origin-width=&quot;461&quot; data-origin-height=&quot;229&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 파라미터 전달은 vue랑 유사함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue-router에서 path에 파라미터를 전달할 경우, 콜론을 붙였었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react에서도 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1635003959799&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Route path=&quot;/sample/:sample_id&quot;&amp;gt;
    &amp;lt;Sample/&amp;gt;
&amp;lt;/Route&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와같이 콜론을 붙이고 파라미터명을 전달하면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 내부의 Sample 이라는 컴포넌트에서는 useParam 이라는 훅(Hook)을 사용해서 받는다.&lt;/p&gt;
&lt;pre id=&quot;code_1635004070341&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Sample(){
    let params = useParams();
    console.log(params); // {sample_id: 값}
  
    return (
        &amp;lt;div&amp;gt;
            &amp;lt;h4&amp;gt;{params.sample_id}&amp;lt;/h4&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같이 콜론을 붙여서 넘긴 파라미터명을 그대로 활용가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 값에 따라서 추가 로직이 필요하다면 구현하면 된다.&lt;/p&gt;</description>
      <category>개발/개발일지</category>
      <category>frontend</category>
      <category>react</category>
      <category>개발일지</category>
      <category>리액트</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/107</guid>
      <comments>https://blinders.tistory.com/107#entry107comment</comments>
      <pubDate>Sun, 24 Oct 2021 00:48:37 +0900</pubDate>
    </item>
    <item>
      <title>[211022] React #04 : function &amp;amp; class</title>
      <link>https://blinders.tistory.com/106</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생활코딩! React 리액트 프로그래밍 도서를 바탕으로 React 공부시작.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;금일 진도는 202P ~ 245P.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;목차로는 02. 리액트 클래스 스타일 vs 함수 스타일 &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;(챕터 02, 끝)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;&lt;b&gt;1. function &amp;amp; class&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React에는 컴포넌트 생성 방법이 2가지임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나는 funciton, 하나는 class.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 function 방식보다 class 방식이 선호됐던 이유는,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;function에서는 state 값을 가질 수 없고 + 라이프 사이클 함수를 사용할 수 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 2019년 2월 6일에 &lt;a href=&quot;https://ko.reactjs.org/blog/2019/02/06/react-v16.8.0.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;릴리즈한 React v16.8&lt;/a&gt;부터 function에서도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state와 라이프 사이클 함수를 활용할 수 있게 도와주는 훅(Hook)이 도입되면서, class보다 function 방식에 익숙한 이들에게 환영받는 중이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 초간단한 컴포넌트를 각각의 방식으로 만든 예제다.&lt;/p&gt;
&lt;pre id=&quot;code_1634978923727&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function FuncComp(){
  return (
    &amp;lt;div className=&quot;container&quot;&amp;gt;
      &amp;lt;h2&amp;gt;function style component&amp;lt;/h2&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

class ClassComp extends Component{
  render(){
    return (
      &amp;lt;div className=&quot;container&quot;&amp;gt;
        &amp;lt;h2&amp;gt;class style component&amp;lt;/h2&amp;gt;
      &amp;lt;/div&amp;gt;
    )
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;function 타입은 return으로 컴포넌트의 형태를 정의하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;class는 render 함수내에 return으로 컴포넌트의 형태를 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. props&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;class에선 props가 this.props에 담겨져있었지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;function에서는 아래와 같이 파라미터로 전달받게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1634979970226&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function FuncComp(props){
  return (
    &amp;lt;div className=&quot;container&quot;&amp;gt;
      &amp;lt;h2&amp;gt;function style component : {props.name}&amp;lt;/h2&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. state&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;class에서 state를 정의하는 방법은 constructor내에 정의해야한다고 했지만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생략해서 아래와 같이 정의해도 해석되게 되었다고한다(&lt;a href=&quot;https://stackoverflow.com/questions/48179955/react-without-constructor-declaring-state-in-classs-body&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react state without constructor&lt;/a&gt;)&lt;/p&gt;
&lt;pre id=&quot;code_1634979336102&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ClassComp extends Component{
  state = {name: 'Grey'}
  render(){
    return (
      &amp;lt;div className=&quot;container&quot;&amp;gt;
        &amp;lt;h2&amp;gt;class style component : {this.state.name}&amp;lt;/h2&amp;gt;
      &amp;lt;/div&amp;gt;
    )
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;function에서는 Hook을 사용하는데, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Hook은 use 라는 prefix&lt;/b&gt;&lt;/span&gt;를 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state에 관여하는 Hook은 useState, 라이프 사이클과 연관된 Hook은 useEffect이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useState는 2개의 값을 리턴하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나는 state의 실제 변수, 하나는 setState 함수이다.&lt;/p&gt;
&lt;pre id=&quot;code_1634980285544&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, {useState} from 'react';

function FuncComp(props){
  let [age, setAge] = useState(34); 
  return (
    &amp;lt;div className=&quot;container&quot;&amp;gt;
      &amp;lt;h2&amp;gt;function style component&amp;lt;/h2&amp;gt;
      &amp;lt;h3&amp;gt;Name : {props.name}&amp;lt;/h3&amp;gt;
      &amp;lt;h3&amp;gt;Age : {age}&amp;lt;/h3&amp;gt;
      &amp;lt;input type=&quot;button&quot; value=&quot;increase&quot; onClick=&quot;{
        function(){
          setAge(++age);
        }
      }&quot;&amp;gt;&amp;lt;/input&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 선언하고, age라는 변수에 state가 담기고 해당 값의 변경이 필요하면 setAge 라는 setState에 대응되는 함수를 호출하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 라이프사이클&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue의 create, mounted와 같이 react도 라이프사이클을 가진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;456&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s15e6/btriB6a9zso/TE6UHpVZkgObHvelvPEBNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s15e6/btriB6a9zso/TE6UHpVZkgObHvelvPEBNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s15e6/btriB6a9zso/TE6UHpVZkgObHvelvPEBNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs15e6%2FbtriB6a9zso%2FTE6UHpVZkgObHvelvPEBNK%2Fimg.png&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;456&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림 출처는 : &lt;a href=&quot;https://spicycookie.me/React/lifecycle/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;리액트 Lifecycle API&lt;/a&gt; 인데, react 17 버전부터 위와같으며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 사용 할 수 있었던 componentWillMount, componentWillReceiveProps, componentWillUpdate의 &lt;a href=&quot;https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;3개 API는 17 버전 이후로 deprecated&lt;/a&gt; 되었다고한다(물론, 여전히 사용할 수는 있다. 하지만 아래와 같이 콘솔에 Warning을 띄워댄다)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;191&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pcTbn/btriB5i019n/Q0ffmnULCzQkFz4XfXiDZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pcTbn/btriB5i019n/Q0ffmnULCzQkFz4XfXiDZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pcTbn/btriB5i019n/Q0ffmnULCzQkFz4XfXiDZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpcTbn%2FbtriB5i019n%2FQ0ffmnULCzQkFz4XfXiDZK%2Fimg.png&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;191&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4-1. useEffect&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 본론으로 돌아와서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 React에서는 이런 라이프 사이클 API를 class 방식으로 선언시에만 사용가능했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 function에서는 useEffect라는 Hook을 추가함으로써 function 방식에서도 라이프 사이클 API를 사용할 수 있게끔 뚫어놓았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useEffect는 첫번째 전달인자로 함수를 가지며, 두번째 전달인자로 해당 effect가 발동될 state를 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(여기서 발동될 state를 지정한다는 것의 의미는, react는 state가 변경되면 해당 컴포넌트를 리렌더링해야하는데...이는 update타이밍에 따른 라이프 사이클이 호출되는 경우를 염두해 둔 것이며, 추가로 state별로 서로 다른 라이프사이클 API를 정의할 수 있다는 장점도 가지고 있다)&lt;/p&gt;
&lt;pre id=&quot;code_1634981542860&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 컴포넌트 mount시 최초 1회만 실행
useEffect(function(){
    console.log('%cfunc =&amp;gt; useEffect (componentDidMount)' + +(++funcId), funcStyle);
    document.title = 'Grey';
}, []);

// number에 대해서만 발동
useEffect(function(){
    console.log('%cfunc =&amp;gt; useEffect number (componentDidMount &amp;amp; componentDidUpdate)' + +(++funcId), funcStyle);
    document.title = number;
}, [number]);

// date에 대해서만 발동
useEffect(function(){
    console.log('%cfunc =&amp;gt; useEffect _date (componentDidMount &amp;amp; componentDidUpdate)' + +(++funcId), funcStyle);
    document.title = _date;
}, [_date]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같은 형태가 기본인데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈배열이면 componentDidMount 시점에 발동되며, 감시할 state가 빈배열이기 때문에 최초 1회만 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열에 값이 있을 경우, componentDidMount시점에 발동되고 + 이후에 배열내의 해당 값들이 변경되면 componentDidUpdate 라이프사이클 시점에 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4-2. clean-up&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리,의 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useEffect로 발동된 내용에서 정리될 내용이 있을 경우 호출되는 부분인데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 useEffect의 첫번째 파라미터로 전달된 함수의 반환값에 함수로 정의하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1634981806601&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 컴포넌트 mount시 최초 1회만 실행
useEffect(function(){
    console.log('%cfunc =&amp;gt; useEffect (componentDidMount)');
    document.title = 'Grey';
    return function(){
        console.log('func =&amp;gt; useEffect number return (componentWillUnmount)');
    }
}, []);

// number에 대해서만 발동
useEffect(function(){
    console.log('func =&amp;gt; useEffect number (componentDidMount &amp;amp; componentDidUpdate)');
    document.title = number;
    return function(){
        console.log('func =&amp;gt; useEffect number return (componentDidMount &amp;amp; componentDidUpdate)');
    }
}, [number]);

// date에 대해서만 발동
useEffect(function(){
    console.log('func =&amp;gt; useEffect _date (componentDidMount &amp;amp; componentDidUpdate)');
    document.title = _date;
    return function(){
        console.log('func =&amp;gt; useEffect number return (componentDidMount &amp;amp; componentDidUpdate)');    
    }
}, [_date]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같이 return으로 function을 반환해주면...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue로 비유하자면 v-if가 false되서 해당 컴포넌트가 지워지게되면 clean-up으로 정의된 함수가 호출되게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 기타&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 useContext, useReducer, useMemo등의 훅이 더 있다니까...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 마저 찾아서 정리하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/개발일지</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/106</guid>
      <comments>https://blinders.tistory.com/106#entry106comment</comments>
      <pubDate>Sat, 23 Oct 2021 18:14:04 +0900</pubDate>
    </item>
    <item>
      <title>[211020] React #03 : (props vs state) + CRUD</title>
      <link>https://blinders.tistory.com/105</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생활코딩! React 리액트 프로그래밍 도서를 바탕으로 React 공부시작.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;금일 진도는 126P ~ 199P.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;목차로는 01. 리액트 기초내에 18) 베이스 캠프 ~ 22) 수업을 마치며&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;(챕터 01. 리액트 기초, 끝)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. props vs state&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;props are read only&lt;/li&gt;
&lt;li&gt;props can not be modified&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;state changes can be asynchronous&lt;/li&gt;
&lt;li&gt;state can be modified using this.setState&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 컴포넌트가 하위 컴포넌트에 명령할 땐 props를 이용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 컴포넌트가 상위 컴포넌트에 명령할 땐 event를 이용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. CRUD&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 발생시 실행하는 함수를 핸들러(handler)라고 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App.js의 render 함수에서 this.state.mode에 따라 분기를 태워서 변수에 HTML 태그형태를 담음으로써 화면에 보이는 영역을 동적으로 바꿔줌. 그리고 나중엔 이것도 getContent 라는 별도 함수로 모듈화해서 render 내부는 최대한 깔-끔하게 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;input, textarea 와 같은 HTML 태그의 값을 활용하는경우엔, name attribute를 붙여서 event.target.이름.value 이렇게 값을 발췌함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌더링에 영향을 주지 않는 변수는 굳이 컴포넌트의 state에 넣을 필요없이, 그냥 constructor에 변수처럼 선언해두고 쓰면 됨. 왜냐면 state에 넣는 순간, state의 변경에 따라 컴포넌트가 render 함수를 호출해서 리랜더링하는데...굳이 그럴 필요 없는 값까지 state에서 관리 할 필요는 없으니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;state가 가진 값에 변경,추가,삭제와 같은 로직이 필요할 경우, 원본을 복사(concat이나 Array.from이나 Object.assign)를 통해서 전혀 다른 참조값(call by reference)을 딴 후에, 적용해서 this.setState로 변경할 것. &lt;span style=&quot;color: #666666;&quot;&gt;이 점이 중요한 이유는, react가 state의 변경에 따라 리렌더링의 기준을 삼을 때, shouldComponentUpdate 함수가 호출이 되고 여기서 props의 동일여부에 따라 리렌더링 진행 여부를 판별할 수 있는데...push와 같이 원본 데이터에 변경,추가,삭제를 할 경우 state 변수가 참조하는 메모리값은 변경이 발생하지 않기 때문에 old value와 new value가 결국 동일한 메모리를 참조하므로 변경을 감지하지 못 할 수 있음.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;배열형에&lt;br /&gt;추가때는 concat 또는 Array.from &amp;amp; push&lt;br /&gt;변경때는 Array.from 한 뒤에 타겟 인덱스변경&lt;br /&gt;삭제때는 Array.from 한 뒤에 splice(삭제인덱스, 1)&lt;br /&gt;&lt;br /&gt;객체는 Object.assign({}, 원본) 해서 작업.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;shouldComponentUpdate 는 render 이전에 호출되는 함수로, newProps, newState, nextContext를 파라미터로 가지기 때문에, 기존 props, state와 값의 비교가 가능하다. 따라서 해당 값의 변화가 없을경우 return false를 해주면 render 함수가 재호출되지 않는다. 이를통해 굳이 render가 동작하지 않아도 되는 컴포넌트의 무분별한 리렌더링을 줄임으로써 성능적인 이점을 가질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위에서 props로 전달해 준 값을 하위에서 input 태그의 value로 전달하거나해서 변화시키려고 한다면, 이 경우엔 아래처럼 하위 컴포넌트의 state로 재정의해서 사용해야하고 onChange이벤트도 추가해야함.&lt;/p&gt;
&lt;pre id=&quot;code_1634728421688&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Sample extends Component{
    constructor(props) {
        super(props);
        this.state = {
            title : this.props.data.title
        }
        this.inputFormHandler = this.inputFormHandler.bind(this);
    }
    inputFormHandler(e){
        this.setState({[e.target.name] : e.target.value})
    }
    
    render(){
        return (
            // 중략
            &amp;lt;input type=&quot;text&quot; name=&quot;title&quot; placeholder=&quot;title&quot; value={this.state.title}
                        onChange={this.inputFormHandler}/&amp;gt;
        )
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/개발일지</category>
      <category>frontend</category>
      <category>react</category>
      <category>개발일지</category>
      <category>리액트</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/105</guid>
      <comments>https://blinders.tistory.com/105#entry105comment</comments>
      <pubDate>Wed, 20 Oct 2021 20:17:29 +0900</pubDate>
    </item>
    <item>
      <title>[211019] React #02 : state&amp;amp;event</title>
      <link>https://blinders.tistory.com/104</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생활코딩! React 리액트 프로그래밍 도서를 바탕으로 React 공부시작.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;금일 진도는 65P ~ 125P.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;목차로는 01. 리액트 기초내에 13) React Developer Tools ~ 17) 컴포넌트 이벤트 만들기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;1. React 디버깅 툴&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;크롬 앱스토어에서 &lt;a href=&quot;https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi/related&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Developer Tools 확장도구&lt;/a&gt; 설치(edge에 설치함)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;그냥 Vue devtools랑 거의 같음.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;리액트 기준으로 컴포넌트들 보여주고 state 변경가능하고.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;2. state &amp;amp; 이벤트&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;드디어 나왔다, state.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Vue로 따지면 &amp;lt;script&amp;gt; data 영역에 정의되는 애들.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;state쓰려면 constructor가 필수이며, 거기서 선언 및 초기화.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1634653388302&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class App extends Component{
    constructor(props) {
        super(props);
        this.state = {
            title:'Title'
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법은 아래와 같이 그냥 어제 props 썼던 것처럼 this.state.title와 같이 this.state라는 객체의 property 형태로 씀.&lt;/p&gt;
&lt;pre id=&quot;code_1634653492683&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Subject title={this.state.title}/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;react에선 중괄호 하나로 묶으면 그 내부는 자바스크립트로 취급하기 때문에 위와 같은 형태가 성립됨.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;그리고, state에 있는 배열형 데이터를 바탕으로 화면에 v-for 쓰듯이 여러개 돌리는 것도 함.&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;이때, 얘도 v-for때처럼 key를 줘야함. 안 그러면 콘솔 에러뜸.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1634653790004&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Lists extends Component{
  render(){
    let list = [];
    for(let i = 0; i &amp;lt; 3; i++){
      list.push(&amp;lt;li key={i}&amp;gt;{i} 번째 Row&amp;lt;/li&amp;gt;)
    }
    
    return (
      &amp;lt;ul&amp;gt;
        {list}
      &amp;lt;/ul&amp;gt;
    )
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;그리고 state 변경엔 this.setState 함수를 쓸 것. Vue를 할 때 data내부에 선언한 변수를 조정하는 것도 마찬가지였지만, 모던 자바스크립트의 특성상, 사용중인 변수의 변경을 캐치하기는 힘듦. 왜냐면 이게 객체내부에 내부에 내부에 또 내부에...어디까지 갈 지 알 수가 없기 때문임. 그래서 Vue의 경우엔 Primitive타입은 그냥 대입 변경해도 캐치가 되서 리렌더링 되지만, 객체의 경우엔 Vue.$set을 쓰라고 권장하기도하고 배열은 push, pop같은 기존 함수를 써야한다고 함. 근데 react는 그렇게 개별로 복잡한 사용성 ㄴㄴ임. 무조건 setState 쓸 것.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;HTML의 기본 이벤트 활용시엔 기존에 onclick 이었다면 onClick로 C가 대문자가 됨.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;커스텀 이벤트를 정의하고자 할 때는 Vue처럼 @ 기호로 바인딩하는게 아니라 콜론이나 @없이 그냥 props로 취급해서 Child 컴포넌트로 전달한다는 것. 그래서 Child 컴포넌트에서 이벤트 호출할때도 그냥 this.props.이벤트명() 이렇게 호출함.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;이벤트내에서 this를 활용하기 위해(props나 state를 활용해야하니까) bind로 묶어줄 것.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1634654147470&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;a href=&quot;/&quot; onClick={
  function(e){
    e.preventDefault();
    this.setState({title:'2nd Title'});
  }.bind(this)
}&amp;gt;샘플링크&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;그래서 오늘 한 것중에 제일 중요한 거 2개.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 뒤에 bind(this) 하기&lt;/li&gt;
&lt;li&gt;state 변경은 this.setState 함수쓰기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-1. 기타 알아둘 것들&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;컴포넌트 만들때, 아래 코드는 필수.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1634653260544&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React,{Component} from 'react';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/개발일지</category>
      <category>frontend</category>
      <category>react</category>
      <category>개발일지</category>
      <category>리액트</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/104</guid>
      <comments>https://blinders.tistory.com/104#entry104comment</comments>
      <pubDate>Tue, 19 Oct 2021 23:40:08 +0900</pubDate>
    </item>
    <item>
      <title>[211018] React #01 : 세팅 + props</title>
      <link>https://blinders.tistory.com/103</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생활코딩! React 리액트 프로그래밍 도서를 바탕으로 React 공부시작.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;금일 진도는 0 ~ 64P.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;목차로는 01. 리액트 기초내에 01) 수업소개 ~ 12) props&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. 세팅 및 개발서버&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1634568457979&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install -g create-react-app
mkdir react-app
cd react-app
create-react-app .&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;npm install -g create-react-app : create-react-app 명령어의 전역(-g)에서 사용할 수 있게 받음&lt;/li&gt;
&lt;li&gt;mkdir react-app : react 프로젝트 만들 디렉토리(react-app)생성&lt;/li&gt;
&lt;li&gt;cd react-app&amp;nbsp; : 생성된 디렉토리(react-app)로 이동&lt;/li&gt;
&lt;li&gt;create-react-app . : 현재 디렉토리(.)에 react 프로젝트 생성(npm install 까지 됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;344&quot; data-origin-height=&quot;395&quot; width=&quot;285&quot; height=&quot;328&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bu21eT/btrh6I90z49/4iruvo4Yf3OaLz3b58bEx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bu21eT/btrh6I90z49/4iruvo4Yf3OaLz3b58bEx1/img.png&quot; data-alt=&quot;react 프로젝트 생성완료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bu21eT/btrh6I90z49/4iruvo4Yf3OaLz3b58bEx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbu21eT%2Fbtrh6I90z49%2F4iruvo4Yf3OaLz3b58bEx1%2Fimg.png&quot; data-origin-width=&quot;344&quot; data-origin-height=&quot;395&quot; width=&quot;285&quot; height=&quot;328&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;react 프로젝트 생성완료&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 npm 명령어로 http://localhost:3000/ 에 개발 서버 띄울 수 있음.&lt;/p&gt;
&lt;pre id=&quot;code_1634568806216&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run start&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. render, class, import, props&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React도 Vue와 마찬가지로 Component based 임.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2-1. 컴포넌트 간단형&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1634569002048&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, {Component} from 'react';

class Hello extends Component{
  render(){
    return (
      &amp;lt;h4&amp;gt;Hello React, Hi Grey&amp;lt;/h4&amp;gt;
    )
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 선언하면 Hello 라는 컴포넌트를 만든거임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react npm 패키지로부터 Component를 import 해와서 javascript의 class와 extends 를 통해 컴포넌트를 선언하는 거임. 컴포넌트이기 때문에 import 해 온 Component를 extends 해야하는 거고, 이 경우에 내부에 render라는 함수를 가짐. 이때, render는 여타 javascript와는 다르게 function 키워드가 빠졌는데 이는 javascript의 class내부에 선언된 함수이기 때문임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 return 되는 내부에는 Vue와 마찬가지로 최상단엔 1개의 태그만 존재해야함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2-2. 컴포넌트에 props 추가하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 생성한 Hello 컴포넌트는 아래와 같이 사용되는데,&lt;/p&gt;
&lt;pre id=&quot;code_1634569477139&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class App extends Component{
  render(){
    return {
      &amp;lt;div className=&quot;app&quot;&amp;gt;
        &amp;lt;Hello/&amp;gt; {/* Hello 컴포넌트 사용 */}
      &amp;lt;/div&amp;gt;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 Hello 컴포넌트에 Vue와 같은 props 개념을 적용할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적용법도 사실 Vue와 크게 다르지 않음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름부분만 props로 전달받는다고 한다면...&lt;/p&gt;
&lt;pre id=&quot;code_1634569546217&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, {Component} from 'react';

class Hello extends Component{
  render(){
    return (
      &amp;lt;h4&amp;gt;Hello React, Hi {this.props.name}&amp;lt;/h4&amp;gt;
    )
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 기존에 'Grey'라는 문자열이 있던 부분에 중괄호와 this.props 라는 정의가 추가되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name이라는 props명을 정의하면 됨. 그리고 사용처에서는 아래와 같이 정의하는 거임.&lt;/p&gt;
&lt;pre id=&quot;code_1634569660358&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class App extends Component{
  render(){
    return {
      &amp;lt;div className=&quot;app&quot;&amp;gt;
        &amp;lt;Hello name=&quot;Grey&quot;/&amp;gt; {/* name props와 값 추가 */}
      &amp;lt;/div&amp;gt;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/개발일지</category>
      <category>frontend</category>
      <category>react</category>
      <category>개발일지</category>
      <category>리액트</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/103</guid>
      <comments>https://blinders.tistory.com/103#entry103comment</comments>
      <pubDate>Mon, 18 Oct 2021 23:46:49 +0900</pubDate>
    </item>
    <item>
      <title>[javascript] var, let 그리고 const</title>
      <link>https://blinders.tistory.com/102</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;이 포스팅은 사실&amp;nbsp;&lt;a href=&quot;https://blinders.tistory.com/101&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[javascript] var가 let보다 빠르다...?&lt;/a&gt; 포스팅을 쓰던 중에,&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;부가설명이 필요해서 var과 let, const에 대한 내용을 별첨으로 정리하던 내용인데...&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;이게 또 쓰다보니 제법 길어져서 별도 포스팅으로 발행하게 되었습니다.&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0. javascript에서 변수를 선언하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이들이 마음껏 뛰어놀 수 있는 놀이터처럼,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;컴퓨터로 동작하는 모든 시스템은 메모리라는 놀이터에서 뛰어놀게 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 놀이터에서 뛰어놀기 위한 값들은 메모리의 한 켠에 적재되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적재된 값을 가리키는 변수 혹은 상수를 활용해서 개발자들은 시스템을 구축하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Javascript도 당연히 변수를 정의하는 키워드가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6(2015)가 공시된 2015년 이전에는 &lt;b&gt;var&lt;/b&gt;이라는 하나의 키워드만 존재했지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때를 기점으로 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;변수를 정의하는 let과 상수를 정의하는 const라는 키워드가 추가&lt;/b&gt;&lt;/span&gt;되게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수/상수를 선언하는 방법은 여타 프로그래밍 언어와 크게 다르지않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 형식으로 이름을 짓고 그에 맞는 값을 할당하기만 하면된다.&lt;/p&gt;
&lt;pre id=&quot;code_1634484354112&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let let_value = &quot;let!&quot;;
var var_value = &quot;var!&quot;;
const const_value = &quot;const!&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 여기까지만해도, 이 3가지 키워드는 크게 차이가 없어보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 변수명 앞에 쓰여서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;얘가 변수에요! 라고 선언해주는 역할&lt;/b&gt;이니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. var&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1-1.&amp;nbsp;&lt;/b&gt;&lt;b&gt;굳이 쓰지않는다면 너는 var이어라&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수를 선언할 때, 굳이 var이나 let, const와 같은 &lt;b&gt;키워드를 쓰지않아도 변수로써 정의&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;해당 변수는 var로 취급됨과 동시에 전역변수로써 등록&lt;/b&gt;&lt;/span&gt;된다.&lt;/p&gt;
&lt;pre id=&quot;code_1634474645565&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  function test(){
      num = 10;
      console.log('num &amp;gt;&amp;gt; ', num); // 10
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같은 코드는 정상적으로 콘솔로그에 10이라는 값을 출력해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1-2. 동명이인도 OK&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여타 프로그래밍언어는 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;동일한 변수명에 대해 선언이 불가능하지만, javascript는 가능&lt;/b&gt;&lt;/span&gt;하다.&lt;/p&gt;
&lt;pre id=&quot;code_1634476300561&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  function same_name(){
      var num = 10;
      console.log('num &amp;gt;&amp;gt; ', num); // 10
      var num = 20;
      console.log('num &amp;gt;&amp;gt; ', num); // 20
      var num = 30;
      console.log('num &amp;gt;&amp;gt; ', num); // 30
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 위와같은 형태인데, num이라는 이름을 가진 변수를 3번이나 정의했지만 아무런 에러없이 코드는 잘 실행된다. 다만, 이경우엔 당연하게도 세번째로 정의한 변수가 위의 첫번째, 두번째 변수명을 엎어쳤기 때문에 첫번째와 두번째로 선언한 num이라는 변수는 더이상 코드적으로 접근할 방법이 없으므로 추가적인 활용이 불가능하다&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(let과 const는 변수명의 중복이 불가능하다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1-3. function scope&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;javascript의 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;var은 function scope&lt;/b&gt;&lt;/span&gt;를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;javascript의 함수를 실행하면, 실행 컨텍스트(Execution Context)가 생성되고 이에 따라 동작할 컨텍스트 스택(&lt;span style=&quot;color: #404040;&quot;&gt;Context Stack)이 &lt;/span&gt;콜 스택(Call Stack)이라는 메모리상의 자료구조에 쌓이게 되는데, 이때 적재되는 스택의 단위는 function이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1634478914098&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  function outer(){
      console.log('outer');
      function inner(){
          console.log('inner');
      }
      inner();
  }
  
  outer();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 위와 같은 코드를 실행하게 되면, 대략 아래와 같은 순으로 실행 컨텍스트에 따라 Javascript가 동작하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;388&quot; width=&quot;620&quot; height=&quot;272&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPHx1Z/btrh3pICbOb/s0VInkHjTRE1IKTpELiz6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPHx1Z/btrh3pICbOb/s0VInkHjTRE1IKTpELiz6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPHx1Z/btrh3pICbOb/s0VInkHjTRE1IKTpELiz6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPHx1Z%2Fbtrh3pICbOb%2Fs0VInkHjTRE1IKTpELiz6K%2Fimg.png&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;388&quot; width=&quot;620&quot; height=&quot;272&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 여기서 javascript가 'function'을 기준으로 동작한다는 매커니즘'에 기반해서 생각해보면, javascript의 태생부터 존재했던 var이라는 변수 선언 키워드의 scope도 동일하게 function scope라는 부분이 이해가 될 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 문장으로 요약하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;javascript는 function을 기준으로 동작 하니까, javascript의 변수 선언 키워드인 var도 function scope.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 아래와 같은 예시를 생각해보면,&lt;/p&gt;
&lt;pre id=&quot;code_1634479388932&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function scope_var(){
    // 코드 출처 : https://poiemaweb.com/js-scope
    var x = 'global';

    function foo() {
        var x = 'local';
        console.log(x); // local

        function bar() { 
            console.log(x); // local
        }

        bar();
    }
    foo();
    console.log(x); // global
}

scope_var();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x 라는 변수를 함수 여기저기에 활용하며 function scope의 예시를 보여주는 코드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의깊게 봐야 할 부분은 bar function 내부에서 사용한 &lt;span style=&quot;color: #8a3db6;&quot;&gt;x라는 변수&lt;/span&gt;&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x는 bar function 내부에는 선언되지 않았지만, &lt;b&gt;bar function 이 선언된 foo function 내부에 x 라는 이름의 변수가 선언&lt;/b&gt;되어 있다. 따라서 &lt;b&gt;foo function 안쪽에 정의된 bar function 내에서 x 라는 변수를 활용하게 되면, foo function 이 가지는 scope를 기준으로 x를 가져와서 사용&lt;/b&gt;하게 된다&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(이러한 형태를 스코프 체인(Scope Chain)이라고도 한다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와같이 var로 선언한 변수는 function을 기준으로 scope를 가지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. let&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2-1. Block Scope&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C나 C++, JAVA와 같은 오래된 연식(?)의 프로그래밍언어에서의 변수들은 block scope를 가진다. 그리고 이를통해 개발에 입문한 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(나와같은)&lt;/b&gt;&lt;/span&gt;사람들은 변수는 block scope를 가진다는 개념이 머릿속에 정립되어있기 때문에, javascript에 입문할 때 var가 가지고 있는 function scope 개념이 굉장히 헷갈리곤한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서인지 ES6(2015)에 let이라는 변수 선언용 키워드가 추가되었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 키워드는 var과는 다르게 block scope를 가지고 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1634481994192&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function sample(){
    // 코드 출처 : https://poiemaweb.com/js-scope
    var x = 0;
    {
        var x = 1;
        console.log(x); // 1
    }
    console.log(x);   // 1

    let y = 0;
    {
        let y = 1;
        console.log(y); // 1
    }
    console.log(y);   // 0
}

sample();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;block scope라는 것은 우리가 흔히 중괄호라고 부르는 { } 이 형태로 감싸진 내부에 scope가 맞춰지는 것&lt;/b&gt;&lt;/span&gt;이다. 그렇기 때문에, 위와 같은 코드에서 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;let변수 y는&lt;/span&gt; 각각 선언된 위치에 따른 scope가 다르기때문에&lt;/b&gt; &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;1과 0 이라는 서로 다른 결과&lt;/b&gt;&lt;/span&gt;를 콘솔에 출력하지만, &lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;var로 선언된 변수 x&lt;/span&gt;는 sample이라는 function으로 동일한 scope를 가지기 때문에, 중괄호 내부에 var x를 새롭게 선언함과 동시에 기선언되었던 x가 엎어쳐지게 됨으로써 동&lt;span style=&quot;color: #8a3db6;&quot;&gt;일한 1이라는 값을 콘솔에 출력&lt;/span&gt;&lt;/b&gt;하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. const&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3-1. 상수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;const도 let과 함께 ES6부터 추가된 키워드로써, block scope를 가지고있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;const가 let 그리고 var와 다른점은, 최초 선언시 할당한 값을 변경할 수 없는 상수를 선언한다는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1634485173201&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const name = 'Grey';
name = 'Kai';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 위와같이, 상수로 정의한 name의 값을 변경하려한다면 아래와 같은 콘솔 에러를 확인할 수 있으며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는, 말그대로 상수(constant variable)를 변경하려했기 때문에 발생하는 에러이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;98&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ocwxy/btrhHtF370D/Os4kbbFMuzApQstFRTmKJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ocwxy/btrhHtF370D/Os4kbbFMuzApQstFRTmKJ1/img.png&quot; data-alt=&quot;const에 할당된 값을 변경하려 했을 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ocwxy/btrhHtF370D/Os4kbbFMuzApQstFRTmKJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOcwxy%2FbtrhHtF370D%2FOs4kbbFMuzApQstFRTmKJ1%2Fimg.png&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;98&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;const에 할당된 값을 변경하려 했을 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 const는 상수이기 때문에 아래와 같이 값을 할당하지 않는 것도 에러를 보여준다.&lt;/p&gt;
&lt;pre id=&quot;code_1634485041923&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const name;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;52&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bST6Ds/btrhIokeiVl/zJh1R2Cm6FsD1P7F3rrW81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bST6Ds/btrhIokeiVl/zJh1R2Cm6FsD1P7F3rrW81/img.png&quot; data-alt=&quot;const에 값을 할당하지 않았을 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bST6Ds/btrhIokeiVl/zJh1R2Cm6FsD1P7F3rrW81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbST6Ds%2FbtrhIokeiVl%2FzJh1R2Cm6FsD1P7F3rrW81%2Fimg.png&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;52&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;const에 값을 할당하지 않았을 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3-2. 객체가 const로 선언됐을 때?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;const가 상수라고 했기때문에, 아래와 같은 경우에 종종 헷갈려하는 분들이 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1634483453311&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function sample(){
    const obj = {
        name: 'Grey',
        age: 28
    }
    obj.age = 34;
    console.log(obj.age); // 34
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;const는 상수라고 했는데, obj 내부의 age가 34로 변경되었고 아무런 에러도 발생하지 않는다&lt;/b&gt;. &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;이는 엄밀히 말하자면, obj라는 상수가 변경된 게 아니라, obj라는 객체를 참조하는 값이 가리키는 영역의 값...그러니까 한 단계를 더 거쳐서 메모리에 위치하고 있던 값을 변경하려 했고, 그 값이 변경된 것&lt;/b&gt;&lt;/span&gt;이다. 만약, 아래와 같이 obj라는 상수가 참조하는 값을 변조하려 한다면&lt;/p&gt;
&lt;pre id=&quot;code_1634483701543&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function sample(){
    const obj = {
        name: 'Grey',
        age: 28
    }
    obj = {
        name: 'Grey',
        age: 34
    }    
    console.log(obj.age);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;64&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C3LoC/btrh4No0DYC/0JS5KlJ2iGCE9M6shF8JP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C3LoC/btrh4No0DYC/0JS5KlJ2iGCE9M6shF8JP1/img.png&quot; data-alt=&quot;Error라고 한다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C3LoC/btrh4No0DYC/0JS5KlJ2iGCE9M6shF8JP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC3LoC%2Fbtrh4No0DYC%2F0JS5KlJ2iGCE9M6shF8JP1%2Fimg.png&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;64&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Error라고 한다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 아주 시뻘건 에러로그를 콘솔에서 보게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 동적 타이핑(Dynamic typing)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Javascript의 변수 선언방식은, 기존 프로그래밍 언어들과 다른점은 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;변수의 자료형을 가리지않는다는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1634485228026&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// javascript
var num_value = 42;    // number 
var str_value = &quot;str&quot;; // string 
var bool_value = true;  // boolean&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 특성은 &lt;b&gt;var뿐만 아니라 let, const도 동일하게 가지고 있는 점&lt;/b&gt;으로써, 위 코드에서 대입 연산자(=)를 통해 바인딩되는 값들의 타입은 number, string, boolean으로 전부 다르다. 하지만 var이라는 키워드를 통해 변수를 선언하는 부분은 동일한데, 이는 변수의 타입을 키워드로 특정짓지않아도 프로그램이 동작할 때 자동으로 해석해준다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어, JAVA라면 위와 같은 변수들을 각각 선언할 때 아래와 같이 키워드를 구분해서 써줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(아래 코드 중 JAVA의 String은 객체지만, 동일 형태의 데이터 타입 비교를 위해서니 양해바랍니다)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1634485237156&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// java
int num_value = 42; // number
String str_value = &quot;str&quot;; // string
boolean bool_value = true; // boolean&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와같은 개념을 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Javascript에서는 동적 타이핑(dynamic typing)이라고 정의&lt;/b&gt;&lt;/span&gt;하고있으며, 이는 Javasript가 느슨한 언어(loosely typed) 혹은 동적 언어(dynamic language)라는 개념에 근간을 두고있기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 호이스팅&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var와 let, const로 선언한 변수/상수는 Javascript 실행시 호이스팅되지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;var는 호이스팅때 undefined로 초기화되고 let과 const는 uninitialized로 초기화된다는 차이점&lt;/b&gt;&lt;/span&gt;을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대한 상세한 설명을 여기서 다루기엔 너무 주제를 벗어나기에 우선 저렇게 알아주기를 바라며...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시나 왜 그런지 궁금하신 분은 내가 작성했던 또 다른 포스팅인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://blinders.tistory.com/90&quot;&gt;[Javascript] class도 호이스팅이 되나요(feat. lexical environment)&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 참고하기 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. 간략히 정리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까 윗 내용들을 정리하자면 각각 아래와 같은 특징을 가진다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 79.5349%; height: 144px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;var&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;let&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;const&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;형태&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;변수&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;변수&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;상수&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;호이스팅&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;undefined&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;uninitialized&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;uninitialized&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;스코프&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;block&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center; height: 20px;&quot;&gt;block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;동적 타이핑&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;O&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;변수명 중복선언&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;가능&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;불가능&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;불가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고사이트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Data_structures&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN : Javascript의 자료형&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;a href=&quot;https://poiemaweb.com/js-scope&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Poiemaweb : Scope&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>웹</category>
      <category>웹개발</category>
      <category>자바스크립트</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/102</guid>
      <comments>https://blinders.tistory.com/102#entry102comment</comments>
      <pubDate>Sun, 17 Oct 2021 23:43:01 +0900</pubDate>
    </item>
    <item>
      <title>[javascript] var가 let보다 빠르다?</title>
      <link>https://blinders.tistory.com/101</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0. var가 let보다 빠르다고들 한다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모 프로젝트로부터 헬퍼 요청이 있어서 2주 정도 단기로 투입됐을 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 분석하며 의아했던 점 중에 하나는 대부분의 변수가 var로 선언되어있다는 것이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 살펴봤을 때, let을 두고 var를 사용할 이유가 없어보였기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 로직을 개발하신 분께 여쭤봤더니 아래와 같은 답변을 들을 수 있었다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;&quot;var가 let보다 빨라요&quot;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 당시엔 그런가보다, 하고 넘겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;왜 var가 let보다 빠르다는건지에 대한 설명이 부족했지만,&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈직전의 프로젝트에 헬퍼로 투입된 입장에서 이미 동작하고 있는 로직의 변수선언을 왜 var로 했는지 리뷰하며 수정을 요청드릴 정도로 정신머리가 있지는 았았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;...물론, 급할수록 돌아가랬다고 변명이다. 개발자로써 직무유기랄까.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 얼마전에 팀의 선배가 개발하던 것을 이어받게되어 코드 분석을 하고 있는데,&lt;br /&gt;그 코드들에도 let보다는 var가 대부분의 변수 선언을 담당하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 왜 let대신 var를 쓰셨냐는 질문에 돌아온 대답은 역시나,&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;&quot;var가 let보다 빨라&quot;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;335&quot; height=&quot;204&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;421&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qjDXM/btrhLSZDHLY/SYRX5OZ2cplsPbhnInM4gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qjDXM/btrhLSZDHLY/SYRX5OZ2cplsPbhnInM4gK/img.png&quot; data-alt=&quot;왜 아무도 왜 그런지 왜 말을 안 해주는거야, 왜에ㅠㅠㅠ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qjDXM/btrhLSZDHLY/SYRX5OZ2cplsPbhnInM4gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqjDXM%2FbtrhLSZDHLY%2FSYRX5OZ2cplsPbhnInM4gK%2Fimg.png&quot; width=&quot;335&quot; height=&quot;204&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;421&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;왜 아무도 왜 그런지 왜 말을 안 해주는거야, 왜에ㅠㅠㅠ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...그래서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;왜 var가 let보다 빠르다고들 하는건지 직접 찾아보기&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;로&lt;/span&gt;&lt;/span&gt; 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 구글은 정답을 알고있다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 쪽으로의 궁금증은 개발자라면 누구나 품을 수 있는 거라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그걸 반증하듯, 이미 Stack overflow에는 관련한 질문들이 여럿있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어...&lt;a href=&quot;https://stackoverflow.com/questions/36847394/why-var-declaration-fast-than-let?noredirect=1&amp;amp;lq=1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;why var declaration fast than let&lt;/a&gt; 와 같은 질문이라던가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/36623440/let-vs-var-performance-in-nodejs-and-chrome&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;let vs var performance in nodejs and chrome&lt;/a&gt; 라던가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/37792934/why-is-let-slower-than-var-in-a-for-loop-in-nodejs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Why is let slower than var in a for loop in nodejs?&lt;/a&gt; 라던가.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 해당 질문들은, 본인들이 테스트해보니 아래와 같이 var가 let보다 빠르다는 명확한 기록을 남김으로써, 자신들의 주장에 신빙성을 더해주고 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WUd8v/btrhNphYGrh/PDKqKyoGZ0TKVuKQQKA6U1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WUd8v/btrhNphYGrh/PDKqKyoGZ0TKVuKQQKA6U1/img.png&quot; data-alt=&quot;각 질문들에 있는 데이터들. var가 let보다 빠른 것을 분명하게 알 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WUd8v/btrhNphYGrh/PDKqKyoGZ0TKVuKQQKA6U1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWUd8v%2FbtrhNphYGrh%2FPDKqKyoGZ0TKVuKQQKA6U1%2Fimg.png&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;300&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;각 질문들에 있는 데이터들. var가 let보다 빠른 것을 분명하게 알 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제를 바탕으로 실측된 위와 같은 값들을 바탕으로 var가 let보다 빠르다는 것을 확인할 수는 있었지만...궁극적으로 내가 찾던 답은 이게 아니었다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;내가 찾던 것은 &lt;b&gt;'아, 진짜 빠르구나'라는 결론이 아니라 '그래서 왜 빠른가'에 대한 과정의 설득&lt;/b&gt;성이었고, 이에 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;가장 근접한 내용을 한 블로그에서 찾을 수 있었다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;A Lexical Environment is a specification type used to define the association of Identifiers to specific variables and functions based upon the lexical nesting structure of ECMAScript code. (중략) Usually a Lexical Environment is associated with some specific syntactic structure of ECMAScript code such as a FunctionDeclaration, a BlockStatement, or a Catch clause of a TryStatement and a &lt;b&gt;new Lexical Environment is created each time such code is evaluated.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;(발번역 주의) 렉시컬 환경은 ECMAScript 코드의 렉시컬 중첩구조를 기반으로 식별자(identifier)와 특정 변수 및 함수와의 연관성을 정의하기 위한 스펙 유형이다. 렉시컬 환경은 일반적으로&amp;nbsp;Function Declaration,&amp;nbsp;Block Statement,&amp;nbsp;try구문의&amp;nbsp;catch&amp;nbsp;절과 같은 ECMAScript 코드의 특정 구문 구조와 연결되며, &lt;b&gt;이러한 코드가 평가될 때마다 새로운 렉시컬 환경이 생성&lt;/b&gt;된다.&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;&amp;nbsp; - 출처 : &lt;a href=&quot;https://roy-jung.github.io/170110_let-vs-var-performance-compare/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;let과 var의 성능 비교&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문구는 해당 블로거분이&amp;nbsp;&lt;a href=&quot;http://www.ecma-international.org/ecma-262/6.0/#sec-lexical-environments&quot;&gt;ECMAScript2015 Specfication - Lexical Environments&lt;/a&gt; 에서 발췌한 것으로써, 친절하게 번역까지 해주신 내용을 가져온 것이다. 저기서 설명된 Lexical Environment는 예전에 내가 포스팅했던 &lt;a href=&quot;https://blinders.tistory.com/90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Javascript]&amp;nbsp;class도&amp;nbsp;호이스팅이&amp;nbsp;되나요(feat.&amp;nbsp;lexical&amp;nbsp;environment)&lt;/a&gt; 에서도 언급됐던 내용인데, Javascript의 Execution Context(실행 컨텍스트)가 구축될 때 해당 영역에서 사용되는 변수 혹은 함수들이 선정의되는 자료구조라고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 당연하게도 이때 할당되는 변수나 함수들은 본인들의 scope를 기준으로 Lexical Environment에 할당이 될텐데...&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;let과 const의 경우 Block scope를 가지고 있기 때문에 if나 for와 같이 지정된 Block 영역내에서 활용될 경우 새롭게 생성되는 Lexical Environment에서 시스템적인 비용이 발생한다는 것&lt;/b&gt;&lt;/span&gt;이다. 반면에 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Functional Scope를 가지는 var는 이러한 비용적인 측면에서 자유롭기에, Block Scope를 가진 let/const보다 빠르다는 결론에 도달할 수 있는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 실제로 결과로도 그러하다는 것을 Stackoverflow의 질문들과 위 포스팅에 첨부된 결과값으로 우리는 확인 할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 끝날때까진, 끝난게 아니다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 아름답게, var가 let보다 빠르구나! 라고 박수치고 끝났으면 참 좋았을텐데.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;319&quot; data-origin-height=&quot;258&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O0i1b/btrhNo4saCd/uJVBdYXipKpdKAPCI81q01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O0i1b/btrhNo4saCd/uJVBdYXipKpdKAPCI81q01/img.png&quot; data-alt=&quot;끝날때까진, 끝난 게 아니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O0i1b/btrhNo4saCd/uJVBdYXipKpdKAPCI81q01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO0i1b%2FbtrhNo4saCd%2FuJVBdYXipKpdKAPCI81q01%2Fimg.png&quot; data-origin-width=&quot;319&quot; data-origin-height=&quot;258&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;끝날때까진, 끝난 게 아니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 Stackoverflow와 &lt;a href=&quot;https://roy-jung.github.io/170110_let-vs-var-performance-compare/&quot;&gt;let과 var의 성능 비교&lt;/a&gt; 블로그의 설명을 바탕으로, 나는 설득을 당했고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스팅을 마무리지으려고 했었다. 그렇게 마무리됐다면 참 좋았을텐데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 또 Stackoverflow와 블로그에서 실측되는 예제 코드를 봤으니, 보는걸로 끝맺는게 아니라 실제로 동작시켜보는게 개발자로써의 인지상정 아니겠는가. 그리고, 해당 코드 스니펫들을 동작시켜보는순간...&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;328&quot; width=&quot;379&quot; height=&quot;279&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baG60q/btrhKtTsFKi/ZB5nd9SPkS9nRDqwAL4gaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baG60q/btrhKtTsFKi/ZB5nd9SPkS9nRDqwAL4gaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baG60q/btrhKtTsFKi/ZB5nd9SPkS9nRDqwAL4gaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaG60q%2FbtrhKtTsFKi%2FZB5nd9SPkS9nRDqwAL4gaK%2Fimg.png&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;328&quot; width=&quot;379&quot; height=&quot;279&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;335&quot; height=&quot;204&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;421&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qjDXM/btrhLSZDHLY/SYRX5OZ2cplsPbhnInM4gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qjDXM/btrhLSZDHLY/SYRX5OZ2cplsPbhnInM4gK/img.png&quot; data-alt=&quot;왜, 나는 별 차이가 없어...??&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qjDXM/btrhLSZDHLY/SYRX5OZ2cplsPbhnInM4gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqjDXM%2FbtrhLSZDHLY%2FSYRX5OZ2cplsPbhnInM4gK%2Fimg.png&quot; width=&quot;335&quot; height=&quot;204&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;421&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;왜, 나는 별 차이가 없어...??&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 이 짤을 쓰는 순간이 오게 될 줄이야.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어, 내가 설득당했던 &lt;a href=&quot;https://roy-jung.github.io/170110_let-vs-var-performance-compare/&quot;&gt;let과 var의 성능 비교&lt;/a&gt; 블로그의 예제코드도 돌려보니...&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;193&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPvzlJ/btrhPBhIvar/3xbuFV6kBTmAngqK00OhB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPvzlJ/btrhPBhIvar/3xbuFV6kBTmAngqK00OhB1/img.png&quot; data-alt=&quot;Edge, Chrome, Firefox에서의 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPvzlJ/btrhPBhIvar/3xbuFV6kBTmAngqK00OhB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPvzlJ%2FbtrhPBhIvar%2F3xbuFV6kBTmAngqK00OhB1%2Fimg.png&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;193&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Edge, Chrome, Firefox에서의 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;케이스별로 &lt;b&gt;크게 차이가 나지 않음은 물론이고 일부 구간에선 let이 var보다 빠른 결과&lt;/b&gt;를 보이고 있었다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그러다 나는 이쯤에서 재밌는 Issue 하나를 발견하게 되었다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bugs.chromium.org/p/v8/issues/detail?id=4762&amp;amp;q=let%20label%3APerformance%20&amp;amp;colspec=ID%20Type%20Status%20Priority%20Owner%20Summary%20HW%20OS%20Component%20Stars&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Issue&amp;nbsp;4762:&amp;nbsp;Low&amp;nbsp;performance&amp;nbsp;when&amp;nbsp;use&amp;nbsp;&quot;let&quot;&amp;nbsp;in&amp;nbsp;&quot;for&quot;&amp;nbsp;loop&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이와 관련된 사항이 &lt;b&gt;2016년에 Javascript V8 엔진쪽에 issue로 올라왔고&lt;/b&gt;...&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;결론적으로&amp;nbsp;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;2021년인 현시점엔 fix된 Issue였던 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;...그러니까, &lt;b&gt;황망하게도 결론을 짓자면 삽질 끝에 광명찾은 그런 느낌&lt;/b&gt;이긴한데&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;var가 let보다 빠르다, 라는 건 옛날 이야기&lt;/b&gt;&lt;/span&gt;라는거다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;let과 const는 ES6(2015)때 등장했고, 이듬해인 &lt;b&gt;2016년까지는 브라우저 엔진들이 최적화를 이뤄내지 못 하고 불안정한 시기&lt;/b&gt;를 보냈을 것이다. 그리고 그 때쯤 let과 var을 혼용해서 사용했던 이들...그러니까 stackoverflow에 질문을 던진 이들과 내가 링크한 블로거, 내게 'var가 let보다 빨라'라는 말을 했던 팀선배나 프로젝트 개발자분까지. 그들은 그때 본인들이 실증한 경험을 가지고 있기에 맞는 말이었던 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;다만, 현시점에서의 브라우져 엔진들은 결국 최적화를 위해 계속해서 개선해나가고 있으며,&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;내가 실측한 데이터와 같이 var와 let의 성능적 격차는 거의 없는 것으로 확인되었다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;일부 케이스에선 let이 빠르지만, 또 일부케이스에선 var가 빠르다는 것도 우리는 확인할 수 있었는데,&amp;nbsp;이는 결국 앞서 언급했던 Scope와 Lexical Environment간의 관계의 차이에서 오는 격차일 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 자, 그렇다면 결론은?&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;변수를 선언함에 있어서 어떤 키워드를 쓸지는, 사실 개인 취향이라고해도 할 말은 없지만...&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;var보단 let을 쓰는 게 훨씬 좋다고 생각한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var는,&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;선언하지 않은 시점에도 해당 변수를 마치 선언한 것처럼 사용할 수 있게 해주며 이는 마치 해당 변수가 전역으로 활용되는 착각을 불러일으킬 수 있고, 변수의 명확한 선언 위치를 혼동하기 쉬우며 동일한 변수명에 대해 중복 선언도 가능하다. 또한 C언어를 비롯한 수많은 언어들이 변수에 대해 Block scope를 가지는 것과 이질적인 경향이 있기 때문에, 개발시 혼란스러움을 가중시켜주는 단점을 가지고 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;물론, 위와 같은 점들을 장점이라고 바라보는 시선도 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;어디서든 변수를 부담없이 필요할 때마다 사용할 수 있고, 사용코자하는 변수명의 재차사용이 가능하며 Scope에 대해 깊게 생각지않고 쉬운 코딩을 할 수 있다는...관점에서 말이다&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(대학생때 알고리즘을 가르치던 교수님께서, Javascript의 이런 작태를 보고 &quot;근본이 없는 언어같지 않은 언어&quot;라고 말씀하셨던 게 문득 떠오른다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이제는 학생때 하던 과제 프로젝트 수준이 아니라 대규모 서비스를 개발해야하는 개발자라면, 쉽게 사용할 수 있지만 가독성 및 정립성 관점에서 복잡도를 가중시키는 var는 지양하는게 맞다고 생각한다. 몇년전과 같이 var가 let보다 성능이 5배, 10배 정도 좋았던 환경이라면, let보다 var를 사용하는 것을 동의하는 바였겠지만&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(물론, 그렇다고 var를 여기저기 막 쓰는 것까지 동의하는 건 아니다)&lt;/span&gt; 오늘 확인한 바에 따르면 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;성능적인 격차는 브라우져 엔진들의 최적화로 현격히 줄어들었고, 그렇다면 let보다 var를 선호해야 할 이유가 없다고 생각&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고사이트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;a href=&quot;https://www.samsungsds.com/kr/insights/111517_RD_Refactoring2.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;자바스크립트&amp;nbsp;코드를&amp;nbsp;리팩토링&amp;nbsp;하는&amp;nbsp;방법&amp;nbsp;'&amp;nbsp;ES2015'&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;a href=&quot;https://roy-jung.github.io/170110_let-vs-var-performance-compare/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;let과&amp;nbsp;var의&amp;nbsp;성능&amp;nbsp;비교&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>Let</category>
      <category>var</category>
      <category>웹</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/101</guid>
      <comments>https://blinders.tistory.com/101#entry101comment</comments>
      <pubDate>Thu, 14 Oct 2021 23:52:08 +0900</pubDate>
    </item>
    <item>
      <title>[moment] Module not found: Error: Can't resolve './locale'</title>
      <link>https://blinders.tistory.com/100</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 부분은 에러라기보단, 아래와 같이 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;Warning의 레벨&lt;/b&gt;&lt;/span&gt;이라서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고치지않아도 node.js 서버의 기동이나 개발시엔 이슈 될 일이 없긴한데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;218&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doV5jC/btrgOtzcTKk/vR52ckP1xkKYSmDeu3vOY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doV5jC/btrgOtzcTKk/vR52ckP1xkKYSmDeu3vOY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doV5jC/btrgOtzcTKk/vR52ckP1xkKYSmDeu3vOY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoV5jC%2FbtrgOtzcTKk%2FvR52ckP1xkKYSmDeu3vOY0%2Fimg.png&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;218&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 서버 기동시마다 보이니까, 늘 찝찝한 건 어쩔 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;보통 node.js에서 Module not found와 같은 키워드로 시작하는 이슈&lt;/b&gt;&lt;/span&gt;는&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1. 그 npm 패키지 파일이 설치되지 않았거나&lt;br /&gt;2. import하고 있는 대상 파일이 없거나.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;이 둘 중에 하나로 수렴&lt;/b&gt;&lt;/span&gt;하는데, 해당 Warning 메시지 같은 경우에는 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;2번사항&lt;/b&gt;&lt;/span&gt;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결법부터 설명하자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;./node_modules/moment/src/lib/locale/locales.js 파일의 코드를 아래와 같이 수정해주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1633407049898&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try {
    oldLocale = globalLocale._abbr;
    aliasedRequire = require;
    aliasedRequire('../locale/' + name); // 수정부분. 기존 : aliasedRequire('./locale/' + name);
    getSetGlobalLocale(oldLocale);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;locale 디렉토리의 경로가 상대경로로 설정되어있는데, 그 경로값이 잘 못 설정&lt;/b&gt;&lt;/span&gt;되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;점 하나만 딱&lt;/b&gt;&lt;/span&gt;, 찍어주면 우리는&amp;nbsp;아래와 같이 마음이 편안----해지는 콘솔을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;179&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMGoFv/btrgTEmvxiR/auyLsEVWe7Ud5FPkOXVy3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMGoFv/btrgTEmvxiR/auyLsEVWe7Ud5FPkOXVy3k/img.png&quot; data-alt=&quot;마음이 편해지는 콘솔이다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMGoFv/btrgTEmvxiR/auyLsEVWe7Ud5FPkOXVy3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMGoFv%2FbtrgTEmvxiR%2FauyLsEVWe7Ud5FPkOXVy3k%2Fimg.png&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;179&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;마음이 편해지는 콘솔이다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;477&quot; data-origin-height=&quot;321&quot; width=&quot;432&quot; height=&quot;291&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PBttK/btrgMtmcHkI/46TEfzxdPMqt0ak5WMJ1F1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PBttK/btrgMtmcHkI/46TEfzxdPMqt0ak5WMJ1F1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PBttK/btrgMtmcHkI/46TEfzxdPMqt0ak5WMJ1F1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPBttK%2FbtrgMtmcHkI%2F46TEfzxdPMqt0ak5WMJ1F1%2Fimg.png&quot; data-origin-width=&quot;477&quot; data-origin-height=&quot;321&quot; width=&quot;432&quot; height=&quot;291&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;추가설명&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, 해당 이슈는 꽤나 오래된 moment.js 측의 이슈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/moment/moment/issues/4216&quot;&gt;Moment Github issue #4216 : Webpack Error: Cannot find module &quot;./locale&quot; after updating to 2.19.0&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 이슈 등록일을 보면 2017년 10월 10일이고, 2.19.0 버전부터 발생된 걸로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 우리 프로젝트는 2.22.0 버전의 moment.js를 사용하고 있기때문에 node.js 서버 구동시 해당 Warning 메시지가 발생하는 것인데...의아한 점은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;해당 이슈가 2021년 10월인 현재 버전(2.29.1)에서도 발생하고 있다는 것&lt;/b&gt;&lt;/span&gt;이다(이젠 좀 고쳐 줄 때도 되지 않았니...? 컨트리뷰션이라도 할까...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련해서 moment의 이슈를 좀 더 찾아보면&amp;nbsp;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;2020년에 등록된 &lt;/span&gt;&lt;a style=&quot;letter-spacing: 0px;&quot; href=&quot;https://github.com/moment/moment/issues/5472&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#5472&lt;/a&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;번에도 동일한 내용이 있는데, 해당 이슈에 달린 댓글들을 보면&amp;nbsp;&lt;/span&gt;&lt;b&gt;2.24 버전에선 발생하지 않는다는 사람&lt;/b&gt;도 있고 &lt;b&gt;2.25 이상에서 다시 발생했다는 의견&lt;/b&gt;도 있다(하지만 테스트 결과 나는 2.24에서도 동일한 이슈가 발생했다)&lt;/p&gt;</description>
      <category>개발/트러블 슈팅(Trouble Shooting)</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>Moment'</category>
      <category>NPM</category>
      <category>개발</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/100</guid>
      <comments>https://blinders.tistory.com/100#entry100comment</comments>
      <pubDate>Tue, 5 Oct 2021 13:49:02 +0900</pubDate>
    </item>
    <item>
      <title>[babel] core-js 버전을 3으로 올리면서 만나버린 것들</title>
      <link>https://blinders.tistory.com/95</link>
      <description>&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;목차&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;1. ES11문법을 위한 babel의 최신화(Hi, Unexpected token, bye!)&lt;br /&gt;2. polyfills는 Default를 가지고있다.&lt;br /&gt;3. core-js 3 라고 왠만하면 명시하자.&lt;br /&gt;&lt;br /&gt;...그리고 -1. 별첨. es6? es7? ㄴㄴ es!&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. ES11문법을 위한 babel의 최신화(Hi, Unexpected token, bye!)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;문제점&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;현재 프로젝트에서 사용하고 있는 컴포넌트의, 새버전이 릴리즈되어 현장에 적용하려하였는데...&lt;br /&gt;아래와 같은 에러 로그를 만나게 되었다. &lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Module parse failed: Unexpected token&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;418&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC128B/btre7JW5onn/zu5L6kafmX3DDNp8j4rKUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC128B/btre7JW5onn/zu5L6kafmX3DDNp8j4rKUK/img.png&quot; data-alt=&quot;에러가 발생한 코드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC128B/btre7JW5onn/zu5L6kafmX3DDNp8j4rKUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC128B%2Fbtre7JW5onn%2Fzu5L6kafmX3DDNp8j4rKUK%2Fimg.png&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;418&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;에러가 발생한 코드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Unexpected token 이라는 에러는 보통, Javascript 문법을 잘 못 썼거나 컴파일 단계에서 babel이 이해하지 못 하는 구분자(token)이 있을 때 발생하는 에러다. 그리고 이번 트러블 슈팅의 원인은 후자였다. &lt;b&gt;transpiler인 babel이&lt;/b&gt; &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;?. &lt;span style=&quot;color: #333333;&quot;&gt;라는 코드&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;를 해석하지 못 하는 에러.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(혹시나해서 적어둡니다만, 위의 에러로그에 예시로 활용된 코드는 실제 에러로그 발생 코드를 참고하여 제가 임의로 작성한 코드입니다. 원본 코드를 그대로 노출하는 건, 사내 보안위규 사항이라서요)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;해결법&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;?.&lt;/b&gt; 라는 코드는 Javascript의 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;optional chaining 연산자&lt;/span&gt;&lt;/a&gt;이다. &lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;ES11에 추가된 연산자&lt;/span&gt;&lt;/b&gt;로써 체이닝된 객체의 속성값을 읽어서 유효한지 확인하며, 유효하다면 해당값을 리턴하고 유효하지 않다면 undefined를 리턴하는 연산자다. &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;ES11에 추가된 연산자이니만큼, 그보다 이전에 정의된 babel의 preset을 사용중이라면 babel 입장에서는 해당 연산자가 무슨 의미인지 알 수가 없다. &lt;/span&gt;&lt;/b&gt;따라서, babel의 preset을 재설정해주어야 하는데, 이 방법에도 2가지가 있다.&lt;br /&gt;&lt;br /&gt;우선, 가장 직접적인 해결법은 &lt;a href=&quot;https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;@babel/plugin-proposal-optional-chaining&lt;/span&gt;&lt;/a&gt;을 preset으로 사용하는 방법인데, 사실 해당 링크를 들어가보면 아래와 같은 인용구가 적혀있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;NOTE&lt;/b&gt;: This plugin is included in &lt;b&gt;@babel/preset-env&lt;/b&gt;, in &lt;a href=&quot;https://github.com/tc39/proposals/blob/master/finished-proposals.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;ES2020&lt;/span&gt;&lt;/a&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;즉, @babel/preset-env를 최신버전으로 적용하면 결국 optional chaining뿐만 아니라 여타 ES11 관련 문법도 모두 transpile이 가능해지는 것이다. 그리고, 나는 현재 Vue-cli로 생성한 프로젝트를 활용하고 있기 때문에 babel의 preset 설정(babel.config.js)을 아래와 같이 정의하고 있는데,&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;module.exports = { 
  presets: [ 
    [ 
      '@vue/app', 
      { 
        modules: 'commonjs', 
        useBuiltIns: &quot;usage&quot;, 
        polyfills: [ 
          'es6.promise' 
        ] 
      } 
    ] 
  ] 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 사용되는 @vue/app 이라는 preset의 지원범위는 &lt;a href=&quot;https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/babel-preset-app/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;@vue/babel-preset-app&lt;/span&gt;&lt;/a&gt; 에서 확인할 수 있으며, 위에서 &lt;b&gt;언급했던 @babel/preset-env가 이 안에 포함&lt;/b&gt;되어있다. 즉, &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;babel의 최신화를 위한 최종 목표는 @vue/babel-preset-app을 최신화하면 해결이 되는 것&lt;/span&gt;&lt;/b&gt;이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;323&quot; data-origin-height=&quot;661&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUJB16/btre43hIk2a/1yhyrn1ufcKVZOnNM31Qp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUJB16/btre43hIk2a/1yhyrn1ufcKVZOnNM31Qp1/img.png&quot; data-alt=&quot;바로 요놈이 최신화되어야하는데...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUJB16/btre43hIk2a/1yhyrn1ufcKVZOnNM31Qp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUJB16%2Fbtre43hIk2a%2F1yhyrn1ufcKVZOnNM31Qp1%2Fimg.png&quot; data-origin-width=&quot;323&quot; data-origin-height=&quot;661&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;바로 요놈이 최신화되어야하는데...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그럼 어떻게 @vue/babel-preset-app을 최신화하느냐.&lt;br /&gt;npm에 익숙한 사람이라면, 당연하게도 패키지를 관리하는 package.json을 떠올렸을 텐데, 나처럼 Vue-cli를 활용해서 프로젝트를 구성한 사람이라면 package.json에는 @vue/babel-preset-app에 대한 버전정보가 명시되어있지않을 것이다. 왜냐면 @vue/babel-preset-app 은 @vue/cli-plugin-babel 패키지의 의존모듈(dependency)이기 때문이다.&lt;br /&gt;&lt;br /&gt;아래 스크린샷과 같이 node_modules 내의 @vue/cli-plugin-babel의 package.json을 열어보면&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;609&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhIryG/btre5bNBwKu/vHkklxf4UCKF43cuVtGlb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhIryG/btre5bNBwKu/vHkklxf4UCKF43cuVtGlb1/img.png&quot; data-alt=&quot;node_modules/@vue/cli-plugin-babel/package.json&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhIryG/btre5bNBwKu/vHkklxf4UCKF43cuVtGlb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhIryG%2Fbtre5bNBwKu%2FvHkklxf4UCKF43cuVtGlb1%2Fimg.png&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;609&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;node_modules/@vue/cli-plugin-babel/package.json&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;dependencies&quot; 항목에 @vue/babel-preset-app이 있는 것을 확인 할 수 있다.&lt;br /&gt;그래서 우리는, 최종적으로 &lt;a href=&quot;https://www.npmjs.com/package/@vue/cli-plugin-babel&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;@vue/cli-plugin-babel&lt;/span&gt;&lt;/a&gt;을 최신화해주면&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;npm install @vue/cli-plugin-babel --save-dev&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;Unexpected token과 같은 에러는 사라지는 것을 볼 수 있다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. polyfills는 Default를 가지고있다.&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;문제점&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: Noto Sans Light;&quot;&gt; Syntax Error: Error: [BABEL] ~~파일경로 중략~~~ : Cannot find polyfill es6.promise, please refer to 'core-js-compat' for a complete list of available modules &lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그리고 나는 위와같은 &lt;b&gt;새로운 에러&lt;/b&gt;를 맞이하게 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;해결법&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;위 에러는 생각보다 쉽게 원인을 파악할 수 있었다.&lt;br /&gt;babel의 설정을 담당하는 babel.config.js 파일을 보면 아래와 같이 정의해서 활용중이라고 했었다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;module.exports = { 
  presets: [ 
    [ 
      '@vue/app', 
      { 
        modules: 'commonjs', 
        useBuiltIns: &quot;usage&quot;, 
        polyfills: [ 
          'es6.promise' // 여기가 문제였다. 
        ] 
      } 
    ] 
  ] 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;presets 설정의 polyfills는, transpile시의 polyfill 대상을 정의한 것이다.&lt;br /&gt;ES6에 추가된 Promise에 대해서 polyfill 하도록 한 것인데, &lt;b&gt;babel 최신화를 위해서 참고했던 &lt;/b&gt;&lt;a href=&quot;https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/babel-preset-app/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;@vue/babel-preset-app&lt;/span&gt;&lt;/a&gt;&lt;b&gt; 의 설명에 보면 하기와 같은 문구가 작성&lt;/b&gt;되어있다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;203&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d03ky9/btre7uyQY7B/CLRogHLte8jNMJyNLayaV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d03ky9/btre7uyQY7B/CLRogHLte8jNMJyNLayaV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d03ky9/btre7uyQY7B/CLRogHLte8jNMJyNLayaV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd03ky9%2Fbtre7uyQY7B%2FCLRogHLte8jNMJyNLayaV0%2Fimg.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;203&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 우리가 &lt;b&gt;주목해야 할 포인트는 2가지&lt;/b&gt;다.&lt;br /&gt;하나는,&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt; es라는 키워드 뒤에 6 혹은 7과 같은 숫자가 없다는 것&lt;/span&gt;&lt;/b&gt;.&lt;br /&gt;그리고 하나는, &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;Default에 es.promise가 있다는 것&lt;/span&gt;&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;polyfills 항목이 이미 기본값(Default)으로 Promise 에 대한 설정값을 가지고 있기 때문에&lt;br /&gt;&lt;b&gt;나는 babel.config.js에서 해당 항목을 지워줌으로써 쉽게 해결&lt;/b&gt;되었다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;(혹시 지우지 않고 명시적으로 남겨두고 싶다면 es.promise 로 값을 변경해주면 된다)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;만약, 위 기본 항목들외에 polyfills 대상으로 등록해야하는 것들이 있다면&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://github.com/zloirock/core-js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;core-js의 Github&lt;/span&gt;&lt;/a&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;에서 관련 모듈을 검색해서 이름에 맞게 등록&lt;/span&gt;&lt;/b&gt;해주면 된다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;※ es 키워드 뒤에 6 혹은 7이 왜 없어졌는지에 대해서는 아래 별첨 -1에서 설명&lt;/span&gt;&lt;/b&gt;한다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. core-js 3 라고 왠만하면 명시하자.&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;문제점&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;2번사항까지 해결하고 node 서버를 재기동했지만...또 다시 어마어마한 에러로그를 마주하게 됐다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;* core-js/modules/es.array-buffer.constructor.js ./node_modules~~~~~~~~~~~~ &lt;br /&gt;* core-js/modules/es.array-buffer.slice.js in ./node_modules~~~~~~~~~~~~ &lt;br /&gt;* core-js/modules/es.array.concat.js in ./node_modules/@vue/cli-plugin-babel~~~~~~~ &lt;br /&gt;* core-js/modules/es.array.fill.js in ./node_modules ~~~~~~~~~ &lt;br /&gt;&lt;br /&gt;/* 중략 */ &lt;br /&gt;&lt;br /&gt;To install them, you can run: npm install --save core-js/modules/es.array-buffer.constructor.js core-js/modules/es.array-buffer.slice.js ~~~~~~~~~~~~~~~~~~~~~~&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;위 에러로그 같은 경우에는 우리가 npm 패키지를 활용하다보면 흔하게 만날 수 있는 건데,&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;활용하려는 node_modules를 찾지 못 하겠으니 npm install을 통해서 설치를 해라&lt;/span&gt;&lt;/b&gt;. 라는 내용이다.&lt;br /&gt;&lt;br /&gt;그렇기때문에 우리는 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;우선적으로 node_modules에 해당 모듈이 정말 없는지 확인&lt;/span&gt;&lt;/b&gt;부터 해야한다.&lt;br /&gt;그리고 &lt;b&gt;당연하게도 해당 모듈들이 없을 것&lt;/b&gt;이다&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(없으니까 에러가 나오겠지)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;해결법&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;사실, 이 에러는 1번에서 했던 @vue/cli-plugin-babel 설치가 순조롭게 잘 진행되었다면 발생하지않는 이슈다. 왜냐면, &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;이 에러로그의 해결법이 바로 core-js 3.x 버전의 설치이기 때문&lt;/span&gt;&lt;/b&gt;이다.&lt;br /&gt;&lt;br /&gt;@vue/cli-plugin-babel을 최신버전(2021.09.15기준으로 4.5.13 버전)으로 설치하였다면 node_modules 디렉토리 안의 &lt;b&gt;@vue/babel-preset-app의 package.json을 열어보면 &lt;span style=&quot;color: #009a87;&quot;&gt;dependencies항목에 core-js의 버전이 3.6대로 정의&lt;/span&gt;&lt;/b&gt;되어 있을 것이다. 즉, 우리가 1번에서 babel을 최신화하기 위해 @vue/cli-plugin-babel 버전을 최신으로 재정의했고, 그에따라 &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;@vue/babel-preset-app의 버전도 최신화가 되었으니 해당 패키지에서는 core-js의 버전이 3.x가 되어야 정상적으로 동작하게 되는 것&lt;/span&gt;&lt;/b&gt;이다.&lt;br /&gt;&lt;br /&gt;일반적인 경우라면 @vue/cli-plugin-babel을 npm install 할 때&lt;br /&gt;@vue/babel-preset-app의 의존성에 따라, core-js도 3.6 이상의 버전으로 설치가 되었어야했지만...&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;296&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cp81nd/btreY4Wy1mb/kZ66QO7YVevoapYGoZ3dx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cp81nd/btreY4Wy1mb/kZ66QO7YVevoapYGoZ3dx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cp81nd/btreY4Wy1mb/kZ66QO7YVevoapYGoZ3dx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcp81nd%2FbtreY4Wy1mb%2FkZ66QO7YVevoapYGoZ3dx0%2Fimg.png&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;296&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;현 프로젝트의 package.json에는 기존에 사용하던 core-js 버전이 2.6.5로 명시 되어있었고, &lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;그로인해 @vue/cli-plugin-babel이 최신 버전으로 설치되면서도 core-js 버전은 그대로&lt;/span&gt;&lt;/b&gt;였던 것이다.&lt;br /&gt;&lt;br /&gt;그래서 &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;아래 2개의 명령어를 통해 core-js 버전을 삭제(uninstall)하고 재설치(install)해주면 해결&lt;/span&gt;&lt;/b&gt;이 된다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;npm uninstall core-js 
npm install core-js&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;혹은, &lt;b&gt;package.json에 정의된 &lt;span style=&quot;color: #009a87;&quot;&gt;&quot;core-js&quot;: &quot;^2.6.5&quot; 와 같은 명시사항을 지우고&lt;/span&gt; &lt;span style=&quot;color: #009a87;&quot;&gt;@vue/cli-plugin-babel을 install&lt;/span&gt; &lt;/b&gt;해도 된다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;-1. 별첨. es6? es7? ㄴㄴ es!&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;core-js 측에서 늘 고심했던 이슈 몇가지를 3.x 버전으로 올리면서 정리하려고 노력했는데, 걔중에는 core-js 가 2MB에 육박할 정도로 너무 용량이 크다는 것, 그리고 동일한 목적을 가진 파일들이 중복되어 패키징되고 있다는 이슈가 있었다고한다. 이러한 부분을 좀 더 효율적으로 정리하기위해 기존에 es6 혹은 es7 이라는 prefix를 제거하고 es로 통일하였으며 그에따라 실제로 node_modules 디렉토리에 설치되는 디렉토리 구조나 내용도 아래와 같이 매우 깔끔해졌음을 알 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;741&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnVLnb/btre33CzCit/Jef5bq3ulp7poeEz1QVZu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnVLnb/btre33CzCit/Jef5bq3ulp7poeEz1QVZu1/img.png&quot; data-alt=&quot;core-js 2.x와 core-js 3.x의 node_modules 차이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnVLnb/btre33CzCit/Jef5bq3ulp7poeEz1QVZu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnVLnb%2Fbtre33CzCit%2FJef5bq3ulp7poeEz1QVZu1%2Fimg.png&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;741&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;core-js 2.x와 core-js 3.x의 node_modules 차이&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;좀 더 상세히 알고 싶은 분은 &lt;a href=&quot;https://github.com/zloirock/core-js/blob/e88cee56940308d3b4f99251e8f6d96e1ab69401/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md#packages-entry-points-and-modules-names&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;원문 링크&lt;/span&gt;&lt;/a&gt;를 따라 가보시면 될 것 같다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고사이트&lt;/b&gt;&lt;br /&gt;1. &lt;a href=&quot;https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/babel-preset-app&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;vue.js, Vue-cli의 package 중 @vue/babel-preset-app Github&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;2. &lt;a href=&quot;https://blog.woolta.com/categories/10/posts/145&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;vue-cli core-js 3.x 으로 변경하면서..&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;3. &lt;a href=&quot;https://github.com/zloirock/core-js/blob/e88cee56940308d3b4f99251e8f6d96e1ab69401/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;core-js Github&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;4. &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;MDN Optional chaining&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;5. &lt;a href=&quot;https://john015.netlify.app/what-is-new-in-es-11&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;What's new in ECMAScript 2020 (ES11)&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;6. &lt;a href=&quot;https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;babeljs.io&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/트러블 슈팅(Trouble Shooting)</category>
      <category>babel</category>
      <category>Front-end</category>
      <category>polyfill</category>
      <category>Vue</category>
      <category>개발</category>
      <category>바벨</category>
      <category>웹개발</category>
      <category>트러블슈팅</category>
      <category>폴리필</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/95</guid>
      <comments>https://blinders.tistory.com/95#entry95comment</comments>
      <pubDate>Tue, 14 Sep 2021 23:48:38 +0900</pubDate>
    </item>
    <item>
      <title>[CSS] opacity는 reflow가 발생 안 한다구요...? 정말??</title>
      <link>https://blinders.tistory.com/93</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0. 왜 이 포스팅을&amp;nbsp;쓰게되었는지에 대하여.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스팅은 계획에 없던 포스팅이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 CSS Triggers에 대한 포스팅은 &lt;a href=&quot;https://blinders.tistory.com/92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;저번 포스팅&lt;/a&gt;으로 끝내려고 했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 왜 또, 포스팅을 작성하고 있냐...면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 내가 숱한 기술 블로그 포스팅들을 보면서 답답했던 부분이, 왜 이론은 엄청 방대하고 자세하게 설명들을 하면서 쉽고 직관적이며 이해하기 쉬운 예제는 잘 안 넣어두시는 걸까, 였었다. 그래서 예시가 있으면 이해가 더 쉬울 것 같은 포스팅에는 그때그때 예시를 될 수 있으면 넣으려고 하는데...그래서 저번 포스팅이었던 &lt;a href=&quot;https://blinders.tistory.com/92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[CSS] CSS Triggers&lt;/a&gt; 에서도 역시나, &lt;b&gt;CSS Triggers에 대한 쉬운 예제 코드를 넣으려&lt;/b&gt; 했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 아뿔싸, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;예상치 못 한 현상&lt;/b&gt;&lt;/span&gt;을 봐버린거다.&lt;/p&gt;
&lt;pre id=&quot;code_1630842629410&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- 대충 1초에 한 번씩 opa 라는 class가 토글되는 코드 --&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;
    &amp;lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width,initial-scale=1.0&quot;&amp;gt;
    &amp;lt;title&amp;gt;CSS Triggers&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
        .text {
            opacity: 1;
        }
        .opa {
            opacity: 0.3;
        }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;script&amp;gt;
    window.onload = function () {
        setInterval(() =&amp;gt; {
            document.getElementById('text').classList.toggle('opa');
        }, 1000);
    }
&amp;lt;/script&amp;gt;

&amp;lt;body&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;div id=&quot;app&quot; class=&quot;app&quot;&amp;gt;
            &amp;lt;h1 id=&quot;text&quot; class=&quot;text&quot;&amp;gt;CSS Trigger&amp;lt;/h1&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까, 대략 이런 예제코드를 바탕으로 &lt;b&gt;opacity라는 CSS 요소를 Trigger&lt;/b&gt;로 썼을때...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;내가 기대한 건 아래와 같이 CSS Triggers에 따라서 reflow(layout) 단계가 발생하지 않아야&lt;/b&gt;&lt;/span&gt;되는건데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;275&quot; width=&quot;678&quot; height=&quot;253&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHqHQW/btrd1zpuJCm/0OZ6koZKCV5K2ez5wTev60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHqHQW/btrd1zpuJCm/0OZ6koZKCV5K2ez5wTev60/img.png&quot; data-alt=&quot;CSS Triggers 사이트의 opacity. &amp;amp;#39;Blink&amp;amp;#39;에선 reflow가 발생하지 않는다고 되어있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHqHQW/btrd1zpuJCm/0OZ6koZKCV5K2ez5wTev60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHqHQW%2Fbtrd1zpuJCm%2F0OZ6koZKCV5K2ez5wTev60%2Fimg.png&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;275&quot; width=&quot;678&quot; height=&quot;253&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CSS Triggers 사이트의 opacity. 'Blink'에선 reflow가 발생하지 않는다고 되어있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 개발자도구의 performance탭을 통해서 레코드한 기록을 봤더니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;327&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8p0LH/btrexdlJuki/geAe2nYciC7lNkvsH9jU4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8p0LH/btrexdlJuki/geAe2nYciC7lNkvsH9jU4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8p0LH/btrexdlJuki/geAe2nYciC7lNkvsH9jU4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8p0LH%2FbtrexdlJuki%2FgeAe2nYciC7lNkvsH9jU4K%2Fimg.png&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;327&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;339&quot; width=&quot;431&quot; height=&quot;250&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2VPyT/btrd658yXPW/STkR0PCMbu9RUI3p5SjPI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2VPyT/btrd658yXPW/STkR0PCMbu9RUI3p5SjPI1/img.png&quot; data-alt=&quot;Layout 네가 왜 거기서 나와...?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2VPyT/btrd658yXPW/STkR0PCMbu9RUI3p5SjPI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2VPyT%2Fbtrd658yXPW%2FSTkR0PCMbu9RUI3p5SjPI1%2Fimg.png&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;339&quot; width=&quot;431&quot; height=&quot;250&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Layout 네가 왜 거기서 나와...?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;왜 Layout이 발생...?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;opacity는 분명 reflow 단계부터 발생시키는 애가 아닌데...?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 난 내가 뭔가 잘 못 알고있던건가? 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 그간 알고있던 내용에서도 그렇고, 그 지식을 쌓기위해 공부했을 당시나 최근 리서치 과정에서도 그렇고...분명 opacity는 reflow를 발생하지 않는 CSS 요소값으로 알고있었기 때문이다(이게 포스팅을 작성하는 중요 포인트가 되버리는 이유는...어떻게 보면 겨우 한 가지 속성을 내가 잘 못 알고있었을 수도 있지만, &lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;하나의 오판으로 균열이 가게되서 내가 알고있던 개념이 깨지면, 결국 다른 CSS Triggers 들은 내가 알고있던 게 정확한가? 에 대한 확신이 없어지기 때문&lt;/b&gt;&lt;/span&gt;이다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 그 사이에 렌더링 엔진이 버전업을 하면서 opacity나 일부 CSS값의 Triggers 시점을 변경했을수도있고...그래서 어제 포스팅을 열심히 작성하다가 작성을 멈췄었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 좀 더 깊고 명확한 답을 찾기위해 검색과 검색과 검색을 계속해나갔지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국내외를 가리지않고 대부분의 글에서 opacity는 reflow가 발생하지 않는다고 하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어 어디서는 repaint 마저도 발생하지 않는다, 라고 하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답을 찾기 위한 검색이 오히려 독이 되어가는 느낌이랄까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blinders.tistory.com/92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[CSS] CSS Triggers&lt;/a&gt;를 포스팅한 이후로 어제까지 3일은 계속 시간날때마다 찾아봤던 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 결국 답을 찾을 수 있었는데...&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;결론은, 전부 맞는말&lt;/b&gt;&lt;/span&gt;이라는 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;opacity라는 스타일의 변경은 &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;내가 함정에 빠졌던 윗 스크린샷과 같이 reflow부터 발생하기도하지만, &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;때로는 repaint부터 발생하기도하고, 또 때로는 reflow&amp;amp;repaint 없이 composite 단계에서 GPU의 도움을 받기도 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 &lt;b&gt;'때'&lt;/b&gt;에는 분명 조건이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이해를 돕기위해 Pseudocode로 표현해보자면 대략 아래와 같지않을까, 싶다.&lt;/p&gt;
&lt;pre id=&quot;code_1631158273680&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 실제로 이렇게 동작한다는 건 아니고, 이해를 돕기 위해 작성된 Pseudocode다.
function changeOpacity(value){
  if(composite 발생조건){
    // composite
  } else if(repaint 발생조건){
    // repaint
  } else {
    // reflow
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기억하자. &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;우리가 opacity나 transform과 같은 요소를 사용하는 이유는, 최종적으로 브라우져의 연산 비용을 최대한 줄이고자 하는데 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 1번 항목이라 1이라는 값이 원인인건가?!&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;썰을 하나하나 풀기전에, &lt;b&gt;첫 의문부터 해결&lt;/b&gt;해보자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;opacity의 값을 변경했는데 reflow가 발생한&lt;/span&gt; 원인은 주어진 값이 1이라서&lt;/b&gt; &lt;/span&gt;그렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;app라는 css class에 준, &lt;b&gt;opacity : 1&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1631159224914&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;style&amp;gt;
  .text{
    opacity: 1; /* 이거...바로 이거 !! */
  }
  .opa{
    opacity: 0.3;
  }
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연한 말이지만, opacity라는 속성은 화면에 렌더링되는 요소의 투명도를 조절하는데 쓰이는데...해당 값이 1인 상태로 주어졌을 때 값을 변경하면 reflow가 발생한다. 그럼 text class의 opacity를 0.99 로 주고 다시 개발자도구의 Performance 탭을 보면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;347&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBp8At/btreAKDwtKh/zMjcEgdRykXDt7ykiezUt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBp8At/btreAKDwtKh/zMjcEgdRykXDt7ykiezUt1/img.png&quot; data-alt=&quot;여담이지만, 제가 어제 세차를 했습니다. 그래서 차가 매우 깨끗해졌답니다. 마치 포포몬쓰 탭처럼요.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBp8At/btreAKDwtKh/zMjcEgdRykXDt7ykiezUt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBp8At%2FbtreAKDwtKh%2FzMjcEgdRykXDt7ykiezUt1%2Fimg.png&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;347&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;여담이지만, 제가 어제 세차를 했습니다. 그래서 차가 매우 깨끗해졌답니다. 마치 포포몬쓰 탭처럼요.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;짜잔, reflow(layout)도 repaint(paint)도 없이 깨------끗하게 포포몬쓰가 변해버렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Layer, and Stacking Context&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;903&quot; data-origin-height=&quot;359&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p7byR/btreFS7UHgb/yUyCkAz5XAvSTKcE0vCUKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p7byR/btreFS7UHgb/yUyCkAz5XAvSTKcE0vCUKk/img.png&quot; data-alt=&quot;갑자기 이게 무슨 그림인가 싶겠지만...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p7byR/btreFS7UHgb/yUyCkAz5XAvSTKcE0vCUKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp7byR%2FbtreFS7UHgb%2FyUyCkAz5XAvSTKcE0vCUKk%2Fimg.png&quot; data-origin-width=&quot;903&quot; data-origin-height=&quot;359&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;갑자기 이게 무슨 그림인가 싶겠지만...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우져가 화면을 렌더링하기 위해서는 복잡다단한 과정을 거친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 그나마 간략하게 표현했던 것이 &lt;a href=&quot;https://blinders.tistory.com/92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[CSS] CSS Trigger&lt;/a&gt;에 이미지로 넣었던 Blink(크로미움의 렌더링 엔진)의 Rendering Pipeline이었는데, 그 세부과정을 조금 더 뜯어보면 위와 같은 절차가 포함되어있다. &lt;b&gt;렌더링하려는 HTML을 파싱해서 DOM Tree를 구성하고, DOM Tree와 CSSOM Tree를 하나로 합쳐서 Render Tree가 구성되고, 그 Render Tree를 바탕으로 화면에 표현될 Layer가 구성&lt;/b&gt;되게 되는데...!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스팅에서&lt;b&gt; 우리가 주의깊게 봐야 할 포인트가 바로 이 &lt;span style=&quot;color: #006dd7;&quot;&gt;Layer&lt;/span&gt;&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Layer라는 건 말그대로 '층'의 의미를 가진 형태인데, 이 '층'의 개념이 브라우져 렌더링시 도입되는 이유는 z축을 활용하는 3차원의 개념을 렌더링 과정에 삽입하기 위해서라고 이해하면된다. 좀 더 정확히 말하자면 Paint Layer는 Stacking Context를 구현하기 위한 적용방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stacking Context. &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN에는 쌓임 맥락&lt;/a&gt;...이라는 오묘한 표현으로 번역이 되어있는데, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;HTML요소들을 사용자 기준으로 Z축을 세우기위해 적용된 것&lt;/b&gt;&lt;/span&gt;으로써, 가장 대표적인 사용법은 CSS의 z-index 값을 활용하여 화면을 구성하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 코드는&lt;/p&gt;
&lt;pre id=&quot;code_1631196025162&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;body&amp;gt;
    &amp;lt;div style=&quot;position: absolute; width: 200px; height: 200px; left: 0;top: 0; background-color: crimson;&quot;&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div style=&quot;position: absolute; width: 100px; height: 100px; left: 100px;top: 100px; background-color: cornflowerblue;&quot;&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;274&quot; data-origin-height=&quot;281&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bowa6q/btreDTzuirk/tioum1eXQ4kANUT77A1OYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bowa6q/btreDTzuirk/tioum1eXQ4kANUT77A1OYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bowa6q/btreDTzuirk/tioum1eXQ4kANUT77A1OYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbowa6q%2FbtreDTzuirk%2Ftioum1eXQ4kANUT77A1OYK%2Fimg.png&quot; data-origin-width=&quot;274&quot; data-origin-height=&quot;281&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략 이런형태로 브라우져에 렌더링되게 되는데, 사용자인 우리의 시선(Z축)으로 브라우져를 내려다보는 입장에서 보자면, 파란 사각형 뒤에 렌더링된 빨간 사각형의 일부 영역을 볼 수 없고 이와 같은 형태를 Stacking Context 라고해서 계층 구조를 띈다고 말하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Paint Layer는 Stacking Context를 위한 '층'으로 활용&lt;/b&gt;&lt;/span&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;Paint Layer로 구성되는 '층'에서 GPU가 처리해야 하는 층이 있다면, Graphics Layer를 구성&lt;/b&gt;&lt;/span&gt;하게 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Paint Layer 와 Graphics Layer가 되기 위한 Trigger&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 그럼 다시 이 포스팅의 본론으로 돌아와보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숱한 글들에서 opacity, transform를 활용하면 reflow와 repaint 가 발생하지 않기때문에 브라우져의 불필요한 연산을 줄임으로써 최적화하는 방안으로 활용 할 수 있다, 라는 포인트가 유효해지는 이유는 뭘까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐, 사실 눈치가 빠른 분이라면 이미 눈치를 챘을 것 같은데 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Layer에 해당 요소가 적재되는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Paint Layer는 기본적으로 1개로 구성되며 CPU가 렌더링에 주효한 역할을 하게 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;일반적으로 좌표 공간이 동일한 Layout Object는 동일한 Paint Layer에 적재&lt;/b&gt;&lt;/span&gt;되게 되어있는데, 우리는 아래와 같은 Trigger를 바탕으로 Paint Layer를 층층이 구성 할 수 있다(이 Trigger들은 사실 Stacking Context를 충족하는 Trigger이다)&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1. 문서의 루트요소인 &amp;lt;html&amp;gt;&lt;br /&gt;2. position이 absolute 또는 relative이고, z-index가 auto가 아닐때.&lt;br /&gt;3. position이 fixed 또는 sticky인 요소&lt;br /&gt;4. 플렉스(flexbox) 컨테이너의 자식 요소 중 z-index가 auto가 아닐때.&lt;br /&gt;5. 그리드(grid) 컨테이너의 자식 요소 중 z-index가 auto가 아닐때.&lt;br /&gt;6. opacity가 1보다 작을 때&lt;br /&gt;7. mix-blend-mode가 normal이 아닐 때.&lt;br /&gt;8. 다음 속성 중 하나라도 none이 아닐 때 : transform, filter, perspective, clip-path, mask&lt;br /&gt;9. isolation이 isolate일 때.&lt;br /&gt;10. -webkit-overflow-scrolling이 touch일 때.&lt;br /&gt;11. will-change의 값으로 초기값이 아닐 때 새로운 Stacking Context를 생성하는 속성을 지정했을 경우&lt;br /&gt;12. contain이 layout, paint 또는 둘 중 하나를 포함하는 값(strict, content등)인 경우&lt;br /&gt;13. 화면에 보이지 않지만 층을 이룰 때&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자...여기서 &lt;b&gt;6번을 주목&lt;/b&gt;해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;opacity가 1보다 작을 때&lt;/b&gt;, 라는 항목이 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 opacity를 0.99로 줬을 때 reflow가 실제로 발생하지 않는 것을 보았다. 그리고 이제는 왜 reflow가 왜 발생하지않았는지를 알게되었다. 바로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;opacity가 1미만의 값으로 설정되었기 때문에 해당 요소가 별도의 Paint Layer을 구성했기 때문&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Paint Layout의 Trigger가 위와 같다면, 이젠 &lt;b&gt;Graphics Layer의 Trigger&lt;/b&gt;를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Graphics Layer는 화면을 렌더링 할 때 GPU의 도움을 얻는 층이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU의 도움을 받으면 좋은 점은, CPU에 몰빵되어있던 렌더링 연산을 나눠서 함께한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 마치 땅따먹기를 하듯 GPU에 건내줄 일감을 선정하는 기준은 아래와 같다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1. &amp;lt;video&amp;gt; 혹은 &amp;lt;canvas&amp;gt; 태그 사용&lt;br /&gt;2. 3D transform 요소 적용&lt;br /&gt;3. animation 이나 transition 사용&lt;br /&gt;4. will-change로 opacity, transform, top, left, bottom, right등이 정의된 경우&lt;br /&gt;5. iFrame일 경우&lt;br /&gt;6. flash와 같은 일부 플러그인&lt;br /&gt;7. backface-visibility 가 hidden일 경우&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 그래서, 결론.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 &lt;b&gt;CSS의 요소인 opacity나 transform을 단순 활용하는 것만으로는 우리가 기대하고 있던 '렌더링 연산을 줄임으로써 최적화'라는 목적은 달성 할 수가 없다&lt;/b&gt;. 화면의 렌더링 과정, 그리고 Layer 구성이 어떻게 되는지. 이 요소에 이 값을 줬을때 Paint Layer에 들어가는지, Graphics Layer에 들어가는지에 대한 명확한 확인이 필요하며...또한 무조건적으로&amp;nbsp; GPU의 도움을 받고자 Graphics Layer에 넣기위해 animation이나 transition을 쓰기보단, transition을 쓰더라도 reflow를 발생시키는 기하학적 요소들은 최대한 피하는 방안을 고려하는 등, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;다각적인 입장에서 늘 설계하고 개발을 해야한다&lt;/b&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;-1. 부록 : 그래서 repaint는 언제 발생하는거에요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굳이 설명을 해야할까, 싶은 생각이 들었지만...이왕지사 시작한 거 추가적인 설명을 덫붙이기위해 부록을 추가한다. 나는 분명 위에서 이런 말을 했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;opacity라는 스타일의 변경은 내가 함정에 빠졌던 윗 스크린샷과 같이 reflow부터 발생하기도하지만, &lt;b&gt;때로는 repaint부터 발생하기도&lt;/b&gt;하고, 또 때로는 reflow&amp;amp;repaint 없이 composite 단계에서 GPU의 도움을 받기도 한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reflow부터 발생하는 예제와 reflow&amp;amp;repaint가 발생하지 않는 예제를 본문에서 설명했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 opacity를 변경하면서도 repaint가 발생하는 경우에 대해선 설명하지 않았는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상황을 억지로 발생시켜보기 위해 style 태그에 아래와 같은 코드를 적용했다.&lt;/p&gt;
&lt;pre id=&quot;code_1631203550603&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;style&amp;gt;
  .app {
    display: flex;
    z-index: 1000;
  }
  .text{
    z-index: 2000;
    opacity: 1;
  }
  .opa{
    opacity: 0.3;
  }
&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;148&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UdAXA/btreCDcIKIj/GMxwyK8s4xM739tqNqWsCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UdAXA/btreCDcIKIj/GMxwyK8s4xM739tqNqWsCk/img.png&quot; data-alt=&quot;repaint 발생!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UdAXA/btreCDcIKIj/GMxwyK8s4xM739tqNqWsCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUdAXA%2FbtreCDcIKIj%2FGMxwyK8s4xM739tqNqWsCk%2Fimg.png&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;148&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;repaint 발생!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러자 repaint가 발생하는 걸 performance 탭을 통해 확인 할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드의 경우 reflow가 발생했던 코드에서 z-index와 display flex 요소가 추가되었는데, 이는 &lt;b&gt;PaintLayer의 층 구분 조건 중 &lt;span style=&quot;color: #006dd7;&quot;&gt;플렉스(flexbox) 컨테이너의 자식 요소 중 z-index가 auto가 아닐때&lt;/span&gt;를 충족한 경우&lt;/b&gt;라고 보면 된다. 그래서 실제로 opacity가 1에서 0.3으로 변경되는 코드임에도 불구하고 repaint가 발생하고 있는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고사이트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;a href=&quot;https://snyung.com/content/%EC%9B%B9%20%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%20%EC%9E%91%EB%8F%99%20%EC%9B%90%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Browser] 웹 브라우저 작동 원리&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;a href=&quot;https://www.alibabacloud.com/blog/front-end-performance-optimization-with-accelerated-compositing-part-1_594194&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Front-End Performance Optimization(Alibabacloud)&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;a href=&quot;https://chromium.googlesource.com/chromium/src/+/refs/heads/main/third_party/blink/renderer/core/paint/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Chromium blink official Readme&lt;/a&gt; &amp;amp;&amp;nbsp;&lt;a href=&quot;https://chromium.googlesource.com/chromium/src/+/refs/heads/main/third_party/blink/renderer/platform/graphics/compositing_reasons.h&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Chromium compositing_reasons.h&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>CSS</category>
      <category>Front-end</category>
      <category>frontend</category>
      <category>개발</category>
      <category>개발자</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/93</guid>
      <comments>https://blinders.tistory.com/93#entry93comment</comments>
      <pubDate>Thu, 9 Sep 2021 23:32:20 +0900</pubDate>
    </item>
    <item>
      <title>[210907] 내가 구독중인 개발 관련 서비스들</title>
      <link>https://blinders.tistory.com/94</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. awesome-devblog&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 개발관련 기술 포스팅을 검색하다보면 유독 Velog에 포스팅된 것들이 많이 나오길래,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스마트폰 기변병마냥 블로그를 한 번 더 갈아타야할때인가 싶어서 이래저래 살펴보다가...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 내가 쓰는 글 스타일에는 티스토리가 적격인 것 같아서 스테이하게됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그렇게 리서치하는 과정에서&amp;nbsp;&lt;a href=&quot;http://daily-devblog.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;awesome-devblog&lt;/a&gt; 라는 서비스를 알게됐는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;250&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxZSN1/btrd7TgWmA7/f1vI2zA6MeXWJMcMCYe3Q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxZSN1/btrd7TgWmA7/f1vI2zA6MeXWJMcMCYe3Q0/img.png&quot; data-alt=&quot;http://daily-devblog.com/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxZSN1/btrd7TgWmA7/f1vI2zA6MeXWJMcMCYe3Q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxZSN1%2Fbtrd7TgWmA7%2Ff1vI2zA6MeXWJMcMCYe3Q0%2Fimg.png&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;250&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;http://daily-devblog.com/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 형태로&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 구독받을 이메일만 입력하면&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;매일 오전 10시에 기술 블로거들이 전날 포스팅한 내용이 리스트 형식으로 메일로 도착&lt;/b&gt;&lt;/span&gt;하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;702&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tqQob/btrelRhmnYH/Ozvcof43xrxfMIt4tEQk40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tqQob/btrelRhmnYH/Ozvcof43xrxfMIt4tEQk40/img.png&quot; data-alt=&quot;2021.09.07 오전 10시에 받은 메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tqQob/btrelRhmnYH/Ozvcof43xrxfMIt4tEQk40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtqQob%2FbtrelRhmnYH%2FOzvcof43xrxfMIt4tEQk40%2Fimg.png&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;702&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2021.09.07 오전 10시에 받은 메일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저렇게 메일로 받은 포스팅을 클릭해서 들어가면 해당 포스팅이 나오는 형식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어릴때 등교하려고 집 문을 열면, 현관앞에 놓여진 조간신문같은 느낌인건데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기대해던 것보다 괜찮아서 점심식사후나 출퇴근 버스와 같은 여유시간에 관심가는 포스팅을 읽기에좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유일한 단점이라면...등재된 모든 포스팅을 받아보는 형식이기때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백엔드든 프론트엔드든 도커든 리눅스든 알고리즘이든,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 분야에 관련된 포스팅만 받아볼 수 없다는게 단점이라면 단점이지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역으로 생각해보면 &lt;b&gt;다양한 분야로 저변을 확대해주고&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;계속해서 배워나가야하는 개발분야의 특성상 국한된 시야를 넓혀&lt;/b&gt;주기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;받아들이는 이의 마인드에따라 충분히 장점이 될 수 있다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더불어, 요근래 오늘은 또 뭘 포스팅해야 재밌을까,를 고민하던 &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;나도 오늘 오전에 awesome-devblog에 기술블로거로 등재&lt;/b&gt;&lt;/span&gt;를 하였다(아마 내일 오전 10시면 내 메일로 이 글도 받아보게 되겠지?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;awesome-devblog에 본인의 기술 블로그를 등재하는 법은 전혀 어렵지않다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 문장으로 요약하자면 awesome-devblog의 Github 레파지토리에서 folk를 뜨고 본인의 브랜치를 만든 후, 설정파일(db.yml)에 블로그 정보와 같은 간단한 정보를 입력하고 Pull Request만 생성해서 Merge 되기만을 기다리면 된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Github과 블로그 등록하는 가이드 링크&lt;br /&gt;&lt;/b&gt;&lt;a href=&quot;https://github.com/sarojaba/awesome-devblog&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;awesome-devblog Github&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://soobaaaam.tistory.com/5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;awesome-devblog에 블로그 등록하는 법&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나도 위 가이드를 따라서 했는데 folk부터 최종 Merge까지 20분도 채 되지 않은 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(PR에 대한 Merge도 굉장히 빨리 해주신다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술 블로그를 하시는 분이라면, 이참에 본인의 포스팅을 좀 더 많은 사람들에게 공유도 할 겸 등재해보시는 것을 추천드린다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Javascript Weekly, Frontend Focus&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이런 &lt;b&gt;개발관련 구독서비스는 이미 오래전&lt;/b&gt;부터 받아보고 있었는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1044&quot; data-origin-height=&quot;507&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEH0JB/btree4JiT0I/luOgkjwfG60WmbFSaO2Fj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEH0JB/btree4JiT0I/luOgkjwfG60WmbFSaO2Fj1/img.png&quot; data-alt=&quot;Javascript Weekly, Frontend Focus&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEH0JB/btree4JiT0I/luOgkjwfG60WmbFSaO2Fj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEH0JB%2Fbtree4JiT0I%2FluOgkjwfG60WmbFSaO2Fj1%2Fimg.png&quot; data-origin-width=&quot;1044&quot; data-origin-height=&quot;507&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Javascript Weekly, Frontend Focus&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 &lt;a href=&quot;https://javascriptweekly.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Javascript Weekly&lt;/a&gt;와 &lt;a href=&quot;https://frontendfoc.us/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Frontend Focus&lt;/a&gt;라는 서비스인데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 서비스들도 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;메일만 입력해두면 매주 1회 아래와 같은 내용의 메일을 받아 볼 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;944&quot; data-origin-height=&quot;587&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wgZsE/btrehCes4S3/liAycwVA8LKFZ7ck9ElRI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wgZsE/btrehCes4S3/liAycwVA8LKFZ7ck9ElRI0/img.png&quot; data-alt=&quot;저번 주에 받은 메일들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wgZsE/btrehCes4S3/liAycwVA8LKFZ7ck9ElRI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwgZsE%2FbtrehCes4S3%2FliAycwVA8LKFZ7ck9ElRI0%2Fimg.png&quot; data-origin-width=&quot;944&quot; data-origin-height=&quot;587&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;저번 주에 받은 메일들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유일한 단점은 내용이 전부 영어라는거지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이해하지 못 할 수준으로 어려운 내용은 아니기에 충분히 읽고 이해할 수준이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(여담이지만 요근래 기술관련 영어를 툴로 번역해보니, 구글보단 파파고가 더 좋은 거 같더라)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 나는 Javascript와 Frontend쪽으로만 구독중인데, &lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;혹시 다른 분야의 구독 서비스는 없나요? 라는 의문을 가지실 분들을 위해 좀 더 소개&lt;/b&gt;&lt;/span&gt;하자면...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 서비스는 &lt;a href=&quot;https://cooperpress.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cooperpress 라는 Team&lt;/a&gt;에서 발행중인 건데, 아래 링크를 따라 들어가보면 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Node, React, Golang, Ruby등 다양한 분야의 서비스를 제공하고 있으니 입맛대로 구독&lt;/b&gt;&lt;/span&gt;하시면 될 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cooperpress.com/publications/&quot;&gt;https://cooperpress.com/publications/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1630985675124&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Publications&quot; data-og-description=&quot;Our Publications We help developers, and the companies they work for, stay up-to-date via our range of email digests. Reaching a combined audience of over 470,000 subscribers. Our newsletters enjoy high levels of engagement, seeing net open rates between 3&quot; data-og-host=&quot;cooperpress.com&quot; data-og-source-url=&quot;https://cooperpress.com/publications/&quot; data-og-url=&quot;https://cooperpress.com/publications/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cooperpress.com/publications/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cooperpress.com/publications/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Publications&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Our Publications We help developers, and the companies they work for, stay up-to-date via our range of email digests. Reaching a combined audience of over 470,000 subscribers. Our newsletters enjoy high levels of engagement, seeing net open rates between 3&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cooperpress.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/개발일지</category>
      <category>awesome-devblog</category>
      <category>cooperpress</category>
      <category>dev</category>
      <category>Weekly</category>
      <category>개발</category>
      <category>구독</category>
      <category>웹</category>
      <category>웹개발</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/94</guid>
      <comments>https://blinders.tistory.com/94#entry94comment</comments>
      <pubDate>Tue, 7 Sep 2021 12:36:24 +0900</pubDate>
    </item>
    <item>
      <title>[CSS] CSS Triggers</title>
      <link>https://blinders.tistory.com/92</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0. Rendering Pipeline&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우져는, HTML을 어떻게 해석해서 우리의 눈에 버튼과 텍스트 필드와 아이콘과 테이블과, 지금 읽고 있는 이 글을 보여주게될까? 보통 이에 대한 설명을 단순하게는 'HTML을 해석해서 보여준다'라고들하지만, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;순차적인 단계의 입장에서보면 대략 아래와 같은 절차&lt;/b&gt;&lt;/span&gt;를 거치게된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;259&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3TLwS/btrdT8cNdBI/SLtlIWsJAl9sXJHN6xIh51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3TLwS/btrdT8cNdBI/SLtlIWsJAl9sXJHN6xIh51/img.png&quot; data-alt=&quot;https://www.chromium.org/blink&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3TLwS/btrdT8cNdBI/SLtlIWsJAl9sXJHN6xIh51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3TLwS%2FbtrdT8cNdBI%2FSLtlIWsJAl9sXJHN6xIh51%2Fimg.png&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;259&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.chromium.org/blink&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림은 &lt;b&gt;크로미움에서 사용하는 Blink의 렌더링 엔진&lt;/b&gt;에서 제공하는 그림이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우져 별로 사용하는 렌더링 엔진은 다 다르지만, 대부분 위와같은 프로세스에서 크게 벗어나지 않는다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;* 브라우저별 Rendering Engine&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Blink&lt;/b&gt; : 크롬, 신형 Edge&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Gecko&lt;/b&gt; : 파이어폭스&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;WebKit&lt;/b&gt; : 사파리&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Trident&lt;/b&gt; : IE&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;EdgeHTML&lt;/b&gt; : 구형 Edge&lt;/span&gt;&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 화면의 요소는 언제든 변경될 수 있다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 어떤 웹 서비스에 접속했다고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 서비스를 이용하면, 우리가 보는 화면의 UI는 계속해서 변할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탭을 누르면 보여지던 탭은 사라지고 선택한 탭의 내용이 나오기도하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글을 쓰다가 임시저장 버튼을 누르면 체크표시가 나올수도있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;햄버거 아이콘을 눌렀더니 상세한 메뉴 리스트가 나올수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든 UI적 요소들의 변경은 현재 우리가 보고있는 '화면'에 반영되어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경된 요소가 화면에 '반영'되어야한다는 것은, 기존에 있던 &lt;b&gt;요소(element)들에 변경이 있어야한다는 것이고 그러한 변경점들이 브라우져에 표현&lt;/b&gt;되어야 한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 설명하길, 새로운 HTML이 로딩되면 브라우져의 Rendering Pipeline이 동작해서 우리가 지금 이 글을 보고 있듯이 표현해준다고 설명을 했었다. 그렇다면 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;일부 UI가 변경되는 것도 Rendering Pipeline을 타야할까?&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 질문에 대한 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;답은 Rendering Pipeline이 동작하는 건 맞지만 모든 단계가 동작하는 건 아니다&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. reflow, repaint, composite&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅을 이해하기 위해 우리가 알아둬야 할 키워드는 3가지다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;reflow, repaint, composite.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 키워드들은 Rendering Pipeline 과정에 포함된 것이라고 봐도 되는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 위에 Rendering Pipeline 그림에선 해당 키워드들이 없어요? 라는 의문을 가질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그에 대한 답은&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 're'라는 prefix&lt;/b&gt;&lt;/span&gt;에서 해답을 찾을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;re&lt;/b&gt;&lt;/span&gt;flow, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;re&lt;/b&gt;&lt;/span&gt;paint, Composite&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;(Composite는 re가 붙지 않지만, 그러려니 하자)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면의 요소는 언제든 변경될 수 있다, 라고 앞서 말했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이와 연결지어서 '변경'되기에 're'라는 prefix가 과정의 명칭으로 붙는다고 이해하면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실, Rendering Pipeline과 해당 키워드들을 매핑해보자면, 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;291&quot; width=&quot;630&quot; height=&quot;253&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oIn1o/btrd03wNx9K/Yibq1zlA3lGGNkbR6X4RrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oIn1o/btrd03wNx9K/Yibq1zlA3lGGNkbR6X4RrK/img.png&quot; data-alt=&quot;리,리,리자로 시작하는 말은&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oIn1o/btrd03wNx9K/Yibq1zlA3lGGNkbR6X4RrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoIn1o%2Fbtrd03wNx9K%2FYibq1zlA3lGGNkbR6X4RrK%2Fimg.png&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;291&quot; width=&quot;630&quot; height=&quot;253&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;리,리,리자로 시작하는 말은&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;layout 단계를 reflow, paint 단계를 repaint, compositor thread 단계를 composite&lt;/b&gt;&lt;/span&gt;라고 이해하면 된다. 그리고 여기서 우리가 발견할 수 있는 점이 바로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;본 포스팅이 핵심인데, 만약 Reflow가 발생했다면? 당연하게도 다음 단계인 Repaint, Composite도 연이어 발생 해야한다는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 기존에 UI적인 어떤 변경점이 있었는데, 그 변경점에 의해 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Reflow 단계부터 발생하던 과정을 Repaint부터 발생하게 할 수 있다면? 당연하게도 불필요한 연산이 소거되는 것&lt;/b&gt;&lt;/span&gt;이다. 이런 과정을 하나하나 거치며 개발하는 서비스가 적은 리소스로 최대의 효과를 얻게 하는 것을 우리는 흔히 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;최적화&lt;/b&gt;&lt;/span&gt;라고 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Trigger를 당겨보자.&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;299&quot; data-filename=&quot;99CBF1505E843CD903.gif&quot; width=&quot;384&quot; height=&quot;236&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjHF5K/btrdXAIRLdy/nLQrKeXCfC52CCgbxskrPk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjHF5K/btrdXAIRLdy/nLQrKeXCfC52CCgbxskrPk/img.gif&quot; data-alt=&quot;빵야 빵야 빵야 빵야&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjHF5K/btrdXAIRLdy/nLQrKeXCfC52CCgbxskrPk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bjHF5K/btrdXAIRLdy/nLQrKeXCfC52CCgbxskrPk/img.gif&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;299&quot; data-filename=&quot;99CBF1505E843CD903.gif&quot; width=&quot;384&quot; height=&quot;236&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;빵야 빵야 빵야 빵야&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reflow, repaint, composite의 각 단계를 발생시키는 조건을 우리가 알면, 우리는 우리가 원하는대로 Rendering Pipeline의 단계를 설계하고 개발하여 호출할 수 있을 것이다. 각 단계들이 호출되는 조건을 간략히 설명하자면 다음과 같이 요약할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;reflow&lt;/b&gt; : 높이, 너비, 위치와 같이 화면의 구조(layout)적인 요소에 변경이 가해질때(흔히 기하학적 요소)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;repaint&lt;/b&gt; : 구조(layout)외적으로 보여지는 요소가 변경될 때(색상, 배경색등)&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;composite&lt;/b&gt; : 현재는 opacity, transform 2개의 요소값에 의해 호출(출처 : Google Web Render Performance)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 단계의 호출을 가늠짓는 정의는 위와같이 이해하면되는데, 사실 개념적으로 저렇게 이해하더라도 실제 우리가 개발할 때 각 CSS요소들이 정확히 어떤 단계를 호출하는지를 외우고 있기엔 쉽지않다. 더구다나 본 포스팅에선 크로미움의&amp;nbsp; 렌더링 엔진인 Blink를 기준으로 설명했지만...각 브라우져들은 서로 다른 렌더링 엔진을 사용하고있고 그에따라 CSS요소가 트리거해서 호출되는 Rendering Pipeline의 단계도 다를 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어 transform은 composite 단계를 호출한다고 설명했지만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;283&quot; width=&quot;595&quot; height=&quot;207&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mLarU/btrd0GBPuLE/zDkVNLEvzY3mBBaD8fJPxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mLarU/btrd0GBPuLE/zDkVNLEvzY3mBBaD8fJPxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mLarU/btrd0GBPuLE/zDkVNLEvzY3mBBaD8fJPxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmLarU%2Fbtrd0GBPuLE%2FzDkVNLEvzY3mBBaD8fJPxK%2Fimg.png&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;283&quot; width=&quot;595&quot; height=&quot;207&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림의 우측을 보면 'W'라고 표기된 세로줄이 있는데, W는 Webkit을 의미하며 Webkit은 사파리 브라우저에서 사용하는 렌더링 엔진이다. 그리고 W 아래의 햄버거 아이콘같은 곳을 보면, B와 G는 맨 아래만 색칠되어있는데 W는 모두 색칠되어있다. 이는, &lt;b&gt;Webkit에서는 transform의 변경시 reflow, repaint, composite가 모두 발생한다는 의미&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(참고로 B는 크로미움의 Blink, G는 파이어폭스의 Gecko, E는 EdgeHTML로 구형 Edge의 엔진이다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. CSS Triggers&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 동일한 CSS 요소더라도 브라우져별로 동작이 다르기때문에, 이를 잘 정리해놓은 사이트가 존재하는데...그 사이트가 바로 본 포스팅의 이유인 &lt;a href=&quot;https://csstriggers.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSS Triggers&lt;/a&gt; 라는 사이트다.&lt;/p&gt;
&lt;figure id=&quot;og_1630732827898&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;CSS Triggers&quot; data-og-description=&quot;@PROPERTY_DESCRIPTION@ B G W E Change from default B G W E Subsequent updates&quot; data-og-host=&quot;csstriggers.com&quot; data-og-source-url=&quot;https://csstriggers.com/&quot; data-og-url=&quot;https://csstriggers.com/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://csstriggers.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://csstriggers.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CSS Triggers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;@PROPERTY_DESCRIPTION@ B G W E Change from default B G W E Subsequent updates&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;csstriggers.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고사이트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 네이버 D2 : &lt;a href=&quot;https://d2.naver.com/helloworld/5237120&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;최신 브라우저의 내부 살펴보기 3 - 렌더러 프로세스의 내부 동작&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 크로미움 Doc : &lt;a href=&quot;https://docs.google.com/document/d/1aitSOucL0VHZa9Z2vbRJSyAIsAz24kX8LFByQ5xQnUg/edit#&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How Blink works&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>CSS</category>
      <category>Front-end</category>
      <category>frontend</category>
      <category>개발</category>
      <category>웹</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/92</guid>
      <comments>https://blinders.tistory.com/92#entry92comment</comments>
      <pubDate>Sat, 4 Sep 2021 17:20:15 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] class도 호이스팅이 되나요(feat. lexical environment)</title>
      <link>https://blinders.tistory.com/90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기억도 나지않는 어느 날엔가, 누군가 내게 제목과 같은 질문을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&quot;Javascript의 Class도 호이스팅이 되나요?&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 내가 답했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&quot;네, Class도 당연히 호이스팅&lt;/b&gt;&lt;b&gt; 됩니다.&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러자 질문자가 되물었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;하지만 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;아래와 같은 코드는 에러&lt;/b&gt;&lt;/span&gt;를 뱉는걸요?&quot;&lt;/p&gt;
&lt;pre id=&quot;code_1629947074903&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var foo = new Foo(1, 2); //ReferenceError

class Foo {
   constructor(x, y) {
      this.x = x;
      this.y = y;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;네, 에러를 뱉겠죠. &lt;b&gt;Foo class의 선언보다 사용이 앞섰으니까&lt;/b&gt;요.&quot;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;57&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnGwdK/btrdgR3Qbme/1gTOEiDx1SNDIidsJ7SxRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnGwdK/btrdgR3Qbme/1gTOEiDx1SNDIidsJ7SxRk/img.png&quot; data-alt=&quot;실제 new Foo가 뱉는 에러&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnGwdK/btrdgR3Qbme/1gTOEiDx1SNDIidsJ7SxRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnGwdK%2FbtrdgR3Qbme%2F1gTOEiDx1SNDIidsJ7SxRk%2Fimg.png&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;57&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실제 new Foo가 뱉는 에러&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0. 누구에게나 처음은 있다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 일화가 본 포스팅을 작성하게 된 이유다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마도 Javascript를 시작하는 길목에서 처음 호이스팅이라는 개념을 이해할 때면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 아래와 같은 코드를 보게 될 것이고&lt;/p&gt;
&lt;pre id=&quot;code_1629947367473&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(str); // undefined

var str = &quot;hello&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로 str이라는 변수를 정의하지 않은 시점에 콘솔로 값을 출력했을 때, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;에러가 아닌 undefined라는 값이 출력되는 것은 'str'이라는 변수가 '호이스팅'되서 그렇다,라고 배웠을 것&lt;/b&gt;&lt;/span&gt;이다. 그리고 혹자는 &lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;호이스팅의 개념이 Javascript 내부에 사용되는 변수나 함수를 소스코드 위로 끌어올려주는 것&lt;/b&gt;&lt;/span&gt;, 이라고 정의를 내리곤한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 본 몇몇 책에도 이렇게만 설명되어있었다. 사실 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;이 말은 반은 맞고 반은 틀린 말&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, 입문자의 이해도를 높이려는 관점에서보자면 위와 같은 설명보다 적절한 것은 없는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 하루이틀 Javascript를 사용할 것도 아니고, 업으로 계속 써야하는 입장에서보자면 한 발자국 더 나아가서 호이스팅에 대한 명확한 개념적 이해를 가져야한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 내로남불? ㄴㄴ 쌤쌤.&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;337&quot; width=&quot;416&quot; height=&quot;270&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dZqPPU/btrdjdeuY0a/3RBJJ4CpfwMAKEaoYxxCC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dZqPPU/btrdjdeuY0a/3RBJJ4CpfwMAKEaoYxxCC0/img.png&quot; data-alt=&quot;전설의 베컴형의 &amp;amp;#39;난 둘 다&amp;amp;#39;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dZqPPU/btrdjdeuY0a/3RBJJ4CpfwMAKEaoYxxCC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdZqPPU%2FbtrdjdeuY0a%2F3RBJJ4CpfwMAKEaoYxxCC0%2Fimg.png&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;337&quot; width=&quot;416&quot; height=&quot;270&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;전설의 베컴형의 '난 둘 다'&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class로 정의한 Foo는 선언보다 앞서서 사용되었을 때 에러였고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var로 정의한 str은 선언보다 앞서서 사용했음에도 에러가 발생하지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;이미 결론을 밝혔듯이 Class도 var도 호이스팅&lt;/b&gt;&lt;/span&gt; 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 &lt;b&gt;왜 누구는 에러고 누구는 에러가 아닐까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 이해하기 위해선 호이스팅에 대한 정확한 개념을 알아야한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Lexical Environment&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술 관련 포스팅을 쓰려면 우선, &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;나부터가 그 개념에 대한 명확한 이해를 가져야&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 늘 책을 한 번 더 살펴보거나 다른 분들이 정의한 내용들을 리서치하고 참고 할 만한 자료가 있으면 기억해두곤하는데...보통 이 과정에서 '&lt;b&gt;아, 이 개념에 대해선 이 사람보다 잘 정리 할 순 없을 거 같다'라는 생각이 들게 만드는 분들&lt;/b&gt;이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 호이스팅과 Lexical Environment에 대해 리서치하면서 발견한,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아래 블로그가 딱 그에 해당&lt;/b&gt;했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dkje.github.io/2020/08/30/ExecutionContext/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dkje.github.io/2020/08/30/ExecutionContext/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 링크의 핵심주제는 사실, Execution Context(실행 컨텍스트)와 Call Stack(콜스택)에 대한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 그 과정에서 실행 컨텍스트가 동작하면서 발생되는 필수적인 것들...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까 &lt;b&gt;호이스팅과 Lexical Environment에 대한 설명이 그림을 바탕으로 정말 잘 설명&lt;/b&gt;이 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 위 링크를 가만히 보다보면...&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;141&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QNdTB/btrc7UO222Z/GNqtXcpfJAl7We36GYKgOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QNdTB/btrc7UO222Z/GNqtXcpfJAl7We36GYKgOK/img.png&quot; data-alt=&quot;let도 const도 호이스팅됩니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QNdTB/btrc7UO222Z/GNqtXcpfJAl7We36GYKgOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQNdTB%2Fbtrc7UO222Z%2FGNqtXcpfJAl7We36GYKgOK%2Fimg.png&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;141&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;let도 const도 호이스팅됩니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같은 문구를 볼 수 있는데,&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; 이는 틀린부분&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(댓글로도 어떤 분이 저 부분에 대한 정정 요청을 하셨는데, 글 쓰신 분이 아직 확인을 못 하셨나보다)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2-1. Lexical Environment&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 공유해 준 링크는 어쩌면, 누군가에겐 너무 복잡하게 느껴질 수도 있을 것 같아서 첨언하듯 직접 정리를 해보자면 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Javascript가 실행되면 Execution Context라는 것이 구성&lt;/b&gt;&lt;/span&gt;된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;An execution context is a specification device that is used to track the runtime evaluation of code by an ECMAScript implementation.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;출처 : ECMAScript(262) 9.4 Execution Contexts&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 현재 실행하려는 Javascript 코드가 동작 할 수 있는 환경이 구성되는 것으로, &lt;b&gt;우리가 흔히 Javascript 코드에서 사용하는 변수나 함수, this, arguments, scope등이 정상적으로 동작할 수 있도록 해주는 환경 같은 것&lt;/b&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이때, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;코드에서 활용되는 변수나 함수의 선언부들이 스캔되어 Lexical Environment라는 자료구조에 저장&lt;/b&gt;&lt;/span&gt;되게 된다. 이는 변수나 함수를 선언 이전에 사용할 수 있게 해주기 위함이며, &lt;b&gt;이러한 연유로 인해 호이스팅을 '변수와 함수들이 코드 위쪽으로 끌어올려 지는 것'이라고도 말하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(여기서 한 번 더....&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;변수나 함수를 선언 이전에 사용할 수 있게 해주기 위함인데 왜 class Foo는 에러...? 라는 의문에 대해서는 아래의 3. Temporal Dead Zone 에서 설명&lt;/b&gt;&lt;/span&gt;하겠다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Lexical Environment는 식별자(identifier)와 값(variable)이 매핑된 자료구조&lt;/b&gt; &lt;/span&gt;형태로써,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념적으론 아래와 같은 형태를 띄고있다.&lt;/p&gt;
&lt;pre id=&quot;code_1629953601823&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LexicalEnvironment = {
  Identifier:  &amp;lt;value&amp;gt;,
  Identifier:  &amp;lt;function object&amp;gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 실제로 아래와 같은 코드를 우리가 작성하였다면&lt;/p&gt;
&lt;pre id=&quot;code_1629960225335&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;helloWorld();  // prints 'Hello World!' to the console

function helloWorld(){
  console.log('Hello World!');
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 형태로 LexicalEnvironment가 정의되며&lt;/p&gt;
&lt;pre id=&quot;code_1629960256893&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;lexicalEnvironment = {
  helloWorld: &amp;lt; func &amp;gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Javascript내에서 helloWorld()라는 코드를 통해 해당 function의 호출되면,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LexicalEnvironment를 확인하여 해당 function을 정상적으로 호출하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Temporal Dead Zone&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 이제 그럼 다시 처음으로 돌아가서...아래와 같은 코드에서 왜 누구는 undefined고 누구는 ReferenceError인지를 알아보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1629965900042&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var foo = new Foo(1, 2); //ReferenceError

class Foo {
   constructor(x, y) {
      this.x = x;
      this.y = y;
   }
}

console.log(str); // undefined

var str = &quot;hello&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러기 위해선 &lt;b&gt;Temporal Dead Zone&lt;/b&gt; 이라는 개념을 알아야하는데, 이는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;우리가 사용하려는 변수 혹은 함수의 선언과 초기화 사이의 죽은 시간&lt;/b&gt;&lt;/span&gt;이라고 이해를 하면된다. 호이스팅은 Javascript 코드에서 선언된 변수 및 함수가, Lexical Environment라는 자료구조에 할당되는 것을 의미한다고 말했다. 여기서 &lt;b&gt;포인트는 바로 &lt;span style=&quot;color: #006dd7;&quot;&gt;선언&lt;/span&gt;이라는 키워드&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드에서 선언이 되었다는 건, 해당 변수/함수를 사용하겠다는 것이기 때문에 Lexical Environment에 적재된다. &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;근데 그렇게 사용 될 예정인 변수/함수의 초기화는 언제하는가?&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Foo라는 class의 초기화는, 분명 3번째 줄에 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;str이라는 변수의 초기화는, &quot;hello&quot;라는 값을 할당하는 시점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;실제로 사용하고자하는 변수/함수가 선언되었기때문에 Lexical Environment에 등재되지만, 그 것들이 참조해야하는 실질적인 '값'의 초기화는 이뤄지지 않은 것&lt;/b&gt;&lt;/span&gt;이다&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;(값이라기보단 참조해야 할 메모리의 위치라는 게 좀 더 정확지않을까 싶다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;변수/함수의 선언과 초기화의 사잇시간.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그 사잇시간이 바로 Temporal Dead Zone&lt;/b&gt;이라고 불리며, 만약 이 사잇시간에서 우리가 초기화되지 않은 변수/함수를 사용하려고하면, 당연하게도 해당 변수/함수가 참조해야 할 값(메모리)을 모르기 때문에 Reference Error가 발생하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어, 근데 var로 선언한 str은 왜 Reference Error가 아니고 undefined인가요? 라는 의문이 드는게 당연해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lexical Environment에 대한 설명을 다시 떠올려보자. Lexical Environment는 식별자(identifier)와 값(variable)이 매핑된 자료구조라고 설명을 했었다. 여기서 식별자는 당연하게도 코드에서 사용하고자 선언된 것들(var, let, const, class, 함수선언식)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 &lt;b&gt;Lexical Environment에 등재될 때의 값(variable)의 영역은?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;var의 특이점을 알 수 있는데 var로 선언된 대상은 undefined로 초기화가 이루어지게 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;let이나 const, class와 같은 여타 호이스팅 대상들은 undefined가 아니라 uninitialized로 초기화&lt;/b&gt;&lt;/span&gt;가 된다. 즉, 아래와 같은 형태로 말이다.&lt;/p&gt;
&lt;pre id=&quot;code_1629967211944&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;lexicalEnvironment = {
  Foo: &amp;lt;uninitialized&amp;gt;,
  str: undefined
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;undefined는 Javascript의 Primitive Type중에 하나이고, 실질적인 '값'으로써 인식하기 때문에 에러가 발생하지 않는다&lt;/b&gt;. 반면에, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;lt;uninitialized&amp;gt;로 선언된 변수/함수는 초기화되지 않았다는 에러를 발생하며 이와같이 &amp;lt;uninitialized&amp;gt;로 Lexical Environment의 값(variable)이 정의된 때를 Temporal Dead Zone&lt;/b&gt;&lt;/span&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(여기서 Zone이라고 부르는 이유는, 개인적인 추측이지만 결국 변수/함수가 가리키는 메모리의 영역(Zone)이 할당되지 않았기 때문이 아닐까...즉, 죽은 영역을 가리킨다는 의미가 아닐까 생각해본다)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 함수 표현식(Function Expression)은 호이스팅되지 않아요.&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1629967556959&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;helloWorld(); // TypeError: helloWorld is not a function

var helloWorld = function() {
  console.log('Hello World');
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같은 꼴을, 우리는 &lt;b&gt;함수 표현식(Function Expression)이라고 부르며 &lt;span style=&quot;color: #006dd7;&quot;&gt;함수 표현식은 호이스팅 되지 않는다. &lt;/span&gt;&lt;/b&gt;좀 더 정확하게 말하자면, &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;var로 선언된 helloWorld라는 변수 자체는 undefined로 호이스팅이 되지만&lt;/span&gt; 거기에 할당된 함수 자체는 호이스팅 대상이 아니기 때문&lt;/b&gt;에 helloWorld라는 함수를 정의하기도전에 helloWorld();의 형태로 함수를 호출하듯이 사용하면 에러가 발생하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드상으로 helloWorld()를 호출하는 시점에 helloWorld의 값은 undefined기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;마찬가지로 아래와 같은 클래스 표현식(Class Expression)도 호이스팅 되지않는다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629967862269&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let peter = new Person('Peter', 25); // ReferenceError: Person is  
                                     // not defined
console.log(peter);
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 위와같은 코드가 정상적으로 동작하게 하려면 아래와 같이 정의해주어야한다.&lt;/p&gt;
&lt;pre id=&quot;code_1629967916272&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let Person = class {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}
let peter = new Person('Peter', 25); 
console.log(peter); // Person { name: 'Peter', age: 25 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 결론&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;선언을 목적으로 사용된 것은 호이스팅&lt;/b&gt;&lt;/span&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;let도 const도 var도 class도 함수 선언식도, 다 호이스팅&lt;/b&gt;&lt;/span&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;표현식은 안 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;함수 표현식, 클래스 표현식은 호이스팅 되지 않는다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고사이트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;a href=&quot;https://dkje.github.io/2020/08/30/ExecutionContext/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[JS]Execution Context와 Call Stack&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;a href=&quot;https://blog.bitsrc.io/hoisting-in-modern-javascript-let-const-and-var-b290405adfda&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hoisting&amp;nbsp;in&amp;nbsp;Modern&amp;nbsp;JavaScript&amp;nbsp;&amp;mdash;&amp;nbsp;let,&amp;nbsp;const,&amp;nbsp;and&amp;nbsp;var&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>frontend</category>
      <category>Hoisting</category>
      <category>JavaScript</category>
      <category>lexical</category>
      <category>웹</category>
      <category>웹개발</category>
      <category>자바스크립트</category>
      <category>프론트엔드</category>
      <category>호이스팅</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/90</guid>
      <comments>https://blinders.tistory.com/90#entry90comment</comments>
      <pubDate>Thu, 26 Aug 2021 18:06:54 +0900</pubDate>
    </item>
    <item>
      <title>[미완][React.js &amp;amp; Vue.js] React의 데이터는 불변성이 중요하다.</title>
      <link>https://blinders.tistory.com/89</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;이 포스팅은 미완입니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;써놓은 포스팅임에도 불구하고 미완이라니, 그럼 굳이 왜 써놓는거지? 싶은 생각을 하실 수도 있는데...&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;사실 앞선 포스팅(&lt;u&gt;&lt;a href=&quot;https://blinders.tistory.com/88&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;Javascript의 불변성&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/u&gt;)에서 설레발치듯 '밑밥'이라는 표현을 써서 이렇게 빈 포스팅을 남겨두게 되었습니다(밑밥을 깔아뒀더니 순서상 다른 주제로 포스팅하기가 뭔가 애매해져서...이렇게 영역부터 차지해두려고 합니다)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;그래도 미완이지만 포스팅을 하는김에 또 썰을 풀어보자면, 이번 포스팅에서 다루고싶었던 주제는&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;React.js와 Vue.js에서 데이터를 바라보는 관점, 혹은 다루는 차이에 대해서 작성을 하려고 했습니다.&lt;br /&gt;&lt;br /&gt;저는 보통 기술 포스팅을 할 때면, 눈을 감고도 입에서 술술 나올만큼 완전히 체화된 지식을 바탕으로 포스팅하려하는 편입니다. 그러다보니, 아직 미진한 React의 지식을 바탕으로 쓰기엔, 본 포스팅에 모자람이 너무 많이보였고 그에따라 미완이라는 타이틀을 남겨두었습니다.&lt;br /&gt;&lt;br /&gt;아마 시간이 좀 더 흐른 뒤 React에 대한 이해도와 지식이 지금보다 더 짙어지게되면, 그때 아랫내용들을 더 보충해서 미완의 딱지를 때도록 하겠습니다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그래서 오늘 포스팅을 하려는 주제에 대해 간력하게나마 설명을 나열해보자면,&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;Vue.js에서는 배열형 데이터를 다룰 때, 아래와 같이 래핑된 메소드를 활용&lt;/span&gt;&lt;/b&gt;해야합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;push()&lt;/li&gt;
&lt;li&gt;pop()&lt;/li&gt;
&lt;li&gt;shift()&lt;/li&gt;
&lt;li&gt;unshift()&lt;/li&gt;
&lt;li&gt;splice()&lt;/li&gt;
&lt;li&gt;sort()&lt;/li&gt;
&lt;li&gt;reverse()&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이와 같은 메서드들은 배열의 변경을 감지하게 설계되어있고, 그에따라서 호출시 배열의 변경점을 기준으로 화면에 렌더링된 Vue의 갱신을 트리거하게 됩니다. 예를들어, 아래와 같은 코드가 있다고 한다면&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;!-- items : ['apple', 'banana', 'carrot'] --&amp;gt; 
&amp;lt;div&amp;gt; 
    &amp;lt;div v-for=&quot;(item, idx) in items&quot; :key=&quot;idx&quot;&amp;gt; 
        {{idx}} : {{item}} 
    &amp;lt;/div&amp;gt; 
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;198&quot; data-origin-height=&quot;133&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DJ3Zi/btrcVkfFEQe/GZTA6w69nLvNR6lZJfm2Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DJ3Zi/btrcVkfFEQe/GZTA6w69nLvNR6lZJfm2Ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DJ3Zi/btrcVkfFEQe/GZTA6w69nLvNR6lZJfm2Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDJ3Zi%2FbtrcVkfFEQe%2FGZTA6w69nLvNR6lZJfm2Ck%2Fimg.png&quot; data-origin-width=&quot;198&quot; data-origin-height=&quot;133&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이와 같은 형태로 렌더링되게 될 것입니다.&lt;br /&gt;&lt;br /&gt;이때, items라는 배열형 데이터에 'potato'라는 값을 추가하려 한다면 Vue파일 내의 메서드, 혹은 라이프사이클 어딘가에 아래와 같은 push 메서드를 활용한 코드를 추가해주면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;this.items.push('potato')&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;117&quot; data-origin-height=&quot;114&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pv8XH/btrc4FoPc5x/2opElge4TknAEkX8BWtxKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pv8XH/btrc4FoPc5x/2opElge4TknAEkX8BWtxKk/img.png&quot; data-alt=&quot;추가된 감자&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pv8XH/btrc4FoPc5x/2opElge4TknAEkX8BWtxKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpv8XH%2Fbtrc4FoPc5x%2F2opElge4TknAEkX8BWtxKk%2Fimg.png&quot; data-origin-width=&quot;117&quot; data-origin-height=&quot;114&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;추가된 감자&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;근데, 최근에 React.js에 대해 공부를 조금씩하다보니,&lt;br /&gt;이와 같은 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;배열형 데이터를 다룰 경우 React.js는 Vue.js와는 다른 형식을 취한다&lt;/span&gt;&lt;/b&gt;는 걸 알게되었습니다.&lt;br /&gt;&lt;br /&gt;윗 예제를 바탕으로 설명하자면, &lt;b&gt;Vue.js에서는 push나 pop과 같은 메서드를 바탕으로 원본 데이터에 변경&lt;/b&gt;사항이 있을 경우 리렌더링을 위한 트리거가 발동이 되지만, &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;React.js는 원본 데이터를 변경하는 작업을 지양하라고 가이드&lt;/span&gt;&lt;/b&gt;하고 있습니다. 그래서 위와 같이 Vue.js에서 push로 했던 로직과 동일한 상황을 발생시키려면, setState라는 메서드를 호출해야하는데, 이때 setState에 전달되는 배열은 &lt;b&gt;items.concat('potato')&lt;/b&gt; 라는 형태의 코드로 전달하게 됩니다.&lt;br /&gt;&lt;br /&gt;여기서 concat은 Javascript에서 새로운 배열을 리턴하는 함수인데요.&lt;br /&gt;즉, &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;원본 데이터인 'items'를 훼손하지않으면서 items에 새로운 요소인 'potato'를 추가한 새 배열을 리턴&lt;/span&gt;&lt;/b&gt;하여 'items'에 매핑함으로써, items라는 변수가 가리키는 값이 변경되었다고 캐치해내는 것입니다. 그림으로보면, 아래와 같은 꼴이 되는건데요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;463&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZZMHf/btrc2KcRX83/KaQRWKG4kMgR0Ed7tTs3A1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZZMHf/btrc2KcRX83/KaQRWKG4kMgR0Ed7tTs3A1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZZMHf/btrc2KcRX83/KaQRWKG4kMgR0Ed7tTs3A1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZZMHf%2Fbtrc2KcRX83%2FKaQRWKG4kMgR0Ed7tTs3A1%2Fimg.png&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;463&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;어, 이 그림은?!&lt;br /&gt;이전 포스팅인 &lt;u&gt;&lt;a href=&quot;https://blinders.tistory.com/88&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;Javascript의 불변성&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/u&gt;을 보고오신 분이라면, 익숙한 그림일거라고 생각합니다.&lt;br /&gt;그리고 바로 여기서, 제가 왜 불변성을 먼저 포스팅했는지가 드러나게 됩니다.&lt;br /&gt;&lt;br /&gt;기존에 items라는 변수는 ['apple','banana','carrot'] 라는 배열형 데이터를 '값'으로 가리키고있었고, 우리는 concat을 통해서 potato를 추가했기 때문에, 기존의 ['apple','banana','carrot']와는 전혀 다른 ['apple','banana','carrot','potato'] 라는 배열형 데이터를 '값'으로 가리키게 된 것이죠(아, 혹시나해서 덫붙입니다만...실제 메모리 한 곳에 저렇게 모든 배열이 들어가지는 않습니다. 배열의 각 인덱스별로 나뉘어서 들어갑니다, 그림은 예시를 위해서 저렇게 했을 뿐...)&lt;br /&gt;&lt;br /&gt;그리고 여기서 바로 '불변성(Immutability)'이 지켜지게 되는 겁니다.&lt;br /&gt;왜냐면, ['apple','banana','carrot'] 라는 데이터는 변하지 않았거든요.&lt;br /&gt;&lt;br /&gt;이 불변성이 React.js에서 중요한 포인트로 활용되는 이유는 아래와 같이 2가지 이유인 것 같습니다.&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(사실 더 있을지도 모르지만...아직 React.js에 대한 공부가 미진하여 2개만...)&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;우선, &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;React.js는 setState 메서드를 통해서 기존에 가지고 있던 state의 값과 새롭게 set하는 값을 비교해서, 해당 컴포넌트...혹은 요소의 변경을 트리거&lt;/span&gt;&lt;/b&gt;합니다. 마치 Vue.js에서 push나 pop을 호출하면 데이터의 변경에 따라 Vue 컴포넌트의 변경이 트리거되었듯이 말이죠. 따라서, React.js는 이와같이 불변성을 지키며 전혀 다른 메모리에 할당된 값과 기존에 값을 비교하는 절차를 바탕으로 컴포넌트의 트리거를 발동시키게 됩니다.&lt;br /&gt;&lt;br /&gt;또하나는, &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;브라우져 GC적인 관점에서도 유효한 포인트&lt;/span&gt;&lt;/b&gt;를 가질 수 있습니다.&lt;br /&gt;2012년을 기준으로 모든 최신 브라우져는 Mark-and-sweep 알고리즘을 바탕으로 Garbage Collection이 동작하게 되어있는데요. 만약, 위와 같이 items라는 변수가 가리키는 값이 변경되었다면 기존에 ['apple','banana','carrot'] 라는 값을 참조하는 변수는 없는 상황이되고 이는 해당 값이 GC의 정리 대상이 된다는 것을 의미합니다.&lt;br /&gt;&lt;br /&gt;이 GC의 관점이 유효한 이유는, 위와 같이 간단한 코드가 아니라 웹 서비스가 가지는 로직이 복잡해지면 복잡해질수록 화면에서 다루게 되는 데이터이 양도 많아지게되고 그에따라 메모리에 적재된 각 데이터들을 참조하는 변수도 N:N의 형태를 띄게 될지도 모릅니다. 이와 같은 경우, 미처 인지하지 못 한 실수로 인해 활용하지 않는 값임에도 불구하고 메모리상에 남아있게 되는데, 이를 보통 Memory leak(메모리 누수)이라고하며 웹 서비스의 성능을 저하시키는 주효 원인이기도 합니다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;참고사이트&lt;br /&gt;1. Vue.js 리스트 렌더링 : &lt;a href=&quot;https://kr.vuejs.org/v2/guide/list.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;https://kr.vuejs.org/v2/guide/list.html&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;2. React : &lt;a href=&quot;https://ko.reactjs.org/docs/react-component.html#state&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;https://ko.reactjs.org/docs/react-component.html#state&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>frontend</category>
      <category>react</category>
      <category>Vue</category>
      <category>개발</category>
      <category>개발자</category>
      <category>웹</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/89</guid>
      <comments>https://blinders.tistory.com/89#entry89comment</comments>
      <pubDate>Tue, 24 Aug 2021 00:40:06 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 불변성(Immutability)에 대해서</title>
      <link>https://blinders.tistory.com/88</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이 포스팅은 사실, 하고싶은 &lt;b&gt;다음 포스팅을 위한 밑밥&lt;/b&gt;이라고 보시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;오랜만에 포스팅해보고 싶은 이야깃거리가 생겼는데, 거기서 불변성의 개념까지 설명하기엔 너무 주제를 벗어나는 느낌이기도하고 불변성(&lt;span style=&quot;color: #000000;&quot;&gt;Immutability)이라는 개념 자체도 충분히 하나의 포스팅거리로 삼을법한 주제이기 때문에, 이 포스팅을 작성하게 되었습니다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0. 변수인데 불변한다는게 무슨 말이야?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;처음 불변성이라는 용어를 Javascript를 공부하며 들었을때, 머릿속에 들었던 첫 번째 물음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;우리는 개발을 하고 코드를 작성하며 수많은 변수를 사용한다. 변수라는 건 엄연히 변경이 가능한 수를 뜻하고, 변하지 않는 수라면 그건 상수라고 칭하면 될 텐데 굳이 불변성이라는 용어로 정의하면서까지 설명을 해놓는 이유가 뭘까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 포인터&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 개발입문을 C언어로 한 사람으로써, 포인터의 개념을 뼛속까지 깊이 새겨놓은 개발자 중에 한 사람이다. 철수와 영희네 집 주소부터 시작해서 집 명패가 어쩌구저쩌구 하면서 배웠던 바로 그 개념. 포인터의 가장 중요한 개념은 바로 모든 '값'은 메모리에 존재하며, 그 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;메모리에 적재된 값을 우리가 사용하기 위해 가리키는 지시자가 바로 '포인터'라는 것&lt;/b&gt;&lt;/span&gt;이다. 이러한 개념을 &lt;b&gt;Call by reference&lt;/b&gt;, 라고도하는데 &lt;b&gt;'참조의 형태로 값을 바라본다'&lt;/b&gt;라는 의미로 이해하면 될 것 같다. '포인트'라는 용어를 네이버 사전에서 찾아보면 여러가지 뜻이 나오지만, 여기에서의 개념과 가장 유사한 뜻은 '한 점'으로써, 값이 적재된 메모리의 한 지점을 '포인트'라고 생각했을때, 그 지점을 가리키는 주체에게 point + 'er'을 붙여서 pointer(포인터)라고 명명한 것이다. 즉,&amp;nbsp;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;'메모리에 적재된 값'을 가리키는(참조하는) 주체가 바로 포인터&lt;/b&gt;&lt;/span&gt;인 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1629182605388&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void main(){
 int num = 5;
 int *p = &amp;amp;num;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 위와 같은 코드로 작성이 되었다면, 아래와 같은 형태로 메모리와 메모리에 적재된 값이 구성되게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;443&quot; width=&quot;327&quot; height=&quot;331&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HOJwH/btrcs8S0tRb/HJfhd5rSNwFQpblzkmPzt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HOJwH/btrcs8S0tRb/HJfhd5rSNwFQpblzkmPzt1/img.png&quot; data-alt=&quot;대략 이런 형태&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HOJwH/btrcs8S0tRb/HJfhd5rSNwFQpblzkmPzt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHOJwH%2Fbtrcs8S0tRb%2FHJfhd5rSNwFQpblzkmPzt1%2Fimg.png&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;443&quot; width=&quot;327&quot; height=&quot;331&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대략 이런 형태&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;num이라는 변수는 104번지의 메모리영역을 가리키는데, 104번지에는 int num = 5; 라는 코드를 통해 할당한 '5'라는 값이 정의되어있고 포인터 p가 가리키는 메모리영역인 200번지에는 &amp;amp;num을 통해 할당한 변수 num의 주소지인 104가 '값'으로 정의되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #333333;&quot;&gt;여기서 잠깐...C언어 문법을 모르시는 분들을 위한 설명을 곁들이자면, &lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #333333;&quot;&gt;C언어에선 변수명 앞에 애스터리스크...그러니까 흔한 표현으로 별표(*)를 붙이면 해당 변수는 '포인터'라는 표현이며 해당 포인터 변수가 가리키는 주소지의 값을 의미한다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #333333;&quot;&gt;그리고 변수앞에 앤드연산자인 '&amp;amp;'을 붙이면, &amp;amp;가 붙은 변수는 해당 변수가 가리키는 메모리 영역의 값이 아니라 그 변수가 가리키는 메모리의 주소값을 리턴한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;따라서, p라고 명명된 변수가 실제 메모리에 가지고 있는 값은 104라는 주소지값이지만 애스터리스크를 붙인 *p의 형태로 활용되면 p가 가리키는 200번지 메모리의 값이 가리키는(참조하는) 104번지의 값인 5를 활용할 수 있게 되는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. Javascript Primitive Type&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;느닷없이 Javascript의 불변성(Immutability)을 포스팅하면서 왜 갑자기 C언어의 포인터까지 언급을 했냐면, &lt;b&gt;변수의 메모리 할당적인 관점을 먼저 이해하면 불변성을 이해하기 좀 더 쉽기 때문&lt;/b&gt;이다(내가 그랬으니까)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;자, 그럼 이제 본격적으로...Javascript에서 불변성을 띄는 대표적인 것들은 Primitive Type으로 분류되는 것들이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;boolean&lt;/li&gt;
&lt;li&gt;number&lt;/li&gt;
&lt;li&gt;bigint&lt;/li&gt;
&lt;li&gt;string&lt;/li&gt;
&lt;li&gt;undefined&lt;/li&gt;
&lt;li&gt;null&lt;/li&gt;
&lt;li&gt;symbol&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 7종세트가 Primitive Type(원시타입)으로써, Javascript에선 Immutability하다고 표현을 한다. 그 외에 모든 값은 객체(Object) 타입으로 분류되며, 객체 타입은 Mutable로써 변경이 가능한 값이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 이제 Immutability에 대해서 설명해보자&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자...아주 간단한 예시를 들어보자. 우리는 흔하게 아래와 같은 코드를 쓴다.&lt;/p&gt;
&lt;pre id=&quot;code_1629184449598&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let str = &quot;hello&quot;;
str = &quot;world&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어, 뭔가 이상하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Javascript에서 string은 분명 Primitive Type으로써 불변성을 가진다고 했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;str의 값이 &quot;hello&quot;에서 &quot;world&quot;로 변경됐다. 이러면, 값이 변한게 아닌가?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...라는 생각을 나도 처음에 했었다. 누가봐도 '코드'로 활용된 형태를 본다면 그렇게 생각 할 수 있으니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 질문을 하나 던져보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;위의 2줄짜리 코드에서 '값'은 변했을까?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 질문에 대한 답은 당연하게도&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; '값은 변하지 않았다'&lt;/b&gt;&lt;/span&gt;이다. 변한 것은 str이라는 변수가 가리키는 '값'이지, 기존에 가리키던 &quot;hello&quot;라는 순수한 값이 변경된 것은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까, 약식으로 그려보자면 다음과 같달까.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;355&quot; width=&quot;602&quot; height=&quot;303&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwkTH3/btrcuspYzfT/ssOji1woidMWKkSMCfesB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwkTH3/btrcuspYzfT/ssOji1woidMWKkSMCfesB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwkTH3/btrcuspYzfT/ssOji1woidMWKkSMCfesB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwkTH3%2FbtrcuspYzfT%2FssOji1woidMWKkSMCfesB1%2Fimg.png&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;355&quot; width=&quot;602&quot; height=&quot;303&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;메모리에 적재된 &quot;hello&quot;는 여전히 그대로이고, str이 가리키는 곳이 &quot;world&quot;로 변경되었을 뿐&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;변수 str이 가리키는 메모리의 위치가 바뀐 것이지, 실제 메모리에 있는 '값'이 변경된 건 아닌것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Primitive Type의 string은 이렇게 불변성을 지키게 되는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 마찬가지로 나머지 Primitive Type인 number나 boolean등도 불변성을 지키게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 덫붙이고자 Stack overflow에서 무려 9년전에 올라온 재미난 질문이 있어서 덫붙여본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/10648367/is-number-in-javascript-immutable&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/10648367/is-number-in-javascript-immutable&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. Object는 Mutable하다, Obejct는 참조(reference)하기 때문이다.&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이, Javascript의 Primitive Type들은 '불변성'을 지키는데반해 나머지 '값'을 지칭하는 객체(Object)들은 변경이 가능한(Mutable) 형태로 활용된다. 왜 객체는 Mutable 할까?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;자바스크립트의 객체는 키(key)과 값(value)으로 구성된 프로퍼티(Property)들의 집합&lt;/b&gt;이다.&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- poiemaweb&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 질문에 대한 답은 이미 &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;1. 포인터&lt;/b&gt;&lt;/span&gt;에서 언급한 것이나 마찬가지다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 인용구와 같이 Javascript의 Object는 키(key)와 값(value)으로 구성된 프로퍼티의 집합이고, 이로인해 객체의 모든 연산은 참조하고 있는 '값'을 바탕으로 실행되게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, C언어의 포인터와 같이&amp;nbsp;Call-by-reference의 개념으로서 바라보면, Object로써 선언한 객체를 Primitive Type에서처럼 값을 '변경'하는 듯한 코드를 작성한다하더라도, 새로운 메모리 영역에 새로운 '값'을 할당하고 그 값을 변수가 바라보는 형태로써 불변성이 지키는 게 아니라...&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;객체가 참조하는 메모리 영역의 '값'을 변경하는 것이기에 객체는 Mutable하다고 정의하는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 사이트 : &lt;a href=&quot;https://poiemaweb.com/js-object&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://poiemaweb.com/js-object&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>frontend</category>
      <category>immutability</category>
      <category>JavaScript</category>
      <category>개발</category>
      <category>불변</category>
      <category>불변성</category>
      <category>웹개발</category>
      <category>자바스크립트</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/88</guid>
      <comments>https://blinders.tistory.com/88#entry88comment</comments>
      <pubDate>Tue, 17 Aug 2021 17:30:04 +0900</pubDate>
    </item>
    <item>
      <title>[CSS] CSS 우선순위 정리</title>
      <link>https://blinders.tistory.com/87</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;한줄요약.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;!important &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;b&gt; inline &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;b&gt;&amp;nbsp;id선택자 &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;b&gt; class명 &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;b&gt;HTML 태그명&lt;/b&gt; &lt;span style=&quot;color: #333333;&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;b&gt;DOM구조의 상위 상속&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 요약한 것과 같이 아래 정리된 번호를 기준으로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;낮은 번호가 우선순위가 높습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 1번과 2번이 동일한 Element를 가리키면서 CSS를 정의한다면, 1번 내용이 적용됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. !important&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 높은 우선순위입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 키워드는 정의되는&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt; CSS의 요소 값 뒤에 위치&lt;/b&gt;&lt;/span&gt;하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;h3태그에 대해서 아래와 같은 CSS요소가 정의되어있다면&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; h3태그의 색상이 빨갛게&lt;/b&gt;&lt;/span&gt; 나오게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1626789033857&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.title-box{color: red !important;}
.title-box{color: blue;}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626790568234&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;app&quot; class=&quot;sample-box&quot;&amp;gt;
  &amp;lt;h3 id=&quot;title&quot; class=&quot;title-box&quot;&amp;gt;타이틀&amp;lt;/h3&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;390&quot; data-origin-height=&quot;208&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJc28r/btq94smVqqz/KfiNqadkkpPsBZLOg8WJqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJc28r/btq94smVqqz/KfiNqadkkpPsBZLOg8WJqK/img.png&quot; data-alt=&quot;빠빠,빨간맛.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJc28r/btq94smVqqz/KfiNqadkkpPsBZLOg8WJqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJc28r%2Fbtq94smVqqz%2FKfiNqadkkpPsBZLOg8WJqK%2Fimg.png&quot; data-origin-width=&quot;390&quot; data-origin-height=&quot;208&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;빠빠,빨간맛.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS는 일반적으로 후정의사항이 우선순위가 높게 책정됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 만약 위 코드에서 !important가 없다면, h3 태그의 글자색은 파란색이지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시에서 !important 키워드를 사용하여 정의하였기 때문에 먼저 정의하였음에도 불구하고 빨간색으로 나오게 되는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 만약, 아래와 같이 동일 선택자와 요소에 대해 !important를 사용하면 후정의사항 우선법칙에 따라, &lt;b&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;초록색&lt;/span&gt;&lt;/b&gt;으로 글자색이 정의됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1626789543719&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.title-box{color: red !important;}
.title-box{color: green !important;}
.title-box{color: blue;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;397&quot; data-origin-height=&quot;183&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oxGpu/btq92xvykpS/QNnwHRprQH2afgjID1N8j0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oxGpu/btq92xvykpS/QNnwHRprQH2afgjID1N8j0/img.png&quot; data-alt=&quot;초록색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oxGpu/btq92xvykpS/QNnwHRprQH2afgjID1N8j0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoxGpu%2Fbtq92xvykpS%2FQNnwHRprQH2afgjID1N8j0%2Fimg.png&quot; data-origin-width=&quot;397&quot; data-origin-height=&quot;183&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;초록색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 !important는 모든 우선순위를 제치고 우선적용되기때문에, &lt;b&gt;정말 피치 못 할 상황이 아니라면 사용하지 않는 것이 좋습니다.&lt;/b&gt; 특히나 프로젝트의 공통을 잡는 분들이나 퍼블리셔분이 스타일을 잡아주는 프로젝트의 경우에는, !important라는 키워드가 퍼블리셔분들의 최후의 보루라고 할 수 있기 때문에 지양해주셔야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. inline&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드의 태그내에 style 속성을 활용하여 CSS를 정의하는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;태그 내에 삽입되는 방식이기 때문에 inline이라는 명칭을 가지고 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1626789679475&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;app&quot; class=&quot;sample-box&quot;&amp;gt;
    &amp;lt;h3 id=&quot;title&quot; class=&quot;title-box&quot; style=&quot;color:red;&quot;&amp;gt;타이틀&amp;lt;/h3&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, &lt;b&gt;style=&quot;color:red;&quot;&lt;/b&gt; 라는 코드를 통해, h3태그에 색상을 부여해주고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. id선택자&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시태그(#)를 선택자 앞에 붙이면, 태그의 id를 가리키게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1626790094382&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#title{color:orange;}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626790603111&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;app&quot; class=&quot;sample-box&quot;&amp;gt;
  &amp;lt;h3 id=&quot;title&quot; class=&quot;title-box&quot;&amp;gt;타이틀&amp;lt;/h3&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;359&quot; data-origin-height=&quot;170&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmBp5S/btq91UKLnIJ/QumBfeiqkuEgkriKxyLdG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmBp5S/btq91UKLnIJ/QumBfeiqkuEgkriKxyLdG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmBp5S/btq91UKLnIJ/QumBfeiqkuEgkriKxyLdG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmBp5S%2Fbtq91UKLnIJ%2FQumBfeiqkuEgkriKxyLdG0%2Fimg.png&quot; data-origin-width=&quot;359&quot; data-origin-height=&quot;170&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. class명&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dot(.)를 선택자 앞에 붙이면, 태그의 class명을 가리키게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1626790182491&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.title-box{color:purple;}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626790610876&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;app&quot; class=&quot;sample-box&quot;&amp;gt;
  &amp;lt;h3 id=&quot;title&quot; class=&quot;title-box&quot;&amp;gt;타이틀&amp;lt;/h3&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;368&quot; data-origin-height=&quot;205&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl1IOd/btq93nlVoff/fk1Zhwua6XLc95o3SDHwpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl1IOd/btq93nlVoff/fk1Zhwua6XLc95o3SDHwpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl1IOd/btq93nlVoff/fk1Zhwua6XLc95o3SDHwpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl1IOd%2Fbtq93nlVoff%2Ffk1Zhwua6XLc95o3SDHwpk%2Fimg.png&quot; data-origin-width=&quot;368&quot; data-origin-height=&quot;205&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. HTML 태그명&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;태그명을 그대로 선언하여 CSS속성을 부여 할 수도 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1626790239284&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;h3{color:deeppink;}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626790613839&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;app&quot; class=&quot;sample-box&quot;&amp;gt;
  &amp;lt;h3 id=&quot;title&quot; class=&quot;title-box&quot;&amp;gt;타이틀&amp;lt;/h3&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;269&quot; data-origin-height=&quot;185&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RA29C/btq93nsFeGO/Z9kkfDwbwhfRZdKSqqyaWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RA29C/btq93nsFeGO/Z9kkfDwbwhfRZdKSqqyaWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RA29C/btq93nsFeGO/Z9kkfDwbwhfRZdKSqqyaWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRA29C%2Fbtq93nsFeGO%2FZ9kkfDwbwhfRZdKSqqyaWK%2Fimg.png&quot; data-origin-width=&quot;269&quot; data-origin-height=&quot;185&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. DOM구조에서 상위것 상속&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, CSS 속성을 주려는 대상 Element에게 아무런 속성도 정의하지 않는다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본값은 inherit가 주어지게 되며, 이는 &lt;b&gt;상위 Element의 속성을 계승&lt;/b&gt;하게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1626790335920&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.sample-box{color:darkcyan;}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626790616667&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;app&quot; class=&quot;sample-box&quot;&amp;gt;
  &amp;lt;h3 id=&quot;title&quot; class=&quot;title-box&quot;&amp;gt;타이틀&amp;lt;/h3&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;305&quot; data-origin-height=&quot;189&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfuKQs/btq97OitcJZ/qNNea6jKPl4RUiFeSKipR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfuKQs/btq97OitcJZ/qNNea6jKPl4RUiFeSKipR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfuKQs/btq97OitcJZ/qNNea6jKPl4RUiFeSKipR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfuKQs%2Fbtq97OitcJZ%2FqNNea6jKPl4RUiFeSKipR0%2Fimg.png&quot; data-origin-width=&quot;305&quot; data-origin-height=&quot;189&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에선, h3태그를 감싼 div 태그의 sample-box class를 선택자로하여 색상을 정의하였고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;h3태그까지 그 영향을 미친 것을 확인하실 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로는 아래와 같이 더럽게(?) CSS를 정의할 일은 없는게 맞습니다만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번 그냥 공부하는 셈치고 생각해봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1626791349196&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#title{color: blue;}
.sample-box{color:darkcyan;}
.h2-box{color: cornflowerblue; font-size: 16px;}
.title-box{color: orange; font-size:32px !important;}
h3{color: deeppink; font-size: 20px;}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626791361094&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;app&quot; class=&quot;sample-box&quot;&amp;gt;
    &amp;lt;h3 style=&quot;color: red;&quot;&amp;gt;H3 첫번째&amp;lt;/h3&amp;gt;
    &amp;lt;h3 class=&quot;h2-box&quot;&amp;gt;H3 두번째&amp;lt;/h3&amp;gt;
    &amp;lt;h3 id=&quot;title&quot; class=&quot;title-box&quot; style=&quot;font-size: 10px;&quot;&amp;gt;H3 세번째&amp;lt;/h3&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 사항으로 정의된 화면은 아래와 같이 브라우져에 렌더링 되게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;342&quot; data-origin-height=&quot;294&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyYZqU/btq96Em45zW/sMAdOGAGq8ReAy5vCuK021/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyYZqU/btq96Em45zW/sMAdOGAGq8ReAy5vCuK021/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyYZqU/btq96Em45zW/sMAdOGAGq8ReAy5vCuK021/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyYZqU%2Fbtq96Em45zW%2FsMAdOGAGq8ReAy5vCuK021%2Fimg.png&quot; data-origin-width=&quot;342&quot; data-origin-height=&quot;294&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전부 동일한 h3태그를 통해 정의되었지만, 각자의 우선순위에 따라 렌더링되었는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;H3 첫번째는, inline의&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;color:red;&lt;/b&gt;&lt;/span&gt;과 h3태그 선택자를 통한 &lt;b&gt;font-size: 20px;&lt;/b&gt;이 적용되었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;H3 두번째는,&lt;b&gt; .h2-box class로 정의한 내용&lt;/b&gt;이 고스란히 적용되었네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;H3 세번째는, id선택자로 정의한&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; color: blue;&lt;/b&gt;&lt;/span&gt;와 !important 키워드로 설정한&lt;b&gt; font-size: 32px;&lt;/b&gt; 이 적용되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 상위 태그에서 활용한 .sample-box class 는 모든 h3태그의 우선순위에서 밀렸으며, font-size또한 제각각 우선순위에 따라 책정되게 되었네요. 각 우선순위에 대해서는 브라우져 개발자도구를 열어보시면 아래와 같이 좀 더 명확하게 확인하실 수 있는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;490&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NsUQM/btq98uYm24S/xaQfCXbBgxQ3YD0PYT9ZC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NsUQM/btq98uYm24S/xaQfCXbBgxQ3YD0PYT9ZC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NsUQM/btq98uYm24S/xaQfCXbBgxQ3YD0PYT9ZC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNsUQM%2Fbtq98uYm24S%2FxaQfCXbBgxQ3YD0PYT9ZC0%2Fimg.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;490&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 캡쳐의 우측탭은 H3 세번째에 대한 CSS 정의사항을 보여주고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위에서 밀린 font-size와 color 속성에는 어떤 것이 있고 어떤 속성이 채택되었는지를 좀 더 명확히 확인 할 수 있습니다.&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>CSS</category>
      <category>Development</category>
      <category>Front-end</category>
      <category>frontend</category>
      <category>web</category>
      <category>개발</category>
      <category>개발자</category>
      <category>우선순위</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/87</guid>
      <comments>https://blinders.tistory.com/87#entry87comment</comments>
      <pubDate>Tue, 20 Jul 2021 23:25:10 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] Stack &amp;amp; Queue</title>
      <link>https://blinders.tistory.com/85</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;&amp;nbsp;Stack &amp;amp; Queue는 프로그래밍을 할 때 절대로 빼놓을 수 없는 알고리즘&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;마치 수학의 정석에도 닳고 닳게 보던 집합 챕터같은 느낌이랄까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;은연중에 우리는 많은 코딩방식을 Stack과 Queue를 통해 하고있으며, 본 포스팅에선 이를 정리하려하는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;...&lt;span style=&quot;color: #8a3db6;&quot;&gt;사실, Stack &amp;amp; Queue는 내가 2018년에 블로그 포스팅을 통해 정리를 한 번 했었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;티스토리 블로그가 아닌 &lt;a href=&quot;https://blinders.github.io/tech_blog/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Github 블로그&lt;/a&gt;에 말이다. 링크를 걸어놓은 Github 레파지토리는, Git이 뭔지도 몰랐던 신입사원시절에 '일단 Github가입부터' 했던 시절의 계정이며 지금은 활용되지않아 사장된 계정이다(저때도 기술 블로그와 에세이 블로그를 따로 만들고 디자인 어떻게 할 지 고민하다가 대략 만들어놓고 흐지부지 된 곳이다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이후에, 브런치도 갔다가 네이버도 갔다가...결국 글 쓰는 에디터가 티스토리가 가장 나와 맞는 것 같아서 여기에 안착했는데, 그러다보니 곳곳에 뿌려놓은 것들이 좀 있는 편이다(내가 숨겨놓고 잊은 내 보물찾기를 하는 기분이랄까)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그래서 하기에 설명된 Stack &amp;amp; Queue에 대한 내용은, 2018년에 서술된 Github 블로그의 내용을 그대로 가져왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;알고리즘을 이야기 할 때, 혹은 공부하려 할 때 가장 먼저 접하는 이론은 아마 십중팔구는 Stack과 Queue 를 보게 될 것이다. 대학생때 배웠던 자료구조-알고리즘 수업도 1장은 인트로, 2장이 Array, 3장이 Stack &amp;amp; Queue 였었다(아, 적고보니 Array 부터 포스팅 해야하는 건가, 싶은 생각이 드는데...이건 다음에 해야겠다. 이렇게 컨텐츠 적립하는 거지 뭐)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그래서 첫 알고리즘 카테고리 포스팅으로 Stack 과 Queue를 생각했는데, 사실 이게 설명하기가 좀 애매한 구석이 있다.&amp;nbsp; 그 &lt;span style=&quot;color: #8a3db6;&quot;&gt;애매한 게 뭐냐하면 너무 잘 알고 익숙한 것이라, 어떻게 설명을 해야 할 지 난감한게 문제&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;어떻게 걷고 뛰는 건지에 대한 방법론을, 서른 둘이 된 지금의 시점에서 누군가에게 설명하라고 한다면..음..그냥 다리를 움직이면 걷고 뛰어요..라는 생각이 맨 처음에 드는 거랑 같은 느낌이랄까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;&amp;nbsp;그러니 일단, 정의부터&lt;/b&gt;&lt;/span&gt; 내려보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 id=&quot;Stack&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Stack&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;한 단어로 정의하자면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;LIFO&lt;/b&gt;&lt;/span&gt;다. &lt;span style=&quot;color: #009a87;&quot;&gt;Last In, First Out.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;마지막에 들어온 놈이, 가장 먼저 나간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;즉 입구와 출구가 하나다. 땅으로 깊게 파 놓은 구덩이를 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그 구덩이에 데이터(변수든 Array든, 객체든 뭐든 여튼 하드웨어 적으로 메모리를 잡아먹는 무엇)를 집어넣고 그 위로 또 데이터를 집어넣는다. 그러고 나중에 데이터를 다시 꺼내려면, 옆으로 땅굴이라도 뚫지 않는 이상 가장 먼저 넣은 데이터를 우선적으로 꺼낼 수가 없다. 그 상태에서 꺼낼 수 있는 데이터는 가장 위에 보이는 데이터이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8kBly/btq6SwEVtAs/LLi2u6D39TAeX5u4f0ZcuK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8kBly/btq6SwEVtAs/LLi2u6D39TAeX5u4f0ZcuK/img.jpg&quot; data-alt=&quot;Stack 이라는 모바일 게임&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8kBly/btq6SwEVtAs/LLi2u6D39TAeX5u4f0ZcuK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8kBly%2Fbtq6SwEVtAs%2FLLi2u6D39TAeX5u4f0ZcuK%2Fimg.jpg&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Stack 이라는 모바일 게임&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;위 이미지는 Stack 이라는 안드로이드 게임인데, 실제 플레이를 해보면 계속해서 육면체 박스가 위로 쌓이기만 한다. 타이밍을 맞춰서 쌓고 가장 높은 위치까지 쌓는 것을 다투는 게임인데, 정말 이름을 따라서 쌓고, 또 쌓기만 한다(안타깝게도 꺼내진 않는다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이처럼 Stack은 쌓고, 쌓은 걸 빼는 자료구조라고 생각하면 된다.&lt;br /&gt;&amp;nbsp;또한 범용적으로 쓰이는 용어가 있는데 데이터를 Stack에 넣는 것을 &lt;span style=&quot;color: #009a87;&quot;&gt;&amp;lsquo;밀어 넣는다&amp;rsquo;라는 의미&lt;/span&gt;로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;push&lt;/b&gt;&lt;/span&gt;. Stack에 쌓인 데이터를 빼는 행위를 &lt;span style=&quot;color: #009a87;&quot;&gt;&amp;lsquo;꺼내다&amp;rsquo;라는 의미&lt;/span&gt;로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;pop&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;실제로 Stack을 코드로써 구현한 대부분의 API들은 push와 pop이라는 이름의 메서드를 만들어서 Stack에 데이터를 쌓고 데이터를 꺼내는데 활용되도록 가이드하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;실제 현업에서는 굳이 Stack을 코드로 한땀한땀 작성해서 사용하지는 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;대학생, 혹은 자료구조를 처음 공부하는 입장에서는 직접 구현해보는 것이 도움이 되겠지만, 이미 C++이나 Java등의 언어에서 기본 적인 자료구조는 클래스 형태로 제공을 하고 있기 때문이다. 거기에 위에서 말한 push, pop 이외에도 size, empty등 &lt;span style=&quot;color: #009a87;&quot;&gt;Stack을 활용함에 있어서 부가적으로 필요한 정보들을 리턴해주는 메서드들도 제공&lt;/span&gt;해주고 있기 때문에 우리는 잘 만들어진 아이들을 잘 사용해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;두 언어에 대한 짧은 사용 예시를 아래에 함께 하니 참고하기 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;C++의 경우&lt;/b&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;#include&amp;lt;stack&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1623198617449&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;stack&amp;gt; 

int main(){
  stack&amp;lt;int&amp;gt; stack;

  stack.push(4);
  stack.push(5);
  stack.push(1);

  cout &amp;lt;&amp;lt; stack.size() &amp;lt;&amp;lt; endl; // 3
  cout &amp;lt;&amp;lt; stack.top() &amp;lt;&amp;lt; endl; // 1

  stack.pop();
  cout &amp;lt;&amp;lt; stack.size() &amp;lt;&amp;lt; endl; // 2
  cout &amp;lt;&amp;lt; stack.top() &amp;lt;&amp;lt; endl; // 5

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Java의 경우&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #565a5f;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;import java.util.Stack;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1623198637275&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Stack;

public class StackExample {
  public static void main(String[] args){
    Stack&amp;lt;Integer&amp;gt; stack = new Stack();

    stack.push(4);
    stack.push(5);
    stack.push(1);

    System.out.println(stack.size()); // 3
    System.out.println(stack.peek()); // 1

    System.out.println(stack.size()); // 3
    System.out.println(stack.pop());  // 1

    System.out.println(stack.size()); // 2
    System.out.println(stack.peek()); // 5

  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 id=&quot;Queue&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Queue&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;와..Stack에 대한 글이 생각보다 길어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;사실 이렇게 길게 적을 거라곤 생각 안 했는데, 예시 코드와 함께 쓰다보니 좀 길어진 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그럼 이제 Stack 과 늘 함께 설명되는 &lt;span style=&quot;color: #006dd7;&quot;&gt;Queue에 대해 포스팅&lt;/span&gt;을 해보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;nbsp;Stack과 Queue는 둘다 선형 알고리즘&lt;/b&gt;&lt;/span&gt;이다(물론 Queue의 경우 환형도 있긴하지만)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;여기서 말하는 &amp;lsquo;선형&amp;rsquo;이란.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;nbsp;데이터를 저장하고 활용하는 방식이 &amp;lsquo;선&amp;rsquo;을 그은 것과 같은 형태를 띈다고 해서 선형 알고리즘&lt;/span&gt;이라고 불리운다. 앞에서 설명한 Stack을 생각해보자. 입구와 출구가 하나인 구덩이를 예시로 들었었다. 그 구덩이도 잘 보면 세로로 세워진 선과 같은 형태이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;nbsp;그럼 Queue는 Stack과 무엇이 다를까?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Queue는&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;nbsp;FIFO&lt;/span&gt;&lt;/b&gt;다.&lt;span style=&quot;color: #006dd7;&quot;&gt; First In First Out.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;먼저 들어온 데이터가 먼저 나간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;즉, 데이터가 들어오는 입구와 출구가 별개다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다만, 별개라고 해서 내가 사용하고자 하는 데이터가 중간쯤 들어왔는데 얘부터 먼저 쏙 빼서 사용할 수는 없다. &lt;span style=&quot;color: #006dd7;&quot;&gt;먼저 들어온 데이터가, 먼저 나가야 하는 것이 Queue의 원칙이자 정의&lt;/span&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;213&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbH3Ma/btq6QOGolq6/QcJiMmOpa8im9TGEAGUK6K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbH3Ma/btq6QOGolq6/QcJiMmOpa8im9TGEAGUK6K/img.jpg&quot; data-alt=&quot;2014년 영국에서 본 대기열 안내문구&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbH3Ma/btq6QOGolq6/QcJiMmOpa8im9TGEAGUK6K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbH3Ma%2Fbtq6QOGolq6%2FQcJiMmOpa8im9TGEAGUK6K%2Fimg.jpg&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;213&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2014년 영국에서 본 대기열 안내문구&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이 사진은 2014년에 영국 여행을 하며 본 안내문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;당시 관광지에 들어가기 위한 대기줄에 서 있었고 이 안내문을 보고는 단박에 Queue에 대한 깨달음을 얻을 수 있었다늘 코드와 이론으로만 보던 내용을 이렇게 실생활에서 보게 되다니, 신기할 따름이었다(그러고 본능과 같이 눌러버린 카메라 셔터...이제보니 참 공돌이다웠다)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실상 영어단어로써의 Queue는 이와 같이 무언가를 하기 위해 일렬로 늘어선 사람들로 이루어진 줄을 의미하기도 하는데, 실제로 이렇게 대기줄로 형성된 사람들은 가장 먼저 선 사람이 입장하고 다음 사람이 순번을 이어받게 된다. First In, First Out 의 형태인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이와 동일한 예제로 내가 대학생 시절 받았던 Queue관련 과제는 은행의 업무처리 시스템을 개발하는 것이었다. 말해놓고보니 되게 거창한 과제 같은데, 실제 돈을 송금하고 인출하고 하는 은행 시스템을 생각한다면 오산이다. 과제 설명을 조금 하자면 은행원이 3명이 있을 때 각 은행원 별로 능력의 역차가 있어서 하나의 일에 대해 A는 3분, B는 5분, C는 1분이 걸려 일을 처리한다고 가정한다. 거기에 손님들이 9시부터 1분에 한 명씩 입장할 때에 은행에 업무가 종료되는 가장 빠른 시각은 언제인가, 를 구하는 과제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&amp;nbsp;전형적인 대기열(Queue)문제였는데, 정확치는 않지만 해결하는데 이틀 정도 걸렸던 것 같다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;(이틀 내내 했다는게 아니라..학교가고 밥 먹고 잠자고 놀고 할 거 다 하고&amp;hellip;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;물론, &lt;span style=&quot;color: #006dd7;&quot;&gt;Queue 또한 Stack 처럼 잘 작성 된 API들이 존재&lt;/span&gt;하므로 특별한 경우가 아니라면, 필요시 가져다 잘 사용해주면 된다. 가장 대표적인 C++과 Java의 예시를 아래에 작성하니 참고바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;C++의 경우&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&amp;nbsp;#include&amp;lt;queue&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1623198675551&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#inlcude&amp;lt;iostream&amp;gt;
#include&amp;lt;queue&amp;gt;
using namespace std;

int main(){
  queue&amp;lt;int&amp;gt; q;

  q.push(4);
  q.push(5);
  q.push(1);

  cout &amp;lt;&amp;lt; q.size() &amp;lt;&amp;lt; endl; // 3
  cout &amp;lt;&amp;lt; q.front() &amp;lt;&amp;lt; endl; // 4
  cout &amp;lt;&amp;lt; q.back() &amp;lt;&amp;lt; endl; // 1

  q.pop();
  cout &amp;lt;&amp;lt; stack.size() &amp;lt;&amp;lt; endl; // 2
  cout &amp;lt;&amp;lt; q.front() &amp;lt;&amp;lt; endl; // 5
  cout &amp;lt;&amp;lt; q.back() &amp;lt;&amp;lt; endl; // 1

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Java의 경우&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #565a5f;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;import java.util.Queue;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1623198694441&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.LinkedList;
import java.util.Queue;

public class StackExample {
  public static void main(String[] args){
    Queue&amp;lt;Integer&amp;gt; q = new LinkedList&amp;lt;Integer&amp;gt;();

    q.offer(4);
    q.offer(5);
    q.offer(1);

    System.out.println(q.size()); // 3
    System.out.println(q.peek()); // 4

    System.out.println(q.size()); // 3
    System.out.println(q.poll());  // 4

    System.out.println(q.size()); // 2
    System.out.println(q.peek()); // 5

  }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/알고리즘(Algorithm)</category>
      <category>Algorithm</category>
      <category>Computer</category>
      <category>CS</category>
      <category>Developer</category>
      <category>Development</category>
      <category>Queue</category>
      <category>stack</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/85</guid>
      <comments>https://blinders.tistory.com/85#entry85comment</comments>
      <pubDate>Wed, 9 Jun 2021 09:41:38 +0900</pubDate>
    </item>
    <item>
      <title>[webpack] venders ~~ was preloaded using link preload but not used within a few seconds</title>
      <link>https://blinders.tistory.com/84</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm run build 명령을 통해서 떨어지는 최종 결과물에, &lt;span style=&quot;color: #ee2323;&quot;&gt;Code Split를 적용하기 위해서 아래와 같은 옵션&lt;/span&gt;을 적용했다.&lt;/p&gt;
&lt;pre id=&quot;code_1623136281958&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = {
  configureWebpack: {
    optimization: {
      minimize: true,
      splitChunks: {
        chunks: &quot;all&quot; // 이거
      },
    },
  },
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Entry파일을 여러개로 나눈, Multiple Entry 형태의 구조로 개발을 하기위해서 공통으로 활용되는 npm 패키지들을 하나로 묶고자 위와 같이 설정한 것인데...위와 같이 정의하고&lt;span style=&quot;color: #ee2323;&quot;&gt; npm run build로 webpack을 동작시키면 의도한대로 최종 빌드된 html과 js파일들은 잘 생성&lt;/span&gt;이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만,&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; npm run serve를 통해 webpack-dev-server를 구동시키면 아래와같은 warning을 띄우며 화면이 렌더링 되지 않는다&lt;/b&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;The resource http://localhost:8080/vendors~index.js was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;해결법&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 원인이 발생하는 이유는, vue-cli를 통해서 생성한 프로젝트에서, 빌드할 경우 생성되는 HTML에서 메타 데이터인javascript를 가져 올 경우 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;prefetch와 preload 옵션을 자동으로 정의해주는데...이게 문제&lt;/b&gt;&lt;/span&gt;라는거다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;preload 옵션으로 로드해오는 리소스는 3초내에 실제로 '활용'이 되어야한다&lt;/span&gt;는데, 공통으로 활용되는 패키지가 있는 javascript 파일이니만큼 즉각적으로 활용이 안 되니까, 위와 같은 문제가 발생하는 것으로 추정된다(실제로 구글링해보면 위와같은 에러는 font 리소스를 가져올 때 많이들 발생한다고 포스팅되어있다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 이 prefetch나 preload를 제거할 방법을 찾고자했지만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;github 이슈를 통해서 확인해보니 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;In vue-cli webpack, modules are ALWAYS prefetched, and there is no way&lt;/b&gt;&lt;/span&gt;...라고 누가 답변을 작성해놓았더라. no way...그러니까 단순히 vue-cli의 설정만으로는 방법이 없다는거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 분명 예전에 투입됐던 모 프로젝트에서는 이걸 당연하게 썼었는데, 싶어서 당시의 webpack 설정파일을 찾아서 비교해보니 이 이슈를 해결할 실마리를 찾게되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것은 바로 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;HtmlWebpackPlugin 플러그인.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 플러그인은 최종 빌드되어 떨어지는 HTML 파일과 관련된 설정을 여러 옵션으로 정의해주는 방식인데, 이걸 사용하면 preload나 prefetch와 같은 메타데이터 링크의 옵션들이 붙지 않는다. 물론, preload나 prefetch가 선별적으로 필요한 경우라면 해법을 다르게 찾아봐야하겠지만 현재로썬 그러한 점이 불필요하기 때문에 하기와 같이 플러그인을 설치하고 옵션을 정의하여 해결하게였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, npm install을 통해 html-webpack-plugin을 설치해줘야하는데 webpack 버전을 확인하고 사용하는 버전에 맞는 플러그인을 설치해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Webpack 버전이 4.x 일 경우&lt;/p&gt;
&lt;pre id=&quot;code_1623138277370&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i --save-dev html-webpack-plugin@4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Webpack 버전이 5.x 일 경우&lt;/p&gt;
&lt;pre id=&quot;code_1623138307928&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i --save-dev html-webpack-plugin&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm install이 완료되면, 이제 vue.config.js(혹은 webpack 설정파일)에 아래와 같이 plugin을 정의해주고 webpack-dev-server를 구동시켜주면 정상적으로 동작되는 걸 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1623138507472&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 나는 Entry 파일이 2개라서 2개의 HtmlWebpackPlugin을 정의했다.
plugins: [
  new HtmlWebpackPlugin({
    template: 'public/index.html',
    filename: 'index.html',
    inject: true,
    chunks: ['index']
  }),
  new HtmlWebpackPlugin({
    template: 'public/index2.html',
    filename: 'index2.html',
    inject: true,
    chunks: ['index2']
  })
]&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/트러블 슈팅(Trouble Shooting)</category>
      <category>Front-end</category>
      <category>Vue</category>
      <category>vue config</category>
      <category>vue-cli</category>
      <category>vuejs</category>
      <category>webpack</category>
      <category>개발</category>
      <category>개발자</category>
      <category>트러블슈팅</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/84</guid>
      <comments>https://blinders.tistory.com/84#entry84comment</comments>
      <pubDate>Tue, 8 Jun 2021 16:49:30 +0900</pubDate>
    </item>
    <item>
      <title>[문자열] KMP 알고리즘</title>
      <link>https://blinders.tistory.com/83</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 카테고리의 첫 포스팅은, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;KMP 알고리즘&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Knuth, Morris, Pratt 이라는 세 사람의 첫 글자를 따선 만든 알고리즘인데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 정의하자면 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;서로 다른 문자열을 비교하는 알고리즘&lt;/b&gt;&lt;/span&gt;이라고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 'aaaabbccaab' 라는 문자열이 있을때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'aab'라는 문자열이 몇번째 인덱스에 있는지 찾고자한다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게 찾아야 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당장 떠오르는 방법은 아마도 'aaaabbccaab'의 첫번째글자와&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'aab'의 첫 번째 글자를 비교해서 동일하면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각 두번째 글자를 비교하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 동일하면 세번째 글자를 비교하고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 세번째에서 동일하지 않다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교의 시작점이었던 'aaaabbccaab'의 두번째 글자로 돌아와서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 'aab'의 첫 번째 글자와 비교를 할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법의 시간복잡도는, 두 문자열의 길이의 곱에 비례한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;O(nm)이 된다는 이야기&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 전체 문자열이 10,000,000 개의 글자로 이루어져있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾으려는 문자열이 10,000 개라고 한다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 복잡도는...굳이 말하지 않아도 어마어마하게 크다는 것을 알 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;편차를 O(n+m)이라는 획기적인 수치로 줄여 줄 수 있는 알고리즘이 바로 KMP 알고리즘&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 KMP 알고리즘은 무려 10년 전, 대학생시절 자료구조 수업때 배웠던 내용인데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'조금만 다른 방향에서 생각해보면, 이렇게나 획기적으로 효율성을 가질 수 있구나'라는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충격적인 깨달음을 나한테 줬던 알고리즘으로,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 비교 === KMP 라고 떠올릴만큼 내 머릿속에는 또렷히 박혀있는 알고리즘이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명을 시작해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KMP에 대해 설명된 다른 분들의 포스팅을 보면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;prefix와 postfix 개념을 먼저 설명해놓으셨던데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기선 그 개념을 몰라도 충분히 KMP를 이해 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KMP의 핵심 기법을 한 줄로 정리해보자면.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&quot;패턴을 정의해서, 했던 비교를 또 하지 않는다.&quot;&lt;/b&gt;&lt;/span&gt;라는 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 패턴을 관리하는 failure 배열 만들기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KMP와 관련해서 우리는 기본적으로 2개의 문자열을 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;검색의 대상이되는 문자열(origin)과, 찾아야하는 패턴의 문자(keyword).&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;여기에 KMP를 위해 추가되는 개념이 'failure funtion'&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 문자열 origin 은 전체 길이가 16인 'aabcacabcabcacab'이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾으려는 패턴 keyword은 길이가 10인 'abcabcacab'라고 했을때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 failure function은 아래와 같은 배열의 형태를 띈다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;89&quot; width=&quot;656&quot; height=&quot;115&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L6n8Q/btq4XyF1VKc/td0yAUZ6ikd0pacBVuTthK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L6n8Q/btq4XyF1VKc/td0yAUZ6ikd0pacBVuTthK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L6n8Q/btq4XyF1VKc/td0yAUZ6ikd0pacBVuTthK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL6n8Q%2Fbtq4XyF1VKc%2Ftd0yAUZ6ikd0pacBVuTthK%2Fimg.png&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;89&quot; width=&quot;656&quot; height=&quot;115&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념적으로는 failure function이라고하기 때문에 function인가? 싶을수도 있지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드로 보자면 그냥 인덱스값을 가진 배열형의 변수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;배열형의 변수 failure는, 찾고자 하는 문자열(keyword)이 반복하는 패턴을 기록&lt;/b&gt;&lt;/span&gt;해둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 &lt;b&gt;찾고자 하는 keyword가, 내부적으로 어떠한 '패턴'을 가지고 있다면&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;keyword를 찾기위해 전체 문자열인 origin과 0번 인덱스부터 비교해 나갈때,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서로 다르더라도 다시 처음부터 반복할 필요가 없게 만드는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;왜냐면 패턴만큼, 비교시의 인덱스를 건너뛰면되니까.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 failure라는 배열의 값들을 채우는 방법을 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 채우는 개념은 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. 길이는 keyword와 동일&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. failure[0]의 값은 -1로 초기화한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3. 이후, 반복문을 통해 keyword배열을 순회하는데, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;이때 중점은 현재 인덱스의 failure 값이 아니라,&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp;한 칸 앞의 failure 인덱스의 값보다 +1한 keyword의 '값'을 봐야한다는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp; &amp;nbsp;왜냐면 이건 keyword의 '패턴'을 파악하기위한 것이니까. 아래 예시를 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;3-1. 만약 &lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;idx가 1이라면...failure[0]의 값인 -1보다 +1한 keyword[0]이 가지는 값인 'a'와,&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 현재 idx의 keyword[1]의 값인 'b'를 비교한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 이 경우엔, 당연히 'a'와 'b'는 다르므로, failure[1]의 값은 -1로 채워지게 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;579&quot; data-origin-height=&quot;223&quot; width=&quot;636&quot; height=&quot;245&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bykoF7/btq40QL23o5/zXWcHdKsrkeVKzROsJhYv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bykoF7/btq40QL23o5/zXWcHdKsrkeVKzROsJhYv1/img.png&quot; data-alt=&quot;idx가 1일 때&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bykoF7/btq40QL23o5/zXWcHdKsrkeVKzROsJhYv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbykoF7%2Fbtq40QL23o5%2FzXWcHdKsrkeVKzROsJhYv1%2Fimg.png&quot; data-origin-width=&quot;579&quot; data-origin-height=&quot;223&quot; width=&quot;636&quot; height=&quot;245&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;idx가 1일 때&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3-2. 만약&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;idx가 3이라면...failure[2]가 가지는 -1보다 +1한 keyword[0]이 가지는 값인 'a'와,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 현재 idx의 keyword[3]의 값인 'a'를 비교한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 이때 keyword[0]과 keyword[3]은 둘다 'a'이므로, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; failure[3]에는 failure[2]의 값에 +1한 0이 채워진다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;232&quot; width=&quot;673&quot; height=&quot;265&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEVT0i/btq4ZfSQqfW/cQlfdsQEByRnUh2ZLjnE1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEVT0i/btq4ZfSQqfW/cQlfdsQEByRnUh2ZLjnE1K/img.png&quot; data-alt=&quot;idx가 3일 때&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEVT0i/btq4ZfSQqfW/cQlfdsQEByRnUh2ZLjnE1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEVT0i%2Fbtq4ZfSQqfW%2FcQlfdsQEByRnUh2ZLjnE1K%2Fimg.png&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;232&quot; width=&quot;673&quot; height=&quot;265&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;idx가 3일 때&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3-3. 만약&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;idx가 4이라면...failure[3]가 가지는 0보다 +1한 keyword[1]이 가지는 값인 'b'와,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 현재 idx의 keyword[4]의 값인 'b'를 비교한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 이때 keyword[1]과 keyword[4]은 둘다 'b'이므로, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; failure[4]에는 failure[3]의 값에 +1한 1이 채워진다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;236&quot; width=&quot;681&quot; height=&quot;258&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC2MnI/btq4X6WCG0q/pvlU97xW89ct4O2N7Fyp11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC2MnI/btq4X6WCG0q/pvlU97xW89ct4O2N7Fyp11/img.png&quot; data-alt=&quot;idx가 4일 때&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC2MnI/btq4X6WCG0q/pvlU97xW89ct4O2N7Fyp11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC2MnI%2Fbtq4X6WCG0q%2FpvlU97xW89ct4O2N7Fyp11%2Fimg.png&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;236&quot; width=&quot;681&quot; height=&quot;258&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;idx가 4일 때&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3-4. 만약&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;idx가 7이라면...failure[6]이 가지는 3보다 +1한 keyword[4]이 가지는 값인 'b'와,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 현재 idx의 keyword[7]의 값인 'c'를 비교하는데...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 이때 keyword[4]과 keyword[7]은 서로 다른 값이기 때문에, failure[7]은 다시 -1로 채워진다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;228&quot; width=&quot;734&quot; height=&quot;251&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2JFpI/btq4XyswHxs/oKdzLQRpgHuIaggIblKSw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2JFpI/btq4XyswHxs/oKdzLQRpgHuIaggIblKSw1/img.png&quot; data-alt=&quot;idx가 7일 때&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2JFpI/btq4XyswHxs/oKdzLQRpgHuIaggIblKSw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2JFpI%2Fbtq4XyswHxs%2FoKdzLQRpgHuIaggIblKSw1%2Fimg.png&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;228&quot; width=&quot;734&quot; height=&quot;251&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;idx가 7일 때&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;4. 이렇게 반복된 후, 최종 failure는 아래와 같은 구성을 가지게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;685&quot; height=&quot;120&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;89&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L6n8Q/btq4XyF1VKc/td0yAUZ6ikd0pacBVuTthK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L6n8Q/btq4XyF1VKc/td0yAUZ6ikd0pacBVuTthK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L6n8Q/btq4XyF1VKc/td0yAUZ6ikd0pacBVuTthK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL6n8Q%2Fbtq4XyF1VKc%2Ftd0yAUZ6ikd0pacBVuTthK%2Fimg.png&quot; width=&quot;685&quot; height=&quot;120&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;89&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. failure 배열을 활용해서 keyword 찾기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 origin과 keyword를 첫 번째 인덱스부터 비교하기 시작할텐데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 달라지는 점은 바로, 비교하는 두 값이 다를 때 failure 배열을 활용한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 origin 은 'aabcacabcabcacab'이고 찾으려는 패턴은 keyword 'abcabcacab'이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제, 두 문자열의 첫 인덱스부터 비교를 시작하는데,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;356&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LwjXW/btq4WXl208s/pz7RplUV0plaXZ68kD5tuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LwjXW/btq4WXl208s/pz7RplUV0plaXZ68kD5tuk/img.png&quot; data-alt=&quot;빨간 색 선이 비교된 대상이다.&amp;amp;amp;nbsp;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LwjXW/btq4WXl208s/pz7RplUV0plaXZ68kD5tuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLwjXW%2Fbtq4WXl208s%2Fpz7RplUV0plaXZ68kD5tuk%2Fimg.png&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;356&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;빨간 색 선이 비교된 대상이다.&amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이, keyword와 origin이 달라졌을 경우에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 이미 만들어놓은 failure 배열을 활용해주는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;keyword의 m번째 인덱스값 1에서 keyword와 origin의 값이 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 &lt;b&gt;m의 값이 1이므로 한 칸 앞의 failure[0]번 값&lt;/b&gt;을 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;failure[0]번의 값은 -1이므로, 여기에 1을 더한 값 0이 m의 값이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, m은 다시 0이되고 n은 여전히 1인채로, 한 칸씩 비교를 계속 해나간다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;344&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0b1Nf/btq4Xye1Fwl/8rnps9KPiCqu058dHTgp40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0b1Nf/btq4Xye1Fwl/8rnps9KPiCqu058dHTgp40/img.png&quot; data-alt=&quot;파란색 선이 비교된 대상이다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0b1Nf/btq4Xye1Fwl/8rnps9KPiCqu058dHTgp40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0b1Nf%2Fbtq4Xye1Fwl%2F8rnps9KPiCqu058dHTgp40%2Fimg.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;344&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;파란색 선이 비교된 대상이다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 비교를 해나가다보면 m은 4, n은 5일 때 서로 값이 다르게 되는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 설명한 것과 같이 m이 4일 때 달라졌으므로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 칸 앞의 failure[3]번 값을 보면 0이라는 걸 알 수 있고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0에 1을 더한 '1'이라는 값이 m의 값이되어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;m은 1, n은 5인 상태로 keyword[1]과 origin[5]부터 다시 한 칸씩 비교하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;350&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sA1RG/btq4XXewQs7/kZXmb4AIUkNkhMjVzlN1Hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sA1RG/btq4XXewQs7/kZXmb4AIUkNkhMjVzlN1Hk/img.png&quot; data-alt=&quot;녹샌선을 보자&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sA1RG/btq4XXewQs7/kZXmb4AIUkNkhMjVzlN1Hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsA1RG%2Fbtq4XXewQs7%2FkZXmb4AIUkNkhMjVzlN1Hk%2Fimg.png&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;350&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;녹샌선을 보자&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 keyword[1]과 origin[5]는 서로 다른 값이고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 다시 m이 1이기때문에, 한 칸 앞의 failure[0]값을 봐야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;failure[0]은 -1의 값을 가지기때문에 다시 +1해서 0이 나오고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;m은 0, n은 여전히 5인채로 keyword[0]과 origin[5]를 비교하면 되는데&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;358&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjQobz/btq4Yr0zwIB/rFl3kx1AIHxK2Q6kruEVt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjQobz/btq4Yr0zwIB/rFl3kx1AIHxK2Q6kruEVt0/img.png&quot; data-alt=&quot;주홍색 선을 보자&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjQobz/btq4Yr0zwIB/rFl3kx1AIHxK2Q6kruEVt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjQobz%2Fbtq4Yr0zwIB%2FrFl3kx1AIHxK2Q6kruEVt0%2Fimg.png&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;358&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;주홍색 선을 보자&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 keyword[0]과 origin[5]는 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 이 시점에서 m은 0이고, 그보다 한 칸 앞서려면 failure[-1]이어야 하는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;failure 배열에 이 값은 존재하지 않기때문에 이때는 n의 값을 1늘려서 비교를 다시 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, n이 6으로 늘어나면서 keyword[0]과 origin[6]부터 한 칸씩 비교를 하는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;336&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/730mS/btq4X6h3FLE/VYvGLxJEl1vXlxwoHO9BSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/730mS/btq4X6h3FLE/VYvGLxJEl1vXlxwoHO9BSk/img.png&quot; data-alt=&quot;보라색 선을 보자&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/730mS/btq4X6h3FLE/VYvGLxJEl1vXlxwoHO9BSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F730mS%2Fbtq4X6h3FLE%2FVYvGLxJEl1vXlxwoHO9BSk%2Fimg.png&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;336&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;보라색 선을 보자&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 한 칸씩 이동을 하게되면, 드디어 최종 패턴을 알 수 있게되었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시를 기준으로 보자면 m이 9인 상태로 패턴을 찾아내게되며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;찾고자했던 origin 문자열에서의 keyword 문자열의 위치값은&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;최종 n 값에서 keyword의 길이값을 뺀 6&lt;/b&gt;&lt;/span&gt;이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드는, 내가 정리한 Javascript KMP funciton 이다.&lt;/p&gt;
&lt;pre id=&quot;code_1621070437982&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let kmp = function(origin, keyword){
      
      let oDump = origin.split('');
      let kDump = keyword.split('');
      let oLength = origin.length;
      let kLength = keyword.length;
      
      let failure = [];
      failure.length = kDump.length;
      failure.fill(-1);
      
      // failure 배열 세팅
      for(let i = 1; i &amp;lt; kLength; i++){
          let idx = (1 + failure[i-1]);
          if(kDump[i] === kDump[idx]){
              failure[i] = idx;
          } else{
              failure[i] = -1
          }
      }
      
      // 비교 시작
      let n = 0, m = 0;
      while(m &amp;lt; kLength &amp;amp;&amp;amp; n &amp;lt; oLength){
          if(oDump[n] === kDump[m]){
              n++; m++;
          } else if(m === 0){
              n++;
          } else{
              m = 1 + failure[m-1]
          }
      }
      
      return m === kLength? (n - kLength) : -1
      
  }&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/알고리즘(Algorithm)</category>
      <category>Algorithm</category>
      <category>dev</category>
      <category>Development</category>
      <category>KMP</category>
      <category>개발</category>
      <category>문자열비교</category>
      <category>알고리즘</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/83</guid>
      <comments>https://blinders.tistory.com/83#entry83comment</comments>
      <pubDate>Sat, 15 May 2021 18:21:07 +0900</pubDate>
    </item>
    <item>
      <title>indexOf vs for, 왜 indexOf로 해결되는거지?</title>
      <link>https://blinders.tistory.com/82</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이건, 좀 의아한 기록이고 왜 그런지 모르겠어서 남기는 메모인데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 해커랭크에서 문제를 풀어보는 편인데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가볍게 풀려고 Easy 난이도의 &lt;a href=&quot;https://www.hackerrank.com/challenges/two-strings/problem&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Two Strings&lt;/a&gt; 라는 문제를 봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;그냥 문자열 2개 비교해서, 서로 동일한 문자가 있으면 'YES', 없으면 'NO'를 리턴&lt;/b&gt;&lt;/span&gt;하는건데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 어떤 부분에서 이해가 되질 않아서 이렇게 포스팅까지 하냐면...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 아래와 같이 쉽게 for문 2개 코드로 작성 제출했는데&lt;/p&gt;
&lt;pre id=&quot;code_1620875870238&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function twoStrings(s1, s2) {
    // Write your code here

    for(let i = 0, length = s1.length; i &amp;lt; length; i++){
        for(let j = 0, jlength = s2.length; j &amp;lt; jlength; j++){
            if(s2[j] === s1[i]){
                return 'YES';
            }   
        }
    }
    
    return 'NO';
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;3개 테스트 케이스에서 &lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Time limit exceeded가 발생&lt;/b&gt;&lt;/span&gt;을 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그렇게 한참을 고민.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;고민.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;고민.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;고민.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;고민.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Easy 난이도인데, 이게 이렇게 고민거린가...?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;고민.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고민.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 고민.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 혹시나 싶은 마음에 아래와 같이 작성했는데&lt;/p&gt;
&lt;pre id=&quot;code_1620876006053&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function twoStrings(s1, s2) {
    // Write your code here
    
    for(let i = 0, length = s1.length; i &amp;lt; length; i++){
        if(s2.indexOf(s1[i]) &amp;gt; -1){
            return 'YES';
        }   
    }
     
    return 'NO';
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;통과&lt;/b&gt;했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...????&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 내부 for문을&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt; indexOf&lt;/b&gt;&lt;/span&gt;로 바꾼건데, 통과를 해버렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 왜, 의문거리냐면...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 내 생각으론 둘의 시간복잡도는 O(n^2)로 같기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;for문은 애초에 주어진 데이터를 전체 반복하니까...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이중 포문이면 n^2 인거고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;indexOf도 시간복잡도는 O(n)인데, 그게 for문안에 있으니까 O(n^2)인거고...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어 혹시 indexOf가 Javascript 내부적으로 무언가 내가 알지 못 하는 신박한 방법을 통해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;for 보다 빠른 프로세스를 가지는 건가, 싶어서 찾아봤는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nikitahl.com/how-to-find-an-item-in-a-javascript-array/&quot;&gt;How to find an item in a JavaScript array (+performance tests) (nikitahl.com)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1620876324888&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;How to find an item in a JavaScript array (+performance tests)&quot; data-og-description=&quot;Several examples of how to find an item in an array in JavaScript with performace tests&quot; data-og-host=&quot;nikitahl.com&quot; data-og-source-url=&quot;https://nikitahl.com/how-to-find-an-item-in-a-javascript-array/&quot; data-og-url=&quot;https://nikitahl.com/how-to-find-an-item-in-a-javascript-array/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bpUyyi/hyKbuo7NFi/zGfvklZUiiEqgiCyhvWu60/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://nikitahl.com/how-to-find-an-item-in-a-javascript-array/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nikitahl.com/how-to-find-an-item-in-a-javascript-array/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bpUyyi/hyKbuo7NFi/zGfvklZUiiEqgiCyhvWu60/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;How to find an item in a JavaScript array (+performance tests)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Several examples of how to find an item in an array in JavaScript with performace tests&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;nikitahl.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;631&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYHP0t/btq4PmxxF3H/GpLx11cTBK64ngeBvrthMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYHP0t/btq4PmxxF3H/GpLx11cTBK64ngeBvrthMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYHP0t/btq4PmxxF3H/GpLx11cTBK64ngeBvrthMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYHP0t%2Fbtq4PmxxF3H%2FGpLx11cTBK64ngeBvrthMk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;631&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;...for문이 더 빠르다&lt;/b&gt;&lt;/span&gt;는거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;(물론 저건 String이 아니라 Array지만, 동작매커니즘 자체는 동일할테니까)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;364&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/em60uq/btq4NG4tzfv/JotXUQxNnyuy1QuyksiSdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/em60uq/btq4NG4tzfv/JotXUQxNnyuy1QuyksiSdk/img.png&quot; data-alt=&quot;왜 때문에 그런거에요...대체...?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/em60uq/btq4NG4tzfv/JotXUQxNnyuy1QuyksiSdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fem60uq%2Fbtq4NG4tzfv%2FJotXUQxNnyuy1QuyksiSdk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;364&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;왜 때문에 그런거에요...대체...?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 포스팅을 하는 지금도 왜 때문인지 모르겠다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 있는 함수를 굳이 만드려고하지말고 잘 쓰는 게 좋다,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라는 교훈을 얻고 마침표를 찍어야하나 싶다가...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 ECMA 원문까지 열어봤는데도 모르겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.ecma-international.org/wp-content/uploads/ECMA-262_1st_edition_june_1997.pdf&quot;&gt;ECMA-262_1st_edition_june_1997.pdf (ecma-international.org)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style3&quot;&gt;1. Call ToString, giving it the this value as its argument. &lt;br /&gt;2. Call ToString(searchString). &lt;br /&gt;3. Call ToInteger(position). (If position is undefined or not supplied, this step produces the value 0). &lt;br /&gt;4. Compute the number of characters in Result(1). &lt;br /&gt;5. Compute min(max(Result(3), 0), Result(4)). &lt;br /&gt;6. Compute the number of characters in the string that is Result(2). &lt;br /&gt;7. Compute the smallest possible integer k not smaller than Result(5) such that k+Result(6) is not greater than Result(4), and for all nonnegative integers j less than Result(6), the character at position k+j of Result(1) is the same as the character at position j of Result(2); but if there is no such integer k, then compute the value -1. 8. Return Result(7)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 짧은 영어로 해석해보자면,&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style3&quot;&gt;예를들어, str.indexOf(keyword) 라고 한다면&lt;br /&gt;&lt;br /&gt;1. 찾아볼 전체 문자열(str)을 가져오고&lt;br /&gt;2. 찾으려는 키워드(keyword)를 가져오고&lt;br /&gt;3. 찾으려는 시작점 Index를 가져오는데, 없으면 0으로 세팅되고&lt;br /&gt;4. 전체 문자열의 길이를 계산하고&lt;br /&gt;5. (0이랑 찾으려는 시작점 중 큰 값)을 추출해내고, 그걸 또 전체 문자열과 비교해서 작은 수를 계산해내고&lt;br /&gt;6. 찾으려는 키워드(keyword)의 길이를 계산하고&lt;br /&gt;7. 이제 상수 k를 통해서 결국 위에서 계산된 시작점에서부터 동일한 거 있는지 str을 뒤져보고 있으면 해당 index를 리턴, 없으면 -1을 리턴&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생짜 for문으로 하면 5번과정이 없어서 그런가, 싶다가도.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 결국 둘 다 0번 인덱스부터 반복문이 시작되는거면 다를 게 없는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(오히려 min,max 절차가 더해지니 함수호출로 복잡도가 올라가는 거 아닌가?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 포스팅의 결론은...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇백줄 짜리 코드를 짜다가 발생한 버그로 골머리를 앓는 학생의 뒤를,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;산보하듯 스윽, 걸어가다가 곁눈질만으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&lt;b&gt;N번째 줄에 버그가 있네, 학생&lt;/b&gt;.&quot; 이라는 명언을 남겨주셨던...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내게 SW공학을 가르쳐 주셨던 강쌤의 명언을 떠올리며 포스팅을 마무리 짓는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;굳이 있는 기능을 만드는 건 바보들이나 하는 짓입니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니, 이미 있는 indexOf를 잘 쓰도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(사실 더 파고들고 싶긴한데...회사 점심시간이 끝나간다...)&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/기타(Etc)</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/82</guid>
      <comments>https://blinders.tistory.com/82#entry82comment</comments>
      <pubDate>Thu, 13 May 2021 12:51:39 +0900</pubDate>
    </item>
    <item>
      <title>[npm] Accessing non-existent property 'OO' of module exports inside circular dependency</title>
      <link>https://blinders.tistory.com/81</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;npm run build 명령&lt;/b&gt;을 통해서, Vue Cli로 만든 프로젝트를 빌드&lt;/span&gt;하려했는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Accessing non-existent property 'cd' of module exports inside circular dependency&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Accessing non-existent property 'chcmod' of module exports inside circular dependency&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Accessing non-existent property 'cp' of module exports inside circular dependency&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 메세지가 콘솔창에 가득차며 되게 에러처럼 보이는 무언가를 뱉어낸다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;893&quot; data-origin-height=&quot;475&quot; width=&quot;750&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djphLz/btq20FAz7IB/CIvFqliOtMM0ilsReSZxIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djphLz/btq20FAz7IB/CIvFqliOtMM0ilsReSZxIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djphLz/btq20FAz7IB/CIvFqliOtMM0ilsReSZxIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjphLz%2Fbtq20FAz7IB%2FCIvFqliOtMM0ilsReSZxIk%2Fimg.png&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;893&quot; data-origin-height=&quot;475&quot; width=&quot;750&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이 메시지가 끝난 이후에도 build가 정상적으로 끝난 것처럼 정적 리소스들과 파일들의 용량 및 생성위치는 콘솔에 채워진다. 하지만...역시 찝찝하지 않은가? 저토록 많은 Warning이라니...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;해결법&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;콘솔창에 가득찬 메시지를 보면 뭔가 되게 &lt;b&gt;익숙한 키워드&lt;/b&gt;들이 보인다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;rm, cd, chmod, popd, echo...&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;쉘 명령어&lt;/b&gt;같이 생긴 키워드들이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;구글링을 열심히해보니, 위와 같은 메시지를 본 사람이 가득했고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;공통적으로 node.js 버전이 14.x 대인 사람들이 해당 이슈를 겪는걸&lt;/b&gt;&lt;/span&gt;로 보였다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나또한 이번에 노트북을 바꾸면서 node.js 버전을 14로 올린 이후에 저런 메시지가 npm run build시에 발생했고 node.js 12.x 버전이 설치된 기존 노트북에서는 다시 실행해봐도 저런 메시지가 나오지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그리고 좀 더 찾아보니...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/release-it/release-it/pull/652&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/release-it/release-it/pull/652&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618898289437&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Update &amp;#96;shelljs&amp;#96; dependency by ehmicky &amp;middot; Pull Request #652 &amp;middot; release-it/release-it&quot; data-og-description=&quot;release-it currently prints the following warnings in Node 14: (node:32597) Warning: Accessing non-existent property 'cat' of module exports inside circular dependency at emitCircularRe...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/release-it/release-it/pull/652&quot; data-og-url=&quot;https://github.com/release-it/release-it/pull/652&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/vua52/hyJWDzexck/WzYKrwWYLH5nngYP7wdKtk/img.png?width=1200&amp;amp;height=600&amp;amp;face=973_142_1040_215&quot;&gt;&lt;a href=&quot;https://github.com/release-it/release-it/pull/652&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/release-it/release-it/pull/652&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/vua52/hyJWDzexck/WzYKrwWYLH5nngYP7wdKtk/img.png?width=1200&amp;amp;height=600&amp;amp;face=973_142_1040_215');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Update `shelljs` dependency by ehmicky &amp;middot; Pull Request #652 &amp;middot; release-it/release-it&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;release-it currently prints the following warnings in Node 14: (node:32597) Warning: Accessing non-existent property 'cat' of module exports inside circular dependency at emitCircularRe...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 내용의 릴리즈 내용이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로 말하자면 node.js로부터 의존성(dependency)이 걸린&lt;b&gt; shell.js의 버전이 0.7.x대일때 node.js 14.x와 호환시 이슈&lt;/b&gt;가 있었고, 해당 이슈는 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;shell.js의 0.8.4 버전에서 fix되었다는 내용&lt;/b&gt;&lt;/span&gt;이었다. 그래서 package-lock.json을 열어서 확인해보니...나한테 설치된 shell.js가 0.7.8 이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 package-lock.json에서 shell.js 항목을 지운 뒤(혹여나 캐시처리되서 0.7.8이 재설치될까봐),&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;package.json의 devDependencies에 아래와 같이 shell.js의 버전을 명시하여 npm install을 재실행하였고&lt;/p&gt;
&lt;pre id=&quot;code_1618898589011&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; &quot;shelljs&quot;: &quot;^0.8.4&quot;,&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과 npm run build를 실행해도 위와 같은 Warning 메시지가 생성되지 않았다.&lt;/p&gt;</description>
      <category>개발/트러블 슈팅(Trouble Shooting)</category>
      <category>build</category>
      <category>Front-end</category>
      <category>frontend</category>
      <category>Node</category>
      <category>node.js</category>
      <category>NPM</category>
      <category>shelljs</category>
      <category>개발자</category>
      <category>트러블슈팅</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/81</guid>
      <comments>https://blinders.tistory.com/81#entry81comment</comments>
      <pubDate>Tue, 20 Apr 2021 15:05:05 +0900</pubDate>
    </item>
    <item>
      <title>[vue.js] did you register the component correctly? For recursive components, make sure to provide the &amp;quot;name&amp;quot; option.</title>
      <link>https://blinders.tistory.com/80</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;문제점&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;개발중인 Vue.js 기반의 프로젝트에서, &lt;span style=&quot;color: #ee2323;&quot;&gt;배포를 위해 빌드를 하던중&lt;/span&gt;에&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;배포된 상태의 용량을 최대한 줄이기 위해&lt;/span&gt;서 import된 npm 패키지들을 분석하던 도중에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;컴포넌트 쪽 패키지가 생각보다 너무 크길래 줄이려고 시도하다가 난 이슈다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;확인결과 해당 컴포넌트 패키지를 &lt;span style=&quot;color: #ee2323;&quot;&gt;import 하는 대상이, minify &amp;amp; uglify가 적용되지 않은 js를 사용&lt;/span&gt;하고 있었기에 &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;minify &amp;amp; uglify 된 파일을 import 하는 형태로 바꿨는데...콘솔이 에러메시지로 가득차버렸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;did&amp;nbsp;you&amp;nbsp;register&amp;nbsp;the&amp;nbsp;component&amp;nbsp;correctly?&amp;nbsp;For&amp;nbsp;recursive&amp;nbsp;components,&amp;nbsp;make&amp;nbsp;sure&amp;nbsp;to&amp;nbsp;provide&amp;nbsp;the&amp;nbsp;&quot;name&quot;&amp;nbsp;option.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;246&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OLAtc/btq17ZM2lLh/bgQTI8vYV7UTFSSoWzakA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OLAtc/btq17ZM2lLh/bgQTI8vYV7UTFSSoWzakA1/img.png&quot; data-alt=&quot;비공개해야하는 부분은 캡쳐에서 지웠습니다, 이해 바래여&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OLAtc/btq17ZM2lLh/bgQTI8vYV7UTFSSoWzakA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOLAtc%2Fbtq17ZM2lLh%2FbgQTI8vYV7UTFSSoWzakA1%2Fimg.png&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;246&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;비공개해야하는 부분은 캡쳐에서 지웠습니다, 이해 바래여&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실, 이 에러는...&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Vue 파일에서 활용중인 컴포넌트가 제대로 Vue.install 이 되지 않았을 때 발생하는거&lt;/b&gt;&lt;/span&gt;라...익숙한 에러라서 더 헤맬 수 밖에 없었다. 노멀하게 빌드된 js는 되는데, 왜 minify &amp;amp; uglify를 적용한 js는 안 되는거지??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;...결론부터 말하자면, 팀원중 한 분이 설정값에 주석처리를 하고 올려뒀었다...&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1617872801747&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;output: {
    path : resolve(&quot;/dist&quot;),
    filename: 'component.min.js',
    libraryTarget: 'umd', // 이거랑
    library: 'component', // 이거
    umdNamedDefine: true
},&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;만약 컴포넌트 패키지를 '라이브러리'의 형태로 활용하는 체계가 아니었다면, 해당 항목은 필요가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 npm install을 통해서 라이브러리의 형태로 현재는 활용되고있기 때문에...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 설정값이 없으면 안 된다. &lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;위와 같이&lt;/span&gt; &lt;span style=&quot;color: #009a87;&quot;&gt;libraryTarget: 'umd' 로 설정을 해야, 라이브러리의 형태로 활용&lt;/span&gt;&lt;/b&gt;이되고 그에따라 Vue에서 플러그인 설치를 위한 Vue.install도 적용이 되는 것이다.&lt;/p&gt;</description>
      <category>개발/트러블 슈팅(Trouble Shooting)</category>
      <category>Vue</category>
      <category>Vue.js</category>
      <category>개발</category>
      <category>웹</category>
      <category>웹개발</category>
      <category>트러블슈팅</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/80</guid>
      <comments>https://blinders.tistory.com/80#entry80comment</comments>
      <pubDate>Thu, 8 Apr 2021 18:15:34 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js_#-1] Vue.js 가이드 Github page를 완성했습니다.</title>
      <link>https://blinders.tistory.com/79</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요, 오랜만에 Vue.js 관련 포스팅을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;와...벌써 2021년 4월이라니...Vue.js 관련 마지막 포스팅이 작년 11월이네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blinders.tistory.com/76&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;([Vue.js_#04_2] 라우터(vue-router) vol.2&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무려 4개월이 넘는 시간동안 포스팅을 하지 않다니...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바쁘다는 건 늘 핑계라고 생각하는 성격상 입이 열개라도 할 말이 없습니다......만!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 열 한 번째 입이라도 강물에 둥둥떠서 살아보고자 이 포스팅을 쓰게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실, 티스토리에서 못 다한 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Vue 가이드 포스팅을 Github Page에서 완성&lt;/b&gt;&lt;/span&gt;해버렸답니다? &lt;span style=&quot;color: #ffc1c8;&quot;&gt;&lt;b&gt;에헷&amp;gt;_&amp;lt;?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;clap.gif&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;247&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBioKB/btq1TNM6UTN/KfNfxM40SpDDWng8FLQHF0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBioKB/btq1TNM6UTN/KfNfxM40SpDDWng8FLQHF0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBioKB/btq1TNM6UTN/KfNfxM40SpDDWng8FLQHF0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bBioKB/btq1TNM6UTN/KfNfxM40SpDDWng8FLQHF0/img.gif&quot; data-filename=&quot;clap.gif&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;247&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 티스토리에서 썼던만큼 개드립을 치지는 못 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왠지 Github에선 그러면 안 될 거 같았어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 정말 왠지, 그런 느낌적인 느낌이랄까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 드립을 걷어낸만큼 내용을 좀 더 보강했고, 최대한 담백하고 깔끔하게 이론을 풀어내서 정리했습니다. 쓰면서도 가장 고심했던 포인트는, Vue.js를 1도 모르는 쌩초보가 봐도 이해할 수 있었으면 좋겠다, 였는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사 동기에게 난이도 측정을 해 본 결과, 아주 적절하게 작성되었다는 생각을 가지게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 아마 제 또래에 분들은 아시겠지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교재를 사면 &lt;b&gt;교보재&lt;/b&gt;를 주는게 당연한 거 아니겠습니까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Vue 가이드와 함께 보면 좋은 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Vue 스타터 프로젝트도 하나 제공&lt;/b&gt;&lt;/span&gt;해 드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 또 우리 사이에 그냥 교보재만 달랑 주면 섭하잖아요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Vue 가이드의 맨 아랫메뉴에 '-1. 별첨 : Vue 스타터 프로젝트'을 추가했고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거기서 스타터 프로젝트를 낱낱이 헤쳐놓았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;444&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p7RRU/btq1XMsqLRI/TSKzK3vQkJlrEtwO1qiiK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p7RRU/btq1XMsqLRI/TSKzK3vQkJlrEtwO1qiiK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p7RRU/btq1XMsqLRI/TSKzK3vQkJlrEtwO1qiiK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp7RRU%2Fbtq1XMsqLRI%2FTSKzK3vQkJlrEtwO1qiiK0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;444&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보시면 아시겠지만 &lt;b&gt;아니 뭐, 이렇게까지 설명해놨어?;;;&lt;/b&gt;&amp;nbsp;라는 수준까지 설명해두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 디렉토리, 핵심 파일 하나하나 한땀한땀 놓치지않고 아주 그냥 장인정신으로 방망이 깍듯이,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생마늘이 간마늘이 될 만큼 팍팍 저를 갈아넣어서 만들었으니,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue.js를 시작하시는 분들께 좀 더 많은 도움이 됐으면 좋겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타터의 Github 레파지토리와 가이드 페이지 링크는 아래를 참고해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://onedayz.github.io/vue_guide&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Github Vue 가이드 페이지&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/onedayz/vue_starter&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Github Vue 스타터 레파지토리&lt;/a&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;어느새 이 글을 쓰는 시간이 새벽 5시 28분이네요...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;출근은 망한 거 같지만&amp;nbsp;늘 생각하는건데, 이런 밤샘은 정말 너무 즐겁네요.&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>Front-end</category>
      <category>github</category>
      <category>Vue</category>
      <category>Vue.js</category>
      <category>개발</category>
      <category>개발자</category>
      <category>웹</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/79</guid>
      <comments>https://blinders.tistory.com/79#entry79comment</comments>
      <pubDate>Tue, 6 Apr 2021 05:30:30 +0900</pubDate>
    </item>
    <item>
      <title>숫자 셋째자리에 컴마(,)찍는 정규표현식</title>
      <link>https://blinders.tistory.com/78</link>
      <description>&lt;pre id=&quot;code_1613319509830&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;str.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/기타(Etc)</category>
      <category>regexp</category>
      <category>숫자</category>
      <category>정규표현</category>
      <category>정규표현식</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/78</guid>
      <comments>https://blinders.tistory.com/78#entry78comment</comments>
      <pubDate>Mon, 15 Feb 2021 01:18:55 +0900</pubDate>
    </item>
    <item>
      <title>[210214] 발렌타인의 리스타트 기록</title>
      <link>https://blinders.tistory.com/77</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;그레이입니다, 오랜만이네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;놀랍게도 마지막 기술 포스팅이 작년 11월이네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까 대충 100일 정도는 아무런 글도 쓰지 않았다는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9월 중순경 투입된 프로젝트가 12월에 운영레벨로 최종이관이 되었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 과정에 있어서 11월부터 주말출근이 이어지는 빡센 일정과,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이관해야 할 메뉴얼정리를 비롯해서 운영자들 교육까지 호로록 달렸더니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느새 2020년을 지나 2021년이더군요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 1월은 제법 한가했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히 말하는 농한기라고하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실은 프로젝트가 마무리되어가는 시점에 또 다음 프로젝트지가 정해져서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1월에 이미 투입되었어야합니다만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코로나로 인해 프로젝트 일정 전체가 딜레이되버리는 바람에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차일피일 투입이 미뤄지고, 그로인해 한가해져버린거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이때다 싶은 생각에, 대기하면서 하고싶었던 일과 해야 할 일들을 좀 정리했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중에 하나가 사내 Vue.js 가이드를 만드는 거였는데..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...네, 이게 하다보니 또 우연찮게도 제가 작년에 포스팅했던 것들을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 '회사적'으로 정리하는 작업을 하게 되더라구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어 블로그 포스팅은 vue-router까지밖에 못 했는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'회사에서 쓰여야 하는 가이드'이기에, 최종 챕터까지 다 써버렸습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(그게 일이 되어버리니, 일로써 시간을 할애하게 되니까요)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대충 워킹데이 기준으로 2주반쯤 걸린 거 같은데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여튼 이것만 보면 'Vue.js 는 나도 한다'급의 가이드를 정리하게 되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(물론, 정말 Vue.js를 심도있게 공부해보고 싶은 분은 이 가이드만으로 모자랄거에요, 이건 입문자분들이 타겟이라서요)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여튼, 그러다보니 블로그에 쓰던 Vue 가이드도 얼른 정리를 좀 해야겠다는 생각이 들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나아가서는 사외 Github에도 사내 Github과 비슷하게 Github Page로 가이드를 작성할 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 오늘은 또 밤을 샐 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 내일 휴가거든요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 생각해도 휴가 내놓고 블로그에 기술 포스팅하는 인간은 확실히,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 인간의 범주에는 속하지 않은 거 같긴 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여튼, 리스타트합니다.&lt;/p&gt;</description>
      <category>개발/개발일지</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/77</guid>
      <comments>https://blinders.tistory.com/77#entry77comment</comments>
      <pubDate>Mon, 15 Feb 2021 01:11:46 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js_#04_2] 라우터(vue-router) vol.2</title>
      <link>https://blinders.tistory.com/76</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;어,음&amp;hellip;저번 포스팅때 이번편부터 본격적으로 Vue 파일들에 대해 파헤쳐보겠다고 했던 거 같은데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각해보니 &lt;b&gt;라우터와 관련해서 못 다한 이야기&lt;/b&gt;가 있어서 이렇게 또 라우터를 주제로 작성하게 됐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 나중에 좀 더 상세한 내용을 담는 포스팅에서 쓸까하다가, 그냥 나온김에 쓰자 싶어서요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(제 성격이 방학숙제조차도 미뤄놓으면 되게 찜찜해하는 타입이라 그렇습니다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이번편은 #04_2편 입니다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. vue-router는 사실 2개야.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, Vue에서 라우터 기능을 사용하기 위해서 우리는 하나의 npm 패키지를 설치해줘야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략 vue-router 라는 이름을 가진 npm 패키지구요, Vue.js를 활용하신다면 필수적으로 사용할 수 밖에 없는 라이브러리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 여기서 중요한 점은 포스팅을 작성하고 있는 현 시점에 vue-router의 종류가 2가지라는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-11-12 오전 9.54.12.png&quot; data-origin-width=&quot;549&quot; data-origin-height=&quot;386&quot; width=&quot;292&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DL5Uk/btqNcFWMTar/VnmgKJeaUp15Vefz6HKgYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DL5Uk/btqNcFWMTar/VnmgKJeaUp15Vefz6HKgYK/img.png&quot; data-alt=&quot;하나면 하나지, 둘이겠느냐. 둘이면 둘이지 셋은 아니야&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DL5Uk/btqNcFWMTar/VnmgKJeaUp15Vefz6HKgYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDL5Uk%2FbtqNcFWMTar%2FVnmgKJeaUp15Vefz6HKgYK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-11-12 오전 9.54.12.png&quot; data-origin-width=&quot;549&quot; data-origin-height=&quot;386&quot; width=&quot;292&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;하나면 하나지, 둘이겠느냐. 둘이면 둘이지 셋은 아니야&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 npm 패키지인데 왜 2개일까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 하나는 Vue 2.x대를 위한 vue-router 3.x 버전이구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 하나는 가장 최근에 나온 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Vue 3.x대를 위한 vue-router 4.x버전(a.k.a vue-router-next)&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 &lt;b&gt;vue-router-next는 놀랍게도 현재 베타버전&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-23 오전 12.10.02.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;274&quot; width=&quot;457&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czBJ88/btqNhaHH3O6/ci7gOVMfvJkQ8iMCgzVCd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czBJ88/btqNhaHH3O6/ci7gOVMfvJkQ8iMCgzVCd1/img.png&quot; data-alt=&quot;언제 정식 릴리즈 해 줄 건가요...ㅠㅠㅠ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czBJ88/btqNhaHH3O6/ci7gOVMfvJkQ8iMCgzVCd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczBJ88%2FbtqNhaHH3O6%2Fci7gOVMfvJkQ8iMCgzVCd1%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-23 오전 12.10.02.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;274&quot; width=&quot;457&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;언제 정식 릴리즈 해 줄 건가요...ㅠㅠㅠ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐, 어쩔 수 없겠죠. Vue 3.0 이 9월 중순에 공식 릴리즈를 했으니, &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;그에 대응하는 오픈소스들은 변경된 사항도 반영해야하고 버그도 잡고 추가개발도 해야하니...따라가기에도 얼마나 벅차겠습니까. 물론 한켠으론 vue-router 같은 핵심 패키지들과는 좀 협업해서 제때 내놨으면 좋았을텐데&amp;hellip;라는 생각도 들긴 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 본론으로 돌아와서 2개의 vue-router는 Vue 3에서 바뀐 체계에 따르기 때문에 당연하게도 이전과는 사용법이 다릅니다. 아니, 뭐...비슷한데 조금 달라요. 왜냐하면, &lt;b&gt;Vue 3.0에서 짜잔하고 등장한 Vue Application 때문&lt;/b&gt;에 그래요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue 2.x에서 Vue 인스턴스로 하던 일을 3.0부터 Vue Application 인스턴스가 대신하니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실제 코드로 정의하는 부분이 달라지는 건 당연한 거&lt;/b&gt;겠죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서, vue-router는 이에 대응하기 위해 추가적인 function을 만들어서 우리에게 제공해주고 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 사용법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;우선적으로 우리가 vue-router를 사용하기 위해서는 &amp;lsquo;설치&amp;rsquo;를 해줘야&lt;/b&gt; 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 npm 패키지는 package.json에 명시된 규약에 따라 npm install 이라는 명령어로 패키지를 설치할 수 있죠. 구글에서 vue-router를 검색한 후 &lt;a href=&quot;https://www.npmjs.com/package/vue-router&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;npm 패키지 사이트&lt;/a&gt;에 들어가보면 아래와 같이 가이드하고 있지만...&lt;/p&gt;
&lt;pre id=&quot;code_1605142827146&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i vue-router&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 위 코드를 썼을 때, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;설치되는 버전은 Vue 2.x에 타게팅 된 버전이 설치&lt;/b&gt;&lt;/span&gt;되게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 제가 제공하는 vue_starter 프로젝트는 Vue 3.x를 기반으로 하고 있기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 버전의 vue-router는 호환되지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버전을 올렸는데 호환이 안 된다는 게 말이 되냐...싶긴 합니다만 재차 언급하자면 현재는 Beta 버전이니까요. 정식 릴리즈 이후에는 해주지 않을까, 라는 기대는 합니다만 다들 아시다시피 기대가 크면 실망도 큽니다. 자, 그럼 우리는 어떻게 해야하느냐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;npm install 을 할 때 명시적으로 vue-router의 버전을 함께 적어주면 됩니다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1605142951976&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install vue-router@next&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 우리는 Vue 3.x를 위해 개발되고 있는 vue-router를 설치했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(오&amp;hellip;제가 Vue 포스팅을 시작한 9월 말까지만 해도 vue-router의 Status는 베타였는데, 이젠 Release Candidate로 바꼈네요, 조만간 정식으로 릴리즈 할 건가 봅니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;설치를 했으니, 우리 프로젝트에서 vue-router를 &amp;lsquo;사용하겠다&amp;rsquo;라고 명시해주는 코드가 필요&lt;/b&gt;&lt;/span&gt;합니다. 기본적으로 vue-router는 프로젝트에서 전역으로 활용되게 됩니다. 그도 그럴것이 어떤 화면에서든지 URL의 path 값을 바탕으로 그에 매핑된 vue 컴포넌트(화면급의 컴포넌트)들이 호출되야 하니까요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기때문에 Vue 프로젝트를 구성하는 모듈(파일)들의 진입점 역할을 하는 엔트리 파일에서 '사용하겠다'라는 코드가 정의되게 됩니다(이 규칙은, 단순히 vue-router 뿐만이 아니라 전역으로 쓰이는 컴포넌트, 혹은 차후에 포스팅 될 Store까지도 모두 엔트리 파일에 명시해줘야 합니다. 관리적인 측면에서도 여기저기 껌딱지처럼 두는 것보다는 훨씬 좋겠죠?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1605143117184&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createRouter, createWebHashHistory } from 'vue-router'
import router_main from './router/router_main'

let router = createRouter({
    history: createWebHashHistory(),
    routes: router_main
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 엔트리 파일에 vue-router를 위한 코드들이 있습니다(설명이 필요한 부분만 가져왔습니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, &lt;b&gt;import { createRouter, createWebHashHistory } from &amp;lsquo;vue-router&amp;rsquo;&lt;/b&gt; 를 봐주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import &amp;amp; from 구문은 이전 포스팅에서 설명을 해드린 적이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 주의깊에 보셔야 할 부분은 from 뒤에 따라오는 &amp;lsquo;vue-router&amp;rsquo;부분인데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;위와같이 별다른 alias없이 이름만 정의된 모듈들은 대부분 npm install을 통해서 설치된 npm 패키지&lt;/b&gt;&lt;/span&gt;를 뜻하며 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;해당 패키지들은 node_modules 디렉토리 아래에 위치&lt;/b&gt;&lt;/span&gt;하게 됩니다(마치 maven 인스톨을 통해 설치한 라이브러리들이 .m2 디렉토리 아래에 repository로 모여드는 것과 비슷하게 말이죠)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 중괄호를 통해서 vue-router 모듈로부터 필요한 2개의 function을 import 하고 사용하는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 function 아래와 같은 역할을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;createRotuer&lt;/b&gt; : 실제 Vue Router 인스턴스를 생성할 때 쓰이는 function&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;createWebHashHistory&lt;/b&gt; : Vue Router를 통해 URL로 매핑된 vue 컴포넌트를 전환할 시에 필요한 히스토리 관리 기법을, 해시형으로 쓸 수 있게 해주는 인스턴스를 생성하는 function&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style3&quot;&gt;여기서 히스토리에 대한 이야기가 잠깐 나와서 &lt;b&gt;부연설명&lt;/b&gt;을 좀 드리고 넘어갈게요.&lt;br /&gt;&lt;br /&gt;vue-router의 히스토리는 2가지 형식으로 관리가 됩니다.&lt;br /&gt;예를 들어, 책을 빌리는 화면의 path가 /book/rent 라고 한다면, &lt;br /&gt;위에서 사용한 해시 히스토리 기법은 전체 URL이 http://localhost:9090/&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;#&lt;/b&gt;&lt;/span&gt;/book/rent 이구요.&lt;br /&gt;또다른 히스토리 인스턴스 생성 function인 createWebHistory를 사용하면 http://localhost:9090/book/rent 와 같은 형태가 됩니다.&lt;br /&gt;&lt;br /&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Port 뒤에 해시태그가 붙냐, 붙지 않냐의 차이&lt;/b&gt;&lt;/span&gt;라고 볼 수 있는데요.&lt;br /&gt;이 해시태그가 해주는 주요역할이 바로&amp;nbsp; &amp;lsquo;브라우저의 인식&amp;rsquo;입니다.&lt;br /&gt;&lt;br /&gt;기본적으로 브라우저(IE든 크롬이든 Edge든 뭐든)는 &lt;b&gt;#&lt;/b&gt; 이 붙은 URL의 뒷내용은 인지하지 못 합니다. 즉, 일반적인 경우에&amp;nbsp;&lt;b&gt;# 뒤의 값이 변하더라도 브라우저는 새로운 화면을 로드&lt;/b&gt;하지 않습니다. &lt;br /&gt;만약 우리가 http://localhost:9090/#/book/main 에서&amp;nbsp;&amp;nbsp;&lt;br /&gt;http://localhost:9090/#/book/rent 로 이동을 한다하더라도 &lt;b&gt;브라우저는 화면이 &amp;lsquo;전환&amp;rsquo;되었다고 인지하지 못 한다&lt;/b&gt;는 겁니다. &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;대신에 vue-router가 그걸 인지&lt;/b&gt;&lt;/span&gt;하고 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;URL에 알맞게 매핑된 vue 컴포넌트를 호출&lt;/b&gt;&lt;/span&gt;해주는 것이죠.&lt;br /&gt;&lt;br /&gt;반면에, 해시태그가 없는 경우, 브라우저 스스로가 URL이 바꼈음을 인지하게 됩니다. &lt;br /&gt;그리고 그에따라서 알맞은 vue 컴포넌트를 호출하게 되는 것이구요. &lt;br /&gt;예전에 jsp, html, php를 사용하던 방식이 바로 이와 같이 URL의 경로를 변경함으로써 브라우저가 이를 인식하고 그에 맞는 정적페이지들을 로딩해왔었죠. 이 방식이 바로 그에 착안한 방식이라고 할 수 있습니다.&lt;br /&gt;&lt;br /&gt;다만,&lt;b&gt; 이 경우엔 REST API를 위한 path와 URL상으로 부딪힐 염려가 있고, 혹은 적절하게 매핑된 vue 컴포넌트가 없을 경우 서버측으로부터의 404 에러가 발생할 수 있다는 점 &lt;/b&gt;기억해주세요.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 다음 코드는 실제 path와 vue 컴포넌트간의 매핑이 정의된&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;import router_main from &amp;lsquo;./router/router_main&amp;rsquo;&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 파일은 앞선 포스팅에서 설명을 드렸었는데요. 실제 URL의 path로 쓰이는 값들과, 그 값들이 호출되었을 때 불려질 vue 컴포넌트들에 대한 내역을 정의하고 있는 파일입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(물론 이건 제가 제공해드리는 vue_starter 기준이구요, 여러분은 다른 이름이겠죠?)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue-router 인스턴스를 생성할 때, 당연히 path와 vue 컴포넌트가 어떻게 매핑이 되어있는지를 전달해줘야 실제 동작의 기반으로 삼을 수 있기 때문에 위와 같이 import를 해서 모듈로 불러오는 거구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가져온 router_main.js 파일의 내용은 다음 코드에 기입된 것과 같이 &lt;b&gt;createRouter function의 파라미터&lt;/b&gt;로 사용되게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1605143557998&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let router = createRouter({
    history: createWebHashHistory(),
    routes: router_main
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 createRouter의 파라미터 중 나머지 하나가 바로 위에서 언급했던 히스토리를 위한 &lt;b&gt;createWebHashHistory &lt;/b&gt;죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아, 여러분 이쯤에서 잊으셨을법한 포인트를 짚어드릴게요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 최종목표는 Vue입니다. vue-router는 Vue.js를 잘 활용할 수 있도록 도와주는 도구에 불과하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 createRouter로 생성한 vue-router 인스턴스를, createApp function을 통해 생성한 Vue Application 인스턴스에게 전달해줘야만 실제로 사용을 할 수 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로, 다음과 같은 코드로 말이죠&lt;/p&gt;
&lt;pre id=&quot;code_1605143640826&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let router = createRouter({
    history: createWebHashHistory(),
    routes: router_main
});

const app = createApp(App);
app.use(router);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 여기까지했으면 이제 vue 컴포넌트 어디서든지 &amp;lt;router-view&amp;gt; 라는 태그를 &amp;lt;template&amp;gt; 영역에서 사용하시면, 엔트리 파일에서 정의하고 생성한 vue-router 인스턴스가 그 위치에서 활용되게 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 라우터의 이동&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 거의 다 왔습니다. 조금만 더 힘을 내주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-11-12 오전 10.15.23.png&quot; data-origin-width=&quot;581&quot; data-origin-height=&quot;470&quot; width=&quot;313&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ct7jzv/btqNgtndYkd/mIQXiyKOvZnwnFvzg8WCzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ct7jzv/btqNgtndYkd/mIQXiyKOvZnwnFvzg8WCzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ct7jzv/btqNgtndYkd/mIQXiyKOvZnwnFvzg8WCzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fct7jzv%2FbtqNgtndYkd%2FmIQXiyKOvZnwnFvzg8WCzK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-11-12 오전 10.15.23.png&quot; data-origin-width=&quot;581&quot; data-origin-height=&quot;470&quot; width=&quot;313&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번 편을 유심히 오셨던 분이라면, &lt;a href=&quot;https://blinders.tistory.com/74&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;별첨으로 넣었던 -1 인덱스&lt;/b&gt;&lt;/a&gt;에서 이런 코드를 보신 적이 있을 겁니다.&lt;/p&gt;
&lt;pre id=&quot;code_1605143765544&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;moveTo(url){ 
    this.$router.push(url); 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론부터 말하자면, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;this.$router 라는 전역 객체가 가지고 있는 push 함수를 통해서 라우터를 이동&lt;/b&gt;&lt;/span&gt;을 하게 됩니다, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;전달되는 파라미터의 경로로&lt;/b&gt;&lt;/span&gt; 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 해당 경로는 path와 component를 페어로 정의한 router_main.js에 있는 규칙에 따릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서는 전달 된 url의 경로로 움직이게 되어있죠? 해당 함수의 호출부는 아래와 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1605143866202&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;gnb-menu&quot; v-for=&quot;(menu, idx) in gnbMenu&quot; 
    :key=&quot;idx&quot; @click=&quot;moveTo(menu.url)&quot;&amp;gt;
    {{menu.name}}
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 활용된 gnbMenu라는 배열은 아래와 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1605143964563&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;gnbMenu: [
    {name: 'Intro', url: '/main/intro'},
    {name: 'Front-end', url: '/main/front'},
    {name: 'Back-end', url: '/main/back'}
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마, Vue.js의 문법이라 이게 뭐야, 라고 생각하실 분들을 위해 간단히 설명하자면 gnbMenu라는 배열이 가지고 있는 수만큼 for문(v-for)이 돌면서 위의 &amp;lt;div&amp;gt;태그를 그려주게 되는겁니다. 그리고 해당 &amp;lt;div&amp;gt;태그를 클릭했을 시에, moveTo라는 메서드를 호출하구요. 호출시에 파라미터로 gnbMenu의 인덱스들이 가지고 있는 url 값을 전달하고 있네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;'Front-end'라는 라벨을 클릭하면 /main/front 경로로 this.$router.push('/main/front')를 호출&lt;/b&gt;&lt;/span&gt;하게 되구요. 그에 맞게 router_main.js 파일에 매핑된 frontEnd.vue component가 호출되게 되는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;push외에 또 다른 라우터 이동방법도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;go&lt;/b&gt;&lt;/span&gt; 인데요. &lt;b&gt;push함수와의 차이점은 전달되는 파라미터가 문자열로 이루어진 path의 형태가 아니라 숫자라는 점&lt;/b&gt;인데요. 이 숫자는, vue router 인스턴스가 내부적으로 가지고 있는 history에 기초하여 움직이게 되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, this.$router.go(-1) 을 호출하게되면 이전 페이지로.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;this.$router.go(1)으로 호출하게되면 다음 페이지로 이동하게 되는 간단한 로직인거죠&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;(당연하게도 너무 많은 수, 혹은 너무 적은 수를 전달하게되면 해당 히스토리가 없을 가능성이 높기때문에 정상적으로 페이지 이동을 하지 않습니다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. param과 query&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 특정 path 값을 this.$router 객체가 기진 함수에 전달함으로써,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 서비스에 화면전환을 요청 할 수 있게 되었습니다. 제가 제공해드리는 코드 기준으로보자면, 위에서도 간략히 설명드렸지만 gnbFrame.vue에 있는 gnbMenu를 기반으로 동작을 하게 되어있는거죠&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(아마도, 실제 서비스를 개발하신다면 이런 메뉴체계 자체도 REST API를 통해서 서버로부터 가져올거고, 약속된 데이터의 형태를 바탕으로 GNB 및 LNB를 구성해주시면 되겠습니다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 그럼 여기서 &lt;b&gt;한 걸음 더&lt;/b&gt; 나아가보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;vue router의 path라는 건, 늘 고정된 형식이진 않습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;path를 전달하면서 화면이 매핑된 컴포넌트로 전환이 될 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이전 화면에서 다음 화면으로 전달을 해줘야 하는 값이 있을 수도 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 1번 화면은 사용자의 목록을 보는 화면이고, 여기서 사용자의 이름을 클릭하면 그 사용자의 상세데이터를 보는 2번 화면으로 이동한다고 가정해보겠습니다. 그렇다면, &lt;b&gt;사용자목록에서 선택한 사용자의 정보&amp;hellip;그러니까 보편적인 경우라면 사용자의 ID가 될텐데요. 이 ID를 2번 화면으로 넘겨줘야 하는 경우&lt;/b&gt;가 있을 수 있다는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번 화면의 사용자의 목록을 보는 path가 /user/list 였고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번 화면의 특정 사용자의 상세 데이터를 보는 path가 /user/detail 라고 했을 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번의 path인 /user/detail은 아래와 같은 2가지 형태를 위함으로써&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번 화면에서 사용자의 ID 정보를 넘겨 줄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/user/detail&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;?userId=grey&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/user/detail&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;/grey&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 경우를 &lt;b&gt;각각 vue router의 query 방식, param 방식&lt;/b&gt;이라고 부르는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 우리는 웹개발을 할 때, 종종 URL의 path 영역 뒤에 물음표가 있는 형태를 봐왔을 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 SPA든, 아니든 상관없이 아주 흔하게 볼 수 있는 형태인데요. &lt;b&gt;물음표 뒤에&amp;nbsp; 붙은 것들은 키&amp;amp;밸류 형태를 띄게되어있구요. 이러한 형태의 데이터들 우리는 query&lt;/b&gt;라고 부릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이렇게 전달 된 query 값들은 아래와 같이 발췌해서 코드에서 사용되게 됩니다&lt;/p&gt;
&lt;pre id=&quot;code_1605144470024&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;title&quot;&amp;gt;&amp;lt;h3&amp;gt;Router Example&amp;lt;/h3&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;&amp;lt;h4&amp;gt;URL Query : {{$route.query.userName}}&amp;lt;/h4&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 한 가지 방식은 param 인데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;query방식은 URL을 보면 누구나 아, 저게 query구나. 라고 짐작을 할 수 있지만 param 방식은 한 번에 이게 param 방식이라는 걸 알아채기 힘듭니다. 왜냐면, &lt;b&gt;실제 사용되는 URL에 아주 자연스럽게 녹아들어가 있기 때문&lt;/b&gt;이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 해당 방식은 애초에 vue router가 정의되는 js파일에 아래처럼 선정의가 되어있어야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1605144544719&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{ path: '/router/:userId', component: RouterExample }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;path의 정의방식이 조금 다른 게 보이시나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 값으로 쓰이는 param의 경우에는 path를 이루는 단어 앞에 콜론이 붙어서 정의되게 되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 이름을 그대로 실제 코드에서 활용 할 수 있게 됩니다. 아래 코드 처럼 말이죠.&lt;/p&gt;
&lt;pre id=&quot;code_1605144573250&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;title&quot;&amp;gt;&amp;lt;h3&amp;gt;Router Example&amp;lt;/h3&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;&amp;lt;h4&amp;gt;URL Param : {{$route.params.userId}}&amp;lt;/h4&amp;gt;&amp;lt;/div&amp;gt;
           &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 주의해주실 점은, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;this.$router와 this.$route가 각각 사용되고 있다는 건데요.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;path를 파라미터로 전달함으로서 &lt;b&gt;화면간의 이동을 제어할 때는 this.$router를 사용&lt;/b&gt;했구요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;query나 param과 같이 &lt;b&gt;전달 된 값을 활용하기위해 꺼낼 때는 this.$route를 활용&lt;/b&gt;했다는 걸 꼭 기억하시고 헷갈리지 말아주시기를 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와같이 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;현재 화면에서 필요한 특정 &amp;lsquo;값&amp;rsquo;을 이전화면으로부터 넘겨받아야 하는 경우에는 query 혹은 param 방식을 때에따라 활용&lt;/b&gt;&lt;/span&gt;해주시면 됩니다&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style3&quot;&gt;vue_starter 프로젝트에서 query와 param에 대한 예제는 home.vue 와 routerExample.vue 파일을 봐주시면 됩니다. 정확히는 homve.vue 에서 routerExample.vue로 이동하는 예시를 만들어두었습니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;homve.vue에는 query와 param을 전달하는 부분.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;routerExample.vue에는 전달된 query와 param을 사용하는 부분.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;이렇게 나누어서 정의해두었습니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. beforeEach&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URL의 path가 변경됨에 따라서 이전페이지로부터 넘겨받아야 할 값을 전달하는 방식이, query와 param이었습니다. 그리고 여기서 설명 할 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;beforeEach는 바로 그 화면간의 전환 사이의 시기를 잡아채는 인터셉터&lt;/b&gt;&lt;/span&gt;라고 생각해주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 사용자 목록을 보는 1번 화면과, 선택된 사용자의 상세 정보를 보는 2번화면.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1번에서 2번으로 넘어가는 그 중간지점이 beforeEach&lt;/b&gt; 인겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-11-12 오전 10.34.06.png&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;257&quot; width=&quot;210&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VjJta/btqNfrwGfdp/Ri9s9FFoiPmg97iYxwcLy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VjJta/btqNfrwGfdp/Ri9s9FFoiPmg97iYxwcLy0/img.png&quot; data-alt=&quot;시간과 공간사이 그 어디쯤 아아ㅏㅏㅏ...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VjJta/btqNfrwGfdp/Ri9s9FFoiPmg97iYxwcLy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVjJta%2FbtqNfrwGfdp%2FRi9s9FFoiPmg97iYxwcLy0%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-11-12 오전 10.34.06.png&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;257&quot; width=&quot;210&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;시간과 공간사이 그 어디쯤 아아ㅏㅏㅏ...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 자세히 말해보자면 beforeEach는 function입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;param과 query가 this.$route라는 vue router 인스턴스 내부의 객체였다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;beforeEach는 이러한 vue router가 가지고 있는 function으로써 인터셉터의 역할을 수행&lt;/b&gt;합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(여담으로 beforeEach가 있으니 당연히 afterEach도 있습니다만&amp;hellip;Vue.js를 3년째하고 있는 저로써도 있다는 것만 알 뿐 사용해 본 적이 없어서 굳이 설명하진 않을게요)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;beforeEach를 사용할 때 &lt;b&gt;주요하게 보셔야 할 지점은, 바로 파라미터&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;beforeEach는 function이라고 설명을 드렸고 그렇기에 파라미터를 가지는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 아래와 같은 형태로 &lt;b&gt;from, to, next&lt;/b&gt; 라는 이름을 사용합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(vue router의 beforeEach에 정의된 순서에 따라 각 값들이 매핑되는거지만, 가독성을 높이기 위해 각 파라미터가 가지는 값별로 저런 이름을 붙였습니다)&lt;/p&gt;
&lt;pre id=&quot;code_1605145015237&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;router.beforeEach((to,from,next) =&amp;gt; {
    console.log(from.path + ' -&amp;gt; ' + to.path);
    next();
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;from은 말 그대로 이전 페이지의 정보를 가진 객체구요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;to는 다음 페이지의 정보를 가진 객체입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next는 콜백함수로 인터셉터 역할을 하는 beforeEach가 다음페이지로 넘어갈 지에 대한 처리를 해주게 됩니다. 음&amp;hellip;쓰고보니 이 문장이 좀 헷갈려 보이네요. 예제로 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-11-12 오전 9.34.07.png&quot; data-origin-width=&quot;999&quot; data-origin-height=&quot;369&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQPq6D/btqNcGg5UYn/pY8Us81C8ebO2S6KwcHoCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQPq6D/btqNcGg5UYn/pY8Us81C8ebO2S6KwcHoCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQPq6D/btqNcGg5UYn/pY8Us81C8ebO2S6KwcHoCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQPq6D%2FbtqNcGg5UYn%2FpY8Us81C8ebO2S6KwcHoCK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-11-12 오전 9.34.07.png&quot; data-origin-width=&quot;999&quot; data-origin-height=&quot;369&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 그림이 좀 더 이해가 쉬우실 거라고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;beforeEach의 역할이 인터셉터라고 했던만큼, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;잡아챘으니 다음으로 보내주는 동작도 명시적으로 정의해야하며 바로 그 역할을 하는 것이 next라는 콜백함수&lt;/b&gt;&lt;/span&gt;입니다. 그래서 위의 예시코드와 같이 beforeEach 를 사용 할 경우 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;next(); 라는 함수를 반드시 호출&lt;/b&gt;&lt;/span&gt;해줘야 다음 페이지로 넘어갈 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 만약 인터셉트로 잡아채서 다른 경로로 보내고 싶다. 라고 한다면 &lt;b&gt;next의 파라미터로 특정 path를 기입함으로써 해당 경로로 보내버릴 수 있는 겁니다&lt;/b&gt;. 이 경우에는 다음 페이지 역할을 하는 to 객체의 정보가 변경되었다고 vue router가 인식을 하고, &lt;b&gt;to.path의 값이 바뀐 상태로 한 번 더 beforeEach를 호출&lt;/b&gt;하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자&amp;hellip;이 말인 즉슨, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;여차하면 재귀라는 구렁텅이에 빠져서 여기도 저기도 갈 수 없게 된다는 말&lt;/b&gt;&lt;/span&gt;이라는 거 다들 눈치채셨을 겁니다. 한마디로 조심해서 잘 설계하고 개발해야 하는 영역이라는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어, &lt;b&gt;그래서 beforeEach가 언제 쓰이느냐,&lt;/b&gt; 에 대한 이야기를 해보자면.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 function은 &lt;b&gt;말그대로 인터셉터&lt;/b&gt;입니다. 예를 또 들어, 특정 사용자가 어떤 페이지로 들어가보고 싶은데 권한이 없을 수도 있잖아요? 관리자만 볼 수 있는 페이지가 있는데 일반 사용자가 브라우저에 다이렉트로 path 값을 변조해서 관리자 전용 페이지로 접근하려한다면 어떻게 막을 수 있을까요? 혹은 로그인하지 않은 사용자를 무조건 로그인 페이지로 보내야한다면 어떻게 할 수 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때 쓰이는 게 바로 &lt;b&gt;beforeEach를 통해 권한을 체크한다던가. 혹은 특정 조건을 충족하는 사람은 별도의 페이지로 리다이렉트&lt;/b&gt;시킨다던가. 하는 역할을 beforeEach가 담당하게 되는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서도 보여드렸던 코드이긴 합니다만, 간략한 예제를 보여드리기위해 현재 제 vue_starter 프로젝트에는 아래와 같이 엔트리파일인 main.js에 from -&amp;gt; to의 경로를 콘솔 로그에 찍게끔 만들어놓았구요. 실제 페이지이동시에 개발자도구를 띄워보시면 콘솔에 경로가 찍히는 걸 확인하실 수 있을겁니다.&lt;/p&gt;
&lt;pre id=&quot;code_1605145223329&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let router = createRouter({
    history: createWebHashHistory(),
    routes: router_main
});

const app = createApp(App);
app.use(router);

router.beforeEach((to,from,next) =&amp;gt; {
    console.log(from.path + ' -&amp;gt; ' + to.path);
    next();
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제코드와 같이 createRouter 메서드를 통해 생성된 vue router 인스턴스를 활용하여 beforeEach function을 정의해주시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>Front-end</category>
      <category>Vue</category>
      <category>Vue.js</category>
      <category>개발</category>
      <category>개발자</category>
      <category>웹</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/76</guid>
      <comments>https://blinders.tistory.com/76#entry76comment</comments>
      <pubDate>Thu, 12 Nov 2020 10:44:23 +0900</pubDate>
    </item>
    <item>
      <title>[npm] run `npm audit fix` to fix them, or `npm audit` for details</title>
      <link>https://blinders.tistory.com/75</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;npm install 명령어를 통해서 패키지를 설치&lt;/span&gt;하는데, 아래와 같이&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;run `npm audit fix` to fix them, or `npm audit` for details&lt;/b&gt;&lt;/span&gt; 라는 에러가 발생했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;npm_install_audit.PNG&quot; data-origin-width=&quot;799&quot; data-origin-height=&quot;197&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UNCHk/btqLNrr84e6/k66rUZ1yi1nNq9ktzjeyj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UNCHk/btqLNrr84e6/k66rUZ1yi1nNq9ktzjeyj0/img.png&quot; data-alt=&quot;run `npm audit fix` to fix them, or `npm audit` for details&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UNCHk/btqLNrr84e6/k66rUZ1yi1nNq9ktzjeyj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUNCHk%2FbtqLNrr84e6%2Fk66rUZ1yi1nNq9ktzjeyj0%2Fimg.png&quot; data-filename=&quot;npm_install_audit.PNG&quot; data-origin-width=&quot;799&quot; data-origin-height=&quot;197&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;run `npm audit fix` to fix them, or `npm audit` for details&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;npm을 다룬지도 한참됐는데...처음보는 에러라서 또 뭔가 프록시 설정을 누락했거나, npm config 설정값에 문제가 있는 줄 알았는데, 그게 아니고 npm audit 라고, 각 패키지들이 가진 취약점을 체크해주는 로직이 들어 왔다는 거였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;npm 패키지 자체가 install 시에 물고물고물린 의존성에 따라 여러 패키지들을 알아서 설치해주다보니, 그 과정에 발생할 수 있는 이슈를 대비하기위해 해주는 거&lt;/span&gt;라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;해결법&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;생각보다 심플&lt;/b&gt;&lt;/span&gt;하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;해당 audit 옵션을 쓰지 않겠다는 옵션을 아래와 같이&lt;/b&gt;&lt;/span&gt; 주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(사실 좀 더 세분화해서 보자면 어디에 어떤 패키지가 취약한지 찾아서 버전업을 일일이 해주는게 좋다. 사실 그런 목적으로 만들어진 거라고하고, 옵션에 따라 표로 세분화한 내역까지 콘솔에 보여준다고 한다. 좀 더 심도있게 알고싶으신 분들은 &lt;a href=&quot;https://blog.outsider.ne.kr/1375&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;아웃사이더님의 블로그&lt;/a&gt;를 참고해주시기 바랍니다)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1603763961600&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install --no-audit&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/트러블 슈팅(Trouble Shooting)</category>
      <category>audit</category>
      <category>frontend</category>
      <category>install</category>
      <category>NPM</category>
      <category>Vue</category>
      <category>Vue.js</category>
      <category>개발</category>
      <category>웹개발</category>
      <category>트러블슈팅</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/75</guid>
      <comments>https://blinders.tistory.com/75#entry75comment</comments>
      <pubDate>Tue, 27 Oct 2020 11:03:28 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js_#04] 라우터(vue-router)</title>
      <link>https://blinders.tistory.com/74</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0. Intro&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 편을 쓴 지 일주일이 넘었네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빠르게 되짚고 시작해보도록 하겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐면 지금 이미 새벽 4시거든요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 오늘은 화요일이라, 오늘도 출근을 해야하니까요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 저번 포스팅에서 했던 마지막 단락을 되짚어 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-05 오전 3.16.08.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;479&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVwery/btqLf7OiY6X/h9yK2jwCKiacYEmt1ktn4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVwery/btqLf7OiY6X/h9yK2jwCKiacYEmt1ktn4K/img.png&quot; data-alt=&quot;Vue로 이루어진 SPA의 기본 틀은 대부분 왠만해선 다 이렇습니다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVwery/btqLf7OiY6X/h9yK2jwCKiacYEmt1ktn4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVwery%2FbtqLf7OiY6X%2Fh9yK2jwCKiacYEmt1ktn4K%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-05 오전 3.16.08.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;479&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Vue로 이루어진 SPA의 기본 틀은 대부분 왠만해선 다 이렇습니다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;index.html 이라는 하나의 정적 파일이 있고, 브라우저는 얘만 로딩합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;SPA&lt;/b&gt;&lt;/span&gt;(&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;S&lt;/b&gt;&lt;/span&gt;ingle &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;P&lt;/b&gt;&lt;/span&gt;age &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;A&lt;/b&gt;&lt;/span&gt;pplication) 개념이 적용이 되는 거였구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 index.html 파일에는 우리가 익히 아는 &amp;lt;div&amp;gt; 태그 하나와,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;build.js를 정의하는 코드로 이루어져 있었습니다&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(기타 메타태그는 그냥 무시할게여)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 딱 하나 있는 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;&amp;lt;div&amp;gt; 태그가 가진 id &amp;lsquo;app&amp;rsquo;&lt;/b&gt;&lt;/span&gt;를, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Vue Application 인스턴스(Vue 2.x버전의 경우 Vue 인스턴스)가 가리킴&lt;/b&gt;&lt;/span&gt;으로써 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;그 위치에 Vue로 이루어진 화면들이 그려진다&lt;/b&gt;&lt;/span&gt;고 말씀을 드렸었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 엔트리파일이라는 녀석이 등장하구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Vue Application 인스턴스의 생성&lt;/b&gt;&lt;/span&gt; 및&lt;span style=&quot;color: #009a87;&quot;&gt; &lt;b&gt;id가 app인 &amp;lt;div&amp;gt;태그를 가리키도록&amp;nbsp; 정의&lt;/b&gt;&lt;b&gt;해 놓은 파일&lt;/b&gt;&lt;/span&gt;을 우리는 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;엔트리파일(main.js)&lt;/b&gt;&lt;/span&gt;이라고 부릅니다. 또한, 엔트리 파일은 모듈로 정의할 수 있는 N개의 파일들이 build.js라는 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;하나의 파일로 집약될 수 있도록 돕는 진입점&lt;/b&gt;&lt;/span&gt;이라고 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지가 저번 포스팅의 내용이었죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 여기까지 잘 따라오셨으면 이제 본 포스팅을 시작하도록 하겠습니다. 이번 포스팅의 주제는 예고했던대로 Router에 대해 설명해보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Router(vue-router)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 흔히 아는 라우터는 이겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.42.54.png&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;487&quot; width=&quot;444&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baivdr/btqLepaDUBH/tJm7YAMCN9985KDT4futbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baivdr/btqLepaDUBH/tJm7YAMCN9985KDT4futbk/img.png&quot; data-alt=&quot;출처 : 위키백과 라우터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baivdr/btqLepaDUBH/tJm7YAMCN9985KDT4futbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbaivdr%2FbtqLepaDUBH%2FtJm7YAMCN9985KDT4futbk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.42.54.png&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;487&quot; width=&quot;444&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 위키백과 라우터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사진의 출처를 따라 위키백과에서 '라우터'로 검색을 해보면 아래와 같이 정의되어 있구요&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;라우터(router,&amp;nbsp; 혹은&amp;nbsp; 라우팅기능을 갖는&amp;nbsp; 공유기)는&amp;nbsp; 패킷의 위치를 추출하여, 그 &lt;b&gt;위치에 대한 최적의 경로를 지정&lt;/b&gt;하며, &lt;b&gt;이 경로를 따라 데이터 패킷을 다음 장치로 전향시키는 장치&lt;/b&gt;이다. 이때 최적의 경로는 일반적으로는 가장 빠르게 통신이 가능한 경로이므로, 이것이 최단 거리 일수도 있지만, 돌아가는 경로라도 고속의 전송로를 통하여 전달이 되는 경로가 될 수 있다. 간단히 말해 서로 다른 네트워크 간에 중계 역할을 해준다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말이 되게 기네요. 쉽게 설명하자면 그냥 들어 온 요청을 적절한 곳으로 보내주는 겁니다. 이쪽으로 가세요, 저쪽으로 가세요, 하고 &lt;b&gt;안내해주는 역할&lt;/b&gt;이라는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Vue에서의 Router 개념도 이와 마찬가지&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 위키에 있는 라우터의 정의와 비교를 해보자면 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;들어 온 요청은 path, 적절한 곳은 vue 파일, 에 대입이 됩니다. 이때 언급되는 path는 아래와 같이 URL 개념에서 나오게 되는데요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-13 오전 4.03.05.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;310&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mVXFb/btqLf7Hwxgw/U8oBlUowQi8KVL9OMdWbf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mVXFb/btqLf7Hwxgw/U8oBlUowQi8KVL9OMdWbf0/img.png&quot; data-alt=&quot;출저 : 개발자들을 위한 블로그 서비스, Velog&amp;amp;amp;nbsp;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mVXFb/btqLf7Hwxgw/U8oBlUowQi8KVL9OMdWbf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmVXFb%2FbtqLf7Hwxgw%2FU8oBlUowQi8KVL9OMdWbf0%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-13 오전 4.03.05.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;310&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출저 : 개발자들을 위한 블로그 서비스, Velog&amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;노란색으로 강조된 &lt;span style=&quot;color: #f3c000;&quot;&gt;path&lt;/span&gt;&lt;/b&gt;라고 정의되어 있는 영역이 보이시나요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 흔히 host라고 부르는 웹 브라우저의 주소에서 &lt;b&gt;포트 이후의 뒷 영역을 path라고 정의&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 SPA가 아닌 형태로 웹개발을 많이 하셨던 분들이라면 굉장히 익숙한 형태일텐데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;login.do로 넣으면 login.jsp가 불린다거나, main.jsp라고 넣으면 진짜 main.jsp가 호출된다거나.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것과 거어어어어어어어어의 똑같다고 보시면 되는데, 쪼오오오오오오오끔 다릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.50.45.png&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;264&quot; width=&quot;267&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bykjFc/btqLjtcd0Jk/ZXXoUSPw51Da3jsPQGSJ20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bykjFc/btqLjtcd0Jk/ZXXoUSPw51Da3jsPQGSJ20/img.png&quot; data-alt=&quot;말장난 같지만 진짜 거어어어어의 같은데, 쪼오오오오꼼 달라여...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bykjFc/btqLjtcd0Jk/ZXXoUSPw51Da3jsPQGSJ20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbykjFc%2FbtqLjtcd0Jk%2FZXXoUSPw51Da3jsPQGSJ20%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.50.45.png&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;264&quot; width=&quot;267&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;말장난 같지만 진짜 거어어어어의 같은데, 쪼오오오오꼼 달라여...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 SPA가 아닌 환경에서는 &lt;b&gt;보통 path 영역에 파일명이나 혹은 컨버팅된 대체 경로를 주입함으로써 웹 브라우저에게 해당 웹 페이지를 불러오게끔&lt;/b&gt; 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 누누이 말씀드린 것처럼 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;SPA는 단 하나의 정적 페이지를 기준으로하기 때문에 URL의 path 영역값이 바뀐다고해서 다른 정적 파일을 부르지 않습니다&lt;/b&gt;&lt;/span&gt;(정확하게는 URL의 path가 바뀌면 새로운 정적 파일을 로딩해야 하지만, SPA는 오직 하나의 정적 파일밖에 없으니 아마도 404 Not Found가 뜰 겁니다. 말 그대로 호출 할 HTML 파일이 없으니까요)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 우리는 로그인 기능을 가진 login.jsp도 홈 화면 역할을 할 main.jsp도, 도서를 대여하게 해주는 rent.jsp등등, 기존에 각 파일별로 나뉘어져 있던&amp;nbsp; 기능을 가진 화면들이 여전히 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서비스는 그런 화면과 기능들로 이루어져 있으니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 SPA기반의 Vue에서도 각각의 vue 파일들이 화면과 기능을 가지고 있습니다. 또한, URL에 적절한 path를 입력했을 때 어떤 vue 파일이 호출되는지에 대한 정의와 동작도 가지고 있습니다. 바로 router가 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백문이 불여일견이라, 우리는 백마디 말보다 한 줄의 코드가 더 이해하기 쉬울겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 바로 예시코드를 보시겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1603122935321&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Home from '@page/home';
import Content from '@page/content';
import mainFrame from '@page/frame/mainFrame';
import Intro from '@page/intro';
import BackEnd from '@page/backEnd';
import FrontEnd from '@page/frontEnd';
import NotFound from '@page/notFound';

const router_main = [
        { path: '/', redirect: '/home' },
        { path: '/home', component: Home },
        { path: '/content', component: Content },
        { path: '/main', component: mainFrame,
            children: [
                { path: '', redirect: '/main/intro'},
                { path: 'intro', component: Intro},
                { path: 'front', component: FrontEnd},
                { path: 'back', component: BackEnd},
            ]
        },
        { path: '/:catchAll(.*)', component: NotFound },
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 제가 깃헙에 올려놓은 vue_starter 프로젝트의 router_main.js 파일입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(경로는 src/router/router_main.js입니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라우터에 대한 가타부타 설명이 없었어도 위 코드의 동작방식을 충분히 어림짐작하실거라고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 그래도 굳이 설명을 해드려야, 이 포스팅을 작성하는 의미가 있겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찬찬히 짚어봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;path 가 &amp;ldquo;/&amp;ldquo;일 때는 &amp;ldquo;/home&amp;rdquo; 경로로 리다이렉트합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, vue_starter 프로젝트를 받으셔서 npm run serve를 하신 분이라면 http://localhost:9090/ 이 경로로 접근시 http://localhost:9090/#/home 경로로 자동 전환 될 겁니다. 그리고 &amp;ldquo;/home&amp;rdquo;이라는 path로 접근시 Home 이라는 컴포넌트에 매핑되도록 정의되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 매핑된 Home은 맨 첫줄에 작성된 import Home from &amp;lsquo;@page/home&amp;rsquo; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-20 오전 1.02.45.png&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;123&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dinVdx/btqLcUordZl/7kKnP48rXKhqtLJrMToVD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dinVdx/btqLcUordZl/7kKnP48rXKhqtLJrMToVD0/img.png&quot; data-alt=&quot;위 코드를 풀어보자면 @page/home 경로에 있는 모듈을 해당 파일내에서 Home 이라는 이름으로 쓰겠다, 는 겁니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dinVdx/btqLcUordZl/7kKnP48rXKhqtLJrMToVD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdinVdx%2FbtqLcUordZl%2F7kKnP48rXKhqtLJrMToVD0%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-20 오전 1.02.45.png&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;123&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위 코드를 풀어보자면 @page/home 경로에 있는 모듈을 해당 파일내에서 Home 이라는 이름으로 쓰겠다, 는 겁니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 경로를 정의한 '@page/home'에서 @page로 되어있는 부분은 alias입니다. 실제 가리키는 경로는 vue_starter프로젝트의 src\page 디렉토리이며 이와 관련된 정의는 vue.config.js 파일에 되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠깐 논외로 해당 코드를 짤막하게 나마 설명해보자면 import 라는 문법은 ES6에서 본격적으로 등장한 기법으로, 각각의 모듈들을 가져와서 활용할 때에 쓰입니다. 마치, JAVA에서 여러 라이브러리를 가져다 쓰듯이 말이죠. 다만, 여기서 import는 '모듈'을 가져오는 것이라고 했는데, 실제 코드에서는 아래와 같이 component에 가져온 모듈을 매핑해서 쓰고 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1603123693543&quot; class=&quot;javascript&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{ path: &quot;/home&quot;, component: Home },&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 실제 모듈이라고 가져왔지만, 해당 파일은 엄연히 home.vue 라는 Vue 파일이죠. 그렇기에, 이는 모듈임과 동시에 컴포넌트이기도한데요. 사실 모듈 &amp;amp; 컴포넌트...이 둘은 비슷하면서도 다른 개념입니다. 이에 대해 상세히 설명하기엔 본 포스팅의 주제에서 너무 엇나가기 때문에 그냥 여러분이 여기서 알아야 할 개념은 Vue 파일들을 하나하나가 컴포넌트다, 라고 이해해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(컴포넌트 임과 동시에 모듈이고 모듈임과 동시에 컴포넌트이기 때문에, 앞선 포스팅에서부터 계속해서 말씀드리고 있던...모듈들이 모여서 webpack이라는 모듈 번들러에 의해 하나의 build.js로 정착된다, 라는 개념에 vue 파일들도 속하게 되는 것입니다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 각각의 vue 파일은 컴포넌트이기 때문에 위와 같이 &quot;/home&quot; 이라는 path로 접근하게되면 home.vue 파일이 화면에 그려지게 되는 겁니다. 마찬가지로 &amp;ldquo;/content&amp;rdquo; path로 접근시 src/page 경로에 있는 content.vue 파일이 컴포넌트로써 화면에 그려지게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 마지막에 적힌 &lt;b&gt;catchAll은 Vue 3.x대에 도입된 문법&lt;/b&gt;으로 router에 의해 정의되지 않는 기타 path 값들을 잡아냅니다. 즉, &lt;b&gt;미정의한 경로에 대해 보여줄 vue 컴포넌트를 지정할 때&lt;/b&gt; 쓰이는 거죠. 이와 비슷한 맥락으로 &lt;b&gt;Vue 2.x 대에서는 &amp;ldquo;/*&amp;rdquo; 라는 path에 미정의한 경로로 접근시 보여질 vue 컴포넌트를 매핑&lt;/b&gt;시켜 놓곤 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 엔트리파일과 App.vue&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 보셨으면 이제 Router에 대해서 아셔야 할 게 한가지가 남았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;되짚어보자면 브라우저에 주소를 입력하거나 링크를 통해 우리의 웹 서비스로 접근을 했다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;URL의 path가 변경될때마다, 각각에 알맞게 매핑된 Vue 컴포넌트들이 호출&lt;/b&gt;&lt;/span&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 vue 컴포넌트(파일)들이 화면에 그려지게 된다, 라는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 이게 이번 포스팅이 핵심개념이구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 이 개념이 &lt;b&gt;실제로는 어떻게 파일들이 연계되어 호출되는지를 설명&lt;/b&gt;하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서 말하는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;lsquo;연계&amp;rsquo;&lt;/b&gt;&lt;/span&gt;란, 그렇게 경로(path)와 컴포넌트가 1:1로 매핑된 vue 컴포넌트들이&lt;b&gt; &amp;lsquo;어디&amp;rsquo;&lt;/b&gt;에 &lt;b&gt;'어떻게'&lt;/b&gt; 그려지는 지에 대한 설명을 뜻합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;결론부터 말씀드리자면, &amp;lt;router-view&amp;gt;라는 태그가 있는 위치에 그려지게 됩니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 제공해드리는 vue_starter를 기준으로 보자면 App.vue 파일을 열어보시면 아래와 같이 &amp;lt;template&amp;gt;영역에 해당 태그가 있는 것을 확인하실 수 있구요&lt;/p&gt;
&lt;pre id=&quot;code_1603124373876&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;router-view/&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 &lt;b&gt;저 위치에 router_main.js에 정의된 root path인 &amp;ldquo;/&amp;ldquo;부터 매핑되어 화면에 렌더링&lt;/b&gt;되게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 여기서 의문점이 하나 드는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;router-view&amp;gt;가 여기저기 모든 vue 파일에 선언되어 있으면 어떻게 path가 매핑이 되게 되는걸가요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령, App.vue에도 있고, home.vue에도 있고 content.vue에도 있고 막 그러면 어떻게 되는 건가요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무데나 &amp;lt;router-view&amp;gt;가 있으면, Vue는 어떻게 그 위치가 그 URL에 맞춰서 렌더링을 하는지 판단하는 건가요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 질문에 대한 답은, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Vue는 &amp;lsquo;트리&amp;rsquo;형으로 화면이 구성되는 걸 기본&lt;/b&gt;&lt;/span&gt;으로 하기 때문에, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;vue 컴포넌트들에 매핑되는 URL 체계도 &amp;lsquo;트리&amp;rsquo;형&lt;/b&gt;&lt;/span&gt;을 이루게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-20 오전 1.21.22.png&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;256&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wDsCj/btqLkKYSkGc/Xu3v0oBwsOdKsVbSjpyPv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wDsCj/btqLkKYSkGc/Xu3v0oBwsOdKsVbSjpyPv0/img.png&quot; data-alt=&quot;vue로 구성되는 화면과 Tree 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wDsCj/btqLkKYSkGc/Xu3v0oBwsOdKsVbSjpyPv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwDsCj%2FbtqLkKYSkGc%2FXu3v0oBwsOdKsVbSjpyPv0%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-20 오전 1.21.22.png&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;256&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;vue로 구성되는 화면과 Tree 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;vue 파일들의 기점은 App.vue를 루트(Root)&lt;/b&gt;로하여 &lt;b&gt;전체 Router가 형성&lt;/b&gt;된다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 한 발자국 더 나가면 화면의 구성자체가 트리이기 때문에, 화면을 이루는 vue 컴포넌트들과 1:1로 매핑된 URL 경로(path) 또한 트리형태로 이루어져있다는 것입니다. 그리고 트리이기 때문에 각각의 경로는 Children을 가질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-20 오전 1.26.11.png&quot; data-origin-width=&quot;232&quot; data-origin-height=&quot;204&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/90wta/btqLeo3TGLn/V7fbeOAHEoZOLqOOfFAef1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/90wta/btqLeo3TGLn/V7fbeOAHEoZOLqOOfFAef1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/90wta/btqLeo3TGLn/V7fbeOAHEoZOLqOOfFAef1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F90wta%2FbtqLeo3TGLn%2FV7fbeOAHEoZOLqOOfFAef1%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-20 오전 1.26.11.png&quot; data-origin-width=&quot;232&quot; data-origin-height=&quot;204&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 보여드렸던, router_main.js 코드를 기억하시나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안 나실 걸 당연히 알기때문에 한 번 더 보여드릴게여.&lt;/p&gt;
&lt;pre id=&quot;code_1603124841917&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const router_main = [
        { path: '/', redirect: '/home' },
        { path: '/home', component: Home },
        { path: '/content', component: Content },
        { path: '/main', component: mainFrame,
            children: [
                { path: '', redirect: '/main/intro'},
                { path: 'intro', component: Intro},
                { path: 'front', component: FrontEnd},
                { path: 'back', component: BackEnd},
            ]
        },
        { path: '/:catchAll(.*)', component: NotFound },
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, &quot;/main&quot; 이라는 경로에 정의된 사항들을 집중해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타 경로들은 redirect, component 만을 가지고 있는 반면에, &quot;/main&quot;은 children 이라는 배열 형태의 값까지 정의를 해주고 있습니다. 그리고 그 아래에는 마치, 누가 재귀문이라도 돌린 것처럼 path와 redirect, component가 추가 정의되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어때요, &amp;lsquo;아 저렇게 쓰는거구나?&amp;rsquo;하고 감이 잡히시나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이해를 돕기 위해 위 내용을 그림으로 또 한 번 보도록하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.10.59.png&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;553&quot; width=&quot;689&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyL34j/btqLkLXKWhR/ccKiFgwykqJRMBUgDeEYpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyL34j/btqLkLXKWhR/ccKiFgwykqJRMBUgDeEYpk/img.png&quot; data-alt=&quot;router_main.js의 정의에 따라서 http://localhost:9090/#/main/ 경로로 접근 했을 경우의 화면 구성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyL34j/btqLkLXKWhR/ccKiFgwykqJRMBUgDeEYpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyL34j%2FbtqLkLXKWhR%2FccKiFgwykqJRMBUgDeEYpk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.10.59.png&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;553&quot; width=&quot;689&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;router_main.js의 정의에 따라서 http://localhost:9090/#/main/ 경로로 접근 했을 경우의 화면 구성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 구조는 http://localhost:9090/#/main 경로로 접근했을 때를 보여주고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue의 트리구조로 봤을 때 루트를 담당하는 최외곽에는 App.vue가 존재하구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App.vue는 &amp;lt;template&amp;gt; 영역에 아래와 같이 &amp;lt;router-view&amp;gt;를 가지고 있기때문에,&lt;/p&gt;
&lt;pre id=&quot;code_1603125278781&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;router-view/&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경로에 따른 router구성에서도 트리구조의 최상단인 루트를 담당하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 현재의 router_main.js에 정의된 기준으로 보자면 아래 스크린샷과 같이 빨간 블럭내에 있는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.14.30.png&quot; data-origin-width=&quot;462&quot; data-origin-height=&quot;306&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cD1M1M/btqLf5Qvstk/8cB3PO5Mgkb7j9mQcxEsA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cD1M1M/btqLf5Qvstk/8cB3PO5Mgkb7j9mQcxEsA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cD1M1M/btqLf5Qvstk/8cB3PO5Mgkb7j9mQcxEsA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcD1M1M%2FbtqLf5Qvstk%2F8cB3PO5Mgkb7j9mQcxEsA0%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.14.30.png&quot; data-origin-width=&quot;462&quot; data-origin-height=&quot;306&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;/&amp;ldquo;, &amp;ldquo;/home&amp;rdquo;, &amp;ldquo;/content&amp;rdquo;, &amp;ldquo;/main&amp;rdquo; 의 경로(path)들이 App.vue의 &amp;lt;router-view&amp;gt;에 매핑되어 있다고 보시면 되겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 /main 경로를 보면 children을 추가로 정의하였는데, 이는 /main 이라는 경로 뒤에 각각 intro, front, back 이라는 값들이 추가되었을 때 렌더링되는 화면(vue 컴포넌트)들을 정의한 것입니다. 이 화면들이 그려지는 위치는 children으로 정의된 mainFrame.vue 파일내의 &amp;lt;router-view&amp;gt;인데요.&lt;/p&gt;
&lt;pre id=&quot;code_1603125429940&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;div class=&quot;frame&quot;&amp;gt;
        &amp;lt;gnb-frame&amp;gt;&amp;lt;/gnb-frame&amp;gt;
        &amp;lt;router-view class=&quot;main-router&quot;/&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue_starter 프로젝트를 받고 npm run serve 명령어를 통해 실행하셨다면, http://localhost:9090/#/main 이 주소로 접속해봐주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정상적으로 실행을 했다면 아래와 같은 화면을 마주하게 되실겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.19.41_블럭.png&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;512&quot; width=&quot;578&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ty5CH/btqLeq1EN1V/85pCutacIV3lAnBWjtHcIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ty5CH/btqLeq1EN1V/85pCutacIV3lAnBWjtHcIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ty5CH/btqLeq1EN1V/85pCutacIV3lAnBWjtHcIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fty5CH%2FbtqLeq1EN1V%2F85pCutacIV3lAnBWjtHcIk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.19.41_블럭.png&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;512&quot; width=&quot;578&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 빨간색 영역이 gnbFrame.vue이고 아래쪽 녹색 테두리 영역이 2레벨째의 &amp;lt;router-view&amp;gt;이며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경로에따라 해당 위치에 렌더링되는 파일들은 router_main.js를 보면 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.24.15.png&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;295&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZvLZy/btqLcT355lf/uG8qW5voTWKkpM6dzCep70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZvLZy/btqLcT355lf/uG8qW5voTWKkpM6dzCep70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZvLZy/btqLcT355lf/uG8qW5voTWKkpM6dzCep70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZvLZy%2FbtqLcT355lf%2FuG8qW5voTWKkpM6dzCep70%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.24.15.png&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;295&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;http://localhost:9090/#&lt;/span&gt;/main/intro&amp;nbsp; 경로라면 intro.vue&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;http://localhost:9090/#&lt;/span&gt;/main/front 경로라면 frontEnd.vue&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;http://localhost:9090/#&lt;/span&gt;/main/back 경로라면 backEnd.vue&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 그런지 확인을 위해 상단의 메뉴를 눌러보시면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;브라우저의 URL과 아래쪽 영역이 바뀌는 것을 확인할 수 있을 겁니다&lt;/b&gt;.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 정리!!&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 그럼 늘 그래왔듯이, &lt;b&gt;다시 처음 index.html부터 짚어들어가 보겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.. SPA환경이므로 정적 파일인 HTML은 index.html 하나만 있습니다.&lt;br /&gt;2. index.html은 &amp;lt;div id=&amp;ldquo;app&amp;rdquo;/&amp;gt; DOM 태그를 가지고 있구요.&lt;br /&gt;3. build.js를 포함하고 있습니다.&lt;br /&gt;4. build.js는 엔트리 파일(main.js)을 기점으로 생성된 Vue Application 인스턴스를 가지고 있으며&lt;br /&gt;5. Vue Application 인스턴스는 createApp function의 파라미터로 App.vue를 지정하였고&lt;br /&gt;6. App.vue는 &amp;lt;router-view&amp;gt; 태그를 가지고 있는데, 해당 위치가 바로 URL의 path에 따라 매핑된 vue 컴포넌트들이 렌더링되는 위치입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 정리가 되겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 포스팅에서 말했던 것들에, 마지막 6번 항목이 추가가 된 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐, 물론 본 포스팅의 예시에서나 실제 프로젝트에서는 좀 더 복잡하게 Router를 정의해서 쓰시겠지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이상부터는 각자 정의하고 풀어나가셔야 할 부분이니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 조금이나마 도움이 될까 싶어서, vue_starter 레파지토리에 GNB를 활용하는 코드까지 추가를 해두었으니 참고해주시면 될 것 같습니다(이와 관련된 짧은 설명을 아래 별첨에 작성해둡니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;돌아보니 짧은 포스팅 같은데 쓰다보니 제법 길었던 것 같은 느낌입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 포스팅은 &lt;s&gt;(이제서야)&lt;/s&gt; 본격적으로 Vue 파일내부부터 차근히 설명해보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;궁금하신 사항은 언제든지 댓글 달아주시구요, 감사합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;-1. GNB 형태로 활용하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue_starter 레파지토리를 기준으로 우선,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GNB를 활용하는 예시 경로는 &lt;span style=&quot;color: #333333;&quot;&gt;http://localhost:9090/#&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;/main 로 정의를 해두었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;위에서도 보셨겠지만 해당경로로 들어가보시면 아래와 같은 형태로 브라우저에 렌더링이 될 거구요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.19.41.png&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;512&quot; width=&quot;515&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uleKZ/btqLlB8slyx/OPODAv76QZfV9hxnJnR7d1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uleKZ/btqLlB8slyx/OPODAv76QZfV9hxnJnR7d1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uleKZ/btqLlB8slyx/OPODAv76QZfV9hxnJnR7d1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuleKZ%2FbtqLlB8slyx%2FOPODAv76QZfV9hxnJnR7d1%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-20 오전 12.19.41.png&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;512&quot; width=&quot;515&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이에 관여하는 파일은 총 N개이며 이들에 대해 차근히 설명해 보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. router_main.js&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;위에서도 몇번이나 언급된 파일입니다. Router의 핵심이라고 할 수 있으며 각 경로(path)에 대해 렌더링 될 vue 컴포넌트들을 1:1로 매핑 정의하고 있습니다. GNB 예제를 중점적으로 보자면 /main 을 시작점으로 봐주시면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. App.vue&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Router 구성에서 루트 역할을 맡은 &amp;lt;router-view&amp;gt;를 정의하고 있는 파일이며, Vue Application 인스턴스에서도 모든 vue 파일들의 기점이 되는 루트 역할을 합니다. 실제 &quot;/&quot;경로로 접근시 렌더링되는 화면입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. mainFrame.vue&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;GNB로 구성되는 화면의 전체 틀을 잡아줍니다. 그런 의미에서 mainFrame 이라는 이름을 붙였구요. 해당 파일에는 흔히 헤더라고 불리는 GNB역할의 gnbFrame.vue 가 정의되어 있으며 App.vue에 이어서 2레벨째의 &amp;lt;router-view&amp;gt; 또한 정의되어 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. gnbFrame.vue&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;mainFrame.vue의 상단에 그려지는 GNB(헤더)영역만을 별도로 정의한 컴포넌트입니다. 현재는 아래 코드와 같이 Intro, Front-end, Back-end 라는 이름의 3개 메뉴를 가지고 있으며&lt;/p&gt;
&lt;pre id=&quot;code_1603126320353&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data(){
    return{
        gnbMenu: [
            {name: 'Intro', url: '/main/intro'},
            {name: 'Front-end', url: '/main/front'},
            {name: 'Back-end', url: '/main/back'},
        ]
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;각각의 메뉴는 화면상에 보일 이름(name)과 메뉴를 클릭했을 때 이동할 경로(url)를 가지고 있습니다.&lt;/p&gt;
&lt;p&gt;메뉴를 클릭했을 때 Router가 인식하는 범위 내에서 URL을 변경하는 로직을 아래와 같이 가지고 있으며&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1603126556828&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;moveTo(url){
    this.$router.push(url);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 코드는 파라미터로 전달된 url로 Router를 이동시키는 코드이고, 여기서 전달되는 url은 gnbMenu 라는 배열형 변수가 내포하고 있는 각 url 입니다(어떻게 클릭해서 저 moveTo라는 메서드가 호출되는지등에 대한 건 다음 포스팅에서 다룹니다)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. intro.vue, frontEnd.vue, backEnd.vue&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;mainFrame.vue에서 사용된 gnbFrame.vue의 메뉴를 클릭했을 때, Router가 이동(여기서 말하는 이동은 url의 변경에 따라서 &amp;lt;router-view&amp;gt; 영역에 알맞은 vue 컴포넌트가 그려지는 것을 의미합니다)하게 되고 그에 따라 그려지는 각각의 vue 컴포넌트들입니다.&lt;/p&gt;
&lt;p&gt;현재는 그저 &amp;lt;h3&amp;gt;태그를 이용하여 간단한 문자열을 출력하는 정도지만, 추후 여기에 각각 필요한 로직들을 넣으시면 됩니다.&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>Front-end</category>
      <category>frontend</category>
      <category>Vue</category>
      <category>Vue.js</category>
      <category>Vue3.0</category>
      <category>개발</category>
      <category>개발자</category>
      <category>웹</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/74</guid>
      <comments>https://blinders.tistory.com/74#entry74comment</comments>
      <pubDate>Tue, 20 Oct 2020 02:02:41 +0900</pubDate>
    </item>
    <item>
      <title>[vue-echart] options props 기본값의 axis 설정 누락</title>
      <link>https://blinders.tistory.com/73</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;문제점&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;Cannot&amp;nbsp;read&amp;nbsp;property&amp;nbsp;'coordinateSystem'&amp;nbsp;of&amp;nbsp;undefined&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&amp;nbsp;at Object.layout (catesianAxisHelper.js:54)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&amp;nbsp;at ExtendedClass.render (CartesianAxisView.js:74)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&amp;nbsp;at echarts.js:1450&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&amp;nbsp;at Array.forEach (&amp;lt;anonymous&amp;gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&amp;nbsp;at each (util.js:300)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&amp;nbsp;at renderComponents (echarts.js:1448)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&amp;nbsp;at render (echarts.js:1434)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&amp;nbsp;at ECharts.update (echarts.js:861)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&amp;nbsp;at ECharts.echartsProto.setOption (echarts.js:411)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;vue-echart의&amp;nbsp; 초기 설정값에 문제&lt;/b&gt;&lt;/span&gt;가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라인 그래프이기 때문에 초기 options props에 전달되는 초기 값을 아래와 같이 사용했는데...&lt;/p&gt;
&lt;pre id=&quot;code_1602031590602&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;option: {
    renderer:'svg',
    legend: {
        data: [],
    },
    xAxis: {
        type: 'category',
        data: [],
    },
    series: []
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러로그에 coordinateSystem이 undefined니까,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;축과 관련된 건데 난 분명 xAxis을 줬는데, 대체 이게 왜 나오지 싶었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멍청하게도 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;라인 그래프니까 2차원...그러니까 y축 설정인 yAxis가 빠져서&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;였다^^...&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까 아래와 같이 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;yAxis: {}&lt;/b&gt; &lt;/span&gt;이것만 추가하면 됨...&lt;/p&gt;
&lt;pre id=&quot;code_1602031672759&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;option: {
    renderer:'svg',
    legend: {
        data: [],
    },
    xAxis: {
        type: 'category',
        data: [],
    },
    yAxis: {}, // 이거...이 한 줄 때문에ㅠㅠ
    series: []
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/트러블 슈팅(Trouble Shooting)</category>
      <category>echart</category>
      <category>troubleshooting</category>
      <category>Vue</category>
      <category>vue-echart</category>
      <category>개발</category>
      <category>개발자</category>
      <category>웹개발</category>
      <category>차트</category>
      <category>트러블슈팅</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/73</guid>
      <comments>https://blinders.tistory.com/73#entry73comment</comments>
      <pubDate>Wed, 7 Oct 2020 09:55:28 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js_#03] N : 1 (feat. webpack)</title>
      <link>https://blinders.tistory.com/72</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0. 시작하기에 앞서&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 저번 편에 이어서 이번 편도 좀 지루하지 않을까, 라는 생각이 듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대체 Vue.js 에 대해서 설명하는 포스팅이라고 해놓고 Vue.js를 실질적으로 활용하는 설명은 어디 있는거냐, 라는 생각이 드실수도 있어요, 충분히. 이래저래 필요한 개념들부터 짚고 넘어가려다보니 포스팅이 길어지고 있는데요, 하지만 그렇다고해서 &amp;lsquo;이 정도는 알아야 할 거 같은 것&amp;rsquo;들을 모른 척 당장 넘어갈 수는 없잖아요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당장에 급하기에 활용법부터 필요하실 수도 있습니다만, 급히 먹는 밥은 체하기 마련이니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소한의 기본은 쌓고 인지한채로 개발을 해야하지 않겠습니까?ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 이번편도 &lt;b&gt;당장 Vue.js를 &amp;lsquo;코드&amp;rsquo;로써 활용하고자하시는 분이라면 스킵&lt;/b&gt;하셔도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-05 오전 3.39.31.png&quot; data-origin-width=&quot;501&quot; data-origin-height=&quot;320&quot; width=&quot;388&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zQfNd/btqJZn6AwGP/nTFeyJinggcOKTD5i2XDB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zQfNd/btqJZn6AwGP/nTFeyJinggcOKTD5i2XDB1/img.png&quot; data-alt=&quot;사격도 PRI하고 영점부터 맞추듯이, 기초는 분야를 막론하고 중요합니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zQfNd/btqJZn6AwGP/nTFeyJinggcOKTD5i2XDB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzQfNd%2FbtqJZn6AwGP%2FnTFeyJinggcOKTD5i2XDB1%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-05 오전 3.39.31.png&quot; data-origin-width=&quot;501&quot; data-origin-height=&quot;320&quot; width=&quot;388&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사격도 PRI하고 영점부터 맞추듯이, 기초는 분야를 막론하고 중요합니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은, 이전 글에서도 언급했던 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;N개의 vue파일들이 어떻게 build.js라는 하나의 파일로&lt;/b&gt;&lt;/span&gt; 떨어지는지&amp;hellip;그리고 그렇게 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생성된 하나의 파일이 SPA 구조를 담당하는 HTML에서 어떻게 활용되는지&lt;/b&gt;&lt;/span&gt;에 대한 이야기가 될 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네, 이미 아실분은 알만한 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Webpack에 대한 이야기를 주력&lt;/b&gt;&lt;/span&gt;으로 할 것 같습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Vue.js도 결국은 자바스크립트다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐 어찌보면 당연하고도 아주 심플한 제목입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현대의 웹 서비스라는 건, 더 정확하게 브라우저라는 건,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;HTML, CSS, Javascript 이렇게 딱 3가지&lt;/b&gt;&lt;/span&gt;밖에 모릅니다. 그 이외것들은 아웃오브안중이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 정확하게는 확장자가 html, css, js 인 것들을 인식해서 그에맞게 해석하고 화면에 보여주는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어,그럼 우리가 익숙하게 쓰던 JSP는요? JSP도 브라우저는 논외로 치는거가요?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네 그렇습니다. JSP도 결국은 HTML로 기반이 다져진 코드에 Java 코드를 삽입함으로써 동적으로 웹 페이지를 생성하는 기술이기 때문이죠. 그리고 그렇게 동적으로 생성된 페이지를 브라우저에게 리턴함으로써, 브라우저가 받아들이고 화면에 보여지게끔 하는 겁니다.&lt;b&gt; 결국 HTML&lt;/b&gt;이라는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 다시 본론으로 돌아와서, 우리가 사용하는 Vue.js를 떠올려봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue.js를 기반으로 프론트엔드 개발을 할 때, 우리는 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;확장자가 *.vue인 파일들을 사용&lt;/b&gt;&lt;/span&gt;합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마치 JSP기반으로 개발할 때 *.jsp 확장자인 파일들을 이용하는 것처럼 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 중요한 포인트입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSP처럼 Vue.js도, html이나 js, css가 아닌 아웃오브안중의 확장자인데 브라우저에서는 동작을 하는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 *.jsp는 위에서 설명한 것처럼 HTML을 기반으로 동작을 합니다. 그에반해 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;*.vue는 Javascript를 기반으로 브라우저가 인식해서 동작&lt;/b&gt;&lt;/span&gt;한다는 차이가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언급드렸던 것처럼 JSP는 대표적인 서버사이드 렌더링으로써 서버에서 결국 동적인 영역을 채워놓은 HTML 코드를 리턴하고 브라우저가 아, 얘는 HTML이구나, 라고 인식하게 하는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로, 우리가 작성한 *.vue 파일을 브라우저가 아, 얘는 Javascript구나 라고 인식할 수 있게 변환해주는 작업이 필요합니다. 거기에 더해서 N개의 *.vue파일을 하나의 Javascript 파일로 모아주는 작업도 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, &lt;b&gt;이 작업을 도와주는 녀석&lt;/b&gt;이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 녀석의 이름은 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Webpack&lt;/b&gt; &lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명을 좀 하다보니&amp;nbsp;말이 이래저래 튄 거 같아서, 우선 가볍게 정리를 한 번 해보겠습니다.&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;1. *.vue 파일은 Vue.js에서 활용되는 파일로써, 내부 코드는 Vue.js 문법에 기초해서 작성되어있다.&lt;br /&gt;2. 웹 서비스는 HTML, CSS, Javascript 말고는 모른다.&lt;br /&gt;3. 그렇기 때문에 *.vue 파일내의 코드들을 Javascript로 변환해줘야한다.&lt;br /&gt;4. 이때 사용하는 게 Webpack 이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 4줄로 요약할 수 있겠네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이렇게 짧은데 뭘 주절주절 설명한거람&amp;hellip;)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Webpack&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;At its core, webpack is a static &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;module bundler&lt;/b&gt;&lt;/span&gt; for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph which maps every module your project needs and generates one or more bundles.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문구는 Webpack 사이트에 있는 설명입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 문구에서 우리가 주시해야 할 표현은 &lt;b&gt;module bundler&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 그림을 한 번 봐주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-05 오전 1.24.22.png&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;516&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqQ7Gd/btqJZms5yRL/zi0WW62WAQVtK8iZOiNop1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqQ7Gd/btqJZms5yRL/zi0WW62WAQVtK8iZOiNop1/img.png&quot; data-alt=&quot;Webpack (a.k.a Module Bundler)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqQ7Gd/btqJZms5yRL/zi0WW62WAQVtK8iZOiNop1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqQ7Gd%2FbtqJZms5yRL%2Fzi0WW62WAQVtK8iZOiNop1%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-05 오전 1.24.22.png&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;516&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Webpack (a.k.a Module Bundler)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 이미지를 &lt;b&gt;좌/우&lt;/b&gt;로 나누어 봐주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;좌측은, 여러분이 실제로 개발할 때 사용하는 코드 및 리소스&lt;/b&gt;들이라고 보시면 되구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;우측은, 실제 서비스를 사용자에게 제공할 때 사용되는 코드 및 리소스&lt;/b&gt;라고 보시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까, 그냥 좌측에 있는 애들이 파워레인저 로봇처럼 변신합체해서 오른쪽이 되는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 개발할 때랑, 실제 서비스할 때랑 파일이 다른가요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라는 의문이 생기신다면 위의 1번 항목 &amp;lsquo;&lt;i&gt;Vue.js도 결국은 자바스크립트다.&lt;/i&gt;&amp;rsquo;를 한 번 더 읽어주시기 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 지금 웹 서비스를 개발하기 위해, 프론트엔드 프레임워크로 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Vue.js를 활용&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서비스를 가장 퓨어한 형태로 개발하고 싶다면 HTML,CSS,Javascript만을 활용하면 되겠지만, 우리는 그러지 않을거니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 Vue.js의 파일인 *.vue 확장자를 브라우저가 뭔지 알아채고 이해한다면 참 좋을 겁니다. 그러나 우리의 브라우저는 이게 대체 무슨 파일인지 뭔지 알아먹질 못 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-05 오전 3.57.14.png&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;359&quot; width=&quot;568&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dGxA5Y/btqJ4Hwd80y/FYT1iv6JQwBQrZrKqmm4CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGxA5Y/btqJ4Hwd80y/FYT1iv6JQwBQrZrKqmm4CK/img.png&quot; data-alt=&quot;CSS / HTML / Javascript&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGxA5Y/btqJ4Hwd80y/FYT1iv6JQwBQrZrKqmm4CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGxA5Y%2FbtqJ4Hwd80y%2FFYT1iv6JQwBQrZrKqmm4CK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-05 오전 3.57.14.png&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;359&quot; width=&quot;568&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CSS / HTML / Javascript&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저는 이 3대장만을 이해하고 해석할 줄 아는 멍청이이기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(그래도 나보단 똑똑하겠지...)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3대장을 뒤로하고 하나의 질문을 던져보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Webpack이 해주는 게 *.vue파일을 하나의 Javascript 파일(이하 build.js)로 만들어주는 건가요?&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 질문에 대한 대답은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;그렇긴한데, 아니야. 가 정답&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네니오 같은거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 대답이 네니오 같은 거냐면 Webpack이 *.vue 파일을 build.js로 변환해주기는 하지만, &lt;b&gt;그걸 위한 목적만을 가지고 있는 건&lt;/b&gt;&amp;nbsp;아니기 때문입니다. &lt;b&gt;그것&lt;span style=&quot;color: #006dd7;&quot;&gt;도&lt;/span&gt; 하는 거죠.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 위에 좌/우로 나눈 Webpack의 이미지를 다시 봐주세요. 좌측에 *.vue 파일같은 게 있나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네, 없죠. 그리고 제가 Webpack에 대해서 처음 이야기를 꺼냈을 때 주시해야한다고 했던 단어들이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;module bundler&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 두 단어로 Webpack의 본질이 설명&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, Webpack을 처음 접하시는 분이라면 이것만으로는 대체 무슨 소리인지 의문만 더해질게 자명하기 때문에 좀 더 설명을 해보도록하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-05 오전 4.04.25.png&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;474&quot; width=&quot;294&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfSKzM/btqJ8eNN0kE/T1l4PAdzDqsFM9jkChKB01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfSKzM/btqJ8eNN0kE/T1l4PAdzDqsFM9jkChKB01/img.png&quot; data-alt=&quot;자네가 내게 Webpack을 물었나?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfSKzM/btqJ8eNN0kE/T1l4PAdzDqsFM9jkChKB01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfSKzM%2FbtqJ8eNN0kE%2FT1l4PAdzDqsFM9jkChKB01%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-05 오전 4.04.25.png&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;474&quot; width=&quot;294&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;자네가 내게 Webpack을 물었나?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단, Module Bundler라는 문구에서의 module 개념을 먼저 설명해야 할 거 같은데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 이해하자면, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;파일 1개가 module 1개&lt;/b&gt;&lt;/span&gt;라고 생각하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(물론, 이게 정확한 설명은 아닙니다. 하지만&amp;nbsp;깊게 들어가자면 Javascript 의 ES6에서 도입된 모듈의 개념부터 시작해서 짚고 들어가야 할 분량이 포스팅을 별도로 해야 할 정도로 볼륨이 큽니다. 그러니, 일단 여기에서만큼은 여러분이 개발하실 때 사용하는 파일 하나가 각 모듈 1개라고 이해해주세요)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈은 입 맛 까다로운 브라우저처럼 특정 파일 형식을 가리지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;html, js, css는 당연하구요. vue, scss, jsx를 비롯해서 정적 리소스인 png, jpg와 같은 파일까지도 &lt;b&gt;모두 모듈로 정의&lt;/b&gt;합니다. 그리고 이러한 각 모듈들에 알맞은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;lsquo;형식(loader)&amp;rsquo;을 적용해서 변신&amp;amp;합체와 같은 정리를 해주는 걸 bundle&lt;/b&gt;&lt;/span&gt;이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 역할을 Webpack이 해주기 때문에, 접미사 &amp;lsquo;-er&amp;rsquo;을 붙여서 &lt;b&gt;Module Bundler&lt;/b&gt;라고 부르는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이쯤 왔으니, 한 번 더 정리해봅시다.&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;1. Webpack은 Module Bundler 입니다.&lt;br /&gt;2. 개발할 때 쓰이는 각 파일하나하나가 Module 입니다.&lt;br /&gt;3. *.vue 파일 또한 각각이 Module 입니다.&lt;br /&gt;4. 그리고 Webpack이 Bundle이라는 과정을 거쳐서 *.vue 파일을 *.js 파일로 변환해줍니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Entry File&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-05 오전 2.03.36.png&quot; data-origin-width=&quot;367&quot; data-origin-height=&quot;148&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y9yQ8/btqKdFjy58R/LQ6Kf9AvCmaqRzkKfVRvqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y9yQ8/btqKdFjy58R/LQ6Kf9AvCmaqRzkKfVRvqk/img.png&quot; data-alt=&quot;출처 : 네이버 사전&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y9yQ8/btqKdFjy58R/LQ6Kf9AvCmaqRzkKfVRvqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy9yQ8%2FbtqKdFjy58R%2FLQ6Kf9AvCmaqRzkKfVRvqk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-05 오전 2.03.36.png&quot; data-origin-width=&quot;367&quot; data-origin-height=&quot;148&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 네이버 사전&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Entry의 뜻을 찾아보니 위와같이 나오더군요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Webpack은 N개의 모듈을 정리&lt;/b&gt;해준다고 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이때, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Webpack이 번들을 시작할 시작점 역할의 파일이 필요&lt;/b&gt;&lt;/span&gt;한데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;시작점의 역할을 하는 것이 바로 엔트리 파일&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;The entry object is where webpack looks &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;to start&lt;/b&gt;&lt;/span&gt; building the bundle. The context is an absolute string to the directory that contains the entry files.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 설명을 보시면 명확하게 &amp;lsquo;to start&amp;rsquo;라는 표현을 보실 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔트리 파일을 기점으로 Webpack은 필요한 파일들을 추적하여 번들작업을 진행하게 되는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무조건적으로 파일의 존재유무에 따라서 번들링이 진행되지는 않는다는 말입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 프로젝트의 특정 디렉토리 아래라던가, 혹은 루트 디렉토리 아래에 파일이 존재한다고해서 해당 파일이 번들링되는 건 아니라는 겁니다. 즉, &lt;b&gt;활용되지 않는 파일은 번들링 되지 않습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이때 엔트리 파일은, &lt;b&gt;진입점 역할을 하기 때문에 javascript 파일&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제공해드리는 vue_starter 레파지토리를 기준으로 보자면 src &amp;gt; main.js 파일이 vue_starter의 엔트리 파일 역할을 하고 있으며, 그에 대한 정의는 vue.config.js 파일을 열어보시면 아래와 같은 코드로 명시되어 있습니다&lt;/p&gt;
&lt;pre id=&quot;code_1601838842066&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = {
    // 설정관련 추가 정의코드 생략
    pages: {
        index: {
            entry: 'src/main.js',
            template: 'public/index.html',
            title: 'Vue Starter',
            filename: 'index.html'
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;entry 항목에 src/main.js를 명시하고 있음과 더불어 SPA의 바탕이되는 HTML 파일또한 template 항목을 통해 정의되있는 것을 확인하실 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. Loader&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;음&amp;hellip;사실 이건 설명을 할까말까 싶긴하지만, 그냥 간략히 짚고 넘어가도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 &lt;b&gt;Webpack에서 상당히 다양한 종류의 파일들이 모두 모듈&lt;/b&gt;이라고 설명드렸습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Webpack이 그런 모듈들을 변신&amp;amp;합체를 통해서 번들링하고 실제 브라우저에서 동작이 가능하게끔 정리해준다고 하였구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이때 각 &lt;b&gt;모듈들에 알맞은 형식&lt;/b&gt;이라는 표현을 제가 썼습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;loader&lt;/b&gt;라는 이름으로 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 모듈들, 그러니까 각 파일들을 당연하게도 다 다릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(뭐&amp;hellip;뜯어보면 당연히 확장자부터 시작해서 파일 포맷에다가 바이너리까지 다 다르겠죠)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 &lt;b&gt;번들 작업이 진행될 때는 각 파일들에 맞는 형식으로 번들이 진행&lt;/b&gt;되어야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;사용되는 개념이 loader&lt;/b&gt;&lt;/span&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(음&amp;hellip;개념이라기고 표현하기엔 조금 애매한데 명확한 표현을 찾지 못 하겠네요)&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;webpack enables use of loaders to &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;preprocess&lt;/b&gt; &lt;/span&gt;files. This allows you to bundle any static resource way beyond JavaScript.&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://webpack.js.org/loaders/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webpack의 공홈&lt;/a&gt;에는 이렇게 설명되어있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Webpack에서는 Module Bundler라는 단어를 기억했듯이 &lt;b&gt;Loader에서는 &lt;span style=&quot;color: #006dd7;&quot;&gt;preprocess&lt;/span&gt;, 라는 단어를 기억&lt;/b&gt;해주시면 될 거 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 *.vue 파일을 Webpack이 해석코자할 때는 vue-loader를 사용하구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;css는 css-loader, png나 jpg와 같이 정적 리소스 파일들에는 file-loader등이 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이러한 Loader에 대한 설정은 Webpack 설정파일에 기재가 되어있는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 예시로 제공해드리고 있는 vue_starter 같은 경우에는 &lt;b&gt;vue.config.js 라는 파일&lt;/b&gt;이 webpack의 설정파일역할을 하고 있구요. 일반적인 경우라면 webpack.config.js 라는 이름이거나 webpack.base.confg.js와 같은 이름의 형식으로 사용을 하고 계실 겁니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. new Vue &amp;amp; createApp&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지루한 설명을 거쳐오시느라 고생많으셨습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-05 오전 4.19.44.png&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;348&quot; width=&quot;367&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lPxa1/btqJ6cv0brz/zaJjhBPuWrvFeKaHHmJieK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lPxa1/btqJ6cv0brz/zaJjhBPuWrvFeKaHHmJieK/img.png&quot; data-alt=&quot;지금까지 설명만 주구장창 해왔던 건...!!!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lPxa1/btqJ6cv0brz/zaJjhBPuWrvFeKaHHmJieK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlPxa1%2FbtqJ6cv0brz%2FzaJjhBPuWrvFeKaHHmJieK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-05 오전 4.19.44.png&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;348&quot; width=&quot;367&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;지금까지 설명만 주구장창 해왔던 건...!!!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추진력을 얻으셨으니,&lt;b&gt; 이제 진짜를 마주할 시간&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서 지리멸렬하게 설명했던 건 &lt;b&gt;결국 이 항목을 위해서&lt;/b&gt;였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 하려는 건 Vue.js가 어떻게 HTML, CSS, Javascript만 아는 브라우저에서 동작이 가능한가, 에 대한 이해니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서도 정리를 좀 했지만, 한 번 더 간략하게 3줄로 요약을 해보죠.&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;1. 브라우저는 HTML, CSS, Javascript만 이해한다.&lt;br /&gt;2. *.vue 파일에는 Vue.js의 문법에 맞춰서 코드가 작성되어 있다.&lt;br /&gt;3. *.vue 파일들은 Webpack에 의해 Javascript 파일이 된다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 무던히도 설명했던 것들이 헛되보일만큼 굉장히 심플하게 정리가 되네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제는 &lt;a href=&quot;https://blinders.tistory.com/69?category=636275&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 포스팅이었던 SPA&lt;/a&gt;와 이 포스팅을 합쳐서 설명할 차례입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 SPA에서 Vue.js를 활용한다는 가정을 두고 있기 때문에,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연하게도 아래와 같이 단 하나의 HTML 파일을 기반으로 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601839396796&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;
    &amp;lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width,initial-scale=1&quot;&amp;gt;
    &amp;lt;link rel=&quot;icon&quot; href=&quot;/favicon.ico&quot;&amp;gt;
    &amp;lt;title&amp;gt;Vue Starter&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;app&quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;script src=&quot;/dist/build.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보시는 바와같이 HTML 파일의 body 태그에는 딱 2줄의 코드가 들어가 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;1. &lt;b&gt;id가 app&lt;/b&gt;인 &amp;lt;div&amp;gt; 태그&lt;br /&gt;2. Webpack에 의해 번들링 된 것처럼 보이는 build.js를 사용하는 코드&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;SPA에서는 겨우 이것만으로도 웹 서비스가 가능&lt;/b&gt;&lt;/span&gt;해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 저기에 명시된 build.js라는 javascript 파일 자체가 이미, N개의 *.vue 파일들이 번들링된 최종파일이기 때문이죠. jsp로 치자면 login.jsp, home.jsp, rent.jsp, search.jsp 같은 파일들이 하나로 합쳐져서 HTML 파일내에 명시된거라고 볼 수 있는겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이렇게만 말해서는 도통 이해가 안 되실 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기반이 되는 HTML 파일 안에, 그냥 div 태그 하나 있고 build.js 파일 명시만 해뒀는데...이것만으로 대체 어떻게 웹 서비스가 동작한다는건지. 어떤 구조로, 어떤 프로세스와 매커니즘을 가지고 있길래 이게 먹히는 거냐고 당연히 궁금해하실 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 그것에 대한 설명을 지금부터 찬찬히 풀어보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;여기서부터는 vue_starter 프로젝트의 파일을 예시로 설명&lt;/b&gt;하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 엔트리파일(src/main.js)을 열면 아래와 같은 코드를 보실 수 있을겁니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601839656539&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Vue 3.x
import {createApp} from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'
import App from './App'
import router_main from './router/router_main'
import toyComponents from '@/components'

let router = createRouter({
    history: createWebHashHistory(),
    routes: router_main
})
const app = createApp(App);
app.use(toyComponents)
app.use(router);
app.mount('#app')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 잘 보면, 밑에서 4번째 줄에&amp;nbsp;&lt;b&gt;createApp function을 통해서 뭔가를 만드는 것&lt;/b&gt; 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 만들 때, 전달되는 파라미터가 있는 것도 확인하실 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 이때, createApp을 통해 만들어지는 것이 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Vue 3.0에서 새롭게 도입된 Vue Application 의 인스턴스&lt;/b&gt;&lt;/span&gt;입니다. 그리고, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;인스턴스를 생성할 때 전달되는 파라미터는 App.vue 라는 모듈&lt;/b&gt;&lt;/span&gt;인데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔트리 파일이 build.js로 합쳐지는 파일들 전체의 진입점이라면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;파라미터로 사용된 App.vue 는 *.vue 파일들의 진입점이 되어주는 역할&lt;/b&gt;을 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 설명드린 것과 같이 Webpack은 *.vue들에 한정된 모듈 번들러가 아니기 때문에, Vue.js를 활용하기 위해서는 Vue.js만을 위한 진입점 또한 우리는 필요하고 그런 역할을 수행하는 것이 바로 App.vue 인 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;createApp function을 통해 App.vue를 시작점으로 하는 app인스턴스가 이제 생성됐는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 아래에 정의된 코드들을 보시면 생성된 app 인스턴스가 내재하고있는 use API와 mount API를 추가로 사용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Vue는 플러그인이라는 개념으로 라이브러리를 비롯한 각 모듈들을 글로벌(전역)하게 사용할 수 있도록 환경을 구성&lt;/b&gt;하고 있습니다. 보시는 것처럼 vue_starter에서는 router 와 toyComponents 라는 모듈을 전역으로 사용하게 정의했는데요. 이를위해 app 인스턴스가 내재한 use API를 활용했습니다. 저렇게 명시된 모듈들은 본 프로젝트의 어디에서든지 아래 예시처럼 별도 import없이 사용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601840081685&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;div class=&quot;home&quot;&amp;gt;
        &amp;lt;img src=&quot;@assets/logo.png&quot;&amp;gt;
        &amp;lt;h3&amp;gt;Vue.js Starter by &amp;lt;b&amp;gt;Grey&amp;lt;/b&amp;gt;&amp;lt;/h3&amp;gt;
        &amp;lt;toy-button&amp;gt;Button&amp;lt;/toy-button&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-05 오전 4.33.26.png&quot; data-origin-width=&quot;311&quot; data-origin-height=&quot;308&quot; width=&quot;213&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dM25M3/btqJ3iDuIUJ/AxMVs7KCLURYccffYlwP8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dM25M3/btqJ3iDuIUJ/AxMVs7KCLURYccffYlwP8K/img.png&quot; data-alt=&quot;위와 같은 vue 코드 사용시, 별도 import 없이도 아래 이미지처럼 toyButton 컴포넌트가 적용되었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dM25M3/btqJ3iDuIUJ/AxMVs7KCLURYccffYlwP8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdM25M3%2FbtqJ3iDuIUJ%2FAxMVs7KCLURYccffYlwP8K%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-05 오전 4.33.26.png&quot; data-origin-width=&quot;311&quot; data-origin-height=&quot;308&quot; width=&quot;213&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위와 같은 vue 코드 사용시, 별도 import 없이도 아래 이미지처럼 toyButton 컴포넌트가 적용되었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이제 user API를 뒤이어 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;mount API가 등장&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mount API에는 전달되는 파라미터가 있는데요, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;#app&lt;/b&gt; &lt;/span&gt;라고 되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jQuery에 익숙한 분이시라면 이게 뭘 의미하는지 단박에 눈치채셨을 거라고 생각하는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네, 맞습니다. &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;id가 app인 DOM 태그&lt;/b&gt;&lt;/span&gt;를 가리킵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 우리는 id가 app인 DOM 태그를 딱 하나, 이미 보고 왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 HTML 코드에 있던 &amp;lt;div id=&amp;ldquo;app&amp;rdquo;&amp;gt;&amp;lt;/div&amp;gt; 를 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 이쯤에서 이해도를 높일 겸 그림과 함께 정리를 해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-05 오전 3.16.08.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;479&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VQBW6/btqJ0ojRtXK/jOubVcneQA6OVKMS9aEI4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VQBW6/btqJ0ojRtXK/jOubVcneQA6OVKMS9aEI4k/img.png&quot; data-alt=&quot;물고 물리는 꼬리잡기 같은 관계라고 볼 수 있겠네요&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VQBW6/btqJ0ojRtXK/jOubVcneQA6OVKMS9aEI4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVQBW6%2FbtqJ0ojRtXK%2FjOubVcneQA6OVKMS9aEI4k%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-05 오전 3.16.08.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;479&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;물고 물리는 꼬리잡기 같은 관계라고 볼 수 있겠네요&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윗 그림을 썰 풀듯이 나열하며 설명해보겠습니다.&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;1. HTML은 &amp;lt;div id=&amp;ldquo;app&amp;rdquo;&amp;gt;&amp;lt;/div&amp;gt;와 build.js를 사용하겠다는 코드 2줄로 구성되어있다.&lt;br /&gt;2. src/main.js는 build.js의 근간을 이루는 N개 파일들의 진입점 역할을 한다.&lt;br /&gt;3. main.js 파일은 createApp function을 이용해서 Vue Application의 인스턴스를 생성하고 있다.&lt;br /&gt;4. Vue Application 인스턴스의 시작점을 위해 App.vue를 createApp function의 파라미터로 전달한다.&lt;br /&gt;5. Vue Application 인스턴스의 mount API의 파라미터는 &amp;lsquo;#app&amp;rsquo; 이고, 이 값은 HTML의 &amp;lt;div id=&amp;ldquo;app&amp;rdquo;&amp;gt;를 가리킨다&lt;br /&gt;6. 가리키는 대상이 &amp;lt;div id=&amp;ldquo;app&amp;rdquo;&amp;gt; 이므로, 해당 &amp;lt;div&amp;gt; 태그에 실질적으로 그려지는 코드는 App.vue 이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이해가 잘 되셨는지 모르겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어찌보면 &lt;b&gt;index.html의 &amp;lt;div&amp;gt; 태그부터 시작해서 App.vue까지 물고물고물리는 관계&lt;/b&gt;로 이루어져 있는데요. 이 관계를 잘 이해하신다면, SPA가 어떻게 구성되어 동작을 하는 지, 그리고 Vue.js가 어떻게 단일 build.js 파일만으로도 HTML 내에서 동작하는 지를 이해하실 수 있을 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로, 위 아키텍쳐 그림을 보시면 router_main.js 라는 파일이 등장하는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 파일에 대한 설명은 다음 포스팅에서 계속해서 진행하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본래는 &lt;b&gt;router까지 이번 포스팅으로 정리를 하려했으나&lt;/b&gt;, webpack에 대해 쓰다보니 너무 길어져버렸고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 한 발 더 나가서 서술하는 건 하나의 포스팅이 너무 많은 분량을 먹어버리는 것 같아서입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(글이 길면 지루하기 마련이니까요)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실, &lt;b&gt;router까지 설명을 끝마쳐야 N개의 *.vue 파일들이 어떻게 내부에서 동작하는지 이해가 완결&lt;/b&gt;되실겁니다. 왜냐하면 이 포스팅에서 한 내용은 그저 N개의 파일들이 하나의 build.js 파일로 만들어지는 과정. 그리고 만들어진 이후에 단일 HTML 파일에서 활용되는 방법까지만 설명했기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;build.js가 정의되었는데, 실질적으로 build.js 내부가 어떻게 돌아가는지를 설명드리지 않은거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 앞선 포스팅에서 설명했던 /login.do 면 login.jsp가 호출되고 /home 이면 home.jsp가 호출되는 것과 같은 URL Mapper 관련한 설명도 해드리지 않았구요(이 부분이 다음 포스팅 주제인 router입니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤 안 닦은 것마냥 찝찝하게 끝내는 것 같지만 조금만 양해해주시고 이번 포스팅 내용이 제법 길고 충분히 복잡한 만큼 천천히, 하지만 확실하게 이해해주시기 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 아래와 같이 한 번 더 정리를 해드리고 마무리하도록 하겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. 정리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 정리&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;1. *.vue 파일에는 Vue.js 문법에 맞춰 작성된 코드들이 있다.&lt;br /&gt;2. 해당 코드들은 Webpack에 의해 Javascript로 변환되며 build.js라는 하나의 javascript 파일로 생성된다&lt;br /&gt;3. 변환된 build.js는 SPA의 바탕이 되는 index.html에 사용하도록 명시된다.&lt;br /&gt;4. index.html은 &amp;lt;body&amp;gt; 태그 내부에 &amp;lt;div id=&amp;ldquo;app&amp;rdquo;&amp;gt;&amp;lt;/div&amp;gt;와 &amp;lt;script src=&amp;ldquo;build.js&amp;rdquo;/&amp;gt; 만을 가진다.&lt;br /&gt;5. build.js의 엔트리 파일에서 Vue Application 인스턴스를 생성한다.&lt;br /&gt;6. 생성된 인스턴스는 index.html의 id가 app인 태그를 가리킨다.&lt;br /&gt;7. Vue Application 인스턴스는 App.vue가 바탕이 되며, 해당 인스턴스가 가리키는 &amp;lt;div id=&amp;ldquo;app&amp;rdquo;&amp;gt;&amp;lt;/div&amp;gt;에 렌더링되는 실질적 코드는 App.vue이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상입니다. 궁금하신 점은 댓글로 남겨주세요.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;-1. Vue 2.x의 엔트리파일&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 포스팅은 Vue 3.0 에 버전이 맞춰져 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 여전히 아직은 Vue 2.x를 사용하시는 분들이 훨씬많기 때문에 아래와 같이 Vue 2.x대에서 활용되는 엔트리 파일을 작성해보았습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601841621086&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Vue 2.x
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
import router_main from './router/router_main'
import toyComponents from '@/components'

Vue.use(toyComponents)

const router = new VueRouter({router_main})

const app = new Vue({
  router
}).$mount('#app')
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vue 2.x버전에는 Vue Application 이라는 개념이 없습니다.&lt;/p&gt;
&lt;p&gt;그렇기에 글로벌 활용이 필요한 컴포넌트 및 라우터등은 Vue 객체가 내제하고 있는 Global API인 use를 활용하여야 합니다. 이때 '어, Vue 3.x에서 Vue Application 인스턴스의 use API랑 이름도 목적도 같네?' 라고 느끼실텐데 맞습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;기존에 Vue 2.x 버전때처럼 import 해 온 Vue 모듈에 직접적으로 use나 prototype을 통해 값을 할당하거나 정의하게되면 자바스크립트라는 언어 특성상 완전한 글로벌로 해당 값들이 활용되게 되어버립니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;The application instance is used to register 'globals' that can then be used by components within that application.&amp;nbsp;&lt;/blockquote&gt;
&lt;p&gt;위 인용한 Vue 3.0의 공식 홈페이지 설명을 따라 이해해보자면 아마도 이런 문제점을 수정하기 위해 Vue 3.x 부터는 createApp function을 통해 Vue Application 인스턴스를 생성하고, 생성된 인스턴스에 독립적으로 컴포넌트 및 라우터들을 매핑할 수 있게 바뀐 거라고 생각하고 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이와 관련된 내용은 또 기회가 된다면 Vue 3 포스팅에서 추가적으로 다루도록 하겠습니다.&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>SPA</category>
      <category>Vue</category>
      <category>Vue.js</category>
      <category>webpack</category>
      <category>웹개발</category>
      <category>자바스크립트</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/72</guid>
      <comments>https://blinders.tistory.com/72#entry72comment</comments>
      <pubDate>Mon, 5 Oct 2020 04:53:10 +0900</pubDate>
    </item>
    <item>
      <title>[Vue3] Font Awesome 적용하기</title>
      <link>https://blinders.tistory.com/70</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 작성할 포스팅은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Vue3.0에 Fontawesome을 적용하는 방법&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실, 아직 공식적으로 Fontawesome이 Vue 3.0을 지원하진 않는다&amp;hellip;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그도 그럴것이 &lt;b&gt;정식 릴리즈 된 지 아직 2주도 되지 않은 시점&lt;/b&gt;이니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://fontawesome.com/how-to-use/on-the-web/using-with/vuejs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Font Awesome의 공식 홈페이지&lt;/a&gt;에서 제시하고 있는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/FortAwesome/vue-fontawesome&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;vue-fontawesome 깃헙 레파지토리&lt;/a&gt;도 방문해 보신 분이라면 알아채겠지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Vue 3에 대한 정식 지원이 되지 않고 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 정확히는 아래처럼&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리 지원해. 그러니까 이 방법을 쓰면 될거야, 라고 안내는 하고 있지만&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-30 오후 8.29.02.png&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;529&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8JnTz/btqJXVAsV75/KGwaV1NAcmcr2KK2e9Gol0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8JnTz/btqJXVAsV75/KGwaV1NAcmcr2KK2e9Gol0/img.png&quot; data-alt=&quot;vue-fontawesome의 설치 가이드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8JnTz/btqJXVAsV75/KGwaV1NAcmcr2KK2e9Gol0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8JnTz%2FbtqJXVAsV75%2FKGwaV1NAcmcr2KK2e9Gol0%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-30 오후 8.29.02.png&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;529&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;vue-fontawesome의 설치 가이드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 버젓이 Using Vue 3.x라고 하고 npm install 명령어를 적어놨지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 사용하면 아래와 같이 &lt;span style=&quot;color: #ee2323;&quot;&gt;No matching version found for @fortawesome/vue-fontawesome@3&lt;/span&gt;라고 콘솔에 출력되는 걸 볼 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-30 오후 8.31.33.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;380&quot; width=&quot;599&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTRgCo/btqJUND62CC/1KtrHH3iwH88gWHZjtMoTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTRgCo/btqJUND62CC/1KtrHH3iwH88gWHZjtMoTk/img.png&quot; data-alt=&quot;동작그만, 시작부터 밑장빼기냐?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTRgCo/btqJUND62CC/1KtrHH3iwH88gWHZjtMoTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTRgCo%2FbtqJUND62CC%2F1KtrHH3iwH88gWHZjtMoTk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-30 오후 8.31.33.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;380&quot; width=&quot;599&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;동작그만, 시작부터 밑장빼기냐?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 처음에 fortawesome으로 시작하는 레파지토리명이 잘 못 올려놓은 건 줄 알았지만...그게 아니었다. 그걸 어떻게 아느냐면...해당 vue-fontawesome 깃헙 레파지토리의 마지막 커밋이 29일 전인데 Vue 3는 공식 릴리즈된지 10일밖에 안 됐으니까^^...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;Vue 3의 공식 릴리즈 이후로 vue-fontawesome은 변경사항이 없다&lt;/b&gt;는 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(2020년 09월 30일 기준)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 내가 진행하던 토이프로젝트는 이미 Vue3 를 타겟으로 하기로 마음먹었고, 진행간에 아이콘이 필요하므로 설치 및 활용을 해야했다. 그래서 그 간에 있었던 트러블 슈팅을 포스팅하려고 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0. Fontawesome 사용을 위한 기본 npm 설치&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;우선&lt;/b&gt; 아래와 같은 npm 패키지는 설치하자.&lt;/p&gt;
&lt;pre id=&quot;code_1601466507867&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i --save @fortawesome/fontawesome-svg-core
npm i --save @fortawesome/free-solid-svg-icons&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fontawesome-svg-core는 fontawesome의 아이콘을 svg 형태로 사용 할 수 있게 도와주는 패키지free-solid-svg-icons는 fontawesome에서 제공하는 아이콘 중에서, 무료인 아이콘들 중 solid 카테고리에 있는 항목들을 설치하는 거다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그외에 brand, regular 카테고리의 아이콘들도 있는데 필요시 아래 명령어로 추가 설치를 하면된다.&lt;/p&gt;
&lt;pre id=&quot;code_1601466715506&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i --save @fortawesome/free-brands-svg-icons
npm i --save @fortawesome/free-regular-svg-icons&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 유료 아이콘도 있다. 유료 아이콘부터는 'Pro'라고 불리는데 나는 무료 아이콘만으로도 충분하지만, 그 이상을 필요로 하는 사람이라면 &lt;a href=&quot;https://fontawesome.com/pro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 링크&lt;/a&gt;를 통해 Font Awesome의 공식 홈페이지로 가자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 일단 설치를 해야 뭐라도 해보지.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 본론으로 돌아와서, 당연한 이야기지만...무료든 유료든 우선 설치를 해야 활용을 할 거 아닌가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서도 말했지만 vue-fontawesome에서 가이드하고 있는 아래와 같은 명령어를 사용해봤자&lt;/p&gt;
&lt;pre id=&quot;code_1601465987746&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i --save @fortawesome/vue-fontawesome@3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 본 &lt;span style=&quot;color: #ee2323;&quot;&gt;No matching version found for @fortawesome/vue-fontawesome@3 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;로그를 다시 한번 볼 뿐이다. 자, 그러면 어떡해야 하느냐? &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;실제 @fortawesome/vue-fontawesome이 Vue3에 맞게 설치되는 명령어는 아래와 같다&lt;/b&gt;&lt;/span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1601466203119&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; npm i --save @fortawesome/vue-fontawesome@3.0.0-1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 본 명령어를 통한 해결법은 &lt;a href=&quot;https://github.com/FortAwesome/vue-fontawesome/issues/230&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vue 3 깃헙의 Issue 페이지&lt;/a&gt;에 올라와있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시, 대격변이후로 헤매는 건 만국 개발자 공통인 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명령어를 통한 직접 설치는 위와 같이 하면 되고 package.json에 추가해서 npm install 명령어를 쓰려는 분은 아래와 같이 package.json에 작성해주시면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1601466406286&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;@fortawesome/vue-fontawesome&quot;: &quot;^3.0.0-1&quot;,&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 여기까지 했다면 이제 Vue 3에서 활용가능한 Font Awesome의 설치를 끝냈다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 실제 Vue3에서 활용하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue 3는 뭔가 참...좀 그렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많이 안 바뀐 거 같은데 뭐가 또 많이 바꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이전의 Vue에서는 글로벌 컴포넌트가 필요한 경우&lt;/b&gt; 아래와 같이,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Global API인 Vue.component를 통해 컴포넌트를 정의하고 사용&lt;/b&gt;&lt;/span&gt;해왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-30 오후 9.01.49.png&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;355&quot; width=&quot;615&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKpLMd/btqJWrGCDcz/ZxYTIXkRzkvHUA5xlB2iqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKpLMd/btqJWrGCDcz/ZxYTIXkRzkvHUA5xlB2iqK/img.png&quot; data-alt=&quot;Vue.component(&amp;amp;#39;font-awesome-icon&amp;amp;#39;, FontAwesomeIcon)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKpLMd/btqJWrGCDcz/ZxYTIXkRzkvHUA5xlB2iqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKpLMd%2FbtqJWrGCDcz%2FZxYTIXkRzkvHUA5xlB2iqK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-30 오후 9.01.49.png&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;355&quot; width=&quot;615&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Vue.component('font-awesome-icon', FontAwesomeIcon)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시는 vue-fontawesome에 게시된 npm 패키지 이후,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔트리파일인 main.js에 vue-fontawesome을 정의하는 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;당연한 말이지만...안 된다, 저거.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단...Vue 3에는 Global API에 Component 가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀쩡히 있던...그리고 아주 잘 쓰이던 애를 없애버렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://v3.vuejs.org/api/global-api.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vue3의 Global API&lt;/a&gt; &amp;larr; 이 링크를 통해 들어가보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;없는 걸 확인했는가? 하지만 여기엔 함정이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-30 오후 9.08.54.png&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;219&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZEEdW/btqJZnpYy9O/6TF0sTiJUoxLAFYGIK5HfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZEEdW/btqJZnpYy9O/6TF0sTiJUoxLAFYGIK5HfK/img.png&quot; data-alt=&quot;ㅂㄷㅂㄷㅂㄷㅂㄷ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZEEdW/btqJZnpYy9O/6TF0sTiJUoxLAFYGIK5HfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZEEdW%2FbtqJZnpYy9O%2F6TF0sTiJUoxLAFYGIK5HfK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-30 오후 9.08.54.png&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;219&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ㅂㄷㅂㄷㅂㄷㅂㄷ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://v3.vuejs.org/api/application-api.html#component&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vue3 Application API&lt;/a&gt; &lt;span style=&quot;color: #333333;&quot;&gt;&amp;larr; 이 링크로 들어가보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;봤는가? Component API가 버젓이 있ㅋ다ㅋ&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이에 대한 상세한 설명은 Vue 3에서 나타난 Application 개념&lt;/b&gt;&lt;/span&gt;을 설명해야하는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 포스팅은 어디까지나 Font Awesome을 Vue3에 적용하는 트러블 슈팅이므로 &lt;b&gt;그에대한 설명은 다른 포스팅&lt;/b&gt;에서 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 우선 vue-fontawesome 깃헙에 적힌 것처럼 &lt;b&gt;그대로 엔트리 파일에 정의&lt;/b&gt;하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 활용되는 코드 또한, 아래와 같이 깃헙에 있는 가이드를 &lt;b&gt;그대로 따라서 실행&lt;/b&gt;해보겠다.&lt;/p&gt;
&lt;pre id=&quot;code_1601468166125&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; &amp;lt;font-awesome-icon icon=&quot;user-secret&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...예상한 결과지만 아래와 같이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-30 오후 9.35.23.png&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;129&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z0PM4/btqJZnKiL6x/wb22pPLNaESh7kykVGfbNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z0PM4/btqJZnKiL6x/wb22pPLNaESh7kykVGfbNK/img.png&quot; data-alt=&quot;없으니까 당연히 못 찾겠지^^&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z0PM4/btqJZnKiL6x/wb22pPLNaESh7kykVGfbNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz0PM4%2FbtqJZnKiL6x%2Fwb22pPLNaESh7kykVGfbNK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-30 오후 9.35.23.png&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;129&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;없으니까 당연히 못 찾겠지^^&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 그럼 어떻게 해야하느냐...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 매우 간단하다. &lt;b&gt;로마에 가면 로마법을 따르듯이, Vue 3에 왔으니 Vue 3의 법을 따르면 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Vue 3에서 Application 라는 개념이 등장을 했고, 기존에 new Vue 라는 코드를 통해 Vue 인스턴스를 생성해서 활용을 했지만...&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Vue 3 부터는 createApp이라는 메서드의 형태로 Vue Application 인스턴스를 생성해서 활용하게 변경&lt;/b&gt;&lt;/span&gt;되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;즉, 아래와 같이 작성해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1601469543051&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {createApp} from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'
import App from './App'
import router_main from './router/router_main'

// font-awesome과 관련된 import를 정의
import { library } from '@fortawesome/fontawesome-svg-core'
import { faUserSecret } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
library.add(faUserSecret)


let router = createRouter({
    history: createWebHashHistory(),
    routes: router_main
})
const app = createApp(App);

// 위에 createApp을 통해 생성한 Vue Application 인스턴스의 component API 활용
app.component('font-awesome-icon', FontAwesomeIcon)


app.use(router);
app.mount('#app');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 엔트리 파일에 정의하게되면 이제 아래와 같은 예시코드를 사용하면&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1601469618458&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; &amp;lt;font-awesome-icon icon=&quot;user-secret&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 아이콘이 브라우저에 나오는 걸 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-30 오후 9.41.14.png&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;460&quot; width=&quot;303&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bx8pc8/btqJWTppQlp/0K36W4hP5uthfRpxY37ONk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bx8pc8/btqJWTppQlp/0K36W4hP5uthfRpxY37ONk/img.png&quot; data-alt=&quot;별 거 아닌데 아이콘이 뜨니까 그렇게 반갑더라...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bx8pc8/btqJWTppQlp/0K36W4hP5uthfRpxY37ONk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbx8pc8%2FbtqJWTppQlp%2F0K36W4hP5uthfRpxY37ONk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-30 오후 9.41.14.png&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;460&quot; width=&quot;303&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;별 거 아닌데 아이콘이 뜨니까 그렇게 반갑더라...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 정의가 끝났다면, 이제 코드 어디에서든 &amp;lt;font-awesome-icon&amp;gt; 이라는 커스텀 태그를 통해서 Font Awesome의 아이콘을 활용할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 이전 버전 그대로 쓰고 싶을 때&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 하나의 트러블 슈팅거리가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세상엔 함정이 참 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 당신이&amp;nbsp; &lt;a href=&quot;https://www.npmjs.com/package/@fortawesome/vue-fontawesome&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;npm 패키지에서 제공하는 vue-fontawesom 사이트&lt;/a&gt;의 예시를 참고해서 설치했다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 명령어를 썼을거다.&lt;/p&gt;
&lt;pre id=&quot;code_1601474136828&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i @fortawesome/vue-fontawesome&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 npm 패키지를 설치할 때 버전까지는 기입을 잘 하지 않는다. 왜냐면, 이름만 치면 설치 시점의 가장 최신 버전이 설치가 되니까 말이다. 게다가 패키지 사이트의 우상단에도 아래와 같이 아주 잘 보이게 명령어를 써두니가 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-30 오후 10.04.42.png&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;249&quot; width=&quot;410&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LAF3F/btqJWRkOXIr/4JKVwc93XXKjgiiZfPKzJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LAF3F/btqJWRkOXIr/4JKVwc93XXKjgiiZfPKzJk/img.png&quot; data-alt=&quot;대부분은 그냥 저거 복붙에서 cmd에 붙이니까 말이다&amp;amp;amp;hellip;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LAF3F/btqJWRkOXIr/4JKVwc93XXKjgiiZfPKzJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLAF3F%2FbtqJWRkOXIr%2F4JKVwc93XXKjgiiZfPKzJk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-30 오후 10.04.42.png&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;249&quot; width=&quot;410&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대부분은 그냥 저거 복붙에서 cmd에 붙이니까 말이다&amp;hellip;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;하지만 참 안타깝게도, 저 명령어로 vue-fontawesome을 설치하게 되면 2.x 버전이 설치되게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까&amp;hellip;Vue 2.x 버전을 지원하게 작성된 버전말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 버전을 설치하고, &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;&lt;i&gt;2. 실제 Vue3에서 활용하기 &lt;/i&gt;&lt;/b&gt;&lt;/span&gt;항목에서 작성한 것처럼 엔트리 파일에 패키지들을 import 후, component API로 사용하게끔 정의하고 코드를 작성해보면 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;화면에 아무것도 나오지 않을 것&lt;/b&gt;&lt;/span&gt;이다. 그리고 개발자 도구를 열어보면 아래와 같은 에러로그를 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-30 오후 10.09.12.png&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;157&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dyhsct/btqJUObZ5vH/FfaESSseWuDfVY8gcFgq00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dyhsct/btqJUObZ5vH/FfaESSseWuDfVY8gcFgq00/img.png&quot; data-alt=&quot;개발자 도구로 열어본 실제 코드에 에러나는 위치, 그리고 콘솔창 에러로그&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dyhsct/btqJUObZ5vH/FfaESSseWuDfVY8gcFgq00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdyhsct%2FbtqJUObZ5vH%2FFfaESSseWuDfVY8gcFgq00%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-30 오후 10.09.12.png&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;157&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개발자 도구로 열어본 실제 코드에 에러나는 위치, 그리고 콘솔창 에러로그&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Cannot read property &amp;lsquo;icon&amp;rsquo; of undefined&lt;/span&gt; 라는 에러로그가 콘솔에 출력 될 것이고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;index.es.js:434로 집혀있는 코드 위치를 찾아가보면 좌측 이미지와 같이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var iconArgs = props.icon 라고 정의 된 코드인데, &lt;span style=&quot;color: #ee2323;&quot;&gt;props 변수에서 빨간줄&lt;/span&gt;이 그어져 있을 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연하다&amp;hellip;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 저 위치에 브레이크 포인트를 걸고 찍어보면 &lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;props 라는 객체 자체가 undefined&lt;/span&gt;&lt;/b&gt;로 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-30 오후 10.11.18.png&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;185&quot; width=&quot;430&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lWCFM/btqJV6itIsu/jDN7IzNIvUIKe6ddwAwfgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lWCFM/btqJV6itIsu/jDN7IzNIvUIKe6ddwAwfgk/img.png&quot; data-alt=&quot;props = undefined&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lWCFM/btqJV6itIsu/jDN7IzNIvUIKe6ddwAwfgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlWCFM%2FbtqJV6itIsu%2FjDN7IzNIvUIKe6ddwAwfgk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-30 오후 10.11.18.png&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;185&quot; width=&quot;430&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;props = undefined&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props라는 인스턴스가 이미 undefined인데 거기에 체이닝된 icon이 인식 될 리 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 &lt;b&gt;1번의 undefined는 이해해줘도 2차 연쇄부터는 참아주지 않는 언어&lt;/b&gt;니까말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐, 사실 이 이슈는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;1번에서 설명했던 3.x 버전을 설치했다면 발생하지 않을 이슈&lt;/b&gt;&lt;/span&gt;지만&amp;hellip;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이리 삽질 저리 삽질하는 개발자의 입장에선 충분히 겪을 수 있는 이슈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 처음 vue-fontawesome 3.x 버전을 옳게 설치하지 못 한 내가 겪은 이슈기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-30 오후 10.22.18.png&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;264&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTJVWT/btqJV5qka5J/Gy2Q6AWornQF6Q7DPxiQUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTJVWT/btqJV5qka5J/Gy2Q6AWornQF6Q7DPxiQUk/img.png&quot; data-alt=&quot;이렇게 에러를 만남으로써 난 또 하나의 트러블 슈팅 능력을 얻었다, 하하하!!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTJVWT/btqJV5qka5J/Gy2Q6AWornQF6Q7DPxiQUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTJVWT%2FbtqJV5qka5J%2FGy2Q6AWornQF6Q7DPxiQUk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-30 오후 10.22.18.png&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;264&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이렇게 에러를 만남으로써 난 또 하나의 트러블 슈팅 능력을 얻었다, 하하하!!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이슈를 해결하는 방법은 &lt;b&gt;생각보다 심플&lt;/b&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Font Awesome은 결국 아이콘을 SVG 형태로 제공하는 역할이므로,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;SVG를 직접 화면에 렌더링하는 Vue Component를 만들면 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(개발자는 개발하는 사람입니다, 없으면 개발하면 됩니다. 그것이 개발자니까요)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 해결법도&amp;nbsp; &lt;a href=&quot;https://github.com/FortAwesome/vue-fontawesome/issues/230&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vue 3 Github Issue #230&lt;/a&gt;을 보면 중간쯤 답변으로 작성되어 있는 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Vue 3 Github의 #230 이슈는 이름자체가 Vue 3 Support 인 것으로 보아 Vue 3의 릴리즈 이후, 개발자들을 지원하기 위해 열려있는 이슈로 보인다. 그러니 Vue 3 최신 버전을 적용하려는 개발자라면 필수로 들락날락하자. &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;뭐가 안 된다 싶으면 저기부터&lt;/b&gt;&lt;/span&gt; 가보는 걸 추천한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 내가 작성한 Icon 컴포넌트이며, #230 이슈에 올려진 코드에 사이즈와 관련된 props를 추가하여 수정한 코드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(해당 코드는 Github의&amp;nbsp; &lt;a href=&quot;https://github.com/onedayz/vue_starter&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;vue starter 레파지토리&lt;/a&gt;에도 올라와 있으며 파일에 대한 &lt;a href=&quot;https://github.com/onedayz/vue_starter/blob/dev/src/components/toyIcon.vue&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다이렉트 링크&lt;/a&gt;는 여기 에 남겨둘테니 관심있는 사람은 직접와서 보셔도 된다)&lt;/p&gt;
&lt;pre id=&quot;code_1601474591209&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; :class=&quot;$props.class&quot;
         :viewBox=&quot;`0 0 ${width} ${height}`&quot; :style=&quot;iconStyle&quot;&amp;gt;
        &amp;lt;path fill=&quot;currentColor&quot; :d=&quot;svgPath&quot; /&amp;gt;
    &amp;lt;/svg&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import { library } from '@fortawesome/fontawesome-svg-core';
import { fas } from '@fortawesome/free-solid-svg-icons';
import { defineComponent, computed } from 'vue';
import { findIconDefinition } from '@fortawesome/fontawesome-svg-core';
library.add(fas)

export default defineComponent({
    name: 'toyIcon',
    props: {
        icon: {
            type: String,
            required: true
        },
        type: {
            type: String,
            default: &quot;fas&quot;,
            required: false
        },
        class: String,
        size: {type: [Number, String], default: ''},
        small: {type: Boolean, default: false},
        medium: {type: Boolean, default: false},
        large: {type: Boolean, default: false},
    },
    setup(props) {
        const definition = computed(() =&amp;gt;
            findIconDefinition({prefix: props.type, iconName: props.icon})
        );

        const width = computed(() =&amp;gt; definition.value.icon[0]);
        const height = computed(() =&amp;gt; definition.value.icon[1]);
        const svgPath = computed(() =&amp;gt; definition.value.icon[4]);
        const iconStyle = computed(() =&amp;gt;{
            let style = {};
            if(props.small){style.width = '12px';}
            else if(props.large){style.width = '18px';}
            else if(props.size){style.width = props.size + 'px';}
            else{style.width = '14px';}
            return style;
        });
        return { width, height, svgPath, iconStyle };
    }
})
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 코드는 내 경우에는 toyIcon.vue라는 이름으로 사용중이며 위와 같이 컴포넌트를 생성한 이후,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔트리 파일에 동일하게 component라는 Application API를 통해 정의하거나,&lt;/p&gt;
&lt;pre id=&quot;code_1601474632116&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {createApp} from &amp;lsquo;vue&amp;rsquo;
import { createRouter, createWebHashHistory } from &amp;lsquo;vue-router&amp;rsquo;
import App from &amp;lsquo;./App&amp;rsquo;
import router_main from &amp;lsquo;./router/router_main&amp;rsquo;

/// 커스텀하게 정의한 toyIcon.vue를 import/
import toyIcon from &amp;lsquo;toyIcon.vue의 경로&amp;rsquo;

let router = createRouter({
    history: createWebHashHistory(),
    routes: router_main
})

const app = createApp(App);

/// Application component API를 통해서 전역으로 설정/
app.component(&amp;lsquo;toy-icon&amp;rsquo;, toyIcon)
app.use(router);
app.mount(&amp;lsquo;#app')&amp;rsquo;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹은 필요한 vue 파일에서 직접 import 하여 사용해도 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1601474714003&quot; class=&quot;javascript&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;toy-icon icon=&quot;user-secret&quot;/&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import toyIcon from 'toyIcon.vue의 경로'

export default {
  components: {toyIcon}
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐, 혹시 이것마저도 귀찮으신 분은 toyIcon.vue 파일을 첨부해서 올려드리니 받아서 쓰시기 바란다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/VxeRN/btqJVPOPwVt/kIGzl7oWBa8fFff5GIb2bk/toyIcon.vue?attach=1&amp;amp;knm=tfile.vue&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;toyIcon.vue&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.00MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>fontawesome</category>
      <category>frontend</category>
      <category>Vue</category>
      <category>Vue.js</category>
      <category>Vue3</category>
      <category>개발</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/70</guid>
      <comments>https://blinders.tistory.com/70#entry70comment</comments>
      <pubDate>Wed, 30 Sep 2020 21:46:04 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js_#02] SPA</title>
      <link>https://blinders.tistory.com/69</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;0. 어때요, 서버는 잘 떴나요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm run serve의 결과로 띄워진 http://localhost:8080 에 브라우저로 접속해서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 화면을 띄웠다면 이제 절반은 끝낸 겁니다&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(시작이 절반이니까요?)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-29 오전 2.12.45.png&quot; data-origin-width=&quot;1049&quot; data-origin-height=&quot;714&quot; width=&quot;523&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0Okqk/btqJOzkZfWv/3O3iCObVrp34QSalZY2mHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0Okqk/btqJOzkZfWv/3O3iCObVrp34QSalZY2mHk/img.png&quot; data-alt=&quot;참 심플하고 좋은 화면이에요,그쵸?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0Okqk/btqJOzkZfWv/3O3iCObVrp34QSalZY2mHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0Okqk%2FbtqJOzkZfWv%2F3O3iCObVrp34QSalZY2mHk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-29 오전 2.12.45.png&quot; data-origin-width=&quot;1049&quot; data-origin-height=&quot;714&quot; width=&quot;523&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;참 심플하고 좋은 화면이에요,그쵸?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아, 시작하기에 앞서서 당부드리자면 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;오늘은 좀 지루한 이야기&lt;/b&gt;&lt;/span&gt;를 해야 할 거 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 좀 더 집중해서 글을 읽어주시면 좋을 거 같습니다. 저도 지루한 이야기는 별로 좋아하지 않습니다만, 지루하더라도 해야하는, 이야기는 해야하니까요ㅎㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아, 뭐 그렇다고해서 되~~~~게 어려운 개념을 설명하려는 건 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 듣는 이에따라서는 이게 대체 뭔 소리야? 라고 생각할 수도 있긴합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 차근차근 설명을 시작해보도록 하겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. SPA (S&lt;/b&gt;ingle&lt;b&gt; P&lt;/b&gt;age&lt;b&gt; A&lt;/b&gt;pplication&lt;b&gt;)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;SPA에 대해 이야기&lt;/b&gt;&lt;/span&gt;&amp;nbsp;해봅시다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 시점에선가부터 웹 개발을 좀 한다 싶으면, 꺼내지는 키워드들이 몇가지가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중에 매우 흔한 키워드가 바로 이 SPA 인데요. 사실 &lt;b&gt;SPA는 SPA라는 축약어에 모든 의미를 다 담고 있습니다&lt;/b&gt;. &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;S&lt;/b&gt;&lt;/span&gt;ingle &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;P&lt;/b&gt;&lt;/span&gt;age &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;A&lt;/b&gt;&lt;/span&gt;pplication. 이 세 단어로 의미와 사용법, 심지어 어떻게보면 아키텍쳐까지 다 설명을 해버립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-29 오전 6.17.53.png&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;206&quot; width=&quot;423&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EKa6i/btqJRmkDcbY/ZkXF4PGlwf7V7Bk63kmTeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EKa6i/btqJRmkDcbY/ZkXF4PGlwf7V7Bk63kmTeK/img.png&quot; data-alt=&quot;응, 너 아니야...그 스파 아니야...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EKa6i/btqJRmkDcbY/ZkXF4PGlwf7V7Bk63kmTeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEKa6i%2FbtqJRmkDcbY%2FZkXF4PGlwf7V7Bk63kmTeK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-29 오전 6.17.53.png&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;206&quot; width=&quot;423&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;응, 너 아니야...그 스파 아니야...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPA에서 꼭 기억하셔야 할 개념은, 실제 사용되는 건&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;딱! 딱! Just One,&lt;/b&gt;&amp;nbsp;&lt;b&gt;하나의 페이지&lt;/b&gt;&lt;/span&gt; 라는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(주구장창 싱글 페이지 싱글 페이지, 하나의 페이지, 온리 원, 저스트 원...이걸 계속 반복 말씀드리고 있습니다. 그만큼 중요하단거지만 그게 전부라는 반증입니다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 쉬운 설명을 위해 예시를 들어보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도서관리를 하는 웹 서비스를 여러분이 개발하려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽고 싶은 책을 검색하고, 책을 빌리고, 반납하는 정도의 서비스를 하는 웹 페이지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 서비스를 만들 때, 기존의 JSP/PHP/ASP 와 같은 기술을 사용하셨다면 아마 무수히 많은 JSP, PHP, ASP 파일들을 만드셨을 겁니다. 사용자가 서비스에 접근시 맨 처음 보여야 하는 home.jsp가 있을 거구요, 로그인을 해야하니까 login.jsp도 있어야 겠죠. 아, 저흰 도서관리를 하는 웹 서비스니까 책을 검색하는 search.jsp, 책을 대여하는 rent.jsp, 책을 반납하는 return.jsp 도 필요할 거 같네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐, 이 &lt;b&gt;이외에도 아주 많은 페이지들이 각자의 용도에 맞게 생성&lt;/b&gt;이 되었을겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;여기에서 우리가 주목해야 할 포인트는 &lt;span style=&quot;color: #006dd7;&quot;&gt;아주 많은 페이지&lt;/span&gt;&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 많다, 라는 건 1개가 아니라는 소리죠. &lt;b&gt;이 서비스를 위해선 N개의 파일들이 필요하다&lt;/b&gt;라는거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 SPA는 어떨까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이름이 모든 걸 대변&lt;/b&gt;한다고 말씀드렸죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱글 페이지 어플리케이션.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;딱! &lt;span style=&quot;color: #006dd7;&quot;&gt;하나&lt;/span&gt;의!! 파일!!!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-29 오전 6.25.28.png&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;428&quot; width=&quot;335&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eMY9xA/btqJKwoNh22/wYK4QvMkeoKZ02UrOHAHmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eMY9xA/btqJKwoNh22/wYK4QvMkeoKZ02UrOHAHmk/img.png&quot; data-alt=&quot;어, 형 나두...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eMY9xA/btqJKwoNh22/wYK4QvMkeoKZ02UrOHAHmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeMY9xA%2FbtqJKwoNh22%2FwYK4QvMkeoKZ02UrOHAHmk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-29 오전 6.25.28.png&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;428&quot; width=&quot;335&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;어, 형 나두...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네, 그렇습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPA는 HTML 파일 하나.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;단 하나의 파일(페이지)만을 가지고 웹 서비스를 제공&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 정확하게 말을 해볼께요. &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;단 하나의 '정적 페이지(a.k.a HTML)'만을 가지고 웹 서비스를 제공&lt;/b&gt;&lt;/span&gt;한다, 바로! 이겁니다!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 삼위일체&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-29 오전 6.30.52.png&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;377&quot; width=&quot;381&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QDnEO/btqJKvXItku/yyUY7kdGpQES8S2vbrRVs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QDnEO/btqJKvXItku/yyUY7kdGpQES8S2vbrRVs0/img.png&quot; data-alt=&quot;하나면 하나지 둘이겠느냐, 둘이며 둘이지 셋은 아니야, 셋이면 셋이지&amp;amp;amp;nbsp;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QDnEO/btqJKvXItku/yyUY7kdGpQES8S2vbrRVs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQDnEO%2FbtqJKvXItku%2FyyUY7kdGpQES8S2vbrRVs0%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-29 오전 6.30.52.png&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;377&quot; width=&quot;381&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;하나면 하나지 둘이겠느냐, 둘이며 둘이지 셋은 아니야, 셋이면 셋이지&amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아, 고백합니다. 사실 파일 하나로 서비스를 제공하는 건 맞는데요 그게 또 파일 하나로 다 커버를 하느냐고 물어보시면 그건 또 아니거든여...그러니가 진짜 정말로 리얼리 온리 원 에이치티엠웰 파일 이즈 올 커버 ㅇㅈ? ㄴㅇㅈ, 동의보감? 이냐고 물으신다면...좀 애매합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 번복해서 헷갈리게 하냐구요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정말 웹 서비스를 제공하는데 HTML 파일 하나만으로 될까요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니죠, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;그럴리가요.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 여러분이 개발한 &lt;b&gt;서비스를 제공하기 위해서 필요한 건 아래의 3개&lt;/b&gt;라고 보시면 됩니다.&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;1. 웹 서비스의 밑 바탕을 이루는&amp;nbsp;&lt;b&gt;HTML 파일&lt;/b&gt;(예를 들어, index.html)&lt;br /&gt;2. 스크립트 코드들이 빌드된&amp;nbsp;&lt;b&gt;Javascript 파일&lt;/b&gt;(예를 들어, build.js)&lt;br /&gt;3. 이미지, 폰트와 같은&amp;nbsp;&lt;b&gt;정적 리소스&lt;/b&gt;(예를 들어 *.jpg, *.png, *.woff)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 이렇게 3가지 구성으로 &lt;b&gt;SPA의 기반이 마련&lt;/b&gt;되고, 하나의 웹 서비스를 제공할 수 있는 겁니다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. N개의 vue 파일&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 파일로 제공하는 서비스지만 한 파일 같지 않은 한 파일의 SPA.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;내꺼인 듯 내꺼 아닌 내꺼 같은 너...ㅈㅅ....&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거기에 좀 더 헷갈릴 수 있는 대목이 ㄷㄷㄷㅈ!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-29 오전 6.48.19.png&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;593&quot; width=&quot;295&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAvs03/btqJHasWUr1/oUVJQICbKDfN0ej4X87GAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAvs03/btqJHasWUr1/oUVJQICbKDfN0ej4X87GAk/img.png&quot; data-alt=&quot;두둥등장!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAvs03/btqJHasWUr1/oUVJQICbKDfN0ej4X87GAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAvs03%2FbtqJHasWUr1%2FoUVJQICbKDfN0ej4X87GAk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-29 오전 6.48.19.png&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;593&quot; width=&quot;295&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;두둥등장!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단 하나의 파일, 이라는 개념을 좀 더 파고들어가보겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;여기서부턴 천천히 따라와주세요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링의 MVC구조가 익숙하신 분이라면, 컨트롤러 역할의 JAVA 파일에서 아래와 같은 리턴 형태를 많이 보셨을 겁니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601329945757&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;return &amp;ldquo;redirect:/&amp;rdquo;;
혹은
return &amp;ldquo;home&amp;rdquo;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 문자열을 정의하여 리턴해주면, 그에 맞게 이름이 일치하게끔 매핑된 파일, 혹은 해당 URL 경로에 지정해놓은 파일이 불리게 됩니다. 이때 각 조건에 맞춰서 호출되는 파일들이 바로, JSP/PHP/ASP 기반으로 작성된 파일들이었습니다. 그리고 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이것이 그동안 활용되던 웹 서비스의 동작 방식&lt;/b&gt;&lt;/span&gt;이구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서비스의 접속시 최초로 보이는 home.jsp&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인을 해야하니까, 로그인 기능이 있는 login.jsp&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책을 검색하고 그 결과가 나오는 search.jsp&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾은 책을 빌리는 rent.jsp, 책을 반납하는 return.jsp&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략 이런 파일들 말이죠&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(혹은 ModelAndView나, HTML 태그를 문자열 형태로 리턴하는 방법등등 다양하지만, 결코 이 모든 것들은 &lt;b&gt;1개 파일로 이루어진 구성이라고 말할 수가 없습니다&lt;/b&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 &lt;b&gt;SPA도 비슷&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 SPA도 개발을 할 때는 각 파일별로 기능이 나누어져 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼레, 뭐야? 그럼 다를 게 없는 거 아냐?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다를 게 있습니다. 바로 이 SPA의 파일들은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;실제 서비스에 직접적으로 사용되진 않습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSP/PHP/ASP에서와 같이 각 파일별로 기능을 개발했는데, 서비스에 사용되지 않는다&amp;hellip;라니? 이게 콩이여 된장이여 말이여 빙구여, 뭔 귀신 씨나락 까먹는 소리인가 싶으실거에요. 이해합니다...프로젝트 현장에 Vue.js 교육을 해드릴때도 여기서 헤매시는 분들이 여럿 있으시더라구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 저희가 &lt;b&gt;주목해야 할 포인트는 바로 &lt;span style=&quot;color: #006dd7;&quot;&gt;직접적&lt;/span&gt;으로라는 대목&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 파일명에서부터 출발해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;JSP 기반의 프로젝트라면 JSP파일&lt;/b&gt;을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PHP 기반이라면, PHP 파일&lt;/b&gt;을 이용하겠죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Vue.js 기반을 공부&lt;/b&gt;&lt;/span&gt;하고 있습니다. 그럼, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;당연히 Vue파일을 활용&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;확장자가 .vue 인 파일들에 우리는 기능을 개발하고 정의&lt;/b&gt;&lt;/span&gt;할 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어, 근데 이상한 점이 있어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPA에서는 하나의 파일로 서비스를 제공한다고 하지 않았나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 &lt;b&gt;vue 파일&lt;span style=&quot;color: #006dd7;&quot;&gt;'들'&lt;/span&gt;이라니요? &amp;lsquo;들&amp;rsquo;은 하나가 아니잖&lt;/b&gt;아요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-29 오전 7.12.23.png&quot; data-origin-width=&quot;451&quot; data-origin-height=&quot;352&quot; width=&quot;349&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9hCsa/btqJPCIvHho/xiTfp2Pb5CkcGBXAK8u2U1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9hCsa/btqJPCIvHho/xiTfp2Pb5CkcGBXAK8u2U1/img.png&quot; data-alt=&quot;나 갖다가 너는 밤낮 장난하나&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9hCsa/btqJPCIvHho/xiTfp2Pb5CkcGBXAK8u2U1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9hCsa%2FbtqJPCIvHho%2FxiTfp2Pb5CkcGBXAK8u2U1%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-29 오전 7.12.23.png&quot; data-origin-width=&quot;451&quot; data-origin-height=&quot;352&quot; width=&quot;349&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;나 갖다가 너는 밤낮 장난하나&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네, 맞습니다. &lt;b&gt;vue파일들이 서비스를 제공&lt;/b&gt;하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;N개로 이루어진 형태가 아니라 단일화된 하나의 파일로써 서비스를 제공&lt;/b&gt;&lt;/span&gt;하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(집중 박수 세번 짝, 짝, 짝. 별표 5개 땅&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;★&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;따라&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;★&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;땅&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;★&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;따라&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;★&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;땅&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;★&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 2번 삼위일체 항목을 먼저 언급드렸던 이유가 바로 이겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자...다시 한 번 SPA에서 서비스를 제공하기 위해 &lt;b&gt;기본적으로 필요한 3가지&lt;/b&gt;를 되짚어 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style2&quot;&gt;1. 웹 서비스의 밑 바탕을 이루는&amp;nbsp;&lt;b&gt;HTML 파일&lt;/b&gt;(예를들어, index.html)&lt;br /&gt;2. 스크립트 코드들이 빌드된&amp;nbsp;&lt;b&gt;Javascript 파일&lt;/b&gt;(예를들어, build.js)&lt;br /&gt;3. 이미지, 폰트와 같은&lt;b&gt; 정적 리소스&lt;/b&gt;(예를들어, *.jpg, *.png, *.woff)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서, 2번 항목으로 쓰인 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Javascript 파일&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 파일이 바로 &lt;b&gt;N개의 vue 파일들이 컴파일과 빌드를 거쳐서 단일화 된 파일&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 사실상 SPA의 주축, 뼈대 역할을 하는 HTML 파일에는 아래와 유사한 &amp;lt;body&amp;gt; 태그가 작성되게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1601331753323&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;body&amp;gt;
  &amp;lt;div id=app&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;script src=/dist/build.js&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;body&amp;gt; 태그의 내부를 잘 봐주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, &lt;b&gt;id가 app인 &amp;lt;div&amp;gt; 태그&lt;/b&gt;가 하나 있구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 아래에 &lt;b&gt;&amp;lt;script&amp;gt; 태그를 사용해서 Javascript 파일인 build.js를 품고 있다&lt;/b&gt;는 걸 아실 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 정리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어...? 어어...?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐야 갑자기 왜 벌써 정리야...?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 설명해야 할 게 산더미아냐?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네 맞습니다.&lt;b&gt; 아직 설명드려야 할 게 많아요.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;대체 어떻게 vue 파일들이 컴파일/빌드를 통해 단일화해서 build.js가 되는지.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그 build.js가 어떻게 HTML에서 활용되어 화면을 렌더링 하는지.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;앞서 설명한 return &amp;ldquo;home&amp;rdquo;; 을 통해 home.jsp를 호출하던 것과 같은 매커니즘은 vue에서 어떻게 정의하고 어떻게 동작하는지.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;...등등등을 설명해야 하지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;사실 여기까지 보시는 것만으로도 슬슬 머리가 아파오시지 않을까 싶습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-29 오전 7.34.13.png&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;162&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kJu6Q/btqJP6vOK3u/LKT4YIqoiSK2pM7I4KFim0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kJu6Q/btqJP6vOK3u/LKT4YIqoiSK2pM7I4KFim0/img.png&quot; data-alt=&quot;우리에겐 다음이 있지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kJu6Q/btqJP6vOK3u/LKT4YIqoiSK2pM7I4KFim0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkJu6Q%2FbtqJP6vOK3u%2FLKT4YIqoiSK2pM7I4KFim0%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-29 오전 7.34.13.png&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;162&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;우리에겐 다음이 있지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그래서 &lt;b&gt;한 번 끊고 포스팅을 이어가려고&lt;/b&gt; 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 정리해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.&lt;/b&gt; &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;SPA는 단일 파일로 하나의 &amp;lsquo;웹 서비스&amp;rsquo;를 제공&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.&lt;/b&gt; &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;서비스의 기능 구현은 각 역할에 맞는 vue파일에 정의&lt;/b&gt;&lt;/span&gt;한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.&lt;/b&gt; 하지만 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이때 개발한 N개의 vue 파일은 컴파일&amp;amp;빌드되어 1개의 Javascript&lt;/b&gt;&lt;/span&gt;가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.&lt;/b&gt; &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;HTML파일은 빌드된 Javascript 파일을 활용&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 4줄로 이번 포스팅에서 설명한 개념이 축약되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참 짧은데...풀어쓰고 풀어쓰니 참 길게도 적었네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 다음 편에서 뵙도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;질문은 언제나 환영합니다. 댓글은 언제든 남겨주세요.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;-1. 부록&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 또 가기엔 섭섭하니 부록 하나를 남겨보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 근본적인 질문을 던져볼게요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSP/PHP/ASP 잘 쓰고 있고 저는 그게 더 편해요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 &lt;b&gt;왜 굳이 SPA를 해야하나요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-29 오전 7.42.46.png&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;371&quot; width=&quot;428&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4tzEH/btqJKvi6bg6/Q9c16GCKP7dHfj17QR7iEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4tzEH/btqJKvi6bg6/Q9c16GCKP7dHfj17QR7iEK/img.png&quot; data-alt=&quot;SPA 설명 실컷 해놓고, 이 X끼 뭐야, 너 인성 문제있어?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4tzEH/btqJKvi6bg6/Q9c16GCKP7dHfj17QR7iEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4tzEH%2FbtqJKvi6bg6%2FQ9c16GCKP7dHfj17QR7iEK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-29 오전 7.42.46.png&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;371&quot; width=&quot;428&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SPA 설명 실컷 해놓고, 이 X끼 뭐야, 너 인성 문제있어?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맞는말입니다. 굳이, SPA를 고집해서 서비스를 구축하실 필요는 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;잘 돌아가는 시스템은 건드는 게 아냐,&lt;/b&gt;&lt;/span&gt; 라는 이쪽 업계의 전통적인 명언이 떠오르네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPA도 분명 장단이 여러개 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 대표적으로 제시하는 장점은 역시, 최초의 접속 이후로는 브라우저가 캐싱처리를 통해 보다 빠른 서비스를 제공할 수 있다는 점. 그와 동시에 최초 접속 시 필요한 js파일 및 리소스 파일이 많기에 처음 1번이 제법 느릴 수도 있다는 점.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;REST API로 백엔드와 통신하는 게 국룰이 된 현재의 웹 서비스 체계에서는 유연하게 데이터를 요청하고 받을 수 있다는 장점, 그와 동시에 활용되는 데이터에 대한 메모리 관리를 브라우저의 가비지 컬렉터에 전적으로 의존한다는 단점(물론 이건 IE만 아니면 정말 앵간해선 다 커버가 되는데...아시잖아요, 여러분? 대한민국은 IE 못 버려...거기에 한 발 더 나아가 우리회사는...IE......후우, 할말하않)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 이 물음에 대한 결론을 지어보자면,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;개발하고자 하는 서비스에 대한 철저한 분석을 바탕으로 적절한 아키텍쳐를 구성해야 한다는 게 답&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐, 사실 뻔한 답이긴 합니다만...글로벌 트렌드가 어떠니, 이거 좋다던데, 라며 던지시고는 AS-IS에서 되던건데 외않됀데? 라는 분들을 너무나도 많이 겪었고, 논리를 바탕으로 설득하려해도 아몰랑 스킬에 울화통 터지는 건 결국 개발자인 제가 되더라구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네, 그러니 여러분들도 SPA가 정말 우리 서비스와 맞는 걸까? 에 대한 고민을 한 번 정도 해보시기 바랍니다. 이상, 제 마음을 대변하는 짤로 이번 포스팅 끝!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-29 오전 8.02.48.png&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;291&quot; width=&quot;318&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wQrz2/btqJTE6cvlA/m6fSSuwzCIXKuXVL7OZX10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wQrz2/btqJTE6cvlA/m6fSSuwzCIXKuXVL7OZX10/img.png&quot; data-alt=&quot;우리 엄마가 아무거나 주워먹지 말랬는데 왜 그걸 나를 먹여?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wQrz2/btqJTE6cvlA/m6fSSuwzCIXKuXVL7OZX10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwQrz2%2FbtqJTE6cvlA%2Fm6fSSuwzCIXKuXVL7OZX10%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-29 오전 8.02.48.png&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;291&quot; width=&quot;318&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;우리 엄마가 아무거나 주워먹지 말랬는데 왜 그걸 나를 먹여?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>Front-end</category>
      <category>SPA</category>
      <category>Vue</category>
      <category>Vue.js</category>
      <category>web</category>
      <category>개발</category>
      <category>개발자</category>
      <category>스파</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/69</guid>
      <comments>https://blinders.tistory.com/69#entry69comment</comments>
      <pubDate>Tue, 29 Sep 2020 08:07:29 +0900</pubDate>
    </item>
    <item>
      <title>[Vue3] Vue 3.0 One Piece가 릴리즈 되었습니다.</title>
      <link>https://blinders.tistory.com/68</link>
      <description>&lt;p&gt;[Vue.js_#02]번쨰 글을 시작하기에 앞 서&amp;hellip;타이밍이 기가 막힌 건지,&lt;/p&gt;
&lt;p&gt;어쩐건지 2020년 09월 18일을 기준으로 Vue.js 3.0이 릴리즈 됐다.&lt;/p&gt;
&lt;p&gt;첫 번째 이름은 아주아주 유명한 만화 &lt;b&gt;&amp;lsquo;One Piece&amp;rsquo;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-26 오후 11.14.00.png&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;355&quot; width=&quot;535&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XHeQf/btqJCu5EJkS/3h5Gjn80JIfk9vAo4ExH6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XHeQf/btqJCu5EJkS/3h5Gjn80JIfk9vAo4ExH6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XHeQf/btqJCu5EJkS/3h5Gjn80JIfk9vAo4ExH6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXHeQf%2FbtqJCu5EJkS%2F3h5Gjn80JIfk9vAo4ExH6K%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-26 오후 11.14.00.png&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;355&quot; width=&quot;535&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/vuejs/vue-next)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공식 레파지토리&lt;/a&gt; 또한 오픈되었는데, 아직까진 공식 한글 번역 페이지가 존재하지 않는다&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(현재 위 레파지토리의 이슈를 통해 번역에 대한 컨트리뷰션을 받는 중이다)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고 기가 막히게도 내가 얼마전에 쓰기 시작한 &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Vue.js 시리즈&lt;/b&gt;&lt;/span&gt;를 시작한 날이 9월 21일이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;hellip;그렇다, Github 커밋 이력을 보시는 분들은 알 수 있겠지만 내가 Vue-cli 3를 통해 프로젝트를 만든 게 9월 8일. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;그리고 어느정도 글을 쓰며 함께 진행해도 이상이 없을 법할 수준으로 기본 베이스 세팅을 마친게 9월 21일이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;즉, 어쩌다보니 최신 Vue.js 3.0에 맞춰서 설명을 진행하게 된 거 같다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고 &lt;b&gt;그 덕에 Vue 2.x대와 Vue 3.0 의 차이를 이론보다 실전으로 먼저 터득해 나가는 중&lt;/b&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예를 들어 이제는 filter를 method로 대체해야 한다던가,&lt;/p&gt;
&lt;p&gt;Vue.prototype에 넣어서 this 객체의 전역으로 쓰던 형식이 config.globalProperties 와 같은 형태로 바뀌었다던가, v-for를 쓸 때 이젠 :key를 분명하게 명시해야 한다던가, 이벤트 버스도 대체할 방법을 찾아야 한다던가, 하는 &lt;b&gt;실증적 코드들에서의 문제점을 여과없이 몸으로 때려맞는 중&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;왜냐면, 앞선 글에서도 썼지만 나는 이미 2017년부터 Vue 2.x 버전으로 프로젝트를 몇개나 진행해왔고 그 때마다 재사용성이 높아 비축된 둔 코드들이 있는 상태다. 그리고 그 코드들을 이번에 만들기 시작한 vue starter 프로젝트에 적용을 해보려했는데&amp;hellip;와장창 깨지더라&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그걸 또 수정해보겠다고 퀭하게 삽질하며 무수히 뜨는 빨간 에러로그를 얼마나 고쳐댔는지 모르겠다&amp;hellip;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-26 오후 11.35.25.png&quot; data-origin-width=&quot;325&quot; data-origin-height=&quot;164&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIrES5/btqJF0IMB40/mer1Gm0V7MSFZ3FjlcNJ90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIrES5/btqJF0IMB40/mer1Gm0V7MSFZ3FjlcNJ90/img.png&quot; data-alt=&quot;없앤 이유가 이해는 되는데, 그래도 이봐요 에반 유 아저씨ㅠㅠㅠ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIrES5/btqJF0IMB40/mer1Gm0V7MSFZ3FjlcNJ90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIrES5%2FbtqJF0IMB40%2Fmer1Gm0V7MSFZ3FjlcNJ90%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-26 오후 11.35.25.png&quot; data-origin-width=&quot;325&quot; data-origin-height=&quot;164&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;없앤 이유가 이해는 되는데, 그래도 이봐요 에반 유 아저씨ㅠㅠㅠ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;뭐, 사실 솔직히 말하자면 단순 회사생활을 위해서는 지금의 릴리즈를 그냥 모른 척 하고 넘겨도 회사생활에는 1도 타격이 없다(어차피 지금당장 3.x대를 도입하겠다는 곳도 없고, 해달라는 곳도 없으니까. 익숙한 2.x가 있는데 굳이 리스크를 감수할 사람이 얼마나 있을까)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하지만 그런 연유로 다른 사람들이 편하게 포스팅 해주길 기다리고, 포도가 떨어질 때까지 입만 벌리고 있을 사람이 아니라서 나는.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이왕지사 이리 된 거, 이 참에 3.0 릴리즈 버전을 제대로 탐구하면서 글을 써보기로 했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;물론,&amp;nbsp; 내게 익숙한 Vue 2.x대로 설명을 해가며 쓴다면 매우 편하긴 할 거다.&lt;/p&gt;
&lt;p&gt;설명을 쓸 때 막힘도 없을 거고 예제 코드를 만들때도 생각하는 대로 적으면 될 테니까. 왠만한 트러블 슈팅도 구글링없이 처리할 수준이니까 말이다&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;(좀 과한 자신감 같긴하지만, 그래도 3년을 넘게 가지고 논 프레임워크인데 이 정도도 못 하면&amp;hellip;)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;여튼, 생각난 Vue.js 다음편을 쓰기에 앞 서 주절주절 대보려했는데 생각보다 길게 써져서 이렇게 별도 포스팅을 했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이제, 진짜 Vue.js_#02 편을 쓰러 가야겠다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>Frone-end</category>
      <category>Tech</category>
      <category>Vue</category>
      <category>Vue3</category>
      <category>개발</category>
      <category>개발자</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/68</guid>
      <comments>https://blinders.tistory.com/68#entry68comment</comments>
      <pubDate>Sat, 26 Sep 2020 23:28:57 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js_#01] 일단 서버를 띄우자</title>
      <link>https://blinders.tistory.com/67</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;이제 시작입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-21 오전 6.23.00.png&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;275&quot; width=&quot;275&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P1S8t/btqI58aoZuN/RR1TOO2dqNRf5hAKKsLVYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P1S8t/btqI58aoZuN/RR1TOO2dqNRf5hAKKsLVYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P1S8t/btqI58aoZuN/RR1TOO2dqNRf5hAKKsLVYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP1S8t%2FbtqI58aoZuN%2FRR1TOO2dqNRf5hAKKsLVYk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-21 오전 6.23.00.png&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;275&quot; width=&quot;275&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;새로운 걸 배운다는 건, 참 재밌는 일&lt;/b&gt;이에요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;저는 평생 공부만 하면서 살 수 있다면 참 좋을텐데, 라는 마인드를 가진 사람이라 그런지 뭔가 새로운 지식을 머리속에 넣는게 그렇게 재밌더라구요. 막, 지식의 석탑이 머릿속에 차곡차곡 쌓여가는 그 느낌? 남들보다 내가 한 치라도 더 알아간다는 도취감이랄까? 뭐 대충 그런 걸 좋아합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;hellip;는 또 샛길로 빠지려고 하는 기미가 보이니 본론으로 돌아와보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;일단 인트로를 열어보자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://blinders.tistory.com/66&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Vue.js_#00] 원래 시험공부는 방청소부터 하는 거랬다&lt;/a&gt; 에서도 말했지만 2017년부터 Vue.js를 기반으로 한 프로젝트를 하다보니 종종 현장지원의 형태로 개발자분들을 대상으로 교육을 하기도 했습니다. 마음 같아선 3일 정도 일정을 잡고 천천히, 라이브 코딩을 해가면서 여기선 왜 이렇게 쓰고 이걸 응용하려면 어떻게 해야하는지, SPA의 구조에서 가상 DOM의 역할과 매커니즘&amp;hellip;등등 찬찬히 설명드리고 이해시켜드리고 싶지만, &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;현실은 전혀 1도 그렇지가 않거든요.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;보통 Vue.js교육 요청을 받아서 3일 이야기를 꺼내면 난색을 표하십니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그러면 대다수는 8시간으로 교육 일정이 잡힙니다. 최단시간 교육은 3시간 30분이었던 적도 있었죠. 와우, 책 한 권도 뚝딱거리며 나오는 Vue.js에 대해서 3시간 30분만에 JSP 및 서버사이드 렌더링에 익숙하신 분들을 대상으로 모든 걸 전수해드려야합니다. 아하하하하.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-21 오전 6.26.40.png&quot; data-origin-width=&quot;339&quot; data-origin-height=&quot;236&quot; width=&quot;319&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GXi8g/btqJeaky0wk/fnx5DHuS1erD4VlcLZZ7X1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GXi8g/btqJeaky0wk/fnx5DHuS1erD4VlcLZZ7X1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GXi8g/btqJeaky0wk/fnx5DHuS1erD4VlcLZZ7X1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGXi8g%2FbtqJeaky0wk%2Ffnx5DHuS1erD4VlcLZZ7X1%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-21 오전 6.26.40.png&quot; data-origin-width=&quot;339&quot; data-origin-height=&quot;236&quot; width=&quot;319&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그럴때면 결국 아웃사이더처럼 &lt;i&gt;상처를 치료해줄 사람어디없나 가만히 놔두다간 끊임없이 덧나 사랑도 사람도 너무나도 겁나 혼자인게 무서워 난 잊혀질까 두려워 하다가&lt;/i&gt; 끝나는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그렇게 내가 랩을 한 건지 설명을 한 건지 모를 교육이 끝나면, 나는 교육을 했지만 한 게 아니고 받은 분들도 받았지만 받은게 아닌 상태가 되어버리죠. 후에 열이면 열, 백이면 백. 메신져가 옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(시간낭비, 돈낭비, 인력낭비...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;&amp;lsquo;프로님 질문이 있는데요&amp;hellip;&amp;rsquo;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그런 쳇바퀴를 몇번이나 돌고 돌았던 점 또한 이렇게 포스팅을 하게 된 계기이기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;좀 더 쉽게, 기반지식이 1도 없는 분들도 Vue.js에 대해 이해할 수 있게, 진입장벽을 최대한 낮추는 방식으로 설명을 할 수 없을까, 싶었던거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;s&gt;&lt;b&gt;(절대 프로님 질문있어요, 라는 메신져가 귀찮아서가 아니에여, 에헷^^)&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그럼, &lt;b&gt;진짜&amp;nbsp;시작&lt;/b&gt;해봅시다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;0. 명령어 4개로 끝&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;사실 여러분이 이번 편에서 할 건 커맨드 창에서 &lt;span style=&quot;color: #41b884;&quot;&gt;&lt;b&gt;아래 명령어 4개를 실행하는 게 전부&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;git clone http://github.com/onedayz/vue_starter.git&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;cd vue_starter&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;npm install&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;npm run serve&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 위 명령어가 모두 정상적으로 실행되었다면, http://localhost:9090 에 접속하면 아래와 같은 화면을 마주하시게 될 겁니다(혹시 git clone이 안 되시는 분들은 스크롤을 굴려 맨 밑에 잠시 다녀와주세요. 프로젝트를 압축해서 올려두었습니다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-21 오전 6.18.22.png&quot; data-origin-width=&quot;1588&quot; data-origin-height=&quot;968&quot; width=&quot;597&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bre302/btqJetYGEhA/KeQRCh1qfoz7lsSKEtEmy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bre302/btqJetYGEhA/KeQRCh1qfoz7lsSKEtEmy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bre302/btqJetYGEhA/KeQRCh1qfoz7lsSKEtEmy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbre302%2FbtqJetYGEhA%2FKeQRCh1qfoz7lsSKEtEmy0%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-21 오전 6.18.22.png&quot; data-origin-width=&quot;1588&quot; data-origin-height=&quot;968&quot; width=&quot;597&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;간단하죠. 이게 끝이에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그냥 &lt;b&gt;딱 4줄로, 여러분은 Vue.js + node.js 기반의 서버를 띄우신 겁니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 코드를 살짝살짝 바꿔가면서 프론트엔드를 개발하시면 되는거에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;컴포넌트도 추가하고, 스크립트도 넣고, 백엔드랑 REST API 통신도 하고 말예요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-21 오전 6.32.36.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;355&quot; width=&quot;317&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XCgoi/btqJesrVBA0/OzD3H7c0Ph81heWkoLNRBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XCgoi/btqJesrVBA0/OzD3H7c0Ph81heWkoLNRBk/img.png&quot; data-alt=&quot;참, 쉽다 그쵸??&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XCgoi/btqJesrVBA0/OzD3H7c0Ph81heWkoLNRBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXCgoi%2FbtqJesrVBA0%2FOzD3H7c0Ph81heWkoLNRBk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-21 오전 6.32.36.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;355&quot; width=&quot;317&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;참, 쉽다 그쵸??&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자, 쉬운 건 했으니, 이제 썰을 좀 풀어봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;그래서 내가 방금 실행한 4개 명령어가 뭘 하는 건지&lt;/b&gt;&lt;/span&gt;에 대해서 말이에요.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. git clone&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Git 은 형상관리를 위해 쓰이는 오픈소스입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;항간에는 토발즈 아저씨가 SVN 쓰다가 빡쳐서 만들었다고 하던데&amp;hellip;역시 빡침은 많은 개발자들에게 영감을 주는 거 같아요,그쵸?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Git에 대해서는 차후에 각잡고 포스팅을 해야 할 만큼, 문장 몇개로 정의되는 대상이 아니긴 합니다. 그리고 아마 본 포스팅을 보실만큼 기술 스택에 대한 호기심이 왕성한 개발자라면 대부분 &amp;lsquo;형상관리&amp;rsquo;의 개념을 알고 계실거라고 생각합니다. 그런 의미에서 Git도 어느 정도 다루실 줄 아실거라고 생각해요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그래서 여기선 굳이 길게길게 설명하지 않을게요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;하지만! &lt;b&gt;또 누군가에겐 필요할 수 있으니 쉽게 설명&lt;/b&gt;하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;일반적인 프로젝트는 다수의 개발자가 함께합니다. 그렇기에 당연히 A 개발자와 B 개발자가 각각 작업한 코드도 한 프로젝트에 반영이 되야 할 거고, 이때 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;lsquo;하나&amp;rsquo;로 관리되는 프로젝트를 &amp;lsquo;형상&amp;rsquo;이라고 지칭&lt;/b&gt;&lt;/span&gt;합니다. 그리고 그런 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;형상을 &amp;lsquo;관리&amp;rsquo; 할 수 있게 도와주는 도구가 Git&lt;/b&gt;&lt;/span&gt;입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;형상관리를 위해 Git 은 여러 개념(명령어)를 제공하는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그중에 하나가 clone 이에요. &lt;b&gt;clone은, 의미그대로 &amp;lsquo;복사&amp;rsquo;를 의미&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여러분이 방금 실행하신 '&lt;span style=&quot;color: #333333;&quot;&gt;git clone http://&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;github.com/onedayz/vue_starter.git' 명령어는&lt;/span&gt; Github이라는 곳에서, 여러분의 로컬로 형상(레파지토리)를 복사하신 거에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;좀 더 정확히는 제가 만들어놓은 원격지의 레파지토리에서 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그 외에도 Git에 대해선 브랜치 전략이나 pull, rebase, fetch와 같은 명령어등등 알아야 할 게 많습니다만, 일단 넘어갈게요. 이건 Vue.js 포스팅이니까요.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. npm install&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자, 그래서 이제 로컬에 vue_starter 라는 디렉토리가 생겼을거고, 여러분은 제가 지시했던 &lt;b&gt;2번째 명령어 npm install을 실행&lt;/b&gt;하셨을 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;npm install 명령어를 실행하시면 콘솔창에 뭔가 쫙쫙쫙 많이 설치되는 느낌의 출력창을 보셨을 거에요. install 이라는 어원에서 알 수 있듯이, &lt;b&gt;본 명령어를 무언가를 설치하는 명령어&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그렇다면 그 설치하는 게 무엇이냐?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;바로 npm 라이브러리들을 설치&lt;/b&gt;&lt;/span&gt;하는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;우리는 모두 어른이니까, 어린애들이 흙장난 하다가 아무거나 막 집어먹듯이 마구잡이로 랜덤하게 설치할 순 없잖아요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자, 프로젝트 루트 디렉토리에 있는 package.json 파일을 한 번 열어보도록 할게요. json형태로 정의된 여러값들이 보일 겁니다. 그 중에 dependencies/devDependencies 항목이 있습니다. 감이 딱! 오시죠? npm install은 그 항목에 명시된 라이브러리들을 설치하는 작업입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-21 오전 6.40.01.png&quot; data-origin-width=&quot;314&quot; data-origin-height=&quot;339&quot; width=&quot;351&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctcWrH/btqJbyzckqh/to5Jh8CkUVAFYXdZaaYSw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctcWrH/btqJbyzckqh/to5Jh8CkUVAFYXdZaaYSw1/img.png&quot; data-alt=&quot;Vue Cli3 기본에 제가 추가한 몇개 라이브러리가 정의되어있습니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctcWrH/btqJbyzckqh/to5Jh8CkUVAFYXdZaaYSw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctcWrH%2FbtqJbyzckqh%2Fto5Jh8CkUVAFYXdZaaYSw1%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-21 오전 6.40.01.png&quot; data-origin-width=&quot;314&quot; data-origin-height=&quot;339&quot; width=&quot;351&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Vue Cli3 기본에 제가 추가한 몇개 라이브러리가 정의되어있습니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;설치가 되는 라이브러리들에는 당연하게도 Vue.js도 포함이 되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(dependencies 2번째 줄)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;네, Vue.js도 결국은 뭔가 새롭게 짜잔!해서 나타난 아이가 아니구요, 그저 Javascript로 만들어진 라이브러리일 뿐입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;우리가 흔히 백엔드를 구성할 때 활용하는 스프링 프레임워크를 생각해보세요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스프링 프레임워크도 뜯어보면 결국 JAVA로 만들어진 라이브러리일 뿐입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그것과 크게 다르지 않아요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 여기까지 하셨다면 프론트엔드 개발에 필요한 라이브러리 설치까지 끝났습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⌘&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;dependendencies 와 devDependencies 의 차이&lt;/b&gt;&lt;/span&gt;를 물으시는 분들이 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 둘의 차이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;런타임에 계속 필요한 라이브러리는 dependencies에 정의&lt;/b&gt;되어야하고,&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;개발 및 빌드/컴파일시만 필요한 거라면 devDependencies&lt;/b&gt;에 있으면 됩니다. 그래서 빌드할 때만 쓰이는 babel이나 cli-service와 같은 라이브러리는 devDependencies에 있고 서버가 기동되는 중인 런타임에 필요한 vue나 vue-router같은 라이브러리는 dependencies에 정의되어 있는 겁니다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. npm run serve&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;npm run serve는 hot reload 기능을 내포한 node.js 서버를 기동하는 명령어&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;딱 이 한 줄만 기억을 하셔도 됩니다. 웹팩 설정이나 vue-cli-service와 같은 추가적인 개념은 지금 단계에선 굳이 모르셔도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;hellip;사실 길게길게 vue-cli-service 부터, webpack 2.x -&amp;gt; 4.x 로 바뀌면서 변한 것들, 설정등등을 몇 문단에 걸쳐서 적었는데&amp;hellip;읽다보니 &lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;&amp;lsquo;아, 이거 읽다가 더 헷갈리겠는데?&amp;rsquo;&lt;/b&gt;&lt;/span&gt;라는 생각이 들어거 그냥 다 지웠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;쉽게 보고 쉽게 익히는 게 기조이니만큼, 지금은 그냥 딱 이 정도만 알아두세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이번 편은 이쯤에서 마치려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;운동도 시작전엔 스트레칭을 해야하듯이, 적당히 머리를 풀어주신 거라고 생각해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;사실 다음편부터 좀 개념적인 부분으로 진행 될 예정이기 때문에 Vue.js나 SPA를 처음 접하시는 분이라면 혼돈의 카오스를 맞이하실 수도 있기에...일단 뭐라도 띄워놓으면 마음이 편하시지 않을까 싶어서 1편을 이렇게 적었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그럼 안녕, 다음편에서 봐요 :)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;-1. 부록&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. git clone을 잘 모르신다면, 아래 zip파일을 받아서 압축을 해제하시고 npm install을 실행해주세요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/OB8t0/btqI6F7a02w/g1KkIiJOaKjSLlDPXCKCK1/vue_starter-dev.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;vue_starter-dev.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.14MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. npm install 진행중에 에러가 발생한다면, npm config list 명령어를 통해 npm 설정을 확인해주세요. 보통 proxy나 ssl 같은 설정을 추가해주셔야 하는 경우가 많습니다. 아래 명령어를 참고해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;npm config list 로 설정을 확인한 후,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;npm config set proxy http://host:port&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;npm config set https-proxy https://host:port&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;npm config set strict-ssl false&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;npm config set registry&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;http://registry.npmjs.org&quot;&gt;http://registry.npmjs.org&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/프론트엔드(Front-end)</category>
      <category>Front-end</category>
      <category>Vue</category>
      <category>Vue.js</category>
      <category>개발</category>
      <category>개발자</category>
      <category>뷰</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>Blindr_grey</author>
      <guid isPermaLink="true">https://blinders.tistory.com/67</guid>
      <comments>https://blinders.tistory.com/67#entry67comment</comments>
      <pubDate>Mon, 21 Sep 2020 07:24:11 +0900</pubDate>
    </item>
  </channel>
</rss>